seamwang 2 gadi atpakaļ
vecāks
revīzija
f8aa163517

+ 107 - 107
src/api/course.js

@@ -1,107 +1,107 @@
1
-import fetch from '@/common/utils/fetch.js'
2
-
3
-// 获取课程列表
4
-export function _optionCourse(params) {
5
-  return fetch('/parents/Mycourses/option_course', params)
6
-}
7
-
8
-// 获取课程筛选选项 parents/Mycourses/advanced_filter
9
-export function _filter(params) {
10
-  return fetch('/parents/Mycourses/advanced_filter', params)
11
-}
12
-// 课程详情 parents/Mycourses/course_details
13
-export function _detail(params) {
14
-  return fetch('/parents/Mycourses/course_details', params)
15
-}
16
-// 课程套餐详情 parents/Mycourses/course_gift
17
-export function _gift(params) {
18
-  return fetch('/parents/Mycourses/course_gift', params)
19
-}
20
-// 课程评价 parents/Mycourses/now_details_comment
21
-export function _comments(params) {
22
-  return fetch('/parents/Mycourses/now_details_comment', params)
23
-}
24
-// 添加购物车 parents/Commit/join_shop
25
-export function _joinShop(params, showFail = true) {
26
-  return fetch('/parents/Commit/join_shop', params, 'POST', showFail)
27
-}
28
-// 批量添加购物车
29
-export function _joinShops(params) {
30
-  return fetch('/parents/Commit/joinShopMulti', params)
31
-}
32
-// 购物车列表 /parents/Shopping/index
33
-export function _shopList(params) {
34
-  return fetch('/parents/Shopping/index', params)
35
-}
36
-// 删除购物车 /parents/Shopping/del_shopping
37
-export function _delShop(params) {
38
-  return fetch('/parents/Shopping/del_shopping', params)
39
-}
40
-// 生成订单 parents/Commit/order
41
-export function _createOrder(params) {
42
-  return fetch('/parents/Commit/order', params)
43
-}
44
-// 订单列表 parents/Ordercentre/index
45
-export function _orderCenter(params) {
46
-  return fetch('/parents/Ordercentre/index', params)
47
-}
48
-// 退课数据 get_dropcourse_byorder
49
-export function _dropList(params) {
50
-  return fetch('/parents/dropcourse/get_dropcourse_byorder', params)
51
-}
52
-// 订单支付
53
-export function _payOrder(params) {
54
-  return fetch('/parents/pay/payment', params)
55
-}
56
-// 取消订单 /parents/Ordercentre/del_order
57
-export function _cancelOrder(params) {
58
-  return fetch('/parents/Ordercentre/del_order', params)
59
-}
60
-// 进行退课 /parents/dropcourse/to_drop_course
61
-export function _dropCourse(params) {
62
-  return fetch('/parents/dropcourse/to_drop_course', params)
63
-}
64
-// 历史课程 /parents/Mycourses/course_history
65
-export function _courseHistory(params) {
66
-  return fetch('/parents/Mycourses/course_history', params)
67
-}
68
-// 我的课程 /parents/Mycourses/course_history
69
-export function _nowCourse(params) {
70
-  return fetch('/parents/Mycourses/now_course', params)
71
-}
72
-// 课程表 /parents/Mycourses/date_course
73
-export function _dateCourse(params) {
74
-  return fetch('/parents/Mycourses/date_course', params)
75
-}
76
-// 考勤记录 /parents/attendance/get_attendance
77
-export function _attendance(params) {
78
-  return fetch('/parents/attendance/get_attendance', params)
79
-}
80
-// 课堂详情 /parents/dailyclass/get_dailyclass_details
81
-export function _dailiClass(params) {
82
-  return fetch('/parents/dailyclass/get_dailyclass_details', params)
83
-}
84
-// 安全交接情况 /parents/sign/get_sign
85
-export function _getSignIn(params) {
86
-  return fetch('/parents/sign/get_sign', params)
87
-}
88
-// 进行安全交接 /parents/sign/to_sign
89
-export function _toSignIn(params) {
90
-  return fetch('/parents/sign/to_sign', params)
91
-}
92
-// 进行评价 /parents/Todayclass/comment
93
-export function _tocomment(params) {
94
-  return fetch('/parents/Todayclass/comment', params)
95
-}
96
-// 评价详情
97
-export function _commentDetail(params) {
98
-  return fetch('/parents/dailyclass/get_satisfaction', params)
99
-}
100
-// 获取请假类型
101
-export function _leaveType(params) {
102
-  return fetch('/teacher/leave/get_leave_type', params)
103
-}
104
-// 申请请假 parents/schedule/student_leave
105
-export function _askLeave(params) {
106
-  return fetch('/parents/schedule/student_leave', params)
107
-}
1
+import fetch from '@/common/utils/fetch.js'
2
+
3
+// 获取课程列表
4
+export function _optionCourse(params) {
5
+  return fetch('/parents/Mycourses/option_course', params)
6
+}
7
+
8
+// 获取课程筛选选项 parents/Mycourses/advanced_filter
9
+export function _filter(params) {
10
+  return fetch('/parents/Mycourses/advanced_filter', params)
11
+}
12
+// 课程详情 parents/Mycourses/course_details
13
+export function _detail(params) {
14
+  return fetch('/parents/Mycourses/course_details', params)
15
+}
16
+// 课程套餐详情 parents/Mycourses/course_gift
17
+export function _gift(params) {
18
+  return fetch('/parents/Mycourses/course_gift', params)
19
+}
20
+// 课程评价 parents/Mycourses/now_details_comment
21
+export function _comments(params) {
22
+  return fetch('/parents/Mycourses/now_details_comment', params, 'POST', false)
23
+}
24
+// 添加购物车 parents/Commit/join_shop
25
+export function _joinShop(params, showFail = true) {
26
+  return fetch('/parents/Commit/join_shop', params, 'POST', showFail)
27
+}
28
+// 批量添加购物车
29
+export function _joinShops(params) {
30
+  return fetch('/parents/Commit/joinShopMulti', params)
31
+}
32
+// 购物车列表 /parents/Shopping/index
33
+export function _shopList(params) {
34
+  return fetch('/parents/Shopping/index', params)
35
+}
36
+// 删除购物车 /parents/Shopping/del_shopping
37
+export function _delShop(params) {
38
+  return fetch('/parents/Shopping/del_shopping', params)
39
+}
40
+// 生成订单 parents/Commit/order
41
+export function _createOrder(params) {
42
+  return fetch('/parents/Commit/order', params)
43
+}
44
+// 订单列表 parents/Ordercentre/index
45
+export function _orderCenter(params) {
46
+  return fetch('/parents/Ordercentre/index', params)
47
+}
48
+// 退课数据 get_dropcourse_byorder
49
+export function _dropList(params) {
50
+  return fetch('/parents/dropcourse/get_dropcourse_byorder', params)
51
+}
52
+// 订单支付
53
+export function _payOrder(params) {
54
+  return fetch('/parents/pay/payment', params)
55
+}
56
+// 取消订单 /parents/Ordercentre/del_order
57
+export function _cancelOrder(params) {
58
+  return fetch('/parents/Ordercentre/del_order', params)
59
+}
60
+// 进行退课 /parents/dropcourse/to_drop_course
61
+export function _dropCourse(params) {
62
+  return fetch('/parents/dropcourse/to_drop_course', params)
63
+}
64
+// 历史课程 /parents/Mycourses/course_history
65
+export function _courseHistory(params) {
66
+  return fetch('/parents/Mycourses/course_history', params)
67
+}
68
+// 我的课程 /parents/Mycourses/course_history
69
+export function _nowCourse(params) {
70
+  return fetch('/parents/Mycourses/now_course', params)
71
+}
72
+// 课程表 /parents/Mycourses/date_course
73
+export function _dateCourse(params) {
74
+  return fetch('/parents/Mycourses/date_course', params)
75
+}
76
+// 考勤记录 /parents/attendance/get_attendance
77
+export function _attendance(params) {
78
+  return fetch('/parents/attendance/get_attendance', params)
79
+}
80
+// 课堂详情 /parents/dailyclass/get_dailyclass_details
81
+export function _dailiClass(params) {
82
+  return fetch('/parents/dailyclass/get_dailyclass_details', params)
83
+}
84
+// 安全交接情况 /parents/sign/get_sign
85
+export function _getSignIn(params) {
86
+  return fetch('/parents/sign/get_sign', params)
87
+}
88
+// 进行安全交接 /parents/sign/to_sign
89
+export function _toSignIn(params) {
90
+  return fetch('/parents/sign/to_sign', params)
91
+}
92
+// 进行评价 /parents/Todayclass/comment
93
+export function _tocomment(params) {
94
+  return fetch('/parents/Todayclass/comment', params)
95
+}
96
+// 评价详情
97
+export function _commentDetail(params) {
98
+  return fetch('/parents/dailyclass/get_satisfaction', params)
99
+}
100
+// 获取请假类型
101
+export function _leaveType(params) {
102
+  return fetch('/teacher/leave/get_leave_type', params)
103
+}
104
+// 申请请假 parents/schedule/student_leave
105
+export function _askLeave(params) {
106
+  return fetch('/parents/schedule/student_leave', params)
107
+}

