fix: 聊天(已实现发送文本消息,接收未实现)

This commit is contained in:
2025-07-19 16:04:43 +08:00
parent 1d0c89ac16
commit 86d7f5b21c
16 changed files with 2349 additions and 348 deletions

10
App.vue
View File

@@ -2,6 +2,7 @@
import { import {
getVersion getVersion
} from './request/api/api' } from './request/api/api'
import { webSocketManager } from '@/utils/ws/websocket.js';
export default { export default {
// //初始化状态-如果登录过,保持登录状态 // //初始化状态-如果登录过,保持登录状态
onLaunch: async function() { onLaunch: async function() {
@@ -81,6 +82,8 @@
content: '当前微信版本过低,可能无法使用该功能,请升级到最新版本后重试。' content: '当前微信版本过低,可能无法使用该功能,请升级到最新版本后重试。'
}) })
} }
this.initWebSocket();
}, },
onShow: function(e) { onShow: function(e) {
@@ -110,7 +113,12 @@
}, },
onUnload:function() { onUnload:function() {
// uni.removeStorageSync('token') // uni.removeStorageSync('token')
} },
methods: {
initWebSocket() {
webSocketManager.connect();
}
}
} }
</script> </script>

View File

@@ -77,7 +77,17 @@
"optimization" : { "optimization" : {
"subPackages" : true "subPackages" : true
}, },
"permission" : {} "permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于获取附近服务"
},
"scope.record": {
"desc": "需要录音功能发送语音消息"
},
"scope.camera": {
"desc": "需要摄像头拍照和视频通话"
}
}
}, },
"mp-alipay" : { "mp-alipay" : {
"usingComponents" : true "usingComponents" : true
@@ -91,5 +101,6 @@
"uniStatistics" : { "uniStatistics" : {
"enable" : false "enable" : false
}, },
"vueVersion" : "2" "vueVersion" : "2",
"sassImplementationName": "node-sass"
} }

288
package-lock.json generated
View File

@@ -5,19 +5,305 @@
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"@vue/composition-api": "^1.4.1",
"js-base64": "^3.7.7", "js-base64": "^3.7.7",
"uview-ui": "^1.8.8" "pinia": "^2.0.14",
"uview-ui": "^1.8.8",
"vue-demi": "^0.14.5",
"vuex": "^3.6.2"
} }
}, },
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
"integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
"integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/types": "^7.28.0"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/types": {
"version": "7.28.1",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz",
"integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "2.7.16",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
"integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==",
"peer": true,
"dependencies": {
"@babel/parser": "^7.23.5",
"postcss": "^8.4.14",
"source-map": "^0.6.1"
},
"optionalDependencies": {
"prettier": "^1.18.2 || ^2.0.0"
}
},
"node_modules/@vue/composition-api": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@vue/composition-api/-/composition-api-1.4.1.tgz",
"integrity": "sha512-ZTat9ru/rwecveRnFzlO2mduOBpGfnBdXn+WtBcFLV9UsL/D+6nX47RWuLiVdNxNDX0qphGZRC+JDjwt+YTnRA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.3.1"
},
"peerDependencies": {
"vue": ">= 2.5 < 3"
}
},
"node_modules/@vue/devtools-api": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"license": "MIT",
"peer": true
},
"node_modules/js-base64": { "node_modules/js-base64": {
"version": "3.7.7", "version": "3.7.7",
"resolved": "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.7.tgz", "resolved": "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.7.tgz",
"integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==" "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="
}, },
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"peer": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"license": "ISC",
"peer": true
},
"node_modules/pinia": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz",
"integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^6.6.3",
"vue-demi": "^0.14.10"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"typescript": ">=4.4.4",
"vue": "^2.7.0 || ^3.5.11"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/pinia/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"license": "MIT",
"optional": true,
"peer": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"license": "BSD-3-Clause",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"license": "BSD-3-Clause",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/uview-ui": { "node_modules/uview-ui": {
"version": "1.8.8", "version": "1.8.8",
"resolved": "https://registry.npmmirror.com/uview-ui/-/uview-ui-1.8.8.tgz", "resolved": "https://registry.npmmirror.com/uview-ui/-/uview-ui-1.8.8.tgz",
"integrity": "sha512-Osal3yzXiHor0In9OPTZuXTaqTbDglMZ9RGK/MPYDoQQs+y0hrBCUD0Xp5T70C8i2lLu2X6Z11zJhmsQWMR7Jg==" "integrity": "sha512-Osal3yzXiHor0In9OPTZuXTaqTbDglMZ9RGK/MPYDoQQs+y0hrBCUD0Xp5T70C8i2lLu2X6Z11zJhmsQWMR7Jg=="
},
"node_modules/vue": {
"version": "2.7.16",
"resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz",
"integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
"deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-sfc": "2.7.16",
"csstype": "^3.1.0"
}
},
"node_modules/vue-demi": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/vuex": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
"integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==",
"license": "MIT",
"peerDependencies": {
"vue": "^2.0.0"
}
} }
} }
} }

