소스 검색

feat: 新增消息提醒

double 2 년 전
부모
커밋
7e8ec1fdd1
3개의 변경된 파일510개의 추가작업 그리고 21개의 파일을 삭제
  1. BIN
      src/assets/audio/order_ready_15.mp3
  2. BIN
      src/assets/audio/order_ready_5.mp3
  3. 510 21
      src/components/common/layout/layout.vue

BIN
src/assets/audio/order_ready_15.mp3


BIN
src/assets/audio/order_ready_5.mp3


+ 510 - 21
src/components/common/layout/layout.vue

@@ -23,7 +23,7 @@
23 23
         </div>
24 24
         <div class="right">
25 25
           <div @click="onAppMessage" class="news">
26
-            <span class="dot"></span>
26
+            <span class="dot" v-show="hasUnreadMessage"></span>
27 27
             <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/news.png" />
28 28
           </div>
29 29
           <div class="head-img"><img :src="userInfo.avatar_url"></div>
@@ -46,22 +46,162 @@
46 46
     </div>
47 47
     <minePupop :show="msgPupopVisible">
48 48
       <div class="block">
49
-          <div class="delete-pupop" @click="msgPupopVisible=false">
50
-            <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/delete.png" alt />
49
+          <div class="title">
50
+            <div @click="clearUnreadMsgsByType(0)" class="clear">
51
+              <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/clearMsg.png" alt="">
52
+              <div class="">清除未读</div>
53
+            </div>
54
+            <div class="txt">消息</div>
55
+            <div class="delete-pupop" @click="closeMsgPanel">
56
+              <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/delete.png" alt />
57
+            </div>
51 58
           </div>
