Browse Source

feat:购物车

dev_des
1054425342@qq.com 1 month ago
parent
commit
9b45b1f6c5
  1. 4
      components/DynamicIsland.vue
  2. 2
      components/ProductSection.vue
  3. 3
      pages.json
  4. 53
      pages/index/index.vue
  5. 262
      pages/index/sensoryStore - 副本.vue
  6. 84
      pages/index/sensoryStore.vue
  7. 47
      static/js/CommonFunction.js
  8. 204
      subPackages/points/index.vue
  9. 823
      subPackages/techan/detail - 副本.vue
  10. 85
      subPackages/techan/detail.vue
  11. 1601
      subPackages/user/gwc.vue

4
components/DynamicIsland.vue

@ -112,8 +112,8 @@
style="display: flex;align-items: center;font-size: 26rpx;font-weight: bold;display: flex;align-items: center;margin-top: 20rpx;">
<view class="" style="width: 200rpx;">
时长:{{
userInfo && userInfo.token ? userInfo.hour||0+'h' : "-"
}}
userInfo && userInfo.token ? userInfo.hour: 0
}}h
</view>
<view class="">
<image style="width: 22rpx;height: 22rpx;margin-right: 15rpx;"

2
components/ProductSection.vue

@ -59,7 +59,7 @@
<view class="card-content">
<view class="title-price-heart">
<view class="card-title">{{ item.title }}</view>
<view class="card-price">{{ item.price }}</view>
<view class="card-price">{{ item.price }} <text style="font-size:24rpx ;margin-left: 5rpx;" v-if="type==2"></text></view>
<template v-if="type==1">
<image
v-if="!item.type"

3
pages.json

@ -779,7 +779,8 @@
{
"path": "pages/index",
"style": {
"navigationBarTitleText": ""
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}
]

53
pages/index/index.vue

