diff --git a/App.vue b/App.vue
index 14cb274..b929757 100644
--- a/App.vue
+++ b/App.vue
@@ -10,7 +10,10 @@
} from '@dcloudio/uni-app';
import {
getCurrentInstance
- } from 'vue'
+ } from 'vue';
+ import {
+ Storelogin
+ } from '@/stores/user.js';
const {
proxy
} = getCurrentInstance()
@@ -18,7 +21,15 @@
onLaunch(async () => {
// 标记应用启动完成
const store = useNavbarStore();
- store.initNavbarHeight();
+ await store.initNavbarHeight();
+ // #ifndef H5
+ try {
+ const storelogin = Storelogin();
+ await storelogin.actionslogin()
+ } catch (error) {
+ console.log(error)
+ }
+ // #endif
try {
uni.getLocation({
type: 'wgs84',
@@ -27,40 +38,43 @@
lng: res.longitude,
lat: res.latitude,
})
- if (successres.code == 0) {
+ if (successres) {
let datastorage = {
- country: successres.data.addressComponent.country, // "中国"
- province: successres.data.addressComponent
+ country: successres.addressComponent.country, // "中国"
+ province: successres.addressComponent
.province, //province: "陕西省"
- address: successres.data.addressComponent.city, //district: "西安市"
- district: successres.data.addressComponent
- .district, //district: "未央区"
+ address: successres.addressComponent.city, //district: "西安市"
+ district: successres.addressComponent.district, //district: "未央区"
lng: res.longitude,
lat: res.latitude,
}
uni.cache.set('getLocationstorage', datastorage);
+ // 登录
proxy.$isResolve()
}
},
});
} catch (error) {
- let successres = await APIgeocodelocation({
- lng: '',
- lat: '',
- })
- if (successres.code == 0) {
- let datastorage = {
- country: successres.data.addressComponent.country, // "中国"
- province: successres.data.addressComponent
- .province, //province: "陕西省"
- address: successres.data.addressComponent.city, //district: "西安市"
- district: successres.data.addressComponent
- .district, //district: "未央区"
- lng: res.longitude,
- lat: res.latitude,
+ try {
+ let successres = await APIgeocodelocation({
+ lng: '',
+ lat: '',
+ })
+ if (successres) {
+ let datastorage = {
+ country: successres.addressComponent.country, // "中国"
+ province: successres.addressComponent
+ .province, //province: "陕西省"
+ address: successres.addressComponent.city, //district: "西安市"
+ district: successres.addressComponent.district, //district: "未央区"
+ lng: res.longitude,
+ lat: res.latitude,
+ }
+ uni.cache.set('getLocationstorage', datastorage);
+ proxy.$isResolve()
}
- uni.cache.set('getLocationstorage', datastorage);
+ } catch (error) {
proxy.$isResolve()
}
}
diff --git a/common/api/api.js b/common/api/api.js
index 696728d..727ac77 100644
--- a/common/api/api.js
+++ b/common/api/api.js
@@ -1,20 +1,33 @@
// 引入 request 文件
import request from '@/common/api/request.js'
-
+const url = '/account'
//根据经纬度获取信息
export const APIgeocodelocation = (data) => {
return request({
- url: '/location/geocode',
+ url: url + '/user/geo/geocode',
method: 'get',
data: data,
toast: false
})
}
-//根据经纬度获取信息
-export const APIcustomlogin = (data) => {
+
+//登录
+export const APIuserlogin = (data) => {
return request({
- url: '/login/auth/custom/login',
+ url: url + '/user/login',
method: 'post',
- data: data
+ data: data,
+ toast: false
})
-}
\ No newline at end of file
+}
+
+
+//用户信息获取
+export const APIuser = (data) => {
+ return request({
+ url: url + '/user',
+ method: 'get',
+ data: data,
+ toast: false
+ })
+}
diff --git a/common/api/index/coupons.js b/common/api/index/coupons.js
index 284107c..22e1111 100644
--- a/common/api/index/coupons.js
+++ b/common/api/index/coupons.js
@@ -1,9 +1,10 @@
// 引入 request 文件
import request from '@/common/api/request.js'
//获取优惠券参数列表
+const url = '/account'
export const APIordergetYhqPara = (data) => {
return request({
- url: '/order/getYhqPara',
+ url: url + '/order/getYhqPara',
method: 'get',
data: data
})
@@ -11,7 +12,7 @@ export const APIordergetYhqPara = (data) => {
//系统优惠券
export const APIorderfindCoupons = (data) => {
return request({
- url: '/order/findCoupons',
+ url: url + '/order/findCoupons',
method: 'get',
data: data
})
@@ -19,7 +20,7 @@ export const APIorderfindCoupons = (data) => {
// 我的优惠券
export const APIordermineCoupons = (data) => {
return request({
- url: '/order/mineCoupons',
+ url: url + '/order/mineCoupons',
method: 'post',
data: data,
toast: false
diff --git a/common/api/index/index.js b/common/api/index/index.js
index 908bfbe..07989d9 100644
--- a/common/api/index/index.js
+++ b/common/api/index/index.js
@@ -1,44 +1,28 @@
// 引入 request 文件
+const url = '/account'
import request from '@/common/api/request.js'
//首页上半部分
export const APIhomehomePageUp = (data) => {
return request({
- url: '/home/homePageUp',
- method: 'post',
+ url: url + '/user/home/homePageUp',
+ method: 'GET',
data: data
})
}
-//首页上半部分
+//首页xia半部分
export const APIhome = (data) => {
return request({
- url: '/home',
- method: 'post',
- data: data,
- toast: false
- })
-}
-//首页上半部分
-export const APIshopUserInfo = (data) => {
- return request({
- url: '/user/shopUserInfo',
- method: 'get',
- data: data,
- toast: false
- })
-}
-//首页上半部分
-export const APIgeocodelocation = (data) => {
- return request({
- url: '/location/geocode',
- method: 'get',
+ url: url + '/user/home/home',
+ method: 'GET',
data: data,
toast: false
})
}
+
///商户登录后 shopId和autokey
export const APIshopExtend = (data) => {
return request({
- url: '/common/shopExtend',
+ url: url + '/common/shopExtend',
method: 'post',
data: data,
toast: false
diff --git a/common/api/index/tothestore.js b/common/api/index/tothestore.js
index 5b2c188..e27b17e 100644
--- a/common/api/index/tothestore.js
+++ b/common/api/index/tothestore.js
@@ -1,9 +1,10 @@
// 引入 request 文件
import request from '@/common/api/request.js'
+const url = '/account'
//获取top部分(店铺列表)
export const APIdistiricttopCommon = (data) => {
return request({
- url: '/distirict/topCommon',
+ url: url + '/distirict/topCommon',
method: 'get',
data: data
})
@@ -11,7 +12,7 @@ export const APIdistiricttopCommon = (data) => {
//预约到店(店铺列表)
export const APIdistirictsubShopList = (data) => {
return request({
- url: '/distirict/subShopList',
+ url: url + '/distirict/subShopList',
method: 'get',
data: data
})
diff --git a/common/api/order/index.js b/common/api/order/index.js
new file mode 100644
index 0000000..a3d6385
--- /dev/null
+++ b/common/api/order/index.js
@@ -0,0 +1,11 @@
+// 引入 request 文件
+import request from '@/common/api/request.js'
+const url = '/order'
+//订单列表
+export const APIuserorder = (data) => {
+ return request({
+ url: url + '/user/order',
+ method: 'post',
+ data: data
+ })
+}
\ No newline at end of file
diff --git a/common/api/product/product.js b/common/api/product/product.js
index ef683c1..4648944 100644
--- a/common/api/product/product.js
+++ b/common/api/product/product.js
@@ -1,10 +1,66 @@
// 引入 request 文件
import request from '@/common/api/request.js'
-
-//通过桌码获取店铺信息
+const urlAccount = '/account'
+const urlProduct = '/product'
+const urlOrder = '/order'
+//桌码换取详细店铺信息
export const APIproductqueryShop = (data) => {
return request({
- url: '/product/queryShop',
+ url: urlAccount + '/user/shopInfo',
+ method: 'get',
+ data: data
+ })
+}
+
+// 获取登录用户店铺会员信息
+export const APIshopUserInfo = (data) => {
+ return request({
+ url: urlAccount + '/user/shopUser',
+ method: 'get',
+ data: data,
+ toast: false
+ })
+}
+
+//获取商品列表数据
+export const APIproductqueryProduct = (data) => {
+ return request({
+ url: urlProduct + '/user/product/miniApp/home/queryProduct',
+ method: 'get',
+ data: data
+ })
+}
+
+//小程序点餐-热销商品查询
+export const productminiApphotsquery = (data) => {
+ return request({
+ url: urlProduct + '/user/product/miniApp/hots/query',
+ method: 'get',
+ data: data
+ })
+}
+
+//小程序点餐-分组商品列表
+export const APIgroupquery = (data) => {
+ return request({
+ url: urlProduct + '/user/product/miniApp/group/query',
+ method: 'get',
+ data: data
+ })
+}
+
+//小程序点餐-分组商品列表
+export const APIminiAppinfo = (data) => {
+ return request({
+ url: urlProduct + '/user/product/miniApp/info/' + data,
+ method: 'get'
+ })
+}
+
+//小程序点餐-分组商品列表
+export const APIminiAppskuinfo = (data) => {
+ return request({
+ url: urlProduct + '/user/product/miniApp/sku/info',
method: 'get',
data: data
})
diff --git a/common/api/request.js b/common/api/request.js
index 8c90c9f..24ba65a 100644
--- a/common/api/request.js
+++ b/common/api/request.js
@@ -19,11 +19,10 @@ export default (params) => {
// #ifdef MP-ALIPAY
environment: 'alipay',
// #endif
- token: uni.cache.get('token'),
- openId: uni.cache.get('miniAppOpenId'),
- id: uni.cache.get('userInfo').id,
- shopId: uni.cache.get('shopId'),
- userId: uni.cache.get('userInfo').id,
+ token: uni.cache.get('token') || '',
+ id: uni.cache.get('userInfo').id || '',
+ shopId: uni.cache.get('shopId') || '',
+ userId: uni.cache.get('userInfo').id || '',
}
if (toast) {
uni.showLoading({
@@ -41,10 +40,10 @@ export default (params) => {
const res = response.data
// 根据返回的状态码做出对应的操作
//获取成功
- if (res.code == 0) {
+ if (res.code == 200) {
uni.hideLoading();
uni.hideToast();
- resolve(res);
+ resolve(res.data);
} else {
switch (res.code) {
case '-4':
diff --git a/common/js/websocket.js b/common/js/websocket.js
index de6ffd8..d011d2d 100644
--- a/common/js/websocket.js
+++ b/common/js/websocket.js
@@ -1,231 +1,301 @@
-class webSocketUtils {
- constructor(url, time, params) {
- this.socketTask = null;
- this.is_open_socket = false; //避免重复连接
- this.url = url;
- this.params = params ? params : null; ////是否初始化请求
- this.connectNum = 1; // 重连次数
- //这个参数是防止重连失败之后onClose方法会重复执行reconnect方法,导致重连定时器出问题
- //连接并打开之后可重连,且只执行重连方法一次
- this.canReconnect = false; // 是否可以重连
- //心跳检测
- this.timeout = time ? time : 5000; //多少秒执行检测
- this.heartbeatInterval = null; //检测服务器端是否还活着
- this.reconnectTimeOut = null; //重连之后多久再次重连
- try {
-
- return this.connectSocketInit({
- data: this.params,
- type: 'connectSocketInit',
- });
- } catch (e) {
- // console.log('catch');
- this.reconnect();
- }
- }
- // 进入这个页面的时候创建websocket连接【整个页面随时使用】
- connectSocketInit(data) {
- let _this = this;
- this.data = data;
- // #ifdef MP-WEIXIN
- this.socketTask = uni.connectSocket({
- // #endif
- // #ifdef MP-ALIPAY
- my.connectSocket({
- // #endif
- url: this.url,
- success: (res) => {
- console.log('创建websocketc成功...');
- // uni.hideLoading();
- // 返回实例
- return this.socketTask;
- },
- fail: (res) => {
- }
- });
-
- // #ifdef MP-WEIXIN
- this.socketTask.onOpen((res) => {
- // #endif
- // #ifdef MP-ALIPAY
- my.onSocketOpen((res) => {
- // #endif
- uni.hideLoading()
- this.connectNum = 1;
- console.log('WebSocket连接正常!==',res);
- if (this.params) { //是否初始化请求
- this.send(this.params);
- }
- clearInterval(this.reconnectTimeOut);
- clearInterval(this.heartbeatInterval);
- this.is_open_socket = true;
- this.canReconnect = true;
- this.start();
- // 注:只有连接正常打开中 ,才能正常收到消息
- // #ifdef MP-WEIXIN
- this.socketTask.onMessage((e) => {
- // #endif
- // #ifdef MP-ALIPAY
- my.onSocketMessage((e)=>{
- // #endif
- // 字符串转json
- let res = JSON.parse(e.data);
- uni.$emit('message', res)
- // 普通socket信息处理 TODO
- });
- });
-
- // 监听连接失败,这里代码我注释掉的原因是因为如果服务器关闭后,和下面的onclose方法一起发起重连操作,这样会导致重复连接
- // #ifdef MP-WEIXIN
- uni.onSocketError((res) => {
- // #endif
- // #ifdef MP-ALIPAY
- my.onSocketError((res) => {
- // #endif
- console.log('网络断开,请检查!');
- this.socketTask = null;
- this.is_open_socket = false;
- // this.Close()
- this.canReconnect = true;
- clearInterval(this.heartbeatInterval);
- clearInterval(this.reconnectTimeOut);
- try {
- if (this.connectNum <= 10) {
- // uni.showLoading({
- // title: `网络连接失败,正尝试第${this.connectNum}次连接`,
- // mask: true
- // })
- uni.$emit('message', 1) //进行重连
- uni.showToast({
- title: `网络连接失败,正尝试第${this.connectNum}次连接`,
- icon: 'none',
- });
- this.reconnect();
- this.connectNum += 1;
- } else {
- // uni.$emit('connectError');
- uni.showToast({
- title: `网络连接失败,请检查网络!`,
- icon: 'none',
- });
- this.connectNum = 1;
- this.canReconnect = false;
- this.Close()
- setTimeout(res => {
- uni.switchTab({
- url: '/pages/index/index'
- })
- uni.hideLoading()
- }, 1000)
+import {
+ ref,
+ onMounted,
+ onBeforeUnmount
+} from 'vue';
+
+const useWebSocket = (options = {}) => {
+ const {
+ heartbeatInterval = 10000, //心跳是10秒一次
+ reconnectInterval = 3000, //重新连接间隔时间的一个参数
+ maxReconnectAttempts = 3, //最大重连接次数
+ initialReconnectInterval = 3000, // 初始重连间隔
+ initMessage,
+ initMessageRetryCount = 3, // 新增:初始化消息发送重试次数
+ initMessageRetryInterval = 2000, // 新增:初始化消息重试间隔
+ maxReconnectDuration = Infinity
+ } = options;
+
+ const autoReconnect = ref(true); //是否自动重新连接
+ const socketTask = ref(null);
+ const isConnected = ref(false); //表示是否已连接上。
+ const heartbeatTimer = ref(null); //心跳定时器
+ const reconnectTimer = ref(null); //重连定时器
+ const reconnectAttempts = ref(0); //重连的尝试次数
+ const isNetworkConnected = ref(true); //监听当前网络连接状态
+ const isManuallyClosed = ref(false); //是否是被手动关闭的
+ const receivedMessages = ref([]); //储从 WebSocket 服务器接收到的消息
+ const initMessageSendAttempts = ref(0); //初始化连接多少次
+ const reconnectStartTime = ref(0); //新增:记录重连开始时间
+
+ // 关闭现有连接并清理资源
+ const closeExistingConnection = () => {
+ if (socketTask.value) {
+ // 关闭 WebSocket 连接
+ socketTask.value.close({
+ success: () => {
+ console.log('WebSocket 连接已关闭');
+ },
+ fail: (err) => {
+ console.error('关闭 WebSocket 连接失败:', err);
}
- } catch (e) {
- //TODO handle the exception
- }
- });
- // 这里仅是事件监听【如果socket关闭了会执行】
- // #ifdef MP-WEIXIN
- this.socketTask.onClose(() => {
- // #endif
- // #ifdef MP-ALIPAY
- my.onSocketClose((res) => {
- // #endif
- console.log("socket关闭了")
- this.socketTask = null;
- clearInterval(this.heartbeatInterval);
- clearInterval(this.reconnectTimeOut);
- // #ifdef MP-ALIPAY
- // 支付宝小程序的ws连接问题,关闭连接时需关闭对于接受,防止关闭失败
- my.offSocketMessage();
- my.offSocketError();
- my.offSocketOpen();
- my.offSocketClose();
- // #endif
- this.is_open_socket = false;
- if (this.canReconnect) {
- this.reconnect();
- this.canReconnect = false;
- }
- });
- }
- // 主动关闭socket连接
- Close() {
- this.is_open_socket = true;
- this.canReconnect = false;
-
- // #ifdef MP-WEIXIN
- if (this.socketTask) {
- this.socketTask.close({
- success(res) {
- console.log('手动关闭成功');
- },
});
+
+ // 清除心跳定时器
+ clearInterval(heartbeatTimer.value);
+ heartbeatTimer.value = null;
+
+ // 清除重连定时器
+ clearTimeout(reconnectTimer.value);
+ reconnectTimer.value = null;
+
+ // 标记连接已断开
+ isConnected.value = false;
}
- // #endif
- // #ifdef MP-ALIPAY
- my.closeSocket({
- success(res) {
- console.log('手动关闭成功');
- // #ifdef MP-ALIPAY
- // 支付宝小程序的ws连接问题,关闭连接时需关闭对于接受,防止关闭失败
- my.offSocketMessage();
- my.offSocketError();
- my.offSocketOpen();
- my.offSocketClose();
- // #endif
-
+ };
+
+ // 连接 WebSocket
+ const connect = () => {
+ if (!isNetworkConnected.value) {
+ console.log('网络未连接,暂不尝试连接 WebSocket');
+ return;
+ }
+
+ // 关闭现有连接并清理资源
+ closeExistingConnection();
+
+ socketTask.value = uni.connectSocket({
+ url: uni.conf.baseUrlwws,
+ success: (res) => {
+ isConnected.value = true;
+ reconnectAttempts.value = 0;
+ // 监听初始化成功在开启心跳
+ // startHeartbeat();
},
- fail: (res) => {
- console.log('手动关闭失败==',res);
+ fail: () => {
+ console.error('WebSocket 连接失败,尝试重连');
+ if (autoReconnect.value) {
+ handleReconnect();
+ }
}
});
- // #endif
- }
- //发送消息
- send(data) {
- // console.log("发送消息---------->", data);
- // 注:只有连接正常打开中 ,才能正常成功发送消息
-
- // #ifdef MP-WEIXIN
- if (this.socketTask) {
- this.socketTask.send({
+
+ if (socketTask.value) {
+ socketTask.value.onOpen(() => {
+ // 初始化 初始购物车
+ sendMessage(initMessage)
+ });
+ socketTask.value.onMessage((res) => {
+ // console.log(res, 'receivedMessages.value')
+ let list = JSON.parse(res.data)
+ receivedMessages.value.push(list);
+ if (list.type == 'p') {
+ console.log('心跳响应正常');
+ // 心跳正常,重置重连尝试次数
+ reconnectAttempts.value = 0;
+ clearTimeout(reconnectTimer.value);
+ }
+ });
+
+ socketTask.value.onClose((res) => {
+ console.log(res, 'WebSocket 连接已关闭,尝试重连');
+ isConnected.value = false;
+ clearInterval(heartbeatTimer.value); // 停止心跳定时器
+ clearTimeout(reconnectTimer.value); // 清除重连定时器
+ if (res.code == '1006') {
+ console.log('服务器正常关闭,停止重连');
+ autoReconnect.value = false;
+ return false;
+ }
+ if (autoReconnect.value && !isManuallyClosed.value) {
+ handleReconnect();
+ }
+ });
+
+ socketTask.value.onError((err) => {
+ console.error('WebSocket 连接发生错误:', err);
+ isConnected.value = false;
+ clearInterval(heartbeatTimer.value);
+ if (autoReconnect.value && !isManuallyClosed.value) {
+ handleReconnect();
+ }
+ });
+ } else {
+ console.error('socketTask 未正确初始化');
+ }
+ };
+
+ // 启动心跳机制
+ const startHeartbeat = () => {
+ if (!isNetworkConnected.value) {
+ console.log('网络未连接,暂停心跳');
+ return;
+ }
+ heartbeatTimer.value = setInterval(() => {
+ if (isConnected.value) {
+ socketTask.value.send({
+ data: JSON.stringify({
+ type: 'pong'
+ }),
+ success: () => {
+ console.log('心跳消息发送成功');
+ const pongTimer = setTimeout(() => {
+ console.error('心跳超时,未收到响应,尝试重连');
+ clearInterval(heartbeatTimer.value);
+ if (autoReconnect) {
+ handleReconnect();
+ }
+ }, heartbeatInterval * 1.2);
+
+ socketTask.value.onMessage((res) => {
+ if (res.data === 'ping') {
+ clearTimeout(pongTimer);
+ }
+ });
+ },
+ fail: () => {
+ console.error('心跳消息发送失败,尝试重连');
+ clearInterval(heartbeatTimer.value);
+ if (autoReconnect) {
+ handleReconnect();
+ }
+ }
+ });
+ }
+ }, heartbeatInterval);
+ };
+
+ // 手动关闭连接
+ const closeSocket = () => {
+ isManuallyClosed.value = true;
+ closeExistingConnection();
+ };
+
+ // 发送消息
+ const sendMessage = async (data) => {
+ if (isConnected.value) {
+ await socketTask.value.send({
data: JSON.stringify(data),
- async success() {
- // console.log("消息发送成功");
+ success: () => {
+ // console.log('消息发送成功');
},
+ fail: () => {
+ // console.error('消息发送失败');
+ }
+ });
+ } else {
+ console.error('WebSocket 未连接,无法发送消息');
+ }
+ };
+
+ // 处理重连逻辑
+ const handleReconnect = () => {
+ if (!isNetworkConnected.value) {
+ console.log('网络未连接,暂停重连');
+ return;
+ }
+ if (isManuallyClosed.value) {
+ console.log('手动关闭连接,不进行重连');
+ return;
+ }
+
+ if (reconnectAttempts.value < maxReconnectAttempts) {
+ reconnectAttempts.value++;
+ const reconnectInterval = initialReconnectInterval * Math.pow(2, reconnectAttempts.value - 1);
+ const randomizedInterval = reconnectInterval + Math.floor(Math.random() * 1000);
+ console.log(`尝试第 ${reconnectAttempts.value} 次重连,重连间隔: ${randomizedInterval}ms...`);
+ reconnectTimer.value = setTimeout(() => {
+ connect();
+ }, randomizedInterval);
+ } else {
+ console.error('重连次数达到上限,停止重连');
+ uni.showToast({
+ title: '重连次数达到上限,停止重连',
+ icon: 'none'
});
}
- // #endif
- // #ifdef MP-ALIPAY
- my.sendSocketMessage({
- data: JSON.stringify(data),
- success(res) {
- // console.log("消息发送成功");
+ };
+
+ // 发送初始化消息
+ const sendInitMessage = async () => {
+ if (initMessageSendAttempts.value < initMessageRetryCount) {
+ initMessageSendAttempts.value++;
+ await socketTask.value.send({
+ data: JSON.stringify(initMessage),
+ success: () => {
+ console.log('初始化消息发送成功');
+ initMessageSendAttempts.value = 0; // 重置尝试次数
+ },
+ fail: () => {
+ console.log(
+ `初始化消息发送失败,第 ${initMessageSendAttempts.value} 次尝试,将在 ${initMessageRetryInterval} 后重试`
+ );
+ setTimeout(() => {
+ sendInitMessage();
+ }, initMessageRetryInterval);
+ }
+ });
+ } else {
+ console.error('初始化消息发送失败,已达到最大重试次数');
+ // initMessageSendAttempts.value = 0; // 重置尝试次数
+ }
+ };
+
+
+ // 网络状态监听
+ const initNetworkListener = () => {
+ uni.getSystemInfo({
+ success: (res) => {
+ if (res.platform !== 'devtools') {
+ uni.onNetworkStatusChange((statusRes) => {
+ isNetworkConnected.value = statusRes.isConnected;
+ if (statusRes.isConnected && !isManuallyClosed.value) {
+ console.log('网络已连接,尝试重新连接 WebSocket');
+ if (!isConnected.value && autoReconnect.value) {
+ connect();
+ }
+ } else if (!statusRes.isConnected) {
+ console.log('网络已断开,暂停 WebSocket 操作');
+ clearInterval(heartbeatTimer.value);
+ clearTimeout(reconnectTimer.value);
+ if (socketTask.value) {
+ socketTask.value.close();
+ isConnected.value = false;
+ }
+ }
+ });
+ }
},
+ fail: (err) => {
+ console.error('获取系统信息失败:', err);
+ }
});
- // #endif
- }
- //开启心跳检测
- start(data) {
- // console.log('开启心跳检测', data)
- this.heartbeatInterval = setInterval(() => {
- this.send({
- data: '心跳检测',
- type: 'heartbeat',
- });
- }, this.timeout);
- }
- //重新连接
- reconnect() {
- //停止发送心跳
- clearInterval(this.heartbeatInterval);
- //如果不是人为关闭的话,进行重连
- if (!this.is_open_socket) {
- console.log('进行重连');
- this.canReconnect = true;
- this.reconnectTimeOut = setInterval(() => {
- this.connectSocketInit(this.data);
- }, this.timeout);
- }
- }
-}
-module.exports = webSocketUtils;
\ No newline at end of file
+
+ uni.getNetworkType({
+ success: (res) => {
+ isNetworkConnected.value = res.networkType !== 'none';
+ if (!isNetworkConnected.value) {
+ console.log('初始网络未连接,暂不尝试连接 WebSocket');
+ }
+ }
+ });
+ };
+
+ onMounted(() => {
+ initNetworkListener();
+ connect();
+ });
+
+ onBeforeUnmount(() => {
+ closeSocket();
+ });
+
+ return {
+ isConnected,
+ sendMessage,
+ closeSocket,
+ receivedMessages
+ };
+};
+
+export default useWebSocket;
\ No newline at end of file
diff --git a/components/CustomNavbar.vue b/components/CustomNavbar.vue
index ac43e8f..d3d16f1 100644
--- a/components/CustomNavbar.vue
+++ b/components/CustomNavbar.vue
@@ -33,19 +33,22 @@
reactive,
watch,
onMounted,
- computed
+ computed,
+ toRefs
} from 'vue';
const store = useNavbarStore();
const {
showBack,
rightText,
+ showSearch,
+ title,
isTransparent,
height,
- hasPlaceholder
- } = store;
- const showSearch = computed(() => store.showSearch);
- const title = computed(() => store.title);
+ hasPlaceholder,
+ scrollTop
+ } = toRefs(store);
+
const keyword = ref()
const goBack = () => {
@@ -60,7 +63,7 @@
const navbarStyle = computed(() => {
return {
- height: `${height}px`,
+ // height: `${height}px`,
backgroundColor: store.scrollTop >= 44 ? '#fff' : 'transparent'
};
});
@@ -70,21 +73,21 @@
towStyle: {}
});
onMounted(() => {
- // #ifdef MP-WEIXIN
+ // #ifdef MP-WEIXIN || MP-ALIPAY
const menuButtonInfo = uni.getMenuButtonBoundingClientRect();
const systemInfo = uni.getSystemInfoSync();
const statusBarHeight = systemInfo.statusBarHeight;
- console.log(menuButtonInfo)
// 计算标题的垂直偏移量
+ const verticalOffset = menuButtonInfo.top;
// const verticalOffset = menuButtonInfo.top - statusBarHeight;
- const verticalOffset = menuButtonInfo.top > menuButtonInfo.height ? menuButtonInfo.height : Math.abs(
- menuButtonInfo.top - menuButtonInfo.height)
+ // const verticalOffset = menuButtonInfo.top > menuButtonInfo.height ? menuButtonInfo.height : Math.abs(
+ // menuButtonInfo.top - menuButtonInfo.height)
const titleHeight = menuButtonInfo.height;
centerContentStyle.oneStyle = {
paddingTop: `${verticalOffset}px`,
paddingRight: `${menuButtonInfo.width +20}px`,
// paddingTeft: `${menuButtonInfo.width +20}px`,
- height: `${height}px`,
+ // height: `${height}px`,
boxSizing: 'border-box',
};
centerContentStyle.towStyle = {
diff --git a/components/indexnav.vue b/components/indexnav.vue
index 9b5fe3a..b997475 100644
--- a/components/indexnav.vue
+++ b/components/indexnav.vue
@@ -29,16 +29,16 @@
diff --git a/pages/index/text.vue b/pages/index/text.vue
index 6535954..edf7123 100644
--- a/pages/index/text.vue
+++ b/pages/index/text.vue
@@ -1,6 +1,6 @@
-
+
@@ -15,7 +15,8 @@
import {
onLoad,
onReady,
- onShow
+ onShow,
+ onPageScroll
} from '@dcloudio/uni-app'
import Nav from '@/components/CustomNavbar.vue'; //导航栏
// pinia管理
@@ -24,15 +25,23 @@
} from '@/stores/navbarStore';
const store = useNavbarStore();
+ // 大于44显示导航栏
+ const navScroll = ref(false)
+
// 动态更新导航栏配置
store.updateNavbarConfig({
showBack: true, //左边返回键
rightText: '', //右边文字
showSearch: true, //true是标题其他事文字
- title: '我的页面',
+ title: '',
isTransparent: false,
hasPlaceholder: false //是否要占位符
});
+
+ //动态导航栏滑动距离
+ onPageScroll((res) => {
+ uni.$u.debounce(store.scrollTop = res.scrollTop, 500)
+ });
\ No newline at end of file
diff --git a/pages/product/components/shopindex.vue b/pages/product/components/shopindex.vue
new file mode 100644
index 0000000..6d123bb
--- /dev/null
+++ b/pages/product/components/shopindex.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+ {{ shopInfo.shopName }}
+
+
+
+
+ 商家信息
+
+
+ 营业时间:
+ {{ (shopInfo.businessStartDay || '--') +'至'+ (shopInfo.businessEndDay || '--') +' '+ (shopInfo.businessTime || '')}}
+
+
+ 商家地址:
+ {{ shopInfo.address }}
+
+
+ 商家电话:
+ {{ shopInfo.phone }}
+
+
+ 商家公告
+
+
+ 公告:
+ {{ shopInfo.detail }}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/product/components/shoppingCartBilling.vue b/pages/product/components/shoppingCartBilling.vue
new file mode 100644
index 0000000..8e5c59e
--- /dev/null
+++ b/pages/product/components/shoppingCartBilling.vue
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+ {{cartLists_count<99?cartLists_count:'99+'}}
+
+
+ ¥
+ {{cartLists.memberAmount||'0.00'}}
+ {{cartLists.amount||'0.00'}}
+
+
+ 去结算
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/product/components/shoppingCartes.vue b/pages/product/components/shoppingCartes.vue
new file mode 100644
index 0000000..8a31181
--- /dev/null
+++ b/pages/product/components/shoppingCartes.vue
@@ -0,0 +1,397 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+ {{item.id == i.productId && item.skuId == i.id ? i.specInfo :""}}
+
+
+
+
+ ¥
+
+ {{shopInfo.isVip ==1?item.memberPrice:item.salePrice}}
+
+
+
+
+
+
+
+
+
+ {{ ifcartNumber(item) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/product/index.vue b/pages/product/index.vue
index c0921fa..559f358 100644
--- a/pages/product/index.vue
+++ b/pages/product/index.vue
@@ -1,8 +1,349 @@
-
-
+
+
+
+
+
+
+ {{ shopInfo.shopName }}
+
+
+ 距离您{{ distance }}
+
+
+
+ 营业时间:{{ (shopInfo.businessStartDay || '--') +' 至 '+ (shopInfo.businessEndDay || '--') +' '+ (shopInfo.businessTime || '')}}
+
+
+ 查看
+
+
+
+
+
+ 本店招牌菜
+
+
+
+
+
+
+
+ {{ item.name }}
+
+
+ 本店回头客第{{index+1}}名
+
+
+ 招牌
+
+
+
+
+
+ ¥
+
+ {{shopInfo.isVip ==1?item.memberPrice:item.salePrice}}
+
+ ¥{{item.originPrice}}
+
+ /{{item.unitName}}
+
+
+
+
+ 非可售时间
+ 已售罄
+
+
+
+
+
+
+
+ ¥
+
+ {{shopInfo.isVip ==1?item.memberPrice:item.salePrice}}
+
+ ¥{{item.originPrice}}
+
+ /{{item.unitName}}
+
+
+
+
+
+
+ 选择套餐
+ 选规格
+ {{ ifcartNumber(item) <99?ifcartNumber(item):'99+'}}
+
+
+
+
+
+
+
+ {{ ifcartNumber(item) }}
+ {{item.suitNum<99?item.suitNum:'99+'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+ TOP{{index1+1}}
+
+ {{ item1.name }}
+
+ 热销
+ {{item1.shortTitle?item1.shortTitle:''}}
+
+
+
+ ¥
+ {{ item1.memberPrice }}
+ ¥
+
+ {{ item1.salePrice }}
+ /{{item1.unitName}}
+
+
+
+ 非可售时间
+ 已售罄
+
+
+
+
+
+ ¥
+ {{ item1.memberPrice }}
+ ¥
+
+ {{ item1.salePrice }}
+ /{{item1.unitName}}
+
+
+
+
+ 选择套餐
+ 选规格
+ {{ ifcartNumber(item1) <99?ifcartNumber(item1):'99+'}}
+
+
+
+
+
+
+
+
+
+
+ {{ ifcartNumber(item1) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{cartLists_count<99?cartLists_count:'99+'}}
+
+
+ ¥
+
+
+
+ 去结算
+
+
+
+
+
+
+
+
+
+
+
+ {{specifications.item.name}}
+ {{specifications.item.shortTitle?specifications.item.shortTitle:''}}
+
+
+
+
+ {{specType }}
+
+
+
+ {{option}}
+
+ 售罄
+
+
+
+
+
+
+
+
+ {{specifications.groupSnap.count }} 选 {{specifications.groupSnap.number }}
+
+
+
+ {{option.proName}}/{{option.skuName}}
+
+ 售罄
+
+
+
+
+
+
+
+
+ ¥
+ {{shopInfo.isVip ==1?specifications.item.memberPrice:specifications.item.salePrice}}
+ /{{specifications.item.unitName}}
+
+
+
+
+
+
+
+ {{ shopCartNumber }}
+
+
+
+
+
+
+
+
+ {{selectedSpecsStr }}
+
+
+ {{skuBtnText}}
+
+
+
+
+
+
@@ -10,38 +351,1579 @@
import {
ref,
reactive,
- onMounted
+ onMounted,
+ watchEffect,
+ getCurrentInstance,
+ computed
} from "vue";
+
import {
onLoad,
onReady,
onShow,
onPageScroll
} from '@dcloudio/uni-app'
- import Nav from '@/components/CustomNavbar.vue'; //导航栏
+
+ //导航栏
+ import Nav from '@/components/CustomNavbar.vue';
+ import shopindex from './components/shopindex.vue'
+ import shoppingCartes from './components/shoppingCartes.vue'
+ // 获取全局属性
+ const {
+ proxy
+ } = getCurrentInstance();
+
+ //接口引入
+ import {
+ productminiApphotsquery,
+ APIgroupquery,
+ APIminiAppinfo,
+ APIminiAppskuinfo
+ } from "@/common/api/product/product.js";
+
+ // websocket
+ import useWebSocket from '@/common/js/websocket.js';
+
// pinia管理
import {
useNavbarStore
} from '@/stores/navbarStore';
const store = useNavbarStore();
+
+ import {
+ productStore
+ } from '@/stores/user.js';
+
+ const userStore = productStore();
+
// 动态更新导航栏配置
store.updateNavbarConfig({
showBack: true, //左边返回键
rightText: '', //右边文字
- showSearch: false, //true是标题其他事文字
+ showSearch: true, //true是标题其他事文字
title: '',
isTransparent: false,
hasPlaceholder: false //是否要占位符
});
-
- // 标题滑动滑动
+
+ const userInfo = uni.cache.get('userInfo')
+ const shopInfo = uni.cache.get('shopInfo')
+ const shopTable = uni.cache.get('shopTable')
+ const distance = uni.cache.get('distance') //距离
+
+
+ //店铺详情
+ const showShopInfoRef = ref(null)
+
+ //调用shop组件
+ const callChildMethod = () => {
+ if (showShopInfoRef.value) {
+ showShopInfoRef.value.childMethod();
+ }
+ }
+
+
+ const shopExtend = reactive({
+ autokey: "index_bg",
+ createTime: "2024-08-27T06:59:35.000+00:00",
+ id: 17,
+ name: "首页",
+ shopId: 29,
+ type: "img",
+ updateTime: null,
+ value: "https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240827/4e58171d813a45269997085b145b8bfe.png"
+ })
+
+ // 计算高度
+ const navScroll = ref(null)
+
+ // 获取商品数据
+ const shopProductList = reactive({
+ hots: [],
+ productInfo: [],
+ })
+
+ // * 图片加载
+ const imageLoaded = (item, index, index1) => {
+ // shopProductList.productInfo[index].products[index1]['imgLoad'] = true;
+ }
+
+ // 计算左侧位置
+ const leftIndex = ref(0)
+
+ //距离顶部的高度
+ const scrollTopSiz = ref(0)
+
+ //元素最低端的距离
+ const lastbottom = ref('')
+
+ //储存元素的下标
+ const topArr = ref([])
+
+ // 填充高度,用于最后一项低于滚动区域时使用
+ const fillHeight = ref(0)
+
+ //距离顶部的高度
+ const scrollTopSize = ref(0)
+
+ //左侧导航点击
+ const leftTap = (index) => {
+ uni.pageScrollTo({
+ scrollTop: topArr.value[index] - store.height,
+ duration: 0
+ });
+ leftIndex.value = index
+ }
+
+ /* 计算左侧滚动位置定位 */
+ const leftIntoView = computed(() => {
+ return `left-${leftIndex.value? leftIndex.value:0}`
+ })
+
+ /* 获取元素顶部信息 */
+ const getElementTop = () => {
+ new Promise((resolve, reject) => {
+ let view = uni.createSelectorQuery().selectAll('.main-item');
+ view.boundingClientRect(async data => {
+ resolve(data);
+ }).exec();
+ proxy.$uGetRect('.scroll-panel').then(res => {
+ scrollTopSize.value = res.top; //元素距离顶部的距离
+ })
+ }).then((res) => {
+ try {
+ topArr.value = res.map((item) => {
+ return item.top; /* 减去滚动容器距离顶部的距离 加导航栏高度*/
+ });
+
+ // 获取最后一个元素最低端的盒子到顶点的距离
+ for (let i = 0; i <= (topArr.value.length - 1); i++) {
+ if ((store.screenHeight - 200) >= (topArr.value[topArr.value.length - 1] - topArr.value[
+ i])) {
+ // 获取距离最后一个index
+ lastbottom.value = i;
+ break;
+ }
+ }
+ /* 获取最后一项的高度,设置填充高度。判断和填充时做了 +-20 的操作,是为了滚动时更好的定位 */
+ let last = res[res.length - 1].height;
+ if (last - 20 < store.screenHeight) {
+ fillHeight.value = 200;
+ }
+ } catch (error) {
+ //TODO handle the exception
+ }
+ });
+ }
+
+ // 定时器
+ const mainThrottle = ref(null)
+
+ /* 主区域滚动监听 */
+ const mainScroll = (e) => {
+ // 节流方法
+ clearTimeout(mainThrottle.value);
+ mainThrottle.value = setTimeout(() => {
+ scrollFn();
+ }, 10);
+ let scrollFn = () => {
+ let top = e.scrollTop;
+ let index = 0;
+ // 判断左边是否可以滑动
+
+ for (let i = (topArr.value.length - 1); i >= 0; i--) {
+ /* 在部分安卓设备上,因手机逻辑分辨率与rpx单位计算不是整数,滚动距离与有误差,增加2px来完善该问题 */
+ if ((top + 2) >= topArr.value[i] - store.height) {
+ index = i;
+ break;
+ }
+ }
+ /* 查找当前滚动距离 */
+ if (index >= lastbottom.value) { //
+ leftIndex.value = index > leftIndex.value ? index : leftIndex.value
+ // this.leftIndex = this.leftIndex
+ } else {
+ leftIndex.value = (index < 0 ? 0 : index);
+ }
+ }
+ }
+
+ //动态导航栏滑动距离
onPageScroll((res) => {
- // isSticky.value = res.scrollTop > elementTop.value ? true : false
- // uni.$u.debounce(store.scrollTop = res.scrollTop, 500)
+ uni.$u.debounce(store.scrollTop = res.scrollTop, 500)
+ uni.$u.debounce(navScroll.value = res.scrollTop, 500)
+ uni.$u.debounce(mainScroll(res), 500)
});
+
+ // 点击详情
+ const showShopsku = ref(false)
+
+ // 规格信息
+ const specifications = reactive({
+ item: {},
+ index: '',
+ inedxs: '',
+ type: '',
+ product_id: '',
+ sku_id: '',
+ groupSnap: {
+ goods: []
+ }
+ })
+
+ /* 价格 */
+ const salePrice = computed(() => {
+ // return shopInfo.isVip == 1 && memberPrice > 0 ? res.data.memberPrice : res.data.salePrice
+ return 0
+ })
+
+ // 用于判断接口数据是否加载完成
+ const isDataLoaded = ref(false);
+
+ // 存储用户当前选择的规格,初始为空对象
+ const selectedSpecs = ref({});
+
+ // 能否提交的状态
+ const canSubmit = ref(false);
+
+ //字形判断
+ const skuBtnText = ref('添加到购物车')
+
+ // 计算属性,判断是否所有规格类型都有选中项
+ const allSpecsSelected = computed(() => {
+ // 获取所有规格类型的键
+ const specKeys = Object.keys(specifications.item.selectSpecInfo);
+ // skuBtnText.value = selectedSpecsStr.value ? `您还没选择${specKeys[1]}哦` : ``
+ // 检查每个规格类型是否都在 selectedSpecs 中有对应的选中值
+ return specKeys.every(key => selectedSpecs.value[key]);
+ });
+
+ // 处理规格选择的方法
+ const selectSpec = async (specType, option) => {
+ // 规格清零
+ shopCartNumber.value = 0
+ // 更新 selectedSpecs 对象,将当前规格类型的选中值设置为用户点击的选项
+ selectedSpecs.value = {
+ ...selectedSpecs.value,
+ [specType]: option
+ };
+ if (allSpecsSelected.value) {
+ try {
+ let result = await APIminiAppskuinfo({
+ specInfo: selectedSpecsStr.value,
+ id: specifications.item.id
+ });
+ specifications.sku_id = result.id
+ specifications.product_id = result.productId
+ specifications.item = Object.assign({}, result, specifications.item);
+ if (result.isPauseSale == 0) {
+ canSubmit.value = true;
+ skuBtnText.value = '添加到购物车'
+ }
+ } catch (error) {
+ canSubmit.value = false;
+ }
+ } else {
+ canSubmit.value = false;
+ }
+ };
+
+ // 存储选中的选项
+ const selectedOptions = ref([]);
+
+ // 选择规格的方法
+ const goodsidClick = (option, goodsid) => {
+ if (isOptionSelected(option)) {
+ // 如果已经选中,取消选中
+ selectedOptions.value = selectedOptions.value.filter(item => item.proId !== option.proId);
+ } else if (!isMaxSelected()) {
+ // 如果未达到最大选择数量,添加到选中列表
+ selectedOptions.value.push(option);
+ }
+ };
+
+ // 判断选项是否已选中
+ const isOptionSelected = (option) => {
+ return selectedOptions.value.some(item => item.proId == option.proId);
+ };
+
+ // 判断是否达到最大选择数量
+ const isMaxSelected = () => {
+ // 初始他为可点击
+ if (selectedOptions.value.length >= specifications.groupSnap.number) {
+ canSubmit.value = true;
+ } else {
+ canSubmit.value = false;
+ }
+ return selectedOptions.value.length >= specifications.groupSnap.number;
+ };
+
+ // 计算属性,将 selectedSpecs 转换为字符串形式
+ const selectedSpecsStr = computed(() => {
+ const values = Object.values(selectedSpecs.value);
+ return values.join(',');
+ });
+
+ //添加购物车数量
+ const shopCartNumber = ref(0)
+
+ // 多规格 去添加购物车
+ const shopCart = (i) => {
+ if (i == '+') {
+ shopCartNumber.value++;
+ } else {
+ shopCartNumber.value--;
+ }
+ }
+
+ // 使用 find 方法查找购物车是否有匹配的数组
+ const matchingProduct = async (data) => {
+ return matchedProducts.value.find(product => {
+ if (data.type === 'single') {
+ return product.skuId == data.skuId && product.id == data.id
+ } else {
+ return product.skuId == data.sku_id && product.id == data.product_id
+ }
+ });
+ }
+
+ // 提交选择并执行下一步操作的方法
+ const submitSelection = async () => {
+ if (!canSubmit.value) {
+ return false;
+ }
+ let res = await matchingProduct(specifications)
+ if (res) {
+ await calculateValue(res.cartNumber, '+', shopCartNumber.value)
+ }
+ // 是否是套餐 有就传
+ if (selectedOptions.value) {
+ specifications.groupSnap.goods = selectedOptions.value
+ }
+ websocketsendMessage({
+ type: 'shopping',
+ table_code: uni.cache.get('tableCode'),
+ shop_id: uni.cache.get('shopId'),
+ operate_type: res ? 'edit' : 'add',
+ product_id: specifications.product_id,
+ sku_id: specifications.sku_id,
+ number: res ? await calculateValue(res.cartNumber, '+', shopCartNumber
+ .value) : shopCartNumber.value,
+ pro_group_info: specifications.groupSnap
+ })
+ showShopsku.value = false
+ // 这里可以添加更多的业务逻辑,例如发送请求到后端等
+ }
+
+ //获取多规格数据
+ const clickspecifications = async (item, index, indexs, type) => {
+ console.log(item, index, indexs, type)
+ // 数量清零
+ shopCartNumber.value = 0
+ // 初始化
+ let data = {
+ item: item,
+ index: '',
+ inedxs: '',
+ type: '',
+ product_id: '',
+ sku_id: ''
+ }
+ Object.assign(specifications, data);
+ // 初始化 多规格选中
+ selectedSpecs.value = {}
+ canSubmit.value = false
+ skuBtnText.value = '请选择规格'
+ // single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券
+ let res = await APIminiAppinfo(item.id)
+ specifications.item = res
+ if (specifications.item.type == "package") {
+ selectedOptions.value = []
+ specifications.product_id = item.id
+ specifications.sku_id = item.skuId
+ specifications.groupSnap = res.groupSnap[0]
+ }
+ // 购物车是否有商品
+ specifications.item.cartListId = await matchingProduct(specifications.item) ? item.cartListId : ''
+ specifications.index = index
+ specifications.indexs = indexs
+ specifications.type = type
+ specifications.item.selectSpecInfo = Object.fromEntries(
+ Object.entries(specifications.item.selectSpecInfo).filter(([_, value]) => value.length > 0)
+ );
+ // 给默认数量
+ specifications.item.amountcartNumber = 0
+ showShopsku.value = true
+ }
+
+ // 单规格
+ const singleclick = async (item, i) => {
+ if (selectedOptions.value.length > 0) {
+ specifications.groupSnap.goods = selectedOptions.value
+ }
+ // 判断购物车是否有该选中商品
+ let res = await matchingProduct(item)
+ console.log(res)
+ websocketsendMessage({
+ id: res ? item.cartListId : '',
+ type: 'shopping',
+ table_code: uni.cache.get('tableCode'),
+ shop_id: uni.cache.get('shopId'),
+ operate_type: await calculateValue(item.cartNumber, i) == 'del' ? 'del' : res ? 'edit' : 'add',
+ product_id: item.id,
+ sku_id: item.skuId,
+ number: await calculateValue(item.cartNumber, i),
+ pro_group_info: specifications.groupSnap,
+ })
+ }
+
+ // 封装加法函数
+ const calculateValue = (cartNumber, i, step = 1) => {
+ if (i == '+') {
+ const result = parseFloat(cartNumber) + step;
+ return result.toFixed(2);
+ } else {
+ // 当减到0返回del
+ const result = parseFloat(cartNumber) - step;
+ return result == 0 ? 'del' : result.toFixed(2);
+ }
+ }
+
+ // WebSocket处理 // 初始化配置
+ const options = {
+ initMessage: {
+ type: 'shopping',
+ operate_type: 'init',
+ table_code: uni.cache.get('tableCode'),
+ shop_id: uni.cache.get('shopId')
+ }
+ }
+
+ const {
+ isConnected,
+ sendMessage,
+ closeSocket: manualClose,
+ receivedMessages
+ } = useWebSocket(options);
+
+
+ //购物车显示
+ const showCart = ref(false)
+
+ // 购物车数组
+ const cartList = ref([])
+
+ // 更新商品数量的方法
+ const updateProductQuantities = () => {
+ // 遍历购物车数组
+ if (cartListFilter.value.length > 0) {
+ cartListFilter.value.forEach((cartItem) => {
+ shopProductList.productInfo.forEach((group) => {
+ group.productList.forEach((product) => {
+ if (product.id == cartItem.product_id && product.skuId == cartItem
+ .sku_id) {
+ product.cartNumber = cartItem.number
+ product.cartListId = cartItem.id
+ }
+ });
+ });
+ });
+ // 遍历购物车数组
+ cartListFilter.value.forEach((cartItem) => {
+ // 遍历商品列表二维数组
+ shopProductList.hots.forEach((group) => {
+ // 商品 id 匹配
+ if (group.id == cartItem.product_id) {
+ // 更新商品的数量
+ group.cartListId = cartItem.id
+ group.cartNumber = cartItem.number
+ }
+ });
+ });
+ } else {
+ shopProductList.hots.forEach((i) => {
+ i.cartNumber = 0
+ })
+ // 遍历商品列表二维数组
+ shopProductList.productInfo.forEach((group) => {
+ group.productList.forEach((product) => {
+ product.cartNumber = 0
+ });
+ });
+ }
+ }
+
+ //websocket产值
+ const websocketsendMessage = (data) => {
+ sendMessage(data)
+ }
+
+ // 监听接收到的消息变化
+ watchEffect(async () => {
+ if (isDataLoaded.value && receivedMessages.value.length > 0) {
+ const Message = receivedMessages.value[receivedMessages.value.length - 1];
+ if (Message) {
+ // 心跳返回 过滤
+ if (Message.type == "p") {
+ return false
+ }
+
+ // 清空购物车
+ if (Message.operate_type == 'shopping_cleanup') {
+ cartList.value = []
+ showCart.value = false
+ }
+
+ // 初始化购物车数据
+ if (Message.operate_type == "shopping_init") {
+ cartList.value = Message.data
+ }
+
+ // 删除除购物车
+ if (Message.operate_type == 'shopping_del') {
+ cartList.value = cartList.value.filter(item => item.id !== Message.data.id);
+ }
+
+ // 添加或者减少购物后返回
+ if (Message.operate_type == 'shopping_add' || Message.operate_type == 'sopping_edit') {
+ [Message.data].forEach((objA) => {
+ const index = cartList.value.findIndex((objB) => objB.id == objA.id);
+ if (index !== -1) {
+ cartList.value[index] = objA;
+ } else {
+ cartList.value.push(objA);
+ }
+ });
+ }
+
+ //除去p 每次返回都回执消息
+ await websocketsendMessage({
+ type: 'receipt',
+ msg_id: Message.msg_id
+ })
+
+ // if(Message.status != 1){
+ // uni.showToast({
+ // title:'操作失败请稍后重试~'
+ // })
+ // }
+
+ // 初始化商品数量
+ await updateProductQuantities()
+
+ }
+ }
+ })
+
+ // 更新购物车数据
+ const matchedProducts = computed(() => {
+ return cartList.value.map((cartItem) => {
+ for (const group of shopProductList.productInfo) {
+ for (const product of group.productList) {
+ if (product.id == cartItem.product_id) {
+ console.log(cartItem, product)
+ // 找到匹配的商品,添加 cartListId 属性
+ return {
+ ...product,
+ // cartListinfo:cartItem
+ cartListId: cartItem.id,
+ cartNumberToAdd: product.type == 'weight' ? 1 : cartItem.number //增加一个数量算法
+ };
+ }
+ }
+ }
+ // 如果没找到匹配的商品,返回 null 或者其他默认值,这里返回 null
+ return null;
+ }).filter(item => item !== null);
+ })
+
+ // 计算购物车商品总数量
+ const cartLists_count = computed(() => {
+ return matchedProducts.value.reduce((sum, item) => {
+ // 将 cartNumberToAdd 转换为数字
+ const num = typeof item.cartNumberToAdd === 'string' ? parseFloat(item.cartNumberToAdd) : item
+ .cartNumberToAdd;
+ return sum + num;
+ }, 0);
+ });
+
+ // 定义 ifcartNumber 计算属性方法 展示数量
+ const ifcartNumber = computed(() => {
+ return (item) => {
+ // 如果 item 为空或者 cartNumber 不是字符串类型,返回 0
+ if (!item || typeof item.cartNumber !== 'string') {
+ return 0;
+ }
+ let numValue = parseFloat(item.cartNumber);
+ if (isNaN(numValue)) {
+ // 如果转换结果是 NaN,说明 cartNumber 不是有效的数字字符串,返回 0
+ return 0;
+ }
+ // type string 商品类型 single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券
+ if (item.type === 'weight') {
+ // 如果类型是称重重量,将值保留两位小数
+ return parseFloat(numValue.toFixed(2));
+ } else {
+ // 如果类型是整数,将值转换为整数
+ return Math.round(numValue);
+ }
+ // 如果类型不匹配,返回原始值
+ return item.cartNumber;
+ };
+ })
+
+
+ // 计算处理后的购物车列表 // 用于筛选后的购物车数组
+ const cartListFilter = computed(() => {
+ console.log(cartList.value)
+ // 使用 reduce 方法对 cartList 进行处理
+ const grouped = cartList.value.reduce((acc, item) => {
+ const productId = item.product_id;
+ const num = parseFloat(item.number);
+
+ if (!acc[productId]) {
+ // 如果 acc 中还没有该 product_id 的记录,创建一个新对象
+ acc[productId] = {
+ ...item,
+ number: num
+ };
+ } else {
+ // 如果已经有该 product_id 的记录,将当前对象的 number 值累加到已有记录的 number 属性上
+ acc[productId].number += num;
+ }
+ return acc;
+ }, {});
+ // 将累加结果保留两位小数,并将对象转换为数组
+ return Object.values(grouped).map(item => ({
+ ...item,
+ number: item.number.toFixed(2)
+ }));
+ })
+
+ // 结账
+
+ const orderdetail = () => {
+
+ if (this.cartLists.data.length == 0) {
+ uni.showToast({
+ title: '请先添加商品',
+ icon: 'none'
+ })
+ return false
+ }
+
+ }
+
+ // 列表请求
+ const productqueryProduct = async () => {
+ shopProductList.hots = await productminiApphotsquery()
+ shopProductList.productInfo = await APIgroupquery()
+ //第一步:将所有商品的 cartNumber 初始化为 0
+ shopProductList.productInfo.forEach((group) => {
+ group.productList.forEach((product) => {
+ product.cartNumber = 0;
+ });
+ });
+ shopProductList.hots.forEach((i) => {
+ i.cartNumber = 0
+ })
+ scrollTopSize.value = 0
+ topArr.value = []
+ userStore.actionsAPIuser()
+ userInfo.value = uni.cache.get('userInfo')
+ // 数据可以更新
+ isDataLoaded.value = true;
+ }
+
+ onLoad(async (e) => {
+ await proxy.$onLaunched;
+ })
+
+ onMounted(async () => {
+ await productqueryProduct()
+ setTimeout(() => {
+ getElementTop()
+ }, 500)
+ })
\ No newline at end of file
diff --git a/pages/user/coupon.vue b/pages/user/coupon.vue
index b91d16d..a9af141 100644
--- a/pages/user/coupon.vue
+++ b/pages/user/coupon.vue
@@ -166,7 +166,7 @@
params.shopId = this.shopId;
}
let res = await this.api.conponList(params)
- if (res.code == 0) {
+ if (res) {
console.log(res)
let list = [];
if (this.type == 'confirm_order_coupon' || this.type == 'orderInfo_coupon') {
@@ -331,7 +331,7 @@
} else {
- uni.pro.navigateTo('/pages/order_food/order_food', {
+ uni.pro.navigateTo('/pages/product/index', {
shopId: item.shopId
})
}
diff --git a/pages/user/user.vue b/pages/user/user.vue
index 4a66e6d..9e58dcc 100644
--- a/pages/user/user.vue
+++ b/pages/user/user.vue
@@ -9,7 +9,7 @@
{{userInfo.nickName || '无'}}
-
@@ -21,11 +21,26 @@
我的资产
-
-
- {{item.name}}
- {{item.num || '**'}}
+
+
+
+ 储值
+ {{userInfo.assetsSummary.amount || '0'}}
+
+
+
+
+ 积分
+ {{userInfo.assetsSummary.couponNum ||'0'}}
+
+
+
+
+ 优惠券
+ {{userInfo.assetsSummary.points ||'0'}}
@@ -33,8 +48,8 @@
我的功能
-
+
{{item.name}}
@@ -63,28 +78,10 @@
onReady,
onShow
} from '@dcloudio/uni-app'
- const myAssetsList = ref([
- [{
- name: "储值",
- type: "recharge",
- num: 0,
- icon: "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/my/storedValue.png"
- },
- {
- name: "积分",
- type: "points",
- num: 0,
- icon: "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/my/points.png"
- },
- {
- name: "优惠券",
- type: "my_coupon",
- num: 0,
- icon: "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/my/coupon.png"
- },
- // { name: "权益卡", type: "", num: 0, icon: "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/my/equityCard.png"}
- ]
- ])
+ import {
+ productStore
+ } from '@/stores/user.js';
+ const store = productStore();
const myFunList = ref([{
name: "我的优惠券",
type: "my_coupon",
@@ -108,15 +105,40 @@
},
// { name: "关于", type: "", icon: "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/my/inRegard.png"},
])
- const shopInfo = reactive({
- isVip: 0
- })
- const userInfo = reactive({
- nickName: '无名',
- headImg: 'https://czg-qr-order.oss-cn-beijing.aliyuncs.com/my/my_member.png'
- })
const teblist = ref([])
const shopExtend = ref(null)
+ const userInfo = ref({
+ headImg: '',
+ nickName: '',
+ isVip: '',
+ assetsSummary: {
+ amount: 0,
+ couponNum: 0,
+ points: 2
+ }
+ })
+ const clickEvent = () => {
+ if (uni.cache.get('shopId') && uni.cache.get('token')) {
+ if (this.userInfo.isVip == 0) {
+ uni.pro.navigateTo('member/memberdetails', {
+ shopId: uni.cache.get('shopId')
+ })
+ } else {
+ uni.navigateTo({
+ url: '/pages/pay_code/pay_code?userInfo=' + JSON.stringify(this.userInfo)
+ })
+ }
+ } else {
+ uni.pro.navigateTo('member/list', {
+ type: 'user_payCode'
+ })
+ }
+ }
+ onShow(async () => {
+ await store.actionsAPIuser()
+ userInfo.value = uni.cache.get('userInfo')
+ console.log(userInfo.value, 11)
+ })