59
+          <div class="msg-con">
60
+            <van-list 
61
+              v-model="mainPanelMsgListLoading"
62
+              :finished="mainPanelMsgListFinished"
63
+              finished-text="没有更多了"
64
+              @load="getMainPanelMessageList"
65
+              :immediate-check="false"
66
+            >
67
+              <div class="order-msg">
68
+                <div class="success">
69
+                  <div class="flex justify-between" @click="toMsgDetail(1)">
70
+                    <div class="desc flex items-center">
71
+                      <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png" alt="" />
72
+                      <div class="title">预约成功信息</div>
73
+                    </div>
74
+                    <div class="count flex flex-column justify-center items-center">
75
+                      <!-- <div class="time">10:23</div> -->
76
+                      <div class="num" v-if="orderSuccessUnreadNum">{{orderSuccessUnreadNum}}</div>
77
+                    </div>
78
+                  </div>
79
+                </div>
80
+                <div class="cancel">
81
+                  <div class="flex justify-between" @click="toMsgDetail(2)">
82
+                    <div class="desc flex items-center">
83
+                      <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/cancelOrder.png" alt="" />
84
+                      <div class="title">预约取消信息</div>
85
+                    </div>
86
+                    <div class="count flex flex-column justify-center items-center">
87
+                      <!-- <div class="time">10:23</div> -->
88
+                      <div class="num" v-if="orderCancelUnreadNum">{{orderCancelUnreadNum}}</div>
89
+                    </div>
90
+                  </div>
91
+                </div>
92
+              </div>
93
+              <div class="ready-msg flex justify-between items-center" 
94
+                v-for="(item, index) in msgPanelList" 
95
+                :key="index"
96
+                @click="readMsgToOrderDetails(item)"
97
+              >
98
+                <div class="content-bar flex flex-column">
99
+                  <div class="desc-info">{{item.sender_name}}</div>
100
+                  <div class="desc-time">{{item.msg | ellipsis(80)}}</div>
101
+                </div>
102
+                <div class="count flex flex-column items-center">
103
+                  <div class="time">{{item.create_time}}</div>
104
+                  <div class="dot" v-if="!item.is_read && allUnread"></div>
105
+                </div>
106
+              </div>
107
+            </van-list>
108
+          </div>
109
+      </div>
110
+    </minePupop>
111
+    <minePupop :show="msgSuccessDetailPupopVisible">
112
+      <div class="block detail">
113
+        <div class="title">
114
+          <div @click="backMsgPanel" class="back flex items-center">
115
+            <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/back.png" alt="" />
116
+          </div>
117
+          <div class="txt">消息</div>
118
+          <div class="delete-msg flex items-center" @click="clearUnreadMsgsByType(1)">
119
+            <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/clearMsg.png" alt />
120
+            <div class="">清除未读</div>
121
+          </div>
122
+        </div>
123
+        <div class="detail-msg-con">
124
+          <van-list 
125
+            v-model="detailSuccessMsgListLoading"
126
+            :finished="detailSuccessMsgListFinished"
127
+            finished-text="没有更多了"
128
+            @load="getMessageByType(orderMsgType)"
129
+            :immediate-check="false"
130
+          >
131
+            <div class="msg-bar flex justify-between items-center" 
132
+              v-for="(item, index) in msgSuccessDetailList" 
133
+              :key="index"
134
+              @click="readMsgToOrderDetails(item)"
135
+            >
136
+              <div class="info flex">
137
+                <!-- <div class="name">张三</div>
138
+                <div class="project">121212122</div> -->
139
+                {{item.msg | ellipsis(50)}}
140
+              </div>
141
+              <div class="flex flex-column items-center">
142
+                <div class="time">{{item.create_time}}</div>
143
+                <div class="dot" v-if="!item.is_read && successUnread"></div>
144
+              </div>
145
+            </div>
146
+          </van-list>
147
+        </div>
148
+      </div>
149
+    </minePupop>
150
+    <minePupop :show="msgCancelDetailPupopVisible">
151
+      <div class="block detail">
152
+        <div class="title">
153
+          <div @click="backMsgPanel" class="back flex items-center">
154
+            <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/back.png" alt="" />
155
+          </div>
156
+          <div class="txt">消息</div>
157
+          <div class="delete-msg flex items-center" @click="clearUnreadMsgsByType(2)">
158
+            <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/clearMsg.png" alt />
159
+            <div class="">清除未读</div>
160
+          </div>
161
+        </div>
162
+        <div class="detail-msg-con">
163
+          <van-list 
164
+            v-model="detailCancelMsgListLoading"
165
+            :finished="detailCancelMsgListFinished"
166
+            finished-text="没有更多了"
167
+            @load="getMessageByType(orderMsgType)"
168
+            :immediate-check="false"
169
+          >
170
+            <div class="msg-bar flex justify-between items-center"
171
+              v-for="(item, index) in msgCancelDetailList"
172
+              :key="index"
173
+              @click="readMsgToOrderDetails(item)"
174
+            >
175
+              <div class="info flex">
176
+                <!-- <div class="name">张三</div>
177
+                <div class="project">121212122</div> -->
178
+                {{item.msg | ellipsis(50)}}
179
+              </div>
180
+              <div class="flex flex-column items-center">
181
+                <div class="time">{{item.create_time}}</div>
182
+                <div class="dot" v-if="!item.is_read"></div>
183
+              </div>
184
+            </div>
185
+          </van-list>
186
+        </div>
52 187
       </div>
53 188
     </minePupop>
54 189
     <audio ref="orderSuccessMp3" id="orderSuccessMp3" muted>
55 190
       <source src="@/assets/audio/order_success.mp3" />
56 191
     </audio>
57
-    <audio ref="orderReadyMp3" id="orderReadyMp3" muted>
58
-      <source src="@/assets/audio/order_ready.mp3" />
192
+    <audio ref="orderReadyMp3_15" id="orderReadyMp3_15" muted>
193
+      <source src="@/assets/audio/order_ready_15.mp3" />
194
+    </audio>
195
+    <audio ref="orderReadyMp3_5" id="orderReadyMp3_5" muted>
196
+      <source src="@/assets/audio/order_ready_5.mp3" />
59 197
     </audio>
