Просмотр исходного кода

feat(goods): 添加商品预览功能及相关API接口

- 新增商品预览详情API接口getProductPreview
- 添加商品预览页面路由配置
- 实现商品预览详情页面功能
- 在收藏夹中增加默认选项设置
- 修改库存计算逻辑,只显示总库存
- 更新后端API地址配置
肖路 2 дней назад
Родитель
Сommit
1d11661797

+ 8 - 0
src/api/goods/index.ts

@@ -18,6 +18,14 @@ export const getProductDetailByNo = (id: any) => {
   });
 };
 
+//商品预览详情
+export const getProductPreview = (id: any) => {
+  return request({
+    url: '/product/indexProduct/getProductPreview/' + id,
+    method: 'get'
+  });
+};
+
 //将商品添加到购物车
 export const addProductShoppingCart = (params: any) => {
   return request({

+ 6 - 0
src/router/index.ts

@@ -170,6 +170,12 @@ export const constantRoutes: RouteRecordRaw[] = [
         name: 'Item',
         meta: { title: '商品详情', nav: true, breadcrumbColor: '#F4F4F4' }
       },
+      {
+        path: '/itemPreview',
+        component: () => import('@/views/item/preview.vue'),
+        name: 'preview',
+        meta: { title: '商品预览详情', nav: true, breadcrumbColor: '#F4F4F4' }
+      },
       {
         path: '/cart',
         component: () => import('@/views/cart/index.vue'),

+ 16 - 7
src/views/enterprise/myCollection/index.vue

@@ -41,6 +41,12 @@
     <el-dialog v-model="categoryDialogVisible" title="添加分类" width="400px">
       <el-form ref="categoryFormRef" :model="categoryForm" :rules="categoryRules">
         <el-form-item prop="name"><el-input v-model="categoryForm.name" placeholder="请输入分类名称" /></el-form-item>
+        <el-form-item label="是否默认">
+          <el-radio-group v-model="categoryForm.isDefault">
+            <el-radio :value="0">是</el-radio>
+            <el-radio :value="1">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
       </el-form>
       <template #footer>
         <el-button @click="categoryDialogVisible = false">取消</el-button>
@@ -55,7 +61,7 @@ import { ref, reactive, watch, onMounted } from 'vue';
 import { Plus } from '@element-plus/icons-vue';
 import { ElMessage, ElMessageBox, type CheckboxValueType } from 'element-plus';
 import { PageTitle, StatusTabs, ProductCard, TablePagination } from '@/components';
-import { favoritesList, favoritesProductList, cancelProductCollect, addProductShoppingCart } from '@/api/goods/index';
+import { favoritesList, favoritesProductList, cancelProductCollect, addProductShoppingCart, addProductCollect } from '@/api/goods/index';
 
 const activeCategory = ref('all');
 const selectAll = ref(false);
@@ -64,7 +70,7 @@ const categoryFormRef = ref();
 const loading = ref(false);
 
 const categoryTabs = ref<any[]>([{ key: 'all', label: '全部' }]);
-const categoryForm = reactive({ name: '' });
+const categoryForm = reactive({ name: '', isDefault: 0 });
 const categoryRules = { name: [{ required: true, message: '请输入分类名称', trigger: 'blur' }] };
 const queryParams = reactive({ pageNum: 1, pageSize: 15, favoritesId: '' as any });
 const total = ref(0);
@@ -134,16 +140,19 @@ const handleSelectAll = (val: CheckboxValueType) => {
 };
 const handleAddCategory = () => {
   categoryForm.name = '';
+  categoryForm.isDefault = 0;
   categoryDialogVisible.value = true;
 };
 const handleSaveCategory = async () => {
   const valid = await categoryFormRef.value?.validate();
   if (!valid) return;
-  // TODO: 调用后端新增收藏夹接口
-  categoryTabs.value.push({ key: categoryForm.name, label: categoryForm.name });
-  ElMessage.success('添加成功');
-  categoryDialogVisible.value = false;
-  getFavoritesTabs();
+  addProductCollect({ title: categoryForm.name, isDefault: categoryForm.isDefault }).then((res: any) => {
+    if (res.code == 200) {
+      ElMessage.success('添加成功');
+      categoryDialogVisible.value = false;
+      getFavoritesTabs();
+    }
+  });
 };
 
 /** 单个加入购物车 */

+ 1 - 1
src/views/item/index.vue

@@ -334,7 +334,7 @@ const getInfo = (res: any) => {
   num.value = Number(res.data.minOrderQuantity || 1);
   dataInfo.value = res.data;
   dataInfo.value.minOrderQuantity = num.value;
-  dataInfo.value.allStock = Number(res.data.totalInventory || 0) + Number(res.data.nowInventory || 0) + Number(res.data.virtualInventory || 0);
+  dataInfo.value.allStock = Number(res.data.totalInventory || 0);
 };
 
 // 收藏

+ 923 - 0
src/views/item/preview.vue

@@ -0,0 +1,923 @@
+<template>
+  <div class="shop-pages">
+    <!-- 面包屑 -->
+    <div class="breadcrumb-bos">
+      <div class="home" @click="onPath('/index')">首页</div>
+      <el-icon style="margin: 2px 4px 0 4px" size="14"><ArrowRight /></el-icon>
+      <div class="home" @click="onPath('/search?type=1&topCategoryId=' + dataInfo.topCategoryId)">{{ dataInfo.topCategoryName }}</div>
+      <el-icon style="margin: 2px 4px 0 4px" size="14"><ArrowRight /></el-icon>
+      <div class="home" @click="onPath('/search?type=2&mediumCategoryId=' + dataInfo.mediumCategoryId)">{{ dataInfo.mediumCategoryName }}</div>
+      <el-icon style="margin: 2px 4px 0 4px" size="14"><ArrowRight /></el-icon>
+      <div class="home" @click="onPath('/search?type=3&bottomCategoryId=' + dataInfo.bottomCategoryId)">{{ dataInfo.bottomCategoryName }}</div>
+    </div>
+    <div class="shop-bos">
+      <div class="shop-left">
+        <!-- 图片展示 -->
+        <div class="images-bos">
+          <!-- 轮播 -->
+          <div class="carousel-bos">
+            <div class="left-carousel" v-if="carousel && carousel.length > 0">
+              <div v-for="(item, index) in carousel" :key="index" class="carousel-item" :class="carouselIndex == index ? 'hig' : ''">
+                <img :src="item" @click="onCarousel(1, index)" @mouseenter="onCarousel(1, index)" />
+              </div>
+            </div>
+            <div class="left-next flex-row-center" @click="onCarousel(2)">
+              <el-icon color="#6A7282" size="15">
+                <ArrowDown />
+              </el-icon>
+            </div>
+          </div>
+          <!-- 中间大图 -->
+          <div class="images-box" @mouseenter="showZoom = true" @mouseleave="showZoom = false" @mousemove="handleMouseMove">
+            <img v-if="carousel && carousel.length > 0" :src="carousel[carouselIndex]" alt="" class="images-img" ref="mainImageRef" />
+            <!-- 新增:放大镜遮罩层 -->
+            <div
+              v-show="showZoom"
+              class="zoom-mask"
+              :style="{
+                left: maskPos.x + 'px',
+                top: maskPos.y + 'px'
+              }"
+            ></div>
+          </div>
+        </div>
+        <!-- tab切换 -->
+        <div class="nav-bos flex-row-start">
+          <div @click="onNav(index)" v-for="(item, index) in navList" :key="index" :class="navIndex == index ? 'hig' : ''">{{ item.title }}</div>
+        </div>
+        <!-- 内容 -->
+        <div class="content-bos">
+          <!-- 商品详情 -->
+          <div class="pc-detail" v-if="navIndex == 0" v-html="dataInfo.pcDetail"></div>
+          <!-- 售后服务说明 -->
+          <div class="service" v-if="navIndex == 1">
+            <div class="service1">原厂正品保证承诺:</div>
+            <div>(1)所有商品均为符合国家有关商品质量的技术标准、服务标准、环保标准的原厂正品。</div>
+            <div>(2)所有商品保证是全新的货物,且来源于中华人民共和国或与中华人民共和国有正常贸易往来的国家或地区。</div>
+            <div>(3)所有商品均为自营,不涉及任何第三方店铺,充分保证产品来源,保证质量。</div>
+            <div>(4)所有商品均为原厂正品,如有假货,假一罚十。</div>
+            <div>(5)所有产品均严格按照国家三包标准执行。</div>
+            <div>(6)保证所售商品开具机打发票或电子发票。</div>
+            <div class="service1">厂家服务:</div>
+            <div>
+              本商品质保周期均为厂商对外公布的质保期或优易365对客户承诺的质保期为准。在此时间范围内可提交维修申请,具体请以厂家服务为准。
+              如因质量问题或故障,凭厂商维修中心或特约维修点的质量检测证明,享受7日内退货,15日内换货,15日以上在质保期内享受免费保修等三包服务!
+            </div>
+            <div>全国统一售后及服务电话:400-111-0027</div>
+            <div>(注:如优易365在商品介绍中有售后保障的说明,则此商品按照说明执行售后保障服务。)</div>
+            <div class="service1">服务承诺:</div>
+            <div>平台销售并发货的商品,均由平台提供发票和相应的售后服务。请您放心购买!</div>
+            <div>优易365确保客户收到的货物与商城图片、产地、附件说明完全一致。均为原厂正货!并且保证与当时市场上同样主流新品一致。</div>
+            <div class="service1">无忧退货:</div>
+            <div>
+              客户购买商品7日内(含7日,自客户收到商品之日起计算),在保证商品完好的前提下,可无理由退货。(部分商品除外,详情请见各商品细则)
+            </div>
+            <div>• 购买运费如何收取?</div>
+            <div class="service2">
+              单笔订单金额(不含运费)满88元免邮费;不满88元,每单收取10元运费。(港澳台地区需满500元免邮费;不满500元,每单收取30元运费)
+            </div>
+            <div>• 使用什么快递发货?</div>
+            <div class="service2">默认使用顺丰快递发货(个别商品使用其他快递)</div>
+            <div class="service2">配送范围覆盖全国大部分地区(港澳台地区除外)。</div>
+            <div>• 如何申请退货?</div>
+            <div class="service2">1.自收到商品之日起30日内,顾客可申请无忧退货,退款将原路返还,不同的银行处理时间不同,预计1-5个工作日到账;</div>
+            <div class="service2">2.内裤和食品等特殊商品无质量问题不支持退货;</div>
+            <div>3.退货流程:</div>
+            <div class="service2">确认收货-申请退货-客服审核通过-用户寄回商品-仓库签收验货-退款审核-退款完成;</div>
+            <div>
+              4.因优品汇产生的退货,如质量问题,退货邮费由优品汇承担,退款完成后会以现金券的形式报销。因客户个人原因产生的退货,购买和寄回运费由客户个人承担。
+            </div>
+          </div>
+          <el-empty v-if="navIndex == 2" description="暂无品牌信息" />
+          <el-empty v-if="navIndex == 3" description="暂无热门评价" />
+        </div>
+      </div>
+      <!-- 图片放大展示区域 -->
+      <div
+        class="image-zoom"
+        v-show="showZoom"
+        :style="{
+          backgroundImage: `url(${carousel[carouselIndex]})`,
+          backgroundPosition: `${bgPos.x} ${bgPos.y}`
+        }"
+      ></div>
+      <!-- 右边 -->
+      <div class="shop-right">
+        <div class="shop-info">
+          <div class="right-title">{{ dataInfo.itemName || '' }}</div>
+          <div class="right-price flex-row-between">
+            <div class="flex-row-start">
+              <div class="price1">
+                <span>¥</span>
+                <span style="font-size: 24px">{{ dataInfo.memberPrice || 0 }}</span>
+              </div>
+              <div class="price2">平台价</div>
+              <div class="price3">
+                <span>¥</span>
+                <span style="font-size: 16px">{{ dataInfo.marketPrice || 0 }}</span>
+              </div>
+            </div>
+            <div class="right-collect flex-row-start" @click="editCollection">
+              <el-icon v-if="collection" :size="16" color="#e7000b"><StarFilled /></el-icon>
+              <el-icon v-else class="icon-star" :size="16"><Star /></el-icon>
+              <span>{{ collection ? '已收藏' : '收藏' }}</span>
+            </div>
+          </div>
+          <div class="address flex-row-start">
+            <img class="address-img" src="@/assets/images/item1.png" alt="" />
+            <div style="margin-right: 10px">配送至</div>
+            <el-cascader v-model="regionCodes" :options="regionData as any" :placeholder="'请选择省/市/区'" style="width: 260px" />
+          </div>
+          <div class="specs-bos">
+            <div class="specs-list">
+              <div>商品编号</div>
+              <div class="specs-item hig">
+                {{ dataInfo.productNo }}
+              </div>
+              <div class="specs-box"></div>
+            </div>
+            <div class="specs-list">
+              <div>规格/型号</div>
+              <div class="specs-item hig">
+                {{ dataInfo.specificationsCode }}
+              </div>
+              <div class="specs-box"></div>
+            </div>
+            <div class="specs-list">
+              <div>UPC(69)条码</div>
+              <div class="specs-item hig">
+                {{ dataInfo.upcBarcode }}
+              </div>
+              <div class="specs-box"></div>
+            </div>
+            <div class="specs-list">
+              <div>定制</div>
+              <div class="specs-item hig">
+                {{ dataInfo.isCustomize == 1 ? '可定制' : '不可定制' }}
+              </div>
+              <div class="specs-box"></div>
+            </div>
+            <div class="specs-list">
+              <div>供货时间</div>
+              <div class="specs-item hig">
+                {{ dataInfo.deliveryTime || '' }}
+              </div>
+              <div class="specs-box"></div>
+            </div>
+            <div class="specs-list">
+              <div>商品库存</div>
+              <div class="specs-item hig">{{ dataInfo.allStock || 0 }} {{ dataInfo.unitName }}</div>
+              <div class="specs-box"></div>
+            </div>
+          </div>
+          <div class="number-bos">
+            <div>数量</div>
+            <div class="flex-row-start number-box">
+              <el-input-number v-model="num" :min="dataInfo.minOrderQuantity" :max="dataInfo.allStock" />
+              <div style="margin-left: 10px">提示:本产品起订为:{{ dataInfo.minOrderQuantity }}{{ dataInfo.unitName }}</div>
+            </div>
+          </div>
+        </div>
+        <div class="bnt-bos flex-row-start">
+          <el-button :disabled="dataInfo.allStock > 0 && dataInfo.productStatus == 1 ? false : true" class="btn" type="primary" @click="onCart"
+            >加入购物车</el-button
+          >
+          <span v-if="dataInfo.allStock <= 0" class="btn-text">(库存不足)</span>
+        </div>
+      </div>
+    </div>
+    <!-- 更多推荐 -->
+    <div class="goods-bos">
+      <div class="shop-more flex-row-between">
+        <div class="flex-row-start">
+          <div class="more1">更多推荐</div>
+          <div class="more2">甄选大牌,优质好品</div>
+        </div>
+      </div>
+      <div class="data-bos">
+        <div
+          v-for="(item, index) in recommendList"
+          :key="index"
+          class="data-list"
+          @click="onPath('/item?id=' + item.id + '&productNo=' + item.productNo)"
+        >
+          <img class="data-img" :src="item.productImage ? item.productImage.split(',')[0] : ''" alt="" />
+          <div class="data-title">{{ item.itemName || '' }}</div>
+          <div class="money">
+            <span class="money1">¥{{ item.memberPrice || '' }}</span>
+            <span class="money2">¥{{ item.marketPrice || '' }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 取消收藏 -->
+    <el-dialog
+      v-model="dialogVisible"
+      title="选择取消的收藏夹"
+      width="500"
+      :before-close="
+        () => {
+          dialogVisible = false;
+        }
+      "
+    >
+      <div>
+        <el-radio-group v-model="radio">
+          <el-radio v-for="(item, index) in favorites" :key="index" :value="item.id">{{ item.title }}</el-radio>
+        </el-radio-group>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="onCancel"> 确认 </el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import Cookies from 'js-cookie';
+import { regionData } from 'element-china-area-data';
+import { onPath } from '@/utils/siteConfig';
+import figure from '@/assets/images/figure.png';
+import {
+  getProductDetail,
+  addProductShoppingCart,
+  isProductInDefaultCollect,
+  addProductBrowsingHistory,
+  addProductCollect,
+  favoritesList,
+  cancelProductCollect,
+  getProductDetailByNo,
+  getProductPreview
+} from '@/api/goods/index';
+
+import { getRecommendedCategoryProductList } from '@/api/home/index-mro';
+
+const route = useRoute();
+const id = ref<any>(null);
+const dataInfo = ref<any>({});
+const carousel = ref<any>([figure]);
+const regionCodes = ref<any>([]);
+const radio = ref<any>(null);
+const favorites = ref<any>([]);
+const collection = ref<any>(null);
+const dialogVisible = ref<any>(false);
+const navList = ref<any>([{ title: '商品详情' }, { title: '售后服务说明' }, { title: '品牌信息' }, { title: '商品评价' }]);
+const navIndex = ref<any>(0);
+const recommendList = ref<any>([]);
+const num = ref<any>(1);
+const carouselIndex = ref<any>(0);
+const productNo = ref<any>(null);
+const token = Cookies.get('Authorization');
+
+watch(route, () => {
+  initData();
+});
+
+onMounted(() => {
+  initData();
+  nextTick(() => {
+    setTimeout(() => {
+      // 兼容不同浏览器的滚动元素
+      window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
+      document.documentElement.scrollTop = 0;
+      document.body.scrollTop = 0;
+    }, 0);
+  });
+});
+
+// 核心修复:统一初始化函数
+const initData = () => {
+  id.value = route.query.id ? route.query.id : null;
+  getInfoId();
+
+  if (token) {
+    console.log('收藏');
+    getCollection();
+    // 浏览记录
+    addProductBrowsingHistory(id.value).then((res) => {});
+  }
+};
+
+// 商品详情-id
+const getInfoId = () => {
+  getProductPreview(id.value).then((res) => {
+    if (res.code == 200) {
+      getInfo(res);
+    }
+  });
+};
+
+//商品详情-productNo
+const getInfoProductNo = () => {
+  getProductDetailByNo(productNo.value).then((res) => {
+    if (res.code == 200 && res.data) {
+      getInfo(res);
+    }
+  });
+};
+
+const getInfo = (res: any) => {
+  carousel.value = [figure];
+  if (res.data && res.data.imageUrl) {
+    carousel.value = res.data.imageUrl.split(',');
+    if (carousel.value.length > 5) {
+      carousel.value = carousel.value.slice(0, 5);
+    }
+  }
+  num.value = Number(res.data.minOrderQuantity || 1);
+  dataInfo.value = res.data;
+  dataInfo.value.minOrderQuantity = num.value;
+  dataInfo.value.allStock = Number(res.data.totalInventory || 0);
+};
+
+// 收藏
+const getCollection = () => {
+  isProductInDefaultCollect(id.value).then((res) => {
+    if (res.code == 200) {
+      collection.value = res.data;
+    }
+  });
+};
+
+//修改收藏
+const editCollection = () => {
+  if (collection.value) {
+    dialogVisible.value = true;
+    favoritesList(id.value).then((res) => {
+      if (res.code == 200) {
+        if (res.rows.length > 0) {
+          radio.value = res.rows[0].id;
+        }
+        favorites.value = res.rows;
+      }
+    });
+  } else {
+    // 添加
+    addProductCollect({ productId: id.value }).then((res) => {
+      if (res.code == 200) {
+        getCollection();
+      }
+    });
+  }
+};
+
+// 取消收藏
+const onCancel = () => {
+  cancelProductCollect({ productId: id.value, favoritesId: radio.value }).then((res) => {
+    if (res.code == 200) {
+      getCollection();
+      dialogVisible.value = false;
+    }
+  });
+};
+
+// 切换
+const onNav = (index: any) => {
+  navIndex.value = index;
+};
+
+const onCarousel = (type: number, index?: any) => {
+  if (type == 1) {
+    carouselIndex.value = index;
+  } else {
+    carouselIndex.value++;
+    if (carouselIndex.value > carousel.value.length - 1) {
+      carouselIndex.value = 0;
+    }
+  }
+};
+
+import { cartStore } from '@/store/modules/cart';
+const cart = cartStore();
+const onCart = () => {
+  addProductShoppingCart({
+    productId: id.value,
+    productNum: num.value
+  }).then((res) => {
+    if (res.code == 200) {
+      ElMessage.success('加入购物车成功');
+      cart.onCartCount();
+    }
+  });
+};
+
+getRecommendedCategoryProductList({}).then((res) => {
+  if (res.code == 200) {
+    recommendList.value = res.data;
+  }
+});
+
+// 新增:放大功能相关
+const showZoom = ref(false);
+const mainImageRef = ref<HTMLImageElement | null>(null);
+const bgPos = ref({ x: '0%', y: '0%' });
+// 新增:遮罩层位置
+const maskPos = ref({ x: 0, y: 0 });
+
+const handleMouseMove = (e: MouseEvent) => {
+  if (!mainImageRef.value) return;
+
+  const image = mainImageRef.value;
+  const rect = image.getBoundingClientRect();
+
+  // 获取容器尺寸 (images-box)
+  const width = rect.width;
+  const height = rect.height;
+
+  // 计算鼠标在图片内的相对坐标
+  const x = e.clientX - rect.left;
+  const y = e.clientY - rect.top;
+
+  // 遮罩层尺寸 (假设放大倍数为2,遮罩层大小为容器的一半,即正方形)
+  // 如果希望遮罩层固定大小,可以写死,例如 200px
+  const maskSize = width / 2;
+
+  // 计算遮罩层左上角的位置 (让鼠标位于遮罩层中心)
+  let maskX = x - maskSize / 2;
+  let maskY = y - maskSize / 2;
+
+  // 边界限制:确保遮罩层不超出图片范围
+  maskX = Math.max(0, Math.min(maskX, width - maskSize));
+  maskY = Math.max(0, Math.min(maskY, height - maskSize + 60));
+
+  // 更新遮罩层位置
+  maskPos.value = {
+    x: maskX,
+    y: maskY
+  };
+
+  // 计算背景图偏移百分比 (用于右侧放大区域)
+  // 背景图移动的比例 = 遮罩层移动的比例
+  // 注意:这里分母是 (总宽度 - 遮罩宽度),因为背景图移动范围也是这么多
+  const percentX = (maskX / (width - maskSize)) * 100;
+  const percentY = (maskY / (height - maskSize)) * 100;
+
+  bgPos.value = {
+    x: `${percentX}%`,
+    y: `${percentY}%`
+  };
+};
+</script>
+<style lang="scss" scoped>
+.shop-pages {
+  margin: 0 auto;
+
+  //面包屑
+  .breadcrumb-bos {
+    width: 1200px;
+    height: 44px;
+    margin: 0 auto;
+    display: flex;
+    align-items: center;
+    @media (min-width: 1600px) {
+      width: 1600px;
+    }
+    .home {
+      cursor: pointer;
+      font-size: 14px;
+      &:hover {
+        color: var(--el-color-primary);
+      }
+    }
+  }
+
+  .shop-bos {
+    display: flex;
+    gap: 0 15px;
+    position: relative;
+    padding-bottom: 15px;
+    //左边
+    .shop-left {
+      // 图片展示
+      .images-bos {
+        display: flex;
+        gap: 15px;
+        // 轮播
+        .carousel-bos {
+          width: 80px;
+
+          @media (min-width: 1600px) {
+            width: 112px;
+          }
+          // 左边的轮播
+          .left-carousel {
+            height: 494px;
+            overflow-y: auto;
+            @media (min-width: 1600px) {
+              height: 674px;
+            }
+
+            .carousel-item {
+              width: 80px;
+              height: 80px;
+              @media (min-width: 1600px) {
+                width: 112px;
+                height: 112px;
+              }
+              border-radius: 4px;
+              overflow: hidden;
+              margin-top: 10px;
+              cursor: pointer;
+
+              &:nth-of-type(1) {
+                margin-top: 0px;
+              }
+
+              &.hig {
+                border: 1px solid #e7000b;
+              }
+
+              img {
+                width: 100%;
+                height: 100%;
+              }
+            }
+          }
+          .left-next {
+            width: 80px;
+            @media (min-width: 1600px) {
+              width: 112px;
+            }
+            height: 36px;
+            background: #ffffff;
+            border-radius: 6px 6px 6px 6px;
+            margin-top: 10px;
+            cursor: pointer;
+          }
+        }
+        // 中间大图
+        .images-box {
+          width: 645px;
+          height: 540px;
+          border-radius: 5px;
+          overflow: hidden;
+          position: relative; /* 关键:作为遮罩层的定位父级 */
+          cursor: crosshair; /* 关键:鼠标变成十字准星 */
+
+          @media (min-width: 1600px) {
+            width: 860px;
+            height: 720px;
+          }
+
+          .images-img {
+            width: 100%;
+            height: 100%;
+            display: block;
+          }
+
+          // 新增:遮罩层样式
+          .zoom-mask {
+            position: absolute;
+            width: 50%; /* 对应2倍放大,宽高各占50%形成正方形 */
+            height: 50%; /* 如果图片不是正方形,这里可能需要调整以保持正方形,但通常跟随容器比例即可 */
+            background-color: rgba(255, 255, 255, 0.3); /* 半透明白色 */
+            border: 1px solid #ccc; /* 边框 */
+            pointer-events: none; /* 关键:让鼠标事件穿透遮罩层,避免闪烁 */
+            z-index: 5;
+          }
+        }
+      }
+      //tab切换
+      .nav-bos {
+        width: 740px;
+        height: 48px;
+        background: #f9fafb;
+        border: 1px solid #e5e7eb;
+        border-bottom: 0px solid #e5e7eb;
+        margin-top: 15px;
+        gap: 0 32px;
+        padding-left: 32px;
+        font-size: 16px;
+        color: #364153;
+        border-radius: 5px 5px 0 0;
+        position: sticky;
+        top: 0;
+        @media (min-width: 1600px) {
+          width: 987px;
+        }
+
+        div {
+          cursor: pointer;
+        }
+
+        .hig {
+          color: #101828;
+          font-weight: 600;
+        }
+      }
+      //内容
+      .content-bos {
+        width: 740px;
+        background-color: #ffffff;
+        padding: 20px 15px;
+        border: 1px solid #e5e7eb;
+        border-top: 0px solid #e5e7eb;
+        border-radius: 0 0 5px 5px;
+        min-height: calc(100vh - 853px);
+        @media (min-width: 1600px) {
+          width: 987px;
+          min-height: calc(100vh - 1033px);
+        }
+
+        //商品详情
+        .pc-detail {
+          width: 100%;
+          :deep(img) {
+            width: 100%;
+            display: block;
+            margin: 0;
+            padding: 0;
+          }
+          :deep(p) {
+            margin: 0;
+            padding: 0;
+          }
+          :deep(*) {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+          }
+        }
+        // 售后服务说明
+        .service {
+          width: 100%;
+          background: #ffffff;
+          div {
+            margin-bottom: 20px;
+            font-size: 14px;
+          }
+          .service1 {
+            font-weight: 600;
+          }
+          .service2 {
+            color: #999999;
+          }
+        }
+      }
+    }
+    //图片放大展示区域
+    .image-zoom {
+      width: 445px;
+      height: 540px;
+      background-color: #ffffff;
+      position: absolute;
+      z-index: 10;
+      right: 0;
+      border: 1px solid #e5e7eb;
+
+      // 新增/修改以下属性以实现放大
+      background-repeat: no-repeat;
+      background-size: 200%; // 放大2倍,可根据需求调整为 250% 等
+      background-position: 0 0; // 默认位置
+
+      @media (min-width: 1600px) {
+        width: 598px;
+        height: 720px;
+      }
+    }
+
+    .shop-right {
+      width: 445px;
+      background-color: #ffffff;
+      border-radius: 5px;
+      height: calc(100vh - 250px);
+      min-height: 580px;
+      position: sticky;
+      top: 0px;
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+      @media (min-width: 1600px) {
+        width: 598px;
+      }
+
+      .shop-info {
+        padding: 20px 20px 30px 20px;
+        .right-title {
+          min-height: 56px;
+          font-weight: 600;
+          font-size: 20px;
+          color: #101828;
+        }
+
+        .right-num {
+          font-size: 14px;
+          color: #6a7282;
+        }
+
+        .right-price {
+          margin-top: 10px;
+
+          .price1 {
+            font-size: 12px;
+            color: #e7000b;
+          }
+
+          .price2 {
+            width: 52px;
+            height: 21px;
+            background: #e7000b;
+            border-radius: 2px;
+            font-size: 12px;
+            color: #ffffff;
+            line-height: 21px;
+            text-align: center;
+            margin: 0 16px 0 8px;
+          }
+
+          .price3 {
+            font-size: 12px;
+            color: #6a7282;
+            text-decoration: line-through;
+          }
+
+          .right-collect {
+            font-size: 14px;
+            color: #6a7282;
+            cursor: pointer;
+            .icon-star {
+              margin-right: 4px;
+            }
+
+            img {
+              width: 12px;
+              height: 12px;
+              margin-right: 6px;
+            }
+          }
+        }
+
+        .address {
+          height: 44px;
+          width: 100%;
+          border-top: 1px solid #e5e7eb;
+          border-bottom: 1px solid #e5e7eb;
+          margin-top: 20px;
+          font-size: 14px;
+          color: #000000;
+
+          .address-img {
+            width: 16px;
+            height: 16px;
+            margin-right: 10px;
+            margin-top: 2px;
+          }
+
+          .address-text {
+            margin-left: 10px;
+            width: 138px;
+          }
+        }
+
+        .specs-bos {
+          .specs-list {
+            margin-top: 15px;
+            font-size: 14px;
+            color: #364153;
+            display: flex;
+            align-items: center;
+            .specs-item {
+              color: #6a7282;
+              margin-left: 10px;
+            }
+          }
+        }
+
+        .number-bos {
+          margin-top: 20px;
+          font-size: 14px;
+          color: #364153;
+
+          .number-box {
+            font-size: 14px;
+            color: #6a7282;
+            margin-top: 8px;
+          }
+        }
+      }
+      .bnt-bos {
+        width: 100%;
+        overflow: hidden;
+        padding: 0 20px 20px 20px;
+        .btn-text {
+          font-size: 12px;
+          color: #666666;
+          margin-left: 10px;
+        }
+
+        .btn {
+          flex: 1;
+          height: 44px;
+          line-height: 44px;
+          width: 100%;
+
+          &:nth-of-type(1) {
+            // background: #fcecf1;
+            // color: #e7000b;
+          }
+
+          &:nth-of-type(2) {
+            background: #e7000b;
+            color: #ffffff;
+          }
+        }
+      }
+    }
+  }
+  // 更多推荐
+  .goods-bos {
+    width: 1200px;
+    @media (min-width: 1600px) {
+      width: 1600px;
+    }
+    .shop-more {
+      width: 100%;
+      margin-top: 15px;
+
+      .more1 {
+        font-weight: 600;
+        font-size: 20px;
+        color: #101828;
+      }
+
+      .more2 {
+        font-size: 14px;
+        color: #364153;
+        margin-left: 10px;
+      }
+
+      .more3 {
+        font-size: 14px;
+        color: #364153;
+        margin-right: 6px;
+        cursor: pointer;
+      }
+    }
+    //数据
+    .data-bos {
+      display: flex;
+      gap: 20px;
+      flex-wrap: wrap;
+      margin-bottom: 40px;
+      margin-top: 24px;
+
+      .data-list {
+        width: 224px;
+        @media (min-width: 1600px) {
+          width: 250px;
+        }
+        background: #ffffff;
+        border-radius: 10px;
+        padding: 20px 20px 22px 20px;
+        cursor: pointer;
+
+        .data-img {
+          width: 184px;
+          height: 184px;
+          border-radius: 10px;
+        }
+
+        .data-title {
+          margin-top: 4px;
+          font-size: 14px;
+          color: #101828;
+          height: 40px;
+        }
+
+        .money {
+          margin-top: 4px;
+
+          .money1 {
+            font-size: 16px;
+            color: #e7000b;
+          }
+
+          .money2 {
+            font-size: 12px;
+            color: #99a1af;
+            text-decoration: line-through;
+            padding-left: 6px;
+          }
+        }
+
+        .data-cat {
+          width: 86px;
+          height: 26px;
+          background: #e7000b;
+          border-radius: 2px;
+          font-size: 14px;
+          color: #ffffff;
+          line-height: 26px;
+          text-align: center;
+          margin-top: 16px;
+        }
+      }
+    }
+  }
+}
+</style>
+
+<!-- 到这里就可以了 -->