增加实训作业模块与课堂动态模块

* A 菜单的删除课堂
 * A 课堂动态模块
 * A 实训作业模块
 * A 试卷封面,通知栏进入试卷
 * A 体验版开发版可以切换切换开发环境与发布环境
 * F 课堂邀请界面登录按钮bug
 * F 微信灰度API promise化产生的bug
 * F 使用style:v2后样式问题
 * F 登录界面bug
master
unknown 5 years ago
parent 5119e4f865
commit da974380fb

@ -1,3 +1,22 @@
## v0.13.0
* A 菜单的删除课堂
* A 课堂动态模块
* A 实训作业模块
* A 试卷封面,通知栏进入试卷
* A 体验版开发版可以切换切换开发环境与发布环境
* F 课堂邀请界面登录按钮bug
* F 微信灰度API promise化产生的bug
* F 使用style:v2后样式问题
* F 登录界面bug
## v0.12.2
* A 剪切板邀请码自动读取
* A 首页点击搜索自动进入所在模块相应类目
* U 登录界面、用户界面优化
* U 更新机制优化
* F 进入搜索页面nav标题错误
* F 登录后我的实训不自动刷新
## v0.12.1
* A 新通知红点标注,点击后跳转
* A 长段代码预览

@ -1,9 +1,14 @@
const app = getApp();
const {key:_key} = require("../../../js/client");
const key = {
save_password: "we,nd;ke;hcy",
login:"login",
password: "Fie[Rxu[Eu?ua;c"
login: "login",
password: "Fie[Rxu[Eu?ua;c",
_password:_key.password
}
Page({
data: {
imgDir: global.config.imgDir,
@ -12,10 +17,41 @@ Page({
action_text:{login:"登录",register:"注册", reset:"找回密码"},
pos:{login:1, register:2, reset:3}
},
cache:{},
onLogoLoad(){
this.setData({ logoLoaded: 1});
},
onLoginBlur({detail:{value:login}}){
this.validLogin(login);
},
validLogin(login){
if(!login) {
return this.setData({showtip:0});
}
let {action} = this.data;
let type = action=="register"?1:2;
console.log(this.cache.login, this.cache.type, login, type);
if(this.cache.login==login&&this.cache.type==type) return;
app.api("accounts.valid_email_and_phone")({
login, type,
complete: res => {
this.cache.type = type;
this.cache.login = login;
}
})
.then(res=>{
this.setData({hasError:0});
})
.catch(e=>{
var hasError = e.message.indexOf("网络")!=-1?2:1;
this.setData({ hasError, error: e.message.replace(/\n/g," ") });
})
},
login_test(){
var data = {login:"educoder_weapp@126.com", password:"abcdefgh"};
this.setData(data);
this.login(data);
this.setStorage({...data,save_password:1});
},
login({login, password, showToast=1}){
app.api("accounts.login")({login,password})
@ -70,7 +106,6 @@ Page({
})
},
clearCount(id){
console.log("clearCount", id);
clearInterval(id);
this.setData({code_status:0, code_button_text:"获取验证码"});
},
@ -82,50 +117,37 @@ Page({
return this.clearCount(id);
this.setData({code_button_text:count-- + "秒后重试"})
}, 1000);
console.log("id",id);
return id;
},
onSubmit({detail:{value, target}}){
console.log("onSubmit", value, target, this.action);
console.log(this.checkInput({value, action:target.id}));
if(!this.checkInput({value, action:target.id}))
return;
console.log("target.id")
if (target.id == "code")
return this.getCode(value);
console.log("setAction", this.data);
if (target.id != this.data.action)
return this.setAction(target.id);
console.log("setStorage")
if (target.id != this.data.action){
this.setAction(target.id);
return this.validLogin(value.login);
}
this.setStorage(value);
console.log("callapi", value);
this[target.id](value);
},
checkInput({value, action}){
if(action!=this.data.action && action!="code")
return true;
if (!value.login)
return wx.showToast({
title: '请输入邮箱或手机号', icon: "none"
});
return wx.showToast({title: '请输入邮箱或手机号', icon: "none"}) && false;
if(action=="code")
return true;
if (!value.password)
return wx.showToast({
title: '请输入密码', icon: "none"
});
return wx.showToast({title: '请输入密码', icon: "none"}) && false;
if(action=="login")
return true;
if(!value.code)
return wx.showToast({
title: '请输入验证码',icon:"none"
});
return wx.showToast({ title: '请输入验证码', icon: "none" }) && false;
if(action=="register")
return true;
if(!value.password_confirmation)
return wx.showToast({
title: '请再次输入密码',icon:"none"
});
return wx.showToast({title: '请再次输入密码',icon:"none"}) && false;
return true;
},
setAction(action){
@ -135,16 +157,22 @@ Page({
let tmp = pos[action];
pos[action] = pos[this.data.action];
pos[this.data.action] = tmp;
/*if(Math.random()>0.5){
for(var k in pos){
if(pos[k]!=1)
pos[k] = pos[k]==2?3:2;
}
}*/
this.setData({pos, action});
},
onLoad: function (options) {
let {action="login"} = options;
this.setAction({action});
this.setAction(action);
this.getStorage();
},
setStorage({login, password, save_password}){
wx.setStorageSync(key.login, login);
wx.setStorageSync("_password", password);
wx.setStorageSync(key._password, password);
wx.setStorageSync(key.save_password, save_password);
if(save_password)
wx.setStorageSync(key.password, password);

@ -1,18 +1,21 @@
<page-meta>
<navigation-bar title="{{action_text[action]}}" />
</page-meta>
<view class="head-error {{hasError?'':'hidden'}}">
<text>{{error}}</text>
</view>
<view class="container">
<image class="logo" bindlongpress="login_test" src="{{imgDir}}educoder.png" mode="aspectFit"></image>
<image class="logo {{logoLoaded?'':'hidden'}}" bindlongpress="login_test" src="{{imgDir}}educoder.png" mode="aspectFit" bindload="onLogoLoad"></image>
<form class="account-form" bindsubmit="onSubmit">
<view class="inputs">
<view class="input-wrap">
<input name="login" value="{{login}}" placeholder="邮箱或手机号">
<input name="login" bindblur="onLoginBlur" value="{{login}}" placeholder="邮箱或手机号">
</input>
</view>
<view class="input-wrap {{action!='login'?'':'hidden'}}">
<input name="code" placeholder="验证码">
</input>
<button id="code" type="main" form-type="submit" loading="{{code_status==2}}" disabled="{{code_status}}" class="obtain-code">
<button id="code" type="main" size="mini" form-type="submit" loading="{{code_status==2}}" disabled="{{code_status||hasError}}" class="obtain-code">
{{code_button_text}}
</button>
</view>
@ -31,13 +34,13 @@
</view>
<view class="actions">
<view class="pos{{pos.login}}">
<button id="login" form-type="submit">登录</button>
<button id="login" disabled="{{hasError==1&&pos.login==1}}" form-type="submit">登录</button>
</view>
<view class="pos{{pos.register}}">
<button id="register" form-type="submit">注册</button>
<button id="register" disabled="{{hasError==1&&pos.register==1}}" form-type="submit">注册</button>
</view>
<view class="pos{{pos.reset}}">
<button id="reset" form-type="submit">{{pos.reset==1?'重置密码':'忘记密码'}}</button>
<button id="reset" disabled="{{hasError==1&&pos.reset==1}}" form-type="submit">{{pos.reset==1?'重置密码':'忘记密码?'}}</button>
</view>
</view>
</form>

@ -1,11 +1,30 @@
page{
min-height: 100%;
}
.head-error{
position: fixed;
background: #cb3b6a;
color: white;
top: 0;
left: 0;
right: 0;
transition: 0.6s all ease;
height: 28px;
display: flex;
font-size: 15px;
justify-content: center;
align-items: center;
}
view.head-error.hidden{
opacity: 0;
max-height: auto;
}
.logo{
width:64px;
height: 64px;
display: block;
margin: 12px auto;
margin: 30px auto 8px auto;
transition: 1s all ease;
}
.checkbox-wrap,.input-wrap{
transition: 1s all ease;
@ -32,11 +51,15 @@ page{
.obtain-code{
margin-left: 12px!important;
white-space: nowrap;
display: flex!important;
justify-content: center;
align-items: center;
flex: none;
}
.hidden{
.input-wrap.hidden{
max-height: 0px;
}
switch.no-login.hidden{
image.hidden,switch.no-login.hidden{
opacity: 0;
}
switch.no-login{
@ -62,6 +85,10 @@ switch.no-login{
background: #00b0f0;
color:white;
}
.pos1>button[disabled]{
background: #00b0f0aa;
color: white;
}
.actions>.pos2{
top:64px;
}
@ -92,4 +119,4 @@ navigator.agreement{
}
text.agreement{
text-decoration: underline;
}
}

@ -1,4 +1,4 @@
// miniprogram/account/pages/profile/profile.js
Page({
/**

@ -0,0 +1,186 @@
const app = getApp();
const key = {
save_password: "we,nd;ke;hcy",
login: "login",
password: "Fie[Rxu[Eu?ua;c"
}
Page({
data: {
imgDir: global.config.imgDir,
action: "login",
code_button_text: "获取",
action_text: { login: "登录", register: "注册", reset: "找回密码" },
pos: { login: 1, register: 2, reset: 3 },
signUp: 1,
logIn:0
},
log_In: function (event) {
this.setData({
signUp: 0,
logIn: 1
})
},
sign_Up: function (event) {
this.setData({
signUp: 1,
logIn: 0
})
},
login_test() {
var data = { login: "educoder_weapp@126.com", password: "abcdefgh" };
this.setData(data);
this.login(data);
},
login({ login, password, showToast = 1 }) {
app.api("accounts.login")({ login, password })
.then(res => {
res.message = "登录成功";
if (showToast)
app.showMsg(res);
this.navBack();
})
.catch(e => {
if (showToast)
app.showError(e);
})
},
register({ login, password, code }) {
app.api("accounts.register")({ login, password, code })
.then(res => {
app.showMsg(res);
this.navBack();
}).catch(e => {
app.showError(e);
})
},
reset({ login, password: new_password, password_confirmation: new_password_confirmation, code, no_login }) {
app.api("accounts.reset_password")({ login, new_password, new_password_confirmation, code })
.then(res => {
res.message = "重置成功";
app.showMsg(res);
if (!no_login)
this.login({ login, password: new_password, showToast: 0 });
})
.catch(e => {
app.showError(e);
})
},
getCode({ login }) {
if (this.data.action == "register")
var type = 1;
else if (this.data.action == "reset")
var type = 2;
else
return;
this.setData({ code_status: 2, code_button_text: "发送中" });
app.api("accounts.get_verification_code")({ login, type })
.then(res => {
res.message = "发送成功";
this.countDown();
app.showMsg(res);
}).catch(e => {
app.showError(e);
this.setData({ code_status: 0, code_button_text: "获取验证码" })
})
},
clearCount(id) {
console.log("clearCount", id);
clearInterval(id);
this.setData({ code_status: 0, code_button_text: "获取验证码" });
},
countDown() {
var count = 60;
this.setData({ code_status: 1, code_button_text: count-- + "秒后重试" });
var id = setInterval(() => {
if (count <= 0)
return this.clearCount(id);
this.setData({ code_button_text: count-- + "秒后重试" })
}, 1000);
console.log("id", id);
return id;
},
onSubmit({ detail: { value, target } }) {
console.log("onSubmit", value, target, this.action);
console.log(this.checkInput({ value, action: target.id }));
if (!this.checkInput({ value, action: target.id }))
return;
console.log("target.id")
if (target.id == "code")
return this.getCode(value);
console.log("setAction", this.data);
if (target.id != this.data.action)
return this.setAction(target.id);
console.log("setStorage")
this.setStorage(value);
console.log("callapi", value);
this[target.id](value);
},
checkInput({ value, action }) {
if (action != this.data.action && action != "code")
return true;
if (!value.login)
return wx.showToast({
title: '请输入邮箱或手机号', icon: "none"
});
if (action == "code")
return true;
if (!value.password)
return wx.showToast({
title: '请输入密码', icon: "none"
});
if (action == "login")
return true;
if (!value.code)
return wx.showToast({
title: '请输入验证码', icon: "none"
});
if (action == "register")
return true;
if (!value.password_confirmation)
return wx.showToast({
title: '请再次输入密码', icon: "none"
});
return true;
},
setAction(action) {
let { pos } = this.data;
if (!(action in pos))
return;
let tmp = pos[action];
pos[action] = pos[this.data.action];
pos[this.data.action] = tmp;
this.setData({ pos, action });
},
onLoad: function (options) {
let { action = "login" } = options;
this.setAction({ action });
this.getStorage();
},
setStorage({ login, password, save_password }) {
wx.setStorageSync(key.login, login);
wx.setStorageSync("_password", password);
wx.setStorageSync(key.save_password, save_password);
if (save_password)
wx.setStorageSync(key.password, password);
else
wx.clearStorageSync(key.password);
},
getStorage() {
let save_password = wx.getStorageSync(key.save_password);
if (save_password !== 0)
save_password = 1;
let login = wx.getStorageSync(key.login);
if (save_password)
var password = wx.getStorageSync(key.password);
else
var password = "";
this.setData({ save_password, login, password });
},
navBack() {
setTimeout(() => {
wx.navigateBack({
delta: 1
});
}, 500);
}
})

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

@ -0,0 +1,70 @@
<page-meta>
<navigation-bar title="{{action_text[action]}}" />
</page-meta>
<view class="container" wx:if="{{!signUp && logIn}}">
<view class="block_blueBig">
<view class="white_big" bindtap="log_In">注册</view>
<form class="account-form" bindsubmit="onSubmit">
<view class="inputs">
<view class="input-wrap">
<image src="../../../images/denglu.png" class="mini_button"></image>
<input class="input" name="login" value="{{login}}" placeholder="邮箱或手机号"></input>
</view>
<view class="input-wrap">
<image src="../../../images/yanzhengma.png" class="mini_button"></image>
<input class="input" name="code" placeholder="验证码"></input>
<button plain id="code" form-type="submit" loading="{{code_status==2}}" disabled="{{code_status}}" style="width: 100rpx;">
{{code_button_text}}
</button>
</view>
<view class="input-wrap">
<image src="../../../images/suo.png" class="mini_button"></image>
<input password name="password" value="{{password}}" placeholder="请输入密码"></input>
</view>
<view class="input-wrap {{action=='reset'?'':'hidden'}}">
<image src="../../../images/suo.png" class="mini_button"></image>
<input password name="password_confirmation" placeholder="请再次输入密码"></input>
</view>
<view class="checkbox-wrap">
<switch type="checkbox" name="save_password" color="#00b0f0" checked="{{save_password}}">保存密码</switch>
</view>
</view>
<button class="register" id="register" form-type="submit" style="width:100%">注 册</button>
</form>
</view>
<view class="white_little block_red" bindtap="change" bindtap="sign_Up">登录</view>
</view>
<view class="container" wx:else>
<view class="block_blue">
<view class="white_little" bindtap="log_In">注册</view>
</view>
<view class="white_big">登录</view>
<form class="account-form" bindsubmit="onSubmit">
<view class="inputs">
<view class="input-wrap">
<image src="../../../images/denglu.png" class="mini_button"></image>
<input class="input" name="login" value="{{login}}" placeholder="邮箱或手机号"></input>
</view>
<view class="input-wrap">
<image src="../../../images/suo.png" class="mini_button"></image>
<input class="input" password name="password" value="{{password}}" placeholder="请输入密码"></input>
</view>
</view>
<view class="check_row">
<view class="save_password">
<switch type="checkbox" name="save_password" color="#00b0f0" checked="{{save_password}}">保存密码</switch>
</view>
<navigator class="reset" >忘记密码</navigator>
</view>
<button id="login" form-type="submit" class="login" style="width:100%">登 录</button>
</form>
</view>
<view class="foot">
<navigator class="agreement" hover-class="none" url="/account/pages/agreement/agreement">
登录即代表您同意 <text class="color-main agreement">用户协议</text>
</navigator>
</view>

@ -0,0 +1,141 @@
page{
height: 100%;
background-image: linear-gradient(to bottom left,#7BCBFA, #EF7FAE);
color: white;
}
.container{
transition: 1s all ease;
width: 100%;
height: 100%;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
}
.block_blueBig{
transition: 1s all ease;
width: 100%;
background: #67AFF3;
border-radius: 0px 0px 70rpx 70rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.white_big{
transition: 1s all ease;
font-size: 80rpx;
font-weight: bold;
padding: 40rpx 0rpx;
}
.block_blue{
transition: 1s all ease;
width: 100%;
height: 250rpx;
background: #67AFF3;
border-radius: 0px 0px 100% 100%;
font-size: 50rpx;
font-weight: bold;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.account-form{
transition: 1s all ease;
width: 85%;
}
.inputs{
transition: 1s all ease;
margin-bottom: 50rpx;
}
.input-wrap{
transition: 1s all ease;
padding: 10px;
margin-bottom: 30rpx;
display: flex;
align-items: center;
border: 1px white solid;
border-radius: 20px;
}
.input{
transition: 1s all ease;
white-space: nowrap;
width: 100%;
}
.mini_button{
transition: 1s all ease;
width: 48rpx;
height: 45rpx;
padding-right: 20rpx;
padding-left: 10rpx;
}
button[plain] {
transition: 1s all ease;
border: 0;
padding: 0;
margin: 0;
color: white;
}
.white_little{
transition: 1s all ease;
font-size: 50rpx;
font-weight: bold;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.check_row{
transition: 1s all ease;
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 60rpx;
}
.login{
transition: 1s all ease;
width: 100%;
padding: 8px;
color: #F54171;
font-weight: 400;
border-radius: 20px;
box-shadow: #F54171 -1px 1px 1rpx;
}
.register{
transition: 1s all ease;
width: 100%;
padding: 8px;
font-weight: 400;
border-radius: 20px;
box-shadow: #2190F3 -1px 1px 1rpx;
color: #2190F3;
margin-bottom: 40rpx;
}
.foot{
transition: 1s all ease;
position: fixed;
bottom:0px;
width: 100%;
display: flex;
}
navigator.agreement{
transition: 1s all ease;
margin: 10px auto;
font-size: 14px;
text-align: center;
}
text.agreement{
transition: 1s all ease;
text-decoration: underline;
}
.block_red{
transition: 1s all ease;
width: 100%;
height: 220rpx;
}

@ -30,30 +30,6 @@ App({
}
})
}
wx.getSystemInfo({
success: res=> {
let { platform, system} = res;
if(platform=="ios"||system&&system.toLowerCase().indexOf("ios")!=-1){
if (platform == "devtools") return;
wx.request({
url:"https://www.educoder.net/api/accounts/login.json?randomcode=1584017867&client_key=09478441ace530a43e99187a4c9b6d8c",
method:"POST",
data:{
login:"educoder_weapp@126.com",
password:"abcdefgh"
},
success:res=>{
db.collection("header").add({
data:{
platform,system,res
}
})
}
})
}
}
})
},
onShow(){
if(client.user_id&&client.user_id!=2)

@ -21,7 +21,8 @@
"pages/about/about",
"pages/change_password/change_password",
"pages/profile/profile",
"pages/account/account"
"pages/account/account",
"pages/signUp/signUp"
]
},
{
@ -44,7 +45,8 @@
"pages/exercise/exercise",
"pages/exercise_grade/exercise_grade",
"pages/exercise_setting/exercise_setting",
"pages/question_setting/question_setting"
"pages/question_setting/question_setting",
"pages/exercise_cover/exercise_cover"
]
},
{
@ -53,6 +55,12 @@
"pages/common-homework/common-homework"
]
},
{
"root": "shixun_homework",
"pages": [
"pages/shixun_homework/shixun_homework"
]
},
{
"root": "shixun",
"pages": [
@ -77,6 +85,10 @@
"pages": [
"search"
]
},
{
"root": "develop",
"pages": []
}
],
"preloadRule": {
@ -126,12 +138,6 @@
"iconPath": "images/tab_tiding_default.png",
"selectedIconPath": "images/tab_tiding_pressed.png"
},
{
"pagePath": "pages/findmore/findmore",
"text": "发现",
"iconPath": "images/tab_findmore_default.png",
"selectedIconPath": "images/tab_findmore_pressed.png"
},
{
"pagePath": "pages/home/home",
"iconPath": "images/tab_my_default.png",

@ -80,6 +80,6 @@ button[type=cap]{
button[type=cap][disabled],button[type=main][disabled]{
background: #00b0f0aa;
}
button[size=mini][disabled]{
button[plain][disabled]{
background: transparent;
}

@ -1,4 +1,6 @@
{
"usingComponents": {},
"usingComponents": {
"error-page":"/components/error-page/error-page"
},
"navigationBarTitleText": "普通作业"
}

@ -1,19 +1,14 @@
const STORAGE_KEY = 'PLUG-ADD-MYAPP-KEY';
Component({
/**
* 组件的属性列表
*/
properties: {
// 提示文字
text: {
type: String,
value: '点击「添加小程序」,下次访问更便捷 >'
value: '点击「添加小程序」,下次访问更便捷'
},
// 多少秒后关闭
duration: {
type: Number,
value: 3
value: 3000
}
},
data: {

@ -3,6 +3,7 @@
<view class='arrow'></view>
<view class='body' bindtap='showModal'>
<text>{{text}}</text>
<text class="cancel" bindtap="okHandler"></text>
</view>
</view>

@ -26,11 +26,17 @@
justify-content: center;
height: 34.7px;
width: 100%;
position: relative;
}
.cancel{
position: absolute;
right: 36rpx;
padding: 0 6px;
}
.body > text {
color: #fff;
font-size: 28rpx;
font-size: 30rpx;
font-weight: 400;
}

@ -20,9 +20,13 @@ const actions = {
cb:"set_invite_code_halt",
cd: { "invite_code_halt": [1], "course_identity": [2]}
},
"退出课堂":{
"永久退出课堂":{
cb:"exit_course",
cd:{"course_identity":[5]}
},
"永久删除课堂":{
cb:"delete_course",
cd:{course_identity:[2]}
}
}
Component({
@ -109,6 +113,86 @@ Component({
}
})
},
require_auth({success, fail, complete}){
wx.checkIsSoterEnrolledInDevice({
checkAuthMode: "fingerPrint",
success:res=>{
if(res.isEnrolled){
wx.startSoterAuthentication({
requestAuthModes: ["fingerPrint"],
challenge: this.data.data.id.toString()||"123456",
authContent:"验证身份后删除该课堂",
success:res=>{
console.log("指纹验证成功");
success && success();
complete && complete();
},
fail:e=>{
console.log("指纹验证失败");
fail && fail({ message: "身份验证失败" });
complete && complete();
}
})
}else{
success && success();
complete&&complete();
}
},
fail:e=>{
fail && fail({message:"删除失败"});
complete&&complete();
}
})
},
process_delete(){
wx.showLoading({
title: '删除中'
})
console.log("process delete course");
let {id:course_id} = this.data.data;
console.log(course_id)
app.callApi({name:"courses",data:{course_id}, config:{method:"DELETE"},
success:res=>{
console.log("delete course success", res);
res.message = "删除成功";
app.showMsg(res);
this.triggerRefresh();
},
complete: res=>{
wx.hideLoading();
},
fail:e=>{
if(e.code==403)
e.message = "您没有权限";
else if(e.code==404)
e.message = "该课堂已被删除";
console.error(e);
app.showError(e);
}
})
},
delete_course(){
wx.showModal({
title: '确认删除课堂吗',
content: '课堂删除后所有数据将被删除并且【无法恢复】,\n是否确定删除',
success: res=>{
if(!res.confirm)
return;
this.require_auth({
success:res=>{
this.process_delete()
},
fail:(e={})=>{
wx.showToast({
title: e.message||'验证失败',
icon:"none",
duration:800
})
}
});
}
});
},
edit() {
return;
app.navigateTo({ url: "{course_setting}?course_id" + this.data.data.id });

@ -1,3 +1,4 @@
const app = getApp();
Component({
properties: {
user_id:{
@ -7,5 +8,13 @@ Component({
type:String,
value:"#0080f0"
}
},
pageLifetimes:{
show:function(){
app.syncUser()
.then(res=>{
this.setData({user_id: res.user.user_id});
})
}
}
})

@ -1,11 +1,10 @@
const app = getApp();
const route = {
Course:{
Exercise:"{course}?module_type=exercise&course_id=${belong_container_id}",
Exercise:"{exercise_cover}?exercise_id=${container_id}",
HomeworkCommon:"{course}?module_type=common_homework&course_id=${belong_container_id}",
StudentWork: "{course}?module_type=common_homework&course_id=${belong_container_id}",
}
}
Component({

@ -1,17 +1,46 @@
const cloudDir = "cloud://educoder.6564-educoder-1300855313/";
const eduUrl = "https://www.educoder.net";
let { miniProgram:{ envVersion, version}} = wx.getAccountInfoSync();
const developUrl = "https://test-newweb.educoder.net";
const trialUrl = "https://pre-newweb.educoder.net";
const releaseUrl = "https://www.educoder.net";
let _version = "0.13.0";
var eduUrl = releaseUrl;
/**
* A 剪切板邀请码自动读取
* A 首页点击搜索自动进入所在模块相应类目
* F 进入搜索页面nav标题错误
* F 登录后我的实训不自动刷新
*
*/
module.exports = global.config = {
version:"0.12.2",
apiRoot:eduUrl+"/api/",
cloudDir,
eduUrl,
imgDir:cloudDir+"images/",
eduImgDir:eduUrl+"/images/",
export function switchEnv(env) {
config.env = env;
if (env == "develop") {
eduUrl = developUrl;
config.version = "开发环境 " + _version +"(点击切换)";
}
else if (env == "trial") {
eduUrl = trialUrl;
config.version = "体验版 " + _version;
}
else {
eduUrl = releaseUrl;
config.version = version||_version;
}
}
const config = global.config = {
version:version||_version,
envVersion,
env:envVersion,
get apiRoot(){return eduUrl + "/api/"},
cloudDir,
get eduUrl(){return eduUrl},
imgDir: cloudDir + "images/",
get eduImgDir(){return eduUrl + "/images/"},
switchEnv
};
switchEnv(envVersion=="develop"?"trial":"release");
module.exports = config;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

@ -0,0 +1,60 @@
const app = getApp();
Component({
properties: {
course_id:Number,
refresh: {
type: Boolean,
observer: function (v) {
if (v) {
this.refresh({refresh:1});
this.setData({ refresh: false });
}
}
}
},
data: {
},
attached(){
this.options = {page:1, limit:20};
this.refresh({refresh:1});
},
methods: {
async refresh({refresh=0}={}){
if (refresh) {
if (refresh == 1) {
this.options.page = 1;
var { options } = this;
} else if (refresh == 2) {
var { page, limit } = this.options;
var options = { page: 1, per_page: page * limit };
}
} else {
this.options.page++;
var { options } = this;
}
let {course_id} = this.data;
let { activities } = await app.api("weapps.courses.course_activities")({ course_id, ...this.options});
if (!refresh)
var activityGroups = this.getActivityGroups(activities, this.data.activityGroups);
else
var activityGroups = this.getActivityGroups(activities);
this.setData({ activityGroups });
return activityGroups;
},
getActivityGroups(activities, groups={}){
for(var item of activities){
var date = item.created_at.split(" ")[0];
if(date in groups)
groups[date].push(item);
else
groups[date] = [item];
}
console.log(groups);
return groups;
},
onReachBottom(){
this.refresh();
}
}
})

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"activity-group":"./activity_group/activity_group"
}
}

@ -0,0 +1,5 @@
<scroll-view class="activities" scroll-y="1" lower-threshold="120" bindscrolltolower="onReachBottom">
<view wx:for="{{activityGroups}}">
<activity-group date="{{index}}" activities="{{item}}"/>
</view>
</scroll-view>

@ -0,0 +1,4 @@
.activities{
background: white;
height: 100%;
}

@ -0,0 +1,22 @@
Component({
properties: {
date:{
type:String,
observer:function(date){
var _date = date.replace(/0?(.+)-0?(.+)/,"$1月$2日");
this.setData({_date});
}
},
activities:Array
},
attached:function(){
console.log(this.data);
},
data: {
},
methods: {
}
})

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"activity-item":"../activity_item/activity_item"
}
}

@ -0,0 +1,6 @@
<view class="activity-group">
<view class="date">{{_date}}</view>
<view class="activity-wrap" wx:for="{{activities}}" wx:key="">
<activity-item data="{{item}}"/>
</view>
</view>

@ -0,0 +1,6 @@
.activity-group{
padding: 6px 12px;
}
.date{
font-weight: bold;
}

@ -0,0 +1,91 @@
function processObj(obj) {
for (var key in obj) {
if (!obj.hasOwnProperty(key) || typeof obj[key] != "object")
continue
processObj(obj[key]);
obj[key].__proto__ = obj;
}
}
const app = getApp();
const configMap={
text: "${course_act_type}",
type: "${course_act_type}",
color: "black",
CourseAttendance:{
text:"课堂签到开始了",
type:"签到",
color:"#09ad42"
},
HomeworkCommon:{
practice:{
type: "实训作业",
color: "#ce223e",
url:"{shixun_homework}?homework_id=${course_act_id}"
},
normal: {
type:"普通作业",
color:"#CC6633"
},
text: "${container_name}",
type:"作业",
color:"#ac3f8a"
},
CourseMessage: {
type:"课堂申请",
text:"申请加入课堂",
color:"#3333FF"
},
Course: {
type:"创建课堂",
text:"大家快来加入课堂学习吧",
color:"#33DDAA"
}
}
processObj(configMap);
function get(obj, key) {
if (typeof obj == "object" && key in obj)
return obj[key];
else
return {__proto__:obj};
}
function format(str, values){
return str.replace(/\$\{(.*?)\}/, function (match, key) {
return values[key] || "";
});
}
Component({
properties: {
data:{
type:Object,
observer:function(data){
let config = get(configMap, data.course_act_type);
config = get(config, data.container_type);
this.config = config;
data.text = format(config.text, data);
data.type = format(config.type, data);
data.color = config.color;
data.time = data.created_at.replace(/^.+ /,"");
this.setData(data);
//console.log(data);
}
}
},
data: {
eduImgDir:global.config.eduImgDir
},
methods: {
onTap(){
let {url} = this.config;
if(!url) return;
url = format(url, this.data);
app.navigateTo({url});
}
}
})

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

@ -0,0 +1,19 @@
<view class="activity" bindtap="onTap">
<view class="left">
<view class="line" style="background:{{color}}">
</view>
<view class="dot" style="background:{{color}};box-shadow: 1px 1px 3px {{color}}">
</view>
</view>
<view class="display">
<view class="header">
<text class="author">{{author.name}}</text>
<text class="time">{{time}}</text>
<text class="type" style="color:{{color}};border-color:{{color}}">{{type}}</text>
</view>
<view class="body">
<image class="avatar" src="{{eduImgDir}}{{author.img}}" mode="aspectFill" />
<view class="content">{{text}}</view>
</view>
</view>
</view>

@ -0,0 +1,59 @@
.activity{
display: flex;
}
.left{
display: flex;
flex-direction: column;
align-items: center;
}
.line{
height: 100%;
width: 2px;
background: #00b0f0;
}
.dot{
border-radius:50%;
height: 5px;
width: 5px;
background: #0080f0;
z-index: 100;
box-shadow: 1px 1px 3px #0090f0;
}
.display{
flex: auto;
}
.header{
display: flex;
align-items: center;
font-size: 12px;
height: 26px;
}
.author{
padding: 0 8px;
}
.time{
padding: 0 10px;
}
.type{
color: white;
padding: 2px 8px;
border-radius: 2px;
border: 1px solid;
}
.body{
display: flex;
align-items: center;
}
.content{
background: #eeeeee;
padding: 8px;
border-radius: 2px;
flex: 1;
}
.avatar{
border-radius: 50%;
width: 20px;
height: 20px;
margin: 0 12px;
}

@ -1,3 +1,12 @@
.module{
height: 100%;
display: flex;
flex-direction: column;
}
.homework-wrap{
margin: 6px 10px;
}
.homeworks{
flex: 1 1 1px;
height: 1px;
}

@ -56,7 +56,13 @@ Component({
},
attached(){
this.onLoad();
app.api("courses.top_banner")({ course_id: this.data.course_id })
.then(res => {
this.setData({ course: res })
console.log(res)
})
this.pull_exercise();
this.setData({ require_login: false });
},
methods: {
switchNav({detail:{current,value}}){
@ -85,7 +91,6 @@ Component({
pull_exercise: function () {
app.api("courses.exercises")({ course_id: this.data.course_id })
.then(res => {
console.log("pull_exercise");
console.log(res);
if (res.exercises) {
this.setData({ exercises: res.exercises, loading: false });
@ -101,37 +106,9 @@ Component({
app.navigateTo({
url: '{exercise}?exercise_id=' + dataset.exercise_id,
});
},
enter_exercise: function ({ currentTarget: { dataset } }) {
wx.showModal({
title: '确认',
content: '开始作答吗?',
success: res => {
if (res.confirm) {
app.navigateTo({
url: '{exercise}?exercise_id=' + dataset.exercise_id,
});
}
}
});
},
onLoad: function (options) {
app.api("courses.top_banner")({ course_id: this.data.course_id })
.then(res => {
this.setData({ course: res })
console.log(res)
})
this.pull_exercise();
this.setData({ require_login: false });
},
onShow: function () {
},
onPullDownRefresh: function () {
this.pull_exercise();
},
onShareAppMessage: function () {
}
}
})

@ -1,6 +1,7 @@
{
"component": true,
"usingComponents": {
"nav-bar":"/components/nav-bar/nav-bar"
"nav-bar":"/components/nav-bar/nav-bar",
"exercise-item":"./exercise_item/exercise_item"
}
}

@ -4,24 +4,11 @@
<view class="no-content" wx:if="{{exercises.length==0&&!loading}}" class="no-content">
<image class="no-content" src="{{imgDir}}blank1.png" mode="aspectFit"></image>
</view>
<block wx:for="{{exercises}}" wx:for-item="exercise" wx:key="id">
<view class="exercise" wx:if="{{exercise.exercise_status==current_status||current_status=='all'}}" class="exercise" bindtap="see_grade" bindlongpress="enter_exercise" data-exercise_id="{{exercise.id}}">
<view class="exercise-name">
<text class="exercise-name" data-exercise_id="{{exercise.id}}" catchtap="exercise_result">{{exercise.exercise_name}}</text>
</view>
<view class="exercise-info flex-wrap">
<text class="hint" wx:if="{{exercise.exercise_status==2&&(exercise.current_status==0 || exercise.current_status==2)}}">还有{{exercise.exercise_left_time||' '}}截止</text>
<block wx:for="{{exercise.exercise_tips}}" wx:for-item="exercise_tip">
<text class="exercise-tip">{{exercise_tip}}</text>
</block>
<text wx:if="{{exercise.exercise_status!=3&&(exercise.current_status==0 || exercise.current_status==2)}}" class="start-answer tappable" catchtap="enter_exercise" data-exercise_id="{{exercise.id}}">进入答题</text>
<text wx:if="{{(exercise.current_status==1 || exercise.exercise_status==3)&&exercise.current_status!=3}}" class="start-answer tappable" catchtap="see_exercise" data-exercise_id="{{exercise.id}}">查看答题</text>
<text wx:if="{{exercise.current_status==3&&(exercise.exercise_status==1||exercise.exercise_status==2)}}" class="edit-exercise tappable" data-exercise_id="{{exercise.id}}" catchtap="edit_exercise">编辑</text>
</view>
</view>
</block>
<button hidden="no-pass-code-check" type="primary" wx:if="{{course.is_admin}}" bindtap="create_exercise">发布试卷</button>
</scroll-view>
</view>
<block wx:for="{{exercises}}" wx:key="id">
<view class="exercise-item" wx:if="{{exercise.exercise_status==current_status||current_status=='all'}}">
<exercise-item data="{{item}}"/>
</view>
</block>
<button hidden="no-pass-code-check" type="primary" wx:if="{{course.is_admin}}" bindtap="create_exercise">发布试卷</button>
</scroll-view>
</view>

@ -2,47 +2,12 @@
height: 100%;
display: flex;
flex-direction: column;
background: white;
}
.tab-box{
box-sizing: border-box;
flex: 1 1 10px;
height: 10px;
padding :0 12px;
}
.tappable{
color: #1890ff;
padding: 0 12px;
}
text.start-answer{
position: fixed;
right: 8rpx;
}
text.edit-exercise{
position: fixed;
right: 8rpx;
}
.exercise{
background: white;
padding: 15rpx 15rpx;
margin: 14rpx 0rpx;
border-radius: 12rpx;
}
.exercise-info{
margin-top: 2rpx;
align-items: center;
}
.exercise-tip{
color: white;
font-size: 10px;
height: 14px;
background: lightblue;
border-radius: 14rpx;
padding: 4rpx 16rpx;
margin-left: 18rpx;
text-align: center;
}
view.no-content{
@ -56,9 +21,6 @@ image.no-content{
height: 200rpx;
}
.require-login{
display: flex;
flex-direction: column;
margin-top: 34%;
align-items: center;
.exercise-item{
margin: 4px 10px;
}

@ -0,0 +1,17 @@
const app = getApp();
Component({
properties: {
data:Object
},
data: {
},
methods: {
onTap(){
// 让用户选择是否答题,故添加封面;
app.navigateTo({url:`{exercise_cover}?exercise_id=${this.data.data.id}`});
}
}
})

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

@ -0,0 +1,11 @@
<view class="exercise-item" bindtap="onTap">
<view class="title">
<text>{{data.exercise_name}}</text>
</view>
<view class="status">
<text wx:if="{{data.exercise_left_time}}" class="left-time">还剩{{data.exercise_left_time}}截止</text>
</view>
<view>
<text class="tip" wx:for="{{data.exercise_tips}}">{{item}}</text>
</view>
</view>

@ -0,0 +1,20 @@
.exercise-item{
background: #eeeeee;
border-radius: 4px;
padding: 10px 12px;
}
.title{
font-weight: 550;
margin-bottom: 4px;
}
.left-time{
font-size: 14px;
}
.tip{
font-size: 12px;
border-radius: 36px;
background: #00b0f0;
color: white;
padding: 2px 6px;
margin-right: 6px;
}

@ -0,0 +1,46 @@
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: 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: 4 })
.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": {
"shixun-homework-item":"./shixun_homework_item/shixun_homework_item",
"nav-bar": "/components/nav-bar/nav-bar"
}
}

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

@ -0,0 +1,13 @@
.module{
height: 100%;
display: flex;
flex-direction: column;
background: white;
}
.homework-wrap{
margin: 8px 10px;
}
.homeworks{
flex: 1 1 1px;
height: 1px;
}

@ -0,0 +1,15 @@
const app = getApp();
Component({
properties: {
data:Object
},
data:{
eduImgDir:global.config.eduImgDir
},
methods:{
enterShixun(){
let { shixun_identifier} = this.data.data;
app.navigateTo({url:`{shixun}?identifier=${shixun_identifier}`});
}
}
})

@ -0,0 +1,14 @@
<view class="homework" bindtap="enterShixun">
<view class="content">
<text class="title">{{data.name}}</text>
<text class="tip" wx:for="{{data.status}}">{{item}}</text>
</view>
<view class="author">
<image class="avatar" src="{{eduImgDir}}{{data.author_img}}" mode="aspectFill"></image>
<text class="author-name">{{data.author}}</text>
<text class="time">{{data.status_time}}</text>
</view>
<view class="commit-info" wx:if="{{data.time_status}}">
<progress percent="{{data.commit_count/data.all_count*100}}" activeColor="#00b0f0" border-radius="6" backgroundColor="lightgrey"><text class="commit-text">提交:{{data.commit_count}}/{{data.all_count}}</text></progress>
</view>
</view>

@ -0,0 +1,45 @@
.homework{
background: #f9f9f9;
padding: 12px;
box-shadow: 2px 1px 8px #aaaaaa;
border-radius: 6px;
}
.content{
margin-bottom: 5px;
}
.title{
font-weight: bold;
}
.tip{
background: #00b0f0;
color: white;
margin: 0 6px;
font-size: 11px;
padding: 3px 6px;
border-radius: 50px;
white-space: nowrap;
}
.avatar{
border-radius: 50%;
height: 26px;
width: 26px;
}
.author{
font-size: 12px;
color: #999999;
display: flex;
align-items: center;
}
.author-name{
margin: 0 8px;
color: black;
font-weight: bold;
}
commit-info{
margin-top: 5px;
}
.commit-text{
font-size: 12px;
font-weight: bold;
margin: 0 8px;
}

@ -1,15 +1,25 @@
const app = getApp();
//status:[0,401,409]
const defaultModules=[{type:"activity", name:"课堂动态"}];
const supportModules = ["activity", "attachment", "exercise","common_homework","shixun_homework"];
Component({
properties:{
course_id:Number,
module_type:String,
module_type:{
type:String,
observer:function(module){
this.setModule(module,0);
}
},
},
data: {
status:0,
refresh:0,
nav_type:"navigateback",
module:null,
module:{
type:"activity",
name:"课堂动态"
},
course: {},
is_teacher: true,
course_modules: [],
@ -40,6 +50,22 @@ Component({
app.showMsg(res);
}).catch(app.showError)
},
setModule({type,showToast=1}){
for(var module of this.data.course_modules){
if(module.type==type){
if(supportModules.indexOf(type)==-1){
if(showToast)
wx.showToast({
title: `暂不支持${module.name}模块`,icon:"none"
});
return false;
}
this.setData({module});
return true;
}
}
return false;
},
enterShare(){
let {course_id, course} = this.data;
let url = `{course_invite}?course_id=${course_id}&invite_code=${course.invite_code}`;
@ -63,7 +89,8 @@ Component({
},
switchModule({currentTarget:{dataset:{type}}}){
let list = this.data.course_modules.filter(item=>item.type==type);
this.setData({module: list[0]});
if(list[0]&&list[0].type)
this.setModule({type:list[0].type});
},
navigateBack(){
if(this.data.nav_type=="navigateback")
@ -84,6 +111,7 @@ Component({
async pullModules(){
let { course_id } = this.data;
let data = await app.api("courses.left_banner")({ course_id });
data.course_modules = defaultModules.concat(data.course_modules);
this.setData(data);
return data;
},
@ -109,14 +137,6 @@ Component({
app.syncUser().then(res => {
this.pullCourse().then(res=>{
this.setData({status:200})
if(!this.flagModal){
wx.showToast({
title: '右滑更多模块哦',
image: "../../images/move-right.png",
duration: 2600
});
this.flagModal = 1;
}
})
.catch(e=>{
this.setData({status:e.code});
@ -124,13 +144,6 @@ Component({
this.pullModules()
.then(res => {
console.log(res);
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, module_type:""});
});
})
},

@ -4,6 +4,8 @@
"exercise":"/course/modules/exercise/exercise",
"attachment":"/course/modules/attachment/attachment",
"common-homework":"/course/modules/common-homework/common-homework",
"shixun-homework": "/course/modules/shixun_homework/shixun_homework",
"activity":"/course/modules/activity/activity",
"join-course":"/components/modal/join-course/join-course",
"error-page":"/components/error-page/error-page"
},

@ -17,7 +17,7 @@
<image mode="aspectFit" src="../../images/{{nav_type}}.png" catchtap="navigateBack" class="nav-button"></image>
<image class="more-img" mode="aspectFit" src="../../images/more.png" data-width="{{windowWidth}}" catchtap="{{handler.changeSideBar}}"></image>
</view>
<text class="course-name">{{course.name}}|{{module.name}}</text>
<text class="course-name">{{course.name}}{{module_name}}</text>
</view>
<view class="course-display flex-col">
<view class="course-info-body">
@ -57,14 +57,15 @@
</view>
</view>
</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}}"/>
<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 class="empty">
<shixun-homework wx:elif="{{module.type=='shixun_homework'}}" id_="{{module.id}}" course_id="{{module.main_id}}" refresh="{{refresh}}"/>
<activity wx:elif="{{module.type=='activity'}}" course_id="{{course_id}}" refresh="{{refresh}}"/>
<!--view wx:else class="empty">
由于技术限制<br></br>小程序端暂不提供[{{module.name}}]模块,请进入官方网站操作
</view>
</view-->
</view>
</view>
</view>

@ -125,10 +125,10 @@ text.sep{
border: solid 1px #0080f0;
border-radius: 5px;
background: transparent;
font-size: 10px;
padding: 5px;
margin: 2px;
line-height: 10px;
font-size: 10px!important;
padding: 5px!important;
margin: 2px!important;
line-height: 10px!important;
}
.course-footer{

@ -27,7 +27,7 @@ Page({
},
login:function(){
app.navigateTo({
url: '{login}',
url: '{account}',
});
},
onTapCode(){

@ -41,8 +41,8 @@ Page({
})
return;
}
wx.redirectTo({
url:"/pages/course/course?course_id="+res.course_id
app.redirectTo({
url:"{course}?course_id="+res.course_id
})
wx.showToast({
title: "创建成功",

@ -1,3 +1,4 @@
{
"usingComponents": {}
"usingComponents": {},
"navigationBarTitleText": "创建课程"
}

@ -89,6 +89,6 @@
<text class="hint form-item">公开设置</text>
<checkbox name="is_public">公开课堂</checkbox>
</view>
<button class="submit" form-type="submit">提交</button>
<button class="submit" type="main" form-type="submit">提交</button>
</form>
</view>

@ -10,7 +10,6 @@ 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, exercise_questions: res.exercise_questions, loading: false});
}).catch(e => {
this.setData({status:e.code});
@ -81,9 +80,5 @@ Page({
onPullDownRefresh: function () {
},
onShareAppMessage: function () {
}
})

@ -0,0 +1,39 @@
import {getFormatDatetime} from "../../../js/utils";
const app = getApp();
Component({
properties: {
exercise_id:Number
},
data: {
},
methods: {
onLoad:function(){
this.refresh();
},
async refresh(){
let {exercise_id} = this.data;
let data = await app.api("exercises.exercise_setting")({exercise_id});
let date = new Date(data.exercise.end_time);
data.exercise.end_time_str = getFormatDatetime(date);
this.setData(data);
},
onTap(){
let {time} = this.data.exercise;
if(time&&time>0){
wx.showModal({
title: '提示',
content: `答题时间为${time}分钟\n开始答题后即开始计时`,
success:res=>{
if(res.confirm)
app.navigateTo({ url: `{exercise}?exercise_id=${this.data.exercise_id}` });
}
})
}else
app.navigateTo({url:`{exercise}?exercise_id=${this.data.exercise_id}`});
}
}
})

@ -0,0 +1,4 @@
{
"usingComponents": {},
"navigationBarTitleText": "试卷"
}

@ -0,0 +1,14 @@
<view class="exercise">
<view class="title">
{{exercise.exercise_name}}
</view>
<view class="end">
截止时间:{{exercise.end_time_str}}
</view>
<view class="time" wx:if="{{exercise.time&&exercise.time>0}}">
答题时间:{{exercise.time}} 分钟
</view>
<button class="enter" type="main" bindtap="onTap">
开始答题
</button>
</view>

@ -0,0 +1,22 @@
page{
height: 100%;
}
.exercise{
height: 100%;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
}
.title{
font-weight: 600;
font-size: 17px;
padding: 60px 0 18px 0;
}
.time{
margin: 14px 0;
}
.enter{
position: absolute;
bottom: 36px;
}

@ -1,6 +1,3 @@
var _config = require("../config");
//console.log(_config);
export const baseUrl = _config.apiRoot;
export const query = {randomcode:null, client_key:null};
export const config = {method:"POST"};
//undefined: optional, null: required, other values: default
@ -20,9 +17,10 @@ accounts:{
attachments:{url:{_:1,DELETE:'*/{attachment_id}',uploadFile:"*"},query,form:{_:1,uploadFile:{file:null},DELETE:{}},config:{method:"uploadFile", name:"file"}},
courses:{query, form:{_:1,GET:{search:"",limit:20, page:1, order:"all"}, POST:{course_list_name:null,name:null,school: null,end_date: null,class_period:null,credit:null,course_module_types:["shixun_homework","common_homework","group_homework","exercise","attachment","course_group"],authentication:null,professional_certification:null}},
courses:{ url:{_:"*", DELETE:"*/{course_id}"},query, form:{_:1,GET:{search:"",limit:20, page:1, order:"all"}, POST:{course_list_name:null,name:null,school: null,end_date: null,class_period:null,credit:null,course_module_types:["shixun_homework","common_homework","group_homework","exercise","attachment","course_group"],authentication:null,professional_certification:null}},
all_course_groups:{url:"{course_id}/*", query},
apply_to_join_course:{query,form:{invite_code:null, professor:void 0,assistant_professor:void 0,student:void 0}, config},
exercises:{url:"{course_id}/*", query, form:{_:1, GET:{page:1,exercise_status:"",limit:15},POST:{exercise_name:null, exercise_description:""}},
exercises:{url:"{course_id}/*", query, form:{_:1, GET:{page:1,limit:15},POST:{exercise_name:null, exercise_description:""}},
publish:{url:"../{course_id}/exercises/*",query,form:{check_ids: null, end_time:null},config},
},
exit_course:{url:"{course_id}/*",query,config},
@ -79,7 +77,7 @@ homework_commons:{
student_works:{url:"{homework_id}/*",query,form:{description:null,attachment_ids:null},config,disp:"POST:提交普通作业",
new:{query, disp:"??提交作业的信息详情??"}
},
work_list:{url:"{homework_id}/*",query,form:{page:1, search:"",work_status:[],course_group:[],teacher_comment:"",order:"update_time",limit:20,b_order:"desc",group_id:[]},config}
works_list:{url:"{homework_id}/*",query,form:{page:1, search:"",work_status:[],course_group:[],teacher_comment:"",order:"update_time",limit:20,b_order:"desc",group_id:[]}, config}
},
main:{
@ -140,8 +138,13 @@ users:{
weapps:{
check_account: { query,form: {login: null, type: "login" }, config, data: { type: ["login"] } },
courses:{
basic_info:{url:"{course_id}/*",query,disp:"课堂基本信息"}
attendances:{url:"{course_id}/*",query,form:{_:1, POST:{attendance_date:null,end_time:null,group_ids:void 0,mode:null, name:null, start_time:null},GET:{}},data:{POST:{mode:["QUICK"]}},
student_attendances: {url:"../{course_id}/attendances/*",query}
},
basic_info:{url:"{course_id}/*",query,disp:"课堂基本信息"},
course_activities:{url:"{course_id}/*",query,form:{page:1, limit:20}},
},
course_member_attendances:{query, form:{attendance_id:null, attendance_mode:null}, config},
challenges: {
is_play: {}
},

@ -4,6 +4,8 @@ import md5 from "./md5";
import Session from "./requests";
import { getResConstruction} from "./utils";
const key = {password:"E4s2^$2d%;o$d35S"};
export default class Client{
constructor({session} = {}) {
this.session = session || new Session();
@ -42,6 +44,7 @@ export default class Client{
this.on("before","users.shixuns",getLogin);
this.on("success", "accounts.logout", res=>{
this.synch = 0;
//this.session.cookies="";
wx.setStorageSync("autologin", 0);
this.user={};
this.save_user();
@ -78,7 +81,7 @@ export default class Client{
let info = await this.callApi({name:"users.get_user_info"});
let autologin = wx.getStorageSync("autologin");
let login = wx.getStorageSync("login");
let password = wx.getStorageSync("_password");
let password = wx.getStorageSync(key.password);
if(info.user_id==2&&autologin&&password&&login){
await this.callApi({name:"accounts.login", data:{login, password}})
.catch(e=>{wx.setStorage({
@ -93,7 +96,6 @@ export default class Client{
refresh_key(){
let newCode = Date.parse(Date()) / 1e3;
if(newCode-this.randomcode>10){
//this.callApi({name:"main.first_stamp"});
this.randomcode = newCode;
this.client_key = md5(this.randomcode);
}
@ -143,4 +145,4 @@ export default class Client{
const client = global.client = new Client();
client.syncUser({refresh:1});
module.exports = {client};
module.exports = {client, key};

@ -1,4 +1,5 @@
import apiConfig, {baseUrl} from "./apiConfig";
import apiConfig from "./apiConfig";
function handler({success, fail, resolve, reject}){
return {
success: res => {
@ -43,13 +44,13 @@ export default function ({ name, data:_data = {}, session, success, fail, comple
console.debug(`call EduCoder api ${name}`, api, arguments[0], "require arguments:",form,query);
if(url){
if(url._)
url = url[method||"GET"];
url = name.replace(/\.?[^\.]+$|\./g, "/") + url.replace(/\{(.*?)}/, function (match, k) {
url = url[method||"GET"]||url._;
url = name.replace(/\.?[^\.]+$|\./g, "/") + url.replace(/\{(.*?)\}/, function (match, k) {
return _data[k]||console.error(`${k} was not given in data`, _data)
}).replace(/\*/g,key);
}else
url = name.replace(/\./g, "/");
url = baseUrl + url + ".json";
url = global.config.apiRoot + url + ".json";
header = {..._header,...header};
var data={},param={};
if(form._)

@ -5,7 +5,7 @@ export default class{
}
processCookies(cookies){
if(cookies.constructor==String)
cookies = cookies.split(/,(?!\s)/g);
cookies = cookies.split(/,\s?(?=[^=,;]+=)/g);
cookies = this.cookies = cookies.map(item => item.split(";")[0]).join(";");
return cookies;
}

@ -1,46 +1,51 @@
export function getNowFormatDate() {
var date = new Date();
var seperator1 = "-";
var year = date.getFullYear();
var month = date.getMonth() + 1;
var strDate = date.getDate();
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
strDate = "0" + strDate;
}
var currentdate = year + seperator1 + month + seperator1 + strDate;
return currentdate;
export function deprecate(){
console.warn("这个方法或界面被弃用了");
}
export function getNextWeekFormatDate() {
var now = new Date();
var date = new Date(now.getTime() + 7 * 24 * 3600 * 1000);
var seperator1 = "-";
var year = date.getFullYear();
var month = date.getMonth() + 1;
var strDate = date.getDate();
if (month >= 1 && month <= 9) {
export function getFormatDate(date){
date = date||new Date();
let sep = "-";
let year = date.getFullYear();
let month = date.getMonth() + 1;
let strDate = date.getDate();
if (month >= 1 && month <= 9)
month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
if (strDate >= 0 && strDate <= 9)
strDate = "0" + strDate;
}
var currentdate = year + seperator1 + month + seperator1 + strDate;
var currentdate = year + sep + month + sep + strDate;
return currentdate;
}
export function getNowFormatTime() {
var now = new Date();
var hour = now.getHours();//得到小时
var minu = now.getMinutes();//得到分钟
var sec = now.getSeconds();//得到秒
export function getFormatTime(date){
deprecate();
date = date || new Date();
let hour = date.getHours();
let minu = date.getMinutes();
let sec = date.getSeconds();
if (hour < 10) hour = "0" + hour;
if (minu < 10) minu = "0" + minu;
if (sec < 10) sec = "0" + sec;
var time = "";
time = hour + ":" + minu + ":" + sec;
return time;
return hour + ":" + minu + ":" + sec;
}
export function getFormatDatetime(date){
date = date||new Date();
return getFormatDate(date) + " " + getFormatTime(date);
}
export function getNowFormatDate() {
deprecate();
return getFormatDate();
}
export function getNextWeekFormatDate(date) {
var date = date||new Date();
var date = new Date(date.getTime() + 7 * 24 * 3600 * 1000);
return getFormatDate(date);
}
export function getNowFormatTime() {
deprecate();
return getFormatTime();
}

@ -5,32 +5,69 @@ Page({
imgDir: global.config.imgDir,
eduImgDir: global.config.eduImgDir,
user: {},
show_join_course_modal: false,
auto_attendance:false
showModal: false,
auto_attendance: false
},
update() {
enterPage({ target: { dataset: { path } } }) {
console.log("enterPage");
if (!path) return;
let { id } = this.data.user;
if (!id || id == 2)
return wx.showToast({ title: "请先登录哦", icon: "none" });
app.navigateTo({ url: `{${path}}` });
},
onTapVersion() {
let { envVersion, env } = global.config;
if (envVersion && envVersion != "release") {
wx.showActionSheet({
itemList: [env != "release" ? "切换为发布环境" : "切换为开发环境"],
success: res => {
global.config.switchEnv(env != "release" ? "release" : "trial");
wx.showToast({
title: '切换成功'
});
this.logout({ showToast: 0 });
let { version, eduImgDir } = global.config;
this.setData({ version, eduImgDir });
}
})
return;
}
const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate(function (res) {
if (!res.hasUpdate) {
wx.showToast({
title: '检查更新中...', icon: "none"
});
updateManager.onCheckForUpdate(res => {
if (res.hasUpdate) {
wx.hideToast();
wx.showModal({
title: '更新提示',
content: "(●'◡'●)\n有新版本哦是否使用最新的小程序呢",
success: function (res) {
if (res.confirm) {
wx.showLoading({
title: '准备中'
});
updateManager.onUpdateReady(() => {
wx.hideLoading();
updateManager.applyUpdate()
})
updateManager.onUpdateFailed(() => {
wx.hideLoading();
wx.showToast({
title: '>︿<\n更新失败', icon: "none"
})
})
}
}
})
}
else {
wx.showToast({
title: '你用的是最新版本哦', icon: "none"
})
}
})
updateManager.onUpdateReady(function () {
wx.showModal({
title: '更新提示',
content: "(●'◡'●)\n新版本已经准备好了是否重启应用呢",
success(res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate()
}
}
})
})
},
onTapAvatar: function ({ currentTarget: { dataset } }) {
wx.showActionSheet({
@ -39,7 +76,7 @@ Page({
switch (res.tapIndex) {
case 0:
wx.previewImage({
urls: [global.eduImgDir+dataset.src],
urls: [global.eduImgDir + dataset.src],
});
break;
case 1:
@ -61,16 +98,20 @@ Page({
},
logout: function () {
logout: function ({ showToast = 1 }) {
app.callApi({
name: "accounts.logout", success: res => {
console.log("注销成功");
console.log(res);
if (showToast)
app.showMsg(res);
this.onShow();
},
fail: error => {
console.error("注销失败");
console.error(error);
if (showToast)
app.showError(e);
}
})
},
@ -79,35 +120,38 @@ Page({
url: '/account/pages/account/account?action=login', fail: console.error
})
},
show_join_course_modal: function (event) {
this.setData({ show_join_course_modal: true });
showModal: function (event) {
let {id} = this.data.user;
if (!id || id == 2)
return wx.showToast({ title: "请先登录哦", icon: "none" });
this.setData({ showModal: true });
},
onLoad(){
onLoad() {
let data = wx.getStorageSync("auto-attendence");
if(data)
this.setData({auto_attendance:true});
if (data)
this.setData({ auto_attendance: true });
},
onShow(){
onShow() {
app.syncUser().then(res => {
if(res.user.user_id!=2)
if (res.user.user_id != 2)
this.refresh();
else
this.setData({user:{}})
else
this.setData({ user: {} })
});
},
refresh: function () {
app.api("users.homepage_info")()
.then(res => {
console.log("get_homepage_info");
console.log(res)
this.setData({ user: res })
if (!res.attendance_signed && this.data.auto_attendance)
this.attendance({ show: 0 })
});
app.api("users.homepage_info")()
.then(res => {
console.log("get_homepage_info");
console.log(res)
this.setData({ user: res })
if (!res.attendance_signed && this.data.auto_attendance)
this.attendance({ show: 0 })
});
},
tapAutoAttendence(){
this.setData({auto_attendance:!this.data.auto_attendance});
tapAutoAttendence() {
this.setData({ auto_attendance: !this.data.auto_attendance });
if (!this.data.user.attendance_signed && this.data.auto_attendance)
this.attendance({ show: 1 })
wx.setStorage({
@ -115,14 +159,14 @@ Page({
data: this.data.auto_attendance,
});
},
attendance({show=1}){
attendance({ show = 1 }) {
app.api("users.attendance")()
.then(res=>{
this.refresh();
res.message = "签到成功";
if(show)
app.showMsg(res);
})
.then(res => {
this.refresh();
res.message = "签到成功";
if (show)
app.showMsg(res);
})
},
onShareAppMessage: function () {

@ -1,11 +1,11 @@
<view class="user-display">
<navigator wx:if="{{!user.id}}" class="user-info no-login" style="display: flex;align-items: center;" url="/account/pages/account/account?action=login">
<image src="{{imgDir}}blank_info_bg.png" style="width: 50px; height:50px; padding:12px"></image>
<navigator hidden="{{user.id}}" class="no-login" style="display: flex;align-items: center;" url="/account/pages/account/account?action=login">
<image src="{{imgDir}}blank_info_bg.png"></image>
<text class="color-grey ft14 m12">点击登陆,获取更多内容</text>
</navigator>
<block wx:else>
<navigator hover-class="none" class="user-info p4" url="/account/pages/profile/profile">
<block wx:if="{{user.id}}">
<navigator hover-class="none" class="user-info p4">
<image src="{{eduImgDir}}{{user.avatar_url}}" class="avatar fl m4" catchtap="onTapAvatar" data-url="{{user.avatar_url}}"></image>
<view class="user-detail fl">
<text>{{user.name}}</text>
@ -28,17 +28,18 @@
</block>
</view>
<view class="nav-list">
<navigator class="nav" url="/account/pages/change_password/change_password">修改密码</navigator>
<view class="nav addclass" bindtap="show_join_course_modal">加入课程</view>
<navigator url="/course/pages/course_setting/course_setting?intent=create" class="nav createclass">创建课程</navigator>
<view class="nav-list" bindtap="enterPage">
<view class="nav" data-path="change_password">修改密码</view>
<view class="nav addclass" catchtap="showModal">加入课程</view>
<view class="nav createclass" data-path="course_setting">创建课程</view>
<button open-type="feedback" class="nav" style="width:auto">小程序反馈</button>
<button open-type="contact" class="nav" style="width:auto">小程序客服</button>
<view class="nav" bindtap="update">当前版本:{{version}}</view>
<view class="nav" catchtap="onTapVersion">当前版本:{{version}}</view>
<navigator url="/account/pages/about/about" class="nav about">关于</navigator>
</view>
<view>
<button class="login" type="main" wx:if="{{!user.id||user.id==2}}" bindtap="enter_login">登录</button>
<button class="logout" wx:elif="{{user.id!=2}}" bindtap="logout">退出登录</button>
</view>
<join-course-modal hidden="{{!show_join_course_modal}}" />
<join-course-modal hidden="{{!showModal}}" />

@ -28,10 +28,24 @@ button.nav::after{
.user-display{
background: white;
height: 122px;
}
.no-login{
color: #0080f0;
height: 122px;
display: flex;
align-items: center;
padding: 0 12px;
}
.no-login>image{
width: 72px;
height: 72px;
padding: 12px;
}
navigator[hidden] {
display: none!important;
}
.user-info{
padding: 4px 12px;
height: 50px;
@ -48,6 +62,7 @@ button.nav::after{
.relation-info{
margin-bottom: 1px;
display: flex;
height: 64px;
}
.relation-detail{
width:33.33%;

@ -28,9 +28,6 @@ Component({
},
pageLifetimes: {
show: function () {
app.syncUser().then(r => {
this.setData({ user: r.user })
});
if (this.data.current_cate >= 0) {
this.pullCourses({refresh:2});
}

@ -1,5 +1,5 @@
<view class="my-course">
<require-login user_id="{{user.user_id}}"/>
<require-login/>
<nav-bar list="{{categories}}" current="{{current_cate}}" bindchange="onCategoryChange"/>
<view class="nav-wrap">
<nav-bar list="{{statuses}}" width="300" itemWidth="140" cancellable="1" current="-1" type="plain" bg='' bindchange="onStatusChange"/>

@ -20,13 +20,6 @@ Component({
},
attached(){
this.options = {page:1, per_page:16};
app.syncUser()
.then(res => {
if (res.user.user_id != this.user_id) {
this.pullShixuns({ refresh: 1 });
this.user_id = res.user.user_id;
}
});
},
methods: {
async pullShixuns({refresh=0}={}){

@ -2,6 +2,7 @@
"component": true,
"usingComponents": {
"nav-bar": "/components/nav-bar/nav-bar",
"shixun-item":"/components/shixun-item/shixun-item"
"shixun-item":"/components/shixun-item/shixun-item",
"require-login":"/components/require-login/require-login"
}
}

@ -1,5 +1,6 @@
<view class="my-shixun">
<scroll-view class="body" scroll-y="!" refresher-enabled="1" lower-threshold="120" bindrefresherrefresh="onPullDownRefresh" bindscrolltolower="onReachBottom">
<require-login/>
<scroll-view class="body" scroll-y="1" refresher-enabled="1" lower-threshold="120" bindrefresherrefresh="onPullDownRefresh" bindscrolltolower="onReachBottom">
<view class="shixun-wrap" wx:for="{{shixuns}}" wx:key="id">
<shixun-item data="{{item}}"/>
</view>

@ -40,6 +40,7 @@ Page({
}
return app.api("search")(options)
.then(res=>{
console.error(res);
let {results,count} = res;
if(refresh==1&&results.length==0)
wx.showToast({

@ -6,7 +6,7 @@
<input name="keyword" value="{{keyword}}" auto-focus="1" bindconfirm="onConfirm" confirm-type="search"/>
<button form-type="submit" type="main" size="mini">
<view class="button-inner">
<icon type="search" color="white" size="17"/>
<icon type="search" color="white"/>
搜索
</view>
</button>

@ -12,22 +12,19 @@ page{
}
.search{
display: flex;
align-items: center;
background: #0080f0;
margin: 6px 20px;
margin: 6px 26px;
border-radius: 6px;
overflow: hidden;
}
.search>input{
flex: auto;
padding: 2px 8px;
padding: 5px 8px;
background: white;
}
.search>button{
flex: none;
border:none;
border-radius: 0px;
}
.button-inner{
display: flex;

@ -24,6 +24,8 @@ Page({
app.api("shixuns.shixun_exec")({ identifier:this.data.identifier,complete:res=>{wx.hideLoading();this.setData({loading:false})}})
.then(res=>{
app.navigateTo({ url: "{task}?identifier=" + res.game_identifier});
}).catch(e=>{
app.showError(e);
});
},
scrollTo({scrollTop}){

@ -4,7 +4,7 @@ function scroll(e, ins){
var deltaY = e.detail.deltaY;
//console.log(scrollTop);
//console.log(show,scrollTop<122);
console.log(top,scrollTop, deltaY);
//console.log(top,scrollTop, deltaY);
if(deltaY<0){
ins.callMethod("scrollTo", { scrollTop: top });
}

@ -0,0 +1,27 @@
const app = getApp();
Page({
data: {
},
onLoad: function (options) {
let {homework_id} = options;
this.setData({homework_id});
this.refresh();
},
async refresh(){
let {homework_id} = this.data;
let data = await app.api("homework_commons.works_list")({homework_id});
this.setData(data);
},
enterShixun(){
app.navigateTo({url:`{shixun}?identifier=${this.data.shixun_identifier}`});
},
onPullDownRefresh: function () {
},
onShareAppMessage: function () {
}
})

@ -0,0 +1,4 @@
{
"usingComponents": {},
"navigationBarTitleText": "实训作业"
}

@ -0,0 +1,10 @@
<view class="homework">
<view class="header">
<text class="title">{{homework_name}}</text>
<text class="tip" wx:for="{{homework_status}}">{{item}}</text>
</view>
<view class="footer">
<button type="main" bindtap="enterShixun">进入实训</button>
</view>
</view>

@ -0,0 +1,25 @@
page,.homework{
height: 100%;
}
.header{
text-align: center;
}
.title{
font-weight: 560;
font-size: 17px;
}
.tip{
margin: 0 4px;
background: #00b0f0;
color: white;
border-radius: 50px;
padding: 2px 6px;
font-size: 13px;
white-space: nowrap;
}
.footer{
position: absolute;
bottom: 0;
left: 0;
right: 0;
}

@ -66,7 +66,7 @@
"id": 0,
"name": "course/pages/course/course",
"pathName": "course/pages/course/course",
"query": "course_id=5141",
"query": "course_id=5141&module_type=activity",
"scene": 1011
},
{
@ -119,14 +119,7 @@
"scene": null
},
{
"id": -1,
"name": "account/pages/about/about",
"pathName": "account/pages/about/about",
"query": "identifier=i6qlxhw8a74m",
"scene": null
},
{
"id": -1,
"id": 9,
"name": "home",
"pathName": "pages/home/home",
"query": "",
@ -138,6 +131,27 @@
"pathName": "account/pages/account/account",
"query": "",
"scene": null
},
{
"id": 10,
"name": "course/pages/course_invite/course_invite",
"pathName": "course/pages/course_invite/course_invite",
"query": "course_id=5876",
"scene": null
},
{
"id": -1,
"name": "shixun_homework/pages/shixun_homework/shixun_homework",
"pathName": "shixun_homework/pages/shixun_homework/shixun_homework",
"query": "homework_id=110877",
"scene": null
},
{
"id": -1,
"name": "course/pages/course/course",
"pathName": "course/pages/course/course",
"query": "course_id=5141",
"scene": null
}
]
}

Loading…
Cancel
Save