zjxpcyc 6 年之前
父節點
當前提交
963e6450b0

+ 1
- 1
dist/index.html 查看文件

@@ -1 +1 @@
1
-<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link rel=stylesheet href=//at.alicdn.com/t/font_775069_dwqa9wy3lkh.css><link rel="shortcut icon" href=favorite.ico><title>城的空间后台管理系统</title><link href=./static/css/app.f404906b44856b72c6d22da1ac019ab1.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.3ad1d5771e9b13dbdad2.js></script><script type=text/javascript src=./static/js/vendor.992319e39e0ff64940a3.js></script><script type=text/javascript src=./static/js/app.93f4ee001438a3a439fb.js></script></body></html>
1
+<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link rel=stylesheet href=//at.alicdn.com/t/font_775069_dwqa9wy3lkh.css><link rel="shortcut icon" href=favorite.ico><title>城的空间后台管理系统</title><link href=./static/css/app.2b6862742e5b7ddbd4c73a63f85dc175.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=./static/js/manifest.d824a66773bc281133c0.js></script><script type=text/javascript src=./static/js/vendor.d93cccd3231f9f669168.js></script><script type=text/javascript src=./static/js/app.3be0be8da89125188ad1.js></script></body></html>

+ 5318
- 5187
package-lock.json
文件差異過大導致無法顯示
查看文件


+ 91
- 155
src/pages/system/newOrder/newOrderList/index.vue 查看文件

@@ -25,7 +25,7 @@
25 25
       <div class="moreFilter"></div>
26 26
     </div>
27 27
     <div class="order-list-box">
28
-      <div style='position:relative;' v-for="(item,index) in list" :key="index">
28
+      <div style='position:relative;' v-for="(item,index) in ordersList" :key="index">
29 29
         <div>
30 30
           <div style="padding:25px 20px 5px;border-bottom:2px solid #cccccc;display:flex;align-items: center;">
31 31
             <!-- <i class="iconfont icon-yinchenglogo" style="font-size:70px;color:red;position: relative;bottom: 20px;margin-right:10px;"></i> -->
@@ -46,28 +46,7 @@
46 46
           <div style="padding:10px 20px;border-bottom:1px solid #cccccc;white-space: normal;">备注:{{item.Remark}}</div>
47 47
           <div style="padding:10px 20px;">下单人:{{item.UserName}}</div>
48 48
         </div>
49
-        <div class="print-area" :class="'item_' + item.OrdersId" style="width:180px;">
50
-          <div style="padding:0px 10px 5px;border-bottom:2px solid #cccccc;">
51
-            <div style="display:inline-block;">
52
-              <img class="topIcon" style="display:block;width:60%;margin:0 0 20px 0px;" src="http://jingcheng-resourceplat.oss-cn-shanghai.aliyuncs.com/upload/111101940020.png" alt="">
53
-              <span style="display:block;font-size:20px;font-weight:700;text-align: center;"> <img width='30px' :src='item.AreaIconWhite' alt=""> {{item.AreaName + item.TableNo}}</span>
54
-            </div>
55
-          </div>
56
-          <div style="padding:10px 10px 5px;border-bottom:1px solid #cccccc;" v-for='(item1,index1) in item.Goods' :key='index1'>
57
-            <div style="font-size:12px;"><span style="display:inline-block;width:75%;text-align:left;">{{item1.GoodsName}}</span><span style="display:inline-block;width:22%;text-align:right;font-size:12px;" v-if='!item1.SpecName'>× {{item1.Number}}</span></div>
58
-            <div style="margin-top:8px;" v-if='item1.SpecName'>
59
-              <span style="display:inline-block;width:75%;text-align:left;color:#cccccc;font-size:12px;">{{item1.SpecName}}</span>
60
-              <span style="display:inline-block;width:20%;text-align:right;font-size:12px;">× {{item1.Number}}</span>
61
-            </div>
62
-          </div>
63
-          <div style="padding:10px 10px 5px;border-bottom:1px solid #cccccc;">
64
-            <div style="font-size:12px;">下单人:{{item.UserName}}</div>
65
-            <span style="display:block;margin-top:10px;font-size:12px;">下单时间:{{toolClass.dateFormat(item.CreateDate)}}</span>
66
-          </div>
67
-          <div style="padding:10px 10px;font-size:12px;">备注:{{item.Remark}}</div>
68
-          <div style="text-align: right;font-size: 12px;">城的空间.城咖啡</div>
69
-          <div style="height:10px"></div>
70
-        </div>
49
+        <print-list :print-list="printList" :lodop="lodop" @printed="clearPrintList" />
71 50
         <div class="btns">
