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.

814 lines
20 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'}">
<view class="lcon">
<view class="leftarr">
<uni-icons type="back" size="24" color="#fff" @tap="gotoBack"></uni-icons>
</view>
<selShop :showName="false" :showQR="true" :shop="shop" @changeArea="changeArea"></selShop>
</view>
<view class="hcon">
<uni-search-bar @confirm="search" @input="input" :focus="false" @focus="focus" v-model="searchValue"
placeholder="请输入商品关键字" bg-color="#FFFFFF" @cancel="cancel" @clear="clear" style="flex:1">
</uni-search-bar>
<view class="cartcon" @tap="gotoCart">
<uni-icons type="cart" size="25" color="#919191"></uni-icons>
<view class="cnum" v-if="cartnum>0">{{cartnum}}</view>
</view>
</view>
</view>
<!-- 关联框示例 -->
<view v-if="!ifshow" class="tcon">
<view class="scell" v-for="(item, index) in searList" :key="index" @click="navToList(item)">
<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="guess-section" v-if="goodsList.length>0">
<view
v-for="(item, index) in goodsList" :key="index"
class="guess-item"
>
<view class="image-wrapper imgload" @click="navToList(item)">
<image :src="getimgRemoteFile(item.pic)" 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?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-else class="skcon">
<image class="skimg" src="@/static/image/nodata.png" mode="aspectFill" ></image>
</view>
<uni-load-more iconType="circle" :status="loadStatus" :content-text="contentText" />
</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.94" y="0.08" @addShopCar="addShopCar" :pdata="product" :ptype="1"></cart>
<!-- cartx carty x0.1 y0.1 x0.9 y0.9-->
<shopCarAnimation ref="carAnmation" cartx="0.94" carty="0.08"></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:"",
loadStatus:'more', //'more', // 'noMore',
ifshow:true, // 显示检索商品
searchValue:"",
cartnum:getcartNum(),// 购物车数量
ifsear:false,
shopid:myCache('myshopid')?myCache('myshopid'):'',
shop:myCache('myshop')?myCache('myshop'):'',
contentText: {
contentdown: '查看更多',
contentrefresh: '加载中',
contentnomore: ''
},
searList:[],
goodsList: [
// {
// id:1,
// name:"瑜伽健身球1",
// isCourse:0,
// img:'../../static/image/theme/p1.jpg',
// price:12.00,
// unit:"个",
// ifspec:'1'
// }
// {
// id:4,
// name:"瑜伽入门,精品团课",
// isCourse:1,
// img:'../../static/image/theme/p2.jpg',
// price:12.00,
// unit:"课",
// ifspec:'0'
// },
],
page: {
pageNum: 0,
pageSize: 10
},
product:{
id:1,
productId:1,
name:"",//"杜威克瑜伽球加厚防滑",
remarks:"",//"0.8cm加厚PVC材质实测承重达200kg防滑底纹设计实测湿滑地面不侧翻超静音充气阀",
price:0,//29.9,
preprice:0,//45,
unit:"",//"个",
tip:"",//"热销",
isCourse:'0',
// 商品规格信息
list:[
// {
// name:"商品编码",
// text:"311289700098"
// }
],
pjnum:0,//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:2,
name:"颜色",
sels:0,
list:[
{
id:22,
name:"黑色"
},
],
},
]
},
};
},
onLoad() {
this.getList();
},
onShow() {
this.openId = myCache('openId');
var user = myCache('user');
this.userid = user.userid? user.userid:'';
this.phone = user.userphone;
},
mounted() {
if(this.userid==""||this.userid=="0"){
this.$refs.loginId.open();
}
},
onPullDownRefresh() {
setTimeout(()=>{
uni.stopPullDownRefresh()
},500);
},
onReachBottom() {
console.log('onReachBottom');
this.loadData();
},
onPageScroll(e) {
//调用子组件方法
this.$refs.topId.topData(e.scrollTop);
},
methods: {
getimgRemoteFile(img){
if(img){
img=img.split(',')[0];
return img;
// return getRemoteFile(img)
}
else{
return require("@/static/image/theme/t2.png")
}
},
// 加入购物车
addShopCar(sels,quantity,buyType){
console.log("mycartlist1,",myCache("mycartlist"));
if(sels){
// 已加入购物车动画
this.cartnum=getcartNum();
this.$forceUpdate();
}
else{
if(buyType==1){
uni.showToast({
title: '加入购物车失败!请重试!',
icon: 'error',
duration: 2000
});
}
else{
uni.showToast({
title: '立即购买失败!请重试!',
icon: 'error',
duration: 2000
});
}
}
},
// 加入购物车
async addCar(e,item) {
if(this.userid==""||this.userid=="0"||this.userid==null){
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={
storeNmae:myCache('myshop'),// 所属门店
id:product.id, // 商品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();
this.$forceUpdate();
}
}
catch(e){
console.log(e)
}
},
// 切换门店
changeArea(item){
this.shop=item.storeName;
this.shopid=item.id;
// 内容切换
this.loadStatus="more";
this.goodsList=[];
this.page={
pageNum: 0,
pageSize: 10
};
this.$forceUpdate();
this.loadData();
},
gotoCart(){
// 跳转 购物车
uni.switchTab({
url: `/pages/cart/cart`
});
},
goservice(val){
console.log(val);
},
highlightKeyword(text, keyword) {
if (!keyword) return text;
// 使用正则表达式将关键词包裹在<span>标签中
const regex = new RegExp(keyword, 'gi');
return text.replace(regex, `<span style="color:#89965f">${keyword}</span>`);
},
input(res) {
if(!this.ifsear){
this.ifsear=true;
this.getld(res);
}
},
async getld(keywords) {
const {data: res} = await uni.$http.post('/yoga/getProductsBykeywords',{keywords:keywords});
this.ifsear=false;
if (res) {
this.searList=res;
this.$forceUpdate();
}
else{
this.searList=[];
this.$forceUpdate();
}
},
focus(res){
console.log('focus',res);
this.ifshow=false;
this.$forceUpdate();
},
search(res) {
this.ifsear=false;
this.ifshow=true;
this.$forceUpdate();
this.getList();
},
clear(res) {
this.searchValue="";
this.ifshow=true;
this.$forceUpdate();
this.getList();
},
cancel(res) {
// uni.showToast({
// title: '点击取消,输入值为:' + res.value,
// icon: 'none'
// })
this.searchValue="";
this.ifshow=true;
this.$forceUpdate();
this.getList();
},
getPhoneNumber(e){
if(e.userid){
this.userid = e.userid
}
this.getmember();
},
async getList() {
if(this.loadStatus!=="noMore")
{
uni.showLoading({
title: '数据加载中...'
});
var para={
storeId:this.shopid,
categoryId:'',
search:this.searchValue,
}
const {data: res} = await uni.$http.post('/api/product/list?page='+this.page.pageNum+'&size='+this.page.pageSize, para);
if(res&&res.content&&res.content.length>0){
if(res.totalPages&&(1*res.totalPages-1)>this.page.pageNum){
// 继续加载
this.page.pageNum++;
this.loadStatus="more";
}
else{
this.loadStatus="noMore";
}
res.content.forEach((cell,idx)=>{
this.goodsList.push(cell);
});
this.$forceUpdate();
}
else{
this.loadStatus="noMore";
this.contentText.contentnomore="亲,没有商品数据了...";
this.$forceUpdate();
}
}
},
searDo(){
this.loadData();
},
loadData(){
// 加载
if(this.loadStatus=="more") {
this.loadStatus="loading";
setTimeout(() => {
this.getList();
}, 300);
}
},
splitNumber(num) {
var nums=num.split('.');
const intPart = nums[0]; // 获取整数部分
const decimalPart = nums[1]; // 获取小数部分
return { intPart, decimalPart };
},
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}`
})
}
},
gotoBack(){
// 返回
uni.navigateBack({
delta: 1
});
},
// 获取状态栏高度
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;
}
.lcon{
display: flex;
flex-direction: row;
align-items: center;
}
.leftarr{
background-color: rgba(184, 174,156, 0.8);
padding: 5rpx;
border-radius: 10rpx;
width: 60rpx;
margin-left: 20rpx;
}
.hcon{
display: flex;
flex-direction: row;
}
.cartcon{
width: 96rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
position: relative;
.cnum{
position: absolute;
top:8rpx;
left:36rpx;
height: 36rpx;
line-height: 34rpx;
min-width: 32rpx;
border-radius: 20rpx;
background: #f7362d;
color:#fff;
font-size: 26rpx;
padding: 0 10rpx;
}
}
.scrolltab{
height: 64rpx;
white-space: nowrap;
margin: 0 20rpx 20rpx 20rpx;
text-align: center;
.tab{
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 - 250rpx - var(--window-top) - var(--window-bottom));
position: relative;
z-index: 101;
margin-top: 250rpx;
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: 270rpx 20rpx 20rpx 20rpx;
/* #ifdef H5 */
margin: calc(200rpx + 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;
}
}
.adimg{
display: flex;
justify-content: space-between;
overflow: hidden;
width: 100%;
height: 180rpx;
padding-bottom: 20rpx;
image{
width: 48%;
height: 100%;
border-radius: 6rpx;
margin-right: 2%;
}
}
}
}
.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>