+ 56 - 57
src/common/commonMethods.js

@@ -1,57 +1,56 @@
1
-// 进入新的页面的方法
2
-import urlMap from '@/common/urlMap'
3
-import Vue from 'vue'
4
-
5
-const encodeParam = function (params) {
6
-  let url = ''
7
-  for (const k in params) {
8
-    const value = params[k] !== undefined ? params[k] : ''
9
-    url += '&' + k + '=' + encodeURIComponent(value)
10
-  }
11
-  return url ? url.substring(1) : ''
12
-}
13
-
14
-const routerToFail = function (err) {
15
-  console.log(err, '跳转新页面失败')
16
-}
17
-
18
-const commonMethods = {
19
-  /**
20
-   * 保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面
21
-   * 页面跳转路径有层级限制,不能无限制跳转新页面
22
-   * @param {*} type 路径唯一类型
23
-   * @param {*} params 路径参数
24
-   * @returns {*} null
25
-   */
26
-  globalNavigateTo: function (type, params) {
27
-    if (urlMap.has(type)) {
28
-      let url = urlMap.get(type)
29
-      if (params) {
30
-        url += (url.indexOf('?') < 0 && params ? '?' : '&') + encodeParam(params)
31
-      }
32
-      uni.navigateTo({ url, fail: routerToFail })
33
-    }
34
-  },
35
-  // 关闭当前页面,跳转到应用内的某个页面
36
-  globalRedirectTo: function (type, params) {
37
-    if (urlMap.has(type)) {
38
-      let url = urlMap.get(type)
39
-      if (params) {
40
-        url += (url.indexOf('?') < 0 && params ? '?' : '&') + encodeParam(params)
41
-      }
42
-      uni.redirectTo({ url, fail: routerToFail })
43
-    }
44
-  },
45
-  // 关闭所有页面,打开应用内的某个页面
46
-  globalReLaunch: function (type, params) {
47
-    if (urlMap.has(type)) {
48
-      let url = urlMap.get(type)
49
-      if (params) {
50
-        url += (url.indexOf('?') < 0 && params ? '?' : '&') + encodeParam(params)
51
-      }
52
-      uni.reLaunch({ url, fail: routerToFail })
53
-    }
54
-  }
55
-}
56
-
57
-export default commonMethods
1
+// 进入新的页面的方法
2
+import urlMap from '@/common/urlMap'
3
+
4
+const encodeParam = function (params) {
5
+  let url = ''
6
+  for (const k in params) {
7
+    const value = params[k] !== undefined ? params[k] : ''
8
+    url += '&' + k + '=' + encodeURIComponent(value)
9
+  }
10
+  return url ? url.substring(1) : ''
11
+}
12
+
13
+const routerToFail = function (err) {
14
+  console.log(err, '跳转新页面失败')
15
+}
16
+
17
+const commonMethods = {
18
+  /**
19
+   * 保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面
20
+   * 页面跳转路径有层级限制,不能无限制跳转新页面
21
+   * @param {*} type 路径唯一类型
22
+   * @param {*} params 路径参数
23
+   * @returns {*} null
24
+   */
25
+  globalNavigateTo: function (type, params) {
26
+    if (urlMap.has(type)) {
27
+      let url = urlMap.get(type)
28
+      if (params) {
29
+        url += (url.indexOf('?') < 0 && params ? '?' : '&') + encodeParam(params)
30
+      }
31
+      uni.navigateTo({ url, fail: routerToFail })
32
+    }
33
+  },
34
+  // 关闭当前页面,跳转到应用内的某个页面
35
+  globalRedirectTo: function (type, params) {
36
+    if (urlMap.has(type)) {
37
+      let url = urlMap.get(type)
38
+      if (params) {
39
+        url += (url.indexOf('?') < 0 && params ? '?' : '&') + encodeParam(params)
40
+      }
41
+      uni.redirectTo({ url, fail: routerToFail })
42
+    }
43
+  },
44
+  // 关闭所有页面,打开应用内的某个页面
45
+  globalReLaunch: function (type, params) {
46
+    if (urlMap.has(type)) {
47
+      let url = urlMap.get(type)
48
+      if (params) {
49
+        url += (url.indexOf('?') < 0 && params ? '?' : '&') + encodeParam(params)
50
+      }
51
+      uni.reLaunch({ url, fail: routerToFail })
52
+    }
53
+  }
54
+}
55
+
56
+export default commonMethods