60 198
   </div>
61 199
 </template>
62 200
 
63 201
 <script type="text/javascript">
64 202
 import { mapMutations } from 'vuex'
203
+import vanList from 'vant/lib/list';
204
+import 'vant/lib/list/style';
65 205
 import leftMenu from './leftMenu'
66 206
 import minePupop from "../../../components/minePupop/index.vue";
67 207
 import api from '@/server/home'
@@ -78,11 +218,36 @@ export default {
78 218
         name: '333'
79 219
       },
80 220
       msgPupopVisible: false,
221
+      msgSuccessDetailPupopVisible: false,
222
+      msgCancelDetailPupopVisible: false,
81 223
       timer: null,
82
-      wsInstance: null
224
+      timer1: null,
225
+      wsInstance: null,
226
+      hasUnreadMessage: null,
227
+      msgPanelList: [],
228
+      mainPanelMsgListLoading: false,
229
+      mainPanelMsgListFinished: false,
230
+      mainPanelMessagePage: 1,
231
+      mainPanelMessageLimit: 5,
232
+      type: 0,
233
+      orderSuccessUnreadNum: null,
234
+      orderCancelUnreadNum: null,
235
+      detailMessageLimit: 10,
236
+      detailSuccessMessagePage: 1,
237
+      msgSuccessDetailList: [],
238
+      detailSuccessMsgListLoading: false,
239
+      detailSuccessMsgListFinished: false,
240
+      detailCancelMessagePage: 1,
241
+      msgCancelDetailList: [],
242
+      detailCancelMsgListLoading: false,
243
+      detailCancelMsgListFinished: false,
244
+      MsgType: null,
245
+      successUnread: true,
246
+      cancelUnread: true,
247
+      allUnread: true,
83 248
     }
84 249
   },
85
-  created () {
250
+  async created () {
86 251
     this.getUserInfo()
87 252
 
88 253
     console.log('开始连接...')
@@ -106,7 +271,11 @@ export default {
106 271
       } else if (data.data.type === 'order_ready') {
107 272
         // TODO: 播报动态语音还是固定的语音有待产品商榷
108 273
         console.log('项目即将开始信息播报')
109
-        this.$refs.orderReadyMp3.play()
274
+        if (data.data.minute == 15) {
275
+          this.$refs.orderReadyMp3_15.play()
276
+        } else if (data.data.minute == 5) {
277
+          this.$refs.orderReadyMp3_5.play()
278
+        }
110 279
       }
111 280
       console.log(data)
112 281
     }
@@ -118,10 +287,23 @@ export default {
118 287
       //如果出现连接、处理、接收、发送数据失败的时候触发onerror事件
119 288
       console.log(e);
120 289
     }
290
+
291
+    await this.queryHasUnreadMessage()
292
+    this.timer1 = setInterval(async() => {
293
+      await this.queryHasUnreadMessage()
294
+    }, 20000)
295
+  },
296
+  mounted () {},
297
+  beforeDestroy () {
298
+    // 关闭WebSocket连接并清除定时器
299
+    this.wsInstance.close()
300
+    clearInterval(this.timer)
301
+    clearInterval(this.timer1)
121 302
   },
122 303
   components: {
123 304
     leftMenu,
124
-    minePupop
305
+    minePupop,
306
+    vanList
125 307
   },
