Procházet zdrojové kódy

feat: 商品详情调试

liangan před 3 týdny
rodič
revize
70055602db

+ 1 - 1
env/.env

@@ -10,7 +10,7 @@ VITE_APP_PUBLIC_BASE=/
 # 登录页面
 VITE_LOGIN_URL = '/pages/login/index'
 # 第一个请求地址
-VITE_SERVER_BASEURL = 'http://192.168.0.101:8101'
+VITE_SERVER_BASEURL = 'http://192.168.0.100:8101'
 # 第二个请求地址
 VITE_API_SECONDARY_URL = 'https://ukw0y1.laf.run'
 

+ 1 - 6
src/components/product/product.vue

@@ -13,10 +13,6 @@ const props = defineProps({
     type: [Number, String],
     default: 260,
   },
-  flex: {
-    type: Boolean,
-    default: false,
-  },
   height: {
     type: [Number, String],
     default: 260,
@@ -33,7 +29,6 @@ function handleClick() {
 <template>
   <view
     class="flex flex-col items-center border-1 border-#E0E0E0 border-solid pb-8rpx"
-    :class="{ 'flex-[0.5]': flex }"
     @click="handleClick"
   >
     <view class="mb-10rpx" :style="{ maxWidth: Number.isFinite(width) ? `${width}rpx` : width, width: Number.isFinite(width) ? `${width}rpx` : width, height: Number.isFinite(height) ? `${height}rpx` : height }">
@@ -43,7 +38,7 @@ function handleClick() {
         mode="aspectFit"
       />
     </view>
-    <view class="box-border w-full px-8rpx text-24rpx">
+    <view class="box-border w-full px-14rpx text-24rpx">
       <view class="truncate">
         {{ item.storeName }}
       </view>

+ 3 - 3
src/pages/index/index.vue

@@ -172,12 +172,12 @@ onLoad(() => {
       </view>
       <view>
         <wd-tabs v-model="priceTab" :line-width="0" :line-height="0">
-          <block v-for="item in priceTabList" :key="item">
+          <template v-for="item in priceTabList" :key="item">
             <wd-tab :title="item.title" />
-          </block>
+          </template>
         </wd-tabs>
         <view class="grid grid-cols-2 gap-22rpx">
-          <product v-for="(item, index) in newProducts" :key="index" flex width="100%" :height="340" :item="item" @item-click="toPage('/pages/productDetail/productDetail', { id: item.id })" />
+          <product v-for="(item, index) in newProducts" :key="index" width="100%" :height="340" :item="item" @item-click="toPage('/pages/productDetail/productDetail', { id: item.id })" />
         </view>
       </view>
     </view>

+ 172 - 44
src/pages/productDetail/productDetail.vue

@@ -67,11 +67,6 @@ onMounted(() => {
 // 搜索结果
 // 轮播图
 const current = ref<number>(0)
-const swiperList = ref([
-  '/static/images/avatar.jpg',
-  '/static/images/vip-info-bg.png',
-  '/static/images/vip-level1.png',
-])
 
 function handleClick(e) {
   // console.log(e)
@@ -95,24 +90,149 @@ const avatarList = ref([
 const showSku = ref(false)
 
 const formData = ref({
-  colorSelect: 1,
   num: 1,
+  selectedSpecs: {}, // 存储选中的规格 { 颜色: '红色', 尺寸: 'M' }
+})
+
+const detail = ref<any>({
+  sliderImage: '',
+  flatPattern: '',
 })
+const matchedAttrValue = ref<any>({})
+
+// 计算选中规格的文案
+const selectedSpecsText = computed(() => {
+  if (!formData.value.selectedSpecs || Object.keys(formData.value.selectedSpecs).length === 0) {
+    return ''
+  }
+
+  // 按照attr的顺序生成文案
+  const specTexts = []
+  if (detail.value.attr) {
+    detail.value.attr.forEach((attr) => {
+      const selectedValue = formData.value.selectedSpecs[attr.attrName]
+      if (selectedValue) {
+        specTexts.push(`${attr.attrName}:${selectedValue}`)
+      }
+    })
+  }
+
+  return specTexts.length > 0 ? ` ${specTexts.join(',')}` : ''
+})
+// 选择规格方法
+function selectSpec(attrName, specValue) {
+  formData.value.selectedSpecs[attrName] = specValue
+
+  // 按照attr的顺序重新构建对象
+  const orderedSpecs = {}
+  if (detail.value.attr) {
+    detail.value.attr.forEach((attr) => {
+      if (formData.value.selectedSpecs[attr.attrName]) {
+        orderedSpecs[attr.attrName] = formData.value.selectedSpecs[attr.attrName]
+      }
+    })
+  }
+
+  // 打印当前选中的规格
+  const selectedSpecsJson = JSON.stringify(orderedSpecs)
+  console.log('当前选中规格:', selectedSpecsJson)
+
+  // 检查是否所有规格都已选中
+  const totalAttrs = detail.value.attr ? detail.value.attr.length : 0
+  const selectedAttrs = Object.keys(orderedSpecs).length
+
+  if (selectedAttrs === totalAttrs && totalAttrs > 0) {
+    // 所有规格都选中了,匹配 attrValue
+    matchedAttrValue.value = findMatchingAttrValue(orderedSpecs)
+    if (matchedAttrValue.value) {
+      console.log('匹配到的规格组合:', matchedAttrValue.value)
+      console.log('对应的图片:', matchedAttrValue.value.image)
+    }
+    else {
+      console.log('未找到匹配的规格组合')
+    }
+  }
+}
+
+// 匹配 attrValue 中对应的规格组合
+function findMatchingAttrValue(selectedSpecs) {
+  if (!detail.value.attrValue || !Array.isArray(detail.value.attrValue)) {
+    return null
+  }
+
+  return detail.value.attrValue.find((attrValue) => {
+    // 将 attrValue 的规格转换为对象进行比较
+    const attrValueSpecs = {}
+    if (attrValue.suk) {
+      // 假设 suk 格式类似 "红色,M" 或者其他分隔符
+      const sukParts = attrValue.suk.split(',')
+      if (detail.value.attr && sukParts.length === detail.value.attr.length) {
+        detail.value.attr.forEach((attr, index) => {
+          attrValueSpecs[attr.attrName] = sukParts[index].trim()
+        })
+      }
+    }
+
+    // 比较选中的规格和当前 attrValue 的规格是否完全匹配
+    const selectedKeys = Object.keys(selectedSpecs)
+    const attrValueKeys = Object.keys(attrValueSpecs)
+
+    if (selectedKeys.length !== attrValueKeys.length) {
+      return false
+    }
+
+    return selectedKeys.every(key => selectedSpecs[key] === attrValueSpecs[key])
+  })
+}
 
 function toPage() {
   uni.navigateTo({
     url: '/pages/productDetail/checkOut',
   })
 }
-const detail = ref<any>({
-  sliderImage: '',
-})
 async function queryDetail(id) {
   const res = await getDetail({ id })
   console.log(res)
   detail.value = res.data
+
+  // 默认选择第一个规格
+  setDefaultSpecs()
+
   paging.value.complete()
 }
+
+// 设置默认规格选择
+function setDefaultSpecs() {
+  if (detail.value.attr && detail.value.attr.length > 0) {
+    const defaultSpecs = {}
+
+    // 为每个规格属性选择第一个值
+    detail.value.attr.forEach((attr) => {
+      if (attr.attrImgValues && attr.attrImgValues.length > 0) {
+        defaultSpecs[attr.attrName] = attr.attrImgValues[0].name
+      }
+    })
+
+    // 更新选中的规格
+    formData.value.selectedSpecs = defaultSpecs
+
+    // 按照attr的顺序重新构建对象
+    const orderedSpecs = {}
+    detail.value.attr.forEach((attr) => {
+      if (formData.value.selectedSpecs[attr.attrName]) {
+        orderedSpecs[attr.attrName] = formData.value.selectedSpecs[attr.attrName]
+      }
+    })
+
+    // 匹配对应的规格组合
+    matchedAttrValue.value = findMatchingAttrValue(orderedSpecs)
+    if (matchedAttrValue.value) {
+      console.log('默认选中规格:', JSON.stringify(orderedSpecs))
+      console.log('默认匹配到的规格组合:', matchedAttrValue.value)
+      console.log('默认对应的图片:', matchedAttrValue.value.image)
+    }
+  }
+}
 const id = ref('')
 onLoad((options) => {
   console.log(options)
@@ -175,13 +295,13 @@ onLoad((options) => {
         <view class="line-clamp-2font-bold mb-16rpx">
           {{ detail.storeName }}
         </view>
-        <view class="flex items-center justify-between">
+        <view class="flex items-center justify-between" @click="showSku = true">
           <view>
             <text class="mr-20rpx">
-              Color
+              Selected
             </text>
             <text class="text-#757575">
-              Black Grey
+              {{ selectedSpecsText }}
             </text>
           </view>
           <wd-icon name="arrow-right" color="#7D7D7D" size="36rpx" />
@@ -243,21 +363,21 @@ onLoad((options) => {
           </wd-button>
         </view>
       </view>
-      <view class="bg-white p-24rpx">
-        <view
-          class="mb-20rpx flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty"
-        >
-          <text class="ml-10rpx text-32rpx">
-            Details
-          </text>
-        </view>
-        <view v-for="i in 3" :key="i">
-          <image
-            src="/static/images/avatar.jpg"
-            mode="widthFix"
-            class="w-full"
-          />
-        </view>
+    </view>
+    <view class="bg-white p-24rpx">
+      <view
+        class="mb-20rpx flex items-center before:h-45rpx before:w-8rpx before:rounded-4rpx before:bg-#FF3778 before:content-empty"
+      >
+        <text class="ml-10rpx text-32rpx">
+          Details
+        </text>
+      </view>
+      <view v-for="i in detail.flatPattern.split(',')" :key="i">
+        <image
+          :src="i"
+          mode="widthFix"
+          class="w-full"
+        />
       </view>
     </view>
     <template #bottom>
@@ -283,7 +403,7 @@ onLoad((options) => {
             </view>
             <CustomTooltip
               v-model:visible="showTip"
-              highlight-text1="$99.99"
+              :highlight-text1="`৳${detail.price}`"
               highlight-text2="$1.8"
             />
           </view>
@@ -298,12 +418,12 @@ onLoad((options) => {
     <view class="px-24rpx">
       <view class="mb-16rpx flex items-center gap-24rpx border-b-1 border-b-color-#E1E1E1 border-b-solid py-24rpx">
         <image
-          src="/static/images/avatar.jpg"
+          :src="matchedAttrValue.image"
           class="h-160rpx w-160rpx shrink-0"
         />
         <view class="flex-1">
           <view class="line-clamp-2 mb-32rpx text-28rpx">
-            SUCGLES for iPhone 14 Plus Case with MagSafe [Ultra Strong Magnetic]
+            {{ detail.storeName }}
           </view>
           <view class="flex items-baseline">
             <view class="text-#FF0010">
@@ -311,30 +431,38 @@ onLoad((options) => {
               </text>
               <text class="text-48rpx">
-                1000
+                {{ matchedAttrValue.price || 0 }}
               </text>
             </view>
             <view class="ml-20rpx text-28rpx text-#787878 line-through">
-              ৳1999
+              ৳{{ matchedAttrValue.otPrice || 0 }}
             </view>
           </view>
         </view>
       </view>
-      <view class="mb-24rpx border-b-1 border-b-color-#E1E1E1 border-b-solid pb-40rpx">
+      <view v-for="i in detail.attr" :key="i.id" class="mb-24rpx border-b-1 border-b-color-#E1E1E1 border-b-solid pb-40rpx">
         <view class="mb-12rpx text-32rpx">
-          Color
+          {{ i.attrName }}
         </view>
         <view class="grid grid-cols-4 gap-20rpx">
-          <view v-for="i in 5" :key="i" class="box-border flex flex-col border-1 border-transparent border-dashed bg-#F5F5F7 text-center" :style="{ borderColor: formData.colorSelect === i ? 'var(--wot-color-theme)' : '' }">
-            <view class="h-160rpx w-full">
-              <image
-                src="/static/images/avatar.jpg"
-                class="h-full w-full"
-                mode="aspectFit"
-              />
-            </view>
-            <view class="text-22rpx text-#757575">
-              Black
+          <view v-for="(e, j) in i.attrImgValues" :key="j" class="flex flex-col justify-end">
+            <view
+              class="box-border flex flex-col border-1 border-transparent border-dashed bg-#F5F5F7 text-center"
+              :style="{ borderColor: formData.selectedSpecs[i.attrName] === e.name ? 'var(--wot-color-theme)' : '' }"
+              @click="selectSpec(i.attrName, e.name)"
+            >
+              <view>
+                <view v-if="e.img" class="h-160rpx w-full">
+                  <image
+                    :src="e.img"
+                    class="h-full w-full"
+                    mode="aspectFit"
+                  />
+                </view>
+                <view class="text-22rpx text-#757575">
+                  {{ e.name }}
+                </view>
+              </view>
             </view>
           </view>
         </view>