cashier_wx/pages/product/index - 副本.vue

2632 lines
69 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<Nav />
<!-- 顶部面板 -->
<view class="top--panel" :class="{ 'grayscale':!isBusinessTime }">
<image class="panelimgbackground"
:src="shopExtend?shopExtend.value:'https://czg-qr-order.oss-cn-beijing.aliyuncs.com/shopDetails/topBanner.png'"
mode="aspectFill">
</image>
<view class="panelone flex-start">
<view class="u-flex u-flex-y-center">
<text>
{{ shopInfo.shopName }}
</text>
<view class="u-flex u-flex-y-center u-m-t-4">
<up-icon name="arrow-right" color="#999999" size="14"></up-icon>
</view>
</view>
<!-- <up-icon name="arrow-right" color="#999999" size="14"></up-icon> -->
</view>
<view class="paneltow" v-if="distance">
距离您{{ distance }}
</view>
<view class="panelthere flex-between">
<view class="paneltheretext">
营业时间:{{ (shopInfo.businessStartDay || '--') +' 至 '+ (shopInfo.businessEndDay || '--')}}
{{endTimeref.startTime}} -
{{endTimeref.endTime < '05'?` 凌晨${endTimeref.endTime}`:endTimeref.endTime}}
</view>
<view class="flex-start" @click="callChildMethod">
<view style="margin-right: 14rpx;">查看</view>
<up-icon name="arrow-down" color="#999999" size="14"></up-icon>
</view>
</view>
<!-- 本店招牌菜 -->
<view class="panelfour" v-if="shopProductList.hots && shopProductList.hots.length > 0">
本店招牌菜
</view>
<view class="panelfive ">
<scroll-view :scroll-x="true" :scroll-with-animation="false">
<view class="panelfive_list">
<view class="panelfiveitem" @click="clickspecifications(item,index,index,'热销')"
v-for="(item,index) in shopProductList.hots" :key="index">
<image class="panelfiveitemimage" :src="item.coverImg" mode="aspectFill"></image>
<view class="vifgoodsImg flex-center"
v-if="item.isSale == 0 || (item.isSaleTime == 0 && !item.isSaleTimeshow) || item.isSoldStock == 1 || (item.isStock == 1 && item.stockNumber <= 0)">
<image v-if="item.isSale == 0" src="@/static/ztt/icon_goods_yxj.svg"
style="width:200rpx; height: 100%;" mode=""></image>
<image v-else-if="(item.isSaleTime == 0 && !item.isSaleTimeshow)"
src="@/static/ztt/icon_goods_wks.svg" style="width:200rpx; height: 100%;" mode="">
</image>
<image v-else-if="item.isSoldStock == 1" src="@/static/ztt/icon_goods_sq.svg"
style="width:200rpx; height: 100%;" mode=""></image>
<image v-else-if="item.isStock == 1 && item.stockNumber <= 0"
src="@/static/ztt/icon_goods_kcbz.svg" style="width:200rpx; height: 100%;" mode="">
</image>
</view>
<view class="panelfiveitemone">
{{ item.name }}
</view>
<view class="panelfiveitemtow">
本店回头客第{{index+1}}名
</view>
<view class="panelfiveitemthere flex-between">
<text>招牌</text>
<view class="describe" v-if="item.suitNum>1 && item.type!= 'sku'"
style="font-size: 20rpx;margin-top: 10rpx;">
「{{item.suitNum}}{{item.unitName}}起点」
</view>
</view>
<!-- <view class="panelfiveitemfour">
{{item.shortTitle?item.shortTitle:''}}
</view>
<view class="panelfiveitemfive">
月售{{item.stockNumber}}
</view> -->
<view v-if="item.isSoldStock == 1 || (item.isSaleTime == 0 && !item.isSaleTimeshow)"
class="flex-between" style="margin-top: 32rpx;margin-bottom: 48rpx;">
<view class="panelfiveitemsex flex-between">
<view class="panelfiveitemsex_oen">
<text class="tips"
:class="shopInfo.isVip == 0 || shopInfo.isMemberPrice==0?'lineThrough':''">¥</text>
<!-- 会员价与价格 -->
<text class="price">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1?(item.memberPrice||item.salePrice):item.salePrice}}
</text>
<!-- 单位 -->
<text class="unit" v-if="item.unitName">/{{item.unitName}}</text>
</view>
</view>
<view class="panelfiveitemNum">
<view class="sku-wrap flex-center" style="background-color: #CECECE;">
<text class="t" v-if="(item.isSaleTime == 0 && !item.isSaleTimeshow)">未开售</text>
<text class="t" v-if="item.isSoldStock == 1">已售罄</text>
</view>
</view>
</view>
<view v-else class="flex-between"
style="margin-top: 32rpx;margin-bottom: 48rpx; flex-wrap: inherit">
<view class="panelfiveitemsex flex-between">
<view class="panelfiveitemsex_oen">
<text class="tips"
:class="shopInfo.isVip ==0 || shopInfo.isMemberPrice==0?'lineThrough':''">¥</text>
<!-- 会员价与价格 -->
<text class="price">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1?(item.memberPrice|| item.salePrice):item.salePrice}}
</text>
<text class="unit" v-if="item.unitName">/{{item.unitName}}</text>
<!-- <text v-if="item.suitNum>1 && item.type!= 'sku'"
style="font-size: 16rpx;">「{{item.suitNum}}{{item.unitName}}起点」</text> -->
</view>
</view>
<!-- single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券 -->
<view class="panelfiveitemNum">
<!-- v-if="item.type == 'single'|| item.type == 'weight' || item.type == 'coupon' || (item.type == 'package' && item.groupType=='0')" -->
<view class="sku-wrap flex-center"
v-if="item.type == 'sku' || (item.type == 'package' && item.groupType == '1')"
@click.stop="clickspecifications(item,index,index1)">
<text class="t" v-if="item.groupType == '1'">选择套餐</text>
<text class="t" v-else>选规格</text>
<text class="dot num"
v-if="item.cartNumber >0">{{ ifcartNumber(item) <99?ifcartNumber(item):'99+'}}</text>
</view>
<view class="Controls" v-else>
<view class="btn" v-if="item.cartNumber != '0'">
<up-icon name="minus-circle-fill" color="#E9AB7A" size="25"></up-icon>
<view class="btnClick"
@tap.stop="$u.throttle(() => singleclick(item, '-'), 500)">
</view>
</view>
<text class="num"> {{ ifcartNumber(item) }} </text>
<view class="btn">
<up-icon name="plus-circle-fill" color="#E9AB7A" size="25"></up-icon>
<view class="btnClick"
@tap.stop="$u.throttle(() => singleclick(item, '+'), 500)">
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
<!-- 滚动区域 -->
<view class="scroll-panel " id="scroll-panel" :class="{ 'grayscale':!isBusinessTime }">
<view class="list-box">
<view class="left" :style="{top: `${store.height}px`}">
<scroll-view :scroll-into-view="leftIntoView" :scroll-with-animation="false" :scroll-y="true"
:style="{height:`${store.screenHeight - store.height}px`}" style="padding-bottom: 200rpx;">
<view class="item" v-for="(item,index) in shopProductList.productInfo" :key="index"
:class="{ 'active':index==leftIndex }" :id="'left-'+index" :data-index="index"
@click="leftTap(index)"><text>{{item.name}}</text></view>
</scroll-view>
</view>
<view class="main">
<view>
<view class="item main-item" v-for="(item,index) in shopProductList.productInfo" :key="index"
:id="'item-'+index">
<view class="title">
<view>{{item.name}}</view>
</view>
<view class="goods" @click="clickspecifications(item1,index,index1)"
v-for="(item1,index1) in item.productList" :key="index1">
<image class="goodsImg" v-if="item1.coverImg!=null" :lazy-load="true"
@load="imageLoaded(item1,index,index1)"
:src="`${item1.coverImg}${!item1.imgLoad?'?x-oss-process=image/resize,m_lfit,w_150,h_150':''}`"
mode="aspectFill"></image>
<image class="goodsImg"
src="https://czg-qr-order.oss-cn-beijing.aliyuncs.com/index/1.gif" mode="" v-else
:lazy-load="true">
</image>
<view class="vifgoodsImg"
v-if="item1.isSale == 0 || (item1.isSaleTime == 0 && !item1.isSaleTimeshow) || item1.isSoldStock == 1 || (item1.isStock == 1 && item1.stockNumber <= 0)">
<image v-if="item1.isSale == 0" src="@/static/ztt/icon_goods_yxj.svg"
style="width:200rpx; height: 100%;" mode=""></image>
<image v-else-if="(item1.isSaleTime == 0 && !item1.isSaleTimeshow)"
src="@/static/ztt/icon_goods_wks.svg" style="width:200rpx; height: 100%;"
mode=""></image>
<image v-else-if="item1.isSoldStock == 1" src="@/static/ztt/icon_goods_sq.svg"
style="width:200rpx; height: 100%;" mode=""></image>
<image v-else-if="item1.isStock == 1 && item1.stockNumber <= 0"
src="@/static/ztt/icon_goods_kcbz.svg" style="width:200rpx; height: 100%;"
mode=""></image>
</view>
<view v-if="index=='0'" class="topSort" :class="'c'+(index1+1)">TOP{{index1+1}}</view>
<view class="goods_right" style="overflow: hidden;">
<view class="name">{{ item1.name }}</view>
<!-- <view class="lookBack" v-if="index=='0'">本店销量第{{index1+1}}名</view>-->
<view class="lookBack" v-if="specifications.item.isHot == 1">热销</view>
<view class="describe"> {{item1.shortTitle?item1.shortTitle:''}} </view>
<view class="describe" v-if="item1.suitNum>1 && item1.type!= 'sku'"
style="font-size: 20rpx;">
「{{item1.suitNum}}{{item1.unitName}}起点」
</view>
<view
v-if="item1.isSoldStock == 1 || (item1.isSaleTime == 0 && !item1.isSaleTimeshow)"
class="flex-between">
<view class="money">
<view>¥</view>
<text class="money_num" style="margin-right: 10rpx;">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1 ?(item1.memberPrice||item1.salePrice):item1.salePrice}}
</text>
<text v-if="item1.unitName">/{{item1.unitName}}</text>
</view>
<view class="flex-end">
<view class="sku-wrap flex-center" style="background-color: #CECECE;">
<text class="t"
v-if="(item1.isSaleTime == 0 && !item1.isSaleTimeshow)">未开售</text>
<text class="t" v-else-if="item1.isSoldStock == 1">已售罄</text>
</view>
</view>
</view>
<view v-else class="flex-between" style="flex-wrap: inherit;">
<view class="money">
<view>¥</view>
<text class="money_num">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1?(item1.memberPrice||item1.salePrice):item1.salePrice}}
</text>
<text class="money_num" v-if="item1.unitName">/{{item1.unitName}}</text>
<!-- <text v-if="item1.suitNum>1 && item1.type!= 'sku'"
style="font-size: 14rpx;">
「{{item1.suitNum}}{{item1.unitName}}起点」
</text> -->
</view>
<view class="flex-end"
v-if="item1.type == 'sku' || (item1.type == 'package' && item1.groupType == '1')">
<view class="sku-wrap flex-center"
@click.stop="clickspecifications(item1,index,index1)">
<text class="t" v-if="item1.groupType == '1'">选择套餐</text>
<text class="t" v-else>选规格</text>
<text class="dot num"
v-if="item1.cartNumber >0">{{ ifcartNumber(item1) <99?ifcartNumber(item1):'99+'}}</text>
</view>
</view>
<view class="Controls" v-else>
<view class="btn" v-if="item1.cartNumber != '0'">
<up-icon name="minus-circle-fill" color="#E9AB7A" size="25"></up-icon>
<view class="btnClick"
@tap.stop="$u.throttle(() => singleclick(item1, '-'), 500)">
</view>
</view>
<text class="num"> {{ ifcartNumber(item1) }} </text>
<view class="btn">
<up-icon name="plus-circle-fill" color="#E9AB7A" size="25"></up-icon>
<view class="btnClick"
@tap.stop="$u.throttle(() => singleclick(item1, '+'), 500)">
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="fill-last" :style="{ 'height':fillHeight + 'px' }"></view>
</view>
</view>
</view>
</view>
<confirmorder ref="confirmorderref" :cartLists_count="cartLists_count" :cartList="matchedProducts"
:totalPrices='totalPrices' :confirmordershow="confirmordershow"
@close="confirmordershow = !confirmordershow" @customevent='websocketsendMessage' :orderinfo="orderinfo">
</confirmorder>
<!-- 店铺详情 -->
<shopindex ref="showShopInfoRef"></shopindex>
<!-- 购物车 -->
<shoppingCartes :cartLists_count="cartLists_count" :cartList="matchedProducts" :showCart="showCart"
@customevent='websocketsendMessage' @close="showCart = !showCart" :orderinfo="orderinfo"
@clickcancelOrder='clickcancelOrder' v-if="cartLists_count > 0">
</shoppingCartes>
<!-- 显示购物车栏 -->
<view class="cart-wrap" v-if="cartLists_count > 0 && !confirmordershow && isBusinessTime">
<view class="cart-content">
<view class="left">
<view class="iconBox">
<image class="icon"
src="https://czg-qr-order.oss-cn-beijing.aliyuncs.com/shopDetails/shopIcon.png"
mode="aspectFill" @click="Historicalorders(true)">
</image>
<text class="u-badge"> {{cartLists_count<99?cartLists_count:'99+'}} </text>
</view>
<text class="i">¥</text>
<text class="num">{{totalPrices}}</text>
</view>
<view class="btn" @tap="$u.debounce(orderdetail, 500)">
<text class="t">结算</text>
</view>
</view>
</view>
<!-- 规格 -->
<up-popup :show="showShopsku" :round="20" mode="bottom" @close="showShopsku = false,pagemetashow = false">
<view class="shop_sku">
<scroll-view scroll-y style="max-height:60vh;width: 100%;">
<view class="positionabsolute">
<up-icon name="close-circle" @click="showShopsku = false;pagemetashow=false" color="#000"
size="25"></up-icon>
</view>
<up-swiper :list="specifications.item.images" height="250"></up-swiper>
<view class="shop_sku_name"> {{specifications.item.name}} </view>
<view class="shop_sku_description">
{{specifications.item.shortTitle?specifications.item.shortTitle:''}}
</view>
<view v-if="specifications.item.type != 'package'">
<view class="shop_sku_box" v-for="(specOptions,specType) in specifications.item.selectSpecInfo"
:key="specType">
<view class="shop_sku_box_name">
{{specType }}
</view>
<view class="flex-start">
<view class="shop_sku_box_item" v-for="option in specOptions" :key="option"
@click="selectSpec(specType, option)"
:class="{ shop_sku_box_item_selected: selectedSpecs[specType] === option }">
{{option}}
<view class="shop_sku_box_item_tip"
v-if="specifications.item.result&& specifications.item.result.isSoldStock== 1 && selectedSpecs[specType] === option">
<view>售罄</view>
</view>
<view class="shop_sku_box_item_tip"
v-if="specifications.item.result == 'kong' && canSubmit == false && selectedSpecs[specType] === option">
<view>已下架</view>
</view>
</view>
</view>
</view>
</view>
<!-- 套餐 -->
<view v-else>
<view class="shop_sku_box">
<view v-for="(setmenu, setmenuindex) in specifications.item.groupSnap" :key='setmenuindex'>
<view class="shop_sku_box_name">
{{setmenu.title}} {{setmenu.count }} 选{{setmenu.number }}
</view>
<view class="flex-start">
<view class="shop_sku_box_item" v-for="(option, goodsid) in setmenu.goods"
:key="goodsid" @click="goodsidClick(setmenuindex, option, goodsid)"
:class="{ shop_sku_box_item_selected: isOptionSelected(setmenuindex, option)}"
:disabled="isMaxSelected(setmenuindex) &&!isOptionSelected(setmenuindex, option)">
{{option.proName}}
<text v-if="option.unitName">/{{option.unitName}}</text>
<view class="shop_sku_box_item_tip" v-if="specifications.item.isSoldStock == 1">
<view>售罄</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<view class="shop_bottom">
<view class="flex-between">
<view class="price" v-if="specifications.item.type != 'package' && specifications.item.result">
<text class="i">¥</text>
<text
class="num">{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1? (specifications.item.result.memberPrice||specifications.item.result.salePrice):specifications.item.result.salePrice}}</text>
<text class="i" v-if="specifications.item.unitName">/{{specifications.item.unitName}}</text>
<text v-if="specifications.item.result.suitNum>1">
「{{specifications.item.result.suitNum}}{{specifications.item.result.unitName}}起点」
</text>
</view>
<view class="price" v-else>
<text class="i">¥</text>
<text class="num">
{{shopInfo.isVip ==1 && shopInfo.isMemberPrice==1? (specifications.item.memberPrice||specifications.item.salePrice):specifications.item.salePrice}}
</text>
<text class="i" v-if="specifications.item.unitName">
/{{specifications.item.unitName}}
</text>
<text v-if="specifications.item.suitNum>1">
「{{specifications.item.suitNum}}{{specifications.item.unitName}}起点」
</text>
</view>
<view class="operation-wrap" v-if="specifications.item.type != 'package'">
<view class="btn">
<up-icon name="minus-circle-fill" color="#E9AB7A" size="25"
v-if="shopCartNumber>0"></up-icon>
<view class="btnClick" @click="shopCart('-')">
</view>
</view>
<text class="num">{{ shopCartNumber }}</text>
<view class="btn">
<up-icon name="plus-circle-fill" color="#E9AB7A" size="25"></up-icon>
<view class="btnClick" @click="shopCart('+')">
</view>
</view>
</view>
</view>
<view class="shop_skuselect flex-start" v-if="selectedSpecsStr">
<view class="shop_skuselectname">{{selectedSpecsStr }}</view>
</view>
<view v-if="specifications.item.type == 'package'" class="addShopping"
:class="shopCartNumber>0&&allConditionsSatisfied?'active':''" @click="submitSelection()">
{{skuBtnText}}
</view>
<view v-else class="addShopping" :class="shopCartNumber>0&&canSubmit?'active':''"
@click="submitSelection()">
{{skuBtnText}}
</view>
</view>
</view>
</up-popup>
<view class="history_order" @click="toHistory" v-if="shopInfo&&shopInfo.registerType == 'after'&&orderinfo.id">
<image class="img" src="@/static/history.png" mode=""></image>
<text>已下单菜品</text>
</view>
<Loading :isLoading="isLoading" />
</view>
</template>
<script setup>
import {
ref,
reactive,
onMounted,
watchEffect,
getCurrentInstance,
computed,
watch
} from "vue";
import {
onLoad,
onReady,
onShow,
onHide,
onPageScroll
} from '@dcloudio/uni-app'
//导航栏
import Nav from '@/components/CustomNavbar.vue';
import shopindex from './components/shopindex.vue'
import shoppingCartes from './components/shoppingCartes.vue'
import confirmorder from './components/confirmorder.vue'
import Loading from '@/components/Loading.vue';
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween'
dayjs.extend(isBetween)
// 获取全局属性
const {
proxy
} = getCurrentInstance();
//接口引入
import {
productminiApphotsquery,
APIgroupquery,
APIminiAppinfo,
APIminiAppskuinfo
} from "@/common/api/product/product.js";
import {
APIhistoryOrder,
APIcancelOrder,
APIrmPlaceOrder
} from "@/common/api/order/index.js";
// websocket
// import useWebSocket from '@/common/js/websocket.js';
import useWebSocket from '@/common/js/carts-websocket.js';
// pinia管理
import {
useNavbarStore
} from '@/stores/navbarStore';
// 结账管理
import {
Memberpay
} from '@/stores/pay.js';
const storeMemberpay = Memberpay();
const store = useNavbarStore();
import {
productStore
} from '@/stores/user.js';
const userStore = productStore();
// 金额管理
import {
useCartStore
} from '@/stores/order.js';
const cartStore = useCartStore()
// 动态更新导航栏配置
store.updateNavbarConfig({
showBack: true, //左边返回键
rightText: '', //右边文字
showSearch: false, //true是标题其他事文字
title: '',
isTransparent: false,
hasPlaceholder: false //是否要占位符
});
const shopInfo = uni.cache.get('shopInfo')
const shopTable = uni.cache.get('shopTable')
const distance = uni.cache.get('distance') //距离
//店铺详情
const showShopInfoRef = ref(null)
// 初始加载中
const isLoading = ref(true);
//调用shop组件
const callChildMethod = () => {
if (showShopInfoRef.value) {
showShopInfoRef.value.childMethod();
}
}
try {
const shopExtend = uni.cache.get('shopTable').shopExtendMap.shopinfo_bg
} catch (error) {}
// 计算高度
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(200)
//距离顶部的高度
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) => {
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: {},
item: {
groupSnap: [],
result: {
isSoldStock: 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 对象,将当前规格类型的选中值设置为用户点击的选项
const newSelectedSpecs = {};
const specKeys = Object.keys(specifications.item.selectSpecInfo);
for (const key of specKeys) {
if (key === specType) {
newSelectedSpecs[key] = option;
} else {
newSelectedSpecs[key] = selectedSpecs.value[key];
}
}
selectedSpecs.value = newSelectedSpecs;
if (allSpecsSelected.value) {
// try {
let result = await APIminiAppskuinfo({
specInfo: selectedSpecsStr.value,
id: specifications.item.id
});
// skuList
if (result != true) {
specifications.sku_id = result.id
specifications.product_id = result.productId
// 添加多规格分组
specifications.item.result = result
if (result.isSoldStock == 0) {
canSubmit.value = true;
} else {
canSubmit.value = false;
}
} else {
specifications.item.result = 'kong'
canSubmit.value = false;
}
} else {
canSubmit.value = false;
}
};
// 监听 specifications 的变化
watch(
() => specifications.item.groupSnap,
(newGroupSnap) => {
if (Array.isArray(newGroupSnap)) {
selectedOptions.value = newGroupSnap.map(() => []);
}
}
);
// 存储选中的选项,二维数组
const selectedOptions = ref(
specifications.item.groupSnap.map(() => [])
);
// / 选择规格的方法
const goodsidClick = (setmenuindex, option, goodsid) => {
if (!selectedOptions.value[setmenuindex]) {
// 如果 selectedOptions.value[setmenuindex] 不存在,初始化一个空数组
selectedOptions.value[setmenuindex] = [];
}
if (isOptionSelected(setmenuindex, option)) {
// 如果已经选中,取消选中
selectedOptions.value[setmenuindex] = selectedOptions.value[setmenuindex].filter(item => item.proId !==
option.proId);
} else if (!isMaxSelected(setmenuindex)) {
// 如果未达到最大选择数量,添加到选中列表
selectedOptions.value[setmenuindex].push(option);
}
};
// 判断选项是否已选中
const isOptionSelected = (setmenuindex, option) => {
// 确保 selectedOptions.value[setmenuindex] 存在
if (selectedOptions.value[setmenuindex]) {
return selectedOptions.value[setmenuindex].some(item => item.proId === option.proId);
}
return false;
};
// 判断是否达到最大选择数量
const isMaxSelected = (setmenuindex) => {
// 确保 selectedOptions.value[setmenuindex] 存在
if (selectedOptions.value[setmenuindex]) {
return selectedOptions.value[setmenuindex].length >= specifications.item.groupSnap[setmenuindex]
.number;
}
return false;
};
// 计算所有选中条件是否都符合
const allConditionsSatisfied = computed(() => {
// 检查 specifications.item.groupSnap 是否存在
if (!specifications.item?.groupSnap) {
return false;
}
return specifications.item.groupSnap.every((optionGroup, index) => {
// 获取当前索引对应的已选选项,如果不存在则默认为空数组
const selected = selectedOptions.value[index] || [];
// 检查是否达到最大选择数量
const hasEnoughSelection = selected.length === optionGroup.number;
return hasEnoughSelection;
});
});
// 提交选择,套餐选中最后处理的数据
const selectedGroupSnap = ref([]);
// 计算属性,将 selectedSpecs 转换为字符串形式
const selectedSpecsStr = computed(() => {
const values = Object.values(selectedSpecs.value);
return values.join('');
});
//添加购物车数量
const shopCartNumber = ref(0)
// 多规格 套餐添加数量
const shopCart = async (i) => {
if (i == '-' && shopCartNumber.value >= 0) {
shopCartNumber.value = 0
return false;
}
let res = await shoppingcart()
if (i == '-') {
if (!res && shopCartNumber.value == specifications.item.suitNum) {
uni.showToast({
title: `起点${specifications.item.suitNum}`,
icon: 'none'
})
return false;
} else {
shopCartNumber.value--;
}
} else {
if (!res && shopCartNumber.value < 1) {
console.log(res, specifications)
if (specifications.type == 'sku') {
shopCartNumber.value = parseFloat(specifications.item.result.suitNum);
} else {
shopCartNumber.value = parseFloat(specifications.item.suitNum);
}
} else {
shopCartNumber.value++;
}
}
}
// 套餐比较两个对象是否相等
function isObjectEqual(obj1, obj2) {
if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {
return obj1 === obj2;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
if (!isArrayEqual(obj1[key], obj2[key])) {
return false;
}
} else if (!isObjectEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
}
// 比较两个数组是否相等(忽略顺序)
function isArrayEqual(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
const usedIndices = new Array(arr2.length).fill(false);
for (const item1 of arr1) {
let found = false;
for (let i = 0; i < arr2.length; i++) {
if (!usedIndices[i] && isObjectEqual(item1, arr2[i])) {
usedIndices[i] = true;
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
// 根据购物车的数据匹配选中的商品查找是否有匹配的数组
const matchingProduct = async (data) => {
return matchedProducts.value.find((product, index) => {
if (specifications.type == 'package') {
// 套餐
let result = false;
try {
if (product.type == "package") {
let res = JSON.parse(product.cartListinfo.pro_group_info);
result = isArrayEqual(res, selectedGroupSnap.value);
}
} catch (error) {
//TODO handle the exception
}
// 直接返回布尔值
return result;
} else if (specifications.item.type == 'sku') {
// 多规格
return product.cartListinfo.sku_id == data.id && product.cartListinfo.product_id == data
.productId
} else {
// 其他
return product.skuId == data.skuId && product.id == data.id
}
});
}
// 判断多规格和套餐 商品是否在购物车有数据
const shoppingcart = async () => {
let res = null
if (specifications.item.type == "package") {
if (!allConditionsSatisfied.value) {
return false
}
// 是否是套餐package
selectedGroupSnap.value = specifications.item.groupSnap.map((setmenu, index) => {
return {
...setmenu,
goods: selectedOptions.value[index]
};
});
res = await matchingProduct(selectedGroupSnap.value)
} else {
if (!canSubmit.value) {
return false
}
res = await matchingProduct(specifications.item.result)
}
return res;
}
// 提交选择并执行下一步操作的方法
const submitSelection = async () => {
if (!isProductAvailable(specifications.productListitem.days, specifications.productListitem.startTime,
specifications.productListitem.endTime)) {
uni.showToast({
title: '不在可售时间内'
})
return false;
}
// 判断购物车是否有该选中商品
// 数量不能少于0
if (shopCartNumber.value <= 0) {
return;
}
if ((specifications.item.type == 'package' && allConditionsSatisfied.value) || (specifications.item.type ==
'sku' && canSubmit.value)) {
let res = await shoppingcart()
// 是否是套餐 有就传
if (specifications.item.type == "package") {
// 需求更改:所所有商品套餐都是add,没有修改
res = null
} else {
selectedGroupSnap.value = []
}
websocketsendMessage({
id: res ? res.cartListId : '',
type: 'shopping',
suitNum: specifications.productListitem.suitNum,
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: selectedGroupSnap.value,
goods_type: specifications.item.type == "package" ? 'package' : '',
is_print: 1,
product_type: specifications.item.type
})
// 清空套餐选中
selectedGroupSnap.value = []
showShopsku.value = false
} else {
return;
}
}
//获取多规格数据
const clickspecifications = async (item, index, indexs, type) => {
console.log(item)
// 商品类型 single-单规格商品 sku-多规格商品 package-套餐商品 weight-称重商品 coupon-团购券
if (item.isSoldStock == 1 || (item.isSaleTime == 0 && !item.isSaleTimeshow) || item.type == 'single' ||
item
.type == 'weight' || (
item.type == 'package' && item.groupType == '0')) {
return false;
}
// 数量清零
shopCartNumber.value = 0
// 初始化
let data = {
item: item,
productListitem: item,
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 = res.id
specifications.sku_id = item.skuId
shopCartNumber.value = 1
}
// 购物车是否有商品
specifications.type = res.type
specifications.item.selectSpecInfo = Object.fromEntries(
Object.entries(specifications.item.selectSpecInfo).filter(([_, value]) => value.length > 0)
);
// 给默认数量
specifications.item.amountcartNumber = 0
showShopsku.value = true
}
// 判断商品是否在可售时间内
const isProductAvailable = async (sellDaysStr, startTimeStr, endTimeStr) => {
// 将后端返回的字符串转换为数组
const sellDays = sellDaysStr.split(',');
const now = dayjs();
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const currentDay = days[now.day()];
// console.log('当前日期:', currentDay);
// console.log('可售日期列表:', sellDays);
// 检查当前周几是否在可售周几列表中
if (!sellDays.includes(currentDay)) {
// console.log('当前日期不在可售日期列表中');
return false;
}
const startTime = dayjs(`${now.format('YYYY-MM-DD')} ${startTimeStr}`);
let endTime = dayjs(`${now.format('YYYY-MM-DD')} ${endTimeStr}`);
// 处理跨天情况
if (endTime.isBefore(startTime)) {
endTime = endTime.add(1, 'day');
}
// console.log('当前时间:', now.format('YYYY-MM-DD HH:mm:ss'));
// console.log('开始时间:', startTime.format('YYYY-MM-DD HH:mm:ss'));
// console.log('结束时间:', endTime.format('YYYY-MM-DD HH:mm:ss'));
const isInRange = now.isBetween(startTime, endTime, null, '[)');
// console.log('当前时间是否在可售时间范围内:', isInRange);
return isInRange;
}
// 单规格
const singleclick = async (item, i) => {
if (!isProductAvailable(item.days, item.startTime, item.endTime)) {
uni.showToast({
title: '不在可售时间内'
})
return false;
}
// 判断购物车是否有该选中商品
let res = null
try {
res = matchedProducts.value.find((product, index) => {
return product.skuId == item.skuId && product.id == item.id
});
} catch (error) {
//TODO handle the exception
}
// 保存这次点击的
specifications.productListitem = item
// 是否起售 如果小于或者大于都是1
let suitNum = 1;
const cartNumberFloat = parseFloat(item.cartNumber);
if (!res && item.suitNum > cartNumberFloat) {
suitNum = item.suitNum;
} else if (item.suitNum >= cartNumberFloat && i === '-') {
suitNum = item.cartNumber;
}
websocketsendMessage({
id: res ? item.cartListId : '',
type: 'shopping',
suitNum: item.suitNum,
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId'),
operate_type: await calculateValue(item.cartNumber, i, suitNum) == 'del' ? 'del' : res ?
'edit' : 'add',
product_id: item.id,
sku_id: item.skuId,
number: await calculateValue(item.cartNumber, i, suitNum),
is_print: 1,
product_type: item.type
})
}
const calculateValue = (cartNumber, i, step = 1) => {
if (i == '+') {
const result = parseFloat(cartNumber) + parseFloat(step);
return result.toFixed(2);
} else {
// 当减到0返回del
const result = parseFloat(cartNumber) - parseFloat(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,
closeExistingConnection,
onShowconnect,
initNetworkListener
} = useWebSocket(options);
//购物车显示
const showCart = ref(false)
// 提交订单显示
const confirmordershow = ref(false)
// 更新商品数量的方法
const updateProductQuantities = () => {
// 先将所有商品的 cartNumber 初始化为 0
shopProductList.hots.forEach((i) => {
i.cartNumber = 0
})
// 遍历商品列表二维数组
shopProductList.productInfo.forEach((group) => {
group.productList.forEach((product) => {
product.cartNumber = 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
}
});
});
}
//websocket产值
const websocketsendMessage = (data) => {
uni.$u.debounce(sendMessage(data), 500)
}
// 用于记录已经处理过的消息的 msg_id
const processedMessageIds = new Set();
// 监听接收到的消息变化
watchEffect(async () => {
if (isDataLoaded.value && receivedMessages.value) {
const Message = receivedMessages.value
if (Message) {
console.log(Message.data);
// 心跳返回 过滤
if (Message.type == "ping_interval" || Message.msg_id == "ping_interval") {
isLoading.value = false;
return false
}
// 检查消息是否已经处理过
if (processedMessageIds.has(Message.msg_id)) {
return;
}
processedMessageIds.add(Message.msg_id);
// 初始化
if (Message.operate_type == "init") {
cartStore.carts = Message.data
uni.hideLoading();
isLoading.value = false;
}
// 清空购物车
if (Message.operate_type == 'cleanup') {
cartStore.carts = []
setTimeout(() => {
Historicalorders()
}, 400)
showCart.value = false
}
// 删除除购物车
if (Message.operate_type == 'del' && Message.status == 1) {
// 优化:使用可选链操作符避免报错
cartStore.carts = cartStore.carts.filter(item => item.id !== Message.data?.id);
// cartStore.carts = cartStore.carts.filter(item => item.id != Message.data.id);
}
// 添加或者减少购物后返回
if (Message.operate_type == 'add' || Message.operate_type == 'edit') {
[Message.data].forEach((objA) => {
const index = cartStore.carts.findIndex((objB) => objB.id == objA.id);
if (index !== -1) {
cartStore.carts[index] = objA;
} else {
cartStore.carts.push(objA);
}
});
}
// 历史订单
if (Message.operate_type == 'clearOrder') {
Historicalorders()
}
// 购物车数据更新从新请求
if (Message.type == 'product' && Message.data_type == 'product_update' && Message
.operate_type == 'product_update') {
isDataLoaded.value = false;
productqueryProduct()
}
// 提示
if (Message.status == 0 && Message.type != 'no_suit_num') {
uni.showToast({
title: Message.msg,
icon: "none"
})
}
if (Message.type == 'no_suit_num') {
// console.log(specifications)
uni.showModal({
title: '提示',
showCancel: false,
content: '此商品库存不足起售数量!',
success: async (data) => {
await websocketsendMessage({
id: Message.id,
type: 'shopping',
table_code: uni.cache.get('tableCode'),
shop_id: uni.cache.get('shopId'),
operate_type: 'del',
is_print: 1,
})
}
});
}
//除去p 每次返回都回执消息
await websocketsendMessage({
type: 'receipt',
msg_id: Message.msg_id
})
// 初始化商品数量
await updateProductQuantities()
}
}
})
// 更新购物车数据shopProductList.hots
const matchedProducts = computed(() => {
if (cartStore.carts.length > 0) {
let Specialstop = null
try {
Specialstop = [...[{
id: "",
name: "",
productList: shopProductList.hots
}], ...shopProductList.productInfo]
} catch (error) {
Specialstop = shopProductList.productInfo
//TODO handle the exception
}
return cartStore.carts.flatMap((cartItem) => {
for (const group of Specialstop) {
for (const product of group.productList) {
if (product.id == cartItem.product_id) {
return {
...product,
cartListinfo: cartItem,
cartListId: cartItem.id, //购物车id
cartNumber: cartItem.number //增加一个数量算法
// cartNumberToAdd: cartItem.number //增加一个数量算法
};
}
}
}
if (cartItem.is_temporary === 1) {
return [{
...cartItem,
memberPrice: cartItem.discount_sale_amount,
salePrice: cartItem.discount_sale_amount,
cartListinfo: cartItem,
cartListId: cartItem.id, // 购物车id
cartNumber: cartItem.number // 增加一个数量算法
}];
}
// 如果没找到匹配的商品,返回 null 或者其他默认值,这里返回 null
return null;
}).filter(item => item !== null);
} else {
return []
}
})
//删除某一个待支付订单
const clickcancelOrder = async (data) => {
if (data.i == 'all') {
await APIcancelOrder({
shopId: uni.cache.get('shopId'),
orderId: orderinfo.value.id,
})
} else {
await APIrmPlaceOrder({
shopId: uni.cache.get('shopId'),
orderId: orderinfo.value.id,
placeNum: data.key
})
}
Historicalorders()
}
// 储存是否存在多次下单
const orderinfo = ref({})
const confirmorderref = ref(null)
// 结账
const orderdetail = async () => {
uni.navigateTo({
url: '/pages/order/confirm-order?tableCode=' + uni.cache.get('tableCode') + '&shopId=' + uni
.cache.get(
'shopId')
})
return
try {
await Historicalorders()
} catch (error) {}
confirmordershow.value = true
showCart.value = false
}
// 历史订单
const Historicalorders = async (W) => {
if (W===true) {
showCart.value = !showCart.value
} else {
let res = await APIhistoryOrder({
tableCode: uni.cache.get('tableCode'),
})
orderinfo.value = {
id: res.id,
detailMap: res.detailMap,
placeNum: res.placeNum
}
}
}
// 提取合并 orderinfo.detailMap 数组的逻辑
function combineOrderInfoDetailMap(orderinfo) {
if (!orderinfo) return [];
let combinedArray = [];
for (const key in orderinfo.detailMap) {
if (orderinfo.detailMap.hasOwnProperty(key)) {
let subArray = orderinfo.detailMap[key];
combinedArray = [...combinedArray, ...subArray];
}
}
return combinedArray;
}
// 计算购物车商品费用
const totalPrices = computed(() => {
// 待支付订单
let cartone = 0
if (orderinfo.value) {
let combinedArray = [];
for (const key in orderinfo.value.detailMap) {
if (orderinfo.value.detailMap.hasOwnProperty(key)) {
let subArray = orderinfo.value.detailMap[key];
combinedArray = [...combinedArray, ...subArray]
}
}
// 购物车总数价格
cartone = combinedArray.reduce((total, item) => {
// 是否启用会员价 0否1是
if (shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1) {
// memberPrice会员价
return total + (parseFloat(item.memberPrice || item.price) * parseFloat(item.num - item
.returnNum));
} else {
// salePrice销售价
return total + (parseFloat(item.price || 0) * parseFloat(item.num - item.returnNum));
}
}, 0);
}
// 购物车总数价格
let cart = 0
if (matchedProducts.value.length > 0) {
// 购物车总数价格
cart = matchedProducts.value.reduce((total, item) => {
if (item.type == 'sku') {
item.skuList.forEach((i, t) => {
if (item.cartListinfo.sku_id == i.id) {
item.memberPrice = i.memberPrice
item.salePrice = i.salePrice
}
})
}
// 是否启用会员价 0否1是
if (shopInfo.isVip == 1 && shopInfo.isMemberPrice == 1) {
// memberPrice会员价
return total + parseFloat(item.memberPrice || item.salePrice) * parseFloat(item
.cartNumber);
} else {
// salePrice销售价
return total + parseFloat(item.salePrice || 0) * parseFloat(item.cartNumber);
}
}, 0);
}
cart = parseFloat(cart)
// 向上取整并保留两位小数
return parseFloat(cart.toFixed(2));
});
// 计算购物车商品总数量
const cartLists_count = computed(() => {
const combinedOrderInfo = combineOrderInfoDetailMap(orderinfo.value);
const orderInfoCount = combinedOrderInfo.reduce((sum, item) => {
return sum + parseFloat(item.num);
}, 0);
const matchedProductsCount = matchedProducts.value.reduce((sum, item) => {
const num = typeof item.cartNumber === 'string' ? parseFloat(item.cartNumber) : item
.cartNumber;
return sum + num;
}, 0);
const totalCount = matchedProductsCount;
return parseFloat(totalCount.toFixed(2));
});
// 定义 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(() => {
// 使用 reduce 方法对 cartList 进行处理
const grouped = cartStore.carts.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 endTimeref = reactive({
startTime: '',
endTime: ''
})
// 获取当前时间
const getCurrentTime = () => {
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
return `${hours}:${minutes}`;
};
// 计算是否在营业时间内
const isBusinessTime = computed(() => {
if (!shopInfo.businessTime) {
return true;
}
const currentTime = getCurrentTime();
const [startTime, endTime] = shopInfo.businessTime.split('-');
endTimeref.startTime = startTime
endTimeref.endTime = endTime
// 如果开始时间大于结束时间,说明是跨天的营业时间
if (startTime > endTime) {
return currentTime >= startTime || currentTime <= endTime;
}
return currentTime >= startTime && currentTime <= endTime;
});
// 列表请求
const productqueryProduct = async () => {
cartStore.goodsIsloading = false;
try {
shopProductList.hots = await productminiApphotsquery()
shopProductList.productInfo = await APIgroupquery()
} catch (error) {
uni.showToast({
title: '网络不稳定,请重新扫码进入',
icon: 'none'
})
setTimeout(() => {
uni.pro.switchTab('index/index')
}, 1000)
}
if (shopProductList.productInfo.length > 0 || shopProductList.hots.length > 0) {
//TODO handle the exception
//第一步:将所有商品的 cartNumber 初始化为 0
shopProductList.productInfo.forEach((group) => {
group.productList.forEach(async (product) => {
product.cartNumber = 0;
product.isSaleTimeshow = await isProductAvailable(product.days, product
.startTime, product.endTime)
cartStore.setGoodsMap(product.id, product)
});
});
shopProductList.hots.forEach(async (i) => {
i.cartNumber = 0
i.isSaleTimeshow = await isProductAvailable(i.days, i.startTime, i.endTime)
cartStore.setGoodsMap(i.id, i)
})
cartStore.goodsIsloading = true;
scrollTopSize.value = 0
topArr.value = []
// userStore.actionsAPIuser()
// 数据可以更新
isDataLoaded.value = true;
// 历史订单
Historicalorders()
} else {
uni.showToast({
title: '暂无列表数据,请重新扫码',
icon: "none"
});
isDataLoaded.value = false;
setTimeout(() => {
uni.pro.switchTab('index/index')
}, 1000)
return false;
}
}
onLoad(async (e) => {
await proxy.$onLaunched;
})
onShow(async() => {
// 监听页面显示和隐藏
onShowconnect()
let res = await APIhistoryOrder({
tableCode: uni.cache.get('tableCode'),
})
if(res){
orderinfo.value = {
id: res.id,
detailMap: res.detailMap,
placeNum: res.placeNum
}
}else{
orderinfo.value = {
id:''
}
}
})
onHide(() => {
closeExistingConnection()
})
onMounted(async () => {
await proxy.$onLaunched;
// 获取当前页面栈
const pages = getCurrentPages();
// 获取当前页面实例
const currentPage = pages[pages.length - 1];
// 获取页面参数
const options = currentPage.options;
let res = await APIhistoryOrder({
tableCode: uni.cache.get('tableCode'),
})
await productqueryProduct()
if (res && res.id && shopInfo.registerType == "after") {
toHistory()
return
}
setTimeout(() => {
// 启动网络监听
initNetworkListener()
getElementTop()
}, 500)
})
//跳转历史订单
function toHistory() {
uni.navigateTo({
url: '/pages/order/confirm-order?tableCode=' + uni.cache.get('tableCode') + '&shopId=' + uni
.cache.get(
'shopId')
})
// uni.navigateTo({
// url: '/pages/order/confirm-order?orderId=' + orderinfo.id + '&shopId=' + uni.cache.get('shopId')+'&tableCode='+uni.cache.get('tableCode')
// })
}
</script>
<style lang="scss" scoped>
.grayscale {
filter: grayscale(100%);
pointer-events: none;
}
.top--panel {
// padding: 0 20rpx;
background-color: #fff;
.panelimgbackground {
width: 100%;
height: 272rpx;
}
.panelone {
padding: 20rpx 20rpx 0 20rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 500;
font-size: 32rpx;
color: #333333;
}
.paneltow {
padding: 0 20rpx;
margin-top: 16rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #999999;
}
.panelthere {
margin-top: 32rpx;
margin-bottom: 50rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #999999;
padding: 0 20rpx;
.paneltheretext {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #999999;
}
.flex-start {
view {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #999999;
}
}
}
.panelfour {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: bold;
font-size: 32rpx;
color: #333333;
padding: 0 20rpx;
}
.panelfive {
width: 100%;
padding: 0 20rpx;
.panelfive_list {
display: flex;
}
.panelfiveitem {
margin-top: 16rpx;
width: 340rpx;
margin-right: 30rpx;
position: relative;
flex-shrink: 0;
.panelfiveitemimage {
border-radius: 20rpx 20rpx 0rpx 0rpx;
width: 100%;
height: 204rpx;
}
.vifgoodsImg {
width: 100%;
height: 204rpx;
position: absolute;
top: 0;
left: 0;
z-index: 9;
background-color: rgb(0, 0, 0, 0.5);
image {
padding: 30rpx;
width: 100%;
height: 100%;
}
}
.panelfiveitemone {
margin-top: 32rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 500;
font-size: 28rpx;
color: #333333;
overflow: hidden; //超出的文本隐藏
text-overflow: ellipsis; //溢出用省略号显示
white-space: nowrap; //溢出不换行
}
.panelfiveitemtow {
margin-top: 16rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #FF534B;
}
.panelfiveitemthere {
margin-top: 12rpx;
// text:nth-child(1) {
// margin-left: 0;
// }
text {
padding: 4rpx 24rpx;
background: #F6F6F6;
border-radius: 8rpx 8rpx 8rpx 8rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 20rpx;
color: #999999;
}
}
.panelfiveitemfour {
margin-top: 12rpx;
width: 100%;
height: 36rpx;
line-height: 36rpx;
overflow: hidden; //超出的文本隐藏
text-overflow: ellipsis; //溢出用省略号显示
white-space: nowrap; //溢出不换行
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #999999;
}
.panelfiveitemfive {
margin-top: 8rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #999999;
}
.panelfiveitemsex {
.panelfiveitemsex_oen {
.tips {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #333333;
}
.price {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: bold;
font-size: 36rpx;
color: #333333;
}
.originalprice {
margin-left: 10rpx;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 20rpx;
text-decoration: line-through;
}
.unit {
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 36rpx;
color: #333333;
}
}
}
.panelfiveitemNum {
// position: absolute;
// bottom: 82rpx;
// right: 0;
display: flex;
align-items: center;
justify-content: flex-end;
.sku-wrap {
padding: 10rpx 20rpx;
background: #E3AD7F;
border-radius: 32rpx;
position: relative;
align-items: center;
.t {
font-size: 28rpx;
color: #fff;
}
.dot {
position: absolute;
top: -15rpx;
right: -10rpx;
background-color: #FF4B33;
color: #fff;
border-radius: 58rpx;
padding: 5rpx 14rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
}
}
.Controls {
display: flex;
align-items: center;
.num {
margin: 8rpx 8rpx 0 8rpx;
}
.btn {
display: flex;
align-items: center;
justify-content: center;
position: relative;
.btnClick {
width: 100rpx;
height: 100rpx;
position: absolute;
// bottom: 0;
}
}
}
}
}
}
}
.scroll-panel {
position: relative;
.list-box {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: flex-start;
align-content: flex-start;
font-size: 28rpx;
position: relative;
.left {
width: 200rpx;
background-color: #f6f6f6;
line-height: normal;
box-sizing: border-box;
font-size: 32rpx;
position: sticky;
top: 0;
// padding-bottom: 200rpx;
.item {
padding: 30rpx 30rpx;
// height: 92rpx;
// line-height: 92rpx;
position: relative;
font-weight: 400;
font-size: 24rpx;
color: #333333;
display: flex;
align-items: center;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
&+.item {
margin-top: 1px;
&::after {
// content: '';
// display: block;
// height: 0;
// border-top: #d6d6d6 solid 1px;
// width: 620upx;
// position: absolute;
// top: -1px;
// right: 0;
// transform: scaleY(0.5);
/* 1px像素 */
}
}
&.active {
color: #333;
background-color: #fff;
position: relative;
&::before {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
border-left: #7E5C23 solid 4px;
height: 100%;
width: 0;
}
&::after {
content: '';
display: block;
position: absolute;
top: 0;
left: -15rpx;
bottom: 0;
margin: auto;
height: 30rpx;
width: 30rpx;
border-radius: 50%;
background-color: #7E5C23;
}
}
}
.items {
height: 90px;
position: relative;
font-weight: 400;
font-size: 24rpx;
color: #333333;
}
.fill-last {
height: 0;
width: 100%;
background: none;
}
}
.main {
background-color: #fff;
padding-left: 20rpx;
width: 0;
flex-grow: 1;
box-sizing: border-box;
position: relative;
.title {
line-height: normal;
padding: 30rpx 0;
font-size: 24rpx;
font-weight: bold;
color: #666;
background-color: #fff;
position: sticky;
top: 0;
z-index: 19;
}
.item {
padding-bottom: 16rpx;
border-bottom: #eee solid 1px;
}
.goods {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-content: center;
position: relative;
&+.goods {
margin-top: 16rpx;
}
&>image {
width: 120rpx;
height: 120rpx;
margin-right: 18rpx;
}
.goodsImg {
position: relative;
width: 200rpx;
height: 200rpx;
border-radius: 18rpx;
flex-shrink: 0;
}
.vifgoodsImg {
width: 200rpx;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 9;
background-color: rgb(0, 0, 0, 0.5);
image {
padding: 30rpx;
width: 100%;
height: 100%;
}
}
.topSort {
width: 92rpx;
height: 38rpx;
text-align: center;
line-height: 38rpx;
position: absolute;
top: 0;
left: 0;
font-weight: 400;
font-size: 24rpx;
color: #FFFFFF;
border-radius: 20rpx 0rpx 20rpx 0rpx;
}
.topSort.c1 {
background: #FC5C2E;
}
.topSort.c2 {
background: #EF994E;
}
.topSort.c3 {
background: #F4B951;
}
.goods_right {
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
position: relative;
padding-top: 5rpx;
padding-right: 20rpx;
box-sizing: border-box;
.name {
font-size: 28rpx;
color: #333;
font-weight: bold;
margin-bottom: 8rpx;
}
.describe,
.monthlySale,
.lookBack {
font-weight: 400;
font-size: 20rpx;
color: #999999;
margin-bottom: 8rpx;
}
.describe,
.name {
width: 270rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.lookBack {
color: #FF534B;
}
.money {
font-weight: bold;
font-size: 24rpx;
color: #333;
display: flex;
align-items: flex-end;
.money_num {
font-size: 28rpx;
color: #333;
font-weight: bold;
}
}
.suit {
font-weight: 400;
font-size: 24rpx;
color: #666666;
}
.sku-wrap {
padding: 10rpx 20rpx;
background: #E3AD7F;
border-radius: 32rpx;
// position: absolute;
// bottom: 10rpx;
// right: 20rpx;
align-items: center;
position: relative;
.t {
font-size: 24rpx;
color: #fff;
}
.dot {
position: absolute;
top: -15rpx;
right: -10rpx;
background-color: #FF4B33;
color: #fff;
border-radius: 58rpx;
padding: 5rpx 14rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
}
}
.Controls {
display: flex;
align-items: center;
justify-content: flex-end;
// position: absolute;
// bottom: 10rpx;
// right: 20rpx;
.num {
margin: auto 16rpx;
}
.btn {
display: flex;
align-items: center;
justify-content: center;
position: relative;
.btnClick {
width: 100rpx;
height: 100rpx;
position: absolute;
// bottom: 0;
}
}
}
}
}
}
}
.lineThrough {
font-weight: normal;
text-decoration: line-through;
color: #999 !important;
font-size: 24rpx !important;
}
.money_num.lineThrough {}
}
.shop_sku {
width: 100%;
position: relative;
border-radius: 20rpx;
background: #fff;
box-sizing: border-box;
padding-bottom: 250rpx;
.positionabsolute {
position: absolute;
top: 30rpx;
z-index: 999;
right: 30rpx;
}
.shop_sku_name {
padding: 0 28rpx;
margin-top: 20rpx;
font-weight: bold;
font-size: 32upx;
margin-bottom: 16rpx;
}
.shop_sku_returned {
padding: 0 28rpx;
font-weight: 400;
font-size: 24rpx;
color: #FF534B;
}
.shop_sku_description {
padding: 0 28rpx;
font-weight: 400;
font-size: 24rpx;
color: #999999;
margin-top: 16rpx;
padding-bottom: 32rpx;
box-sizing: border-box;
border-bottom: 2rpx solid #F0F0F0;
}
.shop_sku_box:last-child {
padding-bottom: 60rpx;
}
.shop_sku_box {
padding: 20rpx;
.shop_sku_box_name {
margin-top: 20rpx;
font-weight: 500;
font-size: 28upx;
color: #333;
}
.flex-start {
.shop_sku_box_item {
margin-top: 16rpx;
padding: 12rpx 28rpx;
border-radius: 8rpx;
font-size: 24upx;
margin-right: 56rpx;
background: #EFEFEF;
border: 2rpx solid #EFEFEF;
position: relative;
color: #666666;
.shop_sku_box_item_tip {
width: 62rpx;
height: 47rpx;
text-align: right;
position: absolute;
top: 0;
right: 0;
background: linear-gradient(45deg, transparent, transparent 50%, #CECECE 50%, #CECECE 100%);
view {
font-size: 18rpx;
color: #666666;
transform: rotate(45deg);
position: absolute;
top: 5rpx;
right: 3rpx;
}
}
}
.shop_sku_box_item:nth-child(1) {
margin-left: 0;
}
.disabled {
color: #999;
background-color: #F5F5F5;
border: 2rpx solid #F5F5F5;
}
.shop_sku_box_item_noselected {
color: #666;
}
.shop_sku_box_item_selected {
background: #FEFAF7;
border-radius: 8rpx;
border: 2rpx solid #E8AD7B;
color: #E8AD7B;
}
}
}
.shop_skuselect {
margin-top: 16rpx;
width: 100%;
// background: #f7f7f7;
color: #999;
font-size: 24upx;
.shop_skuselectname {
color: #000;
font-size: 26upx;
}
}
.shop_bottom {
width: 100%;
box-sizing: border-box;
padding: 30rpx 28rpx;
background-color: #fff;
box-shadow: 0rpx -6rpx 14rpx 2rpx rgba(0, 0, 0, 0.1);
position: fixed;
left: 0;
bottom: 0;
.price {
display: flex;
align-items: flex-end;
.i {
font-size: 28rpx;
color: #E8AD7B;
position: relative;
bottom: 4upx;
font-weight: bold;
}
.num {
font-size: 42rpx;
color: #E8AD7B;
position: relative;
top: 6upx;
padding: 0 4upx;
}
}
.operation-wrap {
display: flex;
align-items: center;
.num {
font-size: 32upx;
padding: 0 16upx;
}
.btn {
display: flex;
align-items: center;
justify-content: center;
position: relative;
.btnClick {
width: 100rpx;
height: 100rpx;
position: absolute;
// bottom: 0;
}
}
}
.addShopping {
width: 100%;
height: 96rpx;
line-height: 96rpx;
text-align: center;
background: #ccc;
border-radius: 48rpx;
font-weight: 400;
font-size: 32rpx;
color: #FFFFFF;
margin-top: 36rpx;
}
.addShopping.active {
background: #E8AD7B;
}
}
}
.shop-info-wrap {
padding: 0 30rpx 50rpx;
box-sizing: border-box;
.info-wrap {
padding: 30rpx 0;
box-sizing: border-box;
.shopName {
align-self: center;
font-size: 32rpx;
color: #333;
font-weight: bold;
}
}
.info-wrap-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.row {
.col {
margin-bottom: 10rpx;
}
.l,
.t {
font-size: 24rpx;
color: #999;
}
}
}
.cart-wrap {
width: 100%;
padding: 0 20rpx;
box-sizing: border-box;
position: fixed;
bottom: 40rpx;
left: 0;
z-index: 99;
.cart-content {
display: flex;
align-items: center;
height: 128rpx;
background: #FFFFFF;
box-shadow: 0rpx 0rpx 20rpx 2rpx rgba(0, 0, 0, 0.15);
border-radius: 58rpx;
padding: 0 36rpx;
box-sizing: border-box;
.left {
flex: 1;
display: flex;
align-items: center;
position: relative;
.iconBox {
position: relative;
}
.icon {
width: 76rpx;
height: 88rpx;
margin-left: 22rpx;
}
.u-badge {
position: absolute;
top: -30rpx;
right: -30rpx;
background-color: #FF4B33;
color: #fff;
border-radius: 58rpx;
padding: 5rpx 14rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
}
.i,
.num {
color: #333;
}
.i {
font-size: 20upx;
position: relative;
top: 4upx;
margin-left: 64rpx;
}
.num {
font-size: 42upx;
font-weight: bold;
}
}
.btn {
height: 100%;
width: 40%;
display: flex;
align-items: center;
justify-content: flex-end;
.t {
width: 160rpx;
height: 64rpx;
line-height: 64rpx;
text-align: center;
background: #FEFAF7;
border-radius: 36rpx 36rpx 36rpx 36rpx;
border: 2rpx solid $my-main-color;
font-weight: bold;
font-size: 28rpx;
color: $my-main-color;
}
}
}
}
.history_order {
background-color: #fff;
padding: 12rpx 16rpx;
font-size: 24rpx;
color: #333;
display: flex;
align-items: center;
box-shadow: 0rpx 6rpx 12rpx 2rpx rgba(0, 0, 0, 0.16);
position: fixed;
top: 50%;
right: 0;
transform: translateY(-50%);
border-radius: 100px 0 0 100px;
z-index: 20;
.img {
width: 36rpx;
margin-right: 8rpx;
height: 36rpx;
}
}
</style>