+ 98 - 99
src/common/utils/socket.js

@@ -1,99 +1,98 @@
1
-import store from '@/store/index'
2
-class websocketUtil {
3
-  constructor(url, time) {
4
-  /*
5
-  url 是请求的后端的地址
6
-  time 是心跳包的时间
7
-  */
8
-    this.is_open_socket = false // 避免重复连接
9
-    this.url = url || process.env.VUE_APP_BASE_WS
10
-    this.data = null
11
-    // 心跳检测
12
-    this.timeout = time || 5000 // 多少秒执行检测
13
-    this.heartbeatInterval = null // 检测服务器端是否还活着
14
-    this.reconnectTimeOut = null // 重连之后多久再次重连
15
-    this.onMessage = Function
16
-    try {
17
-      return this.connectSocketInit()
18
-    } catch (e) {
19
-      console.log('catch')
20
-      this.is_open_socket = false
21
-      this.reconnect()
22
-    }
23
-  }
24
-
25
-  // 进入这个页面的时候创建websocket连接【整个页面随时使用】
26
-  connectSocketInit () {
27
-    const token = store.getters.token
28
-    if (!token) {
29
-      console.log('无效链接')
30
-      return false
31
-    }
32
-    this.socketTask = uni.connectSocket({
33
-      url: `${this.url}?token=${token}`,
34
-      success: () => {
35
-        console.log('正准备建立websocket中...')
36
-        // 返回实例
37
-        return this.socketTask
38
-      }
39
-    })
40
-    this.socketTask.onOpen((res) => {
41
-      console.log('WebSocket连接正常!')
42
-      clearTimeout(this.reconnectTimeOut)
43
-      clearTimeout(this.heartbeatInterval)
44
-      this.is_open_socket = true
45
-      this.start()
46
-      // 注:只有连接正常打开中 ,才能正常收到消息
47
-      this.socketTask.onMessage((res) => {
48
-        try {
49
-          const data = JSON.parse(res.data)
50
-          // 业务逻辑
51
-          this.onMessage(data)
52
-        } catch (error) {
53
-          this.onMessage(res.data)
54
-        }
55
-      })
56
-    })
57
-
58
-    // 这里仅是事件监听【如果socket关闭了会执行】
59
-    this.socketTask.onClose((res) => {
60
-      if (res.code === 1000) {
61
-        this.is_open_socket = true
62
-      } else {
63
-        this.is_open_socket = false
64
-      }
65
-      console.log('已经被关闭了', res)
66
-      this.reconnect()
67
-    })
68
-  }
69
-
70
-  // 发送消息
71
-  send (value) {
72
-    // 注:只有连接正常打开中 ,才能正常成功发送消息
73
-    this.socketTask.send({
74
-      data: value
75
-    })
76
-  }
77
-
78
-  // 开启心跳检测
79
-  start () {
80
-    this.heartbeatInterval = setInterval(() => {
81
-      this.data = { type: 'start' }
82
-      this.send(JSON.stringify(this.data))
83
-    }, this.timeout)
84
-  }
85
-
86
-  // 重新连接
87
-  reconnect () {
88
-    // 停止发送心跳
89
-    clearInterval(this.heartbeatInterval)
90
-    // 如果不是人为关闭的话,进行重连
91
-    if (!this.is_open_socket) {
92
-      this.reconnectTimeOut = setTimeout(() => {
93
-        this.connectSocketInit()
94
-      }, 3000)
95
-    }
96
-  }
97
-}
98
-
99
-module.exports = websocketUtil
1
+import store from '@/store/index'
2
+class websocketUtil {
3
+  constructor(url, time) {
4
+  /*
5
+  url 是请求的后端的地址
6
+  time 是心跳包的时间
7
+  */
8
+    this.is_open_socket = false // 避免重复连接
9
+    this.url = url || process.env.VUE_APP_BASE_WS
10
+    this.data = null
11
+    // 心跳检测
12
+    this.timeout = time || 5000 // 多少秒执行检测
13
+    this.heartbeatInterval = null // 检测服务器端是否还活着
14
+    this.reconnectTimeOut = null // 重连之后多久再次重连
15
+    this.onMessage = Function
16
+    try {
17
+      return this.connectSocketInit()
18
+    } catch (e) {
19
+      console.log('catch')
20
+      this.is_open_socket = false
21
+      this.reconnect()
22
+    }
23
+  }
24
+
25
+  // 进入这个页面的时候创建websocket连接【整个页面随时使用】
26
+  connectSocketInit () {
27
+    const token = store.getters.token
28
+    if (!token) {
29
+      console.log('无效链接')
30
+      return false
31
+    }
32
+    this.socketTask = uni.connectSocket({
33
+      url: `${this.url}?token=${token}`,
34
+      success: () => {
35
+        console.log('正准备建立websocket中...')
36
+        // 返回实例
37
+        return this.socketTask
38
+      }
39
+    })
40
+    this.socketTask.onOpen((res) => {
41
+      console.log('WebSocket连接正常!')
42
+      clearTimeout(this.reconnectTimeOut)
43
+      clearTimeout(this.heartbeatInterval)
44
+      this.is_open_socket = true
45
+      this.start()
46
+      // 注:只有连接正常打开中 ,才能正常收到消息
47
+      this.socketTask.onMessage((res) => {
48
+        try {
49
+          const data = JSON.parse(res.data)
50
+          // 业务逻辑
51
+          this.onMessage(data)
52
+        } catch (error) {
53
+          this.onMessage(res.data)
54
+        }
55
+      })
56
+    })
57
+    // 这里仅是事件监听【如果socket关闭了会执行】
58
+    this.socketTask.onClose((res) => {
59
+      if (res.code === 1000) {
60
+        this.is_open_socket = true
61
+      } else {
62
+        this.is_open_socket = false
63
+      }
64
+      console.log('已经被关闭了', res)
65
+      this.reconnect()
66
+    })
67
+  }
68
+
69
+  // 发送消息
70
+  send (value) {
71
+    // 注:只有连接正常打开中 ,才能正常成功发送消息
72
+    this.socketTask.send({
73
+      data: value
74
+    })
75
+  }
76
+
77
+  // 开启心跳检测
78
+  start () {
79
+    this.heartbeatInterval = setInterval(() => {
80
+      this.data = { class: 'Index', type: 'heart' }
81
+      this.send(JSON.stringify(this.data))
82
+    }, this.timeout)
83
+  }
84
+
85
+  // 重新连接
86
+  reconnect () {
87
+    // 停止发送心跳
88
+    clearInterval(this.heartbeatInterval)
89
+    // 如果不是人为关闭的话,进行重连
90
+    if (!this.is_open_socket) {
91
+      this.reconnectTimeOut = setTimeout(() => {
92
+        this.connectSocketInit()
93
+      }, 3000)
94
+    }
95
+  }
96
+}
97
+
98
+module.exports = websocketUtil

