|
|
@@ -1,3 +1,194 @@
|
|
|
+<template>
|
|
|
+ <!-- 购物车条勿放在 inquiry-page 内:父级 overflow:hidden 会裁切角标;且 bottom 须与 tabBar 对齐 -->
|
|
|
+ <view class="home-root client-theme">
|
|
|
+ <view class="inquiry-page">
|
|
|
+ <view v-if="isLoading" class="state">
|
|
|
+ <ClientSkeleton variant="hero-list" :rows="3" />
|
|
|
+ </view>
|
|
|
+ <view v-else class="content-wrap">
|
|
|
+ <!-- 顶栏:仅渐变背景 + 配送行 + 搜索条(与 sanqiang-client-ui-demo.html .top 一致) -->
|
|
|
+ <view class="filter-top-wrap">
|
|
|
+ <view class="top-row">
|
|
|
+ <text class="top-row-left">{{ deliveryLineLeft }}</text>
|
|
|
+ <text class="top-row-brand">叁强鲜配</text>
|
|
|
+ </view>
|
|
|
+ <view class="search-bar">
|
|
|
+ <input
|
|
|
+ v-model="keyword"
|
|
|
+ class="search-input"
|
|
|
+ type="text"
|
|
|
+ placeholder="搜索商品、品牌、一级/二级分类"
|
|
|
+ placeholder-class="search-placeholder"
|
|
|
+ confirm-type="search"
|
|
|
+ @confirm="onSearchClick"
|
|
|
+ />
|
|
|
+ <view v-if="keyword" class="search-clear" @click.stop="keyword = ''">×</view>
|
|
|
+ <text class="search-action" @click="onSearchClick">搜索</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 一级分类及以下在灰底区域,独立白卡片(与 demo .section + .first-level 一致) -->
|
|
|
+ <view class="category-section">
|
|
|
+ <view class="section-head">
|
|
|
+ <text class="section-title">商品分类</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="first-category-wrap">
|
|
|
+ <swiper
|
|
|
+ class="first-category-swiper"
|
|
|
+ :current="firstCategorySwiperIndex"
|
|
|
+ :circular="false"
|
|
|
+ :indicator-dots="false"
|
|
|
+ @change="onFirstCategorySwiperChange"
|
|
|
+ >
|
|
|
+ <swiper-item v-for="(page, pageIdx) in firstCategoryPages" :key="`category-page-${pageIdx}`">
|
|
|
+ <view class="first-category-grid">
|
|
|
+ <view
|
|
|
+ v-for="cat in page"
|
|
|
+ :key="cat.id"
|
|
|
+ class="first-category-card"
|
|
|
+ :class="{ active: selectedFirstCategoryId === cat.id }"
|
|
|
+ hover-class="first-category-card--hover"
|
|
|
+ :hover-stay-time="120"
|
|
|
+ @click="handleFirstCategoryClick(cat.id)"
|
|
|
+ >
|
|
|
+ <ClientImageLoader
|
|
|
+ class="first-category-image"
|
|
|
+ :src="cat.imageUrl || DEFAULT_PLACEHOLDER_IMAGE_URL"
|
|
|
+ mode="aspectFill"
|
|
|
+ radius="24rpx"
|
|
|
+ />
|
|
|
+ <text class="first-category-name">{{ cat.name }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </swiper-item>
|
|
|
+ </swiper>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-if="firstCategoryPages.length > 0" class="first-level-indicator">
|
|
|
+ <view
|
|
|
+ v-for="(_, idx) in firstCategoryPages"
|
|
|
+ :key="`dot-${idx}`"
|
|
|
+ class="indicator-dot"
|
|
|
+ :class="{ active: firstCategorySwiperIndex === idx }"
|
|
|
+ @click="goFirstCategorySwiperPage(idx)"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="product-layout">
|
|
|
+ <view class="product-body">
|
|
|
+ <scroll-view
|
|
|
+ scroll-y
|
|
|
+ class="category-pane"
|
|
|
+ :show-scrollbar="true"
|
|
|
+ :lower-threshold="60"
|
|
|
+ @scrolltolower="onCategoryScrollToLower"
|
|
|
+ >
|
|
|
+ <view class="category-scroll-inner">
|
|
|
+ <view
|
|
|
+ v-for="cat in displaySidebarRows"
|
|
|
+ :key="cat.id"
|
|
|
+ class="category-item"
|
|
|
+ :class="{ active: selectedSecondCategoryId === cat.id }"
|
|
|
+ hover-class="category-item--hover"
|
|
|
+ :hover-stay-time="120"
|
|
|
+ @click="selectedSecondCategoryId = cat.id"
|
|
|
+ >
|
|
|
+ {{ cat.name }}
|
|
|
+ </view>
|
|
|
+ <view v-if="sidebarLoading && sidebarRows.length === 0" class="pane-footer-tip">加载中...</view>
|
|
|
+ <view v-else-if="sidebarHasMore" class="pane-footer-tip">上拉加载更多分类</view>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+
|
|
|
+ <view class="goods-pane">
|
|
|
+ <scroll-view
|
|
|
+ scroll-y
|
|
|
+ class="goods-scroll"
|
|
|
+ :show-scrollbar="true"
|
|
|
+ :lower-threshold="80"
|
|
|
+ @scrolltolower="onGoodsScrollToLower"
|
|
|
+ >
|
|
|
+ <view class="goods-scroll-inner">
|
|
|
+ <view
|
|
|
+ v-for="product in products"
|
|
|
+ :key="product.id"
|
|
|
+ class="goods-card"
|
|
|
+ hover-class="goods-card--pressed"
|
|
|
+ :hover-stay-time="120"
|
|
|
+ @click="goProductView(product.id)"
|
|
|
+ >
|
|
|
+ <ClientImageLoader
|
|
|
+ class="goods-image"
|
|
|
+ :src="product.imageUrl || IMG_DEFAULT_PRODUCT"
|
|
|
+ mode="aspectFill"
|
|
|
+ radius="16rpx"
|
|
|
+ />
|
|
|
+ <view class="goods-main">
|
|
|
+ <text class="goods-name">{{ product.name || '-' }}</text>
|
|
|
+ <text class="goods-spec">{{ formatMeasureText(product.measureValue, product.unitName) }}</text>
|
|
|
+ <view class="bottom-row">
|
|
|
+ <text class="goods-price">¥{{ formatPrice(product.price || 0) }}</text>
|
|
|
+ <view class="bottom-row-actions">
|
|
|
+ <view v-if="getCartQuantity(product.id) === 0" class="add-btn" @click.stop="addToCart(product)">
|
|
|
+ <text class="add-btn-plus">+</text>
|
|
|
+ </view>
|
|
|
+ <view v-else class="quantity-control" @click.stop>
|
|
|
+ <view class="qty-btn" @click.stop="updateQuantity(product.id, -1)">
|
|
|
+ <text>-</text>
|
|
|
+ </view>
|
|
|
+ <text class="qty-num">{{ getCartQuantity(product.id) }}</text>
|
|
|
+ <view class="qty-btn" @click.stop="updateQuantity(product.id, 1)">
|
|
|
+ <text>+</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-if="products.length === 0 && !productsLoadingMore" class="empty-list-tip">暂无匹配商品</view>
|
|
|
+ <view v-if="productsLoadingMore" class="pane-footer-tip">加载中...</view>
|
|
|
+ <view v-else-if="products.length > 0 && !productHasMore" class="pane-footer-tip">没有更多了</view>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="cart-bar" @click="goToCart">
|
|
|
+ <view class="cart-inner">
|
|
|
+ <view class="cart-left">
|
|
|
+ <view class="cart-count">
|
|
|
+ <text>{{ cartStore.totalCount > 99 ? '99+' : cartStore.totalCount }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="cart-text-col">
|
|
|
+ <text class="cart-items-label">已选商品</text>
|
|
|
+ <text class="cart-total-money">¥{{ formatPrice(cartStore.totalAmount) }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="cart-settle">
|
|
|
+ <text>去结算</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <ProductDetailOverlay
|
|
|
+ :show="showProductOverlay"
|
|
|
+ :product-id="overlayProductId"
|
|
|
+ @close="closeProductOverlay"
|
|
|
+ />
|
|
|
+ <!-- #ifdef H5 -->
|
|
|
+ <ClientTabBar active="home" />
|
|
|
+ <!-- #endif -->
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
<script setup>
|
|
|
import { ref, computed, onMounted, watch } from 'vue'
|
|
|
import { onShow } from '@dcloudio/uni-app'
|
|
|
@@ -391,190 +582,7 @@ onShow(() => {
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
-<template>
|
|
|
- <!-- 购物车条勿放在 inquiry-page 内:父级 overflow:hidden 会裁切角标;且 bottom 须与 tabBar 对齐 -->
|
|
|
- <view class="home-root client-theme">
|
|
|
- <view class="inquiry-page">
|
|
|
- <view v-if="isLoading" class="state">
|
|
|
- <ClientSkeleton variant="hero-list" :rows="3" />
|
|
|
- </view>
|
|
|
- <view v-else class="content-wrap">
|
|
|
- <!-- 顶栏:仅渐变背景 + 配送行 + 搜索条(与 demo 一致) -->
|
|
|
- <view class="filter-top-wrap">
|
|
|
- <view class="top-row">
|
|
|
- <text class="top-row-left">{{ deliveryLineLeft }}</text>
|
|
|
- <text class="top-row-brand">叁强鲜配</text>
|
|
|
- </view>
|
|
|
- <view class="search-bar">
|
|
|
- <input
|
|
|
- v-model="keyword"
|
|
|
- class="search-input"
|
|
|
- type="text"
|
|
|
- placeholder="搜索商品、品牌、一级/二级分类"
|
|
|
- placeholder-class="search-placeholder"
|
|
|
- confirm-type="search"
|
|
|
- @confirm="onSearchClick"
|
|
|
- />
|
|
|
- <view v-if="keyword" class="search-clear" @click.stop="keyword = ''">×</view>
|
|
|
- <text class="search-action" @click="onSearchClick">搜索</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 一级分类及以下在灰底区域,独立白卡片(与 demo 一致) -->
|
|
|
- <view class="category-section">
|
|
|
- <view class="section-head">
|
|
|
- <text class="section-title">商品分类</text>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="first-category-wrap">
|
|
|
- <swiper
|
|
|
- class="first-category-swiper"
|
|
|
- :current="firstCategorySwiperIndex"
|
|
|
- :circular="false"
|
|
|
- :indicator-dots="false"
|
|
|
- @change="onFirstCategorySwiperChange"
|
|
|
- >
|
|
|
- <swiper-item v-for="(page, pageIdx) in firstCategoryPages" :key="`category-page-${pageIdx}`">
|
|
|
- <view class="first-category-grid">
|
|
|
- <view
|
|
|
- v-for="cat in page"
|
|
|
- :key="cat.id"
|
|
|
- class="first-category-card"
|
|
|
- :class="{ active: selectedFirstCategoryId === cat.id }"
|
|
|
- hover-class="first-category-card--hover"
|
|
|
- :hover-stay-time="120"
|
|
|
- @click="handleFirstCategoryClick(cat.id)"
|
|
|
- >
|
|
|
- <ClientImageLoader
|
|
|
- class="first-category-image"
|
|
|
- :src="cat.imageUrl || DEFAULT_PLACEHOLDER_IMAGE_URL"
|
|
|
- mode="aspectFill"
|
|
|
- radius="24rpx"
|
|
|
- />
|
|
|
- <text class="first-category-name">{{ cat.name }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </swiper-item>
|
|
|
- </swiper>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view v-if="firstCategoryPages.length > 0" class="first-level-indicator">
|
|
|
- <view
|
|
|
- v-for="(_, idx) in firstCategoryPages"
|
|
|
- :key="`dot-${idx}`"
|
|
|
- class="indicator-dot"
|
|
|
- :class="{ active: firstCategorySwiperIndex === idx }"
|
|
|
- @click="goFirstCategorySwiperPage(idx)"
|
|
|
- />
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="product-layout">
|
|
|
- <view class="product-body">
|
|
|
- <scroll-view
|
|
|
- scroll-y
|
|
|
- class="category-pane"
|
|
|
- :show-scrollbar="true"
|
|
|
- :lower-threshold="60"
|
|
|
- @scrolltolower="onCategoryScrollToLower"
|
|
|
- >
|
|
|
- <view class="category-scroll-inner">
|
|
|
- <view
|
|
|
- v-for="cat in displaySidebarRows"
|
|
|
- :key="cat.id"
|
|
|
- class="category-item"
|
|
|
- :class="{ active: selectedSecondCategoryId === cat.id }"
|
|
|
- hover-class="category-item--hover"
|
|
|
- :hover-stay-time="120"
|
|
|
- @click="selectedSecondCategoryId = cat.id"
|
|
|
- >
|
|
|
- {{ cat.name }}
|
|
|
- </view>
|
|
|
- <view v-if="sidebarLoading && sidebarRows.length === 0" class="pane-footer-tip">加载中...</view>
|
|
|
- <view v-else-if="sidebarHasMore" class="pane-footer-tip">上拉加载更多分类</view>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
-
|
|
|
- <view class="goods-pane">
|
|
|
- <scroll-view
|
|
|
- scroll-y
|
|
|
- class="goods-scroll"
|
|
|
- :show-scrollbar="true"
|
|
|
- :lower-threshold="80"
|
|
|
- @scrolltolower="onGoodsScrollToLower"
|
|
|
- >
|
|
|
- <view class="goods-scroll-inner">
|
|
|
- <view
|
|
|
- v-for="product in products"
|
|
|
- :key="product.id"
|
|
|
- class="goods-card"
|
|
|
- hover-class="goods-card--pressed"
|
|
|
- :hover-stay-time="120"
|
|
|
- @click="goProductView(product.id)"
|
|
|
- >
|
|
|
- <ClientImageLoader
|
|
|
- class="goods-image"
|
|
|
- :src="product.imageUrl || IMG_DEFAULT_PRODUCT"
|
|
|
- mode="aspectFill"
|
|
|
- radius="16rpx"
|
|
|
- />
|
|
|
- <view class="goods-main">
|
|
|
- <text class="goods-name">{{ product.name || '-' }}</text>
|
|
|
- <text class="goods-spec">{{ formatMeasureText(product.measureValue, product.unitName) }}</text>
|
|
|
- <view class="bottom-row">
|
|
|
- <text class="goods-price">¥{{ formatPrice(product.price || 0) }}</text>
|
|
|
- <view class="bottom-row-actions">
|
|
|
- <view v-if="getCartQuantity(product.id) === 0" class="add-btn" @click.stop="addToCart(product)">
|
|
|
- <text class="add-btn-plus">+</text>
|
|
|
- </view>
|
|
|
- <view v-else class="quantity-control" @click.stop>
|
|
|
- <view class="qty-btn" @click.stop="updateQuantity(product.id, -1)">
|
|
|
- <text>-</text>
|
|
|
- </view>
|
|
|
- <text class="qty-num">{{ getCartQuantity(product.id) }}</text>
|
|
|
- <view class="qty-btn" @click.stop="updateQuantity(product.id, 1)">
|
|
|
- <text>+</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view v-if="products.length === 0 && !productsLoadingMore" class="empty-list-tip">暂无匹配商品</view>
|
|
|
- <view v-if="productsLoadingMore" class="pane-footer-tip">加载中...</view>
|
|
|
- <view v-else-if="products.length > 0 && !productHasMore" class="pane-footer-tip">没有更多了</view>
|
|
|
- </view>
|
|
|
- </scroll-view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
|
|
|
- <view class="cart-bar" @click="goToCart">
|
|
|
- <view class="cart-inner">
|
|
|
- <view class="cart-left">
|
|
|
- <view class="cart-count">
|
|
|
- <text>{{ cartStore.totalCount > 99 ? '99+' : cartStore.totalCount }}</text>
|
|
|
- </view>
|
|
|
- <view class="cart-text-col">
|
|
|
- <text class="cart-items-label">已选商品</text>
|
|
|
- <text class="cart-total-money">¥{{ formatPrice(cartStore.totalAmount) }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="cart-settle">
|
|
|
- <text>去结算</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <ProductDetailOverlay :show="showProductOverlay" :product-id="overlayProductId" @close="closeProductOverlay" />
|
|
|
- <!-- #ifdef H5 -->
|
|
|
- <ClientTabBar active="home" />
|
|
|
- <!-- #endif -->
|
|
|
- </view>
|
|
|
-</template>
|
|
|
|
|
|
<style lang="scss">
|
|
|
/* 仅影响当前页:高度随 tab 内容区,禁止页面级纵向滚动(不写全局 body overflow,避免污染其它路由) */
|
|
|
@@ -584,6 +592,7 @@ page {
|
|
|
background-color: #f5f8f7;
|
|
|
}
|
|
|
|
|
|
+/* input placeholder-class 在部分端需非 scoped 才能命中 */
|
|
|
.search-placeholder {
|
|
|
color: #8aa39a;
|
|
|
}
|
|
|
@@ -648,12 +657,14 @@ page {
|
|
|
.content-wrap {
|
|
|
flex: 1;
|
|
|
min-height: 0;
|
|
|
+ /* demo .section 水平 16px → 32rpx */
|
|
|
padding: 0 32rpx;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
+/* 对齐 mobile-ui/sanqiang-client-ui-demo.html .top */
|
|
|
.filter-top-wrap {
|
|
|
flex-shrink: 0;
|
|
|
background: linear-gradient(
|
|
|
@@ -662,18 +673,18 @@ page {
|
|
|
var(--c-brand-green-2) 70%,
|
|
|
var(--c-barley-yellow) 160%
|
|
|
);
|
|
|
+ box-shadow: var(--c-shadow);
|
|
|
border-bottom-left-radius: 44rpx;
|
|
|
border-bottom-right-radius: 44rpx;
|
|
|
padding: 28rpx 32rpx 32rpx;
|
|
|
margin: 0 -32rpx 0;
|
|
|
- box-shadow: var(--c-shadow);
|
|
|
}
|
|
|
|
|
|
.top-row {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
- color: #fff;
|
|
|
+ color: #ffffff;
|
|
|
font-size: 28rpx;
|
|
|
line-height: 1.35;
|
|
|
margin-bottom: 20rpx;
|
|
|
@@ -715,7 +726,10 @@ page {
|
|
|
color: var(--c-text);
|
|
|
background: transparent;
|
|
|
border: none;
|
|
|
- box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.search-placeholder {
|
|
|
+ color: #8aa39a;
|
|
|
}
|
|
|
|
|
|
.search-clear {
|
|
|
@@ -736,12 +750,15 @@ page {
|
|
|
.search-action {
|
|
|
flex-shrink: 0;
|
|
|
padding: 0 16rpx 0 8rpx;
|
|
|
- color: var(--c-brand-green);
|
|
|
font-size: 24rpx;
|
|
|
+ color: var(--c-brand-green);
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
|
|
|
+/* demo .section 内:标题 + 一级分类白卡片 */
|
|
|
.category-section {
|
|
|
+ flex-shrink: 0;
|
|
|
+ /* demo .section margin 12px 0 顶 */
|
|
|
margin-top: 24rpx;
|
|
|
}
|
|
|
|
|
|
@@ -753,6 +770,7 @@ page {
|
|
|
}
|
|
|
|
|
|
.section-title {
|
|
|
+ /* demo h3 17px */
|
|
|
font-size: 34rpx;
|
|
|
font-weight: 600;
|
|
|
color: var(--c-text);
|
|
|
@@ -768,6 +786,7 @@ page {
|
|
|
}
|
|
|
|
|
|
.first-category-swiper {
|
|
|
+ /* 收紧一级分类区高度,避免短文案卡片出现大块空白 */
|
|
|
height: 336rpx;
|
|
|
}
|
|
|
|
|
|
@@ -782,6 +801,10 @@ page {
|
|
|
align-content: start;
|
|
|
}
|
|
|
|
|
|
+.first-category-grid--single {
|
|
|
+ min-height: auto;
|
|
|
+}
|
|
|
+
|
|
|
.first-category-card {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
@@ -808,6 +831,7 @@ page {
|
|
|
}
|
|
|
|
|
|
.first-category-image {
|
|
|
+ /* demo .first-chip::before 42×42,圆角 12px */
|
|
|
width: 84rpx;
|
|
|
height: 84rpx;
|
|
|
border-radius: 24rpx;
|
|
|
@@ -820,9 +844,11 @@ page {
|
|
|
}
|
|
|
|
|
|
.first-category-name {
|
|
|
+ /* demo .first-chip gap 8px + font 11px */
|
|
|
margin-top: 8rpx;
|
|
|
width: 100%;
|
|
|
font-size: 22rpx;
|
|
|
+ line-height: 1.2;
|
|
|
color: #4f665d;
|
|
|
text-align: center;
|
|
|
overflow: hidden;
|
|
|
@@ -834,16 +860,6 @@ page {
|
|
|
color: var(--c-brand-green);
|
|
|
}
|
|
|
|
|
|
-.product-layout {
|
|
|
- flex: 1;
|
|
|
- min-height: 0;
|
|
|
- margin-top: 20rpx;
|
|
|
- margin-left: -32rpx;
|
|
|
- margin-right: -32rpx;
|
|
|
- width: auto;
|
|
|
- align-self: stretch;
|
|
|
-}
|
|
|
-
|
|
|
.first-level-indicator {
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
@@ -865,10 +881,23 @@ page {
|
|
|
background: linear-gradient(145deg, var(--c-brand-green-2), var(--c-brand-green));
|
|
|
}
|
|
|
|
|
|
+.product-layout {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ /* demo .category-layout margin-top 10px */
|
|
|
+ margin-top: 20rpx;
|
|
|
+ /* 二级分类 + 商品区通栏:抵消 content-wrap 左右 32rpx,商品列更宽 */
|
|
|
+ margin-left: -32rpx;
|
|
|
+ margin-right: -32rpx;
|
|
|
+ width: auto;
|
|
|
+ align-self: stretch;
|
|
|
+}
|
|
|
+
|
|
|
.product-body {
|
|
|
display: flex;
|
|
|
height: 100%;
|
|
|
min-height: 0;
|
|
|
+ /* demo .category-layout min-height 440px */
|
|
|
min-height: 880rpx;
|
|
|
border: 1rpx solid var(--c-border);
|
|
|
border-radius: var(--c-radius-lg);
|
|
|
@@ -877,6 +906,7 @@ page {
|
|
|
}
|
|
|
|
|
|
.category-pane {
|
|
|
+ /* demo grid 92px 侧栏 */
|
|
|
width: 184rpx;
|
|
|
flex-shrink: 0;
|
|
|
height: 100%;
|
|
|
@@ -920,6 +950,7 @@ page {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
background: #ffffff;
|
|
|
+ /* 对齐设计图 goods-area padding:10px */
|
|
|
padding: 16rpx 0 0;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
@@ -935,6 +966,7 @@ page {
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
+/* 内层包裹:各端对 scroll-view 直接 padding 支持不一致,用内层垫高更稳 */
|
|
|
.goods-scroll-inner {
|
|
|
padding-left: 20rpx;
|
|
|
padding-right: 20rpx;
|
|
|
@@ -958,6 +990,7 @@ page {
|
|
|
|
|
|
.goods-card {
|
|
|
display: grid;
|
|
|
+ /* 窄屏:缩略图列随屏宽比例收缩;宽屏仍接近 demo 约 92px/侧 */
|
|
|
grid-template-columns: minmax(112rpx, 36%) minmax(0, 1fr);
|
|
|
gap: min(16rpx, 2.5vw);
|
|
|
align-items: stretch;
|
|
|
@@ -1018,6 +1051,7 @@ page {
|
|
|
}
|
|
|
|
|
|
.bottom-row {
|
|
|
+ /* 栅格:左侧价格区可收缩省略,右侧操作区独占一列,避免 flex 与 text 组件叠在一起 */
|
|
|
display: grid;
|
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
|
align-items: center;
|
|
|
@@ -1064,6 +1098,7 @@ page {
|
|
|
line-height: 1;
|
|
|
}
|
|
|
|
|
|
+/* 「+」在圆内几何居中:抵消 text 默认行高/基线导致的视觉偏移 */
|
|
|
.add-btn-plus {
|
|
|
line-height: 1;
|
|
|
font-size: inherit;
|
|
|
@@ -1106,16 +1141,18 @@ page {
|
|
|
text-overflow: ellipsis;
|
|
|
}
|
|
|
|
|
|
+// 底部购物车:对齐 demo .cart-bar / .cart-inner / .settle
|
|
|
.cart-bar {
|
|
|
position: fixed;
|
|
|
+ left: 50%;
|
|
|
+ transform: translateX(-50%);
|
|
|
z-index: 10010;
|
|
|
width: 100%;
|
|
|
max-width: 840rpx;
|
|
|
padding: 0 24rpx;
|
|
|
box-sizing: border-box;
|
|
|
overflow: visible;
|
|
|
- left: 50%;
|
|
|
- transform: translateX(-50%);
|
|
|
+ /* demo .cart-bar bottom:72px — 在 tab 之上留出空隙;与 uni --window-bottom 叠加 */
|
|
|
/* #ifdef H5 */
|
|
|
bottom: calc(var(--window-bottom, calc(50px + env(safe-area-inset-bottom, 0px))) + 44rpx);
|
|
|
/* #endif */
|