Files
frontend-app/pages/sort/sort.vue
T

931 lines
26 KiB
Vue
Raw Normal View History

2026-08-06 18:50:25 +08:00
<template>
<view class="sort_warp" :class="platformType ? '' : 'iosplatformType'">
<!-- #ifndef MP-WEIXIN -->
2026-08-17 09:27:07 +08:00
<TopSafe bgColor="#F2EBFF"></TopSafe>
2026-08-06 18:50:25 +08:00
<!-- #endif -->
<!-- 顶部固定区域:搜索 + 分类区域 -->
<view class="top_fixed_header" :class="{ is_expanded: showAllCategories }" :style="mpHeaderStyle">
<!-- 搜索框 -->
<view class="search_bar" @click="jumpSearch">
<u-icon name="search" size="18" color="#999"></u-icon>
<text class="search_placeholder">搜索</text>
</view>
<!-- 1. 未展开时:顶部分类横向滚动条 -->
<view class="top_category_row" v-if="!showAllCategories">
<scroll-view class="top_category_scroll" scroll-x :show-scrollbar="false">
<view class="top_cat_list">
<view class="top_cat_item" v-for="(item, index) in categoryList" :key="item.id || index"
@click="selectCategory(index)">
<view class="top_cat_img_box" :class="{ active_img: currentCategoryIndex === index }">
<image class="top_cat_img" :src="item.icon || defaultIcon" mode="aspectFill" />
</view>
<view class="top_cat_name_badge" :class="{ active_badge: currentCategoryIndex === index }">
{{ item.name }}
</view>
</view>
</view>
</scroll-view>
<!-- 右侧全部按钮 -->
<view class="expand_all_btn" @click="toggleAllCategories">
<text class="expand_text">全部</text>
<u-icon name="arrow-down-fill" size="10" color="#666"></u-icon>
</view>
</view>
<!-- 2. 点开全部时:展开所有分类网格面板 -->
<view class="all_categories_panel" v-else>
<view class="panel_header">
<text class="panel_title">所有分类</text>
</view>
<scroll-view class="panel_grid_scroll" scroll-y :show-scrollbar="false">
<view class="panel_grid">
<view class="top_cat_item panel_cat_item" v-for="(item, index) in categoryList" :key="item.id || index"
@click="selectCategory(index, true)">
<view class="top_cat_img_box" :class="{ active_img: currentCategoryIndex === index }">
<image class="top_cat_img" :src="item.icon || defaultIcon" mode="aspectFill" />
</view>
<view class="top_cat_name_badge" :class="{ active_badge: currentCategoryIndex === index }">
{{ item.name }}
</view>
</view>
</view>
</scroll-view>
<view class="collapse_btn" @click="toggleAllCategories">
<text style="margin-right: 6rpx;">全部收起</text>
<u-icon name="arrow-up" size="12" color="#666"></u-icon>
</view>
</view>
</view>
<!-- 主体区域:左侧边栏 + 右侧商品列表 -->
<view class="main_container">
<!-- 展开所有分类时的半透明遮罩 -->
<view class="mask_overlay" v-if="showAllCategories" @click="showAllCategories = false"></view>
<!-- 左侧分类侧边栏 -->
<scroll-view class="left_sidebar_scroll" scroll-y>
2026-08-17 09:27:07 +08:00
<view class="sidebar_item" v-for="(item, index) in subCategoryList" :key="item.id || index"
:class="{ active: currentSubCategoryIndex === index }" @click="selectSubCategory(index)">
2026-08-06 18:50:25 +08:00
<text class="sidebar_name">{{ item.name }}</text>
</view>
</scroll-view>
<!-- 右侧商品列表区 -->
<view class="right_content_area">
<!-- 排序栏 -->
<view class="sort_option_bar">
2026-08-17 09:27:07 +08:00
<view></view>
<!-- <view class="cat_title_text">{{ currentCategory ? currentCategory.name : '' }}</view> -->
2026-08-06 18:50:25 +08:00
<view class="sort_actions">
2026-08-17 09:27:07 +08:00
<view class="sort_item" :class="{ active: sortBy === 'relevance' }" @click="setSort('relevance')">
<text>综合</text>
<view class="sort_icon_box">
<u-icon name="arrow-up-fill" size="10rpx"
:color="sortBy === 'relevance' && sortOrder === 'asc' ? '#7a35f6' : '#cccccc'"
class="icon_up"></u-icon>
<u-icon name="arrow-down-fill" size="10rpx"
:color="sortBy === 'relevance' && sortOrder === 'desc' ? '#7a35f6' : '#cccccc'"
class="icon_down"></u-icon>
</view>
2026-08-06 18:50:25 +08:00
</view>
2026-08-17 09:27:07 +08:00
<view class="sort_item" :class="{ active: sortBy === 'sales' }" @click="setSort('sales')">
<text>销量</text>
<view class="sort_icon_box">
<u-icon name="arrow-up-fill" size="10rpx"
:color="sortBy === 'sales' && sortOrder === 'asc' ? '#7a35f6' : '#cccccc'" class="icon_up"></u-icon>
<u-icon name="arrow-down-fill" size="10rpx"
:color="sortBy === 'sales' && sortOrder === 'desc' ? '#7a35f6' : '#cccccc'"
class="icon_down"></u-icon>
</view>
2026-08-06 18:50:25 +08:00
</view>
2026-08-17 09:27:07 +08:00
<view class="sort_item" :class="{ active: sortBy === 'price' }" @click="setSort('price')">
<text>价格</text>
<view class="sort_icon_box">
<u-icon name="arrow-up-fill" size="10rpx"
:color="sortBy === 'price' && sortOrder === 'asc' ? '#7a35f6' : '#cccccc'" class="icon_up"></u-icon>
<u-icon name="arrow-down-fill" size="10rpx"
:color="sortBy === 'price' && sortOrder === 'desc' ? '#7a35f6' : '#cccccc'"
class="icon_down"></u-icon>
</view>
2026-08-06 18:50:25 +08:00
</view>
</view>
</view>
<!-- 商品列表 -->
2026-08-17 09:27:07 +08:00
<scroll-view class="product_list_scroll" scroll-y @scrolltolower="onReachBottomGoods" :lower-threshold="50">
2026-08-06 18:50:25 +08:00
<view class="product_list_box" v-if="displayProducts && displayProducts.length > 0">
<view class="product_row_card" v-for="(item, index) in displayProducts" :key="item.id || index"
@click="jumpInfo(item)">
<view class="product_img_box">
2026-08-17 09:27:07 +08:00
<image class="product_img" :src="item.url || defaultProductImg" mode="aspectFill" lazy-load />
2026-08-06 18:50:25 +08:00
</view>
<view class="product_info_box">
<view class="product_title">{{ item.name || item.title }}</view>
2026-08-25 15:36:16 +08:00
<view class="product_tags_row"
v-if="item.sellingPoint && getSellingPointTags(item.sellingPoint).length > 0">
<text class="tag_item tag_green" v-for="(tag, tIndex) in getSellingPointTags(item.sellingPoint)"
:key="tIndex">{{ tag }}</text>
2026-08-06 18:50:25 +08:00
</view>
<view class="product_price_row">
<view class="price_box">
<text class="price_symbol">¥</text>
<text class="price_val">{{ item.price }}</text>
</view>
<text class="sales_val">全网销量{{ limit999(item.sales) }}</text>
</view>
</view>
</view>
2026-08-17 09:27:07 +08:00
<!-- 加载更多与无数据状态提示 -->
<view class="load_more_tips" v-if="loadingMore">加载中...</view>
<view class="load_more_tips" v-else-if="noMore && displayProducts.length > 0">没有更多了</view>
2026-08-06 18:50:25 +08:00
</view>
2026-08-17 09:27:07 +08:00
<view class="empty_box" v-else-if="!loading">
2026-08-06 18:50:25 +08:00
<image src="https://static.tbmall.xin/static/not_shopping.png" class="empty_img" />
<text class="empty_text">暂无商品数据</text>
</view>
</scroll-view>
</view>
</view>
<!-- #ifndef H5 || MP-WEIXIN-->
<CustomTabBar :tabIndex="1" />
<!-- #endif -->
2026-08-17 11:32:40 +08:00
<qiaobao-assistant page-key="pages/sort/sort" title="商品分类" />
2026-08-06 18:50:25 +08:00
</view>
</template>
<script>
import { getCascadeCategory } from "@/api/common.js";
2026-08-17 09:27:07 +08:00
import { searchList } from "@/api/product.js";
2026-08-06 18:50:25 +08:00
import CustomTabBar from "@/components/custom-tab-bar.vue";
import TopSafe from "@/components/common/top-safe.nvue";
export default {
components: { CustomTabBar, TopSafe },
data() {
return {
platformType: true,
2026-08-17 09:27:07 +08:00
categoryList: [], // 一级分类列表 (parentId = 0)
currentCategoryIndex: 0, // 当前选中的一级分类索引
subCategoryList: [], // 二级分类列表 (parentId = 一级ID)
currentSubCategoryIndex: 0, // 当前选中的二级分类索引
displayProducts: [], // 三级商品列表 (goods/searchList)
2026-08-06 18:50:25 +08:00
showAllCategories: false,
2026-08-17 09:27:07 +08:00
sortBy: 'relevance', // 'relevance' | 'sales' | 'price'
sortOrder: 'asc', // 'asc' | 'desc'
2026-08-06 18:50:25 +08:00
capsuleTop: 0,
defaultIcon: 'https://static.tbmall.xin/static/new-home/xinren.png',
2026-08-17 09:27:07 +08:00
defaultProductImg: 'https://static.tbmall.xin/static/new-home/nangua.png',
isFromSortShop: false,
loading: false,
loadingMore: false,
noMore: false,
page: 1,
pageSize: 10
2026-08-06 18:50:25 +08:00
};
},
computed: {
mpHeaderStyle() {
/*#ifdef MP-WEIXIN*/
if (this.capsuleTop) {
return { paddingTop: this.capsuleTop + 'px' };
}
return { paddingTop: '80rpx' };
/*#endif*/
return {};
},
currentCategory() {
return this.categoryList[this.currentCategoryIndex] || null;
},
2026-08-17 09:27:07 +08:00
currentSubCategory() {
return this.subCategoryList[this.currentSubCategoryIndex] || null;
2026-08-06 18:50:25 +08:00
}
},
onShow() {
/*#ifdef APP-PLUS*/
uni.hideTabBar({ animation: false });
const appUpdate = uni.getStorageSync("platform");
this.platformType = appUpdate == "android" ? "ANDROID" : "IOS";
/*#endif*/
/*#ifdef MP-WEIXIN*/
try {
const menu = uni.getMenuButtonBoundingClientRect();
if (menu && menu.bottom) {
this.capsuleTop = menu.bottom + 6;
}
2026-08-17 09:27:07 +08:00
} catch (e) { }
2026-08-06 18:50:25 +08:00
/*#endif*/
2026-08-17 09:27:07 +08:00
const isBackFromSortShop = this.isFromSortShop;
this.isFromSortShop = false;
this.fetchCategories(isBackFromSortShop);
2026-08-06 18:50:25 +08:00
},
methods: {
2026-08-20 17:31:00 +08:00
getSellingPointTags(sellingPoint) {
if (!sellingPoint || typeof sellingPoint !== 'string') return [];
return sellingPoint
.split(/[,,]/)
.map(t => t.trim())
.filter(Boolean);
},
2026-08-17 09:27:07 +08:00
// 异步查询级联分类接口 (common/getCascadeCategory)
async getCategoryApi(pId) {
2026-08-06 18:50:25 +08:00
try {
2026-08-17 09:27:07 +08:00
const resp = await getCascadeCategory({ parentId: pId });
if (resp && resp.bizcode === 100 && Array.isArray(resp.data)) {
return resp.data;
2026-08-06 18:50:25 +08:00
}
} catch (e) {
2026-08-17 09:27:07 +08:00
console.error("getCascadeCategory error:", e);
2026-08-06 18:50:25 +08:00
}
2026-08-17 09:27:07 +08:00
return [];
2026-08-06 18:50:25 +08:00
},
2026-08-17 09:27:07 +08:00
// 1. 刚进来获取一级分类 (parentId = 0)
async fetchCategories(isBack = false) {
try {
const topList = await this.getCategoryApi(0);
this.categoryList = topList || [];
} catch (e) {
console.error("获取一级分类失败:", e);
this.categoryList = [];
}
if (this.categoryList.length === 0) {
this.subCategoryList = [];
this.displayProducts = [];
return;
}
let targetIndex = 0;
if (isBack) {
const sortId = uni.getStorageSync("sortId");
if (sortId) {
let idx = this.categoryList.findIndex(item => item.id === sortId);
if (idx !== -1) targetIndex = idx;
else if (this.currentCategoryIndex >= 0 && this.currentCategoryIndex < this.categoryList.length) {
targetIndex = this.currentCategoryIndex;
}
}
} else {
uni.removeStorageSync("sortId");
uni.removeStorageSync("subSortId");
targetIndex = 0;
}
this.selectCategory(targetIndex, false, isBack);
},
// 2. 选择一级分类,根据其 id 获取二级分类 (parentId = 该一级id)
async selectCategory(index, closePopup = false, isBack = false) {
2026-08-06 18:50:25 +08:00
this.currentCategoryIndex = index;
if (closePopup) {
this.showAllCategories = false;
}
2026-08-17 09:27:07 +08:00
const category = this.categoryList[index];
if (!category || !category.id) {
this.subCategoryList = [];
this.displayProducts = [];
return;
}
uni.setStorageSync("sortId", category.id);
this.loading = true;
try {
const subList = await this.getCategoryApi(category.id);
this.subCategoryList = subList || [];
if (this.subCategoryList.length === 0) {
this.displayProducts = [];
this.loading = false;
return;
}
let targetSubIndex = 0;
if (isBack) {
const subSortId = uni.getStorageSync("subSortId");
if (subSortId) {
let sIdx = this.subCategoryList.findIndex(item => item.id === subSortId);
if (sIdx !== -1) targetSubIndex = sIdx;
}
}
this.selectSubCategory(targetSubIndex);
} catch (e) {
console.error("获取二级分类失败:", e);
this.subCategoryList = [];
this.displayProducts = [];
this.loading = false;
}
2026-08-06 18:50:25 +08:00
},
2026-08-17 09:27:07 +08:00
// 3. 选择二级分类,更新当前二级分类并调用 goods/searchList 获取商品列表
selectSubCategory(subIndex) {
this.currentSubCategoryIndex = subIndex;
const subCat = this.subCategoryList[subIndex];
if (subCat && subCat.id) {
uni.setStorageSync("subSortId", subCat.id);
}
this.fetchGoodsList(false);
},
// 4. 调用 /goods/searchList 接口获取商品列表 (支持分页与排序)
async fetchGoodsList(isLoadMore = false) {
const currentSubCat = this.subCategoryList[this.currentSubCategoryIndex];
if (!currentSubCat || !currentSubCat.id) {
this.displayProducts = [];
this.loading = false;
this.loadingMore = false;
return;
}
if (isLoadMore) {
if (this.loadingMore || this.noMore) return;
this.loadingMore = true;
this.page++;
} else {
this.loading = true;
this.page = 1;
this.noMore = false;
}
const params = {
categoryId: currentSubCat.id,
page: this.page,
pageSize: this.pageSize,
sortBy: this.sortBy,
sortOrder: this.sortOrder
};
try {
const resp = await searchList(params);
if (resp && resp.bizcode === 100) {
let list = [];
if (Array.isArray(resp.data)) {
list = resp.data;
} else if (resp.data && Array.isArray(resp.data.entitys)) {
list = resp.data.entitys;
} else if (resp.data && Array.isArray(resp.data.list)) {
list = resp.data.list;
}
if (isLoadMore) {
this.displayProducts = [...this.displayProducts, ...list];
} else {
this.displayProducts = list;
}
if (list.length < this.pageSize) {
this.noMore = true;
}
} else {
if (!isLoadMore) {
this.displayProducts = [];
}
this.noMore = true;
}
} catch (e) {
console.error("searchList error:", e);
if (!isLoadMore) {
this.displayProducts = [];
}
} finally {
this.loading = false;
this.loadingMore = false;
}
},
// 5. 右侧商品列表触底触发分页加载
onReachBottomGoods() {
if (!this.noMore && !this.loadingMore && !this.loading) {
this.fetchGoodsList(true);
}
},
2026-08-06 18:50:25 +08:00
toggleAllCategories() {
this.showAllCategories = !this.showAllCategories;
},
2026-08-17 09:27:07 +08:00
// 6. 排序作用于 goods/searchList 接口
2026-08-06 18:50:25 +08:00
setSort(type) {
2026-08-17 09:27:07 +08:00
if (this.sortBy === type) {
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
2026-08-06 18:50:25 +08:00
} else {
2026-08-17 09:27:07 +08:00
this.sortBy = type;
this.sortOrder = 'asc';
2026-08-06 18:50:25 +08:00
}
2026-08-17 09:27:07 +08:00
this.fetchGoodsList(false);
2026-08-06 18:50:25 +08:00
},
2026-08-17 09:27:07 +08:00
2026-08-06 18:50:25 +08:00
limit999(n) {
const num = Number(n);
if (isNaN(num) || num < 10000) {
return n != null && n !== '' ? String(n) : '0';
}
return `${Math.floor(num / 10000)}万+`;
},
2026-08-17 09:27:07 +08:00
2026-08-06 18:50:25 +08:00
jumpSearch() {
uni.navigateTo({
url: "/pages/rwa_package/insights/search",
});
},
2026-08-17 09:27:07 +08:00
2026-08-06 18:50:25 +08:00
jumpInfo(item) {
2026-08-17 09:27:07 +08:00
this.isFromSortShop = true;
2026-08-06 18:50:25 +08:00
uni.navigateTo({
2026-08-20 17:31:00 +08:00
url: '/pages/other_package/productInfo/productInfo?id=' + item.id,
})
2026-08-06 18:50:25 +08:00
}
}
};
</script>
<style lang="scss" scoped>
page {
height: 100%;
overflow: hidden;
}
.sort_warp {
height: 100vh;
/* #ifdef H5 */
height: calc(100vh - var(--window-top, 0px) - var(--window-bottom, 0px));
/* #endif */
display: flex;
flex-direction: column;
overflow: hidden;
box-sizing: border-box;
background-color: #ffffff;
position: relative;
}
/* 顶部固定区域 */
.top_fixed_header {
position: relative;
z-index: 100;
2026-08-17 09:27:07 +08:00
background: linear-gradient(180deg, #F2EBFF 0%, #FFFFFF 100%);
border-bottom-left-radius: 36rpx;
border-bottom-right-radius: 36rpx;
overflow: hidden;
2026-08-06 18:50:25 +08:00
flex-shrink: 0;
2026-08-17 09:27:07 +08:00
box-shadow: none;
2026-08-06 18:50:25 +08:00
transition: all 0.2s;
&.is_expanded {
background: linear-gradient(180deg, #F2EBFF 0%, #FFFFFF 100%, #FFFFFF 100%) !important;
border-bottom-left-radius: 36rpx !important;
border-bottom-right-radius: 36rpx !important;
box-shadow: 0 12rpx 32rpx rgba(122, 53, 246, 0.12) !important;
overflow: hidden !important;
}
}
/* 搜索框 */
.search_bar {
margin: 16rpx 24rpx 12rpx;
height: 72rpx;
background-color: #ffffff;
border-radius: 36rpx;
padding: 0 28rpx;
display: flex;
align-items: center;
.search_placeholder {
font-size: 28rpx;
color: #999999;
margin-left: 12rpx;
}
}
/* 顶部分类横划栏 */
.top_category_row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10rpx 0 16rpx 20rpx;
.top_category_scroll {
flex: 1;
overflow-x: auto;
white-space: nowrap;
min-width: 0;
}
.top_cat_list {
display: inline-flex;
align-items: flex-start;
}
.expand_all_btn {
width: 90rpx;
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 22rpx;
color: #666666;
padding: 0 12rpx;
.expand_text {
font-size: 22rpx;
color: #666666;
margin-bottom: 4rpx;
}
}
}
/* 分类 Icon 与 Badge 通用样式(同时作用于横滑栏与展开网格) */
.top_cat_item {
display: inline-flex;
flex-direction: column;
align-items: center;
margin-right: 32rpx;
box-sizing: border-box;
&.panel_cat_item {
width: 20% !important;
max-width: 20% !important;
margin-right: 0 !important;
margin-bottom: 24rpx !important;
}
.top_cat_img_box {
width: 96rpx !important;
height: 96rpx !important;
min-width: 96rpx !important;
max-width: 96rpx !important;
min-height: 96rpx !important;
max-height: 96rpx !important;
border-radius: 50% !important;
overflow: hidden !important;
background: #f7f7f7;
display: flex !important;
align-items: center !important;
justify-content: center !important;
box-sizing: border-box !important;
border: 4rpx solid transparent;
transition: all 0.2s;
flex-shrink: 0 !important;
&.active_img {
border-color: #7a35f6 !important;
}
}
.top_cat_img {
width: 88rpx !important;
height: 88rpx !important;
min-width: 88rpx !important;
max-width: 88rpx !important;
min-height: 88rpx !important;
max-height: 88rpx !important;
border-radius: 50% !important;
display: block !important;
flex-shrink: 0 !important;
}
.top_cat_name_badge {
font-size: 22rpx !important;
color: #666666 !important;
margin-top: 10rpx !important;
padding: 2rpx 12rpx !important;
border-radius: 16rpx !important;
line-height: 32rpx !important;
white-space: nowrap !important;
transition: all 0.2s;
&.active_badge {
background-color: #7a35f6 !important;
color: #ffffff !important;
font-weight: bold !important;
}
}
}
/* 点开全部时的网格面板 */
.all_categories_panel {
background: transparent;
padding: 16rpx 24rpx 0;
border-bottom-left-radius: 36rpx !important;
border-bottom-right-radius: 36rpx !important;
overflow: hidden !important;
.panel_header {
margin-bottom: 20rpx;
padding-left: 8rpx;
.panel_title {
font-size: 30rpx;
font-weight: bold;
color: #1a1a1a;
}
}
.panel_grid_scroll {
max-height: 55vh;
overflow-y: auto;
}
.panel_grid {
display: flex !important;
flex-wrap: wrap !important;
width: 100% !important;
}
.collapse_btn {
display: flex !important;
align-items: center !important;
justify-content: center !important;
font-size: 24rpx !important;
color: #666666 !important;
height: 80rpx !important;
background-color: #ffffff !important;
border-top: 1rpx solid #eeeeee !important;
margin-top: 16rpx !important;
margin-left: -24rpx !important;
margin-right: -24rpx !important;
border-bottom-left-radius: 36rpx !important;
border-bottom-right-radius: 36rpx !important;
overflow: hidden !important;
}
}
/* 主内容区 */
.main_container {
position: relative;
flex: 1;
display: flex;
flex-direction: row;
min-height: 0;
width: 100%;
background-color: #f7f7f7;
overflow: hidden;
/* 展开所有分类时的半透明遮罩 */
.mask_overlay {
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: 100vw !important;
height: 100vh !important;
background-color: rgba(0, 0, 0, 0.45) !important;
z-index: 90 !important;
}
}
/* 左侧边栏 */
.left_sidebar_scroll {
2026-08-25 15:36:16 +08:00
width: 160rpx;
2026-08-06 18:50:25 +08:00
height: 100%;
flex-shrink: 0;
background-color: #f7f7f7;
overflow-y: auto;
/* #ifdef APP-PLUS */
padding-bottom: calc(110rpx + env(safe-area-inset-bottom));
/* #endif */
.sidebar_item {
height: 104rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #555555;
padding: 0 12rpx;
text-align: center;
position: relative;
box-sizing: border-box;
&.active {
background-color: #ffffff;
color: #7a35f6;
font-weight: bold;
font-size: 28rpx;
&::before {
content: "";
position: absolute;
left: 0;
top: 34rpx;
width: 6rpx;
height: 36rpx;
background-color: #7a35f6;
border-radius: 0 4rpx 4rpx 0;
}
}
}
}
/* 右侧内容区域 */
.right_content_area {
flex: 1;
height: 100%;
display: flex;
flex-direction: column;
background-color: #ffffff;
min-width: 0;
}
/* 右侧排序栏 */
.sort_option_bar {
height: 80rpx;
padding: 0 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
2026-08-17 09:27:07 +08:00
border-bottom: none;
2026-08-06 18:50:25 +08:00
flex-shrink: 0;
.cat_title_text {
font-size: 30rpx;
font-weight: bold;
color: #7a35f6;
}
.sort_actions {
display: flex;
align-items: center;
gap: 32rpx;
.sort_item {
font-size: 26rpx;
color: #999999;
display: flex;
align-items: center;
2026-08-17 09:27:07 +08:00
cursor: pointer;
2026-08-06 18:50:25 +08:00
&.active {
color: #7a35f6;
font-weight: bold;
}
2026-08-17 09:27:07 +08:00
.sort_icon_box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-left: 6rpx;
line-height: 1;
.icon_up {
margin-bottom: 2rpx;
}
2026-08-06 18:50:25 +08:00
}
}
}
}
/* 商品列表 */
.product_list_scroll {
flex: 1;
height: 100%;
overflow-y: auto;
/* #ifdef APP-PLUS */
padding-bottom: calc(110rpx + env(safe-area-inset-bottom));
/* #endif */
.product_list_box {
padding: 0 24rpx;
}
.product_row_card {
display: flex;
flex-direction: row;
padding: 24rpx 0;
border-bottom: 1rpx solid #f7f7f7;
background: #ffffff;
.product_img_box {
width: 200rpx;
height: 200rpx;
border-radius: 16rpx;
overflow: hidden;
flex-shrink: 0;
margin-right: 20rpx;
background: #f9f9f9;
.product_img {
width: 100%;
height: 100%;
}
}
.product_info_box {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
min-width: 0;
.product_title {
font-size: 28rpx;
color: #1a1a1a;
line-height: 38rpx;
max-height: 76rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-break: break-all;
}
.product_tags_row {
display: flex;
2026-08-20 17:31:00 +08:00
flex-wrap: wrap;
2026-08-06 18:50:25 +08:00
gap: 12rpx;
margin-top: 8rpx;
.tag_item {
font-size: 20rpx;
padding: 2rpx 10rpx;
border-radius: 6rpx;
white-space: nowrap;
&.tag_blue {
color: #2979ff;
border: 1rpx solid #2979ff;
background-color: rgba(41, 121, 255, 0.05);
}
&.tag_green {
color: #19be6b;
border: 1rpx solid #19be6b;
background-color: rgba(25, 190, 107, 0.05);
}
}
}
.product_price_row {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-top: 12rpx;
.price_box {
color: #ff2a2a;
font-weight: bold;
.price_symbol {
font-size: 24rpx;
}
.price_val {
2026-08-25 15:36:16 +08:00
font-size: 36rpx;
font-weight: normal;
2026-08-06 18:50:25 +08:00
}
}
.sales_val {
font-size: 24rpx;
color: #999999;
}
}
}
}
.empty_box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 120rpx;
.empty_img {
width: 160rpx;
height: 160rpx;
}
.empty_text {
font-size: 26rpx;
color: #999999;
margin-top: 20rpx;
}
}
2026-08-17 09:27:07 +08:00
.load_more_tips {
text-align: center;
font-size: 24rpx;
color: #999999;
padding: 24rpx 0;
}
2026-08-06 18:50:25 +08:00
}
</style>