+ 30 - 12
src/common/webSocket.js

@@ -1,12 +1,30 @@
1
-import WebSocket from '@/common/utils/socket.js'
2
-import Vue from 'vue'
3
-const socket = {
4
-  initSocket: function() {
5
-    if (!Vue.prototype.socket) {
6
-      const ws = new WebSocket()
7
-      Vue.prototype.socket = ws
8
-    }
9
-  }
10
-}
11
-
12
-export default socket
1
+import WebSocket from '@/common/utils/socket.js'
2
+import store from '@/store/index'
3
+import commonMethods from '@/common/commonMethods.js'
4
+import Vue from 'vue'
5
+const socket = {
6
+  initSocket: function() {
7
+    Vue.prototype.socket = Vue.prototype.socket || new WebSocket()
8
+    this.onMessage(Vue.prototype.socket)
9
+  },
10
+  onMessage: (ws) => {
11
+    ws.onMessage = message => {
12
+      if (typeof message !== 'object') {
13
+        return false
14
+      }
15
+      if (message.code === 400) {
16
+        uni.hideLoading()
17
+        store.dispatch('setConnect', true)
18
+        uni.showToast({ title: message.msg, icon: 'none', duration: 2000 })
19
+        return false
20
+      }
21
+      if (message.push_type === 'order') {
22
+        uni.hideLoading()
23
+        store.dispatch('setConnect', true)
24
+        commonMethods.globalNavigateTo('order', { type: 1 })
25
+      }
26
+    }
27
+  }
28
+}
29
+
30
+export default socket

+ 6 - 0
src/components/shop-cart.vue

@@ -12,6 +12,10 @@ export default {
12 12
     class_attend_id: {
13 13
       type: Number,
14 14
       default: 0
15
+    },
16
+    disableBtn: {
17
+      type: Boolean,
18
+      default: false
15 19
     }
16 20
   },
17 21
   data() {
@@ -26,6 +30,8 @@ export default {
26 30
   },
27 31
   methods: {
28 32
     goCart() {
33
+      if (this.disableBtn) return false
34
+      this.$emit('changeDisableBtn')// 改变按钮点击
29 35
       this.globalNavigateTo('classCart')
30 36
     }
31 37
   }

+ 13 - 11
src/pages/class/detail.vue

@@ -75,13 +75,13 @@
75 75
 			<view class="shop margin-top-sm shadow" v-if="detail.prop&&detail.prop.length>0">
76 76
 					<view class="shop-title">请选择课程所需要的道具</view>
77 77
 					<radio-group @change="radioChange" class="margin-top-xs">
78
-						<label  v-for="radio in radios" :key="radio.value" class="margin-right-sm">
78
+						<label  v-for="radio in radios" :key="radio.value" class="tool-choose margin-right-sm">
79 79
 								<radio :value="radio.value" class="cyan" :checked="radio.checked" style="transform:scale(0.7)"/>{{radio.name}}
80 80
 						</label>
81 81
 					</radio-group>
82 82
           <checkbox-group @change="checkboxChange" v-if="needTool==='1'" class="checkbox-group margin-top-xs">
83 83
 							<label v-for="prop in detail.prop" :key="prop.id">
84
-								<view>
84
+								<view class="tool-choose-item">
85 85
 									<checkbox :value="prop.id" class="cyan" style="transform:scale(0.7)" :checked="goods.props.includes(prop.id)"/>{{prop.name}}<text>¥{{prop.money}}</text>
86 86
 								</view>
87 87
 							</label>
@@ -156,7 +156,7 @@
156 156
 			</view>
157 157
 			<view class="static-choose text-ellipsis" v-if="goods.choose.length>0">(已选:{{goods.choose.join(',')}})</view>
158 158
 			<view class="static-order flex align-center">
159
-				 <shop-cart :class_attend_id="attend_id"></shop-cart>
159
+				 <shop-cart :class_attend_id="attend_id" :disableBtn="disableBtn" @changeDisableBtn="changeDisableBtn"></shop-cart>
160 160
 				 <button class="cu-btn round bg-student text-white margin-left-xs" :class="{'disabled':carts.includes(attend_id)||!detail.enable}" @tap="addCart">报课</button>
161 161
 			</view>
162 162
 		</view>
@@ -275,16 +275,12 @@ export default {
275 275
         }
276 276
       })
