From c0f6c1743c05cd7d275723e91d4af7359ea37a54 Mon Sep 17 00:00:00 2001 From: zouyanyan <254651820@qq.com> Date: Tue, 19 May 2026 17:17:15 +0800 Subject: [PATCH] upbug --- components/chat/submit.vue | 85 +- manifest.json | 46 +- pages.json | 30 +- pages/book/book.vue | 83 +- pages/book/bookinfo.vue | 581 +++-- pages/book/booklist.vue | 187 +- pages/book/bookshop.vue | 323 +-- pages/book/bookteacher.vue | 321 +-- pages/category/category.vue | 463 +++- pages/chat/chat.vue | 1807 +++++++++++++++ pages/chat/groupchat.vue | 2005 +++++++++++++++++ .../service.vue => chat/groupchat0.vue} | 17 +- pages/chat/groupchat1.vue | 1830 +++++++++++++++ pages/components/cart.vue | 2 +- pages/components/selShop.vue | 42 +- pages/components/service.vue | 36 +- pages/index/index.vue | 87 +- pages/login/login.vue | 14 +- pages/message/contact.vue | 300 ++- pages/message/group.vue | 881 ++++++-- pages/message/group0.vue | 505 +++++ pages/message/group1.vue | 731 ++++++ pages/order/orderinfo.vue | 104 +- pages/product/cdetail.vue | 135 +- pages/product/cxlist.vue | 32 +- pages/product/detail.vue | 66 +- pages/product/list.vue | 17 +- pages/product/order.vue | 2 +- pages/teacher/chat.vue | 1091 --------- pages/teacher/course.vue | 16 +- pages/teacher/detail.vue | 61 +- pages/user/cdlist.vue | 12 - pages/user/courselist.vue | 73 +- pages/user/kslist.vue | 12 - pages/user/mycollect.vue | 3 +- pages/user/tclist.vue | 12 - pages/user/user.vue | 97 +- pages/user/xslist.vue | 12 - static/image/girl.jpg | Bin 13929 -> 0 bytes static/image/girl.png | Bin 0 -> 1594 bytes static/image/jltx.png | Bin 0 -> 911 bytes static/image/kf.png | Bin 912 -> 1929 bytes static/image/mr.png | Bin 0 -> 960 bytes static/image/qd.png | Bin 0 -> 1934 bytes static/image/qltx.png | Bin 0 -> 3019 bytes static/image/xy.png | Bin 0 -> 2176 bytes static/qlfont.ttf | Bin 0 -> 1636 bytes 47 files changed, 9705 insertions(+), 2416 deletions(-) create mode 100644 pages/chat/chat.vue create mode 100644 pages/chat/groupchat.vue rename pages/{product/service.vue => chat/groupchat0.vue} (98%) create mode 100644 pages/chat/groupchat1.vue create mode 100644 pages/message/group0.vue create mode 100644 pages/message/group1.vue delete mode 100644 pages/teacher/chat.vue delete mode 100644 static/image/girl.jpg create mode 100644 static/image/girl.png create mode 100644 static/image/jltx.png create mode 100644 static/image/mr.png create mode 100644 static/image/qd.png create mode 100644 static/image/qltx.png create mode 100644 static/image/xy.png create mode 100644 static/qlfont.ttf diff --git a/components/chat/submit.vue b/components/chat/submit.vue index 39e31f4..b39b386 100644 --- a/components/chat/submit.vue +++ b/components/chat/submit.vue @@ -227,16 +227,7 @@ // 可以使用 res.tempFilePath 获取视频的本地路径 const filePath = res.tempFilePath; console.log(filePath); - if(that.checkImageSize(filePath)){ - that.send(filePath, 'video'); - } - else{ - that.$refs.uToast.show({ - title: "视频大小不能超过20M...", - type: "error", - duration: 2000, - }); - } + that.checkImageSize(filePath,2); }, fail: function (err) { console.error('选择视频失败:', err); @@ -245,6 +236,7 @@ }, //图片发送 sendImg(e) { + var that =this; let count = 9; if (e == 'album') { count = 9; @@ -260,40 +252,66 @@ console.log(JSON.stringify(res.tempFilePaths)); const filePaths = res.tempFilePaths; for (let i = 0; i < filePaths.length; i++) { - if(this.checkImageSize(filePath)){ - this.send(filePaths[i], 'image') - } - else{ - this.$refs.uToast.show({ - title: "图片大小不能超过20M...", - type: "error", - duration: 2000, - }); - } + that.checkImageSize(filePaths[i],1); } } }); }, - checkImageSize(filePath) { - var ifsize= 0; + checkImageSize(filePath,type) { + var that = this; uni.getFileInfo({ filePath: filePath, success: function (res) { console.log('文件大小(字节):', res.size); - if (res.size > 20*1024 * 1024) { // 例如,这里检查文件大小是否超过20MB - console.log('文件过大'); - // 可以根据需要处理文件过大的情况,比如提示用户 - ifsize=0; - } else { - console.log('文件大小合适'); - // 处理正常的文件大小情况 - ifsize=1; - } - return ifsize; + if(type==1){ + // 图片 + if (res.size > 2*1024*1024) { // 例如,这里检查文件大小是否超过20MB + console.log('文件过大'); + // 可以根据需要处理文件过大的情况,比如提示用户 + that.$refs.uToast.show({ + title: "图片大小不能超过2M...", + type: "error", + duration: 2000, + }); + } else { + console.log('文件大小合适'); + // 处理正常的文件大小情况 + that.send(filePath, 'image'); + } + } + else if(type==2){ + // 视频 + if (res.size > 10*1024*1024) { // 例如,这里检查文件大小是否超过20MB + console.log('文件过大'); + // 可以根据需要处理文件过大的情况,比如提示用户 + that.$refs.uToast.show({ + title: "视频大小不能超过10M...", + type: "error", + duration: 2000, + }); + } else { + console.log('文件大小合适'); + // 处理正常的文件大小情况 + that.send(filePath, 'video'); + } + } }, fail: function (err) { console.error('获取文件信息失败:', err); - return ifsize; + if(type==1){ + that.$refs.uToast.show({ + title: "图片大小不能超过2M...", + type: "error", + duration: 2000, + }); + } + else if(type==1){ + that.$refs.uToast.show({ + title: "视频大小不能超过10M...", + type: "error", + duration: 2000, + }); + } } }); }, @@ -377,6 +395,7 @@ }, //发送 send(msg, type) { + console.log("send") console.log(msg, type) let date = { message: msg, diff --git a/manifest.json b/manifest.json index 876047e..56bb6ad 100644 --- a/manifest.json +++ b/manifest.json @@ -2,8 +2,8 @@ "name" : "瑜伽汇", "appid" : "__UNI__B6E0086", "description" : "瑜伽汇", - "versionName" : "1.0.0", - "versionCode" : 100, + "versionName" : "1.0.9", + "versionCode" : 109, "transformPx" : false, "app-plus" : { "flexible" : true, @@ -151,7 +151,47 @@ } } }, - "nativePlugins" : {} + "nativePlugins" : { + "JG-JCore" : { + "JPUSH_APPKEY_ANDROID" : "d5edb270e4b1cc29616e1dd5", + "JPUSH_APPKEY_IOS" : "", + "JPUSH_CHANNEL_ANDROID" : "", + "JPUSH_CHANNEL_IOS" : "", + "__plugin_info__" : { + "name" : "极光推送 JCore 官方 SDK", + "description" : "极光推送 JCore 官方 SDK HBuilder 插件版本", + "platforms" : "Android,iOS", + "url" : "https://ext.dcloud.net.cn/plugin?id=4028", + "android_package_name" : "com.sdlyoga.app", + "ios_bundle_id" : "", + "isCloud" : true, + "bought" : 1, + "pid" : "4028", + "parameters" : { + "JPUSH_APPKEY_ANDROID" : { + "des" : "[Android]极光portal配置应用信息时分配的AppKey", + "key" : "JPUSH_APPKEY", + "value" : "" + }, + "JPUSH_APPKEY_IOS" : { + "des" : "[iOS]极光portal配置应用信息时分配的AppKey", + "key" : "JCore:APP_KEY", + "value" : "" + }, + "JPUSH_CHANNEL_ANDROID" : { + "des" : "[Android]用于统计分发渠道,不需要可填默认值developer-default", + "key" : "JPUSH_CHANNEL", + "value" : "" + }, + "JPUSH_CHANNEL_IOS" : { + "des" : "[iOS]用于统计分发渠道,不需要可填默认值developer-default", + "key" : "JCore:CHANNEL", + "value" : "" + } + } + } + } + } }, "quickapp" : {}, "mp-weixin" : { diff --git a/pages.json b/pages.json index e17cbb5..5d48652 100644 --- a/pages.json +++ b/pages.json @@ -161,10 +161,10 @@ } }, { - "path" : "pages/teacher/chat", + "path" : "pages/chat/chat", "style" : { - "navigationBarTitleText": "咨询", + "navigationBarTitleText": "教练咨询", "enablePullDownRefresh": false } }, @@ -214,11 +214,25 @@ } }, { - "path" : "pages/product/service", + "path" : "pages/chat/groupchat", "style" : { "navigationBarTitleText": "客服", - "enablePullDownRefresh": false + "enablePullDownRefresh": false, + "app-plus": { + "titleNView": { + "buttons": [ + { + "fontSrc": "/static/qlfont.ttf", + "text": "\ue68e", + "fontSize": "28", + "color": "#ffffff", + "float": "right", + "background": "rgba(0,0,0,0)" + } + ] + } + } } }, { @@ -367,6 +381,14 @@ "enablePullDownRefresh": false } }, + { + "path": "pages/book/bookshop", + "style" : + { + "navigationBarTitleText": "预约学员", + "enablePullDownRefresh": false + } + }, { "path": "pages/book/book", "style" : diff --git a/pages/book/book.vue b/pages/book/book.vue index aef5add..9aa3b16 100644 --- a/pages/book/book.vue +++ b/pages/book/book.vue @@ -21,9 +21,15 @@ - {{item.claName}} - {{item.claName}} - + + + {{item.claName}} + + + {{item.courseTypeName}} + + @@ -60,7 +66,8 @@ - + + @@ -95,7 +102,7 @@ @@ -264,130 +407,6 @@ line-height: 60rpx; z-index: 9999; } - .submitcon{ - position: fixed; - display: flex; - bottom: 0; - left: 0; - width: 100%; - height: 140rpx; - background-color: #FFFFFF; - .pcon{ - margin-left: 20rpx; - margin-top: 28rpx; - height: 50rpx; - display: flex; - flex:1; - justify-content: flex-start; - align-items: baseline; - .hj{ - font-size: 30rpx; - } - .rmb{ - font-size: 30rpx; - font-family: smallYuan; - color:#00a89b ; - margin-left: 10rpx; - } - .zs{ - font-size: 48rpx; - font-weight: 600; - font-family: smallYuan; - color:#00a89b ; - } - .xs{ - font-size: 28rpx; - font-weight: 600; - font-family: smallYuan; - color:#00a89b ; - } - } - .btn{ - background-color: #00a89b !important; - margin: 30rpx 20rpx 0 0; - border-radius: 50rpx; - height: 60rpx; - line-height: 60rpx; - width: 180rpx; - font-size: 26rpx; - } - .btn::after{ - border:0 !important; - } - .gzbtn{ - background-color: #4A4AFF !important; - margin: 30rpx 20rpx 0 0; - border-radius: 50rpx; - height: 60rpx; - line-height: 60rpx; - width: 180rpx; - font-size: 26rpx; - } - .gzbtn::after{ - border:0 !important; - } - .cancelbtn{ - background-color: #FFFFFF !important; - margin: 30rpx 20rpx 0 0; - border-radius: 50rpx; - height: 60rpx; - line-height: 60rpx; - width:180rpx; - font-size: 26rpx; - color:#333; - border:1rpx solid #dddddd; - } - .cancelbtn::after{ - border:0 !important; - } - .returnbtn{ - background-color: #ff3d0e !important; - margin: 30rpx 20rpx 0 0; - border-radius: 50rpx; - height: 60rpx; - line-height: 60rpx; - width:180rpx; - font-size: 26rpx; - border:1rpx solid #ff3d0e; - color:#FFF; - } - .returnbtn::after{ - border:0 !important; - } - .pjbtn{ - background-color: #FFFFFF !important; - margin: 30rpx 20rpx 0 0; - border-radius: 50rpx; - height: 60rpx; - line-height: 60rpx; - width:170rpx; - font-size: 26rpx; - border:1rpx solid #f5aa00; - color:#f5aa00; - } - .pjbtn::after{ - border:0 !important; - } - .wlbtn{ - background-color: #FFFFFF !important; - margin: 30rpx 20rpx 0 0; - border-radius: 50rpx; - height: 60rpx; - line-height: 60rpx; - width:170rpx; - font-size: 26rpx; - border:1rpx solid #00a89b; - color:#00a89b; - } - .wlbtn::after{ - border:0 !important; - } - } - .signimg{ - width: 150rpx; - height: 180rpx; - border-radius: 10rpx; - } .oscon{ margin:0; background-color: #f3fafa; @@ -408,13 +427,23 @@ justify-content: flex-start; margin-left: 20rpx; } - .osname{ - line-height: 48rpx; - font-size:32rpx; - font-weight: 600; - color:#009999; - padding-bottom: 15rpx; + .ostop{ + display: flex; + flex-direction: row; border-bottom: 1rpx dotted #74defb; + padding-bottom: 15rpx; + .osname{ + line-height: 48rpx; + font-size:32rpx; + font-weight: 600; + color:#009999; + display: flex; + flex:1; + } + .qrimg{ + width: 50rpx; + height: 50rpx; + } } .oscell{ display: flex; @@ -425,21 +454,111 @@ border-bottom: 1rpx dotted #74defb; .txt{ display: flex; flex: 1; + } + } + .oscellqr{ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin: 20rpx 20rpx 10rpx 20rpx; + .ordtip{ + font-size: 28rpx; + color:#000; + margin-bottom: 10rpx; + } + .ordqr{ + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 200rpx; + margin-bottom: 10rpx; + .imgqr{ + width: 200rpx; + height: 200rpx; + } + } + .ordno{ + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + .txt{ + font-size: 28rpx; + color:#000; + } + .copy{ + font-size: 28rpx; + color:#1296db; + margin-left: 6rpx; + } } } + + .ztip{ + color:#1296db; + font-size: 26rpx; + padding: 0; + height: 40rpx; + line-height: 40rpx; + } + .jtip{ + color:#feb467; + font-size: 26rpx; + padding: 0; + height: 40rpx; + line-height: 40rpx; + } + .htip{ + border-radius: 12rpx; + color:#fc6900; + font-size: 26rpx; + padding: 0; + height: 40rpx; + line-height: 40rpx; + } + .hwtip{ + color:#FF0000; + font-size: 26rpx; + padding: 0; + height: 40rpx; + line-height: 40rpx; + } + .wtip{ + color:#43cca4; + font-size: 26rpx; + padding: 0; + height: 40rpx; + line-height: 40rpx; + } + .gtip{ + color:#0036D6; + font-size: 26rpx; + padding: 0; + height: 40rpx; + line-height: 40rpx; + } + .ftip{ + color:#6A81F1; + font-size: 26rpx; + padding: 0; + height: 40rpx; + line-height: 40rpx; + } + .ctip{ + color:#888; + font-size: 26rpx; + padding: 0; + height: 40rpx; + line-height: 40rpx; + } } - .ydcon{ - position: relative; - } - .yyright{ - position: absolute; - right: 100rpx; - top:50rpx; - } + .oinfo{ padding:20rpx; position: relative; - margin-bottom: 160rpx; + margin-bottom: 20rpx; .ozc{ display: flex; @@ -577,14 +696,7 @@ } } } - - .red{ - color:#ff3d0e; - } - .green{ - color:#00cd00; - } - + ::v-deep.uni-radio-input-checked{ background-color: #00a89b !important; border-color: #00a89b !important; @@ -595,4 +707,93 @@ display: none!important; } + + + .pcon{ + width: 690rpx; + padding-top:30rpx; + padding-bottom:50rpx; + background: #FCFCFD; + box-shadow: 0rpx 128rpx 128rpx 2rpx rgba(31,47,70,0.12); + border-radius: 16rpx 16rpx 16rpx 16rpx; + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .phtxt{ + width: 600rpx; + margin: 20rpx auto 10rpx; + font-size: 36rpx; + font-family: PingFang SC-Regular, PingFang SC; + font-weight: 600; + color: #23262F; + } + .ptxt + { + width: 620rpx; + display: flex; + align-items: center; + justify-content: center; + margin: 30rpx auto; + border-radius: 16rpx 16rpx 16rpx 16rpx; + opacity: 1; + border: 2rpx solid #F7F8FA; + padding: 30rpx; + .qrimg{ + width: 400rpx; + height: 400rpx; + } + } + .btn{ + width: 520rpx; + height: 80rpx; + line-height: 80rpx; + background: #00A99A; + box-shadow: 0rpx 12rpx 64rpx 2rpx rgba(0,169,154,0.4); + border-radius: 254rpx 254rpx 254rpx 254rpx; + text-align: center; + font-size: 32rpx; + font-family: PingFang SC-Medium, PingFang SC; + font-weight: 500; + color: #FCFCFD; + } + } + + .bottom{ + width: 100%; + margin-bottom: 148rpx; + } + + .submitcon{ + position: fixed; + bottom: 0; + left: 0; + width: 100%; + height: 148rpx; + background: #FFFFFF; + box-shadow: 0rpx -4rpx 60rpx 2rpx rgba(1,31,63,0.1); + opacity: 1; + display: flex; + flex-direction: row; + } + .bbtn{ + margin: 20rpx 50rpx 50rpx; + font-size: 32rpx; + font-family: PingFang SC-Medium, PingFang SC; + font-weight: 500; + color: #FCFCFD; + width: 650rpx; + height: 76rpx; + line-height: 76rpx; + background: #00a89b; + box-shadow: 0rpx 12rpx 64rpx 2rpx rgba(137,150,95,0.4); + border-radius: 10rpx; + opacity: 1; + &::after{ + border:none; + } + } + + diff --git a/pages/book/booklist.vue b/pages/book/booklist.vue index 1d9c138..58a0bc1 100644 --- a/pages/book/booklist.vue +++ b/pages/book/booklist.vue @@ -6,13 +6,13 @@ - + - + {{item.storeName?item.storeName:'门店'}} @@ -27,19 +27,24 @@ - + {{item.courseName}} {{item.claName}} - 教练:{{item.teacherName }} - 上课时间:{{ item.claDate+' '+item.startTime+'-'+item.endTime}} - 教室:{{item.roomName}} + 教练:{{item.teacherName || '-'}} + 上课时间:{{ item.claDate+' '+item.startTime+'-'+item.endTime}} + 教室:{{item.roomName}} + - + + + + + @@ -49,6 +54,7 @@ + @@ -59,6 +65,19 @@ + + + + 预约二维码 + + + + + 关闭 + + + + @@ -79,6 +98,7 @@ userid:"", tabCurrentIndex: 0, scrollLeft: 0,//tabs + qr:'', // 预约二维码 // 1:待上课,2:预约中,3:待评价 list:[ { @@ -370,6 +390,18 @@ },100); }, methods: { + openQR(qr){ + console.log("openQR") + this.qr='data:image/png;base64,'+qr; + this.$forceUpdate(); + this.openDialog(); + }, + closeDialog(){ + this.$refs.pfDialog.close(); + }, + openDialog(){ + this.$refs.pfDialog.open(); + }, getimgRemoteFile(img){ if(img){ img=img.split(',')[0]; @@ -442,17 +474,26 @@ tabSelect(e) { console.log(e) this.tabCurrentIndex = e.currentTarget.dataset.id; - this.scrollLeft = (e.currentTarget.dataset.id - 1) * 60; + this.$forceUpdate(); // 重新加载 暂不需要加载 // this.list[this.tabCurrentIndex].loadStatus="more"; // this.list[this.tabCurrentIndex].slist=[]; - this.loadData(); + // this.loadData(); }, animationfinish({ detail: { current } }) { - this.tabCurrentIndex = current; + // this.tabCurrentIndex = current; + // this.loadData(); + }, + handleChange(e) { + //原在animationfinish中的操作转移到这里 + console.log("handleChange"); + this.tabCurrentIndex = e.detail.current; + this.scrollLeft = (e.currentTarget.dataset.id - 1) * 60; + this.$forceUpdate(); this.loadData(); }, gotoInfo(id){ + id=id+""; // 预约详情 uni.navigateTo({ url: `/pages/book/bookinfo?id=${id}` @@ -460,15 +501,41 @@ }, // 联系教练 gototeacher(item){ - var data={ - id:item.id, - name:"教练A" + console.log(item); + if(item.teacherId){ + uni.showLoading({ + title: '会话创建中...' + }); + // 直接跳转到聊天框 + var chatid="privatechat-" + this.userid +"-"+ item.teacherId; + var timestamp = new Date().getTime(); + var info={ + chatId: "privatechat-" + this.userid +"-"+ item.teacherId, + chatType: "coach", + chatName: item.teacherName, + chatAvatar: item.pic?item.pic:'/static/image/kf.png', + chatTime: timestamp, + userid: this.userid, + friendId: item.teacherId, // 会话教练userid + minId: "", // 已读消息的最大id + sort:"privatechat", // privatechat 私聊 groupchat 群聊 + from:"yh" // yh 用户咨询进入聊天框,message 从消息进入聊天框 + } + var data=encodeURIComponent(JSON.stringify(info)); + uni.navigateTo({ + url: `/pages/chat/chat?data=${data}` + }); + } + else{ + uni.showModal({ + title: '提示', + content: '抱歉!当前预约尚未配置教练在线服务..', + cancelText: '取消', + confirmText: '确定', + success: ress => { + } + }); } - // 联系教练 - var data=encodeURIComponent(JSON.stringify(data)); - uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` - }) }, // 去评价 gotoevaluate(item){ @@ -530,11 +597,6 @@ this.reset(); } else{ - // uni.showToast({ - // title: res.msg? res.msg:'上课预约失败!', - // icon: 'error', - // duration: 2000 - // }); uni.showModal({ title: '提示', content: res.message? res.message:'课程预约失败!', @@ -891,18 +953,16 @@ flex-direction: row; justify-content: flex-end; border-top: 1rpx solid #eee; - padding: 20rpx 0 10rpx; + padding: 20rpx 0 0; width: 100%; - .omoney{ + .qr{ display: flex; flex:1; - height: 60rpx; - width: 100%; color:#333; align-items: center; - .omtip{ - font-size: 36rpx; - color:rgb(252, 105, 0); + .qrimg{ + width: 50rpx; + height: 50rpx; } } .cancelbtn{ @@ -991,19 +1051,6 @@ .gzbtn::after{ border:0 !important; } - .gzbtn{ - background-color: #f5aa00 !important; - margin-left: 20rpx; - border-radius: 50rpx; - height: 50rpx; - line-height: 48rpx; - padding: 0 20rpx; - font-size: 24rpx; - border:1rpx solid #f5aa00; - } - .gzbtn::after{ - border:0 !important; - } } .oscon{ margin:20rpx 0; @@ -1022,7 +1069,7 @@ flex: 1; display: flex; flex-direction: column; - margin-left: 26rpx; + margin-left: 20rpx; .ntxt{ font-size: 28rpx; color:#000; @@ -1099,4 +1146,56 @@ } + + .pcon{ + width: 690rpx; + padding-top:30rpx; + padding-bottom:50rpx; + background: #FCFCFD; + box-shadow: 0rpx 128rpx 128rpx 2rpx rgba(31,47,70,0.12); + border-radius: 16rpx 16rpx 16rpx 16rpx; + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .phtxt{ + width: 600rpx; + margin: 20rpx auto 10rpx; + font-size: 36rpx; + font-family: PingFang SC-Regular, PingFang SC; + font-weight: 600; + color: #23262F; + } + .ptxt + { + width: 620rpx; + display: flex; + align-items: center; + justify-content: center; + margin: 30rpx auto; + border-radius: 16rpx 16rpx 16rpx 16rpx; + opacity: 1; + border: 2rpx solid #F7F8FA; + padding: 30rpx; + .qrimg{ + width: 400rpx; + height: 400rpx; + } + } + .btn{ + width: 520rpx; + height: 80rpx; + line-height: 80rpx; + background: #00A99A; + box-shadow: 0rpx 12rpx 64rpx 2rpx rgba(0,169,154,0.4); + border-radius: 254rpx 254rpx 254rpx 254rpx; + text-align: center; + font-size: 32rpx; + font-family: PingFang SC-Medium, PingFang SC; + font-weight: 500; + color: #FCFCFD; + } + } + diff --git a/pages/book/bookshop.vue b/pages/book/bookshop.vue index db7bdaf..b6e1322 100644 --- a/pages/book/bookshop.vue +++ b/pages/book/bookshop.vue @@ -5,9 +5,13 @@ - + - {{item.storeName?item.storeName:'门店'}} + + 姓名:{{item.studentName?item.studentName:'-'}} + 性别:{{item.sex==2?'男':(item.sex==1?'女':'未知')}} + + 电话:{{item.phone?item.phone:'-'}} @@ -20,27 +24,29 @@ - - - - + - {{item.courseName}} {{item.claName}} - 教练:{{item.teacherName }} - 上课时间:{{ item.claDate+' '+item.startTime+'-'+item.endTime}} - 教室:{{item.roomName}} + + 课程:{{item.courseName}} + 班级:{{item.claName}} + + + 教练:{{item.teacherName }} + 教室:{{item.roomName}} + + 上课时间:{{ item.claDate+' '+item.startTime+(item.endTime?'-'+item.endTime:'')}} + + 预约人数:{{item.bookAttendCnt}} + 可容纳人数:{{item.atClassCnt}} + - - - - - - + + @@ -123,7 +129,7 @@ uni.showLoading({ title: '数据加载中...' }); - const {data: res} = await uni.$http.get('/api/my/appointmentListForTeacher'); + const {data: res} = await uni.$http.get('/api/my/appointmentListForManager'); if(res&&res.data){ // 全部 this.loadStatus="noMore"; @@ -137,7 +143,6 @@ } }, loadData(){ - console.log('loadData'); // 加载 if(this.loadStatus=="more") { this.loadStatus="loading"; @@ -152,18 +157,6 @@ url: `/pages/book/bookinfo?id=${id}` }); }, - // 联系教练 - gototeacher(item){ - var data={ - id:item.id, - name:"教练A" - } - // 联系教练 - var data=encodeURIComponent(JSON.stringify(data)); - uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` - }) - }, // 去评价 gotoevaluate(item){ var data=encodeURIComponent(JSON.stringify(item)); @@ -186,52 +179,47 @@ return true; } }, - // 再次预约 - orderdo(e,item){ - console.log(id,item); + // 禁止预约 + stopdo(e,item){ var that = this; - // 再次预约 + // 禁止预约 uni.showModal({ title: '提示', - content: '确定再次预约吗?', + content: '确定禁止预约吗?', cancelText: '取消', confirmText: '确定', success: ress => { if (ress.confirm) { - that.checkdodo(id,item); + that.stopdodo(item); } } }); }, - // 再次预约 - async orderdodo(id,item){ + // 禁止预约 + async stopdodo(item){ var param={ - "courseTimeId": item.courseTimeId + "bookId": item.bookId, + "bookStatus": 2 }; - uni.showToast({ - title: '再次预约中...', - icon: 'success', - duration: 2000 + uni.showLoading({ + title: '禁止预约中...' }); - const {data: res} = await uni.$http.post('/api/course/bookCourse', param); + const {data: res} = await uni.$http.post('/api/my/checkAppointment', param); if(res.success){ uni.showToast({ - title: '上课已预约!', + title: '已禁止预约!', icon: 'success', duration: 2000 }); // 重新加载 + this.loadStatus="more"; + this.$forceUpdate(); this.loadData(); } else{ - // uni.showToast({ - // title: res.msg? res.msg:'上课预约失败!', - // icon: 'error', - // duration: 2000 - // }); uni.showModal({ title: '提示', - content: res.message? res.message:'课程预约失败!', + content: res.message? res.message:'禁止预约失败!', cancelText: '取消', confirmText: '确定', success: ress => { @@ -241,146 +229,59 @@ }); } }, - // 确认上课 + // 确认预约 checkdo(e,item){ console.log(e); var id= e.currentTarget.dataset.id; var that = this; - // 确认上课 + // 确认预约 uni.showModal({ title: '提示', - content: '确定上课吗?', + content: '确认预约吗?', cancelText: '取消', confirmText: '确定', success: ress => { if (ress.confirm) { - that.checkdodo(id,item); + that.checkdodo(item); } } }); }, - // 确认上课 - async checkdodo(id,item){ + // 确认预约 + async checkdodo(item){ var param={ - "courseTimeId": item.courseTimeId, - "startTime": item.startTime, - "endTime": item.endTime + "bookId": item.bookId, + "bookStatus": 1 }; - uni.showToast({ - title: '确定上课中...', - icon: 'success', - duration: 2000 + uni.showLoading({ + title: '确认预约中...' }); - const {data: res} = await uni.$http.post('/api/my/confirmClass', param); - if(res.msg=="successed"){ + const {data: res} = await uni.$http.post('/api/my/checkAppointment', param); + if(res.success){ uni.showToast({ - title: '上课已确认!', + title: '已确认预约!', icon: 'success', duration: 2000 }); // 重新加载 + this.loadStatus="more"; + this.$forceUpdate(); this.loadData(); } else{ - uni.showToast({ - title: res.msg? res.msg:'上课确认失败!', - icon: 'error', - duration: 2000 - }); - } - }, - // 取消预约 - cancelyydo(e){ - console.log(e); - var id= e.currentTarget.dataset.id; - var that = this; - //取消预约 - uni.showModal({ - title: '提示', - content: '确定要取消预约吗?', - cancelText: '取消', - confirmText: '确定', - success: ress => { - if (ress.confirm) { - that.delyydo(id); + uni.showModal({ + title: '提示', + content: res.message? res.message:'确认预约失败!', + cancelText: '取消', + confirmText: '确定', + success: ress => { + if (ress.confirm) { + } } - } - }); - }, - // 取消预约 - async delyydo(id){ - var param={ - "courseTimeId":id - }; - uni.showToast({ - title: '取消中...', - icon: 'success', - duration: 2000 - }); - const {data: res} = await uni.$http.post('/api/course/cancelCourse', param); - if(res.msg=="successed"){ - uni.showToast({ - title: '预约已取消!', - icon: 'success', - duration: 2000 - }); - // 重新加载 - this.loadData(); - } - else{ - uni.showToast({ - title: res.msg? res.msg:'预约取消失败!', - icon: 'error', - duration: 2000 }); } }, - // 取消课程 - cancelkcdo(e){ - console.log(e); - var id= e.currentTarget.dataset.id; - var that = this; - //取消课程 - uni.showModal({ - title: '提示', - content: '确定要取消课程吗?', - cancelText: '取消', - confirmText: '确定', - success: ress => { - if (ress.confirm) { - that.delkcdo(id); - } - } - }); - }, - // 取消课程 - async delkcdo(id){ - var param={ - "courseTimeId":id - }; - uni.showToast({ - title: '取消中...', - icon: 'success', - duration: 2000 - }); - const {data: res} = await uni.$http.post('/api/course/cancelCourse', param); - if(res.msg=="successed"){ - uni.showToast({ - title: '课程已取消!', - icon: 'success', - duration: 2000 - }); - // 重新加载 - this.loadData(); - } - else{ - uni.showToast({ - title: res.msg? res.msg:'课程取消失败!', - icon: 'error', - duration: 2000 - }); - } - } + } } @@ -482,28 +383,26 @@ flex-direction: column; background-color: #FFFFFF; border-radius: 6rpx; - padding: 20rpx; + padding: 20rpx 30rpx; width: 100%; margin-bottom: 20rpx; .otop{ display: flex; flex-direction: row; - padding: 10rpx 0 0; - height: 60rpx; - line-height: 60rpx; width: 100%; + padding: 10rpx 0 10rpx; + border-bottom: 1rpx solid #eee; .hleft{ display: flex; - flex-direction: row; + flex-direction: column; flex:1; - align-items: center; - font-size: 30rpx; + justify-content: flex-start; + font-size: 28rpx; color: #000; } .hright{ display: flex; justify-content: flex-end; - align-items: center; // .ztip{ border-radius: 12rpx; @@ -576,19 +475,14 @@ flex-direction: row; justify-content: flex-end; border-top: 1rpx solid #eee; - padding: 20rpx 0 10rpx; + padding: 20rpx 0 2rpx; width: 100%; .omoney{ display: flex; flex:1; - height: 60rpx; width: 100%; color:#333; - align-items: center; - .omtip{ - font-size: 36rpx; - color:rgb(252, 105, 0); - } + align-items: center; } .cancelbtn{ background-color: #FFFFFF !important; @@ -619,37 +513,7 @@ .viewbtn::after{ border:0 !important; } - .pjbtn{ - background-color: #FFFFFF !important; - margin-left: 20rpx; - border-radius: 50rpx; - border-radius: 50rpx; - height: 50rpx; - line-height: 48rpx; - padding: 0 20rpx; - font-size: 24rpx; - border:1rpx solid rgb(252, 105, 0); - color:rgb(252, 105, 0); - } - .pjbtn::after{ - border:0 !important; - } - .conbtn{ - background-color: #f3f4ef !important; - margin-left: 20rpx; - border-radius: 50rpx; - border-radius: 50rpx; - height: 50rpx; - line-height: 48rpx; - padding: 0 20rpx; - font-size: 24rpx; - border:1rpx solid #00a89b; - color:#595d4d; - } - .conbtn::after{ - border:0 !important; - } - .paybtn{ + .orderbtn{ background-color: #00a89b !important; margin-left: 20rpx; border-radius: 50rpx; @@ -660,38 +524,25 @@ font-size: 24rpx; border:1rpx solid #00a89b; } - .paybtn::after{ - border:0 !important; - } - .gzbtn{ - background-color: #f5aa00 !important; - margin-left: 20rpx; - border-radius: 50rpx; - height: 50rpx; - line-height: 48rpx; - padding: 0 20rpx; - font-size: 24rpx; - border:1rpx solid #f5aa00; - } - .gzbtn::after{ + .orderbtn::after{ border:0 !important; } - .gzbtn{ - background-color: #f5aa00 !important; + .stopbtn{ + background-color: #f47fa0 !important; margin-left: 20rpx; border-radius: 50rpx; height: 50rpx; line-height: 48rpx; padding: 0 20rpx; font-size: 24rpx; - border:1rpx solid #f5aa00; + border:1rpx solid #f47fa0; } - .gzbtn::after{ + .stopbtn::after{ border:0 !important; } } .oscon{ - margin:20rpx 0; + margin:16rpx 0; border-radius: 16rpx; display: flex; flex-direction: row; @@ -707,25 +558,17 @@ flex: 1; display: flex; flex-direction: column; - margin-left: 26rpx; .ntxt{ - font-size: 28rpx; - color:#000; + font-size: 26rpx; + color:#333; line-height: 36rpx; margin-bottom: 8rpx; } .txt{ - font-size: 24rpx; - color:#666; + font-size: 26rpx; + color:#333; } - } - .osprice{ - display: flex; - justify-content: flex-end; - margin-right: 10rpx; - font-size: 30rpx; - color:#666; - } + } } } .sitem { diff --git a/pages/book/bookteacher.vue b/pages/book/bookteacher.vue index db7bdaf..0dd916e 100644 --- a/pages/book/bookteacher.vue +++ b/pages/book/bookteacher.vue @@ -5,9 +5,13 @@ - + - {{item.storeName?item.storeName:'门店'}} + + 姓名:{{item.studentName?item.studentName:'-'}} + 性别:{{item.sex==2?'男':(item.sex==1?'女':'未知')}} + + 电话:{{item.phone?item.phone:'-'}} @@ -20,27 +24,29 @@ - - - - + - {{item.courseName}} {{item.claName}} - 教练:{{item.teacherName }} - 上课时间:{{ item.claDate+' '+item.startTime+'-'+item.endTime}} - 教室:{{item.roomName}} + + 课程:{{item.courseName}} + 班级:{{item.claName}} + + + 教练:{{item.teacherName }} + 教室:{{item.roomName}} + + 上课时间:{{ item.claDate+' '+item.startTime+(item.endTime?'-'+item.endTime:'')}} + + 预约人数:{{item.bookAttendCnt}} + 可容纳人数:{{item.atClassCnt}} + - - - - - - + + @@ -137,7 +143,6 @@ } }, loadData(){ - console.log('loadData'); // 加载 if(this.loadStatus=="more") { this.loadStatus="loading"; @@ -152,18 +157,6 @@ url: `/pages/book/bookinfo?id=${id}` }); }, - // 联系教练 - gototeacher(item){ - var data={ - id:item.id, - name:"教练A" - } - // 联系教练 - var data=encodeURIComponent(JSON.stringify(data)); - uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` - }) - }, // 去评价 gotoevaluate(item){ var data=encodeURIComponent(JSON.stringify(item)); @@ -186,52 +179,47 @@ return true; } }, - // 再次预约 - orderdo(e,item){ - console.log(id,item); + // 禁止预约 + stopdo(e,item){ var that = this; - // 再次预约 + // 禁止预约 uni.showModal({ title: '提示', - content: '确定再次预约吗?', + content: '确定禁止预约吗?', cancelText: '取消', confirmText: '确定', success: ress => { if (ress.confirm) { - that.checkdodo(id,item); + that.stopdodo(item); } } }); }, - // 再次预约 - async orderdodo(id,item){ + // 禁止预约 + async stopdodo(item){ var param={ - "courseTimeId": item.courseTimeId + "bookId": item.bookId, + "bookStatus": 2 }; - uni.showToast({ - title: '再次预约中...', - icon: 'success', - duration: 2000 + uni.showLoading({ + title: '禁止预约中...' }); - const {data: res} = await uni.$http.post('/api/course/bookCourse', param); + const {data: res} = await uni.$http.post('/api/my/checkAppointment', param); if(res.success){ uni.showToast({ - title: '上课已预约!', + title: '已禁止预约!', icon: 'success', duration: 2000 }); // 重新加载 + this.loadStatus="more"; + this.$forceUpdate(); this.loadData(); } else{ - // uni.showToast({ - // title: res.msg? res.msg:'上课预约失败!', - // icon: 'error', - // duration: 2000 - // }); uni.showModal({ title: '提示', - content: res.message? res.message:'课程预约失败!', + content: res.message? res.message:'禁止预约失败!', cancelText: '取消', confirmText: '确定', success: ress => { @@ -241,146 +229,59 @@ }); } }, - // 确认上课 + // 确认预约 checkdo(e,item){ console.log(e); var id= e.currentTarget.dataset.id; var that = this; - // 确认上课 + // 确认预约 uni.showModal({ title: '提示', - content: '确定上课吗?', + content: '确认预约吗?', cancelText: '取消', confirmText: '确定', success: ress => { if (ress.confirm) { - that.checkdodo(id,item); + that.checkdodo(item); } } }); }, - // 确认上课 - async checkdodo(id,item){ + // 确认预约 + async checkdodo(item){ var param={ - "courseTimeId": item.courseTimeId, - "startTime": item.startTime, - "endTime": item.endTime + "bookId": item.bookId, + "bookStatus": 1 }; - uni.showToast({ - title: '确定上课中...', - icon: 'success', - duration: 2000 + uni.showLoading({ + title: '确认预约中...' }); - const {data: res} = await uni.$http.post('/api/my/confirmClass', param); - if(res.msg=="successed"){ + const {data: res} = await uni.$http.post('/api/my/checkAppointment', param); + if(res.success){ uni.showToast({ - title: '上课已确认!', + title: '已确认预约!', icon: 'success', duration: 2000 }); // 重新加载 + this.loadStatus="more"; + this.$forceUpdate(); this.loadData(); } else{ - uni.showToast({ - title: res.msg? res.msg:'上课确认失败!', - icon: 'error', - duration: 2000 - }); - } - }, - // 取消预约 - cancelyydo(e){ - console.log(e); - var id= e.currentTarget.dataset.id; - var that = this; - //取消预约 - uni.showModal({ - title: '提示', - content: '确定要取消预约吗?', - cancelText: '取消', - confirmText: '确定', - success: ress => { - if (ress.confirm) { - that.delyydo(id); + uni.showModal({ + title: '提示', + content: res.message? res.message:'确认预约失败!', + cancelText: '取消', + confirmText: '确定', + success: ress => { + if (ress.confirm) { + } } - } - }); - }, - // 取消预约 - async delyydo(id){ - var param={ - "courseTimeId":id - }; - uni.showToast({ - title: '取消中...', - icon: 'success', - duration: 2000 - }); - const {data: res} = await uni.$http.post('/api/course/cancelCourse', param); - if(res.msg=="successed"){ - uni.showToast({ - title: '预约已取消!', - icon: 'success', - duration: 2000 - }); - // 重新加载 - this.loadData(); - } - else{ - uni.showToast({ - title: res.msg? res.msg:'预约取消失败!', - icon: 'error', - duration: 2000 }); } }, - // 取消课程 - cancelkcdo(e){ - console.log(e); - var id= e.currentTarget.dataset.id; - var that = this; - //取消课程 - uni.showModal({ - title: '提示', - content: '确定要取消课程吗?', - cancelText: '取消', - confirmText: '确定', - success: ress => { - if (ress.confirm) { - that.delkcdo(id); - } - } - }); - }, - // 取消课程 - async delkcdo(id){ - var param={ - "courseTimeId":id - }; - uni.showToast({ - title: '取消中...', - icon: 'success', - duration: 2000 - }); - const {data: res} = await uni.$http.post('/api/course/cancelCourse', param); - if(res.msg=="successed"){ - uni.showToast({ - title: '课程已取消!', - icon: 'success', - duration: 2000 - }); - // 重新加载 - this.loadData(); - } - else{ - uni.showToast({ - title: res.msg? res.msg:'课程取消失败!', - icon: 'error', - duration: 2000 - }); - } - } + } } @@ -482,28 +383,26 @@ flex-direction: column; background-color: #FFFFFF; border-radius: 6rpx; - padding: 20rpx; + padding: 20rpx 30rpx; width: 100%; margin-bottom: 20rpx; .otop{ display: flex; flex-direction: row; - padding: 10rpx 0 0; - height: 60rpx; - line-height: 60rpx; width: 100%; + padding: 10rpx 0 10rpx; + border-bottom: 1rpx solid #eee; .hleft{ display: flex; - flex-direction: row; + flex-direction: column; flex:1; - align-items: center; - font-size: 30rpx; + justify-content: flex-start; + font-size: 28rpx; color: #000; } .hright{ display: flex; justify-content: flex-end; - align-items: center; // .ztip{ border-radius: 12rpx; @@ -576,19 +475,14 @@ flex-direction: row; justify-content: flex-end; border-top: 1rpx solid #eee; - padding: 20rpx 0 10rpx; + padding: 20rpx 0 2rpx; width: 100%; .omoney{ display: flex; flex:1; - height: 60rpx; width: 100%; color:#333; - align-items: center; - .omtip{ - font-size: 36rpx; - color:rgb(252, 105, 0); - } + align-items: center; } .cancelbtn{ background-color: #FFFFFF !important; @@ -619,37 +513,7 @@ .viewbtn::after{ border:0 !important; } - .pjbtn{ - background-color: #FFFFFF !important; - margin-left: 20rpx; - border-radius: 50rpx; - border-radius: 50rpx; - height: 50rpx; - line-height: 48rpx; - padding: 0 20rpx; - font-size: 24rpx; - border:1rpx solid rgb(252, 105, 0); - color:rgb(252, 105, 0); - } - .pjbtn::after{ - border:0 !important; - } - .conbtn{ - background-color: #f3f4ef !important; - margin-left: 20rpx; - border-radius: 50rpx; - border-radius: 50rpx; - height: 50rpx; - line-height: 48rpx; - padding: 0 20rpx; - font-size: 24rpx; - border:1rpx solid #00a89b; - color:#595d4d; - } - .conbtn::after{ - border:0 !important; - } - .paybtn{ + .orderbtn{ background-color: #00a89b !important; margin-left: 20rpx; border-radius: 50rpx; @@ -660,38 +524,25 @@ font-size: 24rpx; border:1rpx solid #00a89b; } - .paybtn::after{ - border:0 !important; - } - .gzbtn{ - background-color: #f5aa00 !important; - margin-left: 20rpx; - border-radius: 50rpx; - height: 50rpx; - line-height: 48rpx; - padding: 0 20rpx; - font-size: 24rpx; - border:1rpx solid #f5aa00; - } - .gzbtn::after{ + .orderbtn::after{ border:0 !important; } - .gzbtn{ - background-color: #f5aa00 !important; + .stopbtn{ + background-color: #f47fa0 !important; margin-left: 20rpx; border-radius: 50rpx; height: 50rpx; line-height: 48rpx; padding: 0 20rpx; font-size: 24rpx; - border:1rpx solid #f5aa00; + border:1rpx solid #f47fa0; } - .gzbtn::after{ + .stopbtn::after{ border:0 !important; } } .oscon{ - margin:20rpx 0; + margin:16rpx 0; border-radius: 16rpx; display: flex; flex-direction: row; @@ -707,25 +558,17 @@ flex: 1; display: flex; flex-direction: column; - margin-left: 26rpx; .ntxt{ - font-size: 28rpx; - color:#000; + font-size: 26rpx; + color:#333; line-height: 36rpx; margin-bottom: 8rpx; } .txt{ - font-size: 24rpx; - color:#666; + font-size: 26rpx; + color:#333; } - } - .osprice{ - display: flex; - justify-content: flex-end; - margin-right: 10rpx; - font-size: 30rpx; - color:#666; - } + } } } .sitem { diff --git a/pages/category/category.vue b/pages/category/category.vue index 14daaa8..0fd6d8f 100644 --- a/pages/category/category.vue +++ b/pages/category/category.vue @@ -79,8 +79,8 @@ - - + + @@ -100,6 +100,28 @@ + + + + {{title}} + + {{description}} + + + + + + {{(j+1)+'、'+cell.content}} + + + + + + + + + @@ -148,7 +170,7 @@ userid:"", tabCurrentIndex: 0, scrollLeft: 0, - shopid:myCache('myshopid')?myCache('myshopid'):'', + shopid:myCache('myshopid')?myCache('myshopid'):null, shop:myCache('myshop')?myCache('myshop'):'', tabIndex: 0, id:1, @@ -254,6 +276,30 @@ }] }, }, + items: [ + { + value: '2', + name: '2', + text: '2' + }, + { + value: '1', + text: '1', + name: '1' + }, + { + value: '0', + text: '0', + name: '0' + } + ], + + description:"(亲爱的伽人,欢迎来到中医九种体质自测普查,此版本适用人群:全年龄段评分标准:请根据近1年真实情况勾选。打分规则:完全符合 = 2分 | 偶尔有 = 1分 | 完全不符合 = 0分请选择)", + title:"中医九种体质自测普查", + surveyId:null, + scores:0, + sessionId:null, + }; }, onLoad(option) { @@ -296,6 +342,199 @@ },100); }, methods: { + numberToChinese(num) { + const chineseNums = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']; + const sections = ['', '十', '百', '千']; + const units = ['', '万', '亿']; + num = String(num).split("").reverse().join(""); // 将数字反转以便从低位到高位处理 + let result = ''; + let unitIndex = 0; + + for (let i = 0; i < num.length; i++) { + let n = Number(num[i]); + if (n !== 0) { + result = chineseNums[n] + sections[i % 4] + result; + if (i % 4 === 0 && i !== 0) { + result = units[unitIndex] + result; + unitIndex++; + } + } else { + if (result.charAt(0) !== chineseNums[0]) { // 避免连续多个零 + result = chineseNums[0] + result; + } + } + } + + return result.replace(/零([亿万])/g, "$1").replace(/零+/g, "零"); // 处理连续零和结果尾部的零 + }, + getoption(options){ + var arrs=[]; + if(options&&options.length>0){ + options.forEach(option=>{ + arrs.push({value:option.score,text:option.optionText}) + }) + } + return arrs; + }, + checkboxChange(e,i,j){ + console.log('e:',e,i,j); + if(e.detail.data){ + this.list[this.tabCurrentIndex].slist[i].questions[j]["score"]=e.detail.value; + this.$forceUpdate(); + this.list[this.tabCurrentIndex].slist[i].questions[j].options.forEach(op=>{ + if(e.detail.value==op.score){ + this.list[this.tabCurrentIndex].slist[i].questions[j]["optionId"]=op.optionId; + this.$forceUpdate(); + } + }) + this.scores=0; + this.list[this.tabCurrentIndex].slist.forEach((item,ind) => { + var score=0 + if(item.questions){ + item.questions.forEach(cell => { + if(cell.score){ + this.scores+=cell.score; + score+=cell.score; + this.$forceUpdate(); + } + }); + } + this.list[this.tabCurrentIndex].slist[ind]["score"]=score; + this.$forceUpdate(); + }); + this.$forceUpdate(); + } + }, + tzsubmit(ref) { + var answers=[]; + var tj=0; + this.list[this.tabCurrentIndex].slist.forEach(item => { + if(item.questions){ + item.questions.forEach(cell => { + if(cell.optionId){ + tj++; + answers.push({ + questionId:cell.questionId, + optionId:cell.optionId + }); + } + }); + } + + }) + if(tj>0){ + this.tzsavedo(answers) + } + else{ + uni.showModal({ + title: '提示', + content: "请选择体质测评数据后提交!", + cancelText: '取消', + confirmText: '确定', + success: ress => { + if (ress.confirm) { + } + } + }); + } + }, + async tzsavedo(answers){ + var params={ + answers:answers, + surveyId:this.surveyId, + sessionId:this.sessionId, + } + try{ + const {data: res} = await uni.$http.post('/api/questionnaire/submit', params); + if(res&&res.success){ + var data=res.data; + var constitutionScores=data.constitutionScores?data.constitutionScores:[]; + + // 1.若平和质总分 ≥ 8分,且其他所有体质总分均 < 6分) + // 则跳出为:恭喜您,您的体质为“为平和体质”,非常完美。请联系您的馆主或教练,领取训练及生活方案,继续保持哦。 + + // 2.(若某一种偏颇体质(气虚/阳虚/阴虚等)总分 ≥ 8分) + // 亲爱的伽人您好,您的体质为典型(气虚/阳虚/阴虚等,是什么就跳出什么)体质。请联系您的馆主或教练,领取训练机生活方案,快速调整哦。 + + // 3.(若某一种偏颇体质总分在 6 ~ 7分 之间)则跳出为: + // 亲爱的伽人您好,您的体质为典型(气虚/阳虚/阴虚等,是什么就跳出什么)倾向体质。请联系您的馆主或教练,领取训练机生活方案,快速调整哦。 + + // 4.(若有两种及以上偏颇体质分数都7分含7分以上,)则跳出: + // 亲爱的伽人您好,您的体质为复合型体质典型,建议综合调理。请联系您的馆主或教练,领取训练机生活方案,快速调整哦。 + var ifone=0,iftwo=0,ifthree=0,iffour=0; + var twostr=[],threestr=[]; + constitutionScores.forEach(item=>{ + // 1.若平和质总分 ≥ 8分,且其他所有体质总分均 < 6分) + if(item.constitutionAlias=="pinghe"){ + if(item.totalScore>=8) + { + ifone=2; + } + } + else{ + if(item.totalScore>6) + { + ifone=ifone-1; + } + if(item.totalScore>=8) + { + iftwo=iftwo+1; + twostr.push(item.constitutionName.replace("体质","")) + } + if(item.totalScore>=7&&item.totalScore<=6) + { + ifthree=ifthree+1; + threestr.push(item.constitutionName.replace("体质","")) + } + if(item.totalScore>=7) + { + iffour=iffour+1; + } + } + }); + var tips=data.resultText?data.resultText:"体质测评提交成功!"; + if(ifone==2){ + tips="恭喜您,您的体质为“为平和体质”,非常完美。请联系您的馆主或教练,领取训练及生活方案,继续保持哦。" + } + else if(iftwo>0){ + tips="亲爱的伽人您好,您的体质为典型"+twostr.toString('/')+"体质。请联系您的馆主或教练,领取训练机生活方案,快速调整哦。" + } + else if(ifthree>0){ + tips="亲爱的伽人您好,您的体质为典型"+threestr.toString('/')+"倾向体质。请联系您的馆主或教练,领取训练机生活方案,快速调整哦。" + } + else if(iffour>1){ + tips="亲爱的伽人您好,您的体质为复合型体质典型,建议综合调理。请联系您的馆主或教练,领取训练机生活方案,快速调整哦。" + } + + uni.showModal({ + title: '提示', + content: tips, + cancelText: '取消', + confirmText: '确定', + success: ress => { + if (ress.confirm) {} + } + }); + } + else{ + uni.showModal({ + title: '提示', + content: res.message? res.message:'体质测评提交失败!请重试!', + cancelText: '取消', + confirmText: '确定' + }); + } + } + catch{ + uni.showModal({ + title: '提示', + content: '计算异常!请重试!', + cancelText: '取消', + confirmText: '确定' + }); + } + + }, async getSort() { // 分类 const {data: res} = await uni.$http.get('/api/index/getIndex'); @@ -413,36 +652,103 @@ // 吃瘦练美(健康饮食) url="/api/healthy/getList"; } + else if(this.list[this.tabCurrentIndex].id==10){ + // 体质测评 + url="/api/questionnaire/getOne"; + } else{ return false; } uni.showLoading({ title: '数据加载中...' }); - // 获取数据 - const {data: res} = await uni.$http.post(url, para); - if(res.data){ - this.list[this.tabCurrentIndex].loadStatus="noMore"; - if(this.list[this.tabCurrentIndex].id==3){ - console.log(res.data) - // 了解场馆 - var companyIntroduction=res.data&&res.data.companyIntroduction?res.data.companyIntroduction:''; - if(companyIntroduction){ - this.html1=companyIntroduction.profile; //企业简介 - this.html2=companyIntroduction.founder; //创始人 + + // 体质测评 + if(this.list[this.tabCurrentIndex].id==10){ + // 获取体质测评项 + const {data: res} = await uni.$http.get(url); + if(res.data){ + var data=res.data; + this.list[this.tabCurrentIndex].loadStatus="noMore"; + this.list[this.tabCurrentIndex].slist=data.constitutions?data.constitutions:[]; + this.description=data.description; + this.title=data.title; + this.surveyId=data.surveyId; + this.sessionId=data.sessionId; + this.$forceUpdate(); + + if(this.userid){ + // 获取体质测评上次答题结果(需登录) + const {data: rest} = await uni.$http.get("/api/questionnaire/result"); + if(rest.data){ + var resultText=rest.data.resultText; + if(resultText){ + uni.showModal({ + title: '上次测评结果', + content: resultText, + cancelText: '取消', + confirmText: '确定', + success: ress => { + if (ress.confirm) {} + } + }); + } + // var constitutionScores=rest.data.constitutionScores?rest.data.constitutionScores:[]; + + // var answers=rest.data.answers?rest.data.answers:[]; + // answers.forEach(cell=>{ + // this.list[this.tabCurrentIndex].slist.forEach((item,ii)=>{ + // if(item.questions&&item.questions.length>0){ + // item.questions.forEach((qt,kk)=>{ + // if(qt.questionId==answers.questionId){ + // if(qt.options){ + // qt.options.forEach((opt,hh)=>{ + // if(opt.optionId==answers.optionId){ + // this.list[this.tabCurrentIndex].slist[ii].questions[kk]["score"]=opt.score; + // this.$forceUpdate(); + // } + // }); + // } + // } + // }) + // } + // }); + // }); + + } } - this.shoplist=res.data&&res.data.storeList?res.data.storeList:[]; - this.$forceUpdate(); } else{ - this.list[this.tabCurrentIndex].slist=res.data; + this.list[this.tabCurrentIndex].loadStatus="noMore"; this.$forceUpdate(); } - this.$forceUpdate(); } else{ - this.list[this.tabCurrentIndex].loadStatus="noMore"; - this.$forceUpdate(); + // 获取数据 + const {data: res} = await uni.$http.post(url, para); + if(res.data){ + this.list[this.tabCurrentIndex].loadStatus="noMore"; + if(this.list[this.tabCurrentIndex].id==3){ + console.log(res.data) + // 了解场馆 + var companyIntroduction=res.data&&res.data.companyIntroduction?res.data.companyIntroduction:''; + if(companyIntroduction){ + this.html1=companyIntroduction.profile; //企业简介 + this.html2=companyIntroduction.founder; //创始人 + } + this.shoplist=res.data&&res.data.storeList?res.data.storeList:[]; + this.$forceUpdate(); + } + else{ + this.list[this.tabCurrentIndex].slist=res.data; + this.$forceUpdate(); + } + this.$forceUpdate(); + } + else{ + this.list[this.tabCurrentIndex].loadStatus="noMore"; + this.$forceUpdate(); + } } } }, @@ -488,7 +794,7 @@ }, animationfinish({ detail: { current } }) { - console.log("animationfinish") + // console.log("animationfinish") // this.tabCurrentIndex = current; }, handleChange(e) { @@ -526,7 +832,7 @@ }, tabChangeDo(){ this.scrollLeft = (this.tabCurrentIndex - 1) * 90; - if(this.list[this.tabCurrentIndex].id==2||this.list[this.tabCurrentIndex].id==10){ + if(this.list[this.tabCurrentIndex].id==2){ var that=this; // 健康指数 体质测评 setTimeout(() => { @@ -674,7 +980,7 @@ } .swiper-box { flex: 1; - height: calc(100vh - var(--window-top) - var(--window-bottom) - 280rpx) !important; + height: calc(100vh - var(--window-top) - var(--window-bottom) - 200rpx) !important; } .swiper-item { height: 100%; @@ -866,8 +1172,6 @@ /* autoprefixer: off */ -webkit-box-orient: vertical; //属性规定框的子元素应该被水平或垂直排列 /* autoprefixer: on */ - - } } } @@ -933,6 +1237,111 @@ } } } - - + + ::v-deep.uni-data-checklist .checklist-group .checklist-box .checklist-content .checklist-text{ + line-height: 40rpx !important; + font-size: 28rpx !important; + font-family: PingFang SC-Regular, PingFang SC !important; + font-weight: 400 !important; + color: #23262F !important; + } + ::v-deep .uni-forms-item.is-direction-top .uni-forms-item__label{ + font-size: 30rpx !important; + font-family: PingFang SC-Semibold, PingFang SC !important; + font-weight: 500 !important; + color: #333333 !important; + } + ::v-deep .uni-forms-item__label{ + height: auto !important; + } + ::v-deep .uni-forms-item__error{ + display: none !important; + } + ::v-deep .uni-forms-item{ + margin-bottom: 16rpx !important; + } + .uni-list-cell{ + display: flex; + flex-direction: row; + padding: 20rpx 0; + } + .rtxt{ + margin-left: 16rpx; + font-size: 28rpx; + font-family: PingFang SC-Regular, PingFang SC; + font-weight: 400; + color: #23262F; + } + .rtip{ + font-size: 28rpx; + color:#F45A45; + margin-right: 5rpx; + } + .rtitle{ + color:#666666; + height: 40rpx; + line-height: 40rpx; + font-size: 28rpx; + font-family: PingFang SC-Regular, PingFang SC; + font-weight: 400; + color: #23262F; + } + .tvalue{ + display: flex; + flex:1; + justify-content: flex-end; + font-size: 24rpx; + font-family: PingFang SC-Regular, PingFang SC; + font-weight: 400; + color: #666666; + height: 40rpx; + line-height: 40rpx; + margin-left: 16rpx; + } + .nvalue{ + display: flex; + flex:1; + justify-content: flex-end; + font-size: 24rpx; + font-family: PingFang SC-Regular, PingFang SC; + font-weight: 400; + color: #999999; + height: 40rpx; + line-height: 40rpx; + margin-left: 16rpx; + } + .example { + margin: 20rpx 8rpx 0; + padding: 20rpx; + background-color: #FFFFFF; + border-radius: 16rpx; + } + .optxt{ + width: 100%; + line-height: 40rpx; + font-size: 28rpx; + color: #23262F; + text-align: left; + } + .tztitle{ + width: 100%; + line-height: 60rpx; + font-size: 36rpx; + font-weight: 600; + color: #000; + } + .tztxt{ + width: 100%; + line-height: 32rpx; + font-size: 28rpx; + color: #000; + text-align: left; + } + .tzcontent{ + background-color: rgba(255, 255,255, 0.5); + border-radius: 20rpx; + margin: 30rpx; + padding:20rpx 20rpx; + text-align: center; + } diff --git a/pages/chat/chat.vue b/pages/chat/chat.vue new file mode 100644 index 0000000..f92c327 --- /dev/null +++ b/pages/chat/chat.vue @@ -0,0 +1,1807 @@ + + + + + diff --git a/pages/chat/groupchat.vue b/pages/chat/groupchat.vue new file mode 100644 index 0000000..9a1f8cb --- /dev/null +++ b/pages/chat/groupchat.vue @@ -0,0 +1,2005 @@ + + + + + diff --git a/pages/product/service.vue b/pages/chat/groupchat0.vue similarity index 98% rename from pages/product/service.vue rename to pages/chat/groupchat0.vue index 87e9b1e..6919b6a 100644 --- a/pages/product/service.vue +++ b/pages/chat/groupchat0.vue @@ -217,17 +217,6 @@ // 在组件销毁前,确保关闭 WebSocket 连接 this.closeWebSocket(); }, - //点击导航栏 buttons 时触发 添加任务 - onNavigationBarButtonTap: async function(e) { - const _that = this; - const index = e.index; - if (index === 0) { - var data=encodeURIComponent(JSON.stringify(_that.info)); - uni.navigateTo({ - url: `/pages/chat/chatset?data=${data}` - }); - } - }, methods: { gotoInfo(item){ var data=encodeURIComponent(JSON.stringify(item)); @@ -237,7 +226,7 @@ }, handleImageError(e,index){ console.log(e,index); - this.unshiftmsg[index]["headimg"]= require("@/static/image/girl.jpg"); + this.unshiftmsg[index]["headimg"]= require("@/static/image/girl.png"); this.$forceUpdate(); }, // 获取聊天缓存 @@ -263,7 +252,7 @@ else if(cell.type=='txt'){ cell.content=decodeURIComponent(cell.content); } - cell["headimg"]=require("@/static/image/girl.jpg"); //this.imgurl+'/images/'+ cell.fromuser+".jpg?id="+Math.random()*100; + cell["headimg"]=require("@/static/image/girl.png"); //this.imgurl+'/images/'+ cell.fromuser+".jpg?id="+Math.random()*100; this.unshiftmsg.push(cell); // 跳转到最后一条数据 与前面的:id进行对照 setTimeout(() => { @@ -567,7 +556,7 @@ let data = { "fromname": this.friendName, "fromuser": this.friendcode, - "headimg":require("@/static/image/girl.jpg"), + "headimg":require("@/static/image/girl.png"), "toname": this.info.name, // 接收人 "touser": this.info.id, // 接收人姓名 "content": e.type=='audio'?e.message.voice:e.message, diff --git a/pages/chat/groupchat1.vue b/pages/chat/groupchat1.vue new file mode 100644 index 0000000..30833e6 --- /dev/null +++ b/pages/chat/groupchat1.vue @@ -0,0 +1,1830 @@ + + + + + diff --git a/pages/components/cart.vue b/pages/components/cart.vue index 37d1e9f..5bce8a9 100644 --- a/pages/components/cart.vue +++ b/pages/components/cart.vue @@ -203,7 +203,7 @@ export default { spData:JSON.stringify(this.product.spData),// this.retSku(this.product.spData) 展示时候再解析,保持数据一致, // 保存字符串 this.product.spData, skuId:this.product.skuId, quantity:this.product.quantity, - storeId:myCache('myshopid')?myCache('myshopid'):'', + storeId:this.product.storeId, isCourse:this.product.isCourse, }; const {data: res1} = await uni.$http.post('/api/cart/add',param); diff --git a/pages/components/selShop.vue b/pages/components/selShop.vue index 347291e..b63a2f8 100644 --- a/pages/components/selShop.vue +++ b/pages/components/selShop.vue @@ -27,8 +27,11 @@ - - + + + + + @@ -86,8 +89,8 @@ export default { default: false, }, shopid: { - type: Number, - default: 0, + type: String, + default: '0', }, shop: { type: String, @@ -111,11 +114,28 @@ export default { } }, // 切换门店 - changeArea(item){ - myCache('myshop',item.storeName); - myCache('myshopid',item.id); - this._hide(); - this.$emit("changeArea", item); + async changeArea(item){ + uni.showLoading({ + title: '门店切换中...' + }); + const {data: res} = await uni.$http.post('/api/index/changeStore',{"visitStoreId":item.id}); + if(res&&res.success){ + var data=res.data; + myCache('myshop',data.storeName); + myCache('myshopid',data.id); + this._hide(); + this.$emit("changeArea", data); + } + else{ + // 切换门店 + uni.showModal({ + title: '提示', + content: res.message? res.message : '切换门店失败!请重试!', + cancelText: '取消', + confirmText: '确定', + success: ress => {} + }); + } }, _show() { this.areas= myCache('shoplist'); @@ -276,6 +296,10 @@ export default { padding: 20rpx 0 20rpx 10rpx; margin: 10rpx 30rpx 0 30rpx; align-items: center; + .sarr{ + width: 30rpx; + margin-right: 10rpx; + } .stimg{ width: 80rpx; height: 80rpx; diff --git a/pages/components/service.vue b/pages/components/service.vue index e511450..5a83ae2 100644 --- a/pages/components/service.vue +++ b/pages/components/service.vue @@ -13,8 +13,9 @@ export default { }, methods: { goservice(){ - console.log('linemobile',myCache('linemobile')) - myCache('linemobile','18900000001') + var shop=myCache('shop'); + var phone=shop&&shop.phone?shop.phone:""; + myCache('linemobile',phone) // 在线客服 if(myCache('linemobile')){ // 在线客服 @@ -28,38 +29,7 @@ export default { } }); } - else{ - // this.getlinemobile(); - } this.$emit("goservice", "goservice"); - }, - async getlinemobile(){ - const {data: res} = await uni.$http.get('/platform/getHotline'); - console.log(res) - if (res) { - myCache('linemobile',res); - uni.makePhoneCall({ - phoneNumber: String(myCache('linemobile')), - success:function(){ - console.log('拨打电话成功'); - }, - fail() { - console.log('打电话失败了'); - } - }); - } - else{ - uni.showModal({ - title: '提示', - content: '在线电话获取失败!请稍后再试!', - cancelText: '取消', - confirmText: '确定', - success: ress => { - if (ress.confirm) { - } - } - }); - } } } } diff --git a/pages/index/index.vue b/pages/index/index.vue index 9e9a07f..eabbe16 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -18,8 +18,8 @@ :duration="1000" :circular="true"> - - + + @@ -104,16 +104,12 @@ openId:"", phone:"", userid:"", - shopid: myCache('myshopid'), + shopid: myCache('myshopid')?myCache('myshopid'):null, shop: myCache('myshop'), // banner swiperList:[ - { - ban_img:"../../static/image/b1.jpg" - }, - { - ban_img:"../../static/image/b2.png" - } + "../../static/image/b1.jpg", + "../../static/image/b2.png" ],// myCache('swiperCache'), colors:[ "#f9d1c8","#c7d7bd","#c4dfe4","#efdddd","#c4ccdf","#fceaac","#d5e7c1", @@ -199,11 +195,18 @@ page: { pageNum: 1, pageSize: 10, - visitStore: myCache('myshopid')?myCache('myshopid'):'', + visitStore: myCache('myshopid')?myCache('myshopid'):null, }, }; }, onLoad() { + var shop=myCache('shop'); + var banner=shop&&shop.banner?shop.banner:""; + banner=banner.split(','); + if(banner.length>0){ + this.swiperList=banner; + this.$forceUpdate(); + } // 获取分类信息 this.getSort(); @@ -212,20 +215,34 @@ this.getservice(); // 获取老师信息 - this.loadData(); + // this.loadData(); + // setTimeout(() => { + // console.log("getCurrentActivity") + // this.getCurrentActivity(); + // },2000); }, onShow() { - this.shopid = myCache('myshopid')?myCache('myshopid'):''; + this.shopid = myCache('myshopid')?myCache('myshopid'):null; this.shop = myCache('myshop')?myCache('myshop'):''; this.$forceUpdate(); - if(myCache("loginindex")=="1"){ - uni.setStorageSync("loginindex", ""); - // 获取老师信息 - this.loadData(); + // 获取老师信息 + this.teacherList=[]; + this.loadStatus="more"; + this.page={ + pageNum: 1, + pageSize: 10, + visitStore:this.shopid } + this.loadData(); + + // if(myCache("loginindex")=="1"){ + // uni.setStorageSync("loginindex", ""); + // // 获取老师信息 + // this.loadData(); + // } this.openId = myCache('openId'); var user = myCache('user'); @@ -286,6 +303,22 @@ this.$refs.topId.topData(e.scrollTop); }, methods: { + getCurrentActivity() { + // 获取当前Activity(仅App端有效) + const mainActivity = plus.android.runtimeMainActivity(); + if (mainActivity) { + console.log('获取到Activity对象:', mainActivity); + // 可进一步调用Activity方法(需通过plus.android.importClass) + plus.android.importClass(mainActivity); + //console.log('Activity类名:', mainActivity.getClass().getSimpleName()); + //console.log('Activity类名:', mainActivity.getClass()); + console.log('Activity类名:', mainActivity.getClassName()); + return mainActivity; + } else { + console.error('无法获取Activity对象'); + return null; + } + }, getimgRemoteFile(img){ if(img){ img=img.split(',')[0]; @@ -391,17 +424,25 @@ this.loadStatus="loading"; setTimeout(() => { this.getTeacherList(); + this.getBanner(); }, 300); } }, async getBanner() { // banner - const {data: res} = await uni.$http.post('/platform/getbanner'); - if (res&&res.length>0) { - this.swiperList=res; - // 保存海报信息 - myCache('swiperCache',this.swiperList); - this.$forceUpdate(); + const {data: res} = await uni.$http.get('/api/getInfo'); + if(res&&res.visitStore){ + var shop=res.visitStore; + var banner=shop&&shop.banner?shop.banner:""; + banner=banner.split(','); + if(banner.length>0){ + this.swiperList=banner; + this.$forceUpdate(); + } + myCache('shop',shop); + myCache('myshop',shop.storeName); + myCache('myshopid',shop.id); + } }, async getSort() { @@ -574,7 +615,7 @@ gotoTeacherMore(){ // 教练风采 uni.reLaunch({ - url: `/pages/category/category?id=2` + url: `/pages/category/category?id=5` }); }, gotoTeacher(info){ diff --git a/pages/login/login.vue b/pages/login/login.vue index d9e4224..9394def 100644 --- a/pages/login/login.vue +++ b/pages/login/login.vue @@ -259,7 +259,7 @@ // phonenumber:"测试人", // userid:"1", // userphone:"18900000001", - // avatar:"/static/image/girl.jpg" + // avatar:"/static/image/girl.png" // }); // this.$refs.uToast.show({ // title: '登录成功', @@ -363,6 +363,12 @@ if(res.data&&res.data.length>0){ myCache('shoplist',res.data); } + else{ + console.log("shoplist") + var shop=myCache('shop'); + var shoplist=shop?[shop]:[]; + myCache('shoplist',shoplist); + } }, async getUserShopList(){ var _this=this; @@ -435,10 +441,10 @@ } .checkimg{ position: absolute; - top:14rpx; + top: 8rpx; right: 130rpx; - width: 150rpx; - height: 50rpx; + width: 160rpx; + height: 66rpx; } .codebtn{ position: absolute; diff --git a/pages/message/contact.vue b/pages/message/contact.vue index b019ea6..62866c6 100644 --- a/pages/message/contact.vue +++ b/pages/message/contact.vue @@ -9,25 +9,35 @@ - + + - 教练 + 教练 - + + - 客服 + 客服 - + + - 课程顾问 + 课程顾问 - + + - 店长 + 店长 + + + + 学员 + + - 群聊 + 群聊 @@ -40,10 +50,10 @@ - + - {{info.name}} + {{info.friendNickName}} @@ -65,83 +75,84 @@ export default { data() { return { + userid:"", + userName:"", messageText:'', //错误提示框 msgType :'error', tabCurrentIndex:0, imgurl:uni.$http.baseUrl, list:[ { - id:0, + id:"coach", name:'教练', loadStatus:'loadmore', - grouplist:[ - // { - // id:1, - // name:"教练A", - // img:"/static/image/jl.png" - // }, - ] + grouplist:[] }, { - id:1, + id:"customerService", name:'客服', loadStatus:'loadmore', - grouplist:[ - // { - // id:1, - // name:"商城客服-伽伽", - // img:"/static/image/kff.png" - // }, - ] + grouplist:[] }, { - id:2, + id:"adviser", name:'课程顾问', loadStatus:'more', - grouplist:[ - // { - // id:1, - // name:"顾问1", - // img:"/static/image/gw.png" - // }, - ] + grouplist:[] }, { - id:3, + id:"storeManager", name:'店长', loadStatus:'more', - grouplist:[ - // { - // id:1, - // name:"顾问1", - // img:"/static/image/dzh.png" - // }, - ] + grouplist:[] }, { - id:4, + id:"groupchat", name:'群聊', loadStatus:'loadmore', - grouplist:[ - // { - // id:1, - // name:"群聊1", - // img:"/static/image/ql.png" - // }, - ] - } + grouplist:[] + }, + { + id:"consumer", + name:'学员', + loadStatus:'loadmore', + grouplist:[] + }, ], - page:{ - // pageNum:'1', - // pageSize: '10' - } + ifxy:false, } }, onLoad(options) { - // 未选择门店,则退出至首页选择门店 - if(myCache('myshopid')){ - + var userInfo=myCache('userInfo'); + this.userid = userInfo.userId? userInfo.userId:''; + this.userName = userInfo.nickName?userInfo.nickName:""; + var roleId=userInfo&&userInfo.roleId?userInfo.roleId:[]; + if(roleId.length<1){ + this.ifxy=true; + this.$forceUpdate(); + } + roleId.forEach(cell=>{ + if(cell=='107'&&roleId.length<2){ + this.ifxy=true; + this.$forceUpdate(); + } + else{ + this.ifxy=false; + this.$forceUpdate(); + } + }); + + if(this.ifxy){ + this.tabCurrentIndex=0; + this.$forceUpdate(); + } + else{ + this.tabCurrentIndex=5; + this.$forceUpdate(); } + + // 未选择门店,则退出至首页选择门店 + if(myCache('myshopid')){} this.loadData(); }, onShow(){ @@ -159,44 +170,86 @@ this.loadData(); }, methods: { - addContacts(){ - }, + // 新增通讯录 + addContacts(){}, gotoBack(){ // 返回 uni.navigateBack({ delta: 1 }); }, - changeTime(date) { - return dateTime.dateTime(date); - }, - gotoGroup(info){ + // 跳转聊天框 + gotoGroup(item){ + console.log(item); + // 直接跳转到聊天框 + var timestamp = new Date().getTime(); + var info={ + chatId: "privatechat-" + this.userid +"-"+ item.friendId, + chatType: (this.tabCurrentIndex==0?"coach":(this.tabCurrentIndex==1?"customerService":(this.tabCurrentIndex==2?"adviser": + (this.tabCurrentIndex==3?"storeManager":(this.tabCurrentIndex==4?"groupchat":(this.tabCurrentIndex==5?"consumer":"")))))), + chatName: item.friendNickName, + chatAvatar: item.friendHeadImage, + chatTime: timestamp, + userid: this.userid, + friendId: item.friendId, // 会话对象 + minId: null, // 已读消息的最大id + sort: this.tabCurrentIndex==4?"groupchat":"privatechat", // privatechat 私聊 groupchat 群聊 + from: "message" // yh 用户咨询进入聊天框,message 从消息进入聊天框 + } + // id:"coach", + // name:'教练', + // id:"customerService", + // name:'客服', + // id:"adviser", + // name:'课程顾问', + // id:"storeManager", + // name:'店长', + // id:"groupchat", + // name:'群聊', + // id:"consumer", + // name:'学员', + + console.log(info); if(this.tabCurrentIndex==0){ // 教练 var data=encodeURIComponent(JSON.stringify(info)); uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` + url: `/pages/chat/chat?data=${data}` }); } else if(this.tabCurrentIndex==1){ // 客服 var data=encodeURIComponent(JSON.stringify(info)); uni.navigateTo({ - url: `/pages/product/service?data=${data}` + url: `/pages/chat/chat?data=${data}` }); } else if(this.tabCurrentIndex==2){ // 顾问 var data=encodeURIComponent(JSON.stringify(info)); uni.navigateTo({ - url: `/pages/product/service?data=${data}` + url: `/pages/chat/chat?data=${data}` }); } else if(this.tabCurrentIndex==3){ + // 店长 + var data=encodeURIComponent(JSON.stringify(info)); + uni.navigateTo({ + url: `/pages/chat/chat?data=${data}` + }); + } + else if(this.tabCurrentIndex==4){ // 群聊 var data=encodeURIComponent(JSON.stringify(info)); uni.navigateTo({ - url: `/pages/product/service?data=${data}` + url: `/pages/chat/groupchat?data=${data}` + }); + } + else if(this.tabCurrentIndex==5){ + // 学员 + var data=encodeURIComponent(JSON.stringify(info)); + uni.navigateTo({ + url: `/pages/chat/chat?data=${data}` }); } }, @@ -219,7 +272,7 @@ if(this.list[this.tabCurrentIndex].loadStatus!=="nomore") { // 教练、客服、顾问、店长列表 - if(this.tabCurrentIndex==0||this.tabCurrentIndex==1||this.tabCurrentIndex==2||this.tabCurrentIndex==3){ + if(this.tabCurrentIndex==0||this.tabCurrentIndex==1||this.tabCurrentIndex==2||this.tabCurrentIndex==3||this.tabCurrentIndex==5){ const {data: res} = await uni.$http.get('/api/friend/list'); this.list[0].loadStatus="nomore"; this.list[0].grouplist=[]; @@ -229,48 +282,32 @@ this.list[2].grouplist=[]; this.list[3].loadStatus="nomore"; this.list[3].grouplist=[]; + this.list[5].loadStatus="nomore"; + this.list[5].grouplist=[]; // 教练列表 - if(res.data&&res.data.customerService&&res.data.customerService.length>0){ - res.data.customerService.forEach(cell => { - this.list[0].grouplist.push({ - id: cell.friendId, - name: cell.friendNickName, - img: cell.friendHeadImage?cell.friendHeadImage:'/static/image/ql.png' - }) - }); + if(res.data&&res.data.coach&&res.data.coach.length>0){ + this.list[0].grouplist=res.data.coach; this.$forceUpdate(); } // 客服列表 - if(res.data&&res.data.coach&&res.data.coach.length>0){ - res.data.coach.forEach(cell => { - this.list[1].grouplist.push({ - id: cell.friendId, - name: cell.friendNickName, - img: cell.friendHeadImage?cell.friendHeadImage:'/static/image/kff.png' - }) - }); + if(res.data&&res.data.customerService&&res.data.customerService.length>0){ + this.list[1].grouplist=res.data.customerService; this.$forceUpdate(); } // 顾问列表 if(res.data&&res.data.adviser&&res.data.adviser.length>0){ - res.data.adviser.forEach(cell => { - this.list[2].grouplist.push({ - id: cell.friendId, - name: cell.friendNickName, - img: cell.friendHeadImage?cell.friendHeadImage:'/static/image/gw.png' - }) - }); + this.list[2].grouplist=res.data.adviser; this.$forceUpdate(); } // 店长列表 if(res.data&&res.data.storeManager&&res.data.storeManager.length>0){ - res.data.storeManager.forEach(cell => { - this.list[3].grouplist.push({ - id: cell.friendId, - name: cell.friendNickName, - img: cell.friendHeadImage?cell.friendHeadImage:'/static/image/dzh.png' - }) - }); + this.list[3].grouplist=res.data.storeManager; + this.$forceUpdate(); + } + + // 学员列表 + if(res.data&&res.data.consumer&&res.data.consumer.length>0){ + this.list[5].grouplist=res.data.consumer; this.$forceUpdate(); } } @@ -282,16 +319,14 @@ this.list[this.tabCurrentIndex].grouplist=[]; if(res.data&&res.data.length>0){ res.data.forEach(cell => { - this.list[this.tabCurrentIndex].grouplist.push({ - id: cell.id, - name: cell.name, - img: cell.headImage?cell.headImage:'/static/image/ql.png' + this.list[this.tabCurrentIndex].grouplist.push({...cell, + friendNickName: cell.name, + friendHeadImage: cell.headImage?cell.headImage:'/static/image/ql.png' }) }); this.$forceUpdate(); } } - } }, // 获取状态栏高度 @@ -322,10 +357,7 @@ width: 100%; z-index: 999; background-color: #00a89b; - .text-center { - width: 100%; - text-align: center; - } + .edit { position: absolute; top: 50%; @@ -338,25 +370,39 @@ width: 100%; background-color: #00a89b; margin: 0; - padding: 26rpx 30rpx; + padding: 0 30rpx; + height: 100rpx; display: flex; + flex-direction: row; color: #fff; font-size: 36rpx; + align-items: center; .leftarr{ background-color: rgba(255, 255,255, 0.3); - padding: 5rpx; border-radius: 10rpx; width: 60rpx; + height: 60rpx; + display: flex; + align-items: center; + justify-content: center; + } + .text-center { + display: flex; + flex: 1; + width: 100%; + align-items: center; + justify-content: center; } } .concon{ display: flex; flex-direction: row; background: #fff; - padding: 30rpx 20rpx 20rpx 20rpx; + padding: 20rpx 0; margin: 0; + height: 190rpx; align-items: center; - justify-content: center; + justify-content: left; .concell{ display: flex; flex-direction: column; @@ -364,8 +410,8 @@ justify-content: center; width: 20%; .cimg{ - width: 100rpx; - height: 100rpx; + width: 90rpx; + height: 90rpx; } .ctxt{ font-size: 28rpx; @@ -374,33 +420,41 @@ } .cur1{ color:#ff7530; - font-size: 30rpx; + font-size: 32rpx; font-weight: 600; } .cur2{ color:#46a0fb; - font-size: 30rpx; + font-size: 32rpx; font-weight: 600; } .cur3{ color:#5bd171; - font-size: 30rpx; + font-size: 32rpx; font-weight: 600; } .cur5{ color:#d4237a; - font-size: 30rpx; + font-size: 32rpx; + font-weight: 600; + } + .cur6{ + color:#00a89b; + font-size: 32rpx; font-weight: 600; } .cur4{ color:#fca600; - font-size: 30rpx; + font-size: 32rpx; font-weight: 600; } } } .wrapcon{ - margin: 400rpx 0 0 0; + margin: 370rpx 0 0 0; + /* #ifdef H5 */ + margin: 300rpx 0 0 0; + /* #endif */ padding: 0; width: 100%; position: relative; @@ -433,8 +487,8 @@ justify-content: center; border-radius: 50%; .img{ - width: 100rpx; - height: 100rpx; + width: 80rpx; + height: 80rpx; border-radius: 10rpx; } } diff --git a/pages/message/group.vue b/pages/message/group.vue index 757a437..27e45fc 100644 --- a/pages/message/group.vue +++ b/pages/message/group.vue @@ -6,35 +6,38 @@ - + 暂无消息~ - - - - - - - {{info.name}} - {{ changeTime(info.datetime)}} - - - - {{info.content}} + + + + - - - {{ info.sl}} + + + {{info.name}} + {{ changeTime(info.datetime)}} + + + + {{ info.type==0?info.content:(info.type==1?"图片":(info.type==2?"文件":(info.type==3?"语音":(info.type==4?"视频": + (info.type==5?"订单咨询":(info.type==6?"商品咨询":info.content))))))}} + + + {{ info.sl}} + + - - - + + + + + @@ -53,92 +56,47 @@ export default { data() { return { + openId:"", + phone:"", + userid:"", + userName:"", + userheadimg:"", messageText:'', //错误提示框 msgType :'error', loadStatus:'loadmore', + options: [ + { + text: '删除', + style: { + backgroundColor: '#ed2a28' + } + } + ], //u-swipe-action样式 imgurl:uni.$http.baseUrl, - grouplist:[ - // { - // id:1, - // sl:25, - // name:"商城客服-伽伽", - // img:"../../static/image/girl.jpg", - // content:"测试信息1", - // datetime:"2025-07-10 12:18", - // type:1, // 客服 - // }, - // { - // id:2, - // sl:8, - // name:"教练A", - // img:"../../static/image/girl.jpg", - // content:"测试信息2", - // datetime:"2025-07-05 12:18", - // type:2, // 老师 - // }, - // { - // id:1, - // sl:25, - // name:"商城客服-伽伽", - // img:"../../static/image/girl.jpg", - // content:"测试信息1", - // datetime:"2025-07-10 12:18", - // type:1, // 客服 - // }, - // { - // id:2, - // sl:8, - // name:"教练A", - // img:"../../static/image/girl.jpg", - // content:"测试信息2", - // datetime:"2025-07-05 12:18", - // type:2, // 老师 - // }, - // { - // id:1, - // sl:25, - // name:"商城客服-伽伽", - // img:"../../static/image/girl.jpg", - // content:"测试信息1", - // datetime:"2025-07-10 12:18", - // type:1, // 客服 - // }, - // { - // id:2, - // sl:8, - // name:"教练A", - // img:"../../static/image/girl.jpg", - // content:"测试信息2", - // datetime:"2025-07-05 12:18", - // type:2, // 老师 - // }, - // { - // id:1, - // sl:25, - // name:"商城客服-伽伽", - // img:"../../static/image/girl.jpg", - // content:"测试信息1", - // datetime:"2025-07-10 12:18", - // type:1, // 客服 - // }, - // { - // id:2, - // sl:8, - // name:"教练A", - // img:"../../static/image/girl.jpg", - // content:"测试信息2", - // datetime:"2025-07-05 12:18", - // type:2, // 老师 - // } - ], - + grouplist:[], + socketTask: null, + isConnected: false, // WebSocket连接状态 + socketmsg:[],//接收信息 + heartbeatInterval: null, // 心跳包20秒连接一次 + heartbeatTimeout: 20000, // 心跳间隔时间,例如每20秒发送一次 } }, onLoad(options) { - // this.getgroupsmembers(); + // socket接收信息初始化 + // this.socketinit(); }, onShow(){ - this.loadStatus='loadmore'; + this.openId = myCache('openId'); + var user = myCache('user'); + this.userid = user.userid? user.userid:''; + this.userName=user.nickName?user.nickName:""; + this.userheadimg=user.avatar?user.avatar:require("@/static/image/girl.png"); + this.phone = user.userphone; + // 如果心跳包在发送,先停止,再启动 + if(this.heartbeatInterval){ + clearInterval(this.heartbeatInterval); // 停止心跳包发送 + } + // 从缓存聊天群里获取聊天群列表 chatlist this.loadData(); }, onPullDownRefresh() { @@ -147,12 +105,250 @@ uni.stopPullDownRefresh() },500); }, - onReachBottom() { - console.log('onReachBottom'); - // 暂不分页 - // this.loadData(); + onBackPress(options) { + if (options.from === 'backbutton') { + // 来自顶部菜单的返回按钮 + // 在这里处理你的逻辑 + console.log('返回按钮被点击'); + this.closeWebSocket(); + uni.onSocketClose(function (res) { + console.log('WebSocket 已关闭!'); + }); + return false; + } + }, + beforeDestroy() { + console.log('界面关闭socket,beforeDestroy'); + // 在组件销毁前,确保关闭 WebSocket 连接 + this.closeWebSocket(); + clearInterval(this.heartbeatInterval); // 停止心跳包发送 + }, + beforeRouteLeave(to, from, next) { + console.log('界面关闭socket,beforeRouteLeave'); + next(); }, methods: { + // 删除 + actionClick(info,index) { + console.log(info,index); + var that=this; + uni.showModal({ + title: '提示', + content: "确定要删除此聊天记录吗?", + cancelText: '取消', + confirmText: '确定', + success: ress => { + if (ress.confirm) { + myCache(info.id,""); + that.grouplist.splice(index, 1); + that.$forceUpdate(); + myCache("chatlist",that.grouplist); + } + } + }); + }, + // 定时心跳包 + startHeartbeat() { + console.log("startHeartbeat") + this.heartbeatInterval = setInterval(() => { + if (this.socketTask) { + this.socketTask.send({ + data: JSON.stringify({ + 'cmd': 1,//心跳 + 'data': { + 'accessToken':uni.getStorageSync("token") + }, + }) // 发送心跳包数据 + }); + } + }, this.heartbeatTimeout); + }, + // ws接收消息 + socketinit(){ + var that = this; + // if (!that.isConnected) { + + that.socketTask=uni.connectSocket({ + url: "wss://www.sanduolantoyoga.com/yoga-imserver/", + header: { + // 'content-type': 'application/json', + Authorization: uni.getStorageSync("token"), + }, + success: (res) => { + console.log(res, 'socket连接成功success'); + }, + fail: (res) => { + console.log(res, 'socket连接失败') + }, + complete: (res) => { + console.log(res,'socket连接成功complete'); + } + }); + + uni.onSocketOpen(resopen => { + console.log('WebSocket连接已打开!'); + that.isConnected = true; + that.$forceUpdate() + uni.sendSocketMessage({ + data: JSON.stringify({ + "cmd": 0,//心跳 + "data": { + "accessToken":uni.getStorageSync("token"), + }, + }), // 发送心跳包数据 // 发送的消息内容 + success(re) { + console.log(re); + console.log('消息发送成功!') + }, + fail(err) { + console.log(err); + console.log('消息发送失败!') + } + }); + + // 发送心跳包 + this.startHeartbeat(); + }); + + uni.onSocketMessage(res => { + console.log('收到WebSocket服务器消息:'); + if(res.data){ + var rs=JSON.parse(res.data); + console.log(rs); + if(rs.cmd==3){ + // 私聊 + if(rs.data){ + var data=rs.data; + if(data.recvId&&(data.recvId).toString()==(that.userid).toString()){ + // 是这个用户的接收的私聊信息 + // 加入聊天记录 + // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记" + if(data.type==0){ + data.content=decodeURIComponent(data.content); + } + if(data.type==0||data.type==1||data.type==2||data.type==3||data.type==4||data.type==5||data.type==6){ + var ifexist=0,idx=null; + that.grouplist.forEach((cell,index)=>{ + if(cell.fromuser==data.sendId&&cell.userid==data.recvId&&cell.sort=="privatechat"){ + ifexist=1; + idx=index; + that.grouplist[index].sl=(that.grouplist[index].sl?that.grouplist[index].sl+1:1); + that.grouplist[index].content=data.content; + that.grouplist[index].datetime=data.sendTime; + that.grouplist[index].type=data.type; + that.$forceUpdate(); + } + }); + + if(ifexist==0){ + // 未保存缓存 + // 接收到socket后更新聊天列表记录 + var chatlastinfo={ + id: "privatechat-" + data.recvId +"-" + data.sendId, + content: data.content, + minId: data.id, + sl:1, + datetime: data.sendTime, + type: data.type, + name: "", + userid: data.recvId, + fromuser: data.sendId, + img: "", + sort:"privatechat" + }; + that.updateChatList(chatlastinfo,ifexist); + } + else{ + that.updateChatList(that.grouplist[idx],ifexist); + } + } + else{ + // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记" + } + } + } + } + else if(rs.cmd==4){ + // 群聊 + if(rs.data){ + var data=rs.data; + if(data.atUserIds&&data.atUserIds.includes(that.userid)){ + // 是这个用户的接收的群聊信息 + // 加入聊天记录 + // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记" + if(data.type==0){ + data.content=decodeURIComponent(data.content); + } + if(data.type==0||data.type==1||data.type==2||data.type==3||data.type==4||data.type==5||data.type==6){ + var ifexist=0,idx=null; + that.grouplist.forEach((cell,index)=>{ + if(cell.groupId==data.groupId&&cell.sort=="groupchat"){ + ifexist=1; + idx=index; + that.grouplist[index].sl=(that.grouplist[index].sl?that.grouplist[index].sl+1:1); + that.grouplist[index].content=data.content; + that.grouplist[index].datetime=data.sendTime; + that.grouplist[index].fromuser=data.sendId; + that.grouplist[index].type=data.type; + that.$forceUpdate(); + } + }); + + if(ifexist==0){ + // 未保存缓存 + // 接收到socket后更新聊天列表记录 + var chatlastinfo={ + id: "groupchat-" + data.groupId, + groupId:data.groupId, + content: data.content, + minId: data.id, + sl:1, + datetime: data.sendTime, + type: data.type, + name: "", + userid: this.userid, + fromuser: data.sendId, + img: "", + sendId: data.sendId, + sendNickName: data.sendNickName, + sort:"groupchat" + }; + that.getGroupInfo(chatlastinfo,ifexist); + } + else{ + that.getGroupInfo(that.grouplist[idx],ifexist); + } + } + else{ + // 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记" + } + } + } + } + } + }); + + uni.onSocketClose(res => { + console.log('WebSocket连接已关闭!',res); + that.isConnected = false; + that.$forceUpdate(); + clearInterval(that.heartbeatInterval); // 停止心跳包发送 + }); + + uni.onSocketError(err => { + console.error('WebSocket连接打开失败,请检查:', err); + that.isConnected = false; + that.$forceUpdate(); + clearInterval(that.heartbeatInterval); // 停止心跳包发送 + }); + // } + }, + // 关闭WebSocket连接 + closeWebSocket() { + uni.closeSocket(); + this.isConnected = false; + this.$forceUpdate() + }, gotoContacts(){ uni.navigateTo({ url: `/pages/message/contact` @@ -161,57 +357,448 @@ changeTime(date) { return dateTime.dateTime(date); }, - gotoGroup(info){ + gotoGroup(chat,index){ + // 当前消息未读数据消除 + this.grouplist[index]["sl"]=0; + this.$forceUpdate(); + myCache("chatlist",this.grouplist); // 去聊天室 - if(info.type==1){ - // 客服 + if(chat.sort=="privatechat"){ + // 私聊 + var info={ + chatId: chat.id, + chatName: chat.name, + chatAvatar: chat.img, + chatTime: chat.datetime, + friendId: chat.fromuser, + minId: chat.minId, + sort:"privatechat", + from:"message" // yh 用户咨询进入聊天框,message 从消息进入聊天框 + } var data=encodeURIComponent(JSON.stringify(info)); uni.navigateTo({ - url: `/pages/product/service?data=${data}` + url: `/pages/chat/chat?data=${data}` }); } - else if(info.type==2){ - // 老师 + else if(chat.sort=="groupchat"){ + // 群聊 + var info={ + chatId: chat.id, + groupId: chat.groupId, + chatName: chat.name, + chatAvatar: chat.img, + chatTime: chat.datetime, + friendId: chat.fromuser, + teacherId: chat.teacherId, + minId: chat.minId, + sort:"groupchat", // privatechat 私聊 groupchat 群聊 + from:"message", // yh 用户咨询进入聊天框,message 从消息进入聊天框 + notice: chat.notice, + remarkNickName: chat.remarkNickName, + showNickName: chat.showNickName, + showGroupName: chat.showGroupName, + remarkGroupName: chat.remarkGroupName, + reason: chat.reason, + customerService: chat.customerService, + instructor: chat.instructor, + productId: chat.productId, + productName: chat.productName + } var data=encodeURIComponent(JSON.stringify(info)); + console.log(data); uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` + url: `/pages/chat/groupchat?data=${data}` }); } }, loadData(){ - // 底部数据加载 - if(this.loadStatus=="loadmore") { - this.loadStatus="loading"; - setTimeout(() => { - this.getgroupsmembers(); - }, 300); - } + // 信息列表加载 + this.loadStatus="loading"; + setTimeout(() => { + this.getgroupsmembers(); + }, 300); }, - // 获取群聊 + // 获取群聊列表 async getgroupsmembers(){ - if(this.loadStatus!=="nomore") - { - this.loadStatus="nomore"; - var chatlist=myCache("chatlist"); - this.grouplist=chatlist?chatlist:[]; - this.grouplist.forEach((cell,i)=>{ - this.grouplist[i]["sl"]=this.getgroupsnums(cell.minId) - }); - this.loadStatus="nomore"; - this.$forceUpdate(); + // 获取聊天群列表 + this.grouplist=[]; + var chatlist=myCache("chatlist")?myCache("chatlist"):[]; + chatlist.forEach(cell=>{ + if(cell.userid==this.userid){ + this.grouplist.push(cell); + } + }); + this.grouplist.forEach((cell,i)=>{ + if(cell.minId){ + // 通过某个会话中已读消息的最大id 获取离线消息 + this.readUp(i,cell); + } + }); + this.loadStatus="nomore"; + this.$forceUpdate(); + var that=this; + setTimeout(() => { + that.reorder(); + myCache("chatlist",that.grouplist); + }, 300); + + // socket接收实时消息 + this.socketinit(); + }, + // 重新排序 + reorder(){ + this.grouplist.sort((a, b) => b.datetime - a.datetime); + this.$forceUpdate(); + }, + // 已读推送 + async readUp(i,item) { + if(item.sort=="groupchat"){ + const {data: res} = await uni.$http.put('/api/message/group/readed?groupId='+item.groupId); + this.getgroupsnums(i,item); + } + else{ + const {data: res} = await uni.$http.put('/api/message/private/readed?friendId='+item.fromuser); + this.getgroupsnums(i,item); + } + }, + // 获取群聊中离线信息 + async getgroupsnums(i,item){ + if(item.sort=="groupchat"){ + // 群聊 + const {data: res} = await uni.$http.get("/api/message/group/pullOfflineMessage",{minId:item.minId}); + if(res.data&&res.data.length>0){ + // 获取消息后对消息进行缓存处理 + var data=res.data; + // 获取离线消息数量返回 + this.grouplist[i]["sl"]=res.data.length; + var last=res.data[res.data.length-1]; + if(last.type==0){ + last.content=decodeURIComponent(last.content); + } + if(last.type==0||last.type==1||last.type==2||last.type==3||last.type==4||data.type==5||data.type==6){ + this.grouplist[i].content=last.content; + this.grouplist[i].type=last.type; + this.grouplist[i].datetime=last.datetime; + this.$forceUpdate(); + // 重新排序 + this.reorder(); + myCache("chatlist",this.grouplist); + } + } + } + else{ + // 私聊 + const {data: res} = await uni.$http.get("/api/message/private/pullOfflineMessage",{minId:item.minId}); + if(res.data&&res.data.length>0){ + // 获取消息后对消息进行缓存处理 + var data=res.data; + // 获取离线消息数量返回 + this.grouplist[i]["sl"]=res.data.length; + var last=res.data[res.data.length-1]; + if(last.type==0){ + last.content=decodeURIComponent(last.content); + } + if(last.type==0||last.type==1||last.type==2||last.type==3||last.type==4||data.type==5||data.type==6){ + this.grouplist[i].content=last.content; + this.grouplist[i].type=last.type; + this.grouplist[i].datetime=last.datetime; + this.$forceUpdate(); + // 重新排序 + this.reorder(); + myCache("chatlist",this.grouplist); + } + } + } + }, + // 获取群信息 + async getGroupInfo(info,ifexist) { + const {data: res} = await uni.$http.get('/api/group/find/'+info.groupId); + if(res.data){ + var data = res.data; + info.name=data.name; + info.img=data.headImage||'/static/image/qltx.png'; + info.notice=data.notice; + info.remarkNickName=data.remarkNickName; + info.showNickName=data.showNickName; + info.showGroupName=data.showGroupName; + info.remarkGroupName=data.remarkGroupName; + info.customerService=data.customerService; + info.instructor=data.instructor; + info.productId=data.productId; + info.productName=data.productName; + this.updateChatGroupList(info,ifexist); + } + }, + async updateChatGroupList(info,ifexist){ + var name=info.name,img=info.img||require("@/static/image/girl.png"); + const {data: res} = await uni.$http.get("/api/friend/find/"+info.sendId); + if(res.data){ + var data=res.data; + name=data.nickName?data.nickName:"匿名"; + img=data.headImage?data.headImage:require("@/static/image/girl.png"); + if(ifexist==0){ + this.grouplist.push(info); + this.$forceUpdate(); + } + // 重新排序 保存缓存 + this.reorder(); + myCache("chatlist",this.grouplist); + // 聊天框消息缓存 + var msgchat=myCache(info.id); + if(ifexist==0||!msgchat){ + // 第一条聊天记录保存缓存 + let firstmsg = [{ + "fromname": name, // 发送人 + "fromuser": info.fromuser, // 发送人 + "headimg": img, // 发送人 + "toname": this.userName, // 接收人 + "touser": this.userid, // 接收人姓名 + "content": info.content, + "time": info.type==3?5:0, + "ifaudio":info.type==3? true:false, + "fromtime": info.datetime, + "type": info.type==0?'txt':(info.type==1?'image':info.type==3?'audio':(info.type==4?'video':'product')), + "id": info.id, + "minId": info.minId, + "sendId": info.sendId, + "send": info.type==6?await this.getProduct(info.content):(info.type==5?await this.getOrder(info.content):null) + }]; + console.log("firstmsg",firstmsg) + myCache(info.id,firstmsg); + } + else{ + // 聊天框信息 保存缓存 + let firstmsg = { + "fromname": name, // 发送人 + "fromuser": info.fromuser, // 发送人 + "headimg": img, // 发送人 + "toname": this.userName, // 接收人 + "touser": this.userid, // 接收人姓名 + "content": info.content, + "time": info.type==3?5:0, + "ifaudio":info.type==3? true:false, + "fromtime": info.datetime, + "type": info.type==0?'txt':(info.type==1?'image':info.type==3?'audio':(info.type==4?'video':'product')), + "id": info.id, + "minId": info.minId, + "sendId": info.sendId, + "send": info.type==6?await this.getProduct(info.content):(info.type==5?await this.getOrder(info.content):null) + }; + msgchat.push(firstmsg); + myCache(info.id,msgchat); + } + } + else{ + name="匿名"; + img="../../static/image/girl.png"; + if(ifexist==0){ + this.grouplist.push(info); + this.$forceUpdate(); + } + // 重新排序 + this.reorder(); + myCache("chatlist",this.grouplist); + var msgchat=myCache(info.id); + if(ifexist==0||!msgchat){ + // 第一条聊天记录保存缓存 + let firstmsg = [{ + "fromname": name, // 发送人 + "fromuser": info.fromuser, // 发送人 + "headimg": img, // 发送人 + "toname": this.userName, // 接收人 + "touser": this.userid, // 接收人姓名 + "content": info.content, + "time": info.type==3?5:0, + "ifaudio":info.type==3? true:false, + "fromtime": info.datetime, + "type": info.type==0?'txt':(info.type==1?'image':info.type==3?'audio':(info.type==4?'video':'product')), + "id": info.id, + "minId": info.minId, + "sendId": info.sendId, + "send": info.type==6?await this.getProduct(info.content):(info.type==5?await this.getOrder(info.content):null) + }]; + myCache(info.id,firstmsg); + } + else{ + // 聊天框信息 保存缓存 + let firstmsg = { + "fromname": name, // 发送人 + "fromuser": info.fromuser, // 发送人 + "headimg": img, // 发送人 + "toname": this.userName, // 接收人 + "touser": this.userid, // 接收人姓名 + "content": info.content, + "time": info.type==3?5:0, + "ifaudio":info.type==3? true:false, + "fromtime": info.datetime, + "type": info.type==0?'txt':(info.type==1?'image':info.type==3?'audio':(info.type==4?'video':'product')), + "id": info.id, + "minId": info.minId, + "sendId": info.sendId, + "send": info.type==6?await this.getProduct(info.content):(info.type==5?await this.getOrder(info.content):null) + }; + msgchat.push(firstmsg); + myCache(info.id,msgchat); + } + } + }, + async updateChatList(info,ifexist){ + const {data: res} = await uni.$http.get("/api/friend/find/"+info.fromuser); + if(res.data){ + var data=res.data; + info.name=data.nickName?data.nickName:"匿名"; + info.img=data.headImage?data.headImage:require("@/static/image/girl.png"); + if(ifexist==0){ + this.grouplist.push(info); + this.$forceUpdate(); + } + // 重新排序 保存缓存 + this.reorder(); + myCache("chatlist",this.grouplist); + // 聊天框消息缓存 + var msgchat=myCache(info.id); + if(ifexist==0||!msgchat){ + // 第一条聊天记录保存缓存 + let firstmsg = [{ + "fromname": info.name, // 发送人 + "fromuser": info.fromuser, // 发送人 + "headimg": info.img, // 发送人 + "toname": this.userName, // 接收人 + "touser": this.userid, // 接收人姓名 + "content": info.content, + "time": info.type==3?5:0, + "ifaudio":info.type==3? true:false, + "fromtime": info.datetime, + "type": info.type==0?'txt':(info.type==1?'image':info.type==3?'audio':(info.type==4?'video':'product')), + "id": info.id, + "minId": info.minId, + "recvId": info.recvId, + "sendId": info.sendId, + "send": info.type==6?await this.getProduct(info.content):(info.type==5?await this.getOrder(info.content):null) + }]; + myCache(info.id,firstmsg); + } + else{ + // 聊天框信息 保存缓存 + let firstmsg = { + "fromname": info.name, // 发送人 + "fromuser": info.fromuser, // 发送人 + "headimg": info.img, // 发送人 + "toname": this.userName, // 接收人 + "touser": this.userid, // 接收人姓名 + "content": info.content, + "time": info.type==3?5:0, + "ifaudio":info.type==3? true:false, + "fromtime": info.datetime, + "type": info.type==0?'txt':(info.type==1?'image':info.type==3?'audio':(info.type==4?'video':'product')), + "id": info.id, + "minId": info.minId, + "recvId": info.recvId, + "sendId": info.sendId, + "send": info.type==6?await this.getProduct(info.content):(info.type==5?await this.getOrder(info.content):null) + }; + msgchat.push(firstmsg); + myCache(info.id,msgchat); + } + } + else{ + info.name="匿名"; + info.img="../../static/image/girl.png"; + if(ifexist==0){ + this.grouplist.push(info); + this.$forceUpdate(); + } + // 重新排序 + this.reorder(); + myCache("chatlist",this.grouplist); + var msgchat=myCache(info.id); + if(ifexist==0||!msgchat){ + // 第一条聊天记录保存缓存 + let firstmsg = [{ + "fromname": info.name, // 发送人 + "fromuser": info.fromuser, // 发送人 + "headimg": info.img, // 发送人 + "toname": this.userName, // 接收人 + "touser": this.userid, // 接收人姓名 + "content": info.content, + "time": info.type==3?5:0, + "ifaudio":info.type==3? true:false, + "fromtime": info.datetime, + "type": info.type==0?'txt':(info.type==1?'image':info.type==3?'audio':(info.type==4?'video':'product')), + "id": info.id, + "minId": info.minId, + "recvId": info.recvId, + "sendId": info.sendId, + "send": info.type==6?await this.getProduct(info.content):(info.type==5?await this.getOrder(info.content):null) + }]; + myCache(info.id,firstmsg); + } + else{ + // 聊天框信息 保存缓存 + let firstmsg = { + "fromname": info.name, // 发送人 + "fromuser": info.fromuser, // 发送人 + "headimg": info.img, // 发送人 + "toname": this.userName, // 接收人 + "touser": this.userid, // 接收人姓名 + "content": info.content, + "time": info.type==3?5:0, + "ifaudio":info.type==3? true:false, + "fromtime": info.datetime, + "type": info.type==0?'txt':(info.type==1?'image':info.type==3?'audio':(info.type==4?'video':'product')), + "id": info.id, + "minId": info.minId, + "recvId": info.recvId, + "sendId": info.sendId, + "send": info.type==6?await this.getProduct(info.content):(info.type==5?await this.getOrder(info.content):null) + }; + msgchat.push(firstmsg); + myCache(info.id,msgchat); + } } }, - // 获取群聊 - async getgroupsnums(id){ - var nums=0 - const {data: res} = await uni.$http.get("/api/message/private/pullOfflineMessage",{"minId":id}); - if(res.data&&res.data.length>0){ - nums=res.data.length; - return nums; + async getProduct(id){ + console.log("getProduct",id) + var rets=null; + const {data: res} = await uni.$http.post("/api/message/private/getProductForIm",{"productId":id}); + if(res.data){ + var data=res.data; + rets={ + type:data.isCourse==0?1:2,// 1 商品,2 课程,3订单 + id:data.id, + name:data.name, + pic:data.pic, + price:data.price, + unit: data.unit, + brandName:data.brandName, + isCourse:data.isCourse + } + console.log(rets) + return rets; } else{ - console.log("nums",nums) - return nums; + return rets; + } + }, + async getOrder(id){ + var rets=null; + const {data: res} = await uni.$http.post("/api/message/private/getOrderForIm",{"orderItemId":id}); + if(res.data){ + var data=res.data; + rets={ + type:3,// 1 商品,2 课程,3订单 + id:data.id, + orderId:data.orderId, + name:data.productName, + pic:data.pic?data.pic:'/static/image/nopic.png', + price:data.totalAmount, + quantity:data.quantity, + spData: data.spData? JSON.parse(data.spData):null + } + return rets; + } + else{ + return rets; } }, // 获取状态栏高度 @@ -263,29 +850,31 @@ width: 100%; position: relative; margin: 180rpx 0 0 0; - min-height: calc(100vh - 100rpx); + min-height: calc(100vh - 180rpx); /* #ifdef H5 */ margin: calc( 110rpx + var(--window-top)) 0 0 0; - min-height: calc(100vh - var(--window-top) - var(--window-bottom) - 100rpx); + min-height: calc(100vh - var(--window-top) - var(--window-bottom) - 180rpx); /* #endif */ overflow-y: auto; } .listcell{ background: #fff; margin: 0; + width: 100%; .lcon{ border-bottom: 1rpx solid #eee; - padding-top: 28rpx; - padding-bottom: 28rpx; + padding-top: 20rpx; + padding-bottom: 20rpx; opacity: 1; display: flex; flex-direction: row; align-items: center; + width: 100%; .limg{ - width: 120rpx; - height: 120rpx; - margin-right: 24rpx; - margin-left: 24rpx; + width: 100rpx; + height: 100rpx; + margin-right: 20rpx; + margin-left: 20rpx; display: flex; flex-direction: row; flex-wrap: wrap; @@ -293,8 +882,8 @@ justify-content: center; border-radius: 50%; .img{ - width: 120rpx; - height: 120rpx; + width: 100rpx; + height: 100rpx; } } .lright{ diff --git a/pages/message/group0.vue b/pages/message/group0.vue new file mode 100644 index 0000000..9341fd1 --- /dev/null +++ b/pages/message/group0.vue @@ -0,0 +1,505 @@ + + + + + diff --git a/pages/message/group1.vue b/pages/message/group1.vue new file mode 100644 index 0000000..c011b0a --- /dev/null +++ b/pages/message/group1.vue @@ -0,0 +1,731 @@ + + + + + diff --git a/pages/order/orderinfo.vue b/pages/order/orderinfo.vue index c4d75c6..493ac38 100644 --- a/pages/order/orderinfo.vue +++ b/pages/order/orderinfo.vue @@ -173,7 +173,7 @@ - + @@ -447,18 +447,104 @@ url: `/pages/order/orderpj?data=${id}` }); }, - gotosj(){ + // 在线客服 + async gotoSevice(){ + // 商品中获取客服信息 + var orderItemList=this.info.orderItemList?this.info.orderItemList[0]:null; + if(orderItemList) + { + const {data: res1} = await uni.$http.get('/api/product/detail/'+orderItemList.productId); + if(res1&&res1.product){ + var product=res1.product; + var customerService=product.customerService;// 客服id; + if(!customerService){ + uni.showModal({ + title: '提示', + content: '抱歉!当前订单尚未配置客服服务..', + cancelText: '取消', + confirmText: '确定', + success: ress => { + } + }); + return false; + } + var nickName="客服"; + var headImage="/static/image/kfr.png"; + uni.showLoading({ + title: '会话创建中...' + }); + const {data: res} = await uni.$http.get("/api/friend/find/"+customerService); + console.log(res) + if(res.data){ + // 客服头像和名称 + var data = res.data; + nickName=data.nickName?data.nickName:"客服"; + headImage=data.headImage?data.headImage:'/static/image/kfr.png'; + this.gotoSeviceTZ(nickName,headImage,customerService); + } + else{ + this.gotoSeviceTZ(nickName,headImage,customerService); + } + } + else{ + uni.showModal({ + title: '提示', + content: '抱歉!当前订单尚未配置客服服务..', + cancelText: '取消', + confirmText: '确定', + success: ress => { + } + }); + return false; + } + } + else{ + uni.showModal({ + title: '提示', + content: '抱歉!当前订单尚未配置客服服务..', + cancelText: '取消', + confirmText: '确定', + success: ress => { + } + }); + return false; + } + }, + gotoSeviceTZ(nickName,headImage,customerService){ // 在线客服 - uni.makePhoneCall({ - phoneNumber: "18900000001", - success:function(){ - console.log('拨打电话成功'); - }, - fail() { - console.log('打电话失败了'); + // 私聊 + // 直接跳转到聊天框 + var chatid="privatechat-" + this.userid +"-"+ customerService; + var timestamp = new Date().getTime(); + var sp=this.info.orderItemList[0]; + var info={ + chatId: chatid, + chatType: "customerService", // 客服 + chatName: nickName, + chatAvatar: headImage, + chatTime: timestamp, + userid: this.userid, + friendId: customerService, // 会话教练userid + minId: "", // 已读消息的最大id + sort:"privatechat", // privatechat 私聊 groupchat 群聊 + from:"yh", // yh 用户咨询进入聊天框,message 从消息进入聊天框 + sendinfo:{ + type:3,// 1 商品,2 课程,3订单 + id:sp.id, + orderId:sp.orderId, + name:sp.productName, + pic:sp.pic?sp.pic:'/static/image/nopic.png', + price:this.info.totalAmount, + quantity:sp.quantity, + spData: sp.spData? JSON.parse(sp.spData):null } + } + var data=encodeURIComponent(JSON.stringify(info)); + uni.navigateTo({ + url: `/pages/chat/chat?data=${data}` }); }, + async getinfo() { uni.showLoading({ title: '数据加载中...' diff --git a/pages/product/cdetail.vue b/pages/product/cdetail.vue index 41a714e..0fba6b2 100644 --- a/pages/product/cdetail.vue +++ b/pages/product/cdetail.vue @@ -452,7 +452,8 @@ img:product.pic?product.pic:'',// 详情 img1:product.pic?getRemoteFile(product.pic):'../../static/image/imgicon.png', // 规格图片 商品详情默认图片 state:product.showStatus, // 1:已上架 2:审核中 3:已下架 4:未通过 5:草稿 - customerService:product.scustomerService,// 客服id + storeId:product.storeId, + customerService:product.customerService,// 客服id pjnum:0, // 总评价数量 quantity:1, // 商品数量 ifspec: res1.skus&&res1.skus.length>0?'1':'0', @@ -609,7 +610,7 @@ spData:this.product.spData, skuId:this.product.skuId, quantity:this.product.quantity, - storeId:myCache('myshopid')?myCache('myshopid'):'', + storeId:this.product.storeId, isCourse:this.product.isCourse, }; // 加入购物车 @@ -680,11 +681,133 @@ url: `/pages/cart/cart` }); }, - gotoSevice(){ - // 在线客服 - uni.navigateTo({ - url: `/pages/product/service` + async gotoSevice(){ + if(!this.product.instructor&&!this.product.customerService){ + uni.showModal({ + title: '提示', + content: '抱歉!当前课程暂未配置客服咨询..', + cancelText: '取消', + confirmText: '确定', + success: ress => { + } + }); + return false; + } + var nickName="客服"; + var headImage="/static/image/kfr.png"; + uni.showLoading({ + title: '会话创建中...' }); + const {data: res} = await uni.$http.get("/api/friend/find/"+this.product.customerService); + if(res.data){ + // 客服头像和名称 + var data = res.data; + nickName=data.nickName?data.nickName:"客服"; + headImage=data.headImage?data.headImage:'/static/image/kfr.png'; + this.gotoSeviceTZ(nickName,headImage); + } + else{ + this.gotoSeviceTZ(nickName,headImage); + } + }, + async gotoSeviceTZ(nickName,headImage){ + // 在线客服 + if(this.product.instructor&&this.product.customerService&&this.product.instructor!=this.product.customerService) + { + // 群聊 + // 创建群聊 + var params={ + "productId": this.product.id, //商品id + "productName": this.product.name, //商品名 + "customerService": this.product.customerService, //客服(顾问)id + "instructor": this.product.instructor //教练id + } + const {data: res} = await uni.$http.post("/api/group/create",params); + console.log(res) + if(res&&res.data){ + var data=res.data; + var timestamp = new Date().getTime(); + var chatid="groupchat-" + data.id; + var info={ + chatId: chatid, + groupId: data.id, + chatName: data.name, + chatAvatar: data.headImage?data.headImage:'/static/image/kfr.png', + chatTime: timestamp, + userid: data.ownerId, + friendId: this.product.customerService, // 客服userid + teacherId: this.product.instructor, // 教练userid + minId: "", // 已读消息的最大id + sort:"groupchat", // privatechat 私聊 groupchat 群聊 + from:"yh", // yh 用户咨询进入聊天框,message 从消息进入聊天框 + notice: data.notice, + remarkNickName: data.remarkNickName, + showNickName: data.showNickName, + showGroupName: data.showGroupName, + remarkGroupName: data.remarkGroupName, + reason: data.reason, + customerService: data.customerService, + instructor: data.instructor, + productId: data.productId, + productName: data.productName, + sendinfo:{ + type:1,// 1 商品,2 课程,3订单 + id:this.product.id, + name:this.product.name, + pic:this.product.pic, + price:this.product.price, + unit: this.product.unit, + brandName:this.product.brandName, + isCourse:this.product.isCourse + } + } + var data=encodeURIComponent(JSON.stringify(info)); + uni.navigateTo({ + url: `/pages/chat/groupchat?data=${data}` + }); + } + else{ + uni.showModal({ + title: '提示', + content: res.msg? res.msg:'当前会话创建失败..', + cancelText: '取消', + confirmText: '确定', + success: ress => {} + }); + } + } + else{ + // 私聊 + // 直接跳转到聊天框 + var chatid="privatechat-" + this.userid +"-"+ this.product.customerService; + var timestamp = new Date().getTime(); + var info={ + chatId: chatid, + chatName: nickName, + chatAvatar: headImage, + chatTime: timestamp, + userid: this.userid, + friendId: this.product.customerService, // 会话教练userid + minId: "", // 已读消息的最大id + sort:"privatechat", // privatechat 私聊 groupchat 群聊 + from:"yh", // yh 用户咨询进入聊天框,message 从消息进入聊天框 + sendinfo:{ + type:2,// 1 商品,2 课程,3订单 + id:this.product.id, + name:this.product.name, + pic:this.product.pic, + price:this.product.price, + unit: this.product.unit, + brandName:this.product.brandName, + isCourse:this.product.isCourse + } + } + var data=encodeURIComponent(JSON.stringify(info)); + uni.navigateTo({ + url: `/pages/chat/chat?data=${data}` + }); + + } }, gotoCourse(){ // 课程表 diff --git a/pages/product/cxlist.vue b/pages/product/cxlist.vue index 9b77285..47c7427 100644 --- a/pages/product/cxlist.vue +++ b/pages/product/cxlist.vue @@ -96,7 +96,7 @@ searchValue:"", cartnum:getcartNum(),// 购物车数量 ifsear:false, - shopid:myCache('myshopid')?myCache('myshopid'):'', + shopid:myCache('myshopid')?myCache('myshopid'):null, shop:myCache('myshop')?myCache('myshop'):'', contentText: { contentdown: '查看更多', @@ -274,6 +274,7 @@ img:product.pic?product.pic:'',// 详情 img1:product.pic?getRemoteFile(product.pic):'../../static/image/imgicon.png', // 规格图片 商品详情默认图片 state:product.showStatus, // 1:已上架 2:审核中 3:已下架 4:未通过 5:草稿 + storeId:product.storeId, customerService:product.scustomerService,// 客服id quantity:1, // 商品数量 ifspec: res1.skus&&res1.skus.length>0?'1':'0', @@ -321,7 +322,7 @@ spData:this.product.spData, skuId:this.product.skuId, quantity:this.product.quantity, - storeId:myCache('myshopid')?myCache('myshopid'):'', + storeId:this.product.storeId, isCourse:this.product.isCourse, }; // 加入购物车 @@ -439,10 +440,11 @@ return text.replace(regex, `${keyword}`); }, input(res) { - if(!this.ifsear){ - this.ifsear=true; - this.getld(res); - } + console.log('input',res); + // if(!this.ifsear){ + // this.ifsear=true; + // this.getld(res); + // } }, async getld(keywords) { const {data: res} = await uni.$http.post('/yoga/getProductsBykeywords',{keywords:keywords}); @@ -458,18 +460,26 @@ }, focus(res){ console.log('focus',res); - this.ifshow=false; + // this.ifshow=false; this.$forceUpdate(); }, search(res) { + // 查询商品事件 + console.log('search',res); this.ifsear=false; - this.ifshow=true; + // this.ifshow=true; this.$forceUpdate(); - this.getList(); + if(res.value){ + this.loadStatus="more"; + this.goodsList=[]; + this.page.pageNum=1; + this.$forceUpdate(); + this.getList(); + } }, clear(res) { this.searchValue=""; - this.ifshow=true; + // this.ifshow=true; this.$forceUpdate(); this.getList(); }, @@ -479,7 +489,7 @@ // icon: 'none' // }) this.searchValue=""; - this.ifshow=true; + // this.ifshow=true; this.$forceUpdate(); this.getList(); }, diff --git a/pages/product/detail.vue b/pages/product/detail.vue index 87fdcc3..ff35ff7 100644 --- a/pages/product/detail.vue +++ b/pages/product/detail.vue @@ -406,7 +406,8 @@ img:product.pic?product.pic:'',// 详情 img1:product.pic?getRemoteFile(product.pic):'../../static/image/imgicon.png', // 规格图片 商品详情默认图片 state:product.showStatus, // 1:已上架 2:审核中 3:已下架 4:未通过 5:草稿 - customerService:product.scustomerService,// 客服id + storeId:product.storeId, + customerService:product.customerService,// 客服id pjnum:0, // 总评价数量 quantity:1, // 商品数量 ifspec: res1.skus&&res1.skus.length>0?'1':'0', @@ -564,7 +565,7 @@ spData:this.product.spData, skuId:this.product.skuId, quantity:this.product.quantity, - storeId:myCache('myshopid')?myCache('myshopid'):'', + storeId:this.product.storeId, isCourse:this.product.isCourse, }; // 加入购物车 @@ -638,10 +639,67 @@ url: `/pages/cart/cart` }); }, - gotoSevice(){ + async gotoSevice(){ + if(!this.product.instructor&&!this.product.customerService){ + uni.showModal({ + title: '提示', + content: '抱歉!当前课商品未配置客服咨询..', + cancelText: '取消', + confirmText: '确定', + success: ress => { + } + }); + return false; + } + + var nickName="客服"; + var headImage="/static/image/kfr.png"; + uni.showLoading({ + title: '会话创建中...' + }); + const {data: res} = await uni.$http.get("/api/friend/find/"+this.product.customerService); + if(res.data){ + // 客服头像和名称 + var data = res.data; + nickName=data.nickName?data.nickName:"客服"; + headImage=data.headImage?data.headImage:'/static/image/kfr.png'; + this.gotoSeviceTZ(nickName,headImage); + } + else{ + this.gotoSeviceTZ(nickName,headImage); + } + }, + async gotoSeviceTZ(nickName,headImage){ + console.log(this.product.instructor,this.product.customerService) // 在线客服 + // 私聊 + // 直接跳转到聊天框 + var timestamp = new Date().getTime(); + var chatid="privatechat-" + this.userid +"-"+ this.product.customerService; + var info={ + chatId: chatid, + chatName: nickName, + chatAvatar: headImage, + chatTime: timestamp, + userid: this.userid, + friendId: this.product.customerService, // 会话教练userid + minId: "", // 已读消息的最大id + sort:"privatechat", // privatechat 私聊 groupchat 群聊 + from:"yh", // yh 用户咨询进入聊天框,message 从消息进入聊天框 + sendinfo:{ + type:1,// 1 商品,2 课程,3订单 + id:this.product.id, + name:this.product.name, + pic:this.product.pic, + price:this.product.price, + unit: this.product.unit, + brandName:this.product.brandName, + isCourse:this.product.isCourse + } + } + var data=encodeURIComponent(JSON.stringify(info)); uni.navigateTo({ - url: `/pages/product/service` + url: `/pages/chat/chat?data=${data}` }); }, gotoShop(){ diff --git a/pages/product/list.vue b/pages/product/list.vue index 64af66c..0ca6010 100644 --- a/pages/product/list.vue +++ b/pages/product/list.vue @@ -24,8 +24,8 @@ - - + + 达人好物 买贵双倍赔 @@ -37,7 +37,7 @@ - + 精品课程 @@ -52,7 +52,7 @@ - + - + @@ -118,7 +118,7 @@ ifshow:true, // 显示检索商品 searchValue:"", ifsear:false, - shopid: myCache('myshopid'), + shopid: myCache('myshopid')?myCache('myshopid'):null, shop: myCache('myshop'), scrollLeft: 0, tabCurrentIndex:0, @@ -300,6 +300,7 @@ img:product.pic?product.pic:'',// 详情 img1:product.pic?getRemoteFile(product.pic):'../../static/image/imgicon.png', // 规格图片 商品详情默认图片 state:product.showStatus, // 1:已上架 2:审核中 3:已下架 4:未通过 5:草稿 + storeId:product.storeId, customerService:product.scustomerService,// 客服id quantity:1, // 商品数量 ifspec: res1.skus&&res1.skus.length>0?'1':'0', @@ -347,7 +348,7 @@ spData:this.product.spData, skuId:this.product.skuId, quantity:this.product.quantity, - storeId:myCache('myshopid')?myCache('myshopid'):'', + storeId:this.product.storeId, isCourse:this.product.isCourse, }; const {data: res1} = await uni.$http.post('/api/cart/add',param); @@ -644,6 +645,7 @@ res.content.forEach((cell,idx)=>{ var celnew={ id:cell.id, + isCourse:cell.isCourse, name:cell.name, type:cell.isCourse=='1'?'2':'1', img: cell.pic, @@ -704,6 +706,7 @@ }) }, navToList(item){ + console.log("item",item) if(item.isCourse==1){ uni.navigateTo({ url: `/pages/product/cdetail?id=${item.id}` diff --git a/pages/product/order.vue b/pages/product/order.vue index 81767d7..ddd406a 100644 --- a/pages/product/order.vue +++ b/pages/product/order.vue @@ -661,7 +661,7 @@ }); }, adrchange(e){ - console.log(e); + // console.log(e); if(e.detail.value||e.detail.value=='0'){ var data= this.myaddresslist[parseInt(e.detail.value)]; // 订单收货信息 diff --git a/pages/teacher/chat.vue b/pages/teacher/chat.vue deleted file mode 100644 index 8f1e3ea..0000000 --- a/pages/teacher/chat.vue +++ /dev/null @@ -1,1091 +0,0 @@ - - - - - diff --git a/pages/teacher/course.vue b/pages/teacher/course.vue index 8fcea59..b2ef30f 100644 --- a/pages/teacher/course.vue +++ b/pages/teacher/course.vue @@ -30,8 +30,14 @@ + + :style="{ + fontSize:(dd.fontSize?dd.fontSize+'px':'26rpx'), + color: (dd.fontColor?dd.fontColor:'#000'), + backgroundColor:( dd.claColor?dd.claColor:colorlist[index].color), + borderLeftColor: '#fef2ce' + }" > {{dd.startTime}}-{{dd.endTime}} {{dd.courseName}} {{dd.claName}} @@ -794,11 +800,12 @@ flex-direction: column; width: 100%; height: 240rpx; - justify-content: center; + justify-content:flex-start; align-items: center; border-bottom: 1rpx dotted #ccc; color:#000; font-size: 28rpx; + padding-top: 10rpx; } .courheadtext{ display: flex; @@ -808,13 +815,12 @@ justify-content: center; align-items: center; border-radius: 10rpx; - border-radius: 10rpx; - border-left-width: 10rpx; + border-left-width: 6rpx; border-left: solid; } .ctxt{ - font-size: 24rpx; line-height: 30rpx; + padding-bottom: 4rpx; margin-bottom: 6rpx; } } diff --git a/pages/teacher/detail.vue b/pages/teacher/detail.vue index aaaef7e..9076e2f 100644 --- a/pages/teacher/detail.vue +++ b/pages/teacher/detail.vue @@ -44,8 +44,8 @@ - - + + @@ -79,6 +79,7 @@ nickName:"", html:``, id:'', + appUserId:'', intro:'', teacherName:'', sex:'', @@ -164,9 +165,9 @@ }; try{ const {data: res} = await uni.$http.post('/api/context/getOne',params); - console.log(res.data); if (res&&res.success) { var data=res.data; + this.appUserId=data.appUserId; this.teacherName=data.userName; this.sex=data.sex=='1'?'女':(data.sex=='2'?'男':'未知'); this.html=getRemoteHtmlFile(data.context); @@ -178,7 +179,6 @@ ban_img:item }) }) - console.log(this.swiperList); this.$forceUpdate(); } else{ @@ -222,27 +222,29 @@ }, // 咨询 async goconsult(){ - // 获取某个会话中已读消息的最大id(已读完的最后一条) - uni.showLoading("会话创建中.."); - var params = { - friendId: this.id - }; - try{ - const {data: res} = await uni.$http.get("/api/message/private/maxReadedId",params); + // uni.showLoading({ + // title: '会话创建中...' + // }); + try{ + // 直接跳转到聊天框 + var chatid="privatechat-" + this.userid +"-"+ this.id; var timestamp = new Date().getTime(); var info={ - chatId: "teacher-" + this.userid +"-"+ this.id, - chatType: "teacher", + chatId: "privatechat-" + this.userid +"-"+ this.id, + chatType: "coach", chatName: this.teacherName, chatAvatar: this.avatar, chatTime: timestamp, - minId: res.data, // 已读消息的最大id - friendId: this.id, // 会话人id + userid: this.userid, + friendId: this.appUserId, // 会话教练userid + minId: "", // 已读消息的最大id + sort: "privatechat", // privatechat 私聊 groupchat 群聊 + from: "yh" // yh 用户咨询进入聊天框,message 从消息进入聊天框 } var data=encodeURIComponent(JSON.stringify(info)); uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` - }) + url: `/pages/chat/chat?data=${data}` + }); } catch(e){ console.log(e); @@ -255,6 +257,31 @@ }); } }, + groupListChange(chatlastinfo){ + // 消息群列表更新 + var chatlist = myCache("chatlist"); + if(chatlist&&chatlist.length>0){ + var ifexist=0; + chatlist.forEach((cell,i)=>{ + if(cell.id==chatlastinfo.id){ + ifexist++; + chatlist[i]=chatlastinfo; + } + }); + if(ifexist==0){ + // 新增的添加 + chatlist.unshift(chatlastinfo); + } + // 重新保存聊天列表记录 + myCache("chatlist",chatlist); + } + else{ + chatlist=[]; + chatlist.push(chatlastinfo); + myCache("chatlist",chatlist); + } + + }, gocourse(){ // 课程表 uni.navigateTo({ diff --git a/pages/user/cdlist.vue b/pages/user/cdlist.vue index 859caf6..aaa65c4 100644 --- a/pages/user/cdlist.vue +++ b/pages/user/cdlist.vue @@ -275,18 +275,6 @@ url: `/pages/book/bookinfo?id=${id}` }); }, - // 联系教练 - gototeacher(item){ - var data={ - id:item.id, - name:"教练A" - } - // 联系教练 - var data=encodeURIComponent(JSON.stringify(data)); - uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` - }) - }, // 去评价 gotoevaluate(info){ var data=encodeURIComponent(JSON.stringify(info)); diff --git a/pages/user/courselist.vue b/pages/user/courselist.vue index 6ca242c..51a6360 100644 --- a/pages/user/courselist.vue +++ b/pages/user/courselist.vue @@ -36,7 +36,7 @@ - {{item.courseName}} + {{item.courseName||'-'}} {{item.startTime+'-'+item.endTime}} @@ -49,9 +49,10 @@ - {{item.claName}} - {{item.claName}} - + + {{item.claName}} + @@ -126,15 +127,22 @@ + + :style="{ + fontSize:(dd.fontSize?dd.fontSize+'px':'26rpx'), + color: (dd.fontColor?dd.fontColor:'#000'), + backgroundColor: ( dd.claColor?dd.claColor:colorlist[index].color), + borderLeftColor: '#fef2ce' + }"> + {{dd.startTime}}-{{dd.endTime}} {{dd.courseName}} {{dd.claName}} {{dd.staffName}} {{dd.roomName}} - - 预约 + + 不可预约 @@ -143,7 +151,6 @@ - @@ -697,11 +704,11 @@ uni.showLoading(); this.loading=true; try{ - const {data: res1} = await uni.$http.get('/api/course/getCourseList'); - console.log(res1); + const {data: res} = await uni.$http.get('/api/course/getCourseList'); + console.log(res); this.loading=false; - if (res1.success) { - var data = res1.data; + if (res.success) { + var data = res.data; this.columnTitles=data.columnTitles?data.columnTitles:[]; this.claTimeContainer=data.claTimeContainer?data.claTimeContainer:[]; this.list=[]; @@ -715,9 +722,9 @@ week:item.weekName, slist:[] } - this.list.push(lcell) - }) - this.$forceUpdate(); + this.list.push(lcell); + this.$forceUpdate(); + }); this.getOrderList(); } else{ @@ -1229,10 +1236,10 @@ position: sticky; top: 0; z-index: 19; - height: calc(100vh - 240rpx); - /* #ifdef H5 */ - height: calc(100vh - 240rpx - var(--window-top)); - /* #endif */ + // height: calc(100vh - 240rpx); + // /* #ifdef H5 */ + // height: calc(100vh - 240rpx - var(--window-top)); + // /* #endif */ background: #f8f8f8; } ::v-deep .uni-table-tr{ @@ -1265,7 +1272,7 @@ } .courcon{ width: 100%; - height: calc(100vh); + height: calc(100vh - 100rpx); /* #ifdef H5 */ height: calc(100vh - 100rpx - var(--window-top)); /* #endif */ @@ -1342,11 +1349,12 @@ width: 100%; height: 280rpx; background-color: #F2F2F2; - justify-content: center; + justify-content: flex-start; align-items: center; border-bottom: 1rpx dotted #ccc; color:#000; font-size: 28rpx; + padding-top: 10rpx; } .courheadtext{ display: flex; @@ -1356,38 +1364,41 @@ justify-content: center; align-items: center; border-radius: 10rpx; - border-radius: 10rpx; - border-left-width: 10rpx; + border-left-width: 6rpx; border-left: solid; } .ctxt{ - font-size: 24rpx; line-height: 30rpx; + padding-bottom: 4rpx; margin-bottom: 6rpx; } .orderbtn{ - background-color: #00A99A !important; + background-color: #ddd !important; border-radius: 40rpx; height: 40rpx; line-height: 38rpx; - padding: 0 20rpx; + padding: 0 16rpx; font-size: 24rpx; - border:1rpx solid #00A99A; + border:1rpx solid #ddd; margin-top: 6rpx; + color:#000; } .orderbtn::after{ border:0 !important; } .noorderbtn{ - background-color: #c8c8c8 !important; + background-color: #eee !important; border-radius: 40rpx; height: 40rpx; line-height: 38rpx; - padding: 0 20rpx; + padding: 0 16rpx; font-size: 24rpx; - border:1rpx solid #c8c8c8; + border:1rpx solid #eee; margin-top: 6rpx; - color:#666; + color:#888; + } + .noorderbtn::after{ + border:0 !important; } } .bbtn{ diff --git a/pages/user/kslist.vue b/pages/user/kslist.vue index 89573a7..050a50f 100644 --- a/pages/user/kslist.vue +++ b/pages/user/kslist.vue @@ -283,18 +283,6 @@ this.tabCurrentIndex = current; this.loadData(); }, - // 联系教练 - gototeacher(item){ - var data={ - id:item.id, - name:"教练A" - } - // 联系教练 - var data=encodeURIComponent(JSON.stringify(data)); - uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` - }) - }, reset(){ // 重新加载数据 this.list.forEach((cell,idx)=>{ diff --git a/pages/user/mycollect.vue b/pages/user/mycollect.vue index 5c4f415..0743e34 100644 --- a/pages/user/mycollect.vue +++ b/pages/user/mycollect.vue @@ -272,6 +272,7 @@ img:product.pic?product.pic:'',// 详情 img1:product.pic?product.pic:'../../static/image/imgicon.png', // 规格图片 商品详情默认图片 state:product.showStatus, // 1:已上架 2:审核中 3:已下架 4:未通过 5:草稿 + storeId:product.storeId, customerService:product.scustomerService,// 客服id quantity:1, // 商品数量 ifspec: res1.skus&&res1.skus.length>0?'1':'0', @@ -319,7 +320,7 @@ spData:this.product.spData, skuId:this.product.skuId, quantity:this.product.quantity, - storeId:myCache('myshopid')?myCache('myshopid'):'', + storeId:this.product.storeId, isCourse:this.product.isCourse, }; const {data: res1} = await uni.$http.post('/api/cart/add',param); diff --git a/pages/user/tclist.vue b/pages/user/tclist.vue index 37761e7..79051e2 100644 --- a/pages/user/tclist.vue +++ b/pages/user/tclist.vue @@ -433,18 +433,6 @@ url: `/pages/book/bookinfo?id=${id}` }); }, - // 联系教练 - gototeacher(item){ - var data={ - id:item.id, - name:"教练A" - } - // 联系教练 - var data=encodeURIComponent(JSON.stringify(data)); - uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` - }) - }, iflogin(){ this.openId = myCache('openId'); var user = myCache('user'); diff --git a/pages/user/user.vue b/pages/user/user.vue index eaef789..0f531b9 100644 --- a/pages/user/user.vue +++ b/pages/user/user.vue @@ -87,63 +87,70 @@ {{servers[3].name}} - + {{servers[12].name}} - + {{servers[13].name}} + + + + + + {{servers[14].name}} + - + {{servers[4].name}} - + {{servers[6].name}} - + {{servers[7].name}} - + {{servers[8].name}} - + {{servers[9].name}} - + {{servers[10].name}} - + @@ -151,9 +158,9 @@ - + - {{servers[14].name}} + {{servers[15].name}} @@ -286,6 +293,11 @@ img:'../../static/image/yyjl.png', name:'预约学员',// 店长 }, + { + key:14, + img:'../../static/image/qd.png', + name:'学员签到',// 教练/顾问 + }, { key:99, img:'../../static/image/tc.png', @@ -348,15 +360,24 @@ uni.stopPullDownRefresh() },500); }, + // onTabItemTap(){ + // console.log('界面关闭socket,onTabItemTap'); + // // 在组件销毁前,确保关闭 WebSocket 连接 + // uni.closeSocket(); + // }, methods: { ifview(value){ // 描述:角色ID;顾问:103 ;教练:104 ;店长:105 ;普通用户:107; var str=false; + var arrs= value.split(','); this.roleId.forEach(item=>{ - if(item==value) - { - str=true; - } + arrs.forEach(cell=>{ + if(item==cell) + { + str=true; + return true; + } + }); }); return str; }, @@ -491,9 +512,13 @@ else if(ii==13){ // 预约学员-店长 uni.navigateTo({ - url: `/pages/book/booktshop` + url: `/pages/book/bookshop` }); } + else if(ii==14){ + // 学员签到 + this.scando(); + } else if(ii==99){ // 退出登录 uni.showModal({ @@ -580,6 +605,44 @@ }); } }, + // 学员签到扫码 + scando(){ + var _this=this; + // 允许从相机和相册扫码 + //qrCode,barCode + // #ifdef APP-PLUS + uni.scanCode({ + scanType: ['qrCode', 'barCode'], + success: function(res) { + console.log(res); + console.log('条码类型:' + res.scanType); + console.log('条码内容:' + res.result); + // 入库扫码内容确认 + var rmbm=res.result; + console.log(rmbm); + if(rmbm){ + // 预约详情 + uni.navigateTo({ + url: `/pages/book/bookinfo?id=${rmbm}&type=qd` + }); + } + else{ + uni.showModal({ + title: '提示', + content: '扫码异常,请正确扫码绑定推广员!', + cancelText: '取消', + confirmText: '确定', + success: ress => { + if (ress.confirm) { + } + } + }); + } + } + }); + // #endif + }, + async logoff(){ uni.showLoading({ title: '账号注销中...' @@ -946,7 +1009,7 @@ height: 32rpx; line-height: 32rpx; padding: 0 2rpx; - border-radius: 50% 50%; + border-radius: 32rpx; background-color: #ff0000; color: #FFF; font-size: 22rpx; diff --git a/pages/user/xslist.vue b/pages/user/xslist.vue index 6b660b3..8f89979 100644 --- a/pages/user/xslist.vue +++ b/pages/user/xslist.vue @@ -307,18 +307,6 @@ this.tabCurrentIndex = current; this.loadData(); }, - // 联系教练 - gototeacher(item){ - var data={ - id:item.id, - name:"教练A" - } - // 联系教练 - var data=encodeURIComponent(JSON.stringify(data)); - uni.navigateTo({ - url: `/pages/teacher/chat?data=${data}` - }) - }, reset(){ this.orderlists=[]; // 重新加载数据 diff --git a/static/image/girl.jpg b/static/image/girl.jpg deleted file mode 100644 index 7c25bcb23d8825276a0a701670608d436bbdfe93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13929 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 literal 0 HcmV?d00001 diff --git a/static/image/jltx.png b/static/image/jltx.png new file mode 100644 index 0000000000000000000000000000000000000000..d16d3a4c981c3a9d2a4ef3dbd34a98eb4c873fe4 GIT binary patch literal 911 zcmV;A191F_P)Px&Nl8ROR9HvVmRo2PR~W~C-^5e`l0sT4jXoqa(Fb2jpiQg=5@swcM0kMw>i535qD1l> zI@LgO&u|!s@Blquny8ybxQDX3NF5kLsYeWp_@{Q60qhGXI}r|}91gC8?h(W|gm96# zS!$~C%O?yanbgaO3?fnud<1+O7-z_bxcVKc6R5sMd)HX0{NVt4(z{VP1N@BAjqp?O z6v*4CdhTpRbPsXs?6U*(ez5}gg`2=Syjnl$W~emo2PUp`Ynhby5g+z8#$*ezy$=_H zDD8k_e-3zO|1hq$&~A>>b8ZaPm*ylE{v~c!ld)G~$W72XpqqqwZ1DgWziwn|$~$^j zfgT`Xo%EAs?OOFB;yoH6dIgZte&V;G~+6ip`)~P`3GjM#VZ}9e1X` zZac`8;BBZINLs&4yENb}I6I6!2hNM4EBgN4t4? z_Shf?0xlbilrIb`IH&>u(jS0)UpC3viQL>AzM3-S~ lbO*{HT6ztXS!AJfPXKe205DeIZ+`#)002ovPDHLkV1izGqzeE5 literal 0 HcmV?d00001 diff --git a/static/image/kf.png b/static/image/kf.png index da3239740503635f2f23ec829b193826d944d631..10078c4045ba4520a2b2078344a3f676c0791d8e 100644 GIT binary patch literal 1929 zcmV;42X^?0P)Px+LrFwIRCr$PTYZdVMG^nin=$KO21$r0CSJH;qWBesi1@+YzV2NXP~;D|g}ZPn z&Z(%2AJHhphzTDt0Z{NK4=3{4Oy{+VBHt$teRsXuGySloUaFP?99?t0aUhjSC_jZibHgOzZ5=GJOWYO`NL{}jIj4@*X<^YsJp+t1CbMAXZ6s;FevyhCU=)7vR`lCF(xd7-oA4Sm-0B425 zMC5??{{49hdhy*D^ECh;Pw0AbX=&;FycH-HfH;nCCZg*T!mG@zUeOymxaUStbS{A3 zA}USeiVyrUsn{6v0D!9!9(sdw?v^YgGXYpmZ-1P~@P59uwDg|E#l>fO()-!HV-N}x zsH2EVS0q6g9v(iWTrTUJa9&{7^R-&-{3Az>{HB?$nE)7Lz6#(I2~@9k&fV9O&a0By z=}8EZDQ_wWxm`^v6*A$OM2FMRrKIJuSLD~Ab_(IdVh+g ze_eo`lYbB2TWb#`lO-Y=bIw)M>~87-*4il%nM_Q4)_c!A1t1%QuVA9`+0dRQUT_~X zU)>S_#u$y8SFbb@k$v9#O3ypLqOh4K)G>;yDlW$ho@3_I3j+|x@irn_NW{Kz>f- ze>Ah_%|P^cA}oJ^iOK~DFW5mu_lNK5_4-8%3ky0)Hc)B^#BqEZ5q)}vlZcKw=ekne z=@`A4eYXShsRlU-FBl#kesQ^6)>^}<0pDHB+z`_GEfoM`j5gNd#0q_hnROG?e>!;g z7EoEe;AMd^YvuxDjC#P1fafV@Zb;@*0az|ZXy&&{B67C(eogYxH#BCZ6PceJ!^G}a zCc@xC-5rMShK7btotvBcYxr)B2gGr_orq>um_+0s-usvIt+Q#04^9t*&@f04Y{Qk6 z#gN??qlK8&@){AH>zw;Z9srYCZwr`y&CFRPul`^&Gu^OC0oa9!ik9bA$rz*O3ugv{ zIpMvZ%>=+&d$WjyxxZ&-)1O{uXq}yY2!hLkIQ;^y+2{XqdJ3c9Di9bCH?1e^VfQURpM48185&07lJs~1Tz4r|plNP-;m)%-BTCdmNLPS~?53|8FZAD}Y5p4-R zv=sumMuiL_vd4QL&dx2h&tf*ld<4KZIuKY0fS&<)eFsXk=^ZQ)Pb23)}YwaIJq#>_vrz1pEan9{)r){#0we}Vf`Fs~-J$@@LlK}1rc#bi1p%Co{0A0@_i)3@n0Nezi4GT%JKvskRypx$9%LHI~TdT37w?V=q@+6d-elq@vt8<=SmfDJr&T`_&r1G)m^1{U&PWr5Ca4bR!J P00000NkvXXu0mjf()O0@ literal 912 zcmV;B18@9^P)Px&N=ZaPR9HvFmRpF8Q547jYtOvQ0}oOnn)9u18frwjHVOM`!zK+elnS?C!%@)V*%VV#yk#!;Kg9|4GO^b{jI9H13+CKLmvU$>g(%k z>h10AD+Z=mfJ$aQ0bpya^feK^ilXQ#fDgu)*{V7lz$^eG0em5%CTs2aLJ$Q3n0Y1u zXUNI5D2fjE^z=OGPjPK+Ehm%7R#jaSuXl+^<3JF_0DN<|BBG7f+6#qlj7rI17NPI zCc-f6Ed$^bfNcOah{(mF06foI?A%5~U!y2`6Nce}QUE;9yH7-}ET;juEF$X)0(hRc zpNI~{8-D;8AtD8W8(EoBCzE>XcdutZe#4ivH{W|^nJfgRrdfmE+V^}jTC_Ac`JzM27u=x zG9&Gxe+>{<#WMiY)76y%@O{5YRSy$Uv$gif5Cb$jF9SFzA}uKZW_IPVj)+!TYp)M6 zz%l?gU5;66*A6>?@B5on^;{OfFo&Q8z=5m~3|A6XS67d%tgL*ds^hYfFwTSFD8no9 zTOqp)(@8f}jR?S9V~m?C4S5?;M&@U>;vN8rayns7iypWYXF#}NG+kAvx;|dUFnUNt zlL3rU)xBXDwiO&krA)niXPEgYfZe$rHt#SRta0D>Q%RMs>5N=j4PYmLIq|nf5phZW zmy|SS~8agSH`dY%MeLTbJ?(Sd3hO-<1=YAK4l(>gSDb-RkK%56HsydH| m9=g$5?5+P<6_jEy_snnoG}$ndjks0-0000d$3 diff --git a/static/image/mr.png b/static/image/mr.png new file mode 100644 index 0000000000000000000000000000000000000000..80204b24b68bcbc995b9881f079e09c1ca4f03cc GIT binary patch literal 960 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 UZYLpP82|tP07*qoM6N<$f^22H*Z=?k literal 0 HcmV?d00001 diff --git a/static/image/qltx.png b/static/image/qltx.png new file mode 100644 index 0000000000000000000000000000000000000000..96075faebfe717bbe85f48409daa3424cb7bb44a GIT binary patch literal 3019 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 N002ovPDHLkV1g#s%ZLB~ literal 0 HcmV?d00001 diff --git a/static/image/xy.png b/static/image/xy.png new file mode 100644 index 0000000000000000000000000000000000000000..19cb8f24beeecfc8e0dc287acf29459c22ef22dd GIT binary patch literal 2176 zcmV-`2!Hp9P)Px-I!Q!9RCr$PTX|5GRTTf-C(0rUs7Z+gq^K;$l7+eEh>qsgV(_r6u>q`^N~+1R zrY4#iwVKqjN#!wFj>SVuTr!BX+zm585uwDul{C=@njp)&&HX;#^MP;qmiy&n?Ed%Q z+}}Cp_ub{(bI&Evy5+101w0Z!5DU;D00{vQ=Rj>KKx+U}2^~t&)>?#==WDbyk!S** zn>_|FKLSc70fv)v_K8Mbn zg`~OlJanihVD)N$c(u(3p|A5WNHPYci_p~d1I(FYlH7;;2ry>P1EHCq@K+5&z6M2#RNz}GN0Eb+v{_PYkVZhRVFM^0l>+EC zG6Z=@PJ7IiJ+2AJF?9V>6+k}0JmQ4UHN>|P;j_A z*e5{T=S$?Oacg-Ujk6ag*eAef_}Ptu9A3QcfIe;9&C5i`zZkRT0c063t+qIRUAtjQ zzhFf4^hb<;Z`>EqNBH+|moDItsSXtlCTu->3iU0`TBrv=GN4aw7dE#a0qkJo-C7Os zkL{V`?+qP>SpVKmohvof;mxvx0ukIBfeBYV!fX#v?Fq=qS_ne8pXwIfdp{OL#K`hz zam69Le)v~eeIyA}vIr@uZ&+k+5FnoCRUIwu8Sw7V`|xI@qXdw1lixd9g15?kljN5y zA)VRZl25onfYI<8fDdE=xeyNT;fJEc=?LiNsR;H`^ED)F+l*tEx#T`Gbg*N03qSiz*B|ohzYF6H;{|0W60{=}w+n;sg5Nz=Rp- zLR?4N&h)lXiU)q&gyKsVc$x9jhY}u)TPXfJwIae znG-JMWC;+u6v^qYhy>&qDnR%qGM^3&$Cn9XW!dCN_?e=eSW|P13ziK?1@vi=1T1e) zJlNjPwY?Y~g-_xih9SCg=BUoohh8afQ=xpm_TOg0dwnDZga&HuR z0;6FOfCaq4NA?NCp7GPTz>eC!1$!@?Y&LxZhsulXAyZR%447(mw z-X`xVKtb(kvBQwc<8ZHTp4gu_9fNxKDL3SL&jp7L;Qh+O!mp|+Nf_YU(XgZ@0aWG+<*wI7&g+ON9#{j%I{LrB2=funDdMTwXLzO4L;wj7GTySjK%EGaIll0hfat7-rcS6 z%=x5!+lAjtV}~PSaI`?c;rfg6OlX%9Q;`&{dvrF~G*H_Pn=T^e2k}cB~)KrrXPE__k_hddM7B}K()peQX)lT+m>b|8JU!Gx&%Z-oDz zoiPh{dHG;i;YRDW$4Ibz`3ZqRg7dx}T?P5)5AMavx$; z`Quj_5c@+OuC%s@p@5X|*zVOBgUrcZsHEhT9d!ry@WY*6KB`8-@~U!dI3*T`mrtIF z$ev;WYJTl06xE$aQt&;9^b2UGpY&mmMCM3=1SXb<(B{G(Ye8apT@9wz6)5|9Qm+3nou|$U9x=oRkvqR3!Bsrx- zR*{rA72KpK+R@T3b;)PWI4+|8zfjWUOzKQU(jA?VP&6$qi*Q>POIuj&OhwZYili-W zNgDwc>CRC+t literal 0 HcmV?d00001 diff --git a/static/qlfont.ttf b/static/qlfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f5f00bfa1278305f4ee685c219e560f9ebce0966 GIT binary patch literal 1636 zcmd^9zfTiU9RIw#w$vhmVvwlAl_(}a+R_+e2s(&BOpF>pCZZng^#@*im+L{miG<0h z=&U1Qa4}9A69*Cp9h`A7#0dr+9CUCn_<47)3e^9=@AbX+`F_4X-@Dg?0MLvj=*Wys z+_-4mKYbSv=g3Z8n@DGeRxjVA{($=JT*Y*^U%r~8{++`u+KUB$?d@|ww`rd)S!O1=>GVvRZQ>BW(5GP>lS59%;$(cw=UC(ohRm=rfwBiiyoz#u0S+Uwy zhhEVB9?*)eQ}Z{zZEVpsLwgqNU0>Q+!gPcxz*+8Qw`c)F_Q}uoo?ER$KhPZdZgsCY z(y_iqAl9kIp-Gk^Gif-%bCDw11Rr2WsuXEYAcG6gE{$H9#39@Ct2i#32t?Xt2JL?N6F{ym7l9f??T)A8F5p)GUY>lV2vcvs{Gxcx>5VHUOT@D5Z za8eyZa8~l9sE2Ps-t*w?>Ak#ZaUAAdfyj0ojdgXO9Y{6+(b8!c>10wQjwO?+UF*8k z_Wr`6N3f}C0quY4${W_McnwXw(P2M2`7VVc#61c}`85dsSS}$Rvb^JD+^e$o!HY2?T z>;C8|dV8qRPv$hx&(C9~A!>|X)xdLqH#N+&T9!Tf?8xBon5jZEs`|6oiA`+q1xnj2 u^W^BALMe!HF^Dvu`hM#EsbHU#@JlG~oBS63OEjSg-Yp(m*{zjp(&abmtka|b literal 0 HcmV?d00001