609 lines
16 KiB
Vue
609 lines
16 KiB
Vue
<template>
|
||
<view class="detail-page-container">
|
||
<!-- 沉浸式顶部标题栏 -->
|
||
<view class="nav-header">
|
||
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
|
||
<view class="header-content">
|
||
<view class="back-area" @click="goBack">
|
||
<text class="back-icon">〈</text>
|
||
</view>
|
||
<view class="title-area">
|
||
<text class="title-text">{{ cateName }}</text>
|
||
</view>
|
||
<view class="placeholder-area"></view>
|
||
</view>
|
||
</view>
|
||
|
||
<scroll-view scroll-y class="scroll-content" @scrolltolower="loadMore">
|
||
<!-- 占位适配固定头部 -->
|
||
<view class="header-placeholder" :style="{ height: (statusBarHeight + 44) + 'px' }"></view>
|
||
|
||
<!-- 排序筛选栏 -->
|
||
<view class="filter-bar">
|
||
<view class="filter-item" :class="{ 'active': sortType === 1 }" @click="changeSort(1)">综合</view>
|
||
<view class="filter-item" :class="{ 'active': sortType === 2 }" @click="changeSort(2)">销量</view>
|
||
<view class="filter-item" :class="{ 'active': sortType === 3 }" @click="changeSort(3)">
|
||
券后价
|
||
<view class="price-arrows">
|
||
<text class="up" :class="{ 'hl': sortType === 3 && priceOrder === 'asc' }">▲</text>
|
||
<text class="down" :class="{ 'hl': sortType === 3 && priceOrder === 'desc' }">▼</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 高级筛选标签栏 -->
|
||
<view class="sub-filter-row">
|
||
<view class="sub-filter-item" :class="{ 'active': filterHasCoupon }" @click="toggleFilter('coupon')">有券</view>
|
||
<view class="sub-filter-item" :class="{ 'active': filterIsFlagship }" @click="toggleFilter('flagship')">旗舰店</view>
|
||
<view class="sub-filter-item" :class="{ 'active': filterIsTmall }" @click="toggleFilter('tmall')">天猫</view>
|
||
<view class="sub-filter-item" :class="{ 'active': filterIsBrand }" @click="toggleFilter('brand')">品牌</view>
|
||
</view>
|
||
|
||
<!-- 商品列表 (横向单列风格) -->
|
||
<view class="goods-list">
|
||
<view class="goods-item" v-for="(goods, idx) in goodsList" :key="idx" @click="goToDetail(goods.id)">
|
||
<view class="g-img-left">
|
||
<image class="goods-img" :src="goods.image" mode="aspectFill"></image>
|
||
</view>
|
||
<view class="goods-info">
|
||
<view class="goods-title-row">
|
||
<image src="https://img-haodanku-com.cdn.fudaiapp.com/FlyOSTvjC3LjrkUoJ0NPxx1qnGz4" class="platform-icon"></image>
|
||
<text class="title-text">{{ goods.title }}</text>
|
||
</view>
|
||
<!-- 标签组 -->
|
||
<view class="labels-row" v-if="goods.labels && goods.labels.length > 0">
|
||
<text class="label-tag" v-for="(label, lIdx) in goods.labels.slice(0, 2)" :key="lIdx">{{ label }}</text>
|
||
</view>
|
||
|
||
<view class="goods-price-section">
|
||
<view class="price-main">
|
||
<text class="price-tip">{{ goods.couponValue > 0 ? '券后' : '抢购价' }}</text>
|
||
<text class="price-symbol">¥</text>
|
||
<text class="price-integer">{{ goods.finalPrice }}</text>
|
||
<view class="coupon-box" v-if="goods.couponValue > 0">
|
||
<text class="coupon-icon">券</text>
|
||
<text class="coupon-txt">{{ goods.couponValue }}元</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="goods-bottom-info">
|
||
<text class="sales">已售{{ goods.sales }}件</text>
|
||
<text class="split-line">|</text>
|
||
<text class="shop-name">店铺:{{ goods.shopName }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 更多推荐分割线 -->
|
||
<view class="recommend-divider" v-if="recommendList.length > 0">
|
||
<view class="line"></view>
|
||
<text class="dot">更多推荐</text>
|
||
<view class="line"></view>
|
||
</view>
|
||
|
||
<!-- 推荐商品列表 -->
|
||
<view class="goods-list recommend-list" v-if="recommendList.length > 0">
|
||
<view class="goods-item" v-for="(goods, idx) in recommendList" :key="idx" @click="goToDetail(goods.id)">
|
||
<view class="g-img-left">
|
||
<image class="goods-img" :src="goods.image" mode="aspectFill"></image>
|
||
</view>
|
||
<view class="goods-info">
|
||
<view class="goods-title-row">
|
||
<image src="https://img-haodanku-com.cdn.fudaiapp.com/FlyOSTvjC3LjrkUoJ0NPxx1qnGz4" class="platform-icon"></image>
|
||
<text class="title-text">{{ goods.title }}</text>
|
||
</view>
|
||
<view class="labels-row" v-if="goods.labels && goods.labels.length > 0">
|
||
<text class="label-tag" v-for="(label, lIdx) in goods.labels.slice(0, 2)" :key="lIdx">{{ label }}</text>
|
||
</view>
|
||
<view class="goods-price-section">
|
||
<view class="price-main">
|
||
<text class="price-tip">{{ goods.couponValue > 0 ? '券后' : '抢购价' }}</text>
|
||
<text class="price-symbol">¥</text>
|
||
<text class="price-integer">{{ goods.finalPrice }}</text>
|
||
<view class="coupon-box" v-if="goods.couponValue > 0">
|
||
<text class="coupon-icon">券</text>
|
||
<text class="coupon-txt">{{ goods.couponValue }}元</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="goods-bottom-info">
|
||
<text class="sales">已售{{ goods.sales }}件</text>
|
||
<text class="split-line">|</text>
|
||
<text class="shop-name">店铺:{{ goods.shopName }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="loading-status">
|
||
<view v-if="loading" class="loading-text">加载中...</view>
|
||
<view v-else-if="goodsList.length === 0" class="empty-text">暂无相关商品</view>
|
||
<view v-else-if="finished" class="finished-text">-- 已经到底啦 --</view>
|
||
</view>
|
||
|
||
<view class="footer-placeholder"></view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
statusBarHeight: 44,
|
||
cateName: '分类详情',
|
||
mainCatId: '',
|
||
secondCategory: '', // 子分类ID串
|
||
goodsList: [],
|
||
page: 1,
|
||
sortType: 1, // 1:综合, 2:销量, 3:价格
|
||
priceOrder: 'desc',
|
||
loading: false,
|
||
finished: false,
|
||
// 高级筛选状态
|
||
filterHasCoupon: false,
|
||
filterIsFlagship: false,
|
||
filterIsTmall: false,
|
||
filterIsBrand: false,
|
||
recommendList: [], // 更多推荐列表
|
||
loadingRecommend: false
|
||
}
|
||
},
|
||
onLoad(options) {
|
||
const sysInfo = uni.getSystemInfoSync();
|
||
this.statusBarHeight = sysInfo.statusBarHeight || 44;
|
||
|
||
if (options.cate_name) this.cateName = decodeURIComponent(options.cate_name);
|
||
if (options.id) this.mainCatId = options.id;
|
||
if (options.second_category) this.secondCategory = options.second_category;
|
||
|
||
this.getProducts(true);
|
||
},
|
||
methods: {
|
||
goBack() {
|
||
uni.navigateBack();
|
||
},
|
||
getProducts(refresh = false) {
|
||
if (refresh) {
|
||
this.page = 1;
|
||
this.finished = false;
|
||
this.goodsList = [];
|
||
}
|
||
if (this.loading || this.finished) return;
|
||
|
||
this.loading = true;
|
||
// 构建排序参数 (0:综合, 3:销量, 8:券后价低到高, 9:券后价高到低)
|
||
let sortParam = 0;
|
||
if (this.sortType === 2) {
|
||
sortParam = 3;
|
||
} else if (this.sortType === 3) {
|
||
sortParam = this.priceOrder === 'asc' ? 8 : 9;
|
||
}
|
||
|
||
// 构建高级筛选参数
|
||
let filterParams = '';
|
||
if (this.filterHasCoupon) filterParams += '&filtrate_type=16';
|
||
if (this.filterIsBrand) filterParams += '&is_brand=1';
|
||
|
||
// 动态构建 shoptype: 旗舰店为1,天猫为2,两者都选为1,2
|
||
let shopTypes = [];
|
||
if (this.filterIsFlagship) shopTypes.push(1);
|
||
if (this.filterIsTmall) shopTypes.push(2);
|
||
if (shopTypes.length > 0) {
|
||
filterParams += `&shoptype=${shopTypes.join(',')}`;
|
||
}
|
||
|
||
uni.request({
|
||
url: `https://api.cmspro.haodanku.com/find/allItemList?category_id=${this.mainCatId}&son_category=${encodeURIComponent(this.secondCategory)}&page=${this.page}&sort=${sortParam}&page_size=20&cid=YsWZ21tx${filterParams}`,
|
||
success: (res) => {
|
||
if (res.data && res.data.code === 200 && res.data.data && res.data.data.item_info) {
|
||
const list = res.data.data.item_info.map(item => ({
|
||
id: item.id,
|
||
image: item.itempic,
|
||
title: item.itemshorttitle && item.itemshorttitle.length > 18 ? item.itemshorttitle.substring(0, 18) + '...' : item.itemshorttitle,
|
||
finalPrice: item.itemendprice,
|
||
couponValue: item.couponmoney || 0,
|
||
sales: item.itemsale >= 10000 ? (item.itemsale / 10000).toFixed(1) + '万' : item.itemsale,
|
||
shopType: item.shoptype === 'B' ? '天猫' : '淘宝',
|
||
shopName: item.shopname,
|
||
labels: item.label || []
|
||
}));
|
||
|
||
if (list.length === 0) {
|
||
this.finished = true;
|
||
} else {
|
||
this.goodsList = [...this.goodsList, ...list];
|
||
this.page++;
|
||
if (list.length < 20) {
|
||
this.finished = true;
|
||
}
|
||
}
|
||
|
||
// 兜底逻辑:如果主列表数据少于 10 条且是首屏加载,则请求推荐列表
|
||
if (refresh && this.goodsList.length < 10) {
|
||
this.getRecommendList();
|
||
}
|
||
} else {
|
||
this.finished = true;
|
||
if (refresh) this.getRecommendList();
|
||
}
|
||
},
|
||
complete: () => {
|
||
this.loading = false;
|
||
}
|
||
});
|
||
},
|
||
getRecommendList() {
|
||
if (this.loadingRecommend) return;
|
||
this.loadingRecommend = true;
|
||
// 构建推荐接口的高级筛选参数
|
||
let recommendParams = '';
|
||
if (this.filterHasCoupon) recommendParams += '&is_coupon=1';
|
||
if (this.filterIsFlagship) recommendParams += '&is_tmall=1';
|
||
if (this.filterIsTmall) recommendParams += '&min_id=1';
|
||
|
||
uni.request({
|
||
url: `https://api.cmspro.haodanku.com/superSearch/getList?sort=0&page_size=20&category_id=${this.mainCatId}&son_category=${encodeURIComponent(this.secondCategory)}&cid=YsWZ21tx${recommendParams}`,
|
||
success: (res) => {
|
||
if (res.data && res.data.code === 200 && res.data.data) {
|
||
const list = res.data.data.map(item => ({
|
||
id: item.id || item.itemid,
|
||
image: item.itempic,
|
||
title: item.itemshorttitle && item.itemshorttitle.length > 18 ? item.itemshorttitle.substring(0, 18) + '...' : item.itemshorttitle,
|
||
finalPrice: item.itemendprice,
|
||
couponValue: item.couponmoney || 0,
|
||
sales: item.itemsale >= 10000 ? (item.itemsale / 10000).toFixed(1) + '万' : item.itemsale,
|
||
shopType: item.shoptype === 'B' ? '天猫' : '淘宝',
|
||
shopName: item.shopname,
|
||
labels: item.label || (item.couponmoney > 0 ? [`${item.couponmoney}元券`] : [])
|
||
}));
|
||
this.recommendList = list;
|
||
}
|
||
},
|
||
complete: () => {
|
||
this.loadingRecommend = false;
|
||
}
|
||
});
|
||
},
|
||
changeSort(type) {
|
||
if (type === 3 && this.sortType === 3) {
|
||
this.priceOrder = this.priceOrder === 'asc' ? 'desc' : 'asc';
|
||
} else {
|
||
this.sortType = type;
|
||
if (type === 3) this.priceOrder = 'desc';
|
||
}
|
||
this.getProducts(true);
|
||
},
|
||
toggleFilter(type) {
|
||
if (type === 'coupon') this.filterHasCoupon = !this.filterHasCoupon;
|
||
if (type === 'flagship') this.filterIsFlagship = !this.filterIsFlagship;
|
||
if (type === 'tmall') this.filterIsTmall = !this.filterIsTmall;
|
||
if (type === 'brand') this.filterIsBrand = !this.filterIsBrand;
|
||
|
||
this.getProducts(true);
|
||
},
|
||
loadMore() {
|
||
this.getProducts();
|
||
},
|
||
goToDetail(id) {
|
||
uni.navigateTo({
|
||
url: `/pages/detail/detail?id=${id}`
|
||
});
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.detail-page-container {
|
||
width: 100%;
|
||
height: 100vh;
|
||
background-color: #f5f6f8;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 顶部导航 */
|
||
.nav-header {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
/* 去掉阴影让头部更轻 */
|
||
right: 0;
|
||
background-color: #ffffff;
|
||
z-index: 100;
|
||
}
|
||
|
||
.header-content {
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 30rpx;
|
||
}
|
||
|
||
.back-area {
|
||
width: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.back-icon {
|
||
font-size: 36rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.title-area {
|
||
flex: 1;
|
||
text-align: center;
|
||
}
|
||
|
||
.nav-header .title-text {
|
||
font-size: 36rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
|
||
|
||
.placeholder-area {
|
||
width: 60rpx;
|
||
}
|
||
|
||
.scroll-content {
|
||
flex: 1;
|
||
height: 100%;
|
||
}
|
||
|
||
.header-placeholder {
|
||
width: 100%;
|
||
}
|
||
|
||
/* 筛选栏 */
|
||
.filter-bar {
|
||
display: flex;
|
||
background: #ffffff;
|
||
height: 76rpx;
|
||
align-items: center;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 90;
|
||
}
|
||
|
||
.filter-item {
|
||
flex: 1;
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.filter-item.active {
|
||
color: #ff416c;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 高级筛选标签栏 */
|
||
.sub-filter-row {
|
||
display: flex;
|
||
background: #ffffff;
|
||
padding: 0 20rpx 16rpx;
|
||
align-items: center;
|
||
border-bottom: 1rpx solid #f1f1f1;
|
||
}
|
||
|
||
.sub-filter-item {
|
||
padding: 8rpx 26rpx;
|
||
background: #f5f6f8;
|
||
color: #333;
|
||
font-size: 24rpx;
|
||
border-radius: 28rpx;
|
||
margin-right: 16rpx;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.sub-filter-item.active {
|
||
background: linear-gradient(to right, #ff758c, #ff416c);
|
||
color: #ffffff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.price-arrows {
|
||
display: flex;
|
||
flex-direction: column;
|
||
margin-left: 6rpx;
|
||
line-height: 1;
|
||
}
|
||
|
||
.price-arrows text {
|
||
font-size: 16rpx;
|
||
color: #ccc;
|
||
}
|
||
|
||
.price-arrows text.hl {
|
||
color: #ff416c;
|
||
}
|
||
|
||
/* 商品列表 */
|
||
.goods-list {
|
||
padding: 0;
|
||
background: #ffffff;
|
||
}
|
||
|
||
.goods-item {
|
||
display: flex;
|
||
padding: 24rpx;
|
||
border-bottom: 1rpx solid #f8f8f8;
|
||
background: #ffffff;
|
||
}
|
||
|
||
.g-img-left {
|
||
flex-shrink: 0;
|
||
width: 240rpx;
|
||
height: 240rpx;
|
||
border-radius: 12rpx;
|
||
overflow: hidden;
|
||
background: #f0f0f0;
|
||
}
|
||
|
||
.goods-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.goods-info {
|
||
flex: 1;
|
||
margin-left: 20rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
padding: 4rpx 0;
|
||
}
|
||
|
||
.goods-title-row {
|
||
display: flex;
|
||
align-items: center;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.platform-icon {
|
||
width: 26rpx;
|
||
height: 26rpx;
|
||
margin-right: 8rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.title-text {
|
||
font-size: 22rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
flex: 1;
|
||
}
|
||
|
||
.labels-row {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
margin-top: 12rpx;
|
||
}
|
||
|
||
.label-tag {
|
||
font-size: 20rpx;
|
||
color: #ff416c;
|
||
background: #fff5f7;
|
||
border: 1rpx solid #ffd6de;
|
||
padding: 2rpx 12rpx;
|
||
border-radius: 20rpx;
|
||
margin-right: 12rpx;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.goods-price-section {
|
||
margin-top: auto;
|
||
padding-bottom: 8rpx;
|
||
}
|
||
|
||
.price-main {
|
||
display: flex;
|
||
align-items: baseline;
|
||
}
|
||
|
||
.price-tip {
|
||
font-size: 24rpx;
|
||
color: #ff416c;
|
||
margin-right: 4rpx;
|
||
}
|
||
|
||
.price-symbol {
|
||
font-size: 24rpx;
|
||
color: #ff416c;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.price-integer {
|
||
font-size: 40rpx;
|
||
color: #ff416c;
|
||
font-weight: bold;
|
||
margin-right: 12rpx;
|
||
}
|
||
|
||
.coupon-box {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #ff416c;
|
||
border-radius: 4rpx;
|
||
overflow: hidden;
|
||
height: 32rpx;
|
||
}
|
||
|
||
.coupon-icon {
|
||
font-size: 20rpx;
|
||
color: #ffffff;
|
||
background: rgba(255,255,255,0.2);
|
||
padding: 0 6rpx;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.coupon-txt {
|
||
font-size: 20rpx;
|
||
color: #ffffff;
|
||
padding: 0 8rpx;
|
||
}
|
||
|
||
.goods-bottom-info {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 22rpx;
|
||
color: #999;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
.split-line {
|
||
margin: 0 10rpx;
|
||
color: #eee;
|
||
}
|
||
|
||
.loading-status {
|
||
text-align: center;
|
||
padding: 40rpx 0;
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
/* 更多推荐分割线 */
|
||
.recommend-divider {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 30rpx 0;
|
||
background-color: #f8f8f8;
|
||
}
|
||
|
||
.recommend-divider .line {
|
||
width: 100rpx;
|
||
height: 1rpx;
|
||
background-color: #ddd;
|
||
}
|
||
|
||
.recommend-divider .dot {
|
||
margin: 0 30rpx;
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.recommend-list {
|
||
background: #ffffff;
|
||
}
|
||
|
||
.footer-placeholder {
|
||
height: 40rpx;
|
||
}
|
||
</style>
|