@ -110,23 +110,23 @@ export default {
// },
],
productListFeeling: [
{
id: 37,
image:
"https://epic.js-dyyj.com/uploads/20250822/f0ade3dd98a5a5e24ed0b60a023979e4.png",
title: "中国神仙IP系列 丝织品",
price: "198.00",
isLiked: true,
isShop: true,
},
{
id: 39,
image:
"https://epic.js-dyyj.com/uploads/20250822/19b1fb3e07fd459d347e727274af445c.png",
title: "仙人乘槎 马克杯",
price: "35.00",
isLiked: false,
},
// {
// id: 37,
// image:
// "https://epic.js-dyyj.com/uploads/20250822/f0ade3dd98a5a5e24ed0b60a023979e4.png",
// title: "IP ",
// price: "198.00",
// isLiked: true,
// isShop: true,
// },
// {
// id: 39,
// image:
// "https://epic.js-dyyj.com/uploads/20250822/19b1fb3e07fd459d347e727274af445c.png",
// title: " ",
// price: "35.00",
// isLiked: false,
// },
],
selectedText: "",
addressInfo: null,
@ -235,6 +235,25 @@ export default {
});
}
});
this.Post(
{
},
"/framework/index/goods/indexList",
"DES"
).then((res) => {
if (res.data) {
this.productListFeeling = res.data.map(item =>{
return {
title:item.goodsName,
price:item.salePrice,
image:item.posterUrl,
id:item.goodsId,
...item
}
})
}
});
},
gotoVideo(item) {
uni.navigateTo({

262
pages/index/sensoryStore - 副本.vue

@ -0,0 +1,262 @@
<template>
<view class="bg">
<BackButton />
<!-- <headerVue :type="'goods'"></headerVue> -->
<view class="banner-content">
<swiper class="top-banner" :circular="true" :interval="6000" :duration="800"
:indicator-dots="false" :autoplay="true" @change="swiperChange" >
<swiper-item v-for="(item, index) in topBanner" :key="index" @click.stop="gotoUrlNew(item)">
<image class="top-banner" :src="showImg(item.head_img)" mode="aspectFill"></image>
</swiper-item>
</swiper>
<view class="dot-container">
<view :class="['dot-line',index==swiperIndex?'active':'']" v-for="(item, index) in topBanner" :key="index"></view>
</view>
</view>
<view class="desc-box">
<view class="title-sec" style="color: black;">
关于有感商品
</view>
<view class="">
寻常商品满足你的日常所需有感商品则回应你的精神所向
</view>
<view class="">
我们坚信意义大于产品这里的每一件商品都诞生于EPIC SOUL交响阅读体的史诗是精神漫游的实体回响它的存在是为了让你在消费中完成一次次深刻的情感连接与自我认同
</view>
<view class="">
在这里消费的终点不是拥有而是更深刻的连接与共鸣欢迎探索一件件写满故事与想象力的生活信物
</view>
</view>
<view class="product-content">
<!-- <image class="head-img" src="https://static.ticket.sz-trip.com/uploads/20250625/e3112c280ef9761af741907a737ef221.png"></image> -->
<view class="title-sec">
有感商品上新
</view>
<scroll-view style="width: 100%;" scroll-x>
<view class="product">
<view class="item" v-for="(item,i) in list" :key="item.goods.id" @click="goDetailByType(item)">
<image class="item-img" :src="showImg(item.goods.image)"></image>
<view class="content">
<view class="title text-overflow">{{item.goods.title}}</view>
<view class="bottom">
<view class="price">{{item.goods.money/100}}</view>
<image src="https://static.ticket.sz-trip.com/epicSoul/readingBody/gwc.png" class="buy-cart"></image>
</view>
</view>
</view>
</view>
</scroll-view>
<!-- <image style="margin: 53rpx 0 35rpx;" class="head-img" src="https://static.ticket.sz-trip.com/uploads/20250627/73153098ff5c115e02afb0328ade1e29.png"></image> -->
<view class="title-sec">
有感商品精选
</view>
<view class="img-container">
<image v-for="(type,i) in typeList" :key="i" :src="showImg(type.img)"
@click="gotoPath(`/subPackages/haveFeeling/detailXiang?id=${type.id}`)"></image>
</view>
</view>
<!-- <CustomTabBar :currentTab="2" /> -->
<MusicControl />
</view>
</template>
<script>
import headerVue from "@/components/header.vue"
import CustomTabBar from '@/components/CustomTabBar.vue';
import MusicControl from '@/components/MusicControl.vue';
import BackButton from "@/components/BackButton.vue";
export default {
components: {CustomTabBar,headerVue,MusicControl,BackButton},
data() {
return {
topBanner: [],
list: [],
swiperIndex: 0,
typeList: [],
}
},
onLoad() {
},
onReady() {
this.getProduct()
this.getTypes()
this.getList()
},
onReachBottom() {
},
methods: {
swiperChange(e) {
this.swiperIndex = e.detail.current
},
viewDetail(item) {
if (item.url) {
uni.navigateTo({
url:"/subPackages/webPage/webPage?url="+encodeURIComponent(item.url)
})
return
}
uni.navigateTo({
url:'/subPackages/letter/detail?id='+item.id
})
},
getProduct () {
this.Post({
tag_id: 40,
offset: 0,
},'/api/tag/getGoodsByTagId').then(res => {
this.list = res.data;
})
},
getList() {
//
this.Post({
type_id: 3,
position: 18,
}, '/api/adv/getAdv').then(res => {
if(res.data) {
this.topBanner = res.data;
}
});
},
//
getTypes () {
this.Post({
parent_id: 0,
}, '/api/goods/type').then(res => {
if(res.data) {
this.typeList = res.data;
}
});
},
}
}
</script>
<style lang="scss" scoped>
.bg {
min-height: 100vh;
background: #FFFFFF;
padding-bottom: 200rpx;
}
.banner-content{
width: 100%;
height: 496.4rpx;
position: relative;
.top-banner {
width: 100%;
height: 100%;
}
.dot-container{
position: absolute;
bottom: 43rpx;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
left: 0;
.dot-line{
width: 52rpx;
height: 4rpx;
margin: 0 8rpx;
background: RGBA(189, 170, 173, 0.8);
&.active{
background: RGBA(255, 255, 255, 0.8);
}
}
}
}
.head-img{
width: 697.24rpx;
height: 42.57rpx;
margin: 0 auto;
display: block;
}
.product-content{
padding: 63rpx 26rpx 0;
padding-top: 0;
.product{
padding: 36rpx 0 0;
padding-top: 0;
display: flex;
flex-wrap: nowrap;
// justify-content: space-between;
.item{
width: 214.69rpx;
margin-right: 20rpx;
}
.item-img{
width: 214.69rpx;
height: 286.33rpx;
}
.content{
height: 80rpx;
padding: 0rpx 4rpx;
font-weight: 400;
font-size: 24rpx;
color: #000000;
}
.bottom{
display: flex;
padding-top: 13rpx;
justify-content: space-between;
align-items: center;
}
.buy-cart{
width: 28rpx;
height: 24rpx;
}
}
}
.img-container{
width: 100%;
image{
display: block;
width: 100%;
height: 314rpx;
border-radius: 40rpx;
margin-bottom: 20rpx;
}
}
.line{
width: 220rpx;
height: 1rpx;
background: #E4E4E4;
flex-shrink: 0;
}
.head-img-yougan{
width: 183.45rpx;
height: 42.57rpx;
}
.title-sec{
font-size: 34rpx;
font-weight: 500;
margin: 30rpx 0;
}
.desc-box{
padding: 0 20rpx;
color: #616161;
margin: 30rpx 0;
font-size: 24rpx;
padding: 0 30rpx;
view{
margin-bottom: 20rpx;
}
}
</style>

84
pages/index/sensoryStore.vue

@ -6,8 +6,8 @@
<swiper class="top-banner" :circular="true" :interval="6000" :duration="800"
:indicator-dots="false" :autoplay="true" @change="swiperChange" >
<swiper-item v-for="(item, index) in topBanner" :key="index" @click.stop="gotoUrlNew(item)">
<image class="top-banner" :src="showImg(item.head_img)" mode="aspectFill"></image>
<swiper-item v-for="(item, index) in topBanner" :key="index" @click.stop="gotoUrlNewDes(item)">
<image class="top-banner" :src="showImg(item.image)" mode="aspectFill"></image>
</swiper-item>
</swiper>
@ -38,13 +38,13 @@
<scroll-view style="width: 100%;" scroll-x>
<view class="product">
<view class="item" v-for="(item,i) in list" :key="item.goods.id" @click="goDetailByType(item)">
<image class="item-img" :src="showImg(item.goods.image)"></image>
<view class="item" v-for="(item,i) in list" :key="item.goodsId" @click="gotoPath(`/subPackages/techan/detail?id=${item.goodsId}`)">
<image mode="aspectFill" class="item-img" :src="showImg(item.mainUrl.split(',')[0])"></image>
<view class="content">
<view class="title text-overflow">{{item.goods.title}}</view>
<view class="title text-overflow">{{item.goodsName}}</view>
<view class="bottom">
<view class="price">{{item.goods.money/100}}</view>
<image src="https://static.ticket.sz-trip.com/epicSoul/readingBody/gwc.png" class="buy-cart"></image>
<view class="price">{{item.salePrice}}</view>
<!-- <image @click.stop="addShopCart(item)" src="https://static.ticket.sz-trip.com/epicSoul/readingBody/gwc.png" class="buy-cart"></image> -->
</view>
</view>
</view>
@ -57,8 +57,8 @@
有感商品精选
</view>
<view class="img-container">
<image v-for="(type,i) in typeList" :key="i" :src="showImg(type.img)"
@click="gotoPath(`/subPackages/haveFeeling/detailXiang?id=${type.id}`)"></image>
<image mode="aspectFill" v-for="(type,i) in typeList" :key="i" :src="showImg(type.image)"
@click="gotoUrlNewDes(type)"></image>
</view>
</view>
<!-- <CustomTabBar :currentTab="2" /> -->
@ -85,9 +85,7 @@
},
onReady() {
this.getProduct()
this.getTypes()
this.getList()
this.getInfo()
},
onReachBottom() {
@ -96,6 +94,23 @@
swiperChange(e) {
this.swiperIndex = e.detail.current
},
getInfo(){
this.Post({
code:'ygsp_top'
},'/framework/banner/getImageByBannerCode',"DES").then(res => {
this.topBanner = res.data;
})
this.Post({
},'/framework/goods/ygPageList',"DES").then(res => {
this.list = res.rows;
})
this.Post({
code:'ygsp_bottom'
},'/framework/banner/getImageByBannerCode',"DES").then(res => {
this.typeList = res.data;
})
},
viewDetail(item) {
if (item.url) {
@ -108,45 +123,15 @@
url:'/subPackages/letter/detail?id='+item.id
})
},
getProduct () {
this.Post({
tag_id: 40,
offset: 0,
},'/api/tag/getGoodsByTagId').then(res => {
this.list = res.data;
})
},
getList() {
//
this.Post({
type_id: 3,
position: 18,
}, '/api/adv/getAdv').then(res => {
if(res.data) {
this.topBanner = res.data;
}
});
},
//
getTypes () {
this.Post({
parent_id: 0,
}, '/api/goods/type').then(res => {
if(res.data) {
this.typeList = res.data;
}
});
},
}
}
</script>
<style lang="scss" scoped>
@font-face {
font-family: "Futura";
src: url(https://static.ticket.sz-trip.com/epicSoul/taozi/fonts/Futura.ttc);
}
.bg {
min-height: 100vh;
background: #FFFFFF;
@ -196,12 +181,12 @@
flex-wrap: nowrap;
// justify-content: space-between;
.item{
width: 214.69rpx;
width: 280rpx;
margin-right: 20rpx;
}
.item-img{
width: 214.69rpx;
height: 286.33rpx;
width: 280rpx;
height: 280rpx;
}
.content{
height: 80rpx;
@ -215,6 +200,7 @@
padding-top: 13rpx;
justify-content: space-between;
align-items: center;
font-family: "Futura";
}
.buy-cart{
width: 28rpx;

47
static/js/CommonFunction.js

@ -450,7 +450,52 @@ Vue.prototype.gotoUrlNew = (item) => {
break;
}
}
Vue.prototype.gotoUrlNewDes = (item) => {
let that = this;
let url = '';
switch (item.jumpType) {
case 0:
break;
case 1:
uni.navigateTo({
url: item.jumpUrl
});
break;
case 2:
uni.navigateTo({
url: '/subPackages/webPage/webPage?url=' + item.jumpUrl
});
break;
case 4:
uni.navigateToMiniProgram({
appId: item.tdata.appid, // 此为appid
path: item.tdata.page, // 此为首页路径
envVersion: 'release',
success: res => {
// 打开成功
console.log('打开成功', res);
},
fail: err => {
console.log(err);
}
});
break;
case 5:
wx.openChannelsActivity({
finderUserName: item.tdata.video_appid, // 视频号的原始ID
feedId: item.tdata.video_id, // 视频号的视频ID
success(res) {
console.log('拉起视频号成功', res);
},
fail(res) {
console.log('拉起视频号失败', res);
}
})
break;
default:
break;
}
}
// 埋点
Vue.prototype.getUuid = () => {
return new Promise((resolve, reject) => {

204
subPackages/points/index.vue

@ -9,7 +9,8 @@
<!-- 时间奖励值 -->
<view class="time-reward" @click="showExchangeModal">
<view class="reward-icon">
<nmr-icon name="jifenduihuan" style="margin-right: 10rpx;margin-top: 5rpx;" size="40" color="white"></nmr-icon>
<nmr-icon name="jifenduihuan" style="margin-right: 10rpx;margin-top: 3rpx;" size="40"
color="white"></nmr-icon>
</view>
</view>
</view>
@ -89,12 +90,7 @@
<view class="exchange-form">
<view class="form-item">
<text class="form-label">兑换数量</text>
<input
class="form-input"
v-model="exchangeAmount"
type="number"
placeholder="请输入兑换数量"
/>
<input class="form-input" v-model="exchangeAmount" type="number" placeholder="请输入兑换数量" />
</view>
</view>
@ -109,7 +105,7 @@
<view class="modal-footer">
<button class="cancel-btn" @click="closeExchangeModal">取消</button>
<button class="confirm-btn" @click="confirmExchange" >确认兑换</button>
<button class="confirm-btn" @click="confirmExchange">确认兑换</button>
</view>
</view>
</uni-popup>
@ -119,36 +115,43 @@
<script>
export default {
data() {
return {
totalPoints: 0,
currentTab: "all",
pointsList: [],
page: 1,
pageSize: 20,
hasMore: true,
loading: false,
refreshing: false,
userInfo: null,
timeReward: 0,
exchangeAmount: '',
exchangeResult: 0,
pointInfo:null
};
},
return {
totalPoints: 0,
currentTab: "all",
pointsList: [],
page: 1,
pageSize: 20,
hasMore: true,
loading: false,
refreshing: false,
userInfo: null,
timeReward: 0,
exchangeAmount: '',
exchangeResult: 0,
pointInfo: null
};
},
onLoad() {
this.getUserInfo();
this.loadPointsData();
this.getTotalPoints();
},
this.getUserInfo();
this.loadPointsData();
this.getTotalPoints();
},
methods: {
getUserInfo() {
this.Post({}, "/framework/user/getInfo", "DES").then((res) => {
this.userInfo = res.data;
});
this.Post({}, "/framework/user/getInfo", "DES").then((res) => {
this.userInfo =
(uni.getStorageSync("userInfo") &&
JSON.parse(uni.getStorageSync("userInfo"))) ||
this.$store.state.user.userInfo || {};
res.data.token = this.userInfo.token;
uni.setStorageSync("userInfo", JSON.stringify(res.data));
this.userInfo = res.data;
});
},
//
goBack() {
@ -173,7 +176,7 @@
//
async getTotalPoints() {
try {
this.Post({}, '/framework/points/getLastBalance', 'DES').then(res =>{
this.Post({}, '/framework/points/getLastBalance', 'DES').then(res => {
if (res.code === 200) {
this.pointInfo = res.data
this.totalPoints = res.data.balance || 0;
@ -258,86 +261,88 @@
//
showExchangeModal() {
this.$refs.exchangePopup.open();
},
//
closeExchangeModal() {
this.$refs.exchangePopup.close();
this.exchangeAmount = '';
this.exchangeResult = 0;
},
async confirmExchange() {
if(parseInt(this.exchangeAmount)>this.userInfo.hourValue){
uni.showToast({
title:'兑换值大于可用值',
icon:'none'
})
return
}
try {
const params = {
amount: parseInt(this.exchangeAmount)
};
this.Post(params, '/framework/timeReward/exchange', 'DES').then(res => {
if (res.code === 200) {
uni.showToast({
title: '兑换成功',
icon: 'success'
});
//
showExchangeModal() {
this.$refs.exchangePopup.open();
},
//
this.getTotalPoints();
this.resetData();
this.loadPointsData();
this.closeExchangeModal();
} else {
uni.showToast({
title: res.msg || '兑换失败',
icon: 'none'
});
}
});
} catch (error) {
console.error('兑换失败:', error);
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
});
}
},
//
closeExchangeModal() {
this.$refs.exchangePopup.close();
this.exchangeAmount = '';
this.exchangeResult = 0;
},
async confirmExchange() {
if (parseInt(this.exchangeAmount) > this.userInfo.hourValue) {
uni.showToast({
title: '兑换值大于可用值',
icon: 'none'
})
return
}
try {
const params = {
hour: parseInt(this.exchangeAmount),
method: 'post'
};
this.Post(params, '/framework/points/hourChange', 'DES').then(res => {
if (res.code === 200) {
uni.showToast({
title: '兑换成功',
icon: 'success'
});
//
this.getUserInfo();
this.getTotalPoints();
this.resetData();
this.loadPointsData();
this.closeExchangeModal();
} else {
uni.showToast({
title: res.msg || '兑换失败',
icon: 'none'
});
}
});
} catch (error) {
console.error('兑换失败:', error);
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
});
}
},
//
formatTime(timestamp) {
const date = new Date(timestamp);
const now = new Date();
const diff = now.getTime() - date.getTime();
//
formatTime(timestamp) {
const date = new Date(timestamp);
const now = new Date();
const diff = now.getTime() - date.getTime();
//
if (diff < 24 * 60 * 60 * 1000 && now.getDate() === date.getDate()) {
return `今天 ${date.getHours().toString().padStart(2, "0")}:${date
//
if (diff < 24 * 60 * 60 * 1000 && now.getDate() === date.getDate()) {
return `今天 ${date.getHours().toString().padStart(2, "0")}:${date
.getMinutes()
.toString()
.padStart(2, "0")}`;
}
}
//
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
if (yesterday.getDate() === date.getDate()) {
return `昨天 ${date.getHours().toString().padStart(2, "0")}:${date
//
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
if (yesterday.getDate() === date.getDate()) {
return `昨天 ${date.getHours().toString().padStart(2, "0")}:${date
.getMinutes()
.toString()
.padStart(2, "0")}`;
}
}
//
return `${date.getMonth() + 1}-${date.getDate()} ${date
//
return `${date.getMonth() + 1}-${date.getDate()} ${date
.getHours()
.toString()
.padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
},
},
},
};
</script>
@ -714,7 +719,8 @@
padding: 20rpx 40rpx 40rpx;
}
.cancel-btn, .confirm-btn {
.cancel-btn,
.confirm-btn {
flex: 1;
height: 80rpx;
border-radius: 8rpx;

823
subPackages/techan/detail - 副本.vue

@ -0,0 +1,823 @@
<template>
<view class="bg" id="bg" v-if="info">
<view class="swipe-box">
<swiper class="swiper" :indicator-dots="false" :autoplay="false" :interval="3000" :duration="1000" circular>
<swiper-item v-if="info && info.videourl">
<video
:src="showImg(info.videourl)"
id="detailVideo"
:poster="showImg(info.image)"
@play="play"
@error="videoErrorCallback"
controls
style="width: 100%;height: 100%;"
object-fit="cover"
></video>
</swiper-item>
<swiper-item v-for="(item, index) in info.list_images.split(',')" :key="item.id">
<view class="swiper-item">
<image class="item-img" :src="showImg(item)" mode="aspectFill"></image>
</view>
</swiper-item>
</swiper>
<view class="swiper-item-num">{{ info.list_images.split(',').length }}</view>
</view>
<view class="w-full relative" style="padding: 26rpx 0;top: -52rpx;">
<view class="price-box ">
<view class="price-zan">
<view class="price">
<view class="present-price">{{ info.money / 100 }}</view>
<view class="old-price">{{info.price / 100}}</view>
</view>
</view>
<view class="tag no-scrollbar" v-if="info.goods_new_tag">
<view class="tag-item" v-for="(item, index) in info.goods_new_tag.split(',')" :key="index">
{{ item }}
</view>
</view>
<view class="title">{{ info.title }}</view>
</view>
<view class="sku-box" v-if="sku.length>0">
<view class="sku-item" v-for="(item,i) in sku" :key="i">
<image :src="showImg(item.image)"></image>
<view class="sku-content">
<view class="flex-1">{{item.title}}</view>
<view class="present-price">{{item.money/100}}</view>
</view>
</view>
</view>
<view class="notice" v-if="info.reserve_content">
<view class="title">购买须知</view>
<view class="rich-text" v-html="formateRichText(info.reserve_content)"></view>
</view>
<view class="notice" >
<view class="title">商品须知</view>
<view class="rich-text" v-html="formateRichText(info.special_content)"></view>
</view>
</view>
<template v-if="!popShow">
<view class="btn-list" v-if="!paramData.showCart">
<view class="left-box">
<!-- <view class="img-box" slot="content">
<uni-badge class="uni-badge-left-margin" :text="paramData.num" absolute="rightTop" :offset="[5, 5]" size="small"
:custom-style="{background:'#D90F01',color:'#ffffff',border:'1px solid #ffffff'}">
<image @click.stop="showCartClick" :src="showImg('/uploads/20250513/29fd015f8c779f08e53d1016d3643c58.png')" mode="aspectFill"
style="width: 60rpx;height: 50rpx;"></image>
</uni-badge>
<text class="text">购物车</text>
</view> -->
</view>
<view class="btn-post">
<view class="left-btn-buy" @click="openPop(true)">加入购物车</view>
<view class="right-btn-buy" @click="openPop(false)">立即购买</view>
</view>
</view>
<view class="btn-list" v-else>
<view class="left-box">
<view class="img-box" slot="content">
<uni-badge class="uni-badge-left-margin" :text="paramData.num" absolute="rightTop" :offset="[5, 5]" size="small"
:custom-style="{background:'#D90F01',color:'#ffffff',border:'1px solid #ffffff'}">
<image @click.stop="showCartClick" :src="showImg('/uploads/20250513/29fd015f8c779f08e53d1016d3643c58.png')" mode="aspectFill"
style="width: 60rpx;height: 50rpx;"></image>
</uni-badge>
<text class="text">购物车</text>
</view>
<view class="bottom-price">
<text style="color: #000000;">总计</text>
<view class="bottom-price-yuan">{{paramData.iNum}}</view>
<view>.{{paramData.fNum}}</view>
</view>
</view>
<view class="btn-buy" @click="goCartOrder">
去结算
</view>
</view>
</template>
<cartDataVue ref="cartDataVueRef" :paramData="paramData" @changeParamData="changeParamData" :key="new Date().getTime()"></cartDataVue>
<uni-popup ref="popup" type="bottom" @change="changPopShow"
:safe-area="false" style="position: relative;z-index: 50;">
<view class="popup-content" v-if="sku.length>0">
<view @click="closePopup" style="padding: 31rpx 0 0 639rpx;width: 50rpx;height: 80rpx;">
<uni-icons type="closeempty" size="24"></uni-icons>
</view>
<view class="bottom-productImg">
<img :src="showImg(sku[productIndex].image)" alt="">
<view class="right-content">
<view class="bottom-productPrice com-price">{{(sku[productIndex].money||0)/100}}</view>
<view class="bottom-content text-overflow">已选择{{sku[productIndex].title}}</view>
</view>
</view>
<view>
<view class="sp">
规格
</view>
<view style="display: flex;align-items: center;justify-content: space-between;flex-wrap: wrap;">
<view style="position:relative;" v-for="(botItem,botIndex) in sku" :key="botIndex">
<view :class="['botProduct',{'noStore':botItem.store==0},{'botProducts':productIndex==botIndex}]"
@click="changeProduct(botItem,botIndex)">
{{botItem.title}}
</view>
<view class="noStore-text" v-if="botItem.store==0">
不可购买
</view>
<!-- <view class="noStore-text" v-else-if="is_post==1&&botItem.is_post!=1">不可加购</view> -->
</view>
</view>
</view>
<view class="buy-num com-flex-tao">
数量
<view class="number-btn">
<view>
<text @click="delNumber">-</text>
</view>
<view style="width: 96rpx;height: 69rpx;margin: 0 14rpx;">{{ buyNum }}</view>
<view>
<text @click="addNumber">+</text>
</view>
</view>
</view>
</view>
<!-- <view style="height: 100rpx;"></view> -->
<view class="btn-box">
<view class="buy-btn" @click="openPop(addCartOrOrder)">
{{addCartOrOrder?'加入购物车':'立即购买'}}
</view>
</view>
</uni-popup>
<!-- 购物车数量 -->
<!-- <view class="cart-box flex-center">
<image src="https://static.ticket.sz-trip.com/epicSoul/gowuche.png" mode="widthFix"></image>
</view> -->
</view>
</template>
<script>
import cartDataVue from '../../components/cartData.vue'
export default {
components: {cartDataVue},
data() {
return {
id: null,
info: null,
sku: [],
productIndex: 0,
is_post: "1",
isCollect: false,
showLength: 0,
buyNum: 1,
popShow: false,
paramData: {allPrice: 0,iNum:0, fNum:'00', showCart: false, num: 0},
addCartOrOrder: null, //true false
};
},
onShow() {
//
this.Post({
is_post: 1,
}, '/api/shopping/getShoppingList').then(res => {
console.log(res)
})
},
onLoad(option) {
this.id = option.id;
this.getInfo();
this.getSpecificationsByGoodsId();
},
methods: {
changPopShow (e) {
this.popShow = e.show
},
getInfo() {
this.Post({
goods_id: this.id
},
'/api/goods/getGoodDetail'
).then(res => {
if (res.data.flag == 0) {
setTimeout(() => {
uni.showToast({
title: '商品不存在或已下架',
icon: 'none'
})
}, 0)
setTimeout(() => {
this.goBack()
}, 2000)
}
this.info = res.data;
// this.isCollect = this.info.is_collect;
if (this.info.title) {
uni.setNavigationBarTitle({
title: this.info.title
})
this.browse_record({type: 'goods',title: this.info.title});
}
});
},
getSpecificationsByGoodsId() {
this.Post({
goods_id: this.id
},
'/api/goods/getSpecificationsByGoodsId'
).then(res => {
if (res) {
this.sku = res.data || [];
// todo
// this.is_post = "2"
// if (this.sku.length>0 && this.sku.some(v=>v.is_post == 1)) {
// this.is_post = "1"
// }
}
});
},
//
collect() {
this.Post({
type: 5,
id: this.id
},
'/api/scenic/collect'
).then(res => {
if (res) {
uni.showToast({
title: res.msg,
icon: 'none'
});
this.isCollect = !this.isCollect
}
});
},
//
addNumber() {
this.buyNum += 1;
},
delNumber() {
if (this.buyNum <= 1) {
return;
}
this.buyNum -= 1;
},
closePopup() {
this.$refs.popup.close()
},
// false true
openPop(flag) {
if (!this.sku||this.sku.length<=0) {
uni.showToast({
title:'暂无可选规格',
icon:'none'
})
return
}
if (!this.popShow) {
this.$refs.popup.open()
this.addCartOrOrder = flag
} else {
if (flag) {
this.addToCart()
} else {
this.order()
}
}
},
order(item) {
let goods = this.sku[this.productIndex]
goods.buyNum = this.buyNum
let orderInfo = {
// is_post: goods.is_post || "2",
is_post: 1,
goods: [{goodsInfo: this.info, skuInfo: goods }],
post: 0,
}
uni.setStorageSync('teChanOrder', JSON.stringify(orderInfo)); //
// uni.setStorageSync('teChanInfo', JSON.stringify(this.info)); //
uni.navigateTo({
url: '/subPackages/techan/order'
});
},
addToCart () {
let goods = this.sku[this.productIndex]
goods.buyNum = this.buyNum
let goodsInfo = {goodsInfo:this.info, skuInfo: goods, isSelected: true}
this.Post({good_id: this.info.id, specifications_id: goods.id,num: this.buyNum },
'/api/shopping/addShopping').then(res => {
if (res) {
let selectedData = []
try {
selectedData = JSON.parse(uni.getStorageSync('cartDataInfo'));
} catch(e) {
selectedData = []
}
let currentGoods = selectedData.find(v =>v==goods.id)
if (!currentGoods) {
selectedData.push(goods.id)
}
uni.setStorageSync('cartDataInfo', JSON.stringify(selectedData));
uni.$emit("updateDataByConnect", {msgType:'updateCartDataInfo',data:null})
this.closePopup()
}
});
},
goUser() {
uni.switchTab({
url: '/pages/index/user'
})
},
changeProduct(item,index) {
if (item.store==0) {
uni.showToast({
title:"库存不足!",
icon:'none'
})
return
}
this.productIndex = index
},
//
changeParamData (data) {
for(let key in this.paramData) {
this.paramData[key] = data[key]
}
},
showCartClick () {
if (this.paramData.showCart) {
this.$refs.cartDataVueRef.closePopup()
} else {
this.$refs.cartDataVueRef.openPop()
}
},
goCartOrder () {
this.$refs.cartDataVueRef.goCartOrder()
},
},
onReachBottom() {
}
};
</script>
<style lang="scss" scoped>
.bg {
min-height: 100vh;
overflow-x: hidden;
background: #f2f4f7;
padding-bottom: 210rpx;
}
view {
box-sizing: border-box;
}
.swipe-box {
height: 750rpx;
position: relative;
.swiper-item-num {
width: 90rpx;
height: 40rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 20rpx;
font-size: 24rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ffffff;
text-align: center;
line-height: 40rpx;
position: absolute;
right: 30rpx;
bottom: 50rpx;
}
}
.swiper {
height: 750rpx;
position: relative;
.swiper-item {
width: 100%;
height: 750rpx;
.item-img {
width: 750rpx;
height: 750rpx;
}
}
}
.price-box {
width: 100%;
background: #ffffff;
border-radius: 20rpx 20rpx 0 0;
padding: 24rpx 30rpx;
.price-zan {
display: flex;
align-items: center;
justify-content: space-between;
.price {
display: flex;
align-items: baseline;
}
}
.tag {
margin:24rpx 0 15rpx 0;
display: flex;
align-items: center;
flex-wrap: nowrap;
overflow-x: auto;
.tag-item {
margin-right: 10rpx;
padding: 0rpx 15rpx;
flex-shrink: 0;
font-weight: 500;
font-size: 23rpx;
color: #60989E;
height: 37rpx;
line-height: 37rpx;
background: rgba(96, 152, 158, 0.2);
border-radius: 4rpx;
}
}
.title {
margin-top: 22rpx;
font-family: PingFang;
font-weight: bold;
font-size: 31rpx;
color: #000000;
}
}
.present-price {
font-size: 42rpx;
font-family: PingFang SC;
font-weight: 500;
color: #FC5109;
&:before {
content: '¥';
display: inline-block;
font-size: 26rpx;
}
&:after {
content: '起';
display: inline-block;
font-size: 24rpx;
font-family: PingFangSC;
color: #B5BCC9;
}
}
.old-price {
font-size: 24rpx;
color: #B5BCC9;
margin-left: 10rpx;
text-decoration: line-through;
}
.notice {
width: 700rpx;
margin: 25rpx auto 0;
background: #ffffff;
border-radius: 20rpx;
padding: 40rpx 25rpx;
.title{
font-weight: bold;
font-size: 36rpx;
color: #000000;
margin-bottom: 30rpx;
}
}
.btn-list {
position: fixed;
z-index: 9999;
bottom: 0;
width: 750rpx;
background: #FFFFFF;
box-shadow: 0rpx 0rpx 16rpx 0rpx rgba(6, 0, 1, 0.1);
display: flex;
justify-content: space-between;
padding: 30rpx 25rpx 30rpx;
// padding-bottom: calc(30rpx + env(safe-area-inset-bottom));
.left-box {
display: flex;
align-items: flex-start;
.bottom-price{
display: flex;
align-items: baseline;
font-family: PingFang SC;
font-weight: bold;
font-size: 27rpx;
color: #D70000;
padding-top: 20rpx;
.bottom-price-yuan{
font-size: 40rpx;
}
}
.bottom-detail-icon{
font-size: 24rpx;
display: flex;
align-items: center;
}
.img-box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-right: 50rpx;
image {
width: 48rpx;
height: 48rpx;
}
.text {
font-weight: 500;
font-size: 22rpx;
color: #4D526C;
}
}
}
.btn-buy {
width: 240rpx;
height: 78rpx;
background: #74A5AA;
border-radius: 40rpx;
text-align: center;
line-height: 78rpx;
font-size: 32rpx;
font-family: PingFangSC;
font-weight: 500;
color: #FFFFFF;
}
}
.popup-content {
background-color: white;
padding: 0rpx 39rpx 51rpx 39rpx;
height: auto;
border-radius: 20rpx 20rpx 0 0;
.bottom-productImg {
display: flex;
margin-bottom: 23rpx;
img {
width: 218rpx;
height: 179rpx;
background: #666666;
border-radius: 13rpx;
}
}
.right-content {
margin: 10rpx 0 0 41rpx;
}
.bottom-productPrice {
font-size: 40rpx;
color: #FC524B;
&:before {
content: "¥";
font-size: 26rpx;
}
}
.bottom-content {
width: 331rpx;
font-size: 27rpx;
font-family: PingFang SC;
font-weight: 400;
color: #666666;
}
}
.botProduct {
width: 680rpx;
// height: 78rpx;
border-radius: 13rpx;
background-color: #EFEFEF;
font-size: 29rpx;
font-family: PingFang SC;
font-weight: 400;
color: #333333;
text-align: center;
margin-bottom: 25rpx;
display: inline-block;
position: relative;
padding: 10rpx 40rpx;
}
.noStore{
background-color: rgba(239, 239, 239, 1);
color: rgba(153, 153, 153, 1);
}
.noStore-text{
width: 113rpx;
height: 43rpx;
background: #C0C0C0;
border-radius: 7rpx 0rpx 7rpx 0rpx;
text-align: center;
line-height: 43rpx;
position: absolute;
right: -14rpx;
top: -20rpx;
font-size: 23rpx;
font-family: PingFangSC;
font-weight: 400;
color: #FFFFFF;
}
.botProducts {
// border: 1rpx solid #00AAFF;
// background-color: rgba(254, 180, 25, 1);
background: #74A5AA;
color: #FFFFFF;
}
.buy-num {
font-size: 29rpx;
font-family: PingFang SC;
font-weight: 400;
color: #333333;
// border-top: 1rpx solid #CCCCCC;
padding: 39rpx 0;
display: flex;
align-items: center;
justify-content: space-between;
.number-btn {
display: flex;
}
}
.buy-num .number-btn view {
display: flex;
justify-content: center;
align-items: center;
width: 69rpx;
height: 69rpx;
border: 1rpx solid #CCCCCC;
border-radius: 7rpx;
}
.buy-num .number-btn>view text {
font-size: 46rpx;
}
.buy-btn {
width: 670rpx;
height: 78rpx;
text-align: center;
line-height: 78rpx;
background: #74A5AA;
border-radius: 40rpx;
font-size: 34rpx;
font-family: PingFangSC;
font-weight: 500;
color: #FFFFFF;
}
.btn-box {
width: 750rpx;
height: 151rpx;
background: #FFFFFF;
box-shadow: 0rpx 0rpx 16rpx 0rpx rgba(6, 0, 1, 0.1);
display: flex;
align-items: center;
justify-content: center;
}
.sp {
width: 100%;
height: 30rpx;
font-size: 32rpx;
font-family: PingFangSC;
font-weight: 400;
color: #060001;
line-height: 30rpx;
border-top: solid 2rpx #ccc;
margin: 60rpx 0;
padding-top: 30rpx;
}
.btn-post{
font-weight: 500;
font-size: 32rpx;
color: #60989E;
line-height: 77rpx;
text-align: center;
display: flex;
margin-bottom: env(safe-area-inset-bottom);
.left-btn-buy{
width: 186rpx;
height: 77rpx;
color: #60989E;
border-radius: 39rpx 0rpx 0rpx 39rpx;
background: rgba(116, 165, 170, 0.3);
}
.right-btn-buy{
width: 187rpx;
height: 77rpx;
background: #74A5AA;
border-radius: 0 39rpx 39rpx 0;
color: white;
}
}
.sku-box{
width: 700rpx;
margin: 25rpx auto 0;
background: #FFFFFF;
border-radius: 20rpx;
.sku-item{
// border-radius: 20rpx;
width: 100%;
padding: 14rpx;
display: flex;
border-bottom: 1px solid #D8D8D8;
.sku-content{
display: flex;
padding-left: 16rpx;
flex: 1;
width: 1rpx;
}
image{
width: 160rpx;
height: 160rpx;
border-radius: 13rpx;
flex-shrink: 0;
}
.flex-1{
font-weight: 500;
font-size: 29rpx;
color: #000000;
height: 160rpx;
padding-right: 75rpx;
overflow: hidden;
}
.present-price{
display: flex;
align-items: center;
}
.present-price::after{
content: '';
}
}
.sku-item:last-of-type{
border: none;
}
}
.cart-box {
width: 100rpx;
height: 100rpx;
background: #f5f5f5;
position: fixed;
bottom: 200rpx;
right: 50rpx;
z-index: 100;
image {
width: 60rpx;
}
}
</style>

85
subPackages/techan/detail.vue

@ -2,7 +2,7 @@
<view class="bg" id="bg" v-if="info">
<view class="swipe-box">
<swiper class="swiper" :indicator-dots="false" :autoplay="false" :interval="3000" :duration="1000" circular>
<swiper-item v-if="info && info.videourl">
<!-- <swiper-item v-if="info && info.videourl">
<video
:src="showImg(info.videourl)"
id="detailVideo"
@ -13,22 +13,22 @@
style="width: 100%;height: 100%;"
object-fit="cover"
></video>
</swiper-item>
<swiper-item v-for="(item, index) in info.list_images.split(',')" :key="item.id">
</swiper-item> -->
<swiper-item v-for="(item, index) in info.mainUrl.split(',')" :key="item.id">
<view class="swiper-item">
<image class="item-img" :src="showImg(item)" mode="aspectFill"></image>
</view>
</swiper-item>
</swiper>
<view class="swiper-item-num">{{ info.list_images.split(',').length }}</view>
<view class="swiper-item-num">{{ info.mainUrl.split(',').length }}</view>
</view>
<view class="w-full relative" style="padding: 26rpx 0;top: -52rpx;">
<view class="price-box ">
<view class="price-zan">
<view class="price">
<view class="present-price">{{ info.money / 100 }}</view>
<view class="old-price">{{info.price / 100}}</view>
<view class="present-price">{{ info.salePrice }}</view>
<!-- <view class="old-price">{{info.price / 100}}</view> -->
</view>
</view>
<view class="tag no-scrollbar" v-if="info.goods_new_tag">
@ -36,26 +36,26 @@
{{ item }}
</view>
</view>
<view class="title">{{ info.title }}</view>
<view class="title">{{ info.goodsName }}</view>
</view>
<view class="sku-box" v-if="sku.length>0">
<view class="sku-item" v-for="(item,i) in sku" :key="i">
<image :src="showImg(item.image)"></image>
<image mode="aspectFill" :src="item.imageUrl"></image>
<view class="sku-content">
<view class="flex-1">{{item.title}}</view>
<view class="present-price">{{item.money/100}}</view>
<view class="flex-1">{{item.specValueOne}}-{{item.specValueTwo}}</view>
<view class="present-price">{{item.salePrice}}</view>
</view>
</view>
</view>
<view class="notice" v-if="info.reserve_content">
<!-- <view class="notice" v-if="info.reserve_content">
<view class="title">购买须知</view>
<view class="rich-text" v-html="formateRichText(info.reserve_content)"></view>
</view>
<view class="rich-text" v-html="formateRichText(info.detailUrl)"></view>
</view> -->
<view class="notice" >
<view class="title">商品须知</view>
<view class="rich-text" v-html="formateRichText(info.special_content)"></view>
<view class="rich-text" v-html="formateRichText(info.detailUrl)"></view>
</view>
</view>
@ -112,10 +112,10 @@
</view>
<view class="bottom-productImg">
<img :src="showImg(sku[productIndex].image)" alt="">
<img mode="aspectFill" :src="showImg(sku[productIndex].imageUrl)" alt="">
<view class="right-content">
<view class="bottom-productPrice com-price">{{(sku[productIndex].money||0)/100}}</view>
<view class="bottom-content text-overflow">已选择{{sku[productIndex].title}}</view>
<view class="bottom-productPrice com-price">{{(sku[productIndex].salePrice||0)}}</view>
<view class="bottom-content text-overflow">已选择{{sku[productIndex].specValueOne}}-{{sku[productIndex].specValueTwo}}</view>
</view>
</view>
<view>
@ -124,11 +124,11 @@
</view>
<view style="display: flex;align-items: center;justify-content: space-between;flex-wrap: wrap;">
<view style="position:relative;" v-for="(botItem,botIndex) in sku" :key="botIndex">
<view :class="['botProduct',{'noStore':botItem.store==0},{'botProducts':productIndex==botIndex}]"
<view :class="['botProduct',{'noStore':botItem.quantity==0},{'botProducts':productIndex==botIndex}]"
@click="changeProduct(botItem,botIndex)">
{{botItem.title}}
{{botItem.specValueOne}}-{{botItem.specValueTwo}}
</view>
<view class="noStore-text" v-if="botItem.store==0">
<view class="noStore-text" v-if="botItem.quantity==0">
不可购买
</view>
<!-- <view class="noStore-text" v-else-if="is_post==1&&botItem.is_post!=1">不可加购</view> -->
@ -196,7 +196,6 @@
onLoad(option) {
this.id = option.id;
this.getInfo();
this.getSpecificationsByGoodsId();
},
methods: {
changPopShow (e) {
@ -207,9 +206,8 @@
getInfo() {
this.Post({
goods_id: this.id
},
'/api/goods/getGoodDetail'
`/framework/goods/getGoodsInfo/${this.id}`,'DES'
).then(res => {
if (res.data.flag == 0) {
setTimeout(() => {
@ -223,34 +221,19 @@
}, 2000)
}
this.info = res.data;
this.sku = res.data.specCombinations
// this.isCollect = this.info.is_collect;
if (this.info.title) {
uni.setNavigationBarTitle({
title: this.info.title
title: this.info.goodsName
})
this.browse_record({type: 'goods',title: this.info.title});
this.browse_record({type: 'goods',title: this.info.goodsName});
}
});
},
getSpecificationsByGoodsId() {
this.Post({
goods_id: this.id
},
'/api/goods/getSpecificationsByGoodsId'
).then(res => {
if (res) {
this.sku = res.data || [];
// todo
// this.is_post = "2"
// if (this.sku.length>0 && this.sku.some(v=>v.is_post == 1)) {
// this.is_post = "1"
// }
}
});
},
//
collect() {
@ -325,21 +308,23 @@
addToCart () {
let goods = this.sku[this.productIndex]
goods.buyNum = this.buyNum
let goodsInfo = {goodsInfo:this.info, skuInfo: goods, isSelected: true}
this.Post({good_id: this.info.id, specifications_id: goods.id,num: this.buyNum },
'/api/shopping/addShopping').then(res => {
if (res) {
this.Post({goodsId: this.info.goodsId, specCombinationId: goods.specCombinationId,quantity: this.buyNum,method:'post' },
'/framework/cart/add',"DES").then(res => {
if (res.code==200) {
let selectedData = []
try {
selectedData = JSON.parse(uni.getStorageSync('cartDataInfo'));
} catch(e) {
selectedData = []
}
let currentGoods = selectedData.find(v =>v==goods.id)
let currentGoods = selectedData.find(v =>v==goods.goodsId)
if (!currentGoods) {
selectedData.push(goods.id)
selectedData.push(goods.goodsId)
}
uni.showToast({
title:'加购成功',
icon:'none'
})
uni.setStorageSync('cartDataInfo', JSON.stringify(selectedData));
uni.$emit("updateDataByConnect", {msgType:'updateCartDataInfo',data:null})
this.closePopup()
@ -353,7 +338,7 @@
})
},
changeProduct(item,index) {
if (item.store==0) {
if (item.quantity==0) {
uni.showToast({
title:"库存不足!",
icon:'none'
@ -620,7 +605,7 @@
}
}
.bottom-content {
width: 331rpx;
width: 380rpx;
font-size: 27rpx;
font-family: PingFang SC;
font-weight: 400;

1601
subPackages/user/gwc.vue

File diff suppressed because it is too large
Loading…
Cancel
Save