Add 课堂-普通作业模块

* A 课堂-普通作业模块
   * A 页面不存在时进入主页
   * A referrerInfo 分析
   * A 主页课堂菜单操作
   * A error-page组件错误处理界面
   * U 加入课堂对话框功能升级
   * U 课堂页面错误处理
   * U 课程邀请界面改进,增加已停用时的图标
   * U 改变小程序码生成接口为getWXACodeUnlimited
   * F 试卷题目富文本显示异常
   * D 隐藏发现页入口
master
educoder_weapp 5 years ago
parent 0b47aa0777
commit 62e5403be7

@ -1,28 +1,16 @@
// 云函数模板
// 部署:在 cloud-functions/login 文件夹右击选择 “上传并部署”
const cloud = require('wx-server-sdk')
// 初始化 cloud
cloud.init({
// API 调用都保持和云函数当前所在环境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
/**
* 这个示例将经自动鉴权过的小程序用户 openid 返回给小程序端
*
* event 参数包含小程序端调用传入的 data
*
*/
exports.main = (event, context) => {
console.log(event)
console.log(context)
// 可执行其他自定义逻辑
// console.log 的内容可以在云开发云函数调用日志查看
// 获取 WX Context (微信调用上下文),包括 OPENID、APPID、及 UNIONID需满足 UNIONID 获取条件)等信息
const wxContext = cloud.getWXContext()
return {

@ -2,6 +2,7 @@
"permissions": {
"openapi": [
"wxacode.get",
"wxacode.getUnlimited",
"subscribeMessage.send",
"subscribeMessage.addTemplate",
"templateMessage.send",

@ -1,7 +1,7 @@
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV})
// 云函数入口函数
exports.main = async (event, context) => {
@ -13,6 +13,9 @@ exports.main = async (event, context) => {
case 'sendSubscribeMessage': {
return sendSubscribeMessage(event)
}
case "getWXACodeUnlimited":{
return getWXACodeUnlimited(event)
}
case 'getWXACode': {
return getWXACode(event)
}
@ -54,6 +57,26 @@ async function sendSubscribeMessage(event) {
return sendResult
}
async function getWXACodeUnlimited(event){
let {scene, page} = event;
const wxacodeResult = await cloud.openapi.wxacode.getUnlimited({
scene, page
})
const fileExtensionMatches = wxacodeResult.contentType.match(/\/([^\/]+)/)
const fileExtension = (fileExtensionMatches && fileExtensionMatches[1]) || 'jpg'
const uploadResult = await cloud.uploadFile({
cloudPath: `images/wxacode/${(page+"?"+scene).replace(/[\/?&]/g, "_")}.${fileExtension}`,
fileContent: wxacodeResult.buffer,
})
if (!uploadResult.fileID) {
throw new Error(`upload failed with empty fileID and storage server status code ${uploadResult.statusCode}`)
}
return uploadResult.fileID
}
async function getWXACode(event) {
let {path} = event;

@ -1,6 +1,3 @@
js/apiConfig.js
towxml/
wemark/
# Windows
[Dd]esktop.ini

@ -1,19 +1,13 @@
if (!global.towxml)
global.towxml = require('../../../towxml/index');
Page({
md: '# 服务协议\n\n尊敬的用户您好\n欢迎使用本平台在您使用本平台前请您认真阅读并遵守《服务协议》以下简称”本协议”请您务必审慎阅读、充分理解协议的各条款内容。\n当您在注册过程中点击查看”看过并同意本服务协议”按照注册流程成功注册为平台的用户即表示您已充分阅读、理解并完全接受本协议中的全部条款。您承诺接受并遵守本协议的约定届时您不应以未阅读本协议的内容等理由主张本协议无效或本协议中的某些条款无效或要求撤销本协议。\n\n## 本平台权利和义务\n1. 尊重用户隐私:尊重用户隐私,保障用户隐私安全是平台的一项基本政策;\n2. 管理平台用户:平台依据国家法律、地方法律和国际法律等的标准以及本行业的规则来管理平台注册用户;\n3. 处理用户反馈:平台的相关人员会及时处理用户反馈的问题并给予及时回复。\n## 用户权利和义务\n1. 用户在使用平台的过程中,必须遵守如下原则:\n2. 遵守中国的有关法律和法规;\n3. 使用网络服务不作非法用途;\n4. 不干扰和混乱网络服务;\n5. 遵守所有使用网络服务的网络协议、规定、程序和惯例;\n6. 不传输任何非法的、骚扰性的、中伤他人的、辱骂性的、恐吓性的、伤害性的、庸俗的,淫秽等信息资料;\n7. 不传输任何教唆他人构成犯罪行为的资料;\n8. 用户不得故意或者过失损害平台合法权利和利益。及时回复。\n## 关于责任\n鉴于网络服务的特殊性本平台有权在事先通知的情况下变更、中断、升级部分网络服务。本平台不担保网络服务不会中断但承诺在用户可承受的时间内快速恢复服务同时确保用户数据的安全性和可靠性。\n\n## 免责条款\n鉴于互联网服务的特点本平台对用户自行上传的资料不承担任何法律责任希望各网友对平台提供的互动服务中的内容进行监督若发现存在侵犯任何第三人著作权等合法权益的内容请及时告知我们将严格按照《信息网络传播权保护条例》中的规定予以删除。\n\n1. 本平台属于非赢利性平台转载的文章遵循原作者的版权声明如果原文没有版权声明按照目前互联网开放的原则我们将在不通知作者的情况下转载文章如果原文明确注明“禁止转载”我们一定不会转载。如果我们转载的文章不符合作者的版权声明或者作者不想让我们转载您的文章的话请来信告知zhongjin@educoder.net\n2. 本平台转载文章仅为传播更多信息之目的,凡在本平台出现的信息,均仅供参考。本平台将尽力确保所提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何损失或损害承担责任。\n3. 任何透过本平台网页而链接及得到的资讯、产品及服务,本平台概不负责,亦不负任何法律责任。\n4. 本平台所刊发、转载的文章,其版权均归原作者所有,如其他媒体、平台或个人从本网下载使用,请在转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并自负版权等法律责任。\n## 侵权投诉\nEducoder平台是一个接受外来投稿的平台部分图片和文字来自互联网或原作者自行编辑。投稿到Educoder平台的文章默认作者授权其全部图文内容在Educoder平台、在其微信公众号及微博帐号进行发布Educoder平台对这一部分内容不进行预先审查。\n如您发现平台上文章或图片涉嫌侵犯您的权利请您将所涉及的文章 URL 和侵权理由以邮件形式发送到邮箱zhongjin@educoder.net我们将在核实情况后依照《中华人民共和国侵权责任法》及其司法解释对内容进行屏蔽、删除和通知原作者。\n\n## 服务条款的修改\n本平台保留在必要时对本协议修改的权利一旦发生变动这些条款可由平台项目组及时更新且毋须另行通知修改后的条款一旦在网页上公布即有效代替原来的服务条款。您可随时查阅最新版服务条款。\n\n**本协议最终解释权归本平台所有**。'
,
data: {
article: {}
md: '# 关于\n\n## 简介\n\nEducoder是一个面向计算机类的互联网IT教育和实战平台提供企业级工程实训以实现工程化专业教学的自动化和智能化。高校和企业人员可以在此开展计算机实践性教学活动将传统的知识传授和时兴的工程实战一体化。\n\n本平台核心技术源自国家863计划和重点研发计划科技成果。国防科技大学、北京大学、北京航空航天大学、中科院软件所等单位合作研制曾获2015国家技术发明奖、2013教育部科技成果奖等重要奖项。目前EduCoder已被选为中国计算机协会长沙分部教育实训指定平台、全军大学计算机教改支撑平台。\n\n##优势\n\n- 随时随地动手实训\n\n覆盖不同专业的IT实验和实训每周更新无需配置本机实验环境随时随地开启企业级真实实训。\n\n- 敏捷化工程人才培养\n\n通过伴随式实时指导和辅助将专业知识和动手实践结合起来真正做到即学即用让学生突破纸上谈兵的局限提高就业竞争力。\n\n- 循序渐进的实训路径\n\n平台提供涵盖基础入门、案例实践和创新应用的完整实训项目体系通过由浅入深的实训路径帮助学生快速提升实战能力。\n\n- 自动化工程能力评测\n\n自动评测实训任务支持技能统计提供教学活动分析报告减轻教师和助教的辅导压力免去作业发布和批改的困扰实时了解学生学习情况全面提升教师施教效率和水平。'
},
onLoad: function (options) {
let article = global.towxml(this.md, 'markdown')
this.setData({
article
});
},
onShareAppMessage: function () {

@ -1,5 +1,5 @@
{
"usingComponents": {
"towxml": "/towxml/towxml"
"rich-md": "/components/rich-md/rich-md"
}
}

@ -1 +1 @@
<towxml nodes="{{article}}"></towxml>
<rich-md my-class="body" nodes="{{md}}"/>

@ -0,0 +1,4 @@
.body{
padding-bottom: 12px;
background: white;
}

@ -0,0 +1,13 @@
Page({
data: {
md: '# 服务协议\n\n尊敬的用户您好\n欢迎使用本平台在您使用本平台前请您认真阅读并遵守《服务协议》以下简称”本协议”请您务必审慎阅读、充分理解协议的各条款内容。\n当您在注册过程中点击查看”看过并同意本服务协议”按照注册流程成功注册为平台的用户即表示您已充分阅读、理解并完全接受本协议中的全部条款。您承诺接受并遵守本协议的约定届时您不应以未阅读本协议的内容等理由主张本协议无效或本协议中的某些条款无效或要求撤销本协议。\n\n## 本平台权利和义务\n1. 尊重用户隐私:尊重用户隐私,保障用户隐私安全是平台的一项基本政策;\n2. 管理平台用户:平台依据国家法律、地方法律和国际法律等的标准以及本行业的规则来管理平台注册用户;\n3. 处理用户反馈:平台的相关人员会及时处理用户反馈的问题并给予及时回复。\n## 用户权利和义务\n1. 用户在使用平台的过程中,必须遵守如下原则:\n2. 遵守中国的有关法律和法规;\n3. 使用网络服务不作非法用途;\n4. 不干扰和混乱网络服务;\n5. 遵守所有使用网络服务的网络协议、规定、程序和惯例;\n6. 不传输任何非法的、骚扰性的、中伤他人的、辱骂性的、恐吓性的、伤害性的、庸俗的,淫秽等信息资料;\n7. 不传输任何教唆他人构成犯罪行为的资料;\n8. 用户不得故意或者过失损害平台合法权利和利益。及时回复。\n## 关于责任\n鉴于网络服务的特殊性本平台有权在事先通知的情况下变更、中断、升级部分网络服务。本平台不担保网络服务不会中断但承诺在用户可承受的时间内快速恢复服务同时确保用户数据的安全性和可靠性。\n\n## 免责条款\n鉴于互联网服务的特点本平台对用户自行上传的资料不承担任何法律责任希望各网友对平台提供的互动服务中的内容进行监督若发现存在侵犯任何第三人著作权等合法权益的内容请及时告知我们将严格按照《信息网络传播权保护条例》中的规定予以删除。\n\n1. 本平台属于非赢利性平台转载的文章遵循原作者的版权声明如果原文没有版权声明按照目前互联网开放的原则我们将在不通知作者的情况下转载文章如果原文明确注明“禁止转载”我们一定不会转载。如果我们转载的文章不符合作者的版权声明或者作者不想让我们转载您的文章的话请来信告知zhongjin@educoder.net\n2. 本平台转载文章仅为传播更多信息之目的,凡在本平台出现的信息,均仅供参考。本平台将尽力确保所提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何损失或损害承担责任。\n3. 任何透过本平台网页而链接及得到的资讯、产品及服务,本平台概不负责,亦不负任何法律责任。\n4. 本平台所刊发、转载的文章,其版权均归原作者所有,如其他媒体、平台或个人从本网下载使用,请在转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并自负版权等法律责任。\n## 侵权投诉\nEducoder平台是一个接受外来投稿的平台部分图片和文字来自互联网或原作者自行编辑。投稿到Educoder平台的文章默认作者授权其全部图文内容在Educoder平台、在其微信公众号及微博帐号进行发布Educoder平台对这一部分内容不进行预先审查。\n如您发现平台上文章或图片涉嫌侵犯您的权利请您将所涉及的文章 URL 和侵权理由以邮件形式发送到邮箱zhongjin@educoder.net我们将在核实情况后依照《中华人民共和国侵权责任法》及其司法解释对内容进行屏蔽、删除和通知原作者。\n\n## 服务条款的修改\n本平台保留在必要时对本协议修改的权利一旦发生变动这些条款可由平台项目组及时更新且毋须另行通知修改后的条款一旦在网页上公布即有效代替原来的服务条款。您可随时查阅最新版服务条款。\n\n**本协议最终解释权归本平台所有**。'
},
onLoad: function (options) {
},
onShareAppMessage: function () {
}
})

@ -0,0 +1,5 @@
{
"usingComponents": {
"rich-md": "/components/rich-md/rich-md"
}
}

@ -0,0 +1 @@
<rich-md my-class="body" nodes="{{md}}"/>

@ -0,0 +1,4 @@
.body{
padding-bottom: 12px;
background: white;
}

@ -16,8 +16,31 @@ App({
callApi(options){return client.callApi(options)},
user(){ return client.user},
syncUser(options){return client.syncUser(options)},
onLaunch: function () {
onLaunch: function (options) {
console.log("applaunch",options);
if(Object.keys(options.referrerInfo).length>0){
let { appId, extraData } = options.referrerInfo
const db = wx.cloud.database();
db.collection("referrer_info")
.add({
data:{
appId,
extraData,
createdAt: db.serverDate()
}
})
}
},
onShow(){
this.api("users.unread_message_info")().then(res=>{
if(res.unread_message_count)
wx.setTabBarBadge({index:1,text:res.unread_message_count.toString()});
else if(res.unread_tiding_count)
wx.showTabBarRedDot({index:1})
})
},
onPageNotFound(res) {
this.redirectTo({url:"{my_courses}"});
},
showError(e){
wx.showToast({
@ -30,11 +53,11 @@ App({
title: res.message,
})
},
getPageUrl(url){
getPageUrl(url,root="/"){
return url.replace(/{(.*)}/, function (match, name) {
for (var u of __wxConfig.pages) {
if (u.endsWith("/"+name))
return "/" + u;
return root + u;
}
return match;
});

@ -3,7 +3,9 @@
"pages/my_courses/my_courses",
"pages/findmore/findmore",
"pages/courses/courses",
"pages/my/my"
"pages/my/my",
"pages/tidings/tidings",
"path/pages/path/path"
],
"subpackages": [
{
@ -12,6 +14,7 @@
"pages/login/login",
"pages/reset_password/reset_password",
"pages/register/register",
"pages/agreement/agreement",
"pages/about/about"
]
},
@ -30,13 +33,31 @@
]
},
{
"root":"exercise",
"pages":[
"root": "exercise",
"pages": [
"pages/exercise/exercise",
"pages/exercise_grade/exercise_grade",
"pages/exercise_setting/exercise_setting",
"pages/question_setting/question_setting"
]
},
{
"root": "common-homework",
"pages": [
"pages/common-homework/common-homework"
]
},
{
"root": "shixun",
"pages": [
"pages/shixun/shixun"
]
},
{
"root": "challenge",
"pages": [
"pages/challenge/challenge"
]
}
],
"preloadRule": {
@ -50,13 +71,15 @@
"pages/my_courses/my_courses": {
"network": "all",
"packages": [
"course","account"
"course",
"account"
]
},
"course/pages/course/course":{
"network":"all",
"packages":[
"exercise","account"
"course/pages/course/course": {
"network": "all",
"packages": [
"exercise",
"account"
]
}
},
@ -77,12 +100,11 @@
"iconPath": "images/tab_study_default.png",
"selectedIconPath": "images/tab_study_pressed.png"
},
{
"pagePath": "pages/findmore/findmore",
"text": "发现",
"iconPath": "images/tab_findmore_default.png",
"selectedIconPath": "images/tab_findmore_pressed.png"
"pagePath": "pages/tidings/tidings",
"text": "消息中心",
"iconPath": "images/tab_tiding_default.png",
"selectedIconPath": "images/tab_tiding_pressed.png"
},
{
"pagePath": "pages/my/my",

@ -1,6 +1,5 @@
page {
height: 100%;
background-color: #f0f0f0;
background-color: #f1f1f1;
}
.flex-wrap{
display: flex;
@ -45,4 +44,13 @@ button.button-main{background:#00b0f0}
.round{
border-radius: 50%;
overflow: hidden;
}
radio .wx-radio-input.wx-radio-input-checked{
background: #00b0f0;
border-color: #00b0f0;
}
checkbox .wx-checkbox-input.wx-checkbox-input-checked {
color: #00b0f0;
}

@ -1 +0,0 @@
we-cropper/

File diff suppressed because one or more lines are too long

@ -0,0 +1,17 @@
<template name="we-cropper">
<canvas
class="cropper"
disable-scroll="true"
bindtouchstart="touchStart"
bindtouchmove="touchMove"
bindtouchend="touchEnd"
style="width:{{width}}px;height:{{height}}px;background-color: rgba(0, 0, 0, 0.8)"
canvas-id="{{id}}">
</canvas>
<canvas
class="cropper"
disable-scroll="true"
style="position: fixed; top: -{{width * pixelRatio}}px; left: -{{height * pixelRatio}}px; width:{{width * pixelRatio}}px;height:{{height * pixelRatio}}px;"
canvas-id="{{targetId}}">
</canvas>
</template>

@ -0,0 +1,66 @@
// miniprogram/challenge/pages/challenge/challenge.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})

@ -0,0 +1,2 @@
<!--miniprogram/challenge/pages/challenge/challenge.wxml-->
<text>miniprogram/challenge/pages/challenge/challenge.wxml</text>

@ -0,0 +1 @@
/* miniprogram/challenge/pages/challenge/challenge.wxss */

@ -0,0 +1,183 @@
const app = getApp();
Component({
properties:{
work_id:Number,
homework_id:Number,
homework_name:String,
},
data: {
attachments:[],
description:""
},
methods:{
updateInput({detail:{value}}){
this.setData({description: value});
},
submit(){
let {description} =this.data;
let attachment_ids = this.data.attachments.map(i=>i.id);
if(this.data.uploading)
return wx.showToast({
title: '请等待文件上传完毕',icon:"none"
})
if(this.data.un_commit_work){
let { homework_id } = this.data;
app.api("homework_commons.student_works", { method: "POST" })({ description, attachment_ids, homework_id })
.then(res => {
console.log(res);
app.showMsg(res);
this.setData({})
})
.catch(e => {
app.showError(e);
})
}else{
let { work_id } = this.data;
app.api("student_works")({ description, attachment_ids, work_id })
.then(res => {
app.showMsg(res);
})
.catch(e => {
app.showError(e);
})
}
},
uploadAttachment(){
var cbList = ["uploadFile", "uploadImage", "uploadVideo"];
wx.showActionSheet({
itemList: ["微信文件","上传照片","上传视频"],
success:res=>{
this[cbList[res.tapIndex]]();
}
})
},
uploadFile(){
wx.chooseMessageFile({
count:1,
success:res=>{
console.log("getfilepath");
this.upload(res.tempFiles[0])
}
})
},
uploadImage(){
wx.chooseImage({
count:1,
success:res=>{
this.upload(res.tempFiles[0])
}
})
},
uploadVideo(){
wx.chooseVideo({
success:res=>{
this.upload({path: res.tempFilePath, size:res.size});
}
})
},
upload({path, size, name}){
console.log("upload", path, name)
if(this.size>157286400)
return wx.showModal({
title: '错误',
content: '文件不能大于150M',
showCancel: false
})
this.setData({uploading:true});
console.log("uploading")
app.api("attachments")({
file:path,
complete: ()=>{this.setData({uploading:false})}
})
.then(res=>{
let match = path.match(/\/([^\/]+$)/);
let title = match?match[1]:path;
let attachment = {id:res.id,title,path, url:"/api/attachments/"+res.id}
this.setData({attachments: this.data.attachments.concat(attachment)});
})
.catch(app.showError)
},
onTapFile({target:{dataset:{id}}}){
if(!id) return;
wx.showActionSheet({
itemList: ["预览","删除"],
success:res=>{
if(res.tapIndex==0){
let attachment = this.data.attachments.filter(i=>i.id==id)[0];
let url = global.config.eduUrl + attachment.url;
let path = attachment.path;
let match = attachment.title.match(/.([^.\/]+$)/)
if(match&&["jpg","png","bmp","gif","jpeg"].indexOf(match[1].toLowerCase())!=-1){
if(path)
var urls = [path];
else
var urls = [url];
wx.previewImage({
urls,
fail:e=>{wx.showToast({icon:"none",title:"预览失败"})}
})
}else{
if(path){
wx.openDocument({
filePath: path,
fail:res=>{wx.showToast({icon:"none",title:"不支持该文件类型"})}
})
}else{
wx.showLoading({
title: '加载中',
})
wx.downloadFile({
url,
success:res=>{
wx.openDocument({
filePath: res.tempFilePath,
fail:e=>{wx.showToast({icon:"none",title:"不支持该文件类型"})}
})
},
complete:wx.hideLoading,
fail:e=>{
wx.showToast({
title: '预览失败',icon:"none"
})
}
})
}
}
}else if(res.tapIndex==1){
app.api("attachments",{method:"DELETE"})({attachment_id: id})
.then(res=>{
var attachments = this.data.attachments.filter(i => i.id != id);
this.setData({ attachments });
app.showMsg(res);
})
.catch(e=>{
if(e.code==404){
e.message = "该资源已经被删除了";
var attachments = this.data.attachments.filter(i => i.id != id);
this.setData({ attachments });
}
app.showError(e);
})
}
}
})
},
pullEdit(){
let {work_id} = this.data;
app.api("student_works.edit")({work_id})
.then(res=>{
this.setData(res);
});
},
onLoad: function (options) {
console.log(this.data, options);
if(options.un_commit_work=="true")
this.setData({un_commit_work:true});
if(!this.data.un_commit_work)
this.pullEdit();
},
onShow: function () {
}
}
})

@ -0,0 +1,4 @@
{
"usingComponents": {},
"navigationBarTitleText": "普通作业"
}

@ -0,0 +1,20 @@
<page-meta>
<navigation-bar title="{{homework_name||'普通作业'}}"/>
</page-meta>
<view class="homework">
<textarea
class="desp"
placeholder="输入作品描述"
bindinput="updateInput"
value="{{description}}"/>
<view class="operations">
<button class="upload" bindtap="uploadAttachment" loading="{{uploading}}" disabled="{{uploading}}" size="mini" plain="1">{{uploading?'上传中':'添加附件'}}</button>
<button class="submit" bindtap="submit" size="mini">提交</button>
</view>
<view class="tip">暂不支持保持附件原文件名</view>
<view class="attachments" bindtap="onTapFile">
<view class="attachment" wx:for="{{attachments}}" wx:key="id" data-id="{{item.id}}">
{{item.title}}
</view>
</view>
</view>

@ -0,0 +1,40 @@
.desp{
background: white;
border: 1px solid grey;
border-radius: 5px;
margin: 10px;
padding: 10px;
width: auto;
}
.operations{
display: flex;
}
.operations>button{
width: 96px;
}
.upload{
border-color: #0080f0;
color: #0080f0;
}
.submit{
background: #0080f0;
color: white;
}
.tip{
color: #0080f0;
font-size: 12px;
padding-left: 12px;
}
.attachments{
margin-top: 16px;
}
.attachment{
padding: 8px 10px;
margin: 6px 6px;
border-radius: 6px;
background: white;
overflow: hidden;
word-wrap: break-word;
}

@ -1,17 +1,120 @@
const app = getApp();
const actions = {
"置顶":{
cb:"sticky",
cd:{"sticky":[false]}
},
"取消置顶":{
cb:"cancelSticky",
cd:{"sticky":[true]}
},
"邀请成员":{
cb:"share",
cd:{"course_identity":[2]}
},
"停用邀请码":{
cb: "set_invite_code_halt",
cd: { "invite_code_halt": [0], "course_identity": [2]}
},
"启用邀请码":{
cb:"set_invite_code_halt",
cd: { "invite_code_halt": [1], "course_identity": [2]}
},
"退出课堂":{
cb:"exit_course",
cd:{"course_identity":[5]}
}
}
Component({
properties: {
data:Object, //@todo: simplify
course_id:Number,
teacher:Object,
name:String,
school:String
data:Object,
category:String
},
data: {
eduImgDir:global.config.eduImgDir,
imgDir:global.config.imgDir
eduImgDir:global.config.eduImgDir
},
methods: {
showAction(){
let itemList = this.getActions();
console.log(itemList);
let course = this.data.data;
wx.showActionSheet({
itemList,
success:res=>{
let action = itemList[res.tapIndex];
let cb = actions[action].cb;
this[cb]();
}
})
},
getActions(){
var _actions = [];
for(var name in actions){
var flag = true;
var action = actions[name];
for(var cdt in action.cd){
console.log(action.cd[cdt],this.data.data[cdt])
if(action.cd[cdt].indexOf(this.data.data[cdt])==-1){
flag=false;
break;
}
}
if(flag)
_actions.push(name);
}
return _actions;
},
sticky(){
let course_id = this.data.data.id;
let category = this.data.category;
app.api("weapps.course_stickies")({course_id, category})
.then(res=>{
this.triggerRefresh();
})
.catch(app.showError)
},
share(){
app.navigateTo({url:"{course_invite}?course_id="+this.data.data.id});
},
set_invite_code_halt(){
app.api("courses.set_invite_code_halt")({ course_id: this.data.data.id })
.then(res => {
res.message="操作成功";
app.showMsg(res);
this.triggerRefresh();
})
},
cancelSticky(){
let course_id = this.data.data.id;
let category = this.data.category;
app.api("weapps.course_stickies.cancel_sticky")({ course_id, category })
.then(res => {
this.triggerRefresh();
})
.catch(app.showError)
},
exit_course(){
wx.showModal({
title: '提示',
content: '退出后您将不再是本课题的成员,作品将全部被删除,\n确定要退出该课堂吗',
success:res=>{
if(res.confirm){
app.api("courses.exit_course")({course_id:this.data.data.id})
.then(res=>{
app.showMsg(res);
this.triggerRefresh();
})
.catch(app.showError)
}
}
})
},
edit() {
return;
app.navigateTo({ url: "{course_setting}?course_id" + this.data.data.id });
},
triggerRefresh() {
this.triggerEvent("refresh", {}, { bubbles: true })
},
}
})

@ -1,10 +1,11 @@
<navigator class="bg{{course_id%7}} course" url="/course/pages/course/course?course_id={{course_id}}">
<view class="header"><image class="action" mode="aspectFit" catchtap="showAction" src="{{imgDir}}more-dots-white.png"/></view>
<navigator class="bg{{data.id%7}} course" url="/course/pages/course/course?course_id={{data.id}}" bindlongpress="showAction">
<view wx:if="{{data.sticky}}" class="sticky"></view>
<view class="header"><image class="action" mode="aspectFit" catchtap="showAction" src="./more.png"/></view>
<view class="body">
<image class="avatar" src="{{eduImgDir}}{{teacher.avatar_url}}"/>
<image class="avatar" src="{{eduImgDir}}{{data.avatar_url}}"/>
<view class="course-info">
<view class="course-name">{{name}}</view>
<view><text class="school">{{school}}</text> <text>{{teacher.real_name}}</text> </view>
<view class="course-name">{{data.name}}</view>
<view><text class="school">{{data.school}}</text> <text>{{data.creator}}</text> </view>
</view>
</view>
</navigator>

@ -23,18 +23,31 @@
text-align: end;
}
.action{
width: 20px;
height: 22px;
opacity: 0;
width: 22px;
height: 20px;
padding: 2px 9px;
}
.course{
color: white;
font-size:13px;
border-radius: 5px;
padding: 0px 8px 18px 8px;
padding: 0px 2px 18px 8px;
position: relative;
overflow: hidden;
}
.sticky{
width: 36px;
height: 18px;
transform: rotate(-45deg);
position: absolute;
background: orange;
top: -6px;
left: -16px;
border-bottom: #f0f0f0 2px solid;
}
.body{
display: flex;
padding-right: 6px;
}
.avatar{

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

@ -1,12 +1,49 @@
const app = getApp();
const config = global.config;
const imgUrl = config.imgDir+"blank_info_bg.png";
const scenes = {
imgUrl,
401:{
message:"请先登陆哦",
btnText:"点击登陆"
}
}
Component({
properties: {
status:Number
status:{
type:Number,
observer:function(res){
this.refresh()
}
},
config:Object,
bg:{
type:String,
value:"#00b0f0"
}
},
data: {
},
methods: {
refresh(){
let {config, status} = this.data;
var {message="", btnText="", imgUrl=""} = scenes;
if(scenes[status])
var {message=message, btnText=btnText, imgUrl=imgUrl} = scenes[status];
if(config[status])
var {message=message, btnText=btnText, imgUrl=imgUrl} = config[status];
this.setData({message, btnText, imgUrl});
},
onTapBody(){
console.log("tapbody")
let {status} = this.data;
this.triggerEvent("refresh",{target:"body", status})
},
onTapButton(){
console.log("tapButton")
let {status } =this.data;
this.triggerEvent("refresh",{target:"button", status})
}
}
})

@ -1,5 +1,7 @@
<view class="body" bindtap="onTapBody">
<image class="img" mode="aspectFit" src="{{imgUrl}}"/>
<view class="msg">{{msg}}</view>
<button class="btn" catchtap="onTapButton">{{btnText}}</button>
<view wx:if="{{message}}" class="body" style="background:{{bg}}" bindtap="onTapBody">
<view class="info">
<image class="image" mode="aspectFit" src="{{imgUrl}}"/>
<view class="message">{{message||'请先登陆哦'}}</view>
<button wx:if="{{btnText}}" class="button" catchtap="onTapButton" size="mini">{{btnText}}</button>
</view>
</view>

@ -1,22 +1,33 @@
.body{
z-index: 1000;
top: 0;
right: 0;
position: fixed;
left: 0;
z-index: 1000;
top: 0;
right: 0;
position: fixed;
left: 0;
display: flex;
flex-direction: column;
padding-top: 24px;
bottom: 0;
color:white;
justify-content: center;
align-content: center;
}
.info{
display: flex;
flex-direction: column;
padding-top: 24px;
margin-bottom: 100px;
align-items: center;
}
.img{
.image{
width: 200px;
height: 200px;
}
.msg{
.message{
padding: 10px 0;
}
.btn{
.button{
color: #0080f0;
font-weight: bold;
}

@ -4,41 +4,56 @@ Component({
properties: {
hidden:{
type:Boolean,
value: false,
value: true,
},
show_code:{
type:Number,
value:1
},
invite_code: String,
auto_navigate:{
type:Number,
value:1
},
opentype:{
type:String,
value:"navigateTo"
}
},
data: {
invite_code:"",
identities:[],
hidden:false
hidden:true
},
methods: {
cancel: function (event) {
this.setData({ hidden: true });
},
update_invite_code: function ({ detail: { value } }) {
console.log(value);
this.setData({ invite_code: value });
},
update_identities: function ({ detail: { value } }) {
this.setData({ identities: value })
var data = {assistant_professor:"", professor:"",student:""}
console.log(value);
for(var identity of value)
data[identity] = 1
console.log(data);
this.setData(data)
},
join_course: function (event) {
const { invite_code, identities } = this.data;
let data = { invite_code: invite_code };
for (var identity of identities) {
data[identity] = 1;
}
app.api("courses.apply_to_join_course")({ ...data })
let { invite_code="", assistant_professor="", professor,student=""} = this.data;
console.log(this.data);
app.api("courses.apply_to_join_course")({ invite_code, assistant_professor, professor, student })
.then(res => {
console.log(res);
app.showMsg(res);
if (res.course_id){
wx.navigateTo({
url: `/course/pages/course/course?course_id=${res.course_id}`
if (res.course_id&&this.data.auto_navigate&&res.message.indexOf("助教申请")==-1){
app[this.data.opentype]({
url: `{course}?course_id=${res.course_id}`
});
}
this.triggerEvent("success");
this.cancel();
})
.catch(app.showError)

@ -1,9 +1,9 @@
<modal class="join_course" hidden="{{hidden}}" title="加入课堂" confirm-text="提交" cancel-text="取消" bindcancel="cancel" bindconfirm="join_course">
<input type='text' bindinput="update_invite_code" class="code-input" placeholder="邀请码" auto-focus/>
<checkbox-group bindchange="update_identities">
<modal class="join_course" wx:if="{{!hidden}}" title="加入课堂" confirm-text="提交" cancel-text="取消" bindcancel="cancel" bindconfirm="join_course">
<input type='text' bindinput="update_invite_code" value="{{invite_code}}" class="code-input {{show_code?'':'hidden'}}" placeholder="邀请码" auto-focus/>
<checkbox-group class="identities" bindchange="update_identities">
<text>身份:</text>
<lable class="identity"><checkbox value="professor"/>教师</lable>
<lable class="identity"><checkbox value="assistant_professor"/>助教</lable>
<lable class="identity"><checkbox value="student"/>学生</lable>
<checkbox class="identity" color="#00b0f0" disabled="{{assistant_professor}}" checked="{{professor}}" value="professor">教师</checkbox>
<checkbox class="identity" color="#00b0f0" disabled="{{professor}}" checked="{{assistant_professor}}" value="assistant_professor">助教</checkbox>
<checkbox class="identity" color="#00b0f0" checked="{{student}}" value="student">学生</checkbox>
</checkbox-group>
</modal>

@ -1,15 +1,17 @@
.code-input{
border-radius: 10rpx;
border-radius: 5px;
border: 1rpx solid;
height: 36px;
margin-bottom: 24rpx;
padding-left: 16rpx;
padding: 6px 10px;
}
lable.identity{
margin-right: 16rpx;
.identities{
padding-top: 8px;
display: flex;
}
.loading{
text-align:center;
padding: 14rpx 0;
.identity{
flex:auto;
}
.hidden{
display: none;
}

@ -1,5 +1,5 @@
<scroll-view wx:if="{{list.length>1}}" scroll-x="1" class="c-container" scroll-left="{{scrollLeft}}rpx" scroll-with-animation="1" style="width:{{width}}rpx;background:{{bg}}">
<view wx:for="{{list}}" wx:key="index" class="common c-{{type}} {{current == index ?'active':''}}" data-current="{{index}}" bindtap="switchNav" style="margin:0 {{mg}}rpx;{{_itemWidth>0?'width:'+_itemWidth+'rpx':''}} ">
<text class="common c-{{type}} {{current == index ?'active':''}}">{{item.text}}</text>
<view wx:for="{{list}}" wx:key="index" class="view common c-{{type}} {{current == index ?'active':''}}" data-current="{{index}}" bindtap="switchNav" style="margin:0 {{mg}}rpx;{{_itemWidth>0?'width:'+_itemWidth+'rpx':''}} ">
<text class="text common c-{{type}} {{current == index ?'active':''}}">{{item.text}}</text>
</view>
</scroll-view>

@ -5,53 +5,53 @@
font-size: 13px;
white-space: nowrap;
}
view.common{
.view.common{
color: dimgray;
text-align: center;
display: inline-block;
height: 34px;
line-height: 34px;
}
view.c-nav {
.view.c-nav {
box-sizing: border-box;
border-bottom: 2px solid transparent;
transition: all 0.26s ease;
}
view.c-nav.active{
.view.c-nav.active{
color: #0080f0;
font-size: 15px;
border-bottom: 2px solid #0080f0;
}
view.c-plain{
.view.c-plain{
transition: all 0.26s ease;
}
view.c-plain.active{
.view.c-plain.active{
color: #0080f0;
font-size: 15px;
}
view.c-cap{
.view.c-cap{
border-radius: 36px;
background: #dbdbdb;
padding: 0 14px
}
view.c-cap.active{
.view.c-cap.active{
background: #00a0f0;
color: white;
}
view.c-line{
.view.c-line{
position: relative;
}
text.c-line{
.text.c-line{
display: flex;
justify-content: center;
transition: all 0.26s ease;
}
text.c-line.active{
.text.c-line.active{
font-size: 15px;
color: #0080f0;
}
text.c-line::after{
.text.c-line::after{
transition: all 0.26s ease;
width: 0px;
height: 3.2px;
@ -60,7 +60,7 @@ text.c-line::after{
bottom: 0;
border-radius: 10px;
}
text.c-line.active::after{
.text.c-line.active::after{
width: 22px;
background: #00a0f0;
}

@ -2,33 +2,54 @@ if (!global.towxml)
global.towxml = require('../../towxml/index');
Component({
externalClasses: ['my-class'],
properties: {
nodes:{
type:Object,
optionalTypes:[String],
type:String,
observer:function(nodes){
if(typeof nodes=="string")
this.process(nodes);
this.process(nodes);
}
},
theme:{
type:String,
value:"light"
},
base:{
type:String,
value: "https://www.educoder.net/"
},
type:{
type:String,
value: ""
}
},
data: {
isRich:0
},
methods: {
process(nodes){
if(!nodes.match(/^\s*?<.+>.*<\/.+>\s *? $ /)){
nodes = nodes.replace(/(#+)/g, "$1 ").replace(/`$$(.*)$$`/g, "\$$1\$").replace(/`\$\$(.*)\$\$`/g, "\$$1\$");
nodes = global.towxml(nodes, "markdown", {base:this.data.base});
this.setData({nodes});
let {type} = this.data;
//console.log(type);
if(!type){
if (nodes.match(/<img .*src=.*>/))
type = "html"
else if (nodes.match(/^\s*<.+>.*<\/.+>/s))
type = "rich-text";
else if(nodes.match(/##+|\*.+\*|- |`|\$|\[.*\]\(.+\)|\|.+\|/))
type = "markdown";
else if(nodes.match(/<.+>.*<\/.+>|&nbsp/s))
type= "rich-text";
else
type = "plain";
}
if(type=="markdown"||type=="html"){
nodes = nodes.replace(/(#+)/g, "$1 ").replace(/`\$\$\s*(.*)\s*\$\$`/g, "$$$1$$").replace(/```latex\n(.*)\n```/g,"$$$$\n$1\n$$$$");
//console.log(nodes);
var _nodes = global.towxml(nodes, type, { theme:this.data.theme,base: this.data.base });
this.setData({_nodes, type});
}else{
this.setData({isRich:true})
this.setData({nodes, type})
}
}
}

@ -1,2 +1,5 @@
<rich-text wx:if="{{isRich}}" nodes="{{nodes}}"/>
<toxwml wx:else modes="{{nodes}}"/>
<view class="my-class">
<rich-text wx:if="{{type=='rich-text'}}" space="nbsp" nodes="{{nodes}}"/>
<towxml wx:elif="{{type=='markdown'||type=='html'}}" nodes="{{_nodes}}"/>
<text wx:elif="{{type=='plain'}}">{{nodes}}</text>
</view>

@ -0,0 +1,16 @@
Component({
properties: {
data:Object
},
data: {
eduImgDir:global.config.eduImgDir
},
attached(){
console.log(this.data);
},
methods: {
}
})

@ -0,0 +1,7 @@
<view class="tiding">
<image class="avatar" mode="scaleToFill" src="{{eduImgDir}}{{data.trigger_user.image_url}}"></image>
<view class="tiding-info">
<view class="name">{{data.trigger_user.name}} {{data.time}}</view>
<view class="content">{{data.content}}</view>
</view>
</view>

@ -0,0 +1,22 @@
.tiding{
display: flex;
padding: 12px;
background: white;
}
.avatar{
border-radius: 50px;
width: 50px;
height: 50px;
}
.tiding-info{
margin-left: 12px;
flex: 1 1 1px;
width: 1px;
}
.name{
color: dimgray;
font-size: 14px;
}
.content{
margin: 8px 0;
}

@ -2,8 +2,21 @@ const cloudDir = "cloud://educoder.6564-educoder-1300855313/";
const eduUrl = "https://www.educoder.net";
module.exports = global.config = {
versionCode: 2020022002,
version:"0.9.1",
version:"0.11.0",
/**
* A 课程-普通作业模块
* A 页面不存在时进入主页
* A referrerInfo 分析
* A 主页课堂菜单操作
* A error-page组件错误处理界面
* U 加入课堂对话框功能升级
* U 课堂页面错误处理
* U 课程邀请界面改进增加已停用时的图标
* U 改变小程序码生成接口为getWXACodeUnlimited
* F 试卷题目富文本显示异常
* D 隐藏发现页入口
*
*/
apiRoot:eduUrl+"/api/",
cloudDir,
eduUrl,

@ -1,17 +0,0 @@
<view class="container">
<text>课堂资源</text>
<view class="no-file-view">
<image hidden="{{files.length!=0 || loading}}" src="{{imgDir}}/blank2.png" class="no-file"></image>
</view>
<view class="file-list form-wrap">
<block wx:for="{{files}}" wx:for-item="file" wx:key="objectId">
<view class="file-item flex-wrap" bindtap="previewFile" data-url="{{file.url}}">
<text>{{file.title}}</text>
<text class="hint file-uploader">上传者:{{file.author.name}}</text>
</view>
</block>
</view>
</view>
<view wx:if="{{false}}" class="upload-file foot">
<button type="primary" size="mini" bindtap="upload">上传文件资源</button>
</view>

@ -1,4 +1,4 @@
const app = getApp();
Component({
properties: {
data:Object
@ -8,8 +8,11 @@ Component({
},
methods: {
enterDetail(){
let { work_id, homework_id, un_commit_work,name} = this.data.data;
app.navigateTo({
url: `{common-homework}?work_id=${work_id}&homework_id=${homework_id}&un_commit_work=${un_commit_work}&homework_name=${name}`
})
}
}
})

@ -1,5 +1,3 @@
<nav-bar list="{{navList}}" bindchange="switchNav"></nav-bar>
<scroll-view refresher-enabled="1" bindrefresherrefresh="onPullDownRefresh">
</scroll-view>
<view class="homework" bindtap="enterDetail">
<text>{{data.name}}</text>
</view>

@ -1 +1,5 @@
/* course/components/common-homework-item/common-homework-item.wxss */
.homework{
background: white;
padding: 12px;
border-radius: 4px;
}

@ -1,22 +0,0 @@
const app = getApp();
Component({
properties: {
course_id:Number,
refresh:{
type:Number,
observer:function(r){
if (r) {
this.onPullDownRefresh();
this.setData({ refresh: false });
}
}
}
},
data: {
},
methods: {
}
})

@ -1,2 +0,0 @@
<!--course/components/common-homework/common-homework.wxml-->
<text>course/components/common-homework/common-homework.wxml</text>

@ -1 +0,0 @@
/* course/components/common-homework/common-homework.wxss */

@ -0,0 +1,34 @@
const app = getApp();
Component({
properties: {
data:Object
},
data: {
},
methods: {
preview(){
let url = global.config.eduUrl + this.data.data.url;
if (this.data.data.content_type.startsWith("image")) {
wx.previewImage({
urls: [url]
});
return;
}
wx.showLoading({
title: '下载中',
})
wx.downloadFile({
url,
success: (res) => {
wx.openDocument({
filePath: res.tempFilePath,
fail: app.showError
});
},
fail: app.showError,
complete: wx.hideLoading
})
}
}
})

@ -0,0 +1,4 @@
<view class="file" bindtap="preview">
<text>{{data.title}}</text>
<text class="hint file-uploader">上传者:{{data.author.name}}</text>
</view>

@ -0,0 +1,11 @@
.file{
background: white;
padding: 10px;
border-radius: 4px;
overflow: hidden;
word-wrap: break-word;
}
.file-item text{
vertical-align: middle;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -4,7 +4,7 @@ Component({
course_id: {
type: Number
},
id: {
id_: {
type: Number
},
refresh:{
@ -41,30 +41,7 @@ Component({
.catch(console.error);
},
previewFile: function ({ currentTarget: { dataset:{url=""} } }) {
let ext = url.split(".").slice(-1)[0].toLowerCase();
if(["bmp","jpg","png","gif"].indexOf(ext)!=-1){
wx.previewImage({
urls: [url]
});
return;
}
wx.showLoading({
title: '下载中',
})
wx.downloadFile({
url: global.config.eduUrl + url,
success: (res) => {
wx.openDocument({
filePath: res.tempFilePath,
fail: app.showError
});
},
fail: app.showError,
complete: wx.hideLoading
})
},
onLoad: function (options) {
this.pull_files();
},

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"file-item":"/course/components/file-item/file-item"
}
}

@ -0,0 +1,14 @@
<view class="module">
<text>课堂资源</text>
<view class="no-file-view">
<image hidden="{{files.length!=0 || loading}}" src="{{imgDir}}/blank2.png" class="no-file"></image>
</view>
<view class="files">
<view class="file-wrap" wx:for="{{files}}" wx:key="id">
<file-item data="{{item}}"/>
</view>
</view>
</view>
<view wx:if="{{false}}" class="upload-file foot">
<button type="primary" size="mini" bindtap="upload">上传文件资源</button>
</view>

@ -1,19 +1,10 @@
/* pages/classdetail/classdetail.wxss */
.file-list{
display: flex;
flex-direction: column;
margin: 0 -12px;
margin-bottom: 40px;
}
.file-item{
background: white;
border-bottom: 1px solid #eee;
padding: 16rpx 16px;
position: relative;
}
.file-item text{
vertical-align: middle;
.module{
height: 100%;
overflow-y: scroll;
}
.file-wrap{
margin: 7px 6px;
}
.file-uploader{

@ -0,0 +1,45 @@
const app = getApp();
Component({
properties: {
course_id:Number,
id_:Number,
refresh:{
type:Number,
observer:function(r){
if (r) {
console.log("observer refresh")
this.refresh();
this.setData({ refresh: false });
}
}
}
},
data: {
list:[{text:"全部",order:""},{text:"未发布",order:0},{text:"提交中",order:1},{text:"补交中",order:2},{text:"匿评中",order:3},{text:"申诉中",order:4},{text:"已截止",order:5}]
},
attached(){
this.refresh();
},
methods: {
onSwitchNav({detail:{current, value}}){
console.log("switchNav")
if(!this.options)
this.options={};
this.options.order=value.order;
this.refresh();
},
refresh(){
let {course_id} = this.data;
console.log(this.options);
app.api("courses.homework_commons")({...this.options, course_id, type:1})
.then(res=>{
console.log(res);
this.setData({homeworks: res.homeworks});
}).catch(e=>{
app.showError(e);
console.error(e);
})
}
}
})

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"nav-bar": "/components/nav-bar/nav-bar",
"common-homework-item":"/course/components/common-homework-item/common-homework-item"
}
}

@ -0,0 +1,8 @@
<view class="module">
<nav-bar list="{{list}}" itemWidth="107" bindchange="onSwitchNav"/>
<scroll-view class="homeworks" scroll-y="1">
<view class="homework-wrap" wx:for="{{homeworks}}">
<common-homework-item data="{{item}}"/>
</view>
</scroll-view>
</view>

@ -29,7 +29,7 @@ Component({
course_id:{
type:Number
},
id:{
id_:{
type:Number
},
refresh:{

@ -1,4 +1,4 @@
<view class="container">
<view class="exercise-module">
<nav-bar list="{{navList}}" bindchange="switchNav"></nav-bar>
<scroll-view class="tab-box" scroll-y="1" refresher-enabled="{{true}}" bindrefresherrefresh="onPullDownRefresh">
<view class="no-content" wx:if="{{exercises.length==0&&!loading}}" class="no-content">
@ -22,6 +22,6 @@
</block>
<button type="primary" wx:if="{{course.is_admin}}" bindtap="create_exercise">发布试卷</button>
</scroll-view>
</view>

@ -1,9 +1,8 @@
.container{
.exercise-module{
height: 100%;
display: flex;
flex-direction: column;
}
.tab-box{
box-sizing: border-box;
flex: 1 1 10px;

@ -1,7 +1,12 @@
const app = getApp();
Page({
//status:[0,401,409]
Component({
properties:{
course_id:Number,
module_type:String,
},
data: {
status:0,
refresh:0,
nav_type:"navigateback",
module:null,
@ -11,11 +16,18 @@ Page({
hidden_modules: [] ,
statusBarHeight:20,
windowWidth:375,
eduImgDir: global.config.eduImgDir
eduImgDir: global.config.eduImgDir,
scenes:{
409:{
message:"你不是该课堂的成员",
btnText:"加入课堂"
}
}
},
methods:{
switchRole({target:{dataset:{role}}}){
if(!role) return;
app.api("courses.switch_to_"+role)({course_id: this.course_id})
app.api("courses.switch_to_"+role)({course_id: this.data.course_id})
.then(res=>{
this.onPullDownRefresh();
app.showMsg(res);
@ -34,7 +46,7 @@ Page({
wx.showActionSheet({
itemList: ["启用邀请码"],
success:res=>{
app.api("courses.set_invite_code_halt")({course_id: this.course_id})
app.api("courses.set_invite_code_halt")({course_id: this.data.course_id})
.then(res=>{
app.showMsg(res);
this.refresh({refresh:0});
@ -57,35 +69,49 @@ Page({
});
},
async pullCourse(){
let {course_id} = this;
let {course_id} = this.data;
let course = await app.api("courses.top_banner")({course_id});
this.setData({course});
return {course};
},
async pullModules(){
let { course_id } = this;
let { course_id } = this.data;
let data = await app.api("courses.left_banner")({ course_id });
this.setData(data);
return data;
},
onTapError({detail:{status, target}}){
console.log(target);
switch(status){
case 401:
return app.navigateTo({url:"{login}"});
case 409:
return this.setData({show_join_course: 1});
}
},
refresh({ refresh = 1 } = {}) {
this.setData({ refresh });
app.syncUser().then(res => {
this.pullCourse();
this.pullCourse().then(res=>{
this.setData({status:200})
})
.catch(e=>{
this.setData({status:e.code});
});
this.pullModules()
.then(res => {
console.log(res);
if (this.data.module)
if(this.data.module_type)
var module = res.course_modules.filter(i => i.type == this.data.module_type)[0]
else if (this.data.module)
var module = this.data.module;
else
var module = res.course_modules.filter(i => i.type == "exercise")[0];
this.setData({ module });
this.setData({ module, module_type:""});
});
})
},
onLoad: function (options) {
let course_id = this.course_id = options.course_id;
this.setData({course_id});
onLoad: function () {
wx.getSystemInfo({
success:res=>{
let { statusBarHeight, windowWidth} = res;
@ -100,12 +126,14 @@ Page({
this.refresh({refresh:0});
},
onShow: function () {
if(this.data.status!=200||this.data.status!=0)
this.refresh();
},
onReady:function(){
wx.showToast({
title: '向右滑有更多课堂模块哦',
icon:"none"
title: '右滑更多模块哦',
image:"../../images/move-right.png",
duration:2600
})
},
onPullDownRefresh(){
@ -114,5 +142,5 @@ Page({
onShareAppMessage: function () {
}
}
})

@ -1,8 +1,11 @@
{
"usingComponents": {
"nav-bar":"/components/nav-bar/nav-bar",
"exercise":"/course/components/exercise/exercise",
"attachment":"/course/components/attachment/attachment"
"exercise":"/course/modules/exercise/exercise",
"attachment":"/course/modules/attachment/attachment",
"common-homework":"/course/modules/common-homework/common-homework",
"join-course":"/components/modal/join-course/join-course",
"error-page":"/components/error-page/error-page"
},
"navigationStyle": "custom",
"navigationBarTextStyle": "white",

@ -59,13 +59,12 @@
</view>
<view bindtouchstart="{{handler.touchsHeader}}" bindtouchmove="{{handler.touchmBody}}" bindtouchend="{{handler.toucheBody}}" class="module-container">
<attachment wx:if="{{module.type=='attachment'}}" id="{{module.id}}" course_id="{{module.main_id}}" refresh="{{refresh}}"></attachment>
<exercise wx:elif="{{module.type=='exercise'}}" id="{{module.id}}" course_id="{{module.main_id}}" refresh="{{refresh}}"></exercise>
<attachment wx:if="{{module.type=='attachment'}}" id_="{{module.id}}" course_id="{{module.main_id}}" refresh="{{refresh}}"/>
<exercise wx:elif="{{module.type=='exercise'}}" id_="{{module.id}}" course_id="{{module.main_id}}" refresh="{{refresh}}"/>
<common-homework wx:elif="{{module.type=='common_homework'}}" id_="{{module.id}}" course_id="{{module.main_id}}" refresh="{{refresh}}"/>
<view wx:else style="height: 1000px;">sorry ╥﹏╥\n暂不支持[{{module.name}}]模块</view>
</view>
</view>
</view>
<error-page status="{{status}}" config="{{scenes}}" bindrefresh="onTapError"/>
<join-course hidden="{{!show_join_course}}" bindsuccess="refresh" auto_navigate="0"/>

@ -147,7 +147,6 @@ text.sep{
}
.module-container{
flex: 1 1 10px;
height: 10px;
overflow-y: scroll;
flex: 1 1 1px;
height: 1px;
}

@ -1,19 +1,25 @@
const app = getApp();
/**
* status:[404,-1]
*/
Page({
data: {
course:{
name:"**课堂邀请",
teacher_name:"点击最下方按钮",
teacher_school:"登陆后查看"
teacher_school:"登陆后查看更多",
invite_code:"登陆后查看"
},
imgDir:global.config.imgDir,
user:{},
status:0,
eduImgDir:global.config.eduImgDir
},
onImgError(e){
console.log("onImgError", e);
let path = this.getPageUrl();
wx.cloud.callFunction({ name: "openapi", data: { action:"getWXACode", path}})
let page = this.getPageUrl();
let scene = this.getScene();
wx.cloud.callFunction({ name: "openapi", data: { action:"getWXACodeUnlimited", page, scene}})
.then(res=>{
this.setData({invite_code_url:""});
this.setData({invite_code_url: res.result})
@ -25,47 +31,42 @@ Page({
});
},
onTapCode(){
let data = this.data.course.invite_code || this.data.options.invite_code;
if(this.data.course.code_halt)
return;
let data = this.data.course.invite_code || this.data.scene.invite_code;
wx.setClipboardData({
data
})
},
preview(){
if(this.data.course.code_halt)
return;
wx.previewImage({
urls: [this.data.invite_code_url],
})
},
joinCourse: function(event) {
//@todo 助教加入..
let invite_code = this.data.course.invite_code||this.data.options.invite_code;
let data = { invite_code, student: 1};
if (this.data.course.code_halt){
wx.showToast({
if (this.data.course.code_halt||!this.data.course.invite_code)
return wx.showToast({
title: '>︿<\n邀请码已经停用了',
icon:"none"
});
return;
}
app.api("courses.apply_to_join_course")({ ...data })
.then(res => {
app.showMsg(res);
wx.redirectTo({
url: "../course/course?course_id=" + res.course_id
});
})
.catch(app.showError)
this.setData({show_join_modal:1});
},
getPageUrl(){
let { course_id, _invite_code } = this.data.options;
let {invite_code=_invite_code} = this.data.course;
return app.getPageUrl(`{course_invite}?course_id=${course_id}&invite_code=${invite_code}`);
return app.getPageUrl(`{course_invite}`,"");
},
getScene(){
let { course_id} = this.data;
return `course_id=${course_id}`
},
getWxaCodeUrl(){
let url = this.getPageUrl();
return global.config.imgDir+"wxacode/"+ url.replace(/[\/?&]/g, "_")+".jpeg";
let page = this.getPageUrl();
let scene = this.getScene();
return global.config.imgDir+"wxacode/"+ (page+"?"+scene).replace(/[\/?&]/g, "_")+".jpeg";
},
pull_course(){
app.api("weapps.courses.basic_info")({ course_id:this.options.course_id })
app.api("weapps.courses.basic_info")({ course_id:this.data.course_id })
.then(({course}) => {
this.setData({ course, status: 200});
}).catch(e=>{
@ -74,13 +75,28 @@ Page({
});
},
onLoad: function (options) {
this.setData({options});
this.setData({status:1});
this.pull_course();
console.log("onLoad", options);
var course_id;
if(options.course_id)
course_id= options.course_id;
else if(options.scene){
var scene = {};
for (var item of decodeURIComponent(options.scene).split("&")){
var [k,v] = item.split("=")
scene[k]=v;
}
course_id = scene.course_id;
}else{
this.setData({status: 404});
return;
}
this.setData({ course_id, status: 1});
let invite_code_url = this.getWxaCodeUrl();
this.pull_course();
this.setData({ invite_code_url});
},
onShow:function(){
onShow:function(options){
console.log("onShow", options)
app.syncUser()
.then(({user})=>{
this.setData({user});

@ -1,6 +1,7 @@
{
"usingComponents": {
"require-login":"/components/require-login/require-login"
"require-login":"/components/require-login/require-login",
"join-course":"/components/modal/join-course/join-course"
},
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#56A9EF",

@ -6,10 +6,14 @@
<view class="school">{{course.teacher_school}}</view>
</view>
<view class="flex-col invite-display">
<view class="invite-code" bindtap="onTapCode">邀请码:{{course.invite_code||options.invite_code}}</view>
<image class="invite-code" mode="aspectFit" bindtap="preview" binderror="onImgError" show-menu-by-longpress src="{{invite_code_url}}"/>
<view class="invite-code" bindtap="onTapCode">邀请码:{{course.code_halt?'已停用':course.invite_code}}</view>
<view class="wxacode-wrap">
<image class="wxacode" mode="aspectFit" bindtap="preview" binderror="onImgError" show-menu-by-longpress="{{!course.code_halt}}" style="opacity:{{course.code_halt?0.26:1}}" src="{{invite_code_url}}"/>
<image wx:if="{{course.code_halt}}" class="code-halt" mode="aspectFit" src="{{imgDir}}code_halt.png"/>
</view>
<button open-type="share" size="mini" plain="1">发送分享</button>
</view>
<button wx:if="{{user.user_id!=2}}" class="join-button" bindtap="joinCourse">加入课堂</button>
<button wx:else class="join-button" bindtap="login">点击登陆</button>
</view>
<join-course hidden="{{!show_join_modal}}" show_code="0" invite_code="{{course.invite_code}}" opentype="redirectTo"></join-course>

@ -1,6 +1,7 @@
page{
display: flex;
flex-direction: column;
height: 100%;
}
.body{
flex: 1 1 10px;
@ -40,10 +41,18 @@ view.invite-code{
text-decoration: underline;
font-weight: bold;
}
image.invite-code{
.wxacode-wrap{
position: relative;
margin: 10px 0;
width: 200px;
height:200px;
}
image.code-halt,
image.wxacode{
position: absolute;
top: 0;
width: 200px;
height:200px;
margin: 10px 0;
}
.invite-display>button{
color: #0080f0;

@ -1,15 +1,27 @@
const app = getApp();
Component({
properties: {
data:Object
data:{
type:Object,
observer: function(data){
//console.log(data);
if(data.question_choices){
this.user_answers={};
for(var choice of data.question_choices)
this.user_answers[choice.choice_id] = choice.user_answer_boolean;
}
//console.log(this.user_answers);
}
}
},
data: {
},
methods: {
answer_choice_question: function ({ detail: { value }, currentTarget: { dataset } }) {
answer_choice_question: function (e) {
console.log(e, this.data);
let { detail: { value }, currentTarget: { dataset } }=e
console.log("answer_question");
console.log(value);
console.log(dataset);
@ -25,13 +37,28 @@ Component({
console.log(exercise_choice_id);
}
app.api("exercise_questions.exercise_answers")({ question_id: dataset.question_id, exercise_choice_id })
.then(res => { console.log("answer_question"); console.log(res); })
.catch(error => {
console.error(error);
wx.showToast({
title: error.toString(),
icon: "none"
.then(res => {
console.log("answer_question"); console.log(res);
if (!Array.isArray(exercise_choice_id))
exercise_choice_id = [exercise_choice_id];
for(var choice of this.data.data.question_choices){
if(exercise_choice_id.indexOf(choice.choice_id)==-1)
this.user_answers[choice.choice_id]=false;
else
this.user_answers[choice.choice_id]=true;
}
console.log(this.user_answers);
})
.catch(e => {
//console.error(e);
let {question_choices} = this.data.data;
question_choices = question_choices.map(i=>{
i.user_answer_boolean = this.user_answers[i.choice_id]
console.log(this.user_answers[i.choice_id]);
return i;
})
this.setData({"data.question_choices":question_choices})
app.showError(e)
});
},
}

@ -1,28 +1,24 @@
<view class="question">
<text class="hint">第{{question.q_position}}题</text>
<rich-text class="question-title" nodes="{{question.question_title}}" space="nbsp"></rich-text>
<view wx:if="{{question.question_type==0 || question.question_type==2}}">
<radio-group class="choices" bindchange="answer_choice_question" data-question_id="{{question.question_id}}">
<block wx:for="{{question.question_choices}}" wx:for-item="choice" wx:key="choice_id">
<radio disabled="{{exercise.user_exercise_status==1 || exercise.user_exercise_status==4}}" class="choice" checked="{{choice.user_answer_boolean}}" value="{{choice.choice_id}}">
<view class="choice">
<text class="choice-text">{{choice.choice_text}}</text>
<text wx:if="{{choice.standard_boolean}}" class="error standard-choice">正确答案</text>
</view>
</radio>
</block>
</radio-group>
</view>
<view wx:elif="{{question.question_type==1}}">
<checkbox-group class="choices" bindchange="answer_choice_question" data-question_id="{{question.question_id}}">
<block wx:for="{{question.question_choices}}" wx:for-item="choice" wx:key="choice_id">
<checkbox class="choice" disabled="{{exercise.user_exercise_status==1 || exercise.user_exercise_status==4}}" checked="{{choice.user_answer_boolean}}" value="{{choice.choice_id}}">
<view class="choice">
<text class="choice-text">{{choice.choice_text}}</text>
<text wx:if="{{choice.standard_boolean}}" class="error standard-choice">正确答案</text>
</view>
</checkbox>
</block>
</checkbox-group>
</view>
<view class="hint">第{{data.q_position}}题</view>
<rich-md my-class="title" nodes="{{data.question_title}}"/>
<radio-group class="choices" wx:if="{{data.question_type==0 || data.question_type==2}}" bindchange="answer_choice_question" data-question_id="{{data.question_id}}">
<block wx:for="{{data.question_choices}}" wx:for-item="choice" wx:key="choice_id">
<radio class="choice" color="#00b0f0" disabled="{{exercise.user_exercise_status==1 || exercise.user_exercise_status==4}}" checked="{{choice.user_answer_boolean}}" value="{{choice.choice_id}}">
<view class="choice-content">
<rich-md class="choice-text" nodes="{{choice.choice_text}}"/>
<text wx:if="{{choice.standard_boolean}}" class="error standard-choice">正确答案</text>
</view>
</radio>
</block>
</radio-group>
<checkbox-group class="choices" wx:elif="{{data.question_type==1}}" bindchange="answer_choice_question" data-question_id="{{data.question_id}}">
<block wx:for="{{data.question_choices}}" wx:for-item="choice" wx:key="choice_id">
<checkbox color="#00b0f0" class="choice" disabled="{{exercise.user_exercise_status==1 || exercise.user_exercise_status==4}}" checked="{{choice.user_answer_boolean}}" value="{{choice.choice_id}}">
<view class="choice-content">
<rich-md class="choice-text" nodes="{{choice.choice_text}}"/>
<text wx:if="{{choice.standard_boolean}}" class="error standard-choice">正确答案</text>
</view>
</checkbox>
</block>
</checkbox-group>
</view>

@ -1,50 +1,18 @@
.question{
background: white;
margin: 20rpx -6rpx;
padding: 4rpx 20rpx 22rpx 22rpx;
border-radius: 18rpx;
}
.question-title{
display: inline-block;
margin: 5rpx 0rpx 12rpx 0rpx;
}
@import "../question-common.wxss";
.choices{
display: flex;
flex-direction: column;
}
checkbox.choice{
.choice{
margin-bottom: 12rpx;
}
view.choice{
.choice-content{
width: 600rpx;
}
.main-input{
height: 120rpx;
margin: 18rpx 0 4rpx 18rpx;
border: 1rpx solid lightgray;
border-radius: 12rpx;
padding: 12rpx 10rpx;
}
view.null-input{
align-items: center;
}
input.null-input{
border: 1rpx solid lightgray;
padding: 12rpx 6rpx;
margin: 6rpx 10rpx;
border-radius: 10rpx;
}
.standard-choice{
margin-left: 24rpx;
}
standard-null-input{
align-items: center;
}

@ -1,14 +1,13 @@
// exercise/components/main-question/main-question.js
const app = getApp();
Component({
properties: {
data:Object
},
data: {
},
methods: {
answer_main_question: function ({ detail: { value }, currentTarget: { dataset } }) {
answer_main_question: function ({detail: {value}, currentTarget: { dataset } }) {
console.log("answer_main_question");
console.log(value);
console.log(dataset);

@ -1,4 +1,6 @@
{
"component": true,
"usingComponents": {}
"usingComponents": {
"rich-md": "/components/rich-md/rich-md"
}
}

@ -1,11 +1,13 @@
<view>
<view class="question">
<view class="hint">第{{data.q_position}}题</view>
<rich-md my-class="title" nodes="{{data.question_title}}"/>
<textarea disabled="{{exercise.user_exercise_status==1 || exercise.user_exercise_status==4}}" class="main-input"
placeholder="输入答案"
bindblur="answer_main_question"
value="{{question.user_answer[0]||''}}"
data-question_id="{{question.question_id}}">
value="{{data.user_answer[0]||''}}"
data-question_id="{{data.question_id}}">
</textarea>
<view wx:if="{{question.standard_answer}}" class="standard-main-input">
<view wx:if="{{data.standard_answer}}" class="standard-main-input">
<text class="hint">参考答案:</text>
<text class="error">{{question.standard_answer[0]||'暂无'}}</text>
</view>

@ -1 +1,10 @@
/* exercise/components/main-question/main-question.wxss */
@import "../question-common.wxss";
.main-input{
height: 120rpx;
margin: 18rpx 0 4rpx 18rpx;
border: 1rpx solid lightgray;
border-radius: 12rpx;
padding: 12rpx 10rpx;
}

@ -1,24 +1,23 @@
const app = getApp();
Component({
properties: {
data:Object
},
data: {
},
methods: {
answer_null_question: function ({ detail: { value }, currentTarget: { dataset } }) {
answer_null_question: function ({ detail: { value }, currentTarget: { dataset:{question_id, exercise_choice_id}} }) {
console.log("answer_main_question");
console.log(value);
console.log(dataset);
app.api("exercise_questions.exercise_answers")({ question_id: dataset.question_id, exercise_choice_id: dataset.exercise_choice_id, answer_text: value })
.then(res => { console.log("answer_main_question"); console.log(res); })
.catch(error => {
console.error(error);
wx.showToast({
title: error.toString(),
icon: "none"
app.api("exercise_questions.exercise_answers")({ question_id, exercise_choice_id, answer_text: value })
.then(res => {
console.log("answer_main_question"); console.log(res);
})
.catch(e => {
console.error(e);
app.showError(e);
});
},
}

@ -1,4 +1,6 @@
{
"component": true,
"usingComponents": {}
"usingComponents": {
"rich-md": "/components/rich-md/rich-md"
}
}

@ -1,18 +1,18 @@
<view>
<block wx:for="{{question.null_inputs}}" wx:for-item="null_input">
<view class="null-input flex-wrap">
<text class="hint">填空{{null_input.choice_id}}</text>
<input disabled="{{exercise.user_exercise_status==1 || exercise.user_exercise_status==4}}" class="null-input"
placeholder="输入填空{{null_input.choice_id}}答案"
data-question_id="{{question.question_id}}"
data-exercise_choice_id="{{null_input.choice_id}}"
value="{{null_input.answer_text}}"
<view class="question">
<view class="hint">第{{data.q_position}}题</view>
<rich-md my-class="title" nodes="{{data.question_title}}"/>
<view wx:for="{{data.multi_count}}" class="input-wrap">
<text class="hint">第{{index+1}}空</text>
<input class="null-input" disabled="{{exercise.user_exercise_status==1 || exercise.user_exercise_status==4}}"
placeholder="输入第{{index+1}}空的答案"
data-question_id="{{data.question_id}}"
data-exercise_choice_id="{{index+1}}"
value="{{data.user_answer[index].answer_text||''}}"
bindblur="answer_null_question">
</input>
</view>
</block>
<view wx:if="{{question.standard_answer}}" class="standard-null-inputs">
<view class="standard-null-input flex-wrap" wx:for="{{question.standard_answer}}" wx:for-item="answer">
</input>
</view>
<view wx:if="{{data.standard_answer}}" class="standard-null-inputs">
<view class="standard-null-input" wx:for="{{question.standard_answer}}" wx:for-item="answer">
<text class="hint">第{{answer.choice_id}}空答案:</text>
<text class="error" style="padding-top: 12rpx;">{{answer.answer_text}}</text>
</view>

@ -1 +1,19 @@
/* exercise/components/null-question/null-question.wxss */
@import "../question-common.wxss";
.input-wrap{
display: flex;
align-items: center;
}
.null-input{
flex: auto;
border: 1rpx solid lightgray;
padding: 10rpx 12rpx;
margin: 6rpx 10rpx;
border-radius: 10rpx;
}
standard-null-input{
align-items: center;
display: flex;
}

@ -0,0 +1,14 @@
.question{
background: white;
padding: 4rpx 20rpx 22rpx 22rpx;
border-radius: 18rpx;
}
.hint{
padding: 6px;
font-size: 15px;
color: #0080f0;
}
.title>text,.title>rich-text{
margin: 5rpx 6rpx 12rpx 6rpx;
display: block;
}

@ -0,0 +1,16 @@
Component({
properties: {
data:Object
},
data: {
},
methods: {
}
})

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"rich-md": "/components/rich-md/rich-md"
}
}

@ -0,0 +1,5 @@
<view class="question">
<view class="hint">第{{data.q_position}}题</view>
<rich-md c-class="title" nodes="{{data.question_title}}"/>
<text class="hint">对不起,暂时不支持实训题 ╥﹏╥ </text>
</view>

@ -10,91 +10,13 @@ Page({
app.api("exercises.start_answer")({exercise_id: this.exercise_id})
.then(res=>{
console.log("pull questions");
console.log(res);
this.setData({exercise: res.exercise});
if (!res.exercise_questions){
if(res.status==401)
wx.showToast({
title: '请登陆后重试',
icon: "none"
})
return;
}
let questions = res.exercise_questions;
for(var i=0;i<questions.length;i++){
if (questions[i]["question_type"]==3){
let null_inputs=[];
for (var j = 1; j<= questions[i]["multi_count"];j++){
var user_answer = questions[i]["user_answer"].filter(answer=>answer.choice_id==j)[0]||{};
console.log(user_answer);
null_inputs.push({choice_id:j, answer_text:user_answer.answer_text||""});
console.log(null_inputs);
}
questions[i]["null_inputs"] = null_inputs;
console.log(questions);
}
}
this.setData({ exercise_questions: questions, loading: false});
console.log(this.data);
}).catch(error => {
console.error(error);
wx.showToast({
title: error.toString(),
icon: "none",
duration: 5000
})
});
},
answer_null_question: function ({ detail: { value }, currentTarget: { dataset } }){
console.log("answer_main_question");
console.log(value);
console.log(dataset);
app.api("exercise_questions.exercise_answers")({ question_id: dataset.question_id, exercise_choice_id:dataset.exercise_choice_id, answer_text: value })
.then(res => { console.log("answer_main_question"); console.log(res); })
.catch(error => {
console.error(error);
wx.showToast({
title: error.toString(),
icon: "none"
})
});
},
answer_main_question: function ({ detail: { value }, currentTarget: { dataset }}){
console.log("answer_main_question");
console.log(value);
console.log(dataset);
app.api("exercise_questions.exercise_answers")({ question_id: dataset.question_id, answer_text: value })
.then(res => { console.log("answer_main_question"); console.log(res); })
.catch(e => {
console.error(e);
//console.log(res);
this.setData({ exercise: res.exercise, exercise_questions: res.exercise_questions, loading: false});
}).catch(e => {
this.setData({status:e.code});
app.showError(e);
});
},
answer_choice_question: function({detail: {value}, currentTarget: {dataset}}){
console.log("answer_question");
console.log(value);
console.log(dataset);
let exercise_choice_id;
if(Array.isArray(value)){
exercise_choice_id = [];
for(var i of value){
exercise_choice_id.push(parseInt(i));
}
console.log(exercise_choice_id);
}else{
exercise_choice_id = parseInt(value);
console.log(exercise_choice_id);
}
app.api("exercise_questions.exercise_answers")({ question_id: dataset.question_id, exercise_choice_id})
.then(res=>{console.log("answer_question");console.log(res);})
.catch(error=>{
console.error(error);
wx.showToast({
title: error.toString(),
icon: "none"
})
});
},
save_exercise: function({show_loading=true}={}){
if(show_loading){
wx.showLoading({
@ -141,13 +63,12 @@ Page({
},
onLoad: function (options) {
this.exercise_id = options.exercise_id;
this.course_name = options.exercise_name;//todo finish
this.course_name = options.exercise_name;
this.pull_questions();
},
onShow: function () {
if(this.data.loading){
this.pull_questions();
}
},
onHide: function () {

@ -2,6 +2,8 @@
"usingComponents": {
"choice-question":"/exercise/components/choice-question/choice-question",
"main-question": "/exercise/components/main-question/main-question",
"null-question": "/exercise/components/null-question/null-question"
}
"null-question": "/exercise/components/null-question/null-question",
"shixun-question":"/exercise/components/shixun-question/shixun-question"
},
"navigationBarTitleText": "试卷"
}

@ -1,14 +1,15 @@
<view class="container">
<view class="question-list">
<view class="question-wrap" wx:for="{{exercise_questions}}" wx:key="question_id">
<question-item data="{{item}}"/>
<view wx:if="{{question.question_type==5}}">
<text class="hint">暂不支持实训题...</text>
</view>
</view>
<page-meta>
<navigation-bar title="{{exercise.exercise_name}}"/>
</page-meta>
<scroll-view scroll-y="1" class="questions">
<view class="question-wrap" wx:for="{{exercise_questions}}" wx:key="question_id">
<choice-question id="q-{{item.question_id}}" wx:if="{{item.question_type<3}}" data="{{item}}"/>
<null-question id="q-{{item.question_id}}" wx:elif="{{item.question_type==3}}" data="{{item}}"/>
<main-question id="q-{{item.question_id}}" wx:elif="{{item.question_type==4}}" data="{{item}}"/>
<shixun-question id="q-{{item.question_id}}" wx:elif="{{item.question_type==5}}" data="{{item}}"/>
</view>
</view>
<cover-view wx:if="{{exercise.user_exercise_status!=1 && exercise.user_exercise_status!=4}}" hidden="{{loading}}" class="foot flex-wrap" >
</scroll-view>
<view wx:if="{{exercise.user_exercise_status!=1 && exercise.user_exercise_status!=4}}" hidden="{{loading}}" class="foot flex-wrap" >
<button class="save operation" catchtap="save_exercise">保存</button>
<button class="commit operation" catchtap="commit_exercise">交卷</button>
</cover-view>
</view>

@ -1,10 +1,12 @@
page{
display: flex;
flex-direction: column;
height:100%;
}
.foot{
position: fixed;
flex:none;
width: 100%;
align-items: center;
background: white;
bottom: 0;
z-index: 9;
}
.operation{
color: white;
@ -18,4 +20,11 @@
}
.container{
padding-bottom: 40px;
}
.question-wrap{
margin: 8px 10px;
}
.questions{
flex: 1 1 1px;
height: 1px;
}

@ -22,13 +22,14 @@ Page({
let end_time = getNextWeekFormatDate() + " " + getNowFormatTime();
//end_time = end_time.replace("-11", "-12");
app.api("courses.exercises.publish")({
course_id: this.course_id, exercise_ids: [this.exercise_id],
course_id: this.course_id, check_ids: [this.exercise_id],
end_time: end_time
}).then(res=>{
console.log(res);
app.showMsg(res);
wx.navigateBack({
delta: 1
})
});
}
)
},
@ -41,8 +42,8 @@ Page({
})
return;
}
wx.navigateTo({
url: `../question_setting/question_setting?exercise_id=${this.exercise_id}`,
app.navigateTo({
url: `{question_setting}?exercise_id=${this.exercise_id}`,
})
},
create_exercise: function({detail:{value}}){
@ -83,6 +84,9 @@ Page({
this.intent = options.intent;
this.course_id = options.course_id;
this.exercise_id = options.exercise_id;
},
onShow: function () {
if (this.exercise_id) {
app.api("exercises.edit")({ exercise_id: this.exercise_id })
.then(res => {
@ -94,37 +98,8 @@ Page({
})
})
}
},
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 908 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save