Files
2025-09-04 17:04:21 +08:00

511 lines
12 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 class="cate">
<view class="cate-one row">
<view class="aside">
<scroll-view style="height: 100%;" scroll-y="true" scroll-with-animation="true">
<view style="padding-bottom: 200rpx;">
<block v-for="(item, index) in cateList" :key="index">
<view :class="'one-item sm ' + (index == selectIndex ? 'active bg-white' : '')"
@click="changeActive(index)">
<text class="name">{{ item.name }}</text>
<view v-if="index == selectIndex" class="active-line bg-default"></view>
</view>
</block>
</view>
</scroll-view>
</view>
<view class="main">
<scroll-view style="height: 100%" scroll-y="true" scroll-with-animation="true"
@scrolltolower="getGoodsSearchFun">
<view class="main-wrap">
<view class="goods">
<view class="u-p-t-32 bold-600">{{ cateName }}</view>
<view class="u-p-t-32">
<navigator :url="`/pages/shop/shop?id=${item.id}`" hover-class="none"
class="bg-white br16 row u-col-top u-m-b-24" v-for="(item, index) in goodsList"
:key="index">
<view>
<u-image :src="item.image" width="136" height="136"
border-radius="16"></u-image>
</view>
<view class="info">
<view>
<view class="u-line-2 u-p-t-10">{{ item.name }}</view>
<view class="u-p-t-20 row-between">
<view class="row">
<view class="primary">
<price-format :price="item.price" :subscriptSize="22"
:firstSize="34" :secondSize="26"></price-format>
</view>
<view class="u-m-l-8">
<price-format :price="item.market_price" :lineThrough="true"
color="#C0C0C0" :subscriptSize="22" :firstSize="22"
:secondSize="22"></price-format>
</view>
</view>
</view>
</view>
<view class="column-end">
<view @click.stop="addCartFun(item)">
<u-icon name="plus-circle-fill" color="#254062" size="48"></u-icon>
</view>
<!-- <u-button @click="openSpec(item.name)" hover-class="none"
:customStyle="{width: '116rpx', height: '46rpx', lineHeight: '46rpx', fontSize: '24rpx', backgroundColor: themeColor, color: '#fff', border: 'none', paddingTop: '8rpx'}"
:hair-line="false"
shape="circle">
选规格
</u-button> -->
</view>
</view>
</navigator>
<loading-footer :status="status" :slot-empty="true">
<view slot="empty" class="column-center" style="padding: 200rpx 0 0">
<text class="lighter sm">暂无商品</text>
</view>
</loading-footer>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
<view class="buy mx40 px40 br60 row-between">
<view class="row" @tap="showCartPopup">
<view class="u-relative">
<u-image :src="cloudPath + 'img/icon_cart.png'" width="80" height="80"></u-image>
<view class="u-absolute top-0 right-0 text-fff number u-text-center xxs" v-if="cartNum">
{{ cartNum }}
</view>
</view>
<view class="u-m-l-32">
<view class="row-center" v-if="totalPrice">
<text class="text-fff">
共计
</text>
<view class="primary u-m-t-10 u-m-l-20">
<price-format :price="totalPrice" :subscriptSize="26" :firstSize="34"
:secondSize="26"></price-format>
</view>
</view>
<view class="text-fff" v-else>
未选购商品
</view>
</view>
</view>
<view class="text-999" @tap="goSettle">去结算</view>
</view>
<!-- 购物车 -->
<u-popup v-model="showCart" mode="bottom" :border-radius="16">
<view style="max-height: 800rpx;">
<view class="px20 text-999 mt20">
温馨提示:请适量点餐,套餐与单品系列限购2套
</view>
<view v-if="cartLists.length > 0">
<scroll-view style="height: 700rpx;" scroll-y="true" scroll-with-animation="true">
<view class="row-start u-row-between u-p-t-20 u-padding-bottom-20 px20"
v-for="(item, index) in cartLists" :key="index">
<view class="row-start">
<view>
<u-image :src="item.img" width="136" height="136" border-radius="16"></u-image>
</view>
<view class="ml20">
<view class="u-line-2 sm">{{ item.name }}</view>
<view class="xxs text-999 u-m-t-8 attr u-p-6-8 u-p-b-8">
<text>味浓芳香</text>
<text class="u-m-l-8 u-m-r-8">|</text>
<text>味浓芳香</text>
<text class="u-m-l-8 u-m-r-8">|</text>
<text>味浓芳香</text>
</view>
<view class="primary">
<price-format :price="item.price" :subscriptSize="22" :firstSize="34"
:secondSize="26"></price-format>
</view>
</view>
</view>
<view>
<view class="u-text-right" @tap="deleteGoods(item.cart_id)">
<u-icon class="u-p-t-10" name="trash" size="32"></u-icon>
</view>
<view class="u-p-t-30">
<u-number-box :disabled="item.cart_status != 0" :min="1" :max="item.first_category_id == 1 || item.first_category_id == 2 ? 2 : item.stock"
:value="item.goods_num" @blur="countChange($event, item.cart_id, item)"
@minus="countChange($event, item.cart_id, item)"
@plus="countChange($event, item.cart_id, item)"></u-number-box>
</view>
</view>
</view>
<view class="settle-btn">
<u-button @tap="goSettle" shape="circle" :hair-line="false" hover-class="none"
:customStyle="{ backgroundColor: themeColor, color: '#fff', border: 'none', padding: '36rpx' }">去结算</u-button>
</view>
</scroll-view>
</view>
<view class="u-text-center" style="height: 700rpx;line-height: 700rpx;" v-else>
~ 暂无商品 ~
</view>
</view>
</u-popup>
<shop-spec v-model="showSpec" :name="goodsName" :spec="goods_spec" @close="showSpec = false"
@confirm="confirmSpec"></shop-spec>
</view>
</template>
<script>
import {
mapActions,
mapGetters
} from 'vuex';
import {
loadingFun
} from '@/utils/tools'
import {
getGoodsSearch,
addCart,
getPoster,
getCartNum,
getCartList,
changeGoodsCount,
deleteGoods
} from '@/api/store';
import {
loadingType
} from '@/utils/type';
export default {
name: "cate-one",
props: {
list: {
type: Array,
default: () => ([])
}
},
data() {
return {
page: 1,
status: loadingType.LOADING,
selectIndex: 0,
categoryId: 0,
cateList: [],
goodsList: [],
goods_spec: [],
cateName: '',
numberVal: 1,
showCart: false,
showSpec: false,
goods_num: 0,
cartLists: [],
totalPrice: 0,
goodsName: '',
}
},
created() {
this.getCartNum();
this.getCartListFun();
uni.$on('refreshCartList', this.getCartListFun);
},
beforeDestroy() {
uni.$off('refreshCartList', this.getCartListFun);
},
methods: {
...mapActions(['getCartNum']),
// 切换商品分类
changeActive(index) {
const {
cateList
} = this
this.cateName = cateList[index].name
this.selectIndex = index
this.onRefresh()
},
onRefresh() {
this.page = 1
this.goodsList = []
this.status = loadingType.LOADING
this.$nextTick(() => {
this.getGoodsSearchFun();
});
},
async getGoodsSearchFun() {
let {
page,
goodsList,
priceSort,
saleSort,
status,
cateList,
selectIndex
} = this;
const item = cateList[selectIndex]
if (item.type == 0) return
if (status == loadingType.FINISHED) return;
const params = {
category_id: item.id,
page_no: page,
price: priceSort,
sales_sum: saleSort
}
const data = await loadingFun(getGoodsSearch, page, goodsList, status, params)
console.log(data);
if (!data) return
this.page = data.page
this.goodsList = data.dataList
this.status = data.status
},
// 显示购物车弹出窗
showCartPopup() {
if (this.cartLists.length > 0) {
this.showCart = true
} else {
this.$toast({
title: '请先添加商品'
});
}
},
// 添加到购物车(默认商品数量+1,可以让后端连表查询商品数量字段)
async addCartFun(item) {
uni.navigateTo({
url: `/pages/shop/shop?id=${item.id}&showPopup=true`
})
return
// 限购逻辑
if (item.first_category_id === 1 || item.first_category_id === 2) {
// 统计购物车中同类商品的总数量
const totalNum = this.cartLists
.filter(i => i.first_category_id === item.first_category_id)
.reduce((sum, i) => sum + (i.goods_num || 0), 0);
if (totalNum >= 2) {
this.$toast({ title: '该类商品每人限购2件' });
return;
}
}
const {
code,
data,
msg
} = await addCart({
item_id: item.id,
goods_num: 1
});
if (code == 1) {
this.getCartListFun()
}
},
// 打开规格弹窗
openSpec(name) {
this.showSpec = true
this.goodsName = name
},
// 购物车商品里面的数量
countChange({ value }, cartId, item) {
console.log("countChange", value, cartId, item);
changeGoodsCount({
cart_id: cartId,
goods_num: value,
}).then((res) => {
if (res.code == 1) {
this.getCartListFun()
}
});
},
// 获取购物车列表数据
getCartListFun() {
// 获取商品的分类ID
getCartList().then((res) => {
if (res.code == 1) {
let {
lists,
total_amount
} = res.data;
this.cartLists = lists;
console.log("🚀 ~ getCartListFun ~ lists:", lists)
// // let cartType = 0;
// // if (lists.length == 0) {
// // cartType = 2;
// // } else {
// // cartType = 1;
// // }
// this.cartLists = list;
// console.log(">>>", this.cartLists);
// // this.cartType = cartType;
this.totalPrice = total_amount
// // this.isShow = true;
this.getCartNum();
}
});
},
// 购物车删除商品
deleteGoods(cart_id) {
deleteGoods({
cart_id
}).then((res) => {
if (res.code == 1) {
this.getCartListFun();
}
});
},
// 去结算
goSettle() {
console.log(this.cartLists)
this.showCart = false
const goods = this.cartLists.map(item => {
return {
item_id: item.item_id,
num: item.goods_num
}
})
uni.navigateTo({
url: "/pages/order_now/order_now?data=" +
encodeURIComponent(
JSON.stringify({
goods,
type: "cart",
})
),
});
},
// 跳转商品详情页
toShop(id) {
uni.navigateTo({
url: `/pages/shop/shop?id=${id}`
})
}
},
computed: {
...mapGetters(['cartNum']),
// 显示购物车数量
buyNumber() {
if (this.goods_num > 0) {
return this.goods_num > 99 ? '99+' : this.goods_num
}
return ''
}
},
watch: {
list: {
handler(val) {
if (!val.length) return
let index = val.findIndex((item) => item.type == 1)
this.selectIndex = index == -1 ? 0 : index
this.cateName = val[this.selectIndex].name
this.cateList = val
this.getGoodsSearchFun()
}
}
},
}
</script>
<style lang="scss">
page {
padding-bottom: 0;
}
$header-height: 94rpx;
.cate {
position: relative;
}
.cate-one {
height: 100vh;
.aside {
width: 180rpx;
flex: none;
height: 100%;
background-color: #F7F8FA;
.one-item {
position: relative;
text-align: center;
height: 108rpx;
line-height: 108rpx;
&.active {
color: $-color-theme;
font-size: 26rpx;
font-weight: bold;
}
.active-line {
position: absolute;
width: 6rpx;
height: 30rpx;
left: 4rpx;
top: 50%;
transform: translateY(-50%);
}
}
}
.main {
background-color: #FFFAFB;
height: 100%;
flex: 1;
.main-wrap {
position: relative;
padding: 0 20rpx 160rpx;
.goods {
.info {
width: 100%;
display: flex;
justify-content: space-between;
margin: 0 16rpx;
}
}
}
}
}
.buy {
position: fixed;
left: 0;
right: 0;
bottom: calc(env(safe-area-inset-bottom) + 10rpx);
height: 100rpx;
background-color: #212526;
}
.number {
background-color: #FF2C3C;
width: 40rpx;
height: 40rpx;
line-height: 40rpx;
border-radius: 100%;
}
.settle-btn {
padding: 20rpx;
}
</style>