72 51
           <span @click="cancel(item.OrdersId,index)">取消</span>
73 52
           <span @click="submit(item.OrdersId,index)">确定</span>
@@ -82,22 +61,29 @@ import { createNamespacedHelpers, mapState, mapActions } from 'vuex'
82 61
 import { getLodop } from '@/util/LodopFuncs'
83 62
 import { formatTimeBySeconds } from '@/util/util'
84 63
 import { replaceURLParams } from '@/util/ajax'
64
+import XWebSocket from '@/util/websocket'
85 65
 
86 66
 // const WebSocket = require('ws')
87 67
 const { mapState: mapOrderState, mapActions: mapOrderActions } = createNamespacedHelpers('goodsorder')
88 68
 
89
-var LODOP
90 69
 export default {
91 70
   name: '',
71
+  components: {
72
+    'print-list': () => import('./print'),
73
+  },
92 74
   data () {
93 75
     return {
76
+      lodop: null,
77
+      ws: null,
78
+      wsID: '',
79
+      printList: [],
80
+
94 81
       total: 0,
95 82
       postData: { // 表格搜索条件
96 83
         phone: '', // 手机号
97 84
         page: 1, // 当前页码
98 85
         pagesize: 10, // 请求数据量
99 86
       },
100
-      currentList: [],
101 87
       leftTimes: {},
102 88
       business: false,
103 89
       caseid: '',
@@ -108,8 +94,23 @@ export default {
108 94
   },
109 95
   computed: {
110 96
     ...mapOrderState({
111
-      list: x => (x.ordersList || {}).list || [],
112
-      businessStatus: x => x.businessStatus
97
+      ordersList: x => x.ordersList,
98
+    }),
99
+    ...mapOrderState({
100
+      businessStatus (state) {
101
+        if (!state.businessStatus) {
102
+          this.ws.close()
103
+        }
104
+
105
+        if (state.businessStatus && (this.wsID !== this.CaseId) && this.CaseId) {
106
+          this.ws.close()
107
+          this.initWebSocket()
108
+        }
109
+
110
+        this.wsID = this.CaseId
111
+
112
+        return state.businessStatus
113
+      }
113 114
     }),
114 115
     ...mapState({
115 116
       cases: x => x.app.cases.list,
@@ -123,90 +124,69 @@ export default {
123 124
       set (val) {
124 125
         this.caseid = val
125 126
       }
126
-    }
127
+    },
127 128
   },
128 129
   created () {
130
+    this.lodop = getLodop()
131
+    this.lodop.PRINT_INIT('城咖啡订单')
132
+    this.lodop.SET_PRINT_PAGESIZE(3, 480, 40, '')
133
+
129 134
     this.updateSystemInfo().then(() => {
130 135
       console.log(this.CaseId)
131 136
       if (this.CaseId) {
132 137
         this.init()
133 138
       }
134 139
     })
135
-  },
136
-  mounted () {
137
-    // setTimeout(window.location.reload, 600 * 1000)
138
-  },
139
-  beforeRouteLeave (to, from, next) {
140
-    // 导航离开该组件的对应路由时调用
141
-    // 可以访问组件实例 `this`
142
-    // console.log(this.websockets)
143
-    this.needReload = false
144
-    Object.keys(this.websockets).forEach((key) => {
145
-      this.destroyWebsocket(this.websockets[key])
140
+
141
+    this.ws = new XWebSocket({
142
+      message: this.receviedNewOrders.bind(this),
143
+      delay: 10,
144
+      autoConnect: true,
146 145
     })
147
-    this.websockets = {}
148
-    next()
146
+  },
147
+  beforeDestroyed () {
148
+    this.ws.close()
149 149
   },
150 150
   methods: {
151 151
     init () {
152
-      if (this.needReload) {
153
-        this.needReload = false
154
-        Object.keys(this.websockets).forEach((key) => {
155
-          // console.log(key, this.websockets[key])
156
-          this.destroyWebsocket(this.websockets[key])
152
+      // 必须选案场
153
+      if (!this.CaseId) {
154
+        this.$message({
155
+          type: 'info',
156
+          message: '请先选择案场'
157 157
         })
158
-        this.websockets = {}
159
-        // console.log('init')
160
-        var param = []
161
-        if (!this.CaseId) {
162
-          this.$message({
163
-            type: 'info',
164
-            message: '请先选择案场'
165
-          })
166
-          return
158
+        return
159
+      }
160
+
161
+      // 获取新单
162
+      this.GetOrdersList({ caseid: this.CaseId }).then(list => {
163
+        // 打印新单
164
+        if (list) {
165
+          this.printList = list.map(x => x.IsIntimidate === 0)
167 166
         }
168
-        clearInterval(this.interval)
169
-        // console.log(this.CaseId)
170
-        this.GetOrdersList({ caseid: this.CaseId }).then((res) => {
171
-          for (var n = 0; n < (res.list || []).length; n++) {
172
-            if (res.list[n].IsIntimidate === 0) {
173
-              param.push(res.list[n].OrdersId)
174
-            }
175
-          }
176
-          var bool = true
177
-          var timer = setInterval(() => {
178
-            if (param.length && bool) {
179
-              bool = false
180
-              this.printPdf(`item_${param[0]}`)
181
-              this.putPrintGoodsOrder({
182
-                id: param[0]
183
-              }).then(() => {
184
-                param.splice(0, 1)
185
-                bool = true
186
-              })
187
-            } else {
188
-              this.needReload = true
189
-              clearInterval(timer)
190
-            }
191
-          }, 300)
192
-          this.getBusinessStatus(this.CaseId).then(() => {
193
-            if (this.businessStatus) {
194
-              this.initWebSocket()
195
-            }
196
-          })
167
+
168
+        // 开张, 则实时监控新单
169
+        this.getBusinessStatus(this.CaseId).then(() => {
170
+
197 171
         })
172
+
173
+        // 页面倒计时
174
+        clearInterval(this.interval)
198 175
         this.refreshList()
199
-      }
176
+      })
200 177
     },
201 178
     refreshList () {
202 179
       this.interval = setInterval(() => {
203 180
         const now = (new Date()).valueOf()
204
-        this.leftTimes = this.list.reduce((acc, it) => {
181
+        this.leftTimes = (this.ordersList || []).reduce((acc, it) => {
205 182
           const showDT = now - ((new Date(it.CreateDate)).valueOf())
206 183
           return { ...acc, [`${it.OrdersId}`]: formatTimeBySeconds(showDT) }
207 184
         }, {})
208 185
       }, 1000)
209 186
     },
187
+    clearPrintList () {
188
+      this.printList = []
189
+    },
210 190
     timeOut (c) {
211 191
       let cTime = new Date(c).valueOf()
212 192
       let time = new Date().valueOf()
@@ -241,8 +221,8 @@ export default {
241 221
             type: 'success',
242 222
             message: '确认订单成功'
243 223
           })
244
-          this.list.splice(index, 1)
245
-          this.updateList({ list: this.list })
224
+
225
+          this.updateList({ list: this.ordersList.filter(x => x.OrdersId !== id) })
246 226
         })
247 227
       }).catch((res) => {
248 228
         this.$message({
@@ -262,8 +242,8 @@ export default {
262 242
             type: 'success',
263 243
             message: '取消订单成功'
264 244
           })
265
-          this.list.splice(index, 1)
266
-          this.updateList({ list: this.list })
245
+
246
+          this.updateList({ list: this.ordersList.filter(x => x.OrdersId !== id) })
267 247
         })
268 248
       }).catch((res) => {
269 249
         this.$message({
@@ -272,82 +252,37 @@ export default {
272 252
         })
273 253
       })
274 254
     },
275
-    printPdf (cl) {
276
-      this.CreateOneFormPage(cl)
277
-      LODOP.PRINT()
278
-    },
279
-    CreateOneFormPage (cl) {
280
-      LODOP = getLodop()
281
-      LODOP.PRINT_INIT('订单')
282
-      LODOP.SET_PRINT_PAGESIZE(3, 480, 40, '')
283
-      LODOP.ADD_PRINT_HTM(0, 0, document.getElementsByClassName(cl)[0].offsetWidth, document.getElementsByClassName(cl)[0].offsetHeight, document.getElementsByClassName(cl)[0].innerHTML)
284
-    },
285 255
     initWebSocket () {
286 256
       console.log('initWebSocket')
287
-      // console.log(this.user)
288 257
       let caseid = this.CaseId
289 258
       let id = this.userInfo.UserId
290 259
       const wsPath = this.$api.system.notify.newGoodsOrders.url
291 260
       const wsRealPath = replaceURLParams(wsPath, { grps: caseid, id })
292
-      this.newWebsocket(wsRealPath)
261
+      const wsURL = `${window.location.origin.replace('http', 'ws')}${wsRealPath}?token=${localStorage.getItem('JWT')}`
262
+      this.ws.connect(wsURL)
293 263
     },
294
-    websocketonmessage (e) {
295
-      // let oldList = this.list
296
-      let newList = JSON.parse(e.data).data.refreshOnlineGoodsOrders
297
-      // let newinfo = newList.filter(x => this.list.filter(item => item.OrdersId === x.OrdersId).length === 0)
298
-      this.updateList({ list: this.list.concat(newList) }).then(() => {
299
-        newList.forEach((it) => {
300
-          // console.log(it)
301
-          if (!it.IsIntimidate) {
302
-            // console.log('print')
303
-            this.putPrintGoodsOrder({
304
-              id: it.OrdersId
305
-            }).then(() => {
306
-              this.printPdf(`item_${it.OrdersId}`)
264
+    receviedNewOrders (e) {
265
+      const newOrders = JSON.parse(e.data).data.refreshOnlineGoodsOrders
266
+      if (!newOrders || !newOrders.length) return
267
+
268
+      // 放入待制作队列
269
+      this.updateList({ list: this.list.concat(newOrders) })
270
+
271
+      // 放入待打队列
272
+      const ps = newOrders.filter(x => x.IsIntimidate === 0).map((orders) => {
273
+        return new Promise((resolve, reject) => {
274
+          if (orders.IsIntimidate === 0) {
275
+            // 先远程更新掉打单状态字段
276
+            this.putPrintGoodsOrder({id: orders.OrdersId}).then(() => {
277
+              resolve(orders)
307 278
             })
279
+          } else {
280
+            resolve()
308 281
           }
309 282
         })
310 283
       })
311
-    },
312
-    newWebsocket (wsRealPath) {
313
-      const ws = this.websockets[wsRealPath]
314
-      // console.log('newWebsocket', ws)
315
-      if (!ws) {
316
-        const url = `${window.location.origin.replace('http', 'ws')}${wsRealPath}?token=${localStorage.getItem('JWT')}`
317
-        this.websockets[wsRealPath] = new WebSocket(url)
318
-        this.websockets[wsRealPath].onopen = console.log
319
-        this.websockets[wsRealPath].onmessage = this.websocketonmessage
320
-        this.websockets[wsRealPath].onclose = ((ws) => {
321
-          return e => this.reloadWebSocket(e, ws)
322
-        })(this.websockets[wsRealPath])
323
-        this.websockets[wsRealPath].interval = setInterval(() => {
324
-          try { this.websockets[wsRealPath].send(10) } catch (err) { console.log(err) }
325
-        }, 120000)
326
-      }
327
-    },
328
-    reloadWebSocket (e, ws) {
329
-      if (e.target.readyState >= 2) {
330
-        // console.log(e.currentTarget.url)
331
-        Object.keys(this.websockets).forEach((key) => {
332
-          // this.websockets[key].close()
333
-          clearInterval(this.websockets[key].interval)
334
-        })
335
-        ws = null
336
-        setTimeout(() => {
337
-          if (this.needReload) { // 此变量判断是否需要重连
338
-            this.websockets = {}
339
-            this.initWebSocket()
340
-          }
341
-        }, 5000)
342
-      }
343
-    },
344
-    destroyWebsocket (ws) {
345
-      ws.onclose = ((ws) => {
346
-        // console.log('close')
347
-      })(ws)
348
-      ws.close()
349
-      clearInterval(ws.interval)
350
-      ws = null
284
+
285
+      Promise.all(ps).then((its = []) => this.printList.concat(its.filter(x => x)))
351 286
     },
352 287
     open () {
353 288
       if (!this.CaseId) {
@@ -369,6 +304,7 @@ export default {
369 304
         })
370 305
         return
371 306
       }
307
+      this.ws.close()
372 308
       this.closeBusiness(this.CaseId)
373 309
     }
374 310
   }

+ 60
- 0
src/pages/system/newOrder/newOrderList/print.vue 查看文件

@@ -0,0 +1,60 @@
1
+<template>
2
+  <div>
3
+    <div refs="printPages" v-for="(item, inx) in printList" :key="inx" class="print-area" :class="'item_' + item.OrdersId" style="width:180px;">
4
+      <div style="padding:0px 10px 5px;border-bottom:2px solid #cccccc;">
5
+        <div style="display:inline-block;">
6
+          <img class="topIcon" style="display:block;width:60%;margin:0 0 20px 0px;" src="http://jingcheng-resourceplat.oss-cn-shanghai.aliyuncs.com/upload/111101940020.png" alt="">
7
+          <span style="display:block;font-size:20px;font-weight:700;text-align: center;"> <img width='30px' :src='item.AreaIconWhite' alt=""> {{item.AreaName + item.TableNo}}</span>
8
+        </div>
9
+      </div>
10
+      <div style="padding:10px 10px 5px;border-bottom:1px solid #cccccc;" v-for='(item1,index1) in item.Goods' :key='index1'>
11
+        <div style="font-size:12px;"><span style="display:inline-block;width:75%;text-align:left;">{{item1.GoodsName}}</span><span style="display:inline-block;width:22%;text-align:right;font-size:12px;" v-if='!item1.SpecName'>× {{item1.Number}}</span></div>
12
+        <div style="margin-top:8px;" v-if='item1.SpecName'>
13
+          <span style="display:inline-block;width:75%;text-align:left;color:#cccccc;font-size:12px;">{{item1.SpecName}}</span>
14
+          <span style="display:inline-block;width:20%;text-align:right;font-size:12px;">× {{item1.Number}}</span>
15
+        </div>
16
+      </div>
17
+      <div style="padding:10px 10px 5px;border-bottom:1px solid #cccccc;">
18
+        <div style="font-size:12px;">下单人:{{item.UserName}}</div>
19
+        <span style="display:block;margin-top:10px;font-size:12px;">下单时间:{{toolClass.dateFormat(item.CreateDate)}}</span>
20
+      </div>
21
+      <div style="padding:10px 10px;font-size:12px;">备注:{{item.Remark}}</div>
22
+      <div style="text-align: right;font-size: 12px;">城的空间.城咖啡</div>
23
+      <div style="height:10px"></div>
24
+    </div>
25
+  </div>
26
+</template>
27
+
28
+<script>
29
+export default {
30
+  name: 'orderPrintList',
31
+  props: [
32
+    'lodop',
33
+    'printList',
34
+  ],
35
+  data () {
36
+    return {}
37
+  },
38
+  updated () {
39
+    this.print()
40
+  },
41
+  methods: {
42
+    print () {
43
+      if (this.$refs.printPages && this.$refs.printPages.length > 0) {
44
+        this.$refs.printPages.forEach(($el) => {
45
+          this.lodop.ADD_PRINT_HTM(0, 0, $el.offsetWidth, $el.offsetHeight, $el.innerHTML)
46
+        })
47
+
48
+        this.lodop.PRINT()
49
+
50
+        this.$emit('printed')
51
+      }
52
+    }
53
+  }
54
+}
55
+</script>
56
+
57
+<!-- Add "scoped" attribute to limit CSS to this component only -->
58
+<style lang="scss" scoped>
59
+@import "page.scss";
60
+</style>

+ 15
- 13
src/store/goods/order.js 查看文件

@@ -22,11 +22,11 @@ export default {
22 22
   },
23 23
   actions: {
24 24
     putPrintGoodsOrder ({ commit }, payload) {
25
-      return new Promise((resolve) => {
25
+      return new Promise(resolve => {
26 26
         ajax(api.goodsOrder.putPrintGoodsOrder.url, {
27 27
           method: api.goodsOrder.putPrintGoodsOrder.method,
28 28
           urlData: {
29
-            ...payload,
29
+            ...payload
30 30
           }
31 31
         }).then(res => {
32 32
           resolve(res)
@@ -34,15 +34,17 @@ export default {
34 34
       })
35 35
     },
36 36
     GetOrdersList ({ commit }, payload) {
37
-      return new Promise((resolve) => {
37
+      return new Promise(resolve => {
38 38
         ajax(api.goodsOrder.getOnlineOrder.url, {
39 39
           method: api.goodsOrder.getOnlineOrder.method,
40 40
           queryData: {
41
-            ...payload,
41
+            ...payload
42 42
           }
43 43
         }).then(res => {
44
-          commit('updateList', res)
45
-          resolve(res)
44
+          const list = (res || {}).list || []
45
+
46
+          commit('updateList', list)
47
+          resolve(list)
46 48
         })
47 49
       })
48 50
     },
@@ -60,13 +62,13 @@ export default {
60 62
       })
61 63
     },
62 64
     updateList ({ commit }, data) {
63
-      return new Promise((resolve) => {
65
+      return new Promise(resolve => {
64 66
         commit('updateList', data)
65 67
         resolve(data)
66 68
       })
67 69
     },
68 70
     openBusiness ({ commit }, caseid) {
69
-      return new Promise((resolve) => {
71
+      return new Promise(resolve => {
70 72
         ajax(api.goodsOrder.openBusiness.url, {
71 73
           method: api.goodsOrder.openBusiness.method,
72 74
           urlData: {
@@ -79,7 +81,7 @@ export default {
79 81
       })
80 82
     },
81 83
     closeBusiness ({ commit }, caseid) {
82
-      return new Promise((resolve) => {
84
+      return new Promise(resolve => {
83 85
         ajax(api.goodsOrder.closeBusiness.url, {
84 86
           method: api.goodsOrder.closeBusiness.method,
85 87
           urlData: {
@@ -92,7 +94,7 @@ export default {
92 94
       })
93 95
     },
94 96
     getBusinessStatus ({ commit }, caseid) {
95
-      return new Promise((resolve) => {
97
+      return new Promise(resolve => {
96 98
         ajax(api.goodsOrder.getBusinessStatus.url, {
97 99
           method: api.goodsOrder.getBusinessStatus.method,
98 100
           urlData: {
@@ -106,12 +108,12 @@ export default {
106 108
             status = false
107 109
           }
108 110
           commit('updateBusiness', status)
109
-          resolve(res)
111
+          resolve(status)
110 112
         })
111 113
       })
112 114
     },
113 115
     checkOrder ({ commit }, data) {
114
-      return new Promise((resolve) => {
116
+      return new Promise(resolve => {
115 117
         ajax(api.goodsOrder.checkOrder.url, {
116 118
           method: api.goodsOrder.checkOrder.method,
117 119
           urlData: {
@@ -123,7 +125,7 @@ export default {
123 125
       })
124 126
     },
125 127
     cancelOrder ({ commit }, data) {
126
-      return new Promise((resolve) => {
128
+      return new Promise(resolve => {
127 129
         ajax(api.goodsOrder.cancelOrder.url, {
128 130
           method: api.goodsOrder.cancelOrder.method,
129 131
           urlData: {

+ 92
- 0
src/util/websocket.js 查看文件

@@ -0,0 +1,92 @@
1
+// const WsConnecting = 0
2
+const WsOpen = 1
3
+// const WsClosing = 2
4
+// const WsClosed = 3
5
+
6
+export default class XWebSocket {
7
+  addr = ''
8
+  client = null
9
+  autoConnect = false
10
+  interval = undefined
11
+  delay = 60
12
+  on = { open: null, message: null, error: null, close: null }
13
+
14
+  // constructor
15
+  constructor ({ open, message, error, close, delay, autoConnect }) {
16
+    this.on = { open, message, error, close }
17
+
18
+    if (delay >= 0) {
19
+      this.delay = delay
20
+    }
21
+
22
+    this.autoConnect = autoConnect
23
+  }
24
+
25
+  // 连接
26
+  connect (addr) {
27
+    this.addr = addr
28
+    this._wsInit()
29
+  }
30
+
31
+  // 发送
32
+  send (data) {
33
+    if (this.client && this.client.readyState === WsOpen) {
34
+      this.client.send(data)
35
+    }
36
+  }
37
+
38
+  // 关闭
39
+  close () {
40
+    if (!this.client) return
41
+
42
+    this._breforeClose(false)
43
+
44
+    this.client.close()
45
+    this.client = null
46
+  }
47
+
48
+  _breforeClose (autoConnect) {
49
+    this._wsClearHeartbeat()
50
+
51
+    if (this.client) {
52
+      if (!autoConnect) {
53
+        // 防止 onclose 中实现 断线重连
54
+        this.client.onclose = undefined
55
+      }
56
+    }
57
+  }
58
+
59
+  _wsInit () {
60
+    const _self = this
61
+
62
+    this.client = new window.WebSocket(this.addr)
63
+    this.client.onopen = this.on.open
64
+    this.client.onmessage = this.on.message
65
+    this.client.onerror = this.on.error
66
+    this.client.onclose = e => {
67
+      _self.on.close(e)
68
+      _self._breforeClose(_self.autoConnect)
69
+      _self.client = null
70
+
71
+      if (_self.autoConnect) {
72
+        window.setTimeout(() => _self._wsInit(), _self.delay * 1000)
73
+      }
74
+    }
75
+
76
+    this._wsHeartbeat()
77
+  }
78
+
79
+  _wsHeartbeat () {
80
+    this.interval = window.setInterval(() => {
81
+      if (this.client && this.client.readyState === WsOpen) {
82
+        this.client.send(10)
83
+      }
84
+    }, 60 * 1000)
85
+  }
86
+
87
+  _wsClearHeartbeat () {
88
+    if (this.interval !== undefined) {
89
+      window.clearInterval(this.interval)
90
+    }
91
+  }
92
+}