View File

@@ -1,6 +1,10 @@
{ {
"dependencies": { "dependencies": {
"@vue/composition-api": "^1.4.1",
"js-base64": "^3.7.7", "js-base64": "^3.7.7",
"uview-ui": "^1.8.8" "pinia": "^2.0.14",
"uview-ui": "^1.8.8",
"vue-demi": "^0.14.5",
"vuex": "^3.6.2"
} }
} }

View File

@@ -5,7 +5,8 @@
// npm安装方式 // npm安装方式
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue" "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
}, },
"pages": [ //pages数组中第一项表示应用启动页参考https://uniapp.dcloud.io/collocation/pages "pages": [
//pages数组中第一项表示应用启动页参考https://uniapp.dcloud.io/collocation/pages
{ {
"path": "pages/home/index", "path": "pages/home/index",
"style": { "style": {
@@ -110,9 +111,11 @@
// "needLogin": true // "needLogin": true
} }
], ],
"subPackages": [{ "subPackages": [
{
"root": "subPackages", "root": "subPackages",
"pages": [{ "pages": [
{
"path": "doctor/doctor-detail", "path": "doctor/doctor-detail",
"style": { "style": {
"navigationBarTitleText": "医生详情", "navigationBarTitleText": "医生详情",
@@ -162,9 +165,11 @@
} }
} }
] ]
}, { },
{
"root": "subPackages", "root": "subPackages",
"pages": [{ "pages": [
{
"path": "my/myinfo-add", "path": "my/myinfo-add",
"style": { "style": {
"navigationBarTitleText": "添加就诊人", "navigationBarTitleText": "添加就诊人",
@@ -191,7 +196,8 @@
"navigationBarTitleText": "订单详情", "navigationBarTitleText": "订单详情",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
}, { },
{
"path": "my/myreport", "path": "my/myreport",
"style": { "style": {
"navigationBarTitleText": "检查报告", "navigationBarTitleText": "检查报告",
@@ -211,7 +217,8 @@
"navigationBarTitleText": "线上复诊", "navigationBarTitleText": "线上复诊",
"enablePullDownRefresh": false "enablePullDownRefresh": false
} }
}, { },
{
"path": "my/mystore", "path": "my/mystore",
"style": { "style": {
"navigationStyle": "default", "navigationStyle": "default",
@@ -219,7 +226,8 @@
"navigationBarBackgroundColor": "#1777FF", "navigationBarBackgroundColor": "#1777FF",
"navigationBarTextStyle": "white" "navigationBarTextStyle": "white"
} }
}, { },
{
"path": "my/mycollection", "path": "my/mycollection",
"style": { "style": {
"navigationBarTitleText": "个人资料", "navigationBarTitleText": "个人资料",
@@ -246,7 +254,8 @@
"navigationBarTitleText": "处方记录", "navigationBarTitleText": "处方记录",
"enablePullDownRefresh": true "enablePullDownRefresh": true
} }
}, { },
{
"path": "my/myappiont", "path": "my/myappiont",
"style": { "style": {
"navigationBarTitleText": "挂号记录", "navigationBarTitleText": "挂号记录",
@@ -283,34 +292,42 @@
} }
} }
] ]
}, { },
{
"root": "subPackages", "root": "subPackages",
"pages": [{ "pages": [
"path": "register/register", {
"style": { "path": "register/register",
"navigationBarTitleText": "确认挂号信息" "style": {
"navigationBarTitleText": "确认挂号信息"
}
},
{
"path": "register/register-success",
"style": {
"navigationBarTitleText": "确认挂号信息"
}
},
{
"path": "register/register-info",
"style": {
"navigationBarTitleText": "挂号详情",
"navigationStyle": "custom"
}
} }
}, { ]
"path": "register/register-success", },
"style": { {
"navigationBarTitleText": "确认挂号信息"
}
}, {
"path": "register/register-info",
"style": {
"navigationBarTitleText": "挂号详情",
"navigationStyle": "custom"
}
}]
}, {
"root": "subPackages", "root": "subPackages",
"pages": [{ "pages": [
{
"path": "shop/orders", "path": "shop/orders",
"style": { "style": {
"navigationBarTitleText": "商城订单", "navigationBarTitleText": "商城订单",
"enablePullDownRefresh": true "enablePullDownRefresh": true
} }
}, { },
{
"path": "shop/search-home", "path": "shop/search-home",
"style": { "style": {
"navigationBarTitleText": "萧康诊所门店" "navigationBarTitleText": "萧康诊所门店"
@@ -374,7 +391,8 @@
}, },
{ {
"root": "subPackages", "root": "subPackages",
"pages": [{ "pages": [
{
"path": "setup/filed", "path": "setup/filed",
"style": { "style": {
"navigationBarTitleText": "设置" "navigationBarTitleText": "设置"
@@ -415,6 +433,13 @@
"style": { "style": {
"navigationBarTitleText": "客服中心" "navigationBarTitleText": "客服中心"
} }
},
{
"path": "chat/chat",
"style": {
"navigationBarTitleText": "在线问诊",
"enablePullDownRefresh": false
}
} }
] ]
} }
@@ -425,7 +450,8 @@
"spacing": "4px", "spacing": "4px",
"backgroundColor": "#fff", "backgroundColor": "#fff",
"selectedColor": "#1575FC", "selectedColor": "#1575FC",
"list": [{ "list": [
{
"pagePath": "pages/home/home", "pagePath": "pages/home/home",
"text": "首页", "text": "首页",
"iconPath": "static/home/02.png", "iconPath": "static/home/02.png",
@@ -449,7 +475,8 @@
"iconPath": "static/home/07.png", "iconPath": "static/home/07.png",
"selectedIconPath": "static/home/08.png" "selectedIconPath": "static/home/08.png"
} }
] ],
"color": ""
}, },
"globalStyle": { "globalStyle": {
"navigationBarTextStyle": "black", "navigationBarTextStyle": "black",

View File

@@ -1,310 +1,405 @@
<template> <template>
<view class="content safe-area-inset-bottom"> <view class="content safe-area-inset-bottom">
<!-- 标题 --> <!-- 标题 -->
<view class="title"> <view class="title">
<text>全部消息</text> <text>全部消息</text>
<view class="clear" @click="getClearInfo"> <view class="clear" @click="getClearInfo">
<text class="iconfont icon-qingchu"></text> <text class="iconfont icon-qingchu"></text>
清除未读 清除未读
</view> </view>
</view> </view>
<!-- 消息列表 --> <!-- 消息列表 -->
<view class="list" @click="goSystem"> <view class="list" @click="goSystem">
<!-- 头像 --> <!-- 头像 -->
<view class="avator"> <view class="avator">
<view class="img"> <view class="img">
<image src="/static/xx/xt.png" mode=""></image> <image src="/static/xx/xt.png" mode=""></image>
</view> </view>
<u-badge size="default" v-if="system.num>=0" :count="system.num" :is-dot="system.num==0?true:false" <u-badge size="default" v-if="system.num>=0" :count="system.num" :is-dot="system.num==0?true:false"
type="error" :offset="system.num>0?[-4,-8]:[0,0]"></u-badge> type="error" :offset="system.num>0?[-4,-8]:[0,0]"></u-badge>
</view> </view>
<!-- 描述 --> <!-- 描述 -->
<view class="info"> <view class="info">
<view class="infos_title"> <view class="infos_title">
<text class="infos">系统消息</text> <text class="infos">系统消息</text>
<text class="time">{{system.time}}</text> <text class="time">{{system.time}}</text>
</view> </view>
<view class="preview" v-if="system.num >0"> <view class="preview" v-if="system.num >0">
您有{{system.num}}条未读信息 您有{{system.num}}条未读信息
</view> </view>
<view class="preview" v-if="system.num==undefined"> <view class="preview" v-if="system.num==undefined">
暂无新消息 暂无新消息
</view> </view>
</view> </view>
</view> </view>
<view class="list" @click="goOrder"> <view class="list" @click="goOrder">
<!-- 头像 --> <!-- 头像 -->
<view class="avator"> <view class="avator">
<view class="img"> <view class="img">
<image src="/static/xx/cp.png" mode=""></image> <image src="/static/xx/cp.png" mode=""></image>
</view> </view>
<u-badge size="default" v-if="order.num>=0" :count="order.num" :is-dot="order.num==0?true:false" <u-badge size="default" v-if="order.num>=0" :count="order.num" :is-dot="order.num==0?true:false"
type="error" :offset="order.num>0?[-4,-8]:[0,0]"></u-badge> type="error" :offset="order.num>0?[-4,-8]:[0,0]"></u-badge>
</view> </view>
<!-- 描述 --> <!-- 描述 -->
<view class="info"> <view class="info">
<view class="infos_title"> <view class="infos_title">
<text class="infos">产品订单</text> <text class="infos">产品订单</text>
<text class="time">{{order.time}}</text> <text class="time">{{order.time}}</text>
</view> </view>
<view class="preview" v-if="order.num>0"> <view class="preview" v-if="order.num>0">
您有{{order.num}}条未读信息 您有{{order.num}}条未读信息
</view> </view>
<view class="preview" v-if="order.num==undefined"> <view class="preview" v-if="order.num==undefined">
暂无新消息 暂无新消息
</view> </view>
</view> </view>
</view> </view>
<view class="list" @click="goDoctor"> <view class="list" @click="goDoctor">
<!-- 头像 --> <!-- 头像 -->
<view class="avator"> <view class="avator">
<view class="img"> <view class="img">
<image src="/static/xx/ysxx.png" mode=""></image> <image src="/static/xx/ysxx.png" mode=""></image>
</view> </view>
<u-badge size="default" v-if="doctor.num>=0" :count="doctor.num" :is-dot="doctor.num==0?true:false" <u-badge size="default" v-if="doctor.num>=0" :count="doctor.num" :is-dot="doctor.num==0?true:false"
type="error" :offset="doctor.num>0?[-4,-8]:[0,0]"></u-badge> type="error" :offset="doctor.num>0?[-4,-8]:[0,0]"></u-badge>
</view> </view>
<!-- 描述 --> <!-- 描述 -->
<view class="info"> <view class="info">
<view class="infos_title"> <view class="infos_title">
<text class="infos">医生消息</text> <text class="infos">医生消息</text>
<text class="time">{{doctor.time}}</text> <text class="time">{{doctor.time}}</text>
</view> </view>
<view class="preview" v-if="doctor.num>0"> <view class="preview" v-if="doctor.num>0">
您有{{doctor.num}}条新的消息 您有{{doctor.num}}条新的消息
</view> </view>
<view class="preview" v-if="doctor.num==undefined"> <view class="preview" v-if="doctor.num==undefined">
暂无新消息 暂无新消息
</view> </view>
</view> </view>
</view> </view>
</view>
<!-- 在线问诊-->
<view class="list" @click="goChat">
<!-- 头像 -->
<view class="avator">
<view class="img">
<image src="/static/xx/ysxx.png" mode=""></image>
</view>
<u-badge size="default" v-if="doctor.num>=0" :count="doctor.num" :is-dot="doctor.num==0?true:false"
type="error" :offset="doctor.num>0?[-4,-8]:[0,0]"></u-badge>
</view>
<!-- 描述 -->
<view class="info">
<view class="infos_title">
<text class="infos">在线问诊</text>
<text class="time">{{doctor.time}}</text>
</view>
<view class="preview" v-if="doctor.num>0">
您有{{doctor.num}}条新的消息
</view>
<view class="preview" v-if="doctor.num==undefined">
暂无新消息
</view>
</view>
</view>
<!-- 模拟<u-divider>在线问诊</u-divider>效果-->
<!-- 标题 -->
<view class="title">
<text>在线问诊</text>
<!-- <view class="clear" @click="getClearInfo">-->
<!-- <text class="iconfont icon-qingchu"></text>-->
<!-- 清除未读-->
<!-- </view>-->
</view>
<!-- 在线问诊 - 用户-->
<view v-for="item in imChat" :key="item.id" class="list" @click="goChat(item)">
<!-- 头像 -->
<view class="avator">
<view class="img">
<image :src="item.avatar" mode=""></image>
</view>
<u-badge size="default" v-if="item.un_read_num>=0" :count="item.un_read_num" :is-dot="item.un_read_num==0?true:false"
type="error" :offset="item.un_read_num>0?[-4,-8]:[0,0]"></u-badge>
</view>
<!-- 描述 -->
<view class="info">
<view class="infos_title">
<text class="infos">{{ item.nick_name }}</text>
<text class="time">{{item.last_message_time}}</text>
</view>
<view class="preview" v-if="item.un_read_num>0">
<p>{{ item.last_message }}</p>
<p>您有{{item.un_read_num}}条新的消息</p>
</view>
<view class="preview" v-if="item.un_read_num==undefined">
暂无新消息
</view>
</view>
</view>
</view>
</template> </template>
<script> <script>
import { import {
getseesionInfo, getseesionInfo,
getseesionRead getseesionRead
} from '../../request/api/api' } from '../../request/api/api'
export default { export default {
data() { data() {
return { return {
order: [], order: [],
system: [], system: [],
doctor:[], doctor:[],
type: "" imChat:[
} {
}, id: 'doctor-1',
onLoad() { room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
nick_name: '李二狗',
avatar: 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk_upload_20250108/29bdb9560340373bb3096394a845afa5.jpg',
un_read_num: 0,
last_message: '[图片]',
last_message_time: '2021-07-05 09:05:05'
},
{
id: 'doctor-2',
room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1',
nick_name: '王三三',
avatar: '/static/xx/ysxx.png',
un_read_num: 0,
last_message: '[图片]',
last_message_time: '2021-07-05 09:05:05'
}
],
type: ""
}
},
onLoad() {
}, },
methods: { methods: {
// 清除未读信息 // 清除未读信息
getClearInfo() { getClearInfo() {
getseesionRead({ getseesionRead({
method: "post", method: "post",
data: { data: {
store_id: uni.getStorageSync('store_id') || 11001, store_id: uni.getStorageSync('store_id') || 11001,
type: "all" type: "all"
} }
}).then((res) => { }).then((res) => {
// console.log(res, 'res'); // console.log(res, 'res');
uni.showToast({ uni.showToast({
title: '清除成功', title: '清除成功',
duration: 2000, duration: 2000,
icon: "success" icon: "success"
}); });
this.getInfo() this.getInfo()
}) })
}, },
// 系统信息 // 系统信息
goSystem() { goSystem() {
uni.navigateTo({ uni.navigateTo({
url: '/pages/index/system' url: '/pages/index/system'
}) })
getseesionRead({ getseesionRead({
method: "post", method: "post",
data: { data: {
store_id: uni.getStorageSync('store_id') || 11001, store_id: uni.getStorageSync('store_id') || 11001,
type: "system" type: "system"
} }
}).then((res) => { }).then((res) => {
// console.log(res, 'res'); // console.log(res, 'res');
}) })
}, },
// 详情 // 详情
goOrder() { goOrder() {
uni.navigateTo({ uni.navigateTo({
url: '/pages/index/order-info' url: '/pages/index/order-info'
}) })
getseesionRead({ getseesionRead({
method: "post", method: "post",
data: { data: {
store_id: uni.getStorageSync('store_id') || 11001, store_id: uni.getStorageSync('store_id') || 11001,
type: "order" type: "order"
} }
}).then((res) => { }).then((res) => {
// console.log(res, 'res'); // console.log(res, 'res');
}) })
}, },
goDoctor() { goDoctor() {
uni.navigateTo({ uni.navigateTo({
url: '/pages/index/doctor-info' url: '/pages/index/doctor-info'
}) })
getseesionRead({ getseesionRead({
method: "post", method: "post",
data: { data: {
store_id: uni.getStorageSync('store_id') || 11001, store_id: uni.getStorageSync('store_id') || 11001,
type: "doctor_news" type: "doctor_news"
} }
}).then((res) => { }).then((res) => {
// console.log(res, 'res'); // console.log(res, 'res');
}) })
}, },
// goChat(item) {
getInfo() { uni.navigateTo({
getseesionInfo({ url: `/subPackages/chat/chat?room_id=${item.room_id}&nick_name=${item.nick_name}&user_id=${item.id}&avatar=${item.avatar}`
method: "get", })
data: { // getseesionRead({
store_id: uni.getStorageSync('store_id') || 11001, // method: "post",
} // data: {
}).then((res) => { // store_id: uni.getStorageSync('store_id') || 11001,
// console.log(res, 'info'); // type: "doctor_news"
this.order = res.data.data.order // }
this.system = res.data.data.system // }).then((res) => {
this.doctor=res.data.data.doctor_news // // console.log(res, 'res');
}) // })
} },
}, //
mounted() { getInfo() {
this.getInfo() getseesionInfo({
}, method: "get",
onShow() { data: {
this.order = [] store_id: uni.getStorageSync('store_id') || 11001,
this.system = [] }
this.doctor=[] }).then((res) => {
this.getInfo() // console.log(res, 'info');
} this.order = res.data.data.order
} this.system = res.data.data.system
this.doctor=res.data.data.doctor_news
})
}
},
mounted() {
this.getInfo()
},
onShow() {
this.order = []
this.system = []
this.doctor=[]
this.getInfo()
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.content { .content {
width: 750rpx; width: 750rpx;
max-height: 100%; max-height: 100%;
min-height: 100vh; min-height: 100vh;
padding-bottom: env(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom);
background: #F5F5F5; background: #F5F5F5;
.title { .title {
padding: 32rpx; padding: 32rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
text { text {
height: 50rpx; height: 50rpx;
font-size: 36rpx; font-size: 36rpx;
font-family: PingFang SC-Medium, PingFang SC; font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500; font-weight: 500;
color: #0F172A; color: #0F172A;
} }
.clear { .clear {
height: 40rpx; height: 40rpx;
font-size: 28rpx; font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC; font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400; font-weight: 400;
color: #536DFE; color: #536DFE;
line-height: 33rpx; line-height: 33rpx;
.iconfont { .iconfont {
color: #536DFE; color: #536DFE;
margin-right: 8rpx; margin-right: 8rpx;
vertical-align: text-top; vertical-align: text-top;
} }
} }
} }
.list { .list {
width: 750rpx; width: 750rpx;
display: flex; display: flex;
padding: 32rpx 38rpx; padding: 32rpx 38rpx;
justify-content: space-between; justify-content: space-between;
background: #fff; background: #fff;
.avator { .avator {
position: relative; position: relative;
.img { .img {
width: 84rpx; width: 84rpx;
height: 84rpx; height: 84rpx;
line-height: 84rpx; line-height: 84rpx;
text-align: center; text-align: center;
border-radius: 50%; border-radius: 50%;
background: #E6EAFF; background: #E6EAFF;
image { image {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
} }
.info { .info {
width: 570rpx; width: 570rpx;
height: 94rpx; height: 94rpx;
font-family: PingFang SC-Medium, PingFang SC; font-family: PingFang SC-Medium, PingFang SC;
.infos_title { .infos_title {
width: 570rpx; width: 570rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin-bottom: 8rpx; margin-bottom: 8rpx;
.doctor { .doctor {
.name { .name {
height: 42rpx; height: 42rpx;
font-size: 32rpx; font-size: 32rpx;
font-weight: 500; font-weight: 500;
color: #1E293B; color: #1E293B;
} }
.infos { .infos {
height: 42rpx; height: 42rpx;
font-size: 28rpx; font-size: 28rpx;
font-weight: 500; font-weight: 500;
color: #475569; color: #475569;
} }
} }
.time { .time {
font-size: 24rpx; font-size: 24rpx;
font-weight: 400; font-weight: 400;
color: #94A3B8; color: #94A3B8;
} }
} }
.preview { .preview {
width: 570rpx; width: 570rpx;
font-size: 28rpx; font-size: 28rpx;
font-family: PingFang SC-Regular, PingFang SC; font-family: PingFang SC-Regular, PingFang SC;
font-weight: 400; font-weight: 400;
color: #475569; color: #475569;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 1; -webkit-line-clamp: 1;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
} }
} }
} }
} }
</style> </style>

View File

@@ -3,4 +3,15 @@ import http from './request'
// export async function sendMsg(params) { // export async function sendMsg(params) {
// let data = await http('/v1/im/message-send', params) // let data = await http('/v1/im/message-send', params)
// return data // return data
// } // }
// 登录 手机号授权
export async function sendToUserApi(params) {
return await http('/imApi/send-to-user', {
method: 'POST',
data: params,
// 传输方式是json
headers: {
'Content-Type': 'application/json'
}
}, 1)
}

View File

@@ -18,14 +18,18 @@ const sensitiveData = [
'idcard' 'idcard'
] ]
function request(url, params) { function request(url, params, method = 0) {
let baseURL = "https://app.xiaokang88.com/member" // let baseURL = "https://app.xiaokang88.com/member"
// let baseURL = "http://www.xk888.com/member" let baseURL = "http://127.0.0.1:18000/member"
if (url.split('/').indexOf('imApi') !== -1) {
baseURL = "http://127.0.0.1:12080/api"
}
if (url.split('/').indexOf('newApi') !== -1) { if (url.split('/').indexOf('newApi') !== -1) {
baseURL = "https://shop.xiaokang88.com/member" baseURL = "https://shop.xiaokang88.com/member"
} }
url = url.replace('/oldApi', ''); url = url.replace('/oldApi', '');
url = url.replace('/newApi', ''); url = url.replace('/newApi', '');
url = url.replace('/imApi', '');
// 加密 // 加密
if (params != null) { if (params != null) {
@@ -44,7 +48,7 @@ function request(url, params) {
// 请求头 // 请求头
header: { header: {
"authorization": 'Bearer ' + uni.getStorageSync("token"), "authorization": 'Bearer ' + uni.getStorageSync("token"),
"Content-Type": "application/x-www-form-urlencoded" "Content-Type": method === 0? "application/x-www-form-urlencoded": 'application/json'
}, },
// 成功钩子 // 成功钩子

81
store/chat/chat.js Normal file
View File

@@ -0,0 +1,81 @@
// chat.js
// 聊天消息管理器
const ChatManager = {
// 当前房间ID
currentRoomId: null,
// 存储未读消息数 { roomId: count }
unreadCounts: {},
// 进入聊天室
enterRoom(roomId) {
this.currentRoomId = roomId;
uni.setStorageSync('currentRoomId', roomId);
console.log(`进入房间: ${roomId}`);
},
// 离开聊天室
leaveRoom() {
this.currentRoomId = null;
uni.removeStorageSync('currentRoomId');
console.log('离开当前房间');
},
// 获取当前房间ID
getCurrentRoomId() {
return this.currentRoomId || uni.getStorageSync('currentRoomId');
},
// 增加未读消息数
increaseUnreadCount(roomId) {
// 如果当前不在该房间,才增加未读计数
if (this.getCurrentRoomId() !== roomId) {
this.unreadCounts[roomId] = (this.unreadCounts[roomId] || 0) + 1;
this.notifyUnreadChange();
console.log(`房间 ${roomId} 未读消息 +1, 当前: ${this.unreadCounts[roomId]}`);
}
},
// 重置未读消息数
resetUnreadCount(roomId) {
if (this.unreadCounts[roomId]) {
this.unreadCounts[roomId] = 0;
this.notifyUnreadChange();
console.log(`重置房间 ${roomId} 未读消息数`);
}
},
// 获取未读消息数
getUnreadCount(roomId) {
return this.unreadCounts[roomId] || 0;
},
// 获取所有未读消息数
getAllUnreadCount() {
return Object.values(this.unreadCounts).reduce((sum, count) => sum + count, 0);
},
// 通知未读消息变化
notifyUnreadChange() {
uni.$emit('unread-message-update', {
total: this.getAllUnreadCount(),
byRoom: {...this.unreadCounts}
});
},
// 处理收到的消息
handleIncomingMessage(message) {
const currentRoomId = this.getCurrentRoomId();
// 如果当前在消息所属的房间,直接显示
if (currentRoomId === message.room_id) {
// 通知聊天页面显示消息
uni.$emit('new-message', message);
} else {
// 不在当前房间,增加未读消息数
this.increaseUnreadCount(message.room_id);
}
}
};
export { ChatManager };

View File

@@ -37,7 +37,7 @@
// state, // state,
// dispatch // dispatch
// }, res) { // }, res) {
// console.log('user-123'); // console.log('user-252');
// // 存到状态中 // // 存到状态中
// state.user = res // state.user = res
// state.user_token = uni.getStorageSync('token'); // state.user_token = uni.getStorageSync('token');

1293
subPackages/chat/chat.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -102,7 +102,7 @@
registerList, registerList,
storeChange, storeChange,
userList userList
} from '../../request/api/api' } from '@/request/api/api'
export default { export default {
data() { data() {
return { return {

View File

@@ -519,7 +519,7 @@
color: #1E293B; color: #1E293B;
} }
/deep/ .u-input { ::v-deep .u-input {
width: 380rpx; width: 380rpx;
} }
} }
@@ -573,7 +573,7 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
/deep/ .u-tag { ::v-deep .u-tag {
margin: 10rpx 20rpx 10rpx 0; margin: 10rpx 20rpx 10rpx 0;
} }
@@ -615,11 +615,11 @@
margin-top: 2rpx; margin-top: 2rpx;
} }
/deep/ .u-input { ::v-deep .u-input {
margin-left: 130rpx; margin-left: 130rpx;
} }
/deep/ .u-input__right-icon ::before { ::v-deep .u-input__right-icon ::before {
content: "" content: ""
} }
@@ -671,7 +671,7 @@
.u_inp { .u_inp {
margin: 40rpx 0; margin: 40rpx 0;
/deep/ .u-input { ::v-deep .u-input {
background: #F1F5F9; background: #F1F5F9;
} }
} }

View File

@@ -634,7 +634,7 @@
color: #1E293B; color: #1E293B;
} }
/deep/ .u-input { ::v-deep .u-input {
width: 400rpx; width: 400rpx;
} }
} }
@@ -657,7 +657,7 @@
color: #1E293B; color: #1E293B;
} }
/deep/ .u-input { ::v-deep .u-input {
width: 380rpx; width: 380rpx;
} }
} }
@@ -740,11 +740,11 @@
margin-top: 2rpx; margin-top: 2rpx;
} }
/deep/ .u-input { ::v-deep .u-input {
margin-left: 130rpx; margin-left: 130rpx;
} }
/deep/ .u-input__right-icon ::before { ::v-deep .u-input__right-icon ::before {
content: "" content: ""
} }
@@ -830,7 +830,7 @@
color: #1E293B; color: #1E293B;
} }
/deep/ .u-input { ::v-deep .u-input {
width: 380rpx; width: 380rpx;
} }
} }
@@ -884,7 +884,7 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
/deep/ .u-tag { ::v-deep .u-tag {
margin: 10rpx 20rpx 10rpx 0; margin: 10rpx 20rpx 10rpx 0;
} }
@@ -926,11 +926,11 @@
margin-top: 2rpx; margin-top: 2rpx;
} }
/deep/ .u-input { ::v-deep .u-input {
margin-left: 130rpx; margin-left: 130rpx;
} }
/deep/ .u-input__right-icon ::before { ::v-deep .u-input__right-icon ::before {
content: "" content: ""
} }
@@ -982,7 +982,7 @@
.u_inp { .u_inp {
margin: 40rpx 0; margin: 40rpx 0;
/deep/ .u-input { ::v-deep .u-input {
background: #F1F5F9; background: #F1F5F9;
} }
} }

View File

@@ -723,7 +723,7 @@
color: #1E293B; color: #1E293B;
} }
/deep/ .u-input { ::v-deep .u-input {
width: 380rpx; width: 380rpx;
} }
} }
@@ -746,7 +746,7 @@
color: #1E293B; color: #1E293B;
} }
/deep/ .u-input { ::v-deep .u-input {
width: 380rpx; width: 380rpx;
} }
} }
@@ -828,11 +828,11 @@
margin-top: 2rpx; margin-top: 2rpx;
} }
/deep/ .u-input { ::v-deep .u-input {
margin-left: 130rpx; margin-left: 130rpx;
} }
/deep/ .u-input__right-icon ::before { ::v-deep .u-input__right-icon ::before {
content: "" content: ""
} }
@@ -918,7 +918,7 @@
color: #1E293B; color: #1E293B;
} }
/deep/ .u-input { ::v-deep .u-input {
width: 380rpx; width: 380rpx;
} }
} }
@@ -972,7 +972,7 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
/deep/ .u-tag { ::v-deep .u-tag {
margin: 10rpx 20rpx 10rpx 0; margin: 10rpx 20rpx 10rpx 0;
} }
@@ -1014,11 +1014,11 @@
margin-top: 2rpx; margin-top: 2rpx;
} }
/deep/ .u-input { ::v-deep .u-input {
margin-left: 130rpx; margin-left: 130rpx;
} }
/deep/ .u-input__right-icon ::before { ::v-deep .u-input__right-icon ::before {
content: "" content: ""
} }
@@ -1070,7 +1070,7 @@
.u_inp { .u_inp {
margin: 40rpx 0; margin: 40rpx 0;
/deep/ .u-input { ::v-deep .u-input {
background: #F1F5F9; background: #F1F5F9;
} }
} }