126 308
   methods: {
127 309
     ...mapMutations(['SAVE_COMMON_VALUE']),
@@ -148,6 +330,7 @@ export default {
148 330
       // 关闭WebSocket连接并清除定时器
149 331
       this.wsInstance.close()
150 332
       clearInterval(this.timer)
333
+      clearInterval(this.timer1)
151 334
       
152 335
       this.$router.replace('/login')
153 336
     },
@@ -160,9 +343,166 @@ export default {
160 343
     goBack () {
161 344
       this.$router.back()
162 345
     },
346
+    async queryHasUnreadMessage () {
347
+      let resp = await api.hasUnreadMessage()
348
+      if (resp.code === 200) {
349
+        this.hasUnreadMessage =  resp.data ? true : false
350
+      }
351
+    },
352
+    async getMainPanelMessageList (page = this.mainPanelMessagePage) {
353
+      // setTimeout(async() => {
354
+        let resp = await api.getMessageList({ page: page, limit: this.mainPanelMessageLimit })
355
+        if (resp.code = 200) {
356
+          this.orderSuccessUnreadNum = resp.data.reserved
357
+          this.orderCancelUnreadNum = resp.data.cancel
358
+
359
+          if (this.mainPanelMessagePage === 1) {
360
+            this.msgPanelList = resp.data.list
361
+          } else {
362
+            this.msgPanelList = [...this.msgPanelList, ...resp.data.list]
363
+          }
364
+
365
+          this.mainPanelMessagePage++
366
+          this.mainPanelMsgListLoading = false;
367
+          if (this.msgPanelList.length >= resp.data.total) {
368
+            this.mainPanelMsgListFinished = true;
369
+          }
370
+        }
371
+      // }, 1000);
372
+    },
373
+    async getMessageByType (type, page = this.detailSuccessMessagePage) {
374
+      if (type === 1) {
375
+        let resp = await api.getMessageByType({ type: type, page: page, limit: this.detailMessageLimit })
376
+        if (resp.code = 200) {
377
+
378
+          if (this.detailSuccessMessagePage === 1) {
379
+            this.msgSuccessDetailList = resp.data.list
380
+          } else {
381
+            this.msgSuccessDetailList = [...this.msgSuccessDetailList, ...resp.data.list]
382
+          }
383
+          
384
+          this.detailSuccessMessagePage++
385
+          this.detailSuccessMsgListLoading = false;
386
+          if (this.msgSuccessDetailList.length >= resp.data.total) {
387
+            this.detailSuccessMsgListFinished = true;
388
+          }
389
+        }
390
+      } else if (type === 2) {
391
+        let resp = await api.getMessageByType({ type: type, page: page, limit: this.detailMessageLimit })
392
+        if (resp.code = 200) {
393
+          this.msgCancelDetailList = [...this.msgCancelDetailList, ...resp.data.list]
394
+
395
+          if (this.detailSuccessMessagePage === 1) {
396
+            this.msgCancelDetailList = resp.data.list
397
+          } else {
398
+            this.msgCancelDetailList = [...this.msgCancelDetailList, ...resp.data.list]
399
+          }
400
+
401
+          this.detailCancelMessagePage++
402
+          this.detailCancelMsgListLoading = false;
403
+          if (this.msgCancelDetailList.length >= resp.data.total) {
404
+            this.detailCancelMsgListFinished = true;
405
+          }
406
+        }
407
+      }
408
+    },
163 409
     onAppMessage () {
410
+      this.msgPanelList = []
411
+      this.mainPanelMessagePage = 1
412
+      this.mainPanelMsgListLoading = false
413
+      this.mainPanelMsgListFinished = false
414
+      this.getMainPanelMessageList(1)
164 415
       this.msgPupopVisible = true
165
-    }
416
+    },
417
+    closeMsgPanel () {
418
+      this.msgPupopVisible = false
419
+    },
420
+    toMsgDetail (param) {
421
+      this.msgPupopVisible = false
422
+      // this.getMessageByType(param)
423
+      if (param === 1) {
424
+      this.msgSuccessDetailList = []
425
+      this.detailSuccessMessagePage = 1
426
+      this.detailSuccessMsgListLoading = false
427
+      this.detailSuccessMsgListFinished = false
428
+      this.getMessageByType(param, 1)
429
+
430
+        this.msgSuccessDetailPupopVisible = true
431
+      } else {
432
+      this.msgCancelDetailList = []
433
+      this.detailCancelMessagePage = 1
434
+      this.detailCancelMsgListLoading = false
435
+      this.detailCancelMsgListFinished = false
436
+      
437
+      this.getMessageByType(param, 1)
438
+
439
+        this.msgCancelDetailPupopVisible = true
440
+      }
441
+      this.orderMsgType = param
442
+      console.log(this.orderMsgType)
443
+    },
444
+    backMsgPanel () {
445
+      this.msgSuccessDetailPupopVisible = false
446
+      this.msgCancelDetailPupopVisible = false
447
+      
448
+      this.getMainPanelMessageList()
449
+      this.msgPupopVisible = true
450
+    },
451
+    async clearUnreadMsgsByType (type) {
452
+      let resp = await api.clearMessage({ type: type })
453
+      if (resp.code === 200) {
454
+        if (type === 1) {
455
+          this.getMessageByType(this.orderMsgType)
456
+          this.successUnread = false
457
+        } else if (type === 2) {
458
+          this.getMessageByType(this.orderMsgType)
459
+          this.cancelUnread = false
460
+        } else if (type === 0) {
461
+          this.getMainPanelMessageList()
462
+          this.allUnread = false
463
+        }
464
+      }
465
+    },
466
+    async readMsgToOrderDetails (source) {
467
+      // console.log(source)
468
+      if (!source.is_read) {
469
+        let clearMsgByIdResp = await api.clearMessageById({id: source.id})
470
+        if (clearMsgByIdResp.code === 200) {
471
+          this.getMainPanelMessageList()
472
+        }
473
+      }
474
+      if (source.type === 'BUY' || source.type === 'BUY_CARD') return
475
+      // return
476
+      let orderInfoResp = await api.getOrderInfo({ id: source.order_id })
477
+      if (orderInfoResp.code === 200) {
478
+        if (orderInfoResp.data.order_data.status == 0) {
479
+          // 跳转前关闭所有弹窗
480
+          this.msgPupopVisible = false
481
+          this.msgSuccessDetailPupopVisible = false
482
+          this.msgCancelDetailPupopVisible = false
483
+
484
+          this.$router.push({
485
+            path: '/confirmOrder/details',
486
+            query: {
487
+              id: source.order_id
488
+            }
489
+          })
490
+        } else {
491
+          this.msgPupopVisible = false
492
+          this.msgSuccessDetailPupopVisible = false
493
+          this.msgCancelDetailPupopVisible = false
494
+          
495
+          this.$router.push({
496
+            path: "/historicalOrder/details",
497
+            query: {
498
+              id: source.order_id
499
+            }
500
+          });
501
+        }
502
+      } else {
503
+        this.$message.error("未查到此订单")
504
+      }
505
+    },
166 506
   },