277 277
     },
278
+    changeDisableBtn() {
279
+      this.disableBtn = true
280
+    },
278 281
     addCart() {
279 282
       if (this.disableBtn) return false
280 283
       this.disableBtn = true
281
-      if (this.carts.includes(this.attend_id)) {
282
-        uni.showToast({ title: '课程已存在,请勿重复添加!', icon: 'none' })
283
-        setTimeout(() => {
284
-          this.globalNavigateTo('classCart')
285
-        }, 1000)
286
-        return false
287
-      }
288 284
       if (!this.detail.enable) {
289 285
         uni.showToast({ title: '课程已停止!', icon: 'none' })
290 286
         this.disableBtn = false
@@ -393,8 +389,14 @@ export default {
393 389
 	padding:20rpx;
394 390
 	background:#fff;
395 391
 }
392
+.tool-choose{
393
+	padding:20rpx 20rpx 20rpx 0;
394
+	&-item{
395
+		padding:10rpx 0;
396
+	}
397
+}
396 398
 .checkbox-group{
397
-	height:80px;
399
+	height:100px;
398 400
 	overflow-y:scroll;
399 401
 	border:1px solid #f5f5f5;
400 402
 }

+ 213 - 201
src/pages/class/gift.vue

@@ -1,201 +1,213 @@
1
-<template>
2
-	<view>
3
-		 <cu-custom :isBack="true" title="一键报课"></cu-custom>
4
-		 <view class="VerticalBox">
5
-			<scroll-view class="VerticalNav nav" scroll-y scroll-with-animation :scroll-top="verticalNavTop" :style="'height:calc(100vh - 70px - '+topHeader+'px)'">
6
-				<view class="cu-item" :class="index==tabCur?'text-green cur':''" v-for="(item,index) in attends" :key="index" @tap="TabSelect"
7
-				 :data-id="index">
8
-					{{weekList[index]}}
9
-				</view>
10
-			</scroll-view>
11
-			<scroll-view class="VerticalMain padding-sm" scroll-y scroll-with-animation :style="'height:calc(100vh - 70px - '+topHeader+'px)'"
12
-			 :scroll-into-view="'main-'+mainCur" @scroll="VerticalMain">
13
-       <radio-group @change="changeClass" style="width:100%;" v-for="(attend,i) in attends" :key="i">
14
-         <view class="cu-item bg-white padding margin-bottom-sm" v-for="(item,index) in attend" v-show="i==mainCur" :key="index" :id="'main-'+index">
15
-					<view class="cu-bar solid-bottom">
16
-						<view>
17
-							<label>
18
-								<view class="flex justify-between align-center">
19
-									<view><text>{{item.attend_name}}</text></view>
20
-										<view>
21
-											<radio :value="item.class_attend_id"
22
-											:disabled="!item.enable"
23
-											:class="{'disabled':!item.enable}"
24
-											:checked="checked.includes(item.class_attend_id)"  class="cyan" style="transform:scale(0.7)"/>
25
-										</view>
26
-									</view>
27
-							</label>
28
-						</view>
29
-					</view>
30
-					<view v-if="item.prop.length>0">
31
-							<checkbox-group  class="checkbox-group margin-top-xs" :data-id="item.class_attend_id" @change="propChange">
32
-									<label v-for="prop in item.prop" :key="prop.id">
33
-										<view>
34
-											<checkbox :value="prop.id"
35
-											:disabled="!item.enable"
36
-											:class="{'disabled':!item.enable}"
37
-											:checked="checked_props[mainCur].class_attend_id===item.class_attend_id&&checked_props[mainCur].prop.includes(prop.id+'')" class="cyan" style="transform:scale(0.7)"/>{{prop.name}}<text>¥{{prop.money}}</text>
38
-										</view>
39
-									</label>
40
-							</checkbox-group>
41
-					</view>
42
-				 </view>
43
-       </radio-group>
44
-			</scroll-view>
45
-		</view>
46
-		<view class="static shadow">
47
-			<view class="static-order flex">
48
-				 <shop-cart :class_attend_id="attend_id"></shop-cart>
49
-				 <button class="cu-btn round bg-student text-white margin-left-xs"  @tap="addCart">报课</button>
50
-			</view>
51
-		</view>
52
-	</view>
53
-</template>
54
-
55
-<script>
56
-import { _gift, _joinShops } from '@/api/course'
57
-import { mapGetters } from 'vuex'
58
-import shopCart from '@/components/shop-cart.vue'
59
-export default {
60
-  components: {
61
-    shopCart
62
-  },
63
-  data() {
64
-    return {
65
-      topHeader: this.globalCustomBarHeight,
66
-      package_id: 0,
67
-      attends: [],
68
-      weekList: [],
69
-      attend_id: 0, // 添加成功课程
70
-      checked: [], // 选中
71
-      checked_props: [], // 选中工具
72
-      tabCur: 1,
73
-      mainCur: 1,
74
-      verticalNavTop: 0
75
-    }
76
-  },
77
-  computed: {
78
-    ...mapGetters(['kid'])
79
-  },
80
-  onLoad(options) {
81
-    const id = decodeURIComponent(options.package_id)
82
-    this.package_id = id
83
-    this.init()
84
-  },
85
-  methods: {
86
-    init() {
87
-      _gift({ class_package_id: this.package_id }).then(res => {
88
-        this.attends = res.data.attends
89
-        Object.keys(this.attends).forEach(item => {
90
-          this.$set(this.checked_props, item, { prop: [] })
91
-        })
92
-        this.weekList = res.data.week_list
93
-      })
94
-    },
95
-    addCart() {
96
-      const _self = this
97
-      const list = this.checked_props.filter(item => item.class_attend_id).map(item => {
98
-        return {
99
-          class_attend_id: item.class_attend_id,
100
-          prop: item.prop.join(','),
101
-          student_id: this.kid
102
-        }
103
-      })
104
-      if (list.length < 1) {
105
-        uni.showToast({ title: '请先选择课程', icon: 'none' })
106
-        return false
107
-      }
108
-      _joinShops({ list }).then(res => {
109
-        if (res.code === 1) {
110
-          _self.globalNavigateTo('classCart')
111
-        }
112
-      })
113
-    },
114
-    TabSelect(e) {
115
-      this.tabCur = e.currentTarget.dataset.id
116
-      this.mainCur = e.currentTarget.dataset.id
117
-      this.verticalNavTop = (e.currentTarget.dataset.id - 1) * 50
118
-    },
119
-    changeClass(e) {
120
-      const value = Number(e.detail.value)
121
-      this.checked[this.mainCur] = value
122
-      this.$set(this.checked, this.mainCur, value)
123
-      this.$set(this.checked_props, this.mainCur, { class_attend_id: value, prop: [] })
124
-    },
125
-    propChange(e) {
126
-      const parentId = e.target.dataset.id
127
-      const values = e.detail.value
128
-      if (!this.checked.includes(parentId)) {
129
-        this.$set(this.checked, this.mainCur, parentId)
130
-      }
131
-      const item = { class_attend_id: parentId, prop: values }
132
-      this.$set(this.checked_props, this.mainCur, item)
133
-    },
134
-    VerticalMain(e) {
135
-
136
-    }
137
-  }
138
-}
139
-</script>
140
-
141
-<style lang="scss" scoped>
142
-	::v-deep radio.disabled::before,::v-deep checkbox.disabled::before{
143
-		color:#e1e1e1 !important;
144
-	}
145
-	.static{
146
-			position: fixed;
147
-			left: 0;
148
-			right: 0;
149
-			bottom: 0;
150
-			display: flex;
151
-			background: #fff;
152
-			height: 70px;
153
-			align-items: center;
154
-			padding: 0 0.8rem;
155
-			justify-content: flex-end;
156
-	}
157
-	.fixed {
158
-		position: fixed;
159
-		z-index: 99;
160
-	}
161
-	.VerticalNav.nav {
162
-		width: 200upx;
163
-		white-space: initial;
164
-	}
165
-
166
-	.VerticalNav.nav .cu-item {
167
-		width: 100%;
168
-		text-align: center;
169
-		background-color: #fff;
170
-		margin: 0;
171
-		border: none;
172
-		height: 50px;
173
-		position: relative;
174
-	}
175
-
176
-	.VerticalNav.nav .cu-item.cur {
177
-		background-color: #f1f1f1;
178
-	}
179
-
180
-	.VerticalNav.nav .cu-item.cur::after {
181
-		content: "";
182
-		width: 8upx;
183
-		height: 30upx;
184
-		border-radius: 10upx 0 0 10upx;
185
-		position: absolute;
186
-		background-color: currentColor;
187
-		top: 0;
188
-		right: 0upx;
189
-		bottom: 0;
190
-		margin: auto;
191
-	}
192
-
193
-	.VerticalBox {
194
-		display: flex;
195
-	}
196
-
197
-	.VerticalMain {
198
-		background-color: #f1f1f1;
199
-		flex: 1;
200
-	}
201
-</style>
1
+<template>
2
+	<view>
3
+		 <cu-custom :isBack="true" title="一键报课"></cu-custom>
4
+		 <view class="VerticalBox">
5
+			<scroll-view class="VerticalNav nav" scroll-y scroll-with-animation :scroll-top="verticalNavTop" :style="'height:calc(100vh - 70px - '+topHeader+'px)'">
6
+				<view class="cu-item" :class="index==tabCur?'text-green cur':''" v-for="(item,index) in attends" :key="index" @tap="TabSelect"
7
+				 :data-id="index">
8
+					{{weekList[index]}}
9
+				</view>
10
+			</scroll-view>
11
+			<scroll-view class="VerticalMain padding-sm" scroll-y scroll-with-animation :style="'height:calc(100vh - 70px - '+topHeader+'px)'"
12
+			 :scroll-into-view="'main-'+mainCur" @scroll="VerticalMain">
13
+       <radio-group @change="changeClass" style="width:100%;" v-for="(attend,i) in attends" :key="i">
14
+         <view class="cu-item bg-white padding margin-bottom-sm" v-for="(item,index) in attend" v-show="i==mainCur" :key="index" :id="'main-'+index">
15
+					<view class="cu-bar solid-bottom">
16
+						<view>
17
+							<label>
18
+								<view class="flex justify-between align-center">
19
+									<view><text>{{item.attend_name}}</text></view>
20
+										<view>
21
+											<radio :value="item.class_attend_id"
22
+											:disabled="!item.enable"
23
+											:class="{'disabled':!item.enable}"
24
+											:checked="checked.includes(item.class_attend_id)"  class="cyan" style="transform:scale(0.7)"/>
25
+										</view>
26
+									</view>
27
+							</label>
28
+						</view>
29
+					</view>
30
+					<view v-if="item.prop.length>0">
31
+							<checkbox-group  class="checkbox-group margin-top-xs" :data-id="item.class_attend_id" @change="propChange">
32
+									<label v-for="prop in item.prop" :key="prop.id">
33
+										<view>
34
+											<checkbox :value="prop.id"
35
+											:disabled="!item.enable"
36
+											:class="{'disabled':!item.enable}"
37
+											:checked="checked_props[mainCur].class_attend_id===item.class_attend_id&&checked_props[mainCur].prop.includes(prop.id+'')" class="cyan" style="transform:scale(0.7)"/>{{prop.name}}<text>¥{{prop.money}}</text>
38
+										</view>
39
+									</label>
40
+							</checkbox-group>
41
+					</view>
42
+				 </view>
43
+       </radio-group>
44
+			</scroll-view>
45
+		</view>
46
+		<view class="static shadow">
47
+			<view class="static-order flex">
48
+				 <shop-cart :class_attend_id="attend_id"  @changeDisableBtn="changeDisableBtn"></shop-cart>
49
+				 <button class="cu-btn round bg-student text-white margin-left-xs"  @tap="addCart">报课</button>
50
+			</view>
51
+		</view>
52
+	</view>
53
+</template>
54
+
55
+<script>
56
+import { _gift, _joinShops } from '@/api/course'
57
+import { mapGetters } from 'vuex'
58
+import shopCart from '@/components/shop-cart.vue'
59
+export default {
60
+  components: {
61
+    shopCart
62
+  },
63
+  data() {
64
+    return {
65
+      topHeader: this.globalCustomBarHeight,
66
+      package_id: 0,
67
+      attends: [],
68
+      weekList: [],
69
+      attend_id: 0, // 添加成功课程
70
+      checked: [], // 选中
71
+      checked_props: [], // 选中工具
72
+      tabCur: 1,
73
+      mainCur: 1,
74
+      verticalNavTop: 0,
75
+      disableBtn: false // 避免多次重复点击
76
+    }
77
+  },
78
+  computed: {
79
+    ...mapGetters(['kid'])
80
+  },
81
+  onLoad(options) {
82
+    const id = decodeURIComponent(options.package_id)
83
+    this.package_id = id
84
+    this.init()
85
+  },
86
+  onShow() {
87
+    this.disableBtn = false
88
+  },
89
+  methods: {
90
+    init() {
91
+      _gift({ class_package_id: this.package_id }).then(res => {
92
+        this.attends = res.data.attends
93
+        Object.keys(this.attends).forEach(item => {
94
+          this.$set(this.checked_props, item, { prop: [] })
95
+        })
96
+        this.weekList = res.data.week_list
97
+      })
98
+    },
99
+    changeDisableBtn() {
100
+      this.disableBtn = true
101
+    },
102
+    addCart() {
103
+      if (this.disableBtn) return false
104
+      this.disableBtn = true
105
+      const _self = this
106
+      const list = this.checked_props.filter(item => item.class_attend_id).map(item => {
107
+        return {
108
+          class_attend_id: item.class_attend_id,
109
+          prop: item.prop.join(','),
110
+          student_id: this.kid
111
+        }
112
+      })
113
+      if (list.length < 1) {
114
+        uni.showToast({ title: '请先选择课程', icon: 'none' })
115
+        this.disableBtn = false
116
+        return false
117
+      }
118
+      _joinShops({ list }).then(res => {
119
+        if (res.code === 1) {
120
+          _self.globalNavigateTo('classCart')
121
+        } else {
122
+          this.disableBtn = false
123
+        }
124
+      })
125
+    },
126
+    TabSelect(e) {
127
+      this.tabCur = e.currentTarget.dataset.id
128
+      this.mainCur = e.currentTarget.dataset.id
129
+      this.verticalNavTop = (e.currentTarget.dataset.id - 1) * 50
130
+    },
131
+    changeClass(e) {
132
+      const value = Number(e.detail.value)
133
+      this.checked[this.mainCur] = value
134
+      this.$set(this.checked, this.mainCur, value)
135
+      this.$set(this.checked_props, this.mainCur, { class_attend_id: value, prop: [] })
136
+    },
137
+    propChange(e) {
138
+      const parentId = e.target.dataset.id
139
+      const values = e.detail.value
140
+      if (!this.checked.includes(parentId)) {
141
+        this.$set(this.checked, this.mainCur, parentId)
142
+      }
143
+      const item = { class_attend_id: parentId, prop: values }
144
+      this.$set(this.checked_props, this.mainCur, item)
145
+    },
146
+    VerticalMain(e) {
147
+
148
+    }
149
+  }
150
+}
151
+</script>
152
+
153
+<style lang="scss" scoped>
154
+	::v-deep radio.disabled::before,::v-deep checkbox.disabled::before{
155
+		color:#e1e1e1 !important;
156
+	}
157
+	.static{
158
+			position: fixed;
159
+			left: 0;
160
+			right: 0;
161
+			bottom: 0;
162
+			display: flex;
163
+			background: #fff;
164
+			height: 70px;
165
+			align-items: center;
166
+			padding: 0 0.8rem;
167
+			justify-content: flex-end;
168
+	}
169
+	.fixed {
170
+		position: fixed;
171
+		z-index: 99;
172
+	}
173
+	.VerticalNav.nav {
174
+		width: 200upx;
175
+		white-space: initial;
176
+	}
177
+
178
+	.VerticalNav.nav .cu-item {
179
+		width: 100%;
180
+		text-align: center;
181
+		background-color: #fff;
182
+		margin: 0;
183
+		border: none;
184
+		height: 50px;
185
+		position: relative;
186
+	}
187
+
188
+	.VerticalNav.nav .cu-item.cur {
189
+		background-color: #f1f1f1;
190
+	}
191
+
192
+	.VerticalNav.nav .cu-item.cur::after {
193
+		content: "";
194
+		width: 8upx;
195
+		height: 30upx;
196
+		border-radius: 10upx 0 0 10upx;
197
+		position: absolute;
198
+		background-color: currentColor;
199
+		top: 0;
200
+		right: 0upx;
201
+		bottom: 0;
202
+		margin: auto;
203
+	}
204
+
205
+	.VerticalBox {
206
+		display: flex;
207
+	}
208
+
209
+	.VerticalMain {
210
+		background-color: #f1f1f1;
211
+		flex: 1;
212
+	}
213
+</style>

+ 14 - 16
src/pages/class/shoppingCart.vue

@@ -74,10 +74,10 @@ export default {
74 74
   },
75 75
   computed: {
76 76
     ...mapGetters([
77
-      'carts', 'phone'
77
+      'carts', 'phone', 'ifConnectOrder'
78 78
     ])
79 79
   },
80
-  onLoad(option) {
80
+  onShow() {
81 81
     this.get_list()
82 82
     socket.initSocket()
83 83
   },
@@ -106,6 +106,10 @@ export default {
106 106
       })
107 107
     },
108 108
     pay(item) {
109
+      uni.showLoading({
110
+        mask: true,
111
+        title: '加载中...'
112
+      })
109 113
       const order = JSON.stringify([item])
110 114
       let carts = deepClone(this.carts)
111 115
       const index = carts.indexOf(item.class_attend_id)
@@ -113,21 +117,15 @@ export default {
113 117
       if (!this.phone) {
114 118
         return this.globalNavigateTo('bindPhone')
115 119
       }
116
-      _createOrder({ result: order }).then(res => {
117
-        this.socket.onMessage = message => {
118
-          if (typeof message !== 'object') {
119
-            return false
120
-          }
121
-          if (message.push_type !== 'order') {
122
-            return false
120
+      _createOrder({ result: order, notShowLoading: true }).then(res => {
121
+        this.$store.dispatch('setCarts', carts)
122
+        setTimeout(() => {
123
+          if (!this.ifConnectOrder) { // socket非正常状态
124
+            uni.hideLoading()
125
+            this.globalNavigateTo('order', { type: 1 })
123 126
           }
124
-          if (message.code === 400) {
125
-            uni.showToast({ title: message.msg, icon: 'none', duration: 2000 })
126
-            return false
127
-          }
128
-          this.$store.dispatch('setCarts', carts)
129
-          this.globalNavigateTo('order')
130
-        }
127
+          this.$store.dispatch('setConnect', false)
128
+        }, 3000)
131 129
       })
132 130
     }
133 131
   }

+ 4 - 6
src/pages/order/index.vue

@@ -84,7 +84,7 @@
84 84
 										<view class="card-title">{{item.name}}</view>
85 85
 										<view class="card-item margin-top-xs">
86 86
 											<text class="card-label">时间:</text>
87
-											<text class="card-text">{{item.attend_day}}</text>
87
+											<text class="card-text">{{item.day}}</text>
88 88
 										</view>
89 89
 										<view class="card-item margin-top-xs" >
90 90
 											<text class="card-label">课时:</text>
@@ -180,9 +180,7 @@ export default {
180 180
   },
181 181
   methods: {
182 182
     refresh() {
183
-      this.currentIndex = 0
184 183
       this.params.page = 1
185
-      this.params.type = 5
186 184
       this.get_list()
187 185
     },
188 186
     onRefresh() {
@@ -241,7 +239,7 @@ export default {
241 239
       const _self = this
242 240
       uni.showModal({
243 241
         title: '提示',
244
-        content: '确定要删除?',
242
+        content: '确定退课?',
245 243
         cancelText: '取消',
246 244
         confirmText: '确定',
247 245
         success: res => {
@@ -290,7 +288,7 @@ export default {
290 288
                 paySign: res.data.paySign,
291 289
                 success: function (res) {
292 290
                   _self.isPaying = false
293
-                  _self.refresh()
291
+                  _self.changeTab(0)
294 292
                 },
295 293
                 fail: function(res) {
296 294
                   _self.isPaying = false
@@ -314,7 +312,7 @@ export default {
314 312
           if (res.confirm) {
315 313
             _cancelOrder({ order_id: id }).then(res => {
316 314
               uni.showToast({ title: res.msg, icon: 'none' })
317
-              _self.refresh()
315
+              _self.changeTab(0)
318 316
             })
319 317
           }
320 318
         }

+ 16 - 16
src/store/index.js

@@ -1,16 +1,16 @@
1
-import Vue from 'vue'
2
-import Vuex from 'vuex'
3
-import app from '@/store/app.js'
4
-import data from '@/store/data.js'
5
-import user from '@/store/user.js'
6
-
7
-Vue.use(Vuex)
8
-
9
-export default new Vuex.Store({
10
-  strict: process.env.NODE_ENV !== 'production', // 在非生产环境下,使用严格模式
11
-  modules: {
12
-    app,
13
-    data,
14
-    user
15
-  }
16
-})
1
+import Vue from 'vue'
2
+import Vuex from 'vuex'
3
+import app from '@/store/app.js'
4
+import data from '@/store/data.js'
5
+import user from '@/store/user.js'
6
+
7
+Vue.use(Vuex)
8
+
9
+export default new Vuex.Store({
10
+  strict: process.env.NODE_ENV !== 'production', // 在非生产环境下,使用严格模式
11
+  modules: {
12
+    app,
13
+    data,
14
+    user
15
+  }
16
+})

+ 10 - 0
src/store/user.js

@@ -5,6 +5,7 @@ export default {
5 5
     session: '',
6 6
     kid: 0,
7 7
     phone: '',
8
+    ifConnectOrder: false, // socket连接订单正常
8 9
     carts: null// 购物车
9 10
   },
10 11
   getters: {
@@ -12,6 +13,9 @@ export default {
12 13
       const user = uni.getStorageSync('user')
13 14
       return state.user || user ? JSON.parse(user) : {}
14 15
     },
16
+    ifConnectOrder(state) {
17
+      return state.ifConnectOrder
18
+    },
15 19
     kid(state) {
16 20
       return state.kid || uni.getStorageSync('kid')
17 21
     },
@@ -80,6 +84,9 @@ export default {
80 84
         key: 'carts',
81 85
         data: JSON.stringify(carts)
82 86
       })
87
+    },
88
+    SET_CONNECT(state, bool) {
89
+      state.ifConnectOrder = bool
83 90
     }
84 91
   },
85 92
   actions: {
@@ -89,6 +96,9 @@ export default {
89 96
         resolve(true)
90 97
       })
91 98
     },
99
+    setConnect({ commit }, bool) {
100
+      commit('SET_CONNECT', bool)
101
+    },
92 102
     setUser({ commit }, user) {
93 103
       commit('SET_USER', user)
94 104
     },