diff --git a/http/websock.js b/http/websock.js index ccd13e2..4eb6be0 100644 --- a/http/websock.js +++ b/http/websock.js @@ -1,157 +1,241 @@ -import { - reactive, - ref -} from 'vue'; +import { reactive, ref } from 'vue'; + // WebSocket 工具类,封装了 WebSocket 的连接、发送、接收、心跳、重连和关闭等操作 class WebsocketUtil { - // 构造函数,初始化 WebSocket 连接 - constructor(url, time, params) { - this.url = url; // WebSocket 服务器的 URL - this.params = params; // WebSocket 服务器的 URL - this.time = time; // 心跳发送的间隔时间(秒) - this.socketTask = null; // WebSocket 任务对象 - this.isOpen = false; // WebSocket 连接是否打开 - this.reconnectTimeout = null; // 重连定时器 - this.heartbeatInterval = null; // 心跳定时器 - this.messageCallbacks = []; // 存储外部注册的消息回调函数的数组 - this.messageCallbacks = []; // 存储外部注册的消息回调函数的数组 + // 构造函数,初始化 WebSocket 连接 + constructor(url, time, params) { + this.url = url; // WebSocket 服务器的 URL + this.params = params; // WebSocket 连接参数 + this.time = time; // 心跳发送的间隔时间(毫秒) + this.socketTask = null; // WebSocket 任务对象 + this.isOpen = false; // WebSocket 连接是否打开 - // 初始化 WebSocket 连接 - this.initializeWebSocket(); - } + // 定时器相关 + this.reconnectTimeout = null; // 重连定时器 + this.heartbeatInterval = null; // 心跳定时器 + this.heartbeatTimeout = null; // 心跳超时定时器(检测 pong 响应) + this.checkConnectionInterval = null; // 连接状态主动检查定时器 - // 初始化 WebSocket 连接 - initializeWebSocket() { - console.log('初始化WebSocket连接'); - if (this.isOpen) { - return - } - this.socketTask = uni.connectSocket({ - url: this.url, - success: () => { - console.log('WebSocket连接成功'); - return this.socketTask; - }, - fail: (error) => { - console.error('WebSocket连接失败', error); - uni.$emit('is-socket-open', true) - this.reconnect(); - } - }); + // 消息回调数组 + this.messageCallbacks = []; // 存储外部注册的消息回调函数的数组 - this.socketTask.onOpen((res) => { - console.log('WebSocket连接正常!==', res); - this.isOpen = true; - // 连接成功后启动心跳和消息监听 - this.startHeartbeat(); - this.listenForMessages(); - uni.$emit('is-socket-open', true) + // 重连策略配置 + this.reconnectAttempts = 0; // 当前重连次数 + this.reconnectMaxAttempts = 5; // 最大重连次数(设为 Infinity 表示无限重试) + this.reconnectDelay = 3000; // 基础重连延迟(毫秒) + this.maxReconnectDelay = 30000; // 最大重连延迟(毫秒) - }); - this.socketTask.onError((res) => { - console.log('WebSocket连接失败!==', res); - uni.$emit('is-socket-open', false) - this.reconnect(); - }); - // 注意:这里的 onClose 监听器应该放在 uni.connectSocket 调用之后 - this.socketTask.onClose((result) => { - this.isOpen = false; - // if( this.isOpen ){ - this.reconnect(); - // } - }); + // 初始化 WebSocket 连接 + this.initializeWebSocket(); - } + // 监听设备唤醒事件(浏览器环境) + if (typeof document !== 'undefined') { + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + // 页面可见时,主动检查连接 + this.checkConnection(); + } + }); + } + } - // 启动心跳检测 - startHeartbeat() { - if (this.heartbeatInterval) { - clearInterval(this.heartbeatInterval); - } - this.heartbeatInterval = setInterval(() => { - if (this.isOpen) { - this.send(JSON.stringify({"type": "ping_interval","set": "pad"})); - } - }, this.time); - } + // 初始化 WebSocket 连接 + initializeWebSocket() { + console.log('初始化WebSocket连接'); + if (this.isOpen) { + return; + } - // 发送消息 - send(data, type) { - if (this.socketTask && this.isOpen) { - this.socketTask.send({ - data: data, - success: (res) => { - // console.log('消息发送成功', res); - this.startHeartbeat(); - }, - fail: (error) => { - console.error('消息发送失败', error); - this.reconnect(); // 这里可能需要根据实际情况判断是否重连 - } - }); - } - } + this.socketTask = uni.connectSocket({ + url: this.url, + success: () => { + console.log('WebSocket连接请求发送成功'); + }, + fail: (error) => { + console.error('WebSocket连接失败', error); + uni.$emit('is-socket-open', false); + this.reconnect(); + } + }); - // 监听 WebSocket 消息 - listenForMessages() { - if (this.socketTask) { - this.socketTask.onMessage((res) => { - const { - data - } = res; - this.messageCallbacks.forEach(callback => callback(data - .toString())); // 假设 data 是字符串或可转换为字符串 - }); - // this.send("WebSocket连接正常"); - } else { - console.error('WebSocket 连接尚未建立,无法监听消息'); - } - } + // 连接打开事件 + this.socketTask.onOpen((res) => { + console.log('WebSocket连接正常!==', res); + this.isOpen = true; + // 重置重连状态 + this.reconnectAttempts = 0; + this.reconnectDelay = 3000; + // 启动心跳和消息监听 + this.startHeartbeat(); + this.listenForMessages(); + uni.$emit('is-socket-open', true); + }); - // 重连 WebSocket - reconnect() { - if (this.reconnectTimeout) { - clearTimeout(this.reconnectTimeout); - } - this.reconnectTimeout = setTimeout(() => { - this.initializeWebSocket(); - }, 3000); - } + // 连接错误事件 + this.socketTask.onError((res) => { + console.log('WebSocket连接错误!==', res); + uni.$emit('is-socket-open', false); + this.reconnect(); + }); - // 关闭 WebSocket 连接 - closeSocket() { - if (this.socketTask) { - uni.closeSocket({ - success: () => { - console.log('WebSocket连接已关闭'); - this.isOpen = false; - }, - fail: (error) => { - console.error('关闭WebSocket连接失败', error); - } - }); - this.socketTask = null; - } - } + // 连接关闭事件 + this.socketTask.onClose((result) => { + console.log('WebSocket连接已关闭', result); + this.isOpen = false; + this.reconnect(); + }); - // 外部注册消息回调函数 - onMessage(callback) { - this.messageCallbacks.push(callback); - } + // 启动连接状态主动检查(30秒一次) + this.startConnectionCheck(); + } - // 外部注销消息回调函数 - offMessage(callback) { - this.messageCallbacks = [] - } + // 启动心跳检测 + startHeartbeat() { + // 清除现有定时器 + if (this.heartbeatInterval) clearInterval(this.heartbeatInterval); + if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout); - // 销毁 WebSocket 连接,清理资源 - destroy() { - this.closeSocket(); - clearInterval(this.heartbeatInterval); - clearTimeout(this.reconnectTimeout); - this.messageCallbacks = []; - } + this.heartbeatInterval = setInterval(() => { + if (this.isOpen) { + // 发送心跳包 + this.send(JSON.stringify({ "type": "ping_interval", "set": "pad" })); + // 设置5秒超时:若未收到pong则重连 + this.heartbeatTimeout = setTimeout(() => { + console.log('心跳超时,主动断开并重连'); + this.closeSocket(); + this.reconnect(); + }, 5000); + } + }, this.time); + } + + // 启动连接状态主动检查(30秒一次) + startConnectionCheck() { + if (this.checkConnectionInterval) clearInterval(this.checkConnectionInterval); + this.checkConnectionInterval = setInterval(() => { + if (!this.isOpen && !this.reconnectTimeout) { + console.log('主动检查到连接断开,触发重连'); + this.reconnect(); + } + }, 30000); + } + + // 发送消息 + send(data, type) { + if (this.socketTask && this.isOpen) { + this.socketTask.send({ + data: data, + success: (res) => { + // 发送成功,重置心跳(可选,根据业务需求) + this.startHeartbeat(); + }, + fail: (error) => { + console.error('消息发送失败', error); + this.reconnect(); + } + }); + } else { + console.warn('WebSocket未连接,无法发送消息'); + } + } + + // 监听 WebSocket 消息 + listenForMessages() { + if (this.socketTask) { + this.socketTask.onMessage((res) => { + const data = res.data.toString(); + try { + // 尝试解析JSON,处理pong响应 + const message = JSON.parse(data); + if (message.type === 'pong') { + // 收到pong,清除心跳超时 + if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout); + } + } catch (e) { + console.warn('消息解析失败(非JSON格式):', e); + } + // 触发外部注册的回调函数 + this.messageCallbacks.forEach(callback => callback(data)); + }); + } else { + console.error('WebSocket 连接尚未建立,无法监听消息'); + } + } + + // 重连 WebSocket(指数退避策略) + reconnect() { + if (this.reconnectTimeout) clearTimeout(this.reconnectTimeout); + + // 达到最大重连次数,停止重试(可根据需求调整为无限重试) + if (this.reconnectAttempts >= this.reconnectMaxAttempts) { + console.log(`已达最大重连次数 ${this.reconnectMaxAttempts},停止重连`); + return; + } + + // 指数退避:延迟时间 = 基础延迟 * 2^重连次数,最大不超过maxReconnectDelay + const delay = Math.min( + this.reconnectDelay * Math.pow(2, this.reconnectAttempts), + this.maxReconnectDelay + ); + + this.reconnectTimeout = setTimeout(() => { + this.reconnectAttempts++; + console.log(`重连尝试 ${this.reconnectAttempts}/${this.reconnectMaxAttempts},延迟 ${delay}ms`); + this.initializeWebSocket(); + }, delay); + } + + // 主动检查连接状态 + checkConnection() { + if (!this.isOpen && !this.reconnectTimeout) { + this.reconnect(); + } + } + + // 关闭 WebSocket 连接 + closeSocket() { + if (this.socketTask) { + uni.closeSocket({ + success: () => { + console.log('WebSocket连接已关闭'); + this.isOpen = false; + }, + fail: (error) => { + console.error('关闭WebSocket连接失败', error); + } + }); + this.socketTask = null; + } + } + + // 外部注册消息回调函数 + onMessage(callback) { + this.messageCallbacks.push(callback); + } + + // 外部注销消息回调函数 + offMessage(callback) { + // 若传入callback,则移除指定回调;否则清空所有回调 + if (callback) { + this.messageCallbacks = this.messageCallbacks.filter(cb => cb !== callback); + } else { + this.messageCallbacks = []; + } + } + + // 销毁 WebSocket 连接,清理资源 + destroy() { + this.closeSocket(); + // 清除所有定时器 + clearInterval(this.heartbeatInterval); + clearTimeout(this.heartbeatTimeout); + clearTimeout(this.reconnectTimeout); + clearInterval(this.checkConnectionInterval); + // 清空回调数组 + this.messageCallbacks = []; + console.log('WebSocket资源已销毁'); + } } export default WebsocketUtil; \ No newline at end of file diff --git a/pages/choose-table/choose-table.vue b/pages/choose-table/choose-table.vue index 3acd005..3495137 100644 --- a/pages/choose-table/choose-table.vue +++ b/pages/choose-table/choose-table.vue @@ -2,12 +2,18 @@ - + + + 退出 + + 台桌列表 @@ -215,6 +221,13 @@ onShow(async () => { getTable(); }); +function loginOut() { + uni.clearStorage(); + uni.redirectTo({ + url: "/pages/login/index", + }); +} + /** * 扫码上传 */ diff --git a/pages/login/index.vue b/pages/login/index.vue index 7aa1e88..b90a0d7 100644 --- a/pages/login/index.vue +++ b/pages/login/index.vue @@ -293,20 +293,7 @@ const vdata = reactive({ loginType: "merchant", }, }); -vdata.formData.merchantName = "19107220837"; -vdata.formData.username = "19111112222"; -vdata.formData.pwd = "123456"; -vdata.formData.code = "666666"; -// #ifdef H5 -// vdata.formData.merchantName = "19191703856"; -// vdata.formData.username = "18888888888"; -// vdata.formData.pwd = "123456"; -// vdata.formData.code = "666666"; -// #endif -// #ifdef MP-WEIXIN -// vdata.formData.username = '15699991111' -// vdata.formData.pwd = 'qwer1234' -// #endif + function accountTypeChange(e) { // #ifdef H5 diff --git a/pagesCreateOrder/index/components/car.vue b/pagesCreateOrder/index/components/car.vue index dbcdb1c..f3f324b 100644 --- a/pagesCreateOrder/index/components/car.vue +++ b/pagesCreateOrder/index/components/car.vue @@ -125,7 +125,7 @@ class="u-p-t-32 u-p-b-32 u-p-r-28 u-p-l-28 u-m-t-40 bg-fff u-flex u-row-between" > 历史订单 - + { data.userInfo = shopif; } } - // 判断是否token过期,是否有名字 - if (!data.userInfo.shopName) { - loginShowOut(); - } getHistoryOrderDetail(); nextTick(() => { @@ -2018,7 +2011,7 @@ async function getLimit() { } async function getTableDetail() { - if(!data.table.tableCode){ + if (!data.table.tableCode) { return; } let res = await $returnTableDetail({ diff --git a/pagesCreateOrder/table-order/components/goods-list.vue b/pagesCreateOrder/table-order/components/goods-list.vue index 4a1981f..44158a4 100644 --- a/pagesCreateOrder/table-order/components/goods-list.vue +++ b/pagesCreateOrder/table-order/components/goods-list.vue @@ -180,6 +180,10 @@ function returnLimitPrice(data) { shopUserInfo: cartStore.shopUserInfo, idKey: "productId", }); + + console.log("cartStore.shopInfo", cartStore.shopInfo); + console.log("cartStore.limitTimeDiscount", cartStore.limitTimeDiscount); + console.log("cartStore.shopUserInfo", cartStore.shopUserInfo); return price; } diff --git a/pagesCreateOrder/table-order/index.vue b/pagesCreateOrder/table-order/index.vue index 60ae3f5..165f3c9 100644 --- a/pagesCreateOrder/table-order/index.vue +++ b/pagesCreateOrder/table-order/index.vue @@ -515,6 +515,7 @@ async function discountconfirm(form) { product_id: modelData.data.product_id, sku_id: modelData.data.sku_id, discount_sale_amount: discount_sale_amount, + is_time_discount: discount_sale_amount>0 ? 0 : (modelData.data.is_time_discount||modelData.data.isTimeDiscount) // discount_sale_note: str + form.note, }; updateCart(par); diff --git a/pagesOrder/pay-order/components/edit-accountPoints.vue b/pagesOrder/pay-order/components/edit-accountPoints.vue index 48e5c7f..b3e6f5b 100644 --- a/pagesOrder/pay-order/components/edit-accountPoints.vue +++ b/pagesOrder/pay-order/components/edit-accountPoints.vue @@ -1,195 +1,203 @@ \ No newline at end of file +.placeholder-class { + font-size: 28rpx; +} + diff --git a/pagesOrder/pay-order/pay-order.vue b/pagesOrder/pay-order/pay-order.vue index 7755855..204afa0 100644 --- a/pagesOrder/pay-order/pay-order.vue +++ b/pagesOrder/pay-order/pay-order.vue @@ -998,6 +998,9 @@ watch( if (newval) { getNewUserDiscount(); // getShopUserDetail(); + }else{ + newUserDiscount.value =0 + newUserDiscountRes.value =null } } ); diff --git a/stores/cart.js b/stores/cart.js index 1882126..1999e38 100644 --- a/stores/cart.js +++ b/stores/cart.js @@ -188,7 +188,7 @@ export const useCartStore = defineStore("cart", { }) ); } - if (msg.status == 0&&msg.type!="time_discount") { + if (msg.status == 0 && msg.type != "time_discount") { uni.showToast({ title: "添加失败", icon: "none", @@ -204,6 +204,9 @@ export const useCartStore = defineStore("cart", { this.limitTimeDiscount = msg.time_dis_info; this.getOrder(); break; + case "reload": + this.getOrder(); + break; case "pad_add": case "add": break; @@ -224,7 +227,7 @@ export const useCartStore = defineStore("cart", { break; case "pad_cleanup": case "cleanup": - this.goodsList=[] + this.goodsList = []; break; case "product_update": break; @@ -277,6 +280,7 @@ export const useCartStore = defineStore("cart", { */ setOrder(order) { this.order = order; + this.limitTimeDiscount = order.limitRate; this.oldCartList = Object.values(order.detailMap).reduce((pre, cur) => { pre.push( ...cur.map((v) => {