From c0833bc71cf5245a16fbca39e9c9b6c16cb3e0da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BE=90=E9=A3=9E=E6=B4=8B?=
<15778543+xufeiyang6017@user.noreply.gitee.com>
Date: Sat, 6 Dec 2025 11:48:28 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=95=86=E5=93=81=E8=AF=A6?=
=?UTF-8?q?=E6=83=85=E9=A1=B5=E9=9D=A2=E5=B9=B6=E4=BF=AE=E6=94=B9=E7=9B=B8?=
=?UTF-8?q?=E5=85=B3=E6=96=87=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app.json | 3 +-
pages/buyer/index.js | 43 +--
pages/buyer/index.wxml | 98 +----
pages/goods-detail/goods-detail.js | 440 +++++++++++++++++++++++
pages/goods-detail/goods-detail.json | 4 +
pages/goods-detail/goods-detail.wxml | 175 +++++++++
pages/goods-detail/goods-detail.wxss | 514 +++++++++++++++++++++++++++
7 files changed, 1140 insertions(+), 137 deletions(-)
create mode 100644 pages/goods-detail/goods-detail.js
create mode 100644 pages/goods-detail/goods-detail.json
create mode 100644 pages/goods-detail/goods-detail.wxml
create mode 100644 pages/goods-detail/goods-detail.wxss
diff --git a/app.json b/app.json
index 21cb189..ce8a09d 100644
--- a/app.json
+++ b/app.json
@@ -8,7 +8,8 @@
"pages/seller/index",
"pages/profile/index",
"pages/notopen/index",
- "pages/create-supply/index"
+ "pages/create-supply/index",
+ "pages/goods-detail/goods-detail"
],
"subpackages": [
{
diff --git a/pages/buyer/index.js b/pages/buyer/index.js
index ca2c941..540d5e4 100644
--- a/pages/buyer/index.js
+++ b/pages/buyer/index.js
@@ -1642,7 +1642,7 @@ Page({
});
},
- // 显示商品详情
+ // 跳转到商品详情页面
showGoodsDetail: function (e) {
// 检查用户是否登录
const openid = wx.getStorageSync('openid');
@@ -1664,17 +1664,11 @@ Page({
}
const goodsItem = e.currentTarget.dataset.item;
- this.setData({
- currentGoodsDetail: goodsItem,
- showGoodsDetail: true
+ // 跳转到商品详情页面,并传递商品数据,使用encodeURIComponent编码JSON字符串
+ wx.navigateTo({
+ url: '/pages/goods-detail/goods-detail?goodsData=' + encodeURIComponent(JSON.stringify(goodsItem))
});
- // 隐藏底部导航栏 - 通过更新全局数据
- const app = getApp();
- if (app && app.globalData) {
- app.globalData.showTabBar = false;
- }
-
// 同时尝试直接更新tabBar的选中状态
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
const tabBar = this.getTabBar();
@@ -1693,36 +1687,7 @@ Page({
);
},
- // 关闭商品详情
- closeGoodsDetail: function () {
- this.setData({
- showGoodsDetail: false,
- currentGoodsDetail: {}
- });
-
- // 显示底部导航栏 - 通过更新全局数据
- const app = getApp();
- if (app && app.globalData) {
- app.globalData.showTabBar = true;
- }
-
- // 同时尝试直接更新tabBar的选中状态
- if (typeof this.getTabBar === 'function' && this.getTabBar()) {
- const tabBar = this.getTabBar();
- if (tabBar.setData) {
- tabBar.setData({ show: true });
- }
- }
- },
- // 在详情弹窗中点击"我想要"按钮
- onClickWantInDetail: function (e) {
- const goodsId = e.currentTarget.dataset.id;
- // 先关闭详情弹窗
- this.closeGoodsDetail();
- // 然后调用原来的"我想要"方法
- this.onClickWant({ currentTarget: { dataset: { id: goodsId } } });
- },
// 获取手机号并登录
onGetPhoneNumber: function (e) {
diff --git a/pages/buyer/index.wxml b/pages/buyer/index.wxml
index e801e27..e0aec79 100644
--- a/pages/buyer/index.wxml
+++ b/pages/buyer/index.wxml
@@ -189,103 +189,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{currentGoodsDetail.name}}
- 价格: {{currentGoodsDetail.price || '暂无'}}
-
-
-
-
- 地区
- {{currentGoodsDetail.region}}
-
-
- 规格
- {{currentGoodsDetail.spec || '无'}}
-
-
- 蛋黄
- {{currentGoodsDetail.yolk || '无'}}
-
-
- 斤重
- {{currentGoodsDetail.displayGrossWeight}}
-
-
- 件数
- {{currentGoodsDetail.minOrder}}件
-
-
- 关注人数
- {{currentGoodsDetail.reservedCount || 0}}人
-
-
-
-
-
- 联系信息
-
- 👤
- 联系人: {{currentGoodsDetail.product_contact || '暂无'}}
-
-
- 📞
- 联系电话: {{currentGoodsDetail.contact_phone || '暂无'}}
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/pages/goods-detail/goods-detail.js b/pages/goods-detail/goods-detail.js
new file mode 100644
index 0000000..6845cf0
--- /dev/null
+++ b/pages/goods-detail/goods-detail.js
@@ -0,0 +1,440 @@
+// pages/goods-detail/goods-detail.js
+const API = require('../../utils/api.js')
+
+// 格式化毛重显示的辅助函数
+function formatGrossWeight(grossWeight, weight) {
+ console.log('===== formatGrossWeight 函数调用 =====');
+ console.log('输入参数:');
+ console.log('- grossWeight:', grossWeight, '(类型:', typeof grossWeight, ')');
+ console.log('- weight:', weight, '(类型:', typeof weight, ')');
+
+ // 1. 优先使用grossWeight,只要它不是null、不是undefined、不是空字符串
+ if (grossWeight !== null && grossWeight !== undefined && grossWeight !== '') {
+ console.log('使用grossWeight参数');
+ return grossWeight;
+ }
+ // 如果grossWeight无效,尝试使用weight字段
+ if (weight !== null && weight !== undefined && weight !== '') {
+ console.log('使用weight参数');
+ return weight;
+ }
+
+ // 3. 新增逻辑:如果grossWeight和weight都无效,返回空字符串以支持文字输入
+ console.log('两个参数都无效,返回空字符串');
+ return "";
+}
+
+Page({
+ data: {
+ goodsDetail: {}, // 当前商品详情
+ showImagePreview: false, // 控制图片预览弹窗显示
+ previewImageUrls: [], // 预览的图片URL列表
+ previewImageIndex: 0, // 当前预览图片的索引
+ // 图片缩放相关状态
+ scale: 1, // 当前缩放比例
+ lastScale: 1, // 上一次缩放比例
+ startDistance: 0, // 双指起始距离
+ doubleTapTimer: null, // 双击计时器
+ lastTapTime: 0, // 上一次单击时间
+ isScaling: false, // 是否正在缩放中
+ offsetX: 0, // X轴偏移量
+ offsetY: 0, // Y轴偏移量
+ initialTouch: null, // 初始触摸点
+ },
+
+ onLoad(options) {
+ console.log('商品详情页面加载,参数:', options);
+
+ // 支持两种参数传递方式:直接传递商品数据或仅传递商品ID
+ if (options.goodsData) {
+ try {
+ // 解析JSON字符串为商品对象
+ const goodsData = JSON.parse(decodeURIComponent(options.goodsData));
+ console.log('解析后的商品数据:', goodsData);
+
+ // 设置商品详情数据
+ this.setData({
+ goodsDetail: goodsData
+ });
+ } catch (error) {
+ console.error('解析商品数据失败:', error);
+ wx.showToast({
+ title: '数据解析错误',
+ icon: 'none',
+ duration: 2000
+ });
+ // 2秒后返回上一页
+ setTimeout(() => {
+ wx.navigateBack();
+ }, 2000);
+ }
+ } else if (options.id) {
+ // 如果只传递了商品ID,则从服务器加载商品详情
+ this.loadGoodsDetail(options.id);
+ } else {
+ wx.showToast({
+ title: '参数错误',
+ icon: 'none',
+ duration: 2000
+ });
+ // 2秒后返回上一页
+ setTimeout(() => {
+ wx.navigateBack();
+ }, 2000);
+ }
+ },
+
+ // 加载商品详情
+ loadGoodsDetail(goodsId) {
+ wx.showLoading({
+ title: '加载中',
+ });
+
+ API.getProductDetail({ productId: goodsId })
+ .then(res => {
+ console.log('获取商品详情成功:', res);
+ if (res && res.code === 200 && res.data) {
+ // 从本地存储获取已预约商品ID列表
+ const reservedGoodsIds = wx.getStorageSync('reservedGoodsIds') || [];
+ const product = res.data;
+
+ // 确保商品ID的一致性
+ const productIdStr = String(product.productId || product.id);
+
+ // 增强的预约人数计算逻辑
+ const selectedValue = product.selected;
+ const reservedCountValue = product.reservedCount;
+ const reservationCountValue = product.reservationCount;
+
+ const finalReservationCount = selectedValue !== undefined && selectedValue !== null ? selectedValue :
+ (reservedCountValue !== undefined && reservedCountValue !== null ? reservedCountValue :
+ (reservationCountValue || 0));
+
+ // 处理grossWeight为null或无效的情况,返回空字符串以支持文字输入
+ const grossWeightValue = product.grossWeight !== null && product.grossWeight !== undefined ? product.grossWeight : '';
+
+ // 转换商品数据格式
+ const formattedGoods = {
+ id: productIdStr,
+ productId: productIdStr,
+ name: product.productName,
+ price: product.price,
+ minOrder: product.quantity,
+ yolk: product.yolk,
+ spec: product.specification,
+ region: product.region,
+ contact_phone: product.contactPhone,
+ product_contact: product.contactName,
+ imageUrls: product.images || [],
+ displayGrossWeight: formatGrossWeight(grossWeightValue, product.weight),
+ isReserved: reservedGoodsIds.some(itemId => String(itemId) === productIdStr),
+ reservedCount: finalReservationCount,
+ created_at: product.createdAt,
+ updated_at: product.updatedAt
+ };
+
+ this.setData({
+ goodsDetail: formattedGoods
+ });
+ } else {
+ wx.showToast({
+ title: '获取商品详情失败',
+ icon: 'none',
+ duration: 2000
+ });
+ }
+ })
+ .catch(err => {
+ console.error('获取商品详情失败:', err);
+ wx.showToast({
+ title: '获取商品详情失败',
+ icon: 'none',
+ duration: 2000
+ });
+ })
+ .finally(() => {
+ wx.hideLoading();
+ });
+ },
+
+ // 预览图片
+ previewImage(e) {
+ console.log('预览图片事件:', e);
+ const { urls, index } = e.currentTarget.dataset;
+ if (!urls || urls.length === 0) {
+ wx.showToast({
+ title: '没有图片可预览',
+ icon: 'none'
+ });
+ return;
+ }
+
+ this.setData({
+ showImagePreview: true,
+ previewImageUrls: urls,
+ previewImageIndex: index || 0,
+ // 重置图片缩放状态
+ scale: 1,
+ offsetX: 0,
+ offsetY: 0,
+ isScaling: false
+ });
+ },
+
+ // 关闭图片预览
+ closeImagePreview() {
+ this.setData({
+ showImagePreview: false,
+ // 重置图片缩放状态
+ scale: 1,
+ offsetX: 0,
+ offsetY: 0,
+ isScaling: false
+ });
+ },
+
+ // 图片预览切换
+ onPreviewImageChange(e) {
+ console.log('图片预览切换:', e);
+ this.setData({
+ previewImageIndex: e.detail.current,
+ // 重置当前图片的缩放状态
+ scale: 1,
+ offsetX: 0,
+ offsetY: 0,
+ isScaling: false
+ });
+ },
+
+ // 处理图片点击事件(双击放大/缩小)
+ handleImageTap(e) {
+ console.log('图片点击事件:', e);
+ const now = Date.now();
+ const DOUBLE_TAP_DELAY = 300;
+
+ // 检查是否为双击
+ if (now - this.lastTapTime < DOUBLE_TAP_DELAY) {
+ // 双击事件
+ if (this.doubleTapTimer) {
+ clearTimeout(this.doubleTapTimer);
+ }
+
+ // 切换缩放状态
+ const newScale = this.data.scale === 1 ? 2 : 1;
+ this.setData({
+ scale: newScale,
+ isScaling: false
+ });
+ } else {
+ // 单击事件,设置双击计时器
+ if (this.doubleTapTimer) {
+ clearTimeout(this.doubleTapTimer);
+ }
+
+ this.doubleTapTimer = setTimeout(() => {
+ // 单击后300毫秒内没有第二次点击,视为单击
+ // 可以在这里添加单击事件的处理逻辑
+ }, DOUBLE_TAP_DELAY);
+ }
+
+ this.lastTapTime = now;
+ },
+
+ // 计算两点之间的距离
+ getDistance(point1, point2) {
+ const dx = point2.clientX - point1.clientX;
+ const dy = point2.clientY - point1.clientY;
+ return Math.sqrt(dx * dx + dy * dy);
+ },
+
+ // 处理触摸开始事件
+ handleTouchStart(e) {
+ console.log('触摸开始事件:', e);
+ if (e.touches.length === 2) {
+ // 双指触摸,计算初始距离
+ this.setData({
+ startDistance: this.getDistance(e.touches[0], e.touches[1]),
+ lastScale: this.data.scale,
+ isScaling: true
+ });
+ } else if (e.touches.length === 1) {
+ // 单指触摸,记录初始位置
+ this.setData({
+ initialTouch: {
+ x: e.touches[0].clientX,
+ y: e.touches[0].clientY
+ }
+ });
+ }
+ },
+
+ // 处理触摸移动事件
+ handleTouchMove(e) {
+ console.log('触摸移动事件:', e);
+ const touches = e.touches;
+
+ if (touches.length === 1 && this.data.initialTouch && this.data.scale !== 1) {
+ // 单指拖动(只有在缩放状态下才允许拖动)
+ const deltaX = touches[0].clientX - this.data.initialTouch.x;
+ const deltaY = touches[0].clientY - this.data.initialTouch.y;
+
+ // 计算新的偏移量
+ let newOffsetX = this.data.offsetX + deltaX;
+ let newOffsetY = this.data.offsetY + deltaY;
+
+ // 边界限制
+ const windowWidth = wx.getSystemInfoSync().windowWidth;
+ const windowHeight = wx.getSystemInfoSync().windowHeight;
+ const maxOffsetX = (windowWidth * (this.data.scale - 1)) / 2;
+ const maxOffsetY = (windowHeight * (this.data.scale - 1)) / 2;
+
+ newOffsetX = Math.max(-maxOffsetX, Math.min(maxOffsetX, newOffsetX));
+ newOffsetY = Math.max(-maxOffsetY, Math.min(maxOffsetY, newOffsetY));
+
+ this.setData({
+ offsetX: newOffsetX,
+ offsetY: newOffsetY,
+ initialTouch: {
+ x: touches[0].clientX,
+ y: touches[0].clientY
+ }
+ });
+ } else if (touches.length === 2) {
+ // 双指缩放
+ const currentDistance = this.getDistance(touches[0], touches[1]);
+ const scale = (currentDistance / this.data.startDistance) * this.data.lastScale;
+
+ // 限制缩放范围在0.5倍到3倍之间
+ const newScale = Math.max(0.5, Math.min(3, scale));
+
+ this.setData({
+ scale: newScale,
+ isScaling: true
+ });
+ }
+ },
+
+ // 处理触摸结束事件
+ handleTouchEnd(e) {
+ console.log('触摸结束事件:', e);
+ if (e.touches.length === 0) {
+ // 触摸结束,更新最后缩放比例
+ this.setData({
+ lastScale: this.data.scale,
+ isScaling: false,
+ initialTouch: null
+ });
+ } else if (e.touches.length === 1) {
+ // 单指触摸结束,保留初始触摸点
+ this.setData({
+ initialTouch: {
+ x: e.touches[0].clientX,
+ y: e.touches[0].clientY
+ }
+ });
+ }
+ },
+
+ // 拨打电话
+ makePhoneCall(e) {
+ console.log('拨打电话事件:', e);
+ const phoneNumber = e.currentTarget.dataset.phone;
+ if (phoneNumber) {
+ wx.showModal({
+ title: '联系人电话',
+ content: phoneNumber,
+ showCancel: true,
+ cancelText: '取消',
+ confirmText: '拨打',
+ success: (res) => {
+ if (res.confirm) {
+ wx.makePhoneCall({
+ phoneNumber: phoneNumber,
+ success: () => {
+ console.log('拨打电话成功');
+ },
+ fail: (err) => {
+ console.error('拨打电话失败', err);
+ wx.showToast({
+ title: '拨打电话失败',
+ icon: 'none'
+ });
+ }
+ });
+ }
+ }
+ });
+ }
+ },
+
+ // 我想要(预约)
+ onClickWantInDetail(e) {
+ console.log('我想要事件:', e);
+ const { id } = e.currentTarget.dataset;
+ if (!id) return;
+
+ // 从本地存储获取openid
+ const openid = wx.getStorageSync('openid');
+ console.log('openid:', openid);
+
+ // 检查是否已登录
+ if (!openid) {
+ // 如果未登录,显示授权登录弹窗
+ this.setData({ showAuthModal: true });
+ return;
+ }
+
+ // 获取已预约商品ID列表
+ let reservedGoodsIds = wx.getStorageSync('reservedGoodsIds') || [];
+
+ // 检查是否已经预约过
+ if (reservedGoodsIds.some(itemId => String(itemId) === String(id))) {
+ wx.showToast({
+ title: '您已经预约过该商品',
+ icon: 'none',
+ duration: 1500
+ });
+ return;
+ }
+
+ // 添加到已预约列表
+ reservedGoodsIds.push(id);
+ wx.setStorageSync('reservedGoodsIds', reservedGoodsIds);
+
+ // 更新页面状态
+ this.setData({
+ 'goodsDetail.isReserved': true
+ });
+
+ // 调用API记录预约
+ API.reserveProduct({ id: id })
+ .then(res => {
+ console.log('预约成功:', res);
+ wx.showToast({
+ title: '预约成功',
+ icon: 'success',
+ duration: 1500
+ });
+ })
+ .catch(err => {
+ console.error('预约失败:', err);
+ // 如果API调用失败,从本地列表中移除
+ reservedGoodsIds = reservedGoodsIds.filter(itemId => String(itemId) !== String(id));
+ wx.setStorageSync('reservedGoodsIds', reservedGoodsIds);
+ // 更新页面状态
+ this.setData({
+ 'goodsDetail.isReserved': false
+ });
+ wx.showToast({
+ title: '预约失败,请重试',
+ icon: 'none',
+ duration: 1500
+ });
+ });
+ },
+
+ // 返回上一页
+ goBack() {
+ wx.navigateBack();
+ }
+});
\ No newline at end of file
diff --git a/pages/goods-detail/goods-detail.json b/pages/goods-detail/goods-detail.json
new file mode 100644
index 0000000..7d505f9
--- /dev/null
+++ b/pages/goods-detail/goods-detail.json
@@ -0,0 +1,4 @@
+{
+ "navigationBarTitleText": "商品详情",
+ "enablePullDownRefresh": false
+}
\ No newline at end of file
diff --git a/pages/goods-detail/goods-detail.wxml b/pages/goods-detail/goods-detail.wxml
new file mode 100644
index 0000000..ca26da4
--- /dev/null
+++ b/pages/goods-detail/goods-detail.wxml
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{goodsDetail.name}}
+
+ 价格:
+ {{goodsDetail.price}}
+
+
+
+
+
+
+
+
+ 地区
+
+
+ {{goodsDetail.region || '暂无'}}
+
+
+
+
+ 规格
+
+
+ {{goodsDetail.spec || '暂无'}}
+
+
+
+
+
+
+ 蛋黄
+
+
+ {{goodsDetail.yolk || '暂无'}}
+
+
+
+
+ 斤重
+
+
+ {{goodsDetail.displayGrossWeight || '暂无'}}
+
+
+
+
+
+
+ 件数
+
+
+ {{goodsDetail.minOrder || '暂无'}}
+
+
+
+
+ 关注人数
+
+
+ {{goodsDetail.reservedCount || '0'}}
+
+
+
+
+
+
+
+ 联系信息
+
+
+ 👤
+ 联系人:
+ {{goodsDetail.product_contact || '暂无'}}
+
+
+ 📞
+
+ 联系电话:
+ {{goodsDetail.contact_phone || '暂无'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/goods-detail/goods-detail.wxss b/pages/goods-detail/goods-detail.wxss
new file mode 100644
index 0000000..cdf13cf
--- /dev/null
+++ b/pages/goods-detail/goods-detail.wxss
@@ -0,0 +1,514 @@
+/* pages/goods-detail/goods-detail.wxss */
+
+/* 页面容器 */
+.goods-detail-page {
+ min-height: 100vh;
+ background-color: #f5f7fa;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
+}
+
+/* 页面头部 */
+.page-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: 44px;
+ background: #ffffff;
+ padding: 0 16px;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 100;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+}
+
+.header-left {
+ width: 40px;
+}
+
+.header-center {
+ flex: 1;
+ text-align: center;
+}
+
+.header-title {
+ font-size: 17px;
+ font-weight: 600;
+ color: #000000;
+ letter-spacing: 0.5px;
+}
+
+.header-right {
+ width: 40px;
+ text-align: right;
+}
+
+.close-icon {
+ font-size: 28px;
+ color: #000000;
+ font-weight: 300;
+ line-height: 1;
+}
+
+/* 商品详情内容区域 */
+.goods-detail-content {
+ padding-top: 44px;
+ padding-bottom: 100px;
+}
+
+/* 商品图片轮播 */
+.goods-image-slider {
+ width: 100%;
+ height: 280px;
+ background: linear-gradient(135deg, #f0f4ff 0%, #d9e4ff 100%);
+ overflow: hidden;
+ position: relative;
+}
+
+.goods-image-slider::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background: linear-gradient(90deg, transparent, rgba(0,0,0,0.05), transparent);
+}
+
+.goods-image-slider swiper {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
+
+.goods-image-slider swiper-item {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 20px;
+ box-sizing: border-box;
+}
+
+.slider-image {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ border-radius: 8px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+ transition: transform 0.3s ease;
+}
+
+.slider-image:active {
+ transform: scale(0.98);
+}
+
+/* 商品基本信息 */
+.goods-info {
+ background-color: #ffffff;
+ padding: 20px 16px 16px;
+ position: relative;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+}
+
+.goods-info::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 16px;
+ right: 16px;
+ height: 1px;
+ background: linear-gradient(90deg, transparent, #f0f0f0, transparent);
+}
+
+.goods-name {
+ display: block;
+ font-size: 20px;
+ font-weight: 700;
+ color: #262626;
+ margin-bottom: 12px;
+ line-height: 1.4;
+ letter-spacing: -0.2px;
+}
+
+.goods-price {
+ display: flex;
+ align-items: baseline;
+ margin-bottom: 4px;
+}
+
+.price-symbol {
+ font-size: 15px;
+ color: #666;
+ margin-right: 4px;
+ font-weight: 500;
+}
+
+.price-value {
+ font-size: 28px;
+ color: #ff4d4f;
+ font-weight: 700;
+ letter-spacing: -0.5px;
+}
+
+.price-value::before {
+ content: '¥';
+ font-size: 20px;
+ margin-right: 2px;
+}
+
+/* 商品详细信息网格 */
+.info-grid {
+ background-color: #ffffff;
+ margin: 12px 0;
+ padding: 16px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
+}
+
+.info-row {
+ display: flex;
+ flex-wrap: wrap;
+ margin-bottom: 16px;
+ background: #f0f5ff;
+ border-radius: 10px;
+ overflow: hidden;
+ border: 1px solid #d6e4ff;
+}
+
+.info-row:last-child {
+ margin-bottom: 0;
+}
+
+.info-item {
+ flex: 0 0 50%;
+ display: flex;
+ flex-direction: column;
+ padding: 14px 16px;
+ box-sizing: border-box;
+ position: relative;
+}
+
+.info-item:nth-child(odd)::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 1px;
+ background: linear-gradient(180deg, transparent, #e8e8e8, transparent);
+}
+
+.info-label-container {
+ margin-bottom: 6px;
+}
+
+.info-label {
+ font-size: 13px;
+ color: #8c8c8c;
+ font-weight: 500;
+ text-transform: uppercase;
+ letter-spacing: 0.3px;
+}
+
+.info-value-container {
+ min-height: 24px;
+}
+
+.info-value {
+ font-size: 16px;
+ color: #000000d9;
+ font-weight: 600;
+ line-height: 1.3;
+}
+
+/* 联系信息 */
+.contact-info {
+ margin: 16px;
+ padding: 16px;
+ border-radius: 12px;
+ background: #ffffff;
+ border: 1px solid #d6e4ff;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+}
+
+.contact-label {
+ display: block;
+ font-size: 16px;
+ font-weight: 600;
+ color: #2f54eb;
+ margin-bottom: 16px;
+ text-align: center;
+}
+
+.contact-content {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.contact-item {
+ display: flex;
+ align-items: center;
+ padding: 8px 0;
+}
+
+.phone-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 0;
+}
+
+.contact-icon {
+ font-size: 16px;
+ margin-right: 10px;
+ flex-shrink: 0;
+ width: 20px;
+ text-align: center;
+ color: #2f54eb;
+}
+
+.user-icon {
+ font-size: 18px;
+}
+
+.phone-icon {
+ font-size: 18px;
+}
+
+.contact-label-text {
+ font-size: 14px;
+ color: #595959;
+ margin-right: 8px;
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+.contact-text {
+ font-size: 14px;
+ color: #262626;
+ flex-shrink: 0;
+ margin-right: 16px;
+}
+
+.phone-info {
+ display: flex;
+ flex-direction: row;
+ flex: 1;
+ align-items: center;
+}
+
+.phone-info .contact-label-text {
+ margin-bottom: 0;
+}
+
+.call-button {
+ padding: 0 24px;
+ height: 36px;
+ line-height: 36px;
+ font-size: 14px;
+ color: #ffffff;
+ background-color: #2f54eb;
+ border: 1px solid #2f54eb;
+ border-radius: 4px;
+ flex-shrink: 0;
+ box-shadow: 0 2px 8px rgba(47, 84, 235, 0.2);
+}
+
+.call-button:active {
+ background-color: #4066ff;
+ border-color: #4066ff;
+ box-shadow: 0 4px 12px rgba(47, 84, 235, 0.3);
+}
+
+.call-button:active {
+ background-color: #1d39c4;
+ transform: scale(0.98);
+}
+
+/* 操作按钮区域 */
+.action-buttons {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ padding: 16px;
+ background-color: #ffffff;
+ border-top: 1px solid #f0f0f0;
+ box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.06);
+ z-index: 99;
+ display: flex;
+ gap: 12px;
+}
+
+.bottom-button {
+ flex: 1;
+ height: 52px;
+ border-radius: 26px;
+ font-size: 18px;
+ font-weight: 700;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: none;
+ outline: none;
+ transition: all 0.3s ease;
+}
+
+.call-button.bottom-button {
+ background-color: #ffffff;
+ color: #2f54eb;
+ border: 2px solid #2f54eb;
+ box-shadow: none;
+}
+
+.want-button.bottom-button {
+ background: linear-gradient(135deg, #2f54eb 0%, #1d39c4 100%);
+ color: #ffffff;
+ box-shadow: 0 4px 12px rgba(47, 84, 235, 0.2);
+}
+
+.call-button.bottom-button:active {
+ background-color: #f0f4ff;
+ transform: scale(0.98);
+}
+
+.want-button.bottom-button:active {
+ transform: translateY(2px) scale(0.98);
+ box-shadow: 0 2px 6px rgba(47, 84, 235, 0.15);
+}
+
+.want-button.bottom-button[disabled] {
+ background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
+ color: #ffffff !important;
+ border: none;
+ box-shadow: 0 4px 12px rgba(82, 196, 26, 0.2);
+ opacity: 1;
+}
+
+.want-button.bottom-button[disabled]:active {
+ transform: none;
+ box-shadow: 0 4px 12px rgba(82, 196, 26, 0.3);
+}
+
+/* 图片预览弹窗 */
+.image-preview-container {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #000000;
+ z-index: 1000;
+ display: flex;
+ flex-direction: column;
+}
+
+.preview-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20px 16px;
+ color: #ffffff;
+ z-index: 10;
+ background: rgba(0, 0, 0, 0.5);
+ backdrop-filter: blur(10px);
+}
+
+.preview-close {
+ width: 44px;
+ height: 44px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(255, 255, 255, 0.1);
+ border-radius: 22px;
+ transition: all 0.2s ease;
+}
+
+.preview-close:active {
+ background: rgba(255, 255, 255, 0.2);
+ transform: scale(0.95);
+}
+
+.close-icon {
+ font-size: 24px;
+ color: #ffffff;
+ font-weight: 300;
+}
+
+.preview-indicator {
+ font-size: 15px;
+ color: #ffffff;
+ font-weight: 500;
+ opacity: 0.8;
+}
+
+.preview-swiper {
+ flex: 1;
+ width: 100%;
+}
+
+.preview-image-wrapper {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ padding: 20px;
+ box-sizing: border-box;
+}
+
+.preview-image {
+ width: 100%;
+ height: 100%;
+ max-width: 100%;
+ max-height: 100%;
+ object-fit: contain;
+ border-radius: 8px;
+}
+
+/* 添加一些微动画效果 */
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.goods-info,
+.info-grid,
+.contact-info {
+ animation: fadeIn 0.4s ease-out;
+}
+
+.info-grid {
+ animation-delay: 0.1s;
+}
+
+.contact-info {
+ animation-delay: 0.2s;
+}
+
+/* 响应式调整 */
+@media (min-height: 800px) {
+ .goods-image-slider {
+ height: 320px;
+ }
+
+ .goods-name {
+ font-size: 22px;
+ }
+
+ .price-value {
+ font-size: 32px;
+ }
+}
\ No newline at end of file