181
utils/ws/websocket.js Normal file
View File

@@ -0,0 +1,181 @@
export class WebSocketManager {
constructor(url) {
this.url = url;
this.socket = null;
this.isConnected = false;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.reconnectDelay = 1000;
this.messageHandlers = [];
this.pingInterval = null;
}
connect() {
if (this.isConnected) return;
console.log('正在连接WebSocket...');
this.socket = uni.connectSocket({
url: this.url,
success: () => {
console.log('WebSocket连接成功');
},
fail: (err) => {
console.error('WebSocket连接失败:', err);
this.handleReconnect();
}
});
this.socket.onOpen(() => {
console.log('WebSocket连接已打开');
this.isConnected = true;
this.reconnectAttempts = 0;
// 开始心跳检测
this.startHeartbeat();
// 绑定当前用户
const userId = uni.getStorageSync('userId');
if (userId) {
this.bindUser(userId);
}
});
this.socket.onMessage((res) => {
try {
const data = JSON.parse(res.data);
console.log('收到消息:', data);
this.handleMessage(data);
} catch (e) {
console.error('解析消息失败:', e);
}
});
this.socket.onClose((res) => {
console.log('WebSocket连接关闭:', res);
this.isConnected = false;
this.stopHeartbeat();
this.handleReconnect();
});
this.socket.onError((err) => {
console.error('WebSocket错误:', err);
});
}
bindUser(userId) {
this.send({
type: 'bind',
userId: userId
});
}
send(message) {
if (!this.isConnected) {
console.error('WebSocket未连接');
return false;
}
try {
const messageStr = JSON.stringify(message);
this.socket.send({
data: messageStr,
success: () => {
console.log('消息发送成功:', message);
},
fail: (err) => {
console.error('消息发送失败:', err);
}
});
return true;
} catch (err) {
console.error('发送消息出错:', err);
return false;
}
}
addMessageHandler(handler) {
this.messageHandlers.push(handler);
}
removeMessageHandler(handler) {
const index = this.messageHandlers.indexOf(handler);
if (index !== -1) {
this.messageHandlers.splice(index, 1);
}
}
handleMessage(data) {
// 如果对象中有clientId则给websocket发送
if (data.clientId) {
const userId = '252'; // 实际项目中从存储获取
const bindMessage = {
request_type: 'bind',
user_type: 'user',
sender_user_id: `user-${userId}`,
};
this.send(bindMessage);
}
// 处理聊天消息
if (data.message_type !== undefined) {
// 将消息转发给聊天管理器
this.messageHandlers.forEach(handler => {
try {
handler(data);
} catch (e) {
console.error('消息处理出错:', e);
}
});
} else {
// 其他消息处理
this.messageHandlers.forEach(handler => {
try {
handler(data);
} catch (e) {
console.error('消息处理出错:', e);
}
});
}
}
startHeartbeat() {
this.pingInterval = setInterval(() => {
if (this.isConnected) {
this.send({type: 'ping'});
}
}, 300000);
}
stopHeartbeat() {
if (this.pingInterval) {
clearInterval(this.pingInterval);
this.pingInterval = null;
}
}
handleReconnect() {
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
console.log('已达到最大重连次数');
return;
}
setTimeout(() => {
this.reconnectAttempts++;
this.reconnectDelay = Math.min(this.reconnectDelay * 2, 30000);
console.log(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
this.connect();
}, this.reconnectDelay);
}
disconnect() {
if (this.socket) {
this.socket.close();
this.socket = null;
}
this.isConnected = false;
this.stopHeartbeat();
}
}
// 全局WebSocket实例
export const webSocketManager = new WebSocketManager('ws://127.0.0.1:12080/ws');