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

954 lines
24 KiB

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 class="page">
<view class="fixhead" :style="{ marginTop: geStatusBarHeight() + 'px'}">
<selShop :showName="false" :showQR="true" :shop="shop" @changeArea="changeArea"></selShop>
<view @tap="gotoSearch" >
<uni-search-bar v-model="searchValue" placeholder="请输入关键字" bg-color="#FFFFFF" :readonly="true"></uni-search-bar>
</view>
<scroll-view class="scrolltab" scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
<view class="tab" v-for="(item, index) in list" :key="index" :class="index==tabCurrentIndex?'cur':''" @tap="tabSelect" :data-id="index">
{{item.name}}
</view>
</scroll-view>
</view>
<!-- 关联框示例 -->
<view v-if="!ifshow" class="tcon">
<view class="scell" v-for="(item, index) in searList" :key="index" @click="navToList(item.id)">
<uni-icons type="search" size="20" color="#666"></uni-icons>
<view class="stxt" v-html="highlightKeyword(item.title, searchValue)"></view>
</view>
</view>
<!-- 商品列表 -->
<view v-else class="f-list">
<!-- 广告 -->
<view class="adcon" v-if="adcoursesList.length>0||adgoodsList.length>0">
<view class="adrow" v-if="adgoodsList.length>0" style="background: #f8f6f9;">
<view class="adhead">
<view class="txt">达人好物</view>
<view class="tip">买贵双倍赔</view>
</view>
<scroll-view class="scroll-view_H" scroll-x="true" scroll-with-animation scroll-left="0">
<view class="adimg" v-for="(item,ii) in adgoodsList" :key="item.id" @click="navToGood(item)">
<image :src="item.pic" mode="scaleToFill"></image>
<view class="adname">{{item.name}}</view>
</view>
</scroll-view>
</view>
<view class="adrow" v-if="adcoursesList.length>0" style="margin-left: 2%; background: #f5f9fa;">
<view class="adhead">
<view class="txt">精品课程</view>
<view class="tip"></view>
</view>
<scroll-view class="scroll-view_H" scroll-x="true" scroll-with-animation scroll-left="0">
<view class="adimg" v-for="(item,ii) in adcoursesList" :key="item.id" @click="navToCourse(item)">
<image :src="item.pic" mode="scaleToFill"></image>
<view class="adname">{{item.name}}</view>
</view>
</scroll-view>
</view>
</view>
<view v-for="(tabItem,ii) in list" :key="tabItem.id">
<view v-show="ii==tabCurrentIndex">
<view class="guess-section" v-if="tabItem.goodsList.length>0">
<view
v-for="(item, index) in tabItem.goodsList" :key="index"
class="guess-item"
>
<view class="image-wrapper imgload" @click="navToList(item)">
<image :src="item.img" mode="aspectFill" lazy-load></image>
</view>
<view class="title" @click="navToList(item)">{{item.name}}</view>
<view class="cright">
<view class="price" @click="navToList(item)">
<text class="txt">¥</text>
<text class="tint">{{item.price}}</text>
<text class="txtt"> /{{item.unit}}</text>
</view>
<image class="cart" src="/static/image/cart.png" data-img="/static/image/cart.png" @tap="addCar($event,item)"></image>
</view>
</view>
</view>
<view v-if="tabItem.goodsList.length<1&&tabItem.loadStatus=='noMore'" class="skcon">
<image class="skimg" src="@/static/image/nodata.png" mode="aspectFill" ></image>
</view>
<uni-load-more v-if="tabItem.loadStatus!=='noMore'" iconType="circle" :status="tabItem.loadStatus" :content-text="contentText" />
</view>
</view>
</view>
<!-- 是否登录 -->
<openlogin ref="loginId" @getPhoneNumber="getPhoneNumber"></openlogin>
<!-- service 客服-->
<service ref="serviceId" @goservice="goservice"></service>
<!-- top 返回顶部-->
<top ref="topId"></top>
<!-- cart 购物车-->
<cart ref="cartId" x="0.74" y="1.2" @addShopCar="addShopCar" :pdata="product" :ptype="1"></cart>
<!-- cartx carty x0.1 y0.1 x0.9 y0.9-->
<shopCarAnimation ref="carAnmation" cartx="0.74" carty="1.2"></shopCarAnimation>
</view>
</template>
<script>
import { myCache,getcartNum,getRemoteFile } from '../../utils/utils.js';
import openlogin from "../components/openlogin.vue";
import top from "../components/top.vue";
import service from "../components/service.vue";
import selShop from "../components/selShop.vue";
import cart from "../components/cart.vue";
// 加入购物车动画组件
import shopCarAnimation from '@/components/fly-in-cart/fly-in-cart.vue'
export default {
components: {
openlogin,top,service,selShop,cart,shopCarAnimation
},
data() {
return {
openId:"",
phone:"",
userid:"",
ifshow:true, // 显示检索商品
searchValue:"",
ifsear:false,
shop:myCache('myshop')?myCache('myshop'):'',
scrollLeft: 0,
tabCurrentIndex:0,
list:myCache("spgglist"),
contentText: {
contentdown: '查看更多',
contentrefresh: '加载中',
contentnomore: ''
},
searList:[
// {
// id:1,
// title:"瑜伽健身球1"
// }
],
adcoursesList:myCache("spgglist"),
adgoodsList:[
// {
// sort:1,
// id:1,
// pic:'../../static/image/theme/p4.jpg',
// name:'瑜伽球瑜伽球瑜伽球瑜伽球瑜伽球瑜伽球瑜伽球'
// }
],
product:{
id:1,
productId:1,
name:'',//"杜威克瑜伽球加厚防滑",
remarks:'',//"0.8cm加厚PVC材质实测承重达200kg防滑底纹设计实测湿滑地面不侧翻超静音充气阀",
price:0,//29.9,
preprice:0,//45,
unit:'',//"个",
tip:'',//"热销",
type:'1',
// 商品参数信息
list:[
// {
// name:"商品编码",
// text:"311289700098"
// },
],
pjnum:2,
pjrimg:'../../static/image/ibg.png',
pjname:'',//'小梅花',
pjdate:'',//'2026-06-26',
pjcontent:'该用户觉得商品很好,给出了好评。',
img:'',//'../../static/image/theme/p1.jpg',// 详情
img1:'',//'../../static/image/theme/p2.jpg',// 规格图片
quantity:1, // 商品数量
ifspec:'1',
sels:"",
specs:[]
},
};
},
onLoad(option) {
if(option.id||option.id==0){
if(parseInt(option.id)==0){
this.tabCurrentIndex=0;
}
else{
this.tabCurrentIndex=parseInt(option.id);
}
this.scrollLeft = (this.tabCurrentIndex - 1) * 90;
}
},
mounted() {
if(this.userid==""||this.userid=="0"){
this.$refs.loginId.open();
}
},
onShow() {
this.openId = myCache('openId');
var user = myCache('user');
this.userid = user.userid? user.userid:'';
this.phone = user.userphone;
// this.shop = myCache('myshop')?myCache('myshop'):'';
// 先加载品类,在加载商品列表
this.getsortList();
// 广告
this.getggList();
// 购物车
var cartnum=getcartNum();
if(cartnum>0){
// 底部菜单消息角标
uni.setTabBarBadge({
//显示未读消息条数
index: 4,
text: cartnum+''
});
}
else{
uni.removeTabBarBadge({
index: 4
})
}
},
onPullDownRefresh() {
setTimeout(()=>{
uni.stopPullDownRefresh()
},500);
},
// onReachBottom() {
// console.log('onReachBottom');
// this.loadData();
// },
onPageScroll(e) {
//调用子组件方法
this.$refs.topId.topData(e.scrollTop);
},
methods: {
// 加入购物车
addShopCar(sels,quantity,buyType){
if(sels){
// 已加入购物车动画
var cartnum=getcartNum();
if(cartnum>0){
// 底部菜单消息角标
uni.setTabBarBadge({
//显示未读消息条数
index: 4,
text: cartnum+''
});
}
else{
uni.removeTabBarBadge({
index: 4
})
}
}
else{
if(buyType==1){
uni.showToast({
title: '加入购物车失败!请重试!',
icon: 'error',
duration: 2000
});
}
else{
uni.showToast({
title: '立即购买失败!请重试!',
icon: 'error',
duration: 2000
});
}
}
},
// 加入购物车
async addCar(e,item) {
console.log('加入购物车');
if(this.userid==""||this.userid=="0"){
this.$refs.loginId.open();
}
// 获取商品接口
try{
uni.showLoading();
const {data: res1} = await uni.$http.get('/api/product/detail/'+item.id);
if (res1&&res1.product) {
var product=res1.product;
this.product={
id:product.id,
productId:product.id, // 商品id
name:product.name, // 商品名称
productName:product.name, // 商品名称
unit:product.unit,
weight:product.weight, // 重量,默认克
instructor:product.instructor, // 备注
brandName:product.brandName, //
productCategoryName:product.productCategoryName, //
isCourse:product.isCourse, //
price:product.price, // 价格
pic:product.pic?product.pic:'',// 详情
img:product.pic?product.pic:'',// 详情
img1:product.pic?getRemoteFile(product.pic):'../../static/image/imgicon.png', // 规格图片 商品详情默认图片
state:product.showStatus, // 1已上架 2审核中 3已下架 4未通过 5草稿
customerService:product.scustomerService,// 客服id
quantity:1, // 商品数量
ifspec: res1.skus&&res1.skus.length>0?'1':'0',
skuId:"", //当前选中id
sels:"", //当前选中
specs:[],
skus:res1.skus,
spData:'',
stock:product.stock?product.stock:1000, //商品库存
}
// productAttr 规格
var productAttr= JSON.parse(product.productAttr);
if(productAttr&&productAttr.length>0){
productAttr.forEach((cell,ii)=>{
var list=[];
cell.options.forEach((item,kk)=>{
if(item.name){
list.push({name:item.name,id:kk})
}
});
this.product.specs.push({
id:ii,
name:cell.name,
sels:0,
list:list
});
this.$forceUpdate();
});
}
this.$forceUpdate();
if(this.product.ifspec=='1'){
// 初始化规格
this.selinit();
// 规格商品 弹框选规则
this.$refs.cartId.show();
}
else{
// 直接加入购物车
try{
var param={
productId:this.product.productId,
productName:this.product.name,
pic:this.product.img,
spData:this.product.spData,
skuId:this.product.skuId,
quantity:this.product.quantity,
storeId:myCache('myshopid')?myCache('myshopid'):'',
isCourse:this.product.isCourse,
};
const {data: res1} = await uni.$http.post('/api/cart/add',param);
if (res1) {
// 加入购物车动画
this.$refs.carAnmation.touchOnGoods(e);
// 缓存购物车
this.updatecart();
}
else{
uni.showModal({
title: '提示',
content: res1.message? res1.message:'加入购物车失败!请稍候再试',
cancelText: '取消',
confirmText: '确定',
});
}
}
catch(e){
console.log(e)
}
}
}
else{
uni.showModal({
title: '提示',
content: '当前商品异常,不可加入购物车..',
cancelText: '取消',
confirmText: '确定'
});
}
}
catch(e){
console.log(e)
}
},
selinit(){
// 初始化
if(this.product.specs&&this.product.specs.length>0){
var sels='',spData={};
this.product.specs.forEach((cell,idx)=>{
if(cell.list&&cell.list[cell.sels]){
sels=sels+cell.list[cell.sels].name+' ';
spData[cell.name]=cell.list[cell.sels].name;
}
});
this.product.sels=sels;
this.product.skus.forEach(cell=>{
if(cell.spData==JSON.stringify(spData)){
this.product.skuId=cell.id;
this.product.spData=cell.spData;
this.product.price=cell.price;
this.product.img=cell.pic?getRemoteFile(cell.pic):this.product.img1;
this.product.img1=cell.pic?getRemoteFile(cell.pic):this.product.img1;
this.product.stock=cell.stock;//库存
if(this.product.quantity>this.product.stock){
this.product.quantity=this.product.stock
}
else if(this.product.quantity==0&&this.product.stock>0){
this.product.quantity=1
}
}
});
this.$forceUpdate();
}
else{
this.product.sels='';
this.product.skuId=null;
this.$forceUpdate();
}
},
async updatecart(){
try{
const {data: res } = await uni.$http.get('/api/cart/list');
if (res&&res.length>0) {
// 购物车缓存
myCache("carts",res);
this.cartnum=getcartNum();
if(cartnum>0){
// 底部菜单消息角标
uni.setTabBarBadge({
//显示未读消息条数
index: 4,
text: cartnum+''
});
}
else{
uni.removeTabBarBadge({
index: 4
})
}
this.$forceUpdate();
}
}
catch(e){
console.log(e)
}
},
async getProduct(id) {
uni.showLoading({
title: '加载中...'
});
const {data: res} = await uni.$http.post('/api/product/detail/'+id);
if(res){
this.product = {
storeNmae:myCache('myshop'),// 所属门店
id: res.id,
productId: res.id,
name:res.name,
remarks:'',
price:res.price,
preprice:res.price,
unit:res.unit,
tip:"热销",
type:res.isCourse=='1'?'2':'1',
// 商品参数信息
list:[
{
name:"品牌名",
text:res.brandName
},
{
name:"商品分类",
text:res.productCategoryName
}
],
pjnum:203,
pjrimg:'../../static/image/ibg.png',
pjname:'小梅花',
pjdate:'2026-06-26',
pjcontent:'该用户觉得商品很好,给出了好评。',
img:'../../static/image/theme/p1.jpg',// 详情
img1:'../../static/image/theme/p2.jpg',// 规格图片
quantity:1, // 商品数量
ifspec:'1',
sels:"",
specs:[
// {
// id:1,
// name:"尺码",
// sels:0,
// list:[
// {
// id:11,
// name:"S"
// },
// {
// id:12,
// name:"M"
// },
// ]
// },
// {
// id:2,
// name:"颜色",
// sels:0,
// list:[
// {
// id:22,
// name:"黑色"
// }
// ],
// },
]
};
this.$forceUpdate();
}
else{
// 无商品信息
uni.showModal({
title: '提示',
content: '商品数据异常,加入购物车失败',
cancelText: '取消',
confirmText: '确定'
});
}
},
// 切换门店
changeArea(item){
console.log(item)
this.shop=item.storeName;
// 内容切换
this.$forceUpdate();
this.getsortList();
},
goservice(val){
console.log(val);
},
tabSelect(e) {
var that=this;
this.tabCurrentIndex = e.currentTarget.dataset.id;
this.scrollLeft = (e.currentTarget.dataset.id - 1) * 100;
this.loadData();
},
highlightKeyword(text, keyword) {
if (!keyword) return text;
// 使用正则表达式将关键词包裹在<span>标签中
const regex = new RegExp(keyword, 'gi');
return text.replace(regex, `<span style="color:#89965f">${keyword}</span>`);
},
getPhoneNumber(e){
if(e.userid){
this.userid = e.userid
}
this.getmember();
},
// 达人好物及精品课程
async getggList() {
// uni.showLoading({
// title: '数据加载中...'
// });
var para={
"storeId": myCache('myshopid')
}
const {data: res} = await uni.$http.post('/api/product/getGoodStuff', para);
if(res&&res.courses&&res.courses.length>0){
this.adcoursesList=res.courses;
this.$forceUpdate();
}
if(res&&res.goods&&res.goods.length>0){
this.adgoodsList=res.goods;
this.$forceUpdate();
}
// 缓存
myCache("spgglist",this.adgoodsList);
},
async getsortList() {
uni.showLoading({
title: '数据加载中...'
});
var para={
storeId:myCache('myshopid')
}
const {data: res} = await uni.$http.post('/api/product/categoryList', para);
if(res&&res.data&&res.data.length>0){
this.list=[];
res.data.forEach((cell,idx)=>{
this.list.push({
id:cell.id,
name:cell.typeName,
page:0,
size:10,
goodsList: [],
loadStatus:'more',//'more', // 'noMore',
})
});
this.$forceUpdate();
this.getList();
}
else{
// 暂无商品数据
uni.showModal({
title: '提示',
content: '暂无商品数据,请返回..',
cancelText: '取消',
confirmText: '确定',
success: ress => {
// 返回
// uni.navigateBack({
// delta: 1
// });
}
});
}
},
async getList() {
if(this.list[this.tabCurrentIndex].loadStatus!=="noMore")
{
// uni.showLoading({
// title: '数据加载中...'
// });
var para={
storeId:myCache('myshopid'),
categoryId:this.list[this.tabCurrentIndex].id,
search:this.searchValue,
}
const {data: res} = await uni.$http.post('/api/product/list?page='+this.list[this.tabCurrentIndex].page+'&size='+this.list[this.tabCurrentIndex].size, para);
if(res&&res.content&&res.content.length>0){
if(res.totalPages&&(1*res.totalPages-1)>this.list[this.tabCurrentIndex].page){
// 继续加载
this.list[this.tabCurrentIndex].loadStatus="more";
this.list[this.tabCurrentIndex].page=this.list[this.tabCurrentIndex].page+1;
this.contentText.contentnomore="";
this.$forceUpdate();
}
else{
this.list[this.tabCurrentIndex].loadStatus="noMore";
this.contentText.contentnomore="亲,没有商品数据了...";
this.$forceUpdate();
}
res.content.forEach((cell,idx)=>{
var celnew={
id:cell.id,
name:cell.name,
type:cell.isCourse=='1'?'2':'1',
img: cell.pic,
price:cell.price,
unit:"课",
ifspec:'0'
}
this.list[this.tabCurrentIndex].goodsList.push(celnew);
});
this.$forceUpdate();
}
else{
this.list[this.tabCurrentIndex].loadStatus="noMore";
this.contentText.contentnomore="亲,没有商品数据了...";
this.$forceUpdate();
}
// 缓存
myCache("splist",this.list);
}
},
getimgRemoteFile(img){
if(img){
img=img.split(',')[0];
return img;
// return getRemoteFile(img)
}
else{
return require("@/static/image/theme/p1.jpg")
}
},
searDo(){
this.loadData();
},
loadData(){
console.log('loadData',this.loadStatus)
// 加载
if(this.list[this.tabCurrentIndex].loadStatus=="more") {
this.list[this.tabCurrentIndex].loadStatus="loading";
setTimeout(() => {
this.getList();
}, 300);
}
},
splitNumber(num) {
var nums=num.split('.');
const intPart = nums[0]; // 获取整数部分
const decimalPart = nums[1]; // 获取小数部分
return { intPart, decimalPart };
},
navToGood(item){
uni.navigateTo({
url: `/pages/product/detail?id=${item.id}`
})
},
navToCourse(item){
uni.navigateTo({
url: `/pages/product/cdetail?id=${item.id}`
})
},
navToList(item){
if(item.isCourse==1){
uni.navigateTo({
url: `/pages/product/cdetail?id=${item.id}`
})
}
else {
uni.navigateTo({
url: `/pages/product/detail?id=${item.id}`
})
}
},
gotoSearch(){
console.log("gotoSearch")
uni.navigateTo({
url: `/pages/product/cxlist`
})
},
// 获取状态栏高度
geStatusBarHeight(){
return uni.getSystemInfoSync()['statusBarHeight'];
},
// 获取导航栏高度
getNavBarHeight(){
return 45+uni.getSystemInfoSync()['statusBarHeight'];
},
}
}
</script>
<style lang="less" scoped>
.page {
padding: 0;
position: relative;
background-image: url('@/static/image/bg.jpg');
background-attachment: fixed;
background-size: cover;
background-position: center center;
min-height: calc(100vh - var(--window-top) - var(--window-bottom));
}
.fixhead{
position: fixed;
width: 100%;
padding-top: 20rpx;
background-image: url('@/static/image/bg.jpg');
background-attachment: fixed;
background-size: cover;
background-position: center center;
z-index: 99;
}
.scrolltab{
height: 64rpx;
white-space: nowrap;
margin: 0 20rpx 20rpx 20rpx;
text-align: center;
.tab{
padding: 0 16rpx;
min-width: 180rpx;
height: 60rpx;
background-color: rgba(255, 255, 255, 0.7);
line-height: 55rpx;
position: relative;
display: inline-block;
overflow: hidden;
margin-right: 20rpx;
border-radius: 30rpx;
border: 1rpx solid #ccc;
color: #333333;
font-size: 30rpx;
text-align: center;
}
.tab.cur{
color: #fff;
background-color: #89965f;
border: 1rpx solid #89965f;
}
}
.tcon{
display: flex;
flex-direction: column;
width: 100%;
height: calc(100vh - 180rpx - var(--window-top) - var(--window-bottom));
position: relative;
z-index: 101;
margin-top: 180rpx;
border-radius: 30rpx 30rpx 0 0;
background-color: #fff;
overflow-x: auto;
align-items: center;
justify-content: flex-start;
padding: 20rpx 0;
.scell{
width: 100%;
display: flex;
flex-direction: row;
padding: 22rpx;
border-bottom: 1rpx solid #eee;
line-height: 30rpx;
.stxt{
display: flex;
flex: 1;
font-size: 28rpx;
color: #666;
margin-left: 16rpx;
}
}
}
.skcon{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
.skimg{
width: 338rpx;
height: 300rpx;
margin-top: 200rpx;
}
}
.f-list {
margin: 350rpx 20rpx 20rpx 20rpx;
/* #ifdef H5 */
margin: calc(270rpx + var(--window-top)) 20rpx 20rpx 20rpx;
/* #endif */
.adcon{
display: flex;
flex-direction: row;
background-color: #fff;
padding: 20rpx;
border-radius: 20rpx;
margin-bottom: 20rpx;
.adrow{
display: flex;
flex-direction: column;
width: 49%;
padding: 0 20rpx;
border: 1rpx solid #f0f0f0;
border-radius: 10rpx;
.adhead{
display: flex;
justify-content: space-between;
padding: 20rpx 0;
align-items: center;
.txt{
font-size: 30rpx;
font-weight: 600;
color:#000;
}
.tip{
font-size: 28rpx;
color:#6d6b70;
}
}
.scroll-view_H{
white-space: nowrap;
width: 100%;
}
.adimg{
position: relative;
display: inline-block;
overflow: hidden;
width: 150rpx;
height: 180rpx;
margin-right: 10rpx;
padding-bottom: 10rpx;
image{
width: 100%;
height: 100%;
border-radius: 6rpx;
margin-right: 2%;
}
.adname{
background: rgba(0, 0, 0, 0.1);
position: absolute;
padding: 8rpx 8rpx;
color: #fff;
font-size: 26rpx;
bottom: 0;
left: 0;
}
}
}
}
.guess-section{
display:flex;
flex-wrap:wrap;
.guess-item{
display:flex;
flex-direction: column;
width: 48%;
padding:20rpx 20rpx 30rpx 20rpx;
background: #FFF;
border-radius: 10rpx;
margin-bottom: 20rpx;
&:nth-child(2n+1){
margin-right: 4%;
}
}
.image-wrapper{
width: 100%;
height: 330rpx;
border-radius: 3px;
overflow: hidden;
image{
width: 100%;
height: 100%;
opacity: 1;
}
}
.title{
// height: 72rpx;
line-height: 36rpx;
color: #000000;
font-size: 30rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
margin-top: 16rpx;
margin-bottom: 16rpx;
}
.price{
line-height: 1;
color: #000;
.txt{
font-size: 22rpx;
}
.tint{
font-size: 32rpx;
font-weight: 600;
}
.txtt{
font-size: 20rpx;
margin-left: 7rpx;
}
}
.cright{
display: flex;
justify-content: space-between;
align-items: center;
}
.cart{
width: 55rpx;
height: 55rpx;
}
}
}
</style>