167 507
   computed: {
168 508
     routerItems () {
@@ -182,6 +522,14 @@ export default {
182 522
         }
183 523
       }
184 524
       return resultArr;
525
+    },
526
+    orderMsgType: {
527
+      get () {
528
+        return this.MsgType
529
+      },
530
+      set (val) {
531
+        this.MsgType = val
532
+      } 
185 533
     }
186 534
   },
187 535
 }
@@ -191,6 +539,25 @@ export default {
191 539
 <style lang="less" scoped>
192 540
 @import url(../../../style/root.less);
193 541
 
542
+.flex {
543
+  display: flex;
544
+}
545
+.flex-column {
546
+  flex-direction: column;
547
+}
548
+.justify-center {
549
+  justify-content: center;
550
+}
551
+.justify-between {
552
+  justify-content: space-between;
553
+}
554
+.justify-around {
555
+  justify-content: space-around;
556
+}
557
+.items-center {
558
+  align-items: center;
559
+}
560
+
194 561
 .layout {
195 562
   height: 100vh;
196 563
   display: flex;
@@ -300,23 +667,145 @@ export default {
300 667
     background-color: #f7f8fa;
301 668
   }
302 669
 }
670
+.dot {
671
+  width: 9px;
672
+  height: 9px;
673
+  border-radius: 50%;
674
+  background-color: #FF6945;
675
+  margin-top: 10px;
676
+}
677
+.dot-activated {
678
+  background-color: #fff;
679
+}
303 680
 .block {
304 681
   width: 540px;
305
-  height: 550px;
682
+  height: 400px;
683
+  padding: 20px;
684
+  box-sizing: border-box;
306 685
   background: #ffffff;
307 686
   border-radius: 8px;
308 687
   position: relative;
309
-  .delete-pupop {
310
-    position: absolute;
311
-    width: 32px;
312
-    height: 32px;
313
-    top: 5px;
314
-    right: 5px;
315
-    img {
316
-      width: 100%;
317
-      height: 100%;
318
-      display: block;
688
+  .title {
689
+    display: flex;
690
+    justify-content: space-between;
691
+    font-size: 14px;
692
+    .clear {
693
+      display: flex;
694
+      align-items: center;
695
+      color: #999999;
696
+      img {
697
+        width: 32px;
698
+        height: 32px;
699
+      }
700
+    }
701
+    .txt {
702
+      display: flex;
703
+      align-items: center;
704
+    }
705
+    .delete-pupop {
706
+      width: 32px;
707
+      height: 32px;
708
+      img {
709
+        width: 100%;
710
+        height: 100%;
711
+        display: block;
712
+      }
713
+    }
714
+  }
715
+  .msg-con {
716
+    height: 290px;
717
+    overflow: auto;
718
+    margin-top: 21px;
719
+    .order-msg {
720
+      .success, .cancel {
721
+        .desc {
722
+          img {
723
+            width: 36px;
724
+            height: 36px;
725
+          }
726
+          .title {
727
+            margin-left: 17px;
728
+          }
729
+        }
730
+        .count {
731
+          .time {
732
+            color: #999999;
733
+            margin-bottom: 4px;
734
+          }
735
+          .num {
736
+            width: 25px;
737
+            height: 25px;
738
+            // line-height: 21px;
739
+            // text-align: center;
740
+            display: flex;
741
+            justify-content: center;
742
+            align-items: center;
743
+            padding: 8px;
744
+            box-sizing: border-box;
745
+            color: #ffffff;
746
+            border-radius: 50%;
747
+            background-color: #FF6945;
748
+            
749
+          }
750
+        }
751
+      }
752
+      .cancel {
753
+        margin-top: 23px;
754
+      }
755
+    }
756
+    .ready-msg {
757
+      margin-top: 20px;
758
+      .content-bar {
759
+        .desc-info {
760
+          color: #666666;
761
+          font-weight: 400;
762
+        }
763
+        .desc-time {
764
+          width: 400px;
765
+          margin-top: 5px;
766
+          font-weight: 500;
767
+          line-height: 18px;
768
+        }
769
+        
770
+      }
771
+      .count {
772
+        .time {
773
+          color: #999999;
774
+        }
775
+      }
776
+    }
777
+  }
778
+}
779
+.detail {
780
+  .title {
781
+    .back {
782
+      img {
783
+        width: 24px;
784
+        height: 24px;
785
+      }
786
+    }
787
+    .delete-msg {
788
+      img {
789
+        width: 32px;
790
+        height: 32px;
791
+      }
792
+    }
793
+  }
794
+  .msg-bar {
795
+    margin-top: 18px;
796
+    .info {
797
+      width: 400px;
798
+      line-height: 18px;
799
+      .name {
800
+        font-weight: 600;
801
+        margin-right: 5px;
802
+      }
803
+      .project {}
319 804
     }
320 805
   }
321 806
 }
807
+.detail-msg-con {
808
+  height: 330px;
809
+  overflow: auto;
810
+}
322 811
 </style>