You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

792 lines
24 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view>
<view style="display: flex;flex-direction: column;height: 100vh;background: #F6D13A;" :style="{
background: mch && mch.main_color ? mch.main_color : (mch ? '#F6D13A' : '#F0F0F0')
}">
<view class="hearder-box" style="" v-if="mch">
<view style="display: flex;align-items: center;">
<view style="flex: 1;">
<u-search placeholder="请输入搜索商品名称" v-model="keyword" @search="getData"
@custom="getData"></u-search>
</view>
<view v-if="table" style="font-size: 32rpx;font-weight: bold;margin-left: 20rpx;">
桌号:{{ table.number }}
</view>
</view>
<view style="display: flex;align-items: center;justify-content: space-between;margin-top: 20rpx;">
<view style="display: flex;align-items: center;">
<view style="margin-right: 20rpx;">
<image style="width: 60rpx;height: 60rpx;border-radius: 20rpx;" :src="mch.logo_url"></image>
</view>
<view style="color: #000;font-weight: 600;">
{{ mch.name }}
</view>
<view>
<u-icon name="arrow-right" color="#262626" size="15"></u-icon>
</view>
</view>
<view style="font-size: 28rpx;font-weight: 600;"
v-if="mch.business_hours && mch.business_hours.length > 0">
<!-- <text style="color: #000;">10:30-22:40</text> -->
<view style="margin-left: 20rpx;color: #000;" v-for="(items, i) of mch.business_hours" :key="i">
{{ items.join('-') }}
</view>
</view>
</view>
<view style="margin-top: 14rpx;">
<u-icon @click="openLocation(mch)" name="map" :label="mch.detail || mch.name" labelColor="#a8a8a8"
color="#a8a8a8" size="12" label-size="12"></u-icon>
</view>
</view>
<view class="content-box" style="overflow: hidden;">
<!-- 左侧菜单 -->
<view class="left-tab" style="overflow-y: scroll;background: #F0F0F0;">
<template v-if="cat_list && cat_list.length > 0">
<view v-for="(item, index) in cat_list" class="cat-item" @click="updateCatIndex(index)"
:class="cat_index == index ? 'cat-item-active' : ''">
<template v-if="item.id">
<view v-if="item.pic_url">
<image style="width: 60rpx;height: 60rpx;" :src="item.pic_url" mode=""></image>
</view>
<view :style="{
lineHeight: item.pic_url ? '40rpx' : '60rpx'
}">
{{ item.name }}
</view>
</template>
<template v-else>
<view>
<image style="width: 60rpx;height: 60rpx;" src="@/static/image/bixuan.png" mode="">
</image>
</view>
<view :style="{
lineHeight: '40rpx'
}">
{{ item.name }}
</view>
</template>
</view>
</template>
<template v-else>
<view style="padding: 80rpx 0;">
<u-empty iconSize="80rpx" mode="list"></u-empty>
</view>
</template>
<view style="height: 180rpx;width: 100%;"></view>
</view>
<!-- 右侧菜单 -->
<view class="right-tab" style="display: flex;flex-direction: column;position: relative;">
<view style="display: flex;flex: 1;height: 100%;overflow: hidden;position: relative;">
<scroll-view scroll-y style="overflow-y: scroll;float: left;width: 100%;flex: 1;"
refresher-default-style="none" :refresher-triggered="triggered"
:refresher-enabled="cat_index > 0" @refresherrefresh="onRefresh" :refresher-threshold="60"
@refresherrestore="onStore" @scrolltolower="sBottome" @scroll="is_scroll_bottom = false">
<template #refresher>
<view style="height: 100%;display: flex;align-items: flex-end;justify-content: center;">
<view style="font-size: 28rpx;color: #999;line-height: 60px;">
下滑加载上一分类
</view>
</view>
</template>
<view style="padding: 20rpx;min-height: 100%;" @touchstart="onTouchstart"
@touchend="onTouchend" @touchmove="onTouchmove">
<view v-if="cat_list && cat_list.length > 0" style="margin-bottom: 20rpx;">
{{ cat_list[cat_index].name }}
</view>
<view v-for="(item, index) in goods_list" @click="show_goods_id = item.goods_id"
style="display: flex;width: 100%;background: #FFF;border-radius: 14rpx;box-shadow: 0px 0px 8rpx 0px rgba(0, 0, 0, 0.1);margin-bottom: 20rpx;overflow: hidden;">
<view style="background: #F0F0F0;">
<image style="display: block;width: 200rpx;height: 200rpx;"
:src="item.goods_info.pic_url" mode="aspectFill"></image>
</view>
<view
style="flex: 1;padding: 10rpx 14rpx;display: flex;flex-direction: column;justify-content: space-between;">
<view>
<view class="goods_name">{{ item.goods_info.name }}</view>
<view style="color: #A16222;font-weight: bold;margin-top: 16rpx;">
¥{{ item.goods_info.price_min }}起
</view>
</view>
<view style="display: flex;justify-content: flex-end;">
<view @click.stop="chooseSpecifications(item, $event)" :data-index="index">
<u-icon name="plus-circle-fill"
:color="mch && mch.main_color ? mch.main_color : '#A16222'"
size="50rpx"></u-icon>
</view>
</view>
</view>
</view>
<template v-if="goods_loading == 0">
<!-- 加载中 -->
<view
style="padding: 20rpx;display: flex;align-items: center;justify-content: center;">
<u-loading-icon></u-loading-icon>
</view>
</template>
<view v-else>
<view v-if="(cat_index + 1) < cat_list.length"
style="font-size: 28rpx;color: #999;line-height: 60rpx;display: flex;align-items: center;justify-content: center;">
<view style="margin-right: 10rpx;">
{{ bottom_scoll_px < 200 ? '上滑加载下一分类' : '释放加载下一分类' }}
</view>
<view :style="{
transform: 'rotateX(' + (180 * bottom_scoll_px / 200) + 'deg)'
}" style="border: 1rpx solid #999;width: 34rpx;height: 34rpx;border-radius: 50%;display: flex;align-items: center;justify-content: center;">
<u-icon name="arrow-upward" color="#999" size="28rpx"></u-icon>
</view>
</view>
</view>
<view style="height: 180rpx;width: 100%;"></view>
</view>
</scroll-view>
</view>
<!-- <view v-if="bottom_scoll_px > 0"
style="display: flex;justify-content: center;overflow: hidden;position: absolute;left: 0;right: 0;bottom: 0;"
:style="{
height: bottom_scoll_px + 'px'
}">
<view style="font-size: 28rpx;color: #999;line-height: 60px;">
上滑加载下一分类
</view>
</view> -->
</view>
</view>
</view>
<view class="bttom-box" style="padding: 0 30rpx;" v-show="1 || goodsArr.reduce((sum, item) => sum + (item.num - 0), 0) > 0">
<view
style="padding: 10rpx 20rpx;display: flex;align-items: center;justify-content: space-between;position: relative;z-index: 1;background: #FFF;width: 100%;border-radius: 70rpx;border: 2rpx solid #F0F0F0;">
<view style="display: flex;align-items: center;">
<view @click="show_card = !show_card"
style="width: 100rpx;height: 100rpx;background: #FFF;border-radius: 50%;display: flex;align-items: center;justify-content: center;position: relative;">
<u-icon size="90rpx" name="shopping-cart"
:color="mch && mch.main_color ? mch.main_color : '#A16222'"></u-icon>
<view
style="position: absolute;background: #BD3124;color: #FFF;font-size: 20rpx;line-height: 30rpx;padding: 0 10rpx;border-radius: 15rpx;right: 0;top: 0;">
{{ goodsArr.reduce((sum, item) => sum + (item.num - 0), 0) }}
</view>
</view>
<view style="margin-left: 40rpx;color: #000;font-weight: bold;font-size: 40rpx;">
<!-- ¥{{ (
goodsArr.reduce((sum, item) => sum + (item.activeGoodsInfo.price * item.num - 0), 0)
).toFixed(2) }} -->
¥{{ totalPrice }}
</view>
</view>
<view @click="toSubmit" :style="{
background: mch && mch.main_color ? mch.main_color : '#A16222'
}" style="color: #FFF;padding: 0 40rpx;line-height: 80rpx;border-radius: 40rpx;font-size: 32rpx;">
去下单
</view>
</view>
<view style="position: fixed;bottom: 0;top: 0;left: 0;right: 0;background: rgba(0, 0, 0, .2);"
@click="show_card = !show_card" v-if="show_card">
<view :style="{
maxHeight: show_card ? '60vh' : '0'
}" style="position: absolute;left: 0;right: 0;bottom: 0;background: #FFF;border-radius: 20rpx 20rpx 0 0;z-index: 0;transition: max-height 0.5s;overflow-y: scroll;">
<view
style="padding: 20rpx 30rpx;border-bottom: 1rpx solid #F0F0F0;position: sticky;top: 0;z-index: 3;background: #FFF;">
购物车({{ goodsArr.reduce((sum, item) => sum + (item.num - 0), 0) }})
</view>
<view style="padding: 20rpx;flex: 1;overflow-y: scroll;">
<view v-for="(item, index) in goodsArr" v-if="item.num > 0"
style="display: flex;width: 100%;background: #f7f7f7;border-radius: 14rpx;margin-bottom: 20rpx;overflow: hidden;padding: 16rpx;">
<view style="overflow: hidden;">
<image style="display: block;width: 140rpx;height: 140rpx;border-radius: 18rpx;"
:src="item.goods.pic_url" mode="aspectFill"></image>
</view>
<view
style="flex: 1;padding: 10rpx 14rpx;display: flex;flex-direction: column;justify-content: space-between;">
<view>
<view class="goods_name" style="-webkit-line-clamp: 1;font-size: 20rpx;">
{{ item.goods.name }}
</view>
</view>
<view class="item-desc" style="margin: 10rpx 0;">
<view class="goods_sky" style="color: #999;font-size: 24rpx;">
<text v-for="(sku, _index) of item.activeGoodsInfo.attr_list" :key="_index">
{{ sku.group_name }}{{ sku.name }}
</text>
</view>
</view>
<view style="display: flex;">
<view v-for="(small, index) of item.small_goods" :key="index"
v-show="small.group_item.length != 0">
<view
style="display: flex;background: #FFF;margin: 0 10rpx 10rpx 0;font-size: 22rpx;padding: 10rpx 20rpx;flex-wrap: nowrap;align-items: center;border-radius: 10rpx;justify-content: center;"
v-for="sitem of small.group_item">
<view>
{{ sitem.name }}
</view>
<view v-if="sitem.price" style="color:#BD3124;">
{{ sitem.price }} 元
</view>
</view>
</view>
</view>
<view style="display: flex;justify-content: space-between;align-items: center;">
<view style="color: #A16222;font-weight: bold;">
¥{{ item.activeGoodsInfo.price }}
</view>
<u-number-box :min="0" v-model="item.num"></u-number-box>
</view>
</view>
</view>
</view>
<view style="height: 180rpx;"></view>
</view>
</view>
</view>
<logins v-if="wcCode != -1" :wcCode="wcCode"
:type="$utils.isInAliBrowser() || $utils.isInWeChatBrowser() ? 0 : 2" @isLogin="getCatList"></logins>
<pageSku v-if="goods.id" ref="pagesku" :goods="goods" @skuPopData="skuPopData"></pageSku>
<view v-if="show_donghua == 1" :animation="animationData"
style="position: fixed;right: 32rpx;top: 600rpx;z-index: 10;" :style="{
top: top + 'px'
}">
<!-- <image style="width: 50rpx;height: 50rpx;" src="../my/images/av.png" mode=""></image> -->
<u-icon size="50rpx" name="plus-circle-fill" :color="mch && mch.main_color ? mch.main_color : '#A16222'"
style="background: #fff;border-radius: 50%;"></u-icon>
</view>
<goods v-if="show_goods_id > 0" :goods_id="show_goods_id" @close="show_goods_id = 0"></goods>
<u-popup mode="bottom" :show="show_ren" round="20rpx">
<view v-if="ren_setting" style="padding-bottom: 50rpx;font-size: 40rpx;">
<view style="text-align: center;line-height: 80rpx;font-size: 34rpx;">
请选择人数
</view>
<view style="display: flex;flex-wrap: wrap;">
<view v-for="(item, index) in (ren_setting.max_num - ren_setting.min_num + 1)">
<view @click="table_num = index + (ren_setting.min_num - 0);show_ren = false"
style="padding: 30rpx 40rpx;margin: 20rpx;background: #F0F0F0;border-radius: 10rpx;">
{{ index + (ren_setting.min_num - 0) }}
</view>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import logins from '@/components/login/logins.vue'
import pageSku from "./compontents/page-sku.vue";
import goods from "./compontents/goods.vue";
export default {
components: {
logins,
pageSku,
goods
},
data() {
return {
wcCode: -1,
mch_id: 0,
store_id: 0,
n_id: 0,
cat_index: 0,
goods_loading: 0,
cat_list: [],
goods_list: [],
mch: null,
table: null,
goods: {},
goodsArr: [],
show_card: false,
top: 0,
show_donghua: 0,
animationData: {},
animation: null,
cartData: null,
is_cont: 0,
show_goods_id: 0,
keyword: '',
is_scroll_bottom: false,
start_i: 0,
end_i: 0,
triggered: false,
required_list: [], // 必选订单
show_ren: false,
ren_setting: null,
table_num: 0
}
},
watch: {
cat_index(value) {
this.goods_list = []
this.getGoods()
}
},
async onLoad(query) {
let that = this
if (query.wxcode) {
uni.getStorage({
key: 'take_query',
success(res) {
if (!res.data.mch_id) {
uni.showModal({
title: '提示',
showCancel: false,
content: JSON.stringify(res)
})
} else {
that.mch_id = res.data.mch_id
that.store_id = res.data.store_id
that.n_id = res.data.n_id
that.is_cont = res.data.is_cont ? 1 : 0
that.$nextTick(() => {
that.wcCode = query.wxcode
})
}
},
fail(res) {
uni.showModal({
title: '提示',
showCancel: false,
content: JSON.stringify(res)
})
}
})
} else {
this.mch_id = query.mch_id
this.store_id = query.store_id
this.n_id = query.n_id
if (query.mch_id) {
uni.setStorage({
data: {
mch_id: query.mch_id,
store_id: query.store_id,
n_id: query.n_id,
is_cont: query.is_cont,
},
key: 'take_query',
success() {
that.is_cont = query.is_cont ? 1 : 0
that.wcCode = ''
if (!that.$utils.isInAliBrowser() && !that.$utils.isInWeChatBrowser()) {
that.getCatList()
}
},
fail(res) {
uni.showModal({
title: '提示',
showCancel: false,
content: JSON.stringify(res)
})
}
})
} else {
// uni.showModal({
// title: '提示',
// showCancel: false,
// content: '参数错误'
// })
}
// this.getCatList(query)
}
},
//发送给朋友
onShareAppMessage(res) {},
onPullDownRefresh() {},
onShow() {},
onReady() {
setTimeout(() => {
let view = uni.createSelectorQuery().select(".bttom-box");
if (view) {
view.boundingClientRect(data => {
this.cartData = data
}).exec();
}
}, 200)
},
onHide() {},
computed: {
totalPrice() {
return this.goodsArr.reduce((pre, cur) => {
let price = cur.activeGoodsInfo.price * cur.num
// 计算小料
let smallMaterialPrice = 0
if (cur.small_goods) {
smallMaterialPrice = cur.small_goods.reduce((price, item) => {
return price + item.group_item.reduce((price, item) =>
price + item.price, 0)
}, 0)
}
smallMaterialPrice = cur.num * (Number(smallMaterialPrice))
return pre + Number(price) + smallMaterialPrice;
}, 0).toFixed(2);
},
bottom_scoll_px() {
if (this.is_scroll_bottom && (this.start_i - this.end_i) > 0 && this.start_i > 0 && this.end_i > 0) {
return (this.start_i - this.end_i) > 200 ? 200 : (this.start_i - this.end_i)
} else {
return 0
}
}
},
methods: {
onTouchstart(e) {
if (this.is_scroll_bottom) {
this.start_i = e.changedTouches && e.changedTouches.length > 0 ? e.changedTouches[0].pageY : 0
}
},
onTouchmove(e) {
if (this.is_scroll_bottom) {
this.end_i = e.changedTouches && e.changedTouches.length > 0 ? e.changedTouches[0].pageY : 0
}
},
onTouchend(e) {
if (this.start_i > 0) {
this.end_i = e.changedTouches && e.changedTouches.length > 0 ? e.changedTouches[0].pageY : 0
let start_i = this.start_i,
end_i = this.end_i
this.start_i = 0
this.end_i = 0
if (start_i > end_i && this.is_scroll_bottom) {
if (this.is_scroll_bottom && (start_i - end_i) > 200) {
if (this.cat_index + 1 < this.cat_list.length) {
this.cat_index += 1
}
}
}
}
},
sBottome() {
setTimeout(() => {
this.is_scroll_bottom = true
}, 500)
},
onRefresh(e) {
// console.log(e, 'onRefresh')
var that = this;
if (!this.triggered) {
//下拉加载先让其变true再变false才能关闭
this.triggered = true;
//关闭加载状态 (转动的圈),需要一点延时才能关闭
setTimeout(() => {
that.triggered = false;
}, 500)
}
},
onStore(e) {
if (this.cat_index > 0) {
this.cat_index -= 1
}
},
getData() {
this.cat_list = []
this.goods_list = []
this.cat_index = 0
this.$nextTick(() => {
this.getCatList({
store_id: this.store_id,
mch_id: this.mch_id,
n_id: this.n_id,
})
})
},
async getCatList() {
uni.showLoading({
title: '加载中'
})
let res = await this.$api.common.getFootCat({
store_id: this.store_id,
mch_id: this.mch_id,
n_id: this.n_id,
keyword: this.keyword
})
uni.hideLoading()
if (res.code > 0) {
uni.showModal({
title: '提示',
content: res.msg,
showCancel: false,
success() {
}
})
} else {
if (res.data.is_more && res.data.is_more > 0 && this.is_cont == 0) {
uni.reLaunch({
url: '/pages/takeaway/orderAndSettlement/edit?n_id=' + this.n_id + '&mch_id=' +
this.mch_id + '&store_id=' + this.store_id
})
}
this.cat_list = res.data.cat_list
this.mch = res.data.mch
this.table = res.data.table
if (res.data.cat_list.length > 0) {
this.$nextTick(() => {
this.getGoods()
})
}
}
this.showRen()
},
async getGoods() {
this.goods_loading = 0
this.is_scroll_bottom = true
this.triggered = false
this.start_i = 0
this.end_i = 0
let res = await this.$api.common.getFootGoods({
cat_id: this.cat_list[this.cat_index].id,
store_id: this.store_id,
mch_id: this.mch_id,
keyword: this.keyword
})
this.goods_loading = 1
if (res.code > 0) {
uni.showModal({
title: '提示',
content: res.msg,
showCancel: false,
success() {}
})
} else {
if (this.cat_list[this.cat_index].id == 0) {
this.required_list = res.data
}
this.goods_list = res.data
}
},
// 选择规格
async chooseSpecifications(params, e) {
uni.showLoading({
title: "请稍等",
mask: true,
});
this.goods = {};
await this.$nextTick()
const res = await this.$api.common.goodsInfo({
id: params.goods_id
});
this.goods = res.data
await this.$nextTick()
await this.setStart(e)
setTimeout(async () => {
uni.hideLoading();
this.$refs.pagesku.skuPopData.type = 2;
this.$refs.pagesku.$refs?.popup?.open();
}, 0)
},
async skuPopData(e) {
const goods = this.goodsArr.find(item => item.goods_sku_id === e.goods_sku_id && item
.small_goods_json ===
e.small_goods_json)
if (goods) {
let goodsArr = this.goodsArr
this.goodsArr.forEach((item, index) => {
if (item.goods_sku_id === e.goods_sku_id && item.small_goods_json === e
.small_goods_json) {
this.goodsArr[index].num = (this.goodsArr[index].num - 0) + 1
}
})
this.goodsArr = []
this.goodsArr = goodsArr
} else {
e.key = Math.random()
this.goodsArr.push(JSON.parse(JSON.stringify(e)))
}
console.log(this.goodsArr)
await this.$nextTick()
this.setA()
},
setStart(e) {
this.top = e.detail.y
var animation = uni.createAnimation({
duration: 600,
timingFunction: 'ease',
})
this.animation = animation
this.animationData = animation.export()
},
setA() {
this.show_donghua = 1
// 先旋转后放大
this.animation.translate('-600rpx', (this.cartData.top - this.top)).step()
this.animationData = this.animation.export()
setTimeout(() => {
this.show_donghua = 0
this.$nextTick(() => {
this.animation.translate('600rpx', -(this.cartData.top - this.top)).step()
this.animationData = this.animation.export()
})
}, 600)
},
updateCatIndex(index) {
if (this.cat_index == 0 && this.cat_list[this.cat_index] && this.cat_list[this.cat_index].id == 0) {
if (!this.verRequired()) {
uni.showToast({
icon: 'none',
title: '请选择必选商品'
})
} else {
this.cat_index = index
}
} else {
this.cat_index = index
}
},
// 验证必点商品是否已点
verRequired() {
let that = this
let goodsArr = this.goodsArr.filter(item => item.num > 0)
let required_list = that.required_list.filter((item) => {
return goodsArr.filter((item1) => {
return item.goods_info.id == item1.goods.id
}).length > 0 ? true : false
})
return that.required_list.length <= required_list.length
},
toSubmit() {
let goodsArr = this.goodsArr.filter(item => item.num > 0)
if (!goodsArr.length) {
uni.$u.toast("请选择点餐商品")
return
}
if (this.required_list && this.required_list.length > 0) {
if (!this.verRequired()) {
uni.$u.toast("请选择必选商品")
return
}
}
let that = this
uni.setStorage({
key: 'take_n_id_' + this.n_id,
data: goodsArr,
success() {
uni.navigateTo({
url: "/pages/takeaway/orderAndSettlement/index?" + "n_id=" + that.n_id +
"&mch_id=" + that.mch_id + "&store_id=" + that.store_id + "&table_num=" +
that.table_num,
});
}
})
},
async showRen() {
this.goods = {};
await this.$nextTick()
const res = await this.$api.common.getRen({
store_id: this.store_id,
mch_id: this.mch_id,
n_id: this.n_id,
});
if (res.code == 0) {
this.show_ren = true
this.ren_setting = res.data
}
},
}
}
</script>
<style lang="scss" scoped>
.hearder-box {
// background: linear-gradient(to bottom, #D6BDA3, #F3EEE8);
// background: #FFF;
padding: 20rpx;
}
.content-box {
display: flex;
flex: 1;
background: blue;
border-radius: 20rpx 20rpx 0 0;
overflow: hidden;
.left-tab {
width: 160rpx;
height: 100%;
background: #E3DAD0;
}
.right-tab {
flex: 1;
height: 100%;
background: #FFF;
}
}
.bttom-box {
// padding-bottom: constant(safe-area-inset-bottom);
// padding-bottom: env(safe-area-inset-bottom);
height: 180rpx;
background: rgba(0, 0, 0, 0);
display: flex;
align-items: flex-start;
width: calc(100% - 0rpx);
position: fixed;
left: 0;
right: 0;
bottom: 0rpx;
padding: 0 10rpx;
}
.cat-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 30rpx;
padding: 20rpx;
color: #666666;
}
.cat-item-active {
background: #FFF;
color: #000;
font-weight: bold;
}
.goods_name {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
/* 定义文本的行数 */
overflow: hidden;
text-overflow: ellipsis;
font-size: 28rpx;
}
.minus {
border: 1px solid #e5e5e5;
border-right: none;
border-radius: 20px 0 0 20px;
padding: 6px;
}
.plus {
border: 1px solid #e5e5e5;
border-left: none;
border-radius: 0 20px 20px 0;
padding: 6px;
}
.numInput {
width: 35px;
text-align: center;
border: 1px solid #e5e5e5;
padding: 3px 0;
height: 20px;
line-height: 20px;
font-size: 12px;
color: #000;
}
</style>