baimacms/pages/activity/activity.vue

676 lines
15 KiB
Vue

<template>
<view class="activity-page">
<!-- Banner -->
<view class="banner-wrapper">
<image class="banner-img" :src="banner" mode="widthFix" />
</view>
<!-- 分类 Tabs -->
<view class="category-sticky" v-if="category.list.length > 1">
<scroll-view scroll-x class="category-scroll" :show-scrollbar="false">
<view class="category-tabs">
<view v-for="item in category.list" :key="item.value" class="tab-item"
:class="{ active: category.value === item.value }" @click="onNavChange(item.value)">
{{ item.label }}
</view>
</view>
</scroll-view>
</view>
<!-- 商品列表 -->
<view class="goods-list" :class="{ 'empty-list': !listData.list.length }">
<view class="goods-card" v-for="(item, index) in listData.list" :key="item.itemid"
@click="handleGoodsTransfer(item)">
<view class="cover img-box">
<image class="goods-img" :src="item.itempic" mode="aspectFill" lazy-load v-if="item.itempic" />
<image class="goods-img" src="http://img.bc.fqapps.com/fudai13cae4ae6ef16739ed3b100a2ec39e97.gif"
mode="aspectFill" v-else />
<view class="sale-tag">
<text class="fire-icon">🔥</text>
<text>日销量 {{ getMoneyStr(item.itemsale2) }}</text>
</view>
</view>
<view class="detail">
<view class="title">
<image v-if="item.shoptype === 'B'" class="shop-icon tm"
src="http://img-haodanku-com.cdn.fudaiapp.com/FvU9Lg74-WgBzWQphv98-9KgYF6d" />
<image v-else-if="item.shoptype === 'C'" class="shop-icon tb"
src="http://img-haodanku-com.cdn.fudaiapp.com/FnCy1eY4W5khYdTw_iIDhKuwGLmu" />
<text class="title-text">{{ item.itemshorttitle || item.itemtitle }}</text>
</view>
<view class="center">
<text>{{ item.itemdesc }}</text>
</view>
<view class="price">
<view class="end-price">
券后价<text class="price-strong">¥{{ Number(item.itemendprice) }}</text>
</view>
<view class="origin">
<text class="del-price">¥{{ Number(item.itemprice) }}</text>
</view>
</view>
<view class="tags" v-if="item.couponmoney != '0'">
<view class="ticket">
<text class="name">券</text><text class="value">¥{{ item.couponmoney }}</text>
</view>
</view>
<view class="btn-block">
<view class="btn-order" @click.stop="handleGoodsTransfer(item)">
<text>立即购买</text>
</view>
</view>
</view>
</view>
<!-- 加载提示 -->
<view class="list-loading" v-if="loading && !listData.list.length">数据正在赶来的路上...</view>
<view class="list-finished" v-if="listData.finished && listData.list.length">-优惠到底啦-</view>
</view>
<!-- 分享按钮 -->
<view class="share-btn" :class="{ hide: isScrollToDown }" @click="handleShare">
<view class="share-icon">
<svg viewBox="0 0 18 19.11" class="svg-share">
<path class="cls-1"
d="M17.5,8A2.5,2.5,0,1,0,15,5.5,2.5,2.5,0,0,0,17.5,8Z" transform="translate(-3 -2)" />
<path class="cls-1"
d="M6.5,14.5A2.5,2.5,0,1,0,4,12,2.5,2.5,0,0,0,6.5,14.5Z" transform="translate(-3 -2)" />
<path class="cls-2" d="M15,6.79,8.67,10.62" transform="translate(-3 -2)" />
<path class="cls-2" d="M8.67,13.28,13.27,16" transform="translate(-3 -2)" />
<path class="cls-1"
d="M15.77,15.11a2.5,2.5,0,1,1-2.5,2.5A2.5,2.5,0,0,1,15.77,15.11Z" transform="translate(-3 -2)" />
</svg>
</view>
<text>分享好友</text>
</view>
<!-- 回到顶部 -->
<view class="back-top-btn" :class="{ hide: scrollTop < 600 }" @click="backTop"></view>
</view>
</template>
<script>
const API_BASE = 'https://v2.api.haodanku.com';
const CUSTOM_PARAMS = {
apikey: '5417B681C5EA'
};
export default {
data() {
return {
banner: '',
loading: false,
scrollTop: 0,
lastScrollTop: 0,
isScrollToDown: false,
category: {
value: '0',
list: [],
goodsLists: []
},
listData: {
list: [],
loading: false,
finished: false
}
}
},
onLoad(options) {
const stamp = Date.now() - Date.now() % (60 * 1000 * 30);
this.banner = 'https://img.bc.haodanku.com/cms/1635994050?t=' + stamp;
this.getListData();
},
onPageScroll(e) {
const st = e.scrollTop;
this.isScrollToDown = st > this.lastScrollTop;
this.lastScrollTop = st;
this.scrollTop = st;
},
onPullDownRefresh() {
this.reGetListData().finally(() => {
uni.stopPullDownRefresh();
});
},
methods: {
getListDataParams() {
return { ...CUSTOM_PARAMS };
},
getTransferParams() {
const rid = this.$store.getters.relationId;
return {
pid: 'mm_284380119_1881450385_111415850448',
tb_name: 'michuan2018',
relation_id: rid || '-1',
...CUSTOM_PARAMS
};
},
async getListData() {
const listData = this.listData;
if (this.loading || listData.loading || listData.finished) return;
listData.loading = true;
this.loading = true;
const params = {
id: 125,
...this.getListDataParams()
};
uni.request({
url: `${API_BASE}/get_index_activity_items`,
data: params,
success: (res) => {
if (res.statusCode === 200 && res.data) {
const block = res.data.data ? (res.data.data.block || []) : (res.data.block || []);
this.category.list = block.map((item, index) => ({
label: item.name,
value: String(index)
}));
this.category.goodsLists = block.map(item => item.item || []);
const list = this.category.goodsLists[0] || [];
this.listData.list = list;
this.listData.finished = true;
} else {
this.listData.list = [];
this.listData.finished = true;
}
},
fail: () => {
this.listData.list = [];
this.listData.finished = true;
},
complete: () => {
setTimeout(() => {
this.listData.loading = false;
this.loading = false;
}, 200);
}
});
},
reGetListData() {
this.listData.list = [];
this.listData.finished = false;
return this.getListData();
},
onNavChange(value) {
this.category.value = value;
this.listData.list = this.category.goodsLists[value] || [];
},
backTop() {
uni.pageScrollTo({
scrollTop: 0,
duration: 300
});
},
handleShare() {
let shareUrl;
// #ifdef H5
shareUrl = window.location.href;
// #endif
// #ifndef H5
shareUrl = 'https://your-domain.com/pages/activity/activity';
// #endif
uni.setClipboardData({
data: shareUrl,
success: () => {
uni.showToast({
title: '复制成功,分享给身边好友吧~',
icon: 'none'
});
}
});
},
async handleGoodsTransfer(item) {
const param = {
itemid: item.itemid,
title: item.itemshorttitle || item.itemtitle,
get_taoword: 1,
...this.getTransferParams()
};
this.loading = true;
try {
let isWechatEnv;
// #ifdef H5
isWechatEnv = /micromessenger/i.test(navigator.userAgent);
// #endif
// #ifndef H5
isWechatEnv = false;
// #endif
if (!isWechatEnv) {
// 非微信环境:弹窗确认后跳转
uni.request({
url: `${API_BASE}/ratesurl`,
method: 'POST',
data: param,
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
success: (res) => {
if (res.statusCode === 200 && res.data) {
const data = res.data.data || res.data;
const jumpUrl = data.coupon_click_url || data.item_url;
if (jumpUrl) {
uni.showModal({
title: '提示',
content: '是否跳转到下单页面?',
success: (modalRes) => {
if (modalRes.confirm) {
// #ifdef H5
window.location.href = jumpUrl;
// #endif
// #ifdef APP-PLUS
plus.runtime.openURL(jumpUrl);
// #endif
// #ifndef H5 || APP-PLUS
uni.setClipboardData({
data: jumpUrl,
success: () => {
uni.showToast({
title: '链接已复制,请在浏览器中打开',
icon: 'none',
duration: 3000
});
}
});
// #endif
}
}
});
}
} else {
uni.showToast({
title: '转链失败',
icon: 'none'
});
}
},
fail: () => {
uni.showToast({
title: '转链失败',
icon: 'none'
});
}
});
} else {
// 微信环境:获取淘口令并复制
uni.request({
url: `${API_BASE}/ratesurl`,
method: 'POST',
data: param,
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
success: (res) => {
if (res.statusCode === 200 && res.data) {
const data = res.data.data || res.data;
const taoword = data.taoword;
if (taoword) {
const taocode = '0' + taoword + '/';
uni.setClipboardData({
data: taocode,
success: () => {
uni.showToast({
title: '复制口令成功,请打开淘宝领取',
icon: 'none',
duration: 2000
});
}
});
} else {
uni.showToast({
title: '转链失败',
icon: 'none'
});
}
} else {
uni.showToast({
title: '转链失败',
icon: 'none'
});
}
},
fail: () => {
uni.showToast({
title: '转链失败',
icon: 'none'
});
}
});
}
} catch (e) {
uni.showToast({
title: '转链失败',
icon: 'none'
});
} finally {
setTimeout(() => {
this.loading = false;
}, 200);
}
},
getMoneyStr(num) {
const n = Number(num);
const w = 10000;
if (n < w) return String(n);
return (n / w).toFixed(2) + '万';
}
}
}
</script>
<style scoped>
.activity-page {
background: #f5f5f5;
min-height: 100vh;
}
.banner-wrapper {
width: 100%;
}
.banner-img {
width: 100%;
display: block;
}
.category-sticky {
position: sticky;
top: 0;
z-index: 100;
background: #fff;
}
.category-scroll {
white-space: nowrap;
}
.category-tabs {
display: flex;
padding: 0 20rpx;
border-bottom: 1rpx solid #eee;
}
.tab-item {
display: inline-block;
padding: 24rpx 30rpx;
font-size: 28rpx;
color: #666;
position: relative;
flex-shrink: 0;
}
.tab-item.active {
color: #ff416c;
font-weight: bold;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 40rpx;
height: 4rpx;
background: #ff416c;
border-radius: 2rpx;
}
.goods-list {
padding: 20rpx;
}
.goods-list.empty-list {
min-height: 400rpx;
display: flex;
align-items: center;
justify-content: center;
}
.goods-card {
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
overflow: hidden;
display: flex;
padding: 20rpx;
}
.cover {
position: relative;
width: 240rpx;
height: 240rpx;
flex-shrink: 0;
border-radius: 12rpx;
overflow: hidden;
background: #f9f9f9;
}
.goods-img {
width: 100%;
height: 100%;
}
.sale-tag {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to right, rgba(255, 65, 108, 0.9), rgba(255, 75, 43, 0.9));
color: #fff;
font-size: 20rpx;
padding: 6rpx 12rpx;
display: flex;
align-items: center;
}
.fire-icon {
margin-right: 4rpx;
}
.detail {
flex: 1;
margin-left: 20rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.title {
display: flex;
align-items: flex-start;
font-size: 28rpx;
color: #333;
line-height: 1.4;
}
.shop-icon {
width: 36rpx;
height: 36rpx;
margin-right: 8rpx;
flex-shrink: 0;
margin-top: 2rpx;
}
.title-text {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.center {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.price {
display: flex;
align-items: baseline;
margin-top: 8rpx;
}
.end-price {
font-size: 24rpx;
color: #ff416c;
}
.price-strong {
font-size: 36rpx;
font-weight: bold;
margin-left: 4rpx;
}
.origin {
margin-left: 12rpx;
}
.del-price {
font-size: 24rpx;
color: #999;
text-decoration: line-through;
}
.tags {
margin-top: 8rpx;
}
.ticket {
display: inline-flex;
align-items: center;
border: 1rpx solid #ff416c;
border-radius: 8rpx;
overflow: hidden;
font-size: 22rpx;
}
.ticket .name {
background: linear-gradient(to right, #ff715a, #ff416c);
color: #fff;
padding: 2rpx 10rpx;
}
.ticket .value {
color: #ff416c;
padding: 2rpx 10rpx;
font-weight: bold;
}
.btn-block {
margin-top: 12rpx;
display: flex;
justify-content: flex-end;
}
.btn-order {
background: linear-gradient(to right, #ff715a, #ff416c);
color: #fff;
font-size: 26rpx;
padding: 12rpx 32rpx;
border-radius: 30rpx;
font-weight: bold;
}
.list-loading,
.list-finished {
text-align: center;
padding: 30rpx;
font-size: 24rpx;
color: #999;
}
.share-btn {
position: fixed;
right: 30rpx;
bottom: 160rpx;
z-index: 200;
background: rgba(255, 65, 108, 0.9);
color: #fff;
border-radius: 40rpx;
padding: 16rpx 24rpx;
font-size: 24rpx;
display: flex;
align-items: center;
box-shadow: 0 4rpx 16rpx rgba(255, 65, 108, 0.3);
transition: transform 0.3s, opacity 0.3s;
}
.share-btn.hide {
transform: translateX(120%);
opacity: 0;
}
.share-icon {
width: 32rpx;
height: 32rpx;
margin-right: 8rpx;
}
.svg-share {
width: 100%;
height: 100%;
}
.svg-share .cls-1 {
fill: none;
stroke: #fff;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 1.5px;
}
.svg-share .cls-2 {
fill: none;
stroke: #fff;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 1.5px;
}
.back-top-btn {
position: fixed;
right: 30rpx;
bottom: 80rpx;
z-index: 200;
width: 80rpx;
height: 80rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.3s, opacity 0.3s;
}
.back-top-btn::before {
content: '';
width: 0;
height: 0;
border-left: 16rpx solid transparent;
border-right: 16rpx solid transparent;
border-bottom: 20rpx solid #fff;
}
.back-top-btn.hide {
transform: translateY(200%);
opacity: 0;
}
</style>