Browse Source
1. 改进product-list页面,实现3列布局,添加玻璃质感和动画效果 2. 改进index页面,实现3列布局,添加玻璃质感和动画效果,优化商品信息显示 3. 重写spec-detail页面布局,解决拥挤和超屏幕问题,添加玻璃质感和动画效果 4. 确保所有页面响应式设计,适配不同屏幕尺寸 5. 为所有页面添加一致的现代UI风格和交互效果pull/19/head
7 changed files with 919 additions and 372 deletions
@ -1,61 +1,73 @@ |
|||
<view class="container"> |
|||
<!-- 头部导航栏 --> |
|||
<view class="header"> |
|||
<text class="title">选择规格</text> |
|||
<view class="header-content" style="width: 4200rpx; display: block; box-sizing: border-box; height: 124rpx"> |
|||
<text class="title">规格选择</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="content"> |
|||
<!-- 加载中状态 --> |
|||
<view wx:if="{{loading}}" class="loading"> |
|||
<view class="loading-spinner"></view> |
|||
<text>加载中...</text> |
|||
<text class="loading-text">正在加载规格数据...</text> |
|||
</view> |
|||
|
|||
<!-- 错误提示 --> |
|||
<view wx:if="{{error}}" class="error"> |
|||
<view wx:if="{{error}}" class="error-card"> |
|||
<view class="error-icon">⚠️</view> |
|||
<text>{{error}}</text> |
|||
<text class="error-text">{{error}}</text> |
|||
<view class="button-group"> |
|||
<button bindtap="loadSpecifications" data-product="{{productName}}" type="primary" class="retry-button">重试</button> |
|||
<button bindtap="goBackToProductList" type="default" class="back-button">返回上一步</button> |
|||
<button bindtap="loadSpecifications" data-product="{{productName}}" class="btn-primary">重新加载</button> |
|||
<button bindtap="goBackToProductList" class="btn-secondary">返回商品列表</button> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 商品信息 --> |
|||
<view wx:else class="product-info"> |
|||
<text class="product-label">商品名称:</text> |
|||
<text class="product-value">{{productName}}</text> |
|||
<button bindtap="goBackToProductList" type="default" class="back-button">返回上一步</button> |
|||
<view wx:else class="product-card"> |
|||
<view class="product-info-container"> |
|||
<view class="product-info-row"> |
|||
<text class="product-label">商品名称</text> |
|||
<button bindtap="goBackToProductList" class="btn-back" style="width: 172rpx; display: flex; box-sizing: border-box; left: 0rpx; top: 0rpx; height: 87rpx"> |
|||
<text class="btn-back-icon">←</text> |
|||
<text class="btn-back-text">更换商品</text> |
|||
</button> |
|||
</view> |
|||
<text class="product-name">{{productName}}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 规格列表 --> |
|||
<view wx:if="{{!loading && !error && specifications.length > 0}}" class="spec-list"> |
|||
<view wx:if="{{!loading && !error && specifications.length > 0}}" class="spec-section"> |
|||
<view class="section-header"> |
|||
<text class="section-title">可用规格</text> |
|||
<text class="section-count">{{specifications.length}}个</text> |
|||
</view> |
|||
<view class="spec-items"> |
|||
<view class="spec-grid"> |
|||
<view |
|||
wx:for="{{specifications}}" |
|||
wx:key="item.name" |
|||
class="spec-item" |
|||
class="spec-card" |
|||
data-spec="{{item}}" |
|||
bindtap="goToSpecDetail" |
|||
> |
|||
<view class="spec-info"> |
|||
<text class="spec-name">{{item.name}}</text> |
|||
</view> |
|||
<view class="spec-price-arrow"> |
|||
<text class="spec-price">¥{{item.finalPriceText}}</text> |
|||
<view class="spec-arrow">→</view> |
|||
<view class="spec-price"> |
|||
<text class="price-label">参考价格</text> |
|||
<text class="price-value">¥{{item.finalPriceText}}</text> |
|||
</view> |
|||
<view class="spec-arrow">→</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 无规格提示 --> |
|||
<view wx:if="{{!loading && !error && specifications.length === 0}}" class="hint"> |
|||
<view class="hint-icon">📋</view> |
|||
<text>该商品暂无可用规格</text> |
|||
<view wx:if="{{!loading && !error && specifications.length === 0}}" class="empty-state" style="height: 600rpx; display: flex; box-sizing: border-box"> |
|||
<view class="empty-icon">📋</view> |
|||
<text class="empty-text">该商品暂无可用规格</text> |
|||
<button bindtap="goBackToProductList" class="btn-secondary">返回商品列表</button> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
@ -1,45 +1,59 @@ |
|||
<view class="container"> |
|||
<view class="header"> |
|||
<text class="title">{{productName}}</text> |
|||
<view class="page-container"> |
|||
<!-- 头部导航栏 --> |
|||
<view class="page-header"> |
|||
<text class="header-title">{{productName || '规格详情'}}</text> |
|||
</view> |
|||
|
|||
<view class="content"> |
|||
<view class="spec-card"> |
|||
<view class="spec-item"> |
|||
<text class="label">规格:</text> |
|||
<text class="value">{{specification}}</text> |
|||
<!-- 主要内容区域 --> |
|||
<view class="main-content"> |
|||
<!-- 规格信息卡片 --> |
|||
<view class="info-card"> |
|||
<text class="card-subtitle">规格信息</text> |
|||
<view class="info-row"> |
|||
<text class="info-label">规格</text> |
|||
<text class="info-value">{{specification}}</text> |
|||
</view> |
|||
<view class="spec-item"> |
|||
<text class="label">单价:</text> |
|||
<text class="value price">¥{{price || 0}}</text> |
|||
</view> |
|||
<view class="spec-info"> |
|||
<text>您已选择此规格进行估价</text> |
|||
<view class="info-row"> |
|||
<text class="info-label">单价</text> |
|||
<text class="info-value price">¥{{price || 0}}</text> |
|||
</view> |
|||
<text class="info-hint">您已选择此规格进行估价</text> |
|||
</view> |
|||
|
|||
<view class="quantity-section"> |
|||
<text class="label">件数:</text> |
|||
<input |
|||
class="quantity-input" |
|||
type="number" |
|||
value="{{quantity}}" |
|||
bindinput="onQuantityChange" |
|||
min="1" |
|||
/> |
|||
<!-- 数量设置卡片 --> |
|||
<view class="control-card"> |
|||
<text class="card-subtitle">数量设置</text> |
|||
<view class="quantity-box"> |
|||
<button bindtap="decreaseQuantity" class="quantity-btn minus" style="width: 180rpx; display: flex; box-sizing: border-box; left: 0rpx; top: 0rpx">-</button> |
|||
<input style="width: 420rpx; display: block; box-sizing: border-box" |
|||
class="quantity-input" |
|||
type="number" |
|||
value="{{quantity}}" |
|||
bindinput="onQuantityChange" |
|||
min="1" |
|||
/> |
|||
<button bindtap="increaseQuantity" class="quantity-btn plus" style="width: 180rpx; display: flex; box-sizing: border-box; left: 0rpx; top: 0rpx">+</button> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="calculate-section"> |
|||
<button bindtap="calculatePrice" type="primary" class="calculate-button">计算价格</button> |
|||
<!-- 计算按钮 --> |
|||
<view class="button-section"> |
|||
<button bindtap="calculatePrice" class="primary-btn" style="height: 120rpx; display: block; box-sizing: border-box; left: 0rpx; top: 0rpx">计算预估价格</button> |
|||
</view> |
|||
|
|||
<view class="result-section"> |
|||
<text class="result-label">预估:</text> |
|||
<text class="result-value">¥{{totalPrice > 0 ? totalPrice : ''}}</text> |
|||
<!-- 结果展示卡片 --> |
|||
<view class="result-card" wx:if="{{totalPrice > 0}}"> |
|||
<text class="card-subtitle">预估结果</text> |
|||
<view class="result-row"> |
|||
<text class="result-label">预估总价</text> |
|||
<text class="result-value">¥{{totalPrice}}</text> |
|||
</view> |
|||
<text class="result-hint">此价格为预估价格,实际价格可能会有所变动</text> |
|||
</view> |
|||
|
|||
<view class="action"> |
|||
<button bindtap="goBack" type="default">返回</button> |
|||
<!-- 返回按钮 --> |
|||
<view class="button-section bottom"> |
|||
<button bindtap="goBack" class="secondary-btn" style="height: 120rpx; display: block; box-sizing: border-box; left: 0rpx; top: 0rpx">返回规格列表</button> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
@ -1,127 +1,401 @@ |
|||
.container { |
|||
/* 页面容器 */ |
|||
.page-container { |
|||
min-height: 100vh; |
|||
background-color: #f5f5f5; |
|||
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); |
|||
font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif; |
|||
display: flex; |
|||
flex-direction: column; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.header { |
|||
padding: 30rpx 0; |
|||
/* 头部样式 */ |
|||
.page-header { |
|||
background: rgba(255, 255, 255, 0.95); |
|||
backdrop-filter: blur(10rpx); |
|||
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.05); |
|||
padding: 28rpx 0; |
|||
text-align: center; |
|||
background-color: #fff; |
|||
border-bottom: 1rpx solid #eee; |
|||
position: sticky; |
|||
top: 0; |
|||
z-index: 10; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 32rpx; |
|||
font-weight: bold; |
|||
color: #333; |
|||
.header-title { |
|||
font-size: 30rpx; |
|||
font-weight: 700; |
|||
color: #2c3e50; |
|||
letter-spacing: 1rpx; |
|||
} |
|||
|
|||
.content { |
|||
padding: 30rpx; |
|||
/* 主要内容区域 */ |
|||
.main-content { |
|||
flex: 1; |
|||
padding: 24rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 24rpx; |
|||
padding-bottom: 48rpx; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.spec-card { |
|||
background-color: #fff; |
|||
border-radius: 12rpx; |
|||
padding: 40rpx; |
|||
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.08); |
|||
margin-bottom: 40rpx; |
|||
/* 卡片基础样式 */ |
|||
.info-card, |
|||
.control-card, |
|||
.result-card { |
|||
background: rgba(255, 255, 255, 0.95); |
|||
border-radius: 24rpx; |
|||
padding: 32rpx; |
|||
box-shadow: 0 6rpx 24rpx rgba(0,0,0,0.08); |
|||
backdrop-filter: blur(12rpx); |
|||
border: 1rpx solid rgba(255, 255, 255, 0.4); |
|||
transition: all 0.3s ease; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.info-card:hover, |
|||
.control-card:hover, |
|||
.result-card:hover { |
|||
box-shadow: 0 8rpx 32rpx rgba(0,0,0,0.12); |
|||
transform: translateY(-4rpx); |
|||
background: rgba(255, 255, 255, 0.98); |
|||
} |
|||
|
|||
.spec-item { |
|||
/* 卡片标题 */ |
|||
.card-subtitle { |
|||
font-size: 26rpx; |
|||
font-weight: 600; |
|||
color: #64748b; |
|||
margin-bottom: 24rpx; |
|||
padding-bottom: 16rpx; |
|||
border-bottom: 1rpx solid #f1f5f9; |
|||
} |
|||
|
|||
/* 信息行样式 */ |
|||
.info-row { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 30rpx; |
|||
padding: 16rpx 0; |
|||
border-bottom: 1rpx solid #f8fafc; |
|||
} |
|||
|
|||
.label { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
margin-right: 20rpx; |
|||
width: 120rpx; |
|||
.info-row:last-child { |
|||
border-bottom: none; |
|||
} |
|||
|
|||
.value { |
|||
font-size: 32rpx; |
|||
font-weight: bold; |
|||
color: #FF6B81; |
|||
flex: 1; |
|||
.info-label { |
|||
font-size: 26rpx; |
|||
color: #64748b; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.price { |
|||
color: #FF6B81; |
|||
.info-value { |
|||
font-size: 26rpx; |
|||
font-weight: 600; |
|||
color: #2c3e50; |
|||
} |
|||
|
|||
.spec-info { |
|||
padding-top: 20rpx; |
|||
border-top: 1rpx solid #eee; |
|||
.info-value.price { |
|||
color: #ef4444; |
|||
font-size: 32rpx; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
/* 提示信息 */ |
|||
.info-hint { |
|||
font-size: 22rpx; |
|||
color: #94a3b8; |
|||
text-align: center; |
|||
margin-top: 20rpx; |
|||
padding-top: 20rpx; |
|||
border-top: 1rpx solid #f1f5f9; |
|||
} |
|||
|
|||
.spec-info text { |
|||
font-size: 24rpx; |
|||
color: #999; |
|||
/* 数量控制 */ |
|||
.quantity-box { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 24rpx; |
|||
margin-top: 12rpx; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.quantity-section { |
|||
.quantity-btn { |
|||
width: 80rpx; |
|||
height: 80rpx; |
|||
border-radius: 40rpx; |
|||
font-size: 36rpx; |
|||
font-weight: bold; |
|||
background: rgba(255, 255, 255, 0.9); |
|||
color: #3b82f6; |
|||
border: 2rpx solid rgba(96, 165, 250, 0.4); |
|||
backdrop-filter: blur(12rpx); |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 30rpx; |
|||
justify-content: center; |
|||
transition: all 0.3s ease; |
|||
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.08); |
|||
} |
|||
|
|||
.quantity-btn:hover { |
|||
background: rgba(59, 130, 246, 0.1); |
|||
border-color: rgba(59, 130, 246, 0.6); |
|||
transform: scale(1.1); |
|||
} |
|||
|
|||
.quantity-btn.minus:hover { |
|||
background: rgba(239, 68, 68, 0.1); |
|||
border-color: rgba(239, 68, 68, 0.6); |
|||
color: #ef4444; |
|||
} |
|||
|
|||
.quantity-btn.plus:hover { |
|||
background: rgba(16, 185, 129, 0.1); |
|||
border-color: rgba(16, 185, 129, 0.6); |
|||
color: #10b981; |
|||
} |
|||
|
|||
.quantity-input { |
|||
flex: 1; |
|||
width: 160rpx; |
|||
height: 80rpx; |
|||
border: 2rpx solid #ddd; |
|||
border-radius: 8rpx; |
|||
padding: 0 20rpx; |
|||
border: 2rpx solid rgba(96, 165, 250, 0.4); |
|||
border-radius: 16rpx; |
|||
padding: 0 24rpx; |
|||
font-size: 28rpx; |
|||
font-weight: 600; |
|||
text-align: center; |
|||
color: #2c3e50; |
|||
background: rgba(255, 255, 255, 0.95); |
|||
backdrop-filter: blur(12rpx); |
|||
box-shadow: inset 0 2rpx 8rpx rgba(0,0,0,0.08); |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.calculate-section { |
|||
display: flex; |
|||
justify-content: center; |
|||
margin-bottom: 30rpx; |
|||
/* 按钮区域 */ |
|||
.button-section { |
|||
margin-top: 12rpx; |
|||
} |
|||
|
|||
.calculate-button { |
|||
width: 80%; |
|||
height: 80rpx; |
|||
.button-section.bottom { |
|||
margin-top: 20rpx; |
|||
} |
|||
|
|||
/* 按钮样式 */ |
|||
.primary-btn { |
|||
width: 100%; |
|||
height: 92rpx; |
|||
line-height: 92rpx; |
|||
font-size: 28rpx; |
|||
border-radius: 40rpx; |
|||
font-weight: 600; |
|||
border-radius: 46rpx; |
|||
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%); |
|||
color: #fff; |
|||
border: none; |
|||
box-shadow: 0 6rpx 24rpx rgba(59, 130, 246, 0.4); |
|||
transition: all 0.3s ease; |
|||
text-align: center; |
|||
} |
|||
|
|||
.primary-btn:hover { |
|||
transform: translateY(-4rpx); |
|||
box-shadow: 0 8rpx 32rpx rgba(59, 130, 246, 0.5); |
|||
} |
|||
|
|||
.secondary-btn { |
|||
width: 100%; |
|||
height: 84rpx; |
|||
line-height: 84rpx; |
|||
font-size: 26rpx; |
|||
font-weight: 600; |
|||
border-radius: 42rpx; |
|||
background: rgba(255, 255, 255, 0.95); |
|||
color: #3b82f6; |
|||
border: 2rpx solid rgba(59, 130, 246, 0.4); |
|||
backdrop-filter: blur(12rpx); |
|||
transition: all 0.3s ease; |
|||
text-align: center; |
|||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.08); |
|||
} |
|||
|
|||
.secondary-btn:hover { |
|||
background: rgba(59, 130, 246, 0.08); |
|||
border-color: rgba(59, 130, 246, 0.6); |
|||
transform: translateY(-4rpx); |
|||
box-shadow: 0 6rpx 24rpx rgba(59, 130, 246, 0.3); |
|||
} |
|||
|
|||
/* 结果卡片 */ |
|||
.result-card { |
|||
animation: fadeInUp 0.6s ease-out; |
|||
} |
|||
|
|||
@keyframes fadeInUp { |
|||
from { |
|||
opacity: 0; |
|||
transform: translateY(30rpx); |
|||
} |
|||
to { |
|||
opacity: 1; |
|||
transform: translateY(0); |
|||
} |
|||
} |
|||
|
|||
.result-section { |
|||
/* 结果行 */ |
|||
.result-row { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 40rpx; |
|||
padding: 20rpx; |
|||
background-color: #f9f9f9; |
|||
border-radius: 8rpx; |
|||
padding: 20rpx 0; |
|||
} |
|||
|
|||
.result-label { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
margin-right: 20rpx; |
|||
width: 120rpx; |
|||
font-size: 26rpx; |
|||
color: #64748b; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.result-value { |
|||
font-size: 36rpx; |
|||
font-weight: bold; |
|||
color: #FF6B81; |
|||
flex: 1; |
|||
font-weight: 700; |
|||
color: #ef4444; |
|||
text-shadow: 0 2rpx 4rpx rgba(239, 68, 68, 0.2); |
|||
} |
|||
|
|||
.action { |
|||
display: flex; |
|||
justify-content: center; |
|||
/* 结果提示 */ |
|||
.result-hint { |
|||
font-size: 22rpx; |
|||
color: #94a3b8; |
|||
text-align: center; |
|||
margin-top: 16rpx; |
|||
padding-top: 16rpx; |
|||
border-top: 1rpx solid #f1f5f9; |
|||
line-height: 1.5; |
|||
} |
|||
|
|||
button { |
|||
width: 80%; |
|||
height: 80rpx; |
|||
font-size: 28rpx; |
|||
border-radius: 40rpx; |
|||
/* 响应式设计 */ |
|||
@media (max-width: 750rpx) { |
|||
.main-content { |
|||
padding: 20rpx; |
|||
gap: 20rpx; |
|||
} |
|||
|
|||
.info-card, |
|||
.control-card, |
|||
.result-card { |
|||
padding: 28rpx; |
|||
} |
|||
|
|||
.header-title { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.card-subtitle { |
|||
font-size: 24rpx; |
|||
margin-bottom: 20rpx; |
|||
} |
|||
|
|||
.info-label, |
|||
.info-value { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.info-value.price { |
|||
font-size: 30rpx; |
|||
} |
|||
|
|||
.result-value { |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.quantity-box { |
|||
gap: 20rpx; |
|||
} |
|||
|
|||
.quantity-btn { |
|||
width: 72rpx; |
|||
height: 72rpx; |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.quantity-input { |
|||
width: 140rpx; |
|||
height: 72rpx; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.primary-btn { |
|||
height: 84rpx; |
|||
line-height: 84rpx; |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.secondary-btn { |
|||
height: 76rpx; |
|||
line-height: 76rpx; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
/* 小屏幕设备适配 */ |
|||
@media (max-width: 375rpx) { |
|||
.main-content { |
|||
padding: 16rpx; |
|||
gap: 16rpx; |
|||
} |
|||
|
|||
.info-card, |
|||
.control-card, |
|||
.result-card { |
|||
padding: 24rpx; |
|||
} |
|||
|
|||
.header-title { |
|||
font-size: 26rpx; |
|||
} |
|||
|
|||
.card-subtitle { |
|||
font-size: 22rpx; |
|||
margin-bottom: 16rpx; |
|||
} |
|||
|
|||
.info-label, |
|||
.info-value { |
|||
font-size: 22rpx; |
|||
} |
|||
|
|||
.info-value.price { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.result-value { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.quantity-box { |
|||
gap: 16rpx; |
|||
} |
|||
|
|||
.quantity-btn { |
|||
width: 64rpx; |
|||
height: 64rpx; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.quantity-input { |
|||
width: 120rpx; |
|||
height: 64rpx; |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.primary-btn { |
|||
height: 76rpx; |
|||
line-height: 76rpx; |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.secondary-btn { |
|||
height: 68rpx; |
|||
line-height: 68rpx; |
|||
font-size: 22rpx; |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue