Files
frontend-app/pages/sort/sort copy 2.vue
T
2026-08-17 09:27:07 +08:00

1013 lines
28 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="sort_warp" :class="platformType ? '' : 'iosplatformType'">
<!-- #ifndef MP-WEIXIN -->
<TopSafe bgColor="#F2EBFF"></TopSafe>
<!-- #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>
<view class="sidebar_item" v-for="(item, index) in categoryList" :key="item.id || index"
:class="{ active: currentCategoryIndex === index }" @click="selectCategory(index)">
<text class="sidebar_name">{{ item.name }}</text>
</view>
</scroll-view>
<!-- 右侧商品列表区 -->
<view class="right_content_area">
<!-- 排序栏 -->
<view class="sort_option_bar">
<view class="cat_title_text">{{ currentCategory ? currentCategory.name : '' }}</view>
<view class="sort_actions">
<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>
</view>
<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>
</view>
<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>
</view>
</view>
</view>
<!-- 商品列表 -->
<scroll-view class="product_list_scroll" scroll-y>
<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">
<image class="product_img" :src="item.image || item.icon || defaultProductImg" mode="aspectFill"
lazy-load />
</view>
<view class="product_info_box">
<view class="product_title">{{ item.name || item.title }}</view>
<view class="product_tags_row">
<text class="tag_item tag_blue" v-if="item.tags && item.tags[0]">{{ item.tags[0] }}</text>
<text class="tag_item tag_green" v-if="item.tags && item.tags[1]">{{ item.tags[1] }}</text>
<text class="tag_item tag_blue" v-if="!item.tags">专业检测</text>
<text class="tag_item tag_green" v-if="!item.tags">生态有机</text>
</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>
</view>
<view class="empty_box" v-else>
<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 -->
</view>
</template>
<script>
import { getCascadeCategory } from "@/api/common.js";
import CustomTabBar from "@/components/custom-tab-bar.vue";
import TopSafe from "@/components/common/top-safe.nvue";
// 假数据列表:当后端接口未就绪时自动提供高保真模拟数据
const MOCK_CATEGORIES = [
{
id: 101,
name: '有机食品',
icon: 'https://static.tbmall.xin/static/new-home/xinren.png',
foods: [
{
id: 1001,
name: '鲜8有机贝贝南瓜2500g粉糯板栗味自然生长不催熟',
title: '鲜8有机贝贝南瓜2500g粉糯板栗味自然生长不催熟',
price: '39.00',
sales: 888,
tags: ['专业检测', '生态有机'],
image: 'https://static.tbmall.xin/static/new-home/nangua.png'
},
{
id: 1002,
name: '采缇国产车厘子5kg4j大连美早樱桃生鲜次日达樱桃',
title: '采缇国产车厘子5kg4j大连美早樱桃生鲜次日达樱桃',
price: '26.99',
sales: 888,
tags: ['专业检测', '生态有机'],
image: 'https://static.tbmall.xin/static/new-home/baokuan.png'
},
{
id: 1003,
name: '江苏白凤水蜜桃 应季水果 &新鲜礼盒装',
title: '江苏白凤水蜜桃 应季水果 &新鲜礼盒装',
price: '34.88',
sales: 888,
tags: ['专业检测', '生态有机'],
image: 'https://static.tbmall.xin/static/new-home/cart.png'
},
{
id: 1004,
name: '季新鲜 &进口山竹时令 &老树麻竹整箱送礼',
title: '季新鲜 &进口山竹时令 &老树麻竹整箱送礼',
price: '52.00',
sales: 888,
tags: ['专业检测', '生态有机'],
image: 'https://static.tbmall.xin/static/new-home/huiyuan.png'
}
]
},
{
id: 102,
name: '生鲜食材',
icon: 'https://static.tbmall.xin/static/new-home/baokuan.png',
foods: [
{
id: 1005,
name: '精选新鲜三文鱼中段切片 200g刺身级',
title: '精选新鲜三文鱼中段切片 200g刺身级',
price: '59.90',
sales: 1200,
tags: ['冷链速达', '产地直供'],
image: 'https://static.tbmall.xin/static/new-home/baokuan.png'
},
{
id: 1006,
name: '澳洲进口谷饲安格斯原切雪花牛肉卷 500g',
title: '澳洲进口谷饲安格斯原切雪花牛肉卷 500g',
price: '89.00',
sales: 650,
tags: ['原切牛肉', '品质严选'],
image: 'https://static.tbmall.xin/static/new-home/cart.png'
}
]
},
{
id: 103,
name: '米面粮油',
icon: 'https://static.tbmall.xin/static/new-home/cart.png',
foods: [
{
id: 1007,
name: '五常大米 优质长粒香米 5kg真空包装',
title: '五常大米 优质长粒香米 5kg真空包装',
price: '49.90',
sales: 3400,
tags: ['核心产区', '自然醇香'],
image: 'https://static.tbmall.xin/static/new-home/xinren.png'
}
]
},
{
id: 104,
name: '零食饮料',
icon: 'https://static.tbmall.xin/static/new-home/huiyuan.png',
foods: [
{
id: 1008,
name: '花生造黑松露黑麦苏打饼干 590g*2盒',
title: '花生造黑松露黑麦苏打饼干 590g*2盒',
price: '29.90',
sales: 2300,
tags: ['零反式脂肪酸', '拒绝油炸'],
image: 'https://static.tbmall.xin/static/new-home/huiyuan.png'
}
]
},
{
id: 105,
name: '滋补养生',
icon: 'https://static.tbmall.xin/static/new-home/xinren.png',
foods: [
{
id: 1009,
name: '青海野生黑枸杞干果 250g特级罐装',
title: '青海野生黑枸杞干果 250g特级罐装',
price: '78.00',
sales: 510,
tags: ['正宗原产', '花青素丰富'],
image: 'https://static.tbmall.xin/static/new-home/nangua.png'
}
]
},
{
id: 106,
name: '非遗传承',
icon: 'https://static.tbmall.xin/static/new-home/baokuan.png',
foods: []
},
{
id: 107,
name: '家居百货',
icon: 'https://static.tbmall.xin/static/new-home/cart.png',
foods: []
},
{
id: 108,
name: '美妆护肤',
icon: 'https://static.tbmall.xin/static/new-home/huiyuan.png',
foods: []
},
{
id: 109,
name: '其他特色',
icon: 'https://static.tbmall.xin/static/new-home/xinren.png',
foods: []
}
];
export default {
components: { CustomTabBar, TopSafe },
data() {
return {
platformType: true,
currentCategoryIndex: 0,
showAllCategories: false,
sortBy: 'relevance', // 'relevance' | 'sales' | 'price'
sortOrder: 'asc', // 'asc' | 'desc'
categoryList: [], // 对应 sort copy.vue 的 tabbarList (顶层主分类)
capsuleTop: 0,
defaultIcon: 'https://static.tbmall.xin/static/new-home/xinren.png',
defaultProductImg: 'https://static.tbmall.xin/static/new-home/nangua.png',
isFromSortShop: false,
loading: false
};
},
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;
},
displayProducts() {
if (!this.currentCategory) return [];
let list = [];
if (this.currentCategory.foods && this.currentCategory.foods.length > 0) {
list = [...this.currentCategory.foods];
} else if (this.currentCategory.productList && this.currentCategory.productList.length > 0) {
list = [...this.currentCategory.productList];
}
if (!list || list.length === 0) return [];
if (this.sortBy === 'sales') {
list.sort((a, b) => {
let salesA = Number(a.sales) || 0;
let salesB = Number(b.sales) || 0;
return this.sortOrder === 'asc' ? salesA - salesB : salesB - salesA;
});
} else if (this.sortBy === 'price') {
list.sort((a, b) => {
let priceA = Number(a.price || a.adPrice) || 0;
let priceB = Number(b.price || b.adPrice) || 0;
return this.sortOrder === 'asc' ? priceA - priceB : priceB - priceA;
});
} else if (this.sortBy === 'relevance') {
if (this.sortOrder === 'desc') {
list.reverse();
}
}
return list;
}
},
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;
}
} catch (e) {}
/*#endif*/
const isBackFromSortShop = this.isFromSortShop;
this.isFromSortShop = false;
this.fetchCategories(isBackFromSortShop);
},
methods: {
// 异步查询分类接口
async getSortApi(pId) {
const params = {
parentId: pId,
sortBy: this.sortBy,
sortOrder: this.sortOrder
};
try {
const resp = await getCascadeCategory(params);
if (resp && resp.bizcode === 100 && resp.data) {
return resp.data;
}
} catch (e) {
console.error("getCascadeCategory error:", e);
}
return [];
},
// 1. 初始化/获取顶层主分类列表(对应 tabbarList)
async fetchCategories(isBack = false) {
try {
const topList = await this.getSortApi(0);
if (topList && topList.length > 0) {
this.categoryList = topList;
} else {
this.categoryList = MOCK_CATEGORIES;
}
} catch (e) {
console.log("使用模拟分类数据", e);
this.categoryList = MOCK_CATEGORIES;
}
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");
targetIndex = 0;
}
this.selectCategory(targetIndex);
},
// 2. 选中某个顶层分类并加载右侧货品数据(对应 tabbarContentList 结构)
async selectCategory(index, closePopup = false) {
this.currentCategoryIndex = index;
if (closePopup) {
this.showAllCategories = false;
}
const item = this.categoryList[index];
if (!item) return;
if (item.id) {
uni.setStorageSync("sortId", item.id);
}
// 如果为 mock 数据且已包含 foods 列表,直接渲染
if (!item.id || typeof item.id !== 'number' || (item.foods && item.foods.length > 0 && !item._fromApi)) {
return;
}
this.loading = true;
try {
// 参考 sort copy.vue: 依次查询二级分类 (firstData) 及三级货品 (twoData)
const firstData = await this.getSortApi(item.id);
let allProducts = [];
if (firstData && firstData.length > 0) {
for (let fItem of firstData) {
const twoData = await this.getSortApi(fItem.id);
fItem.foods = twoData || [];
if (fItem.foods && fItem.foods.length > 0) {
allProducts.push(...fItem.foods);
} else {
allProducts.push(fItem);
}
}
this.$set(this.categoryList[index], 'tabbarContentList', firstData);
this.$set(this.categoryList[index], 'foods', allProducts);
this.$set(this.categoryList[index], '_fromApi', true);
}
} catch (err) {
console.error("加载右侧货品数据失败:", err);
} finally {
this.loading = false;
}
},
toggleAllCategories() {
this.showAllCategories = !this.showAllCategories;
},
setSort(type) {
if (type === 'relevance') {
if (this.sortBy === 'relevance') {
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
} else {
this.sortBy = 'relevance';
this.sortOrder = 'asc';
}
} else if (type === 'sales') {
if (this.sortBy === 'sales') {
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
} else {
this.sortBy = 'sales';
this.sortOrder = 'asc';
}
} else if (type === 'price') {
if (this.sortBy === 'price') {
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
} else {
this.sortBy = 'price';
this.sortOrder = 'asc';
}
}
if (this.currentCategory) {
this.$set(this.categoryList[this.currentCategoryIndex], '_fromApi', false);
}
this.selectCategory(this.currentCategoryIndex);
},
limit999(n) {
const num = Number(n);
if (isNaN(num) || num < 10000) {
return n != null && n !== '' ? String(n) : '0';
}
return `${Math.floor(num / 10000)}万+`;
},
jumpSearch() {
uni.navigateTo({
url: "/pages/rwa_package/insights/search",
});
},
jumpInfo(item) {
this.isFromSortShop = true;
uni.navigateTo({
url: `/pages/rwa_package/shop/sort-shop?id=${item.id}&name=${encodeURIComponent(item.name || item.title || '')}`,
});
}
}
};
</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;
background: linear-gradient(180deg, #F2EBFF 0%, #FFFFFF 100%);
border-bottom-left-radius: 36rpx;
border-bottom-right-radius: 36rpx;
overflow: hidden;
flex-shrink: 0;
box-shadow: none;
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 {
width: 180rpx;
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;
border-bottom: none;
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;
cursor: pointer;
&.active {
color: #7a35f6;
font-weight: bold;
}
.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;
}
}
}
}
}
/* 商品列表 */
.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;
font-weight: bold;
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;
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 {
font-size: 38rpx;
}
}
.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;
}
}
}
</style>