index.vue 5.44 KB
<template>
  <div class="min-h-screen bg-[#F9FAFB] pb-[calc(160rpx+env(safe-area-inset-bottom))]">
    <!-- Navigation Header -->
    <NavHeader title="产品知识库" />

    <!-- Content Area -->
    <div class="px-[40rpx] mt-[40rpx]">

      <!-- Filter Tabs -->
      <div class="flex overflow-x-auto no-scrollbar mb-[40rpx] space-x-[24rpx]">
        <div v-for="(tab, index) in tabs" :key="index"
          class="px-[32rpx] py-[16rpx] rounded-full text-[28rpx] whitespace-nowrap transition-colors"
          :class="activeTab === index ? 'bg-[#2563EB] text-white' : 'bg-[#F3F4F6] text-[#6B7280]'"
          @click="activeTab = index">
          {{ tab }}
        </div>
      </div>

      <!-- Section Title -->
      <div class="text-[#1F2937] text-[32rpx] font-bold mb-[24rpx]">
        {{ tabs[activeTab] }}
      </div>

      <!-- Product Grid -->
      <div class="flex flex-wrap justify-between">
        <!-- Card Item -->
        <div v-for="(item, index) in filteredProducts" :key="index"
          class="w-[48%] bg-white rounded-[24rpx] overflow-hidden mb-[24rpx] shadow-sm flex flex-col active:scale-[0.98] transition-transform duration-200"
          @tap="handleProductClick(item)">
          <!-- Image Container -->
          <div class="relative w-full h-[200rpx]">
            <img :src="item.image" class="w-full h-full object-cover bg-gray-100" referrerpolicy="no-referrer" />
            <!-- Tag -->
            <div v-if="item.tag"
              class="absolute top-[12rpx] right-[12rpx] bg-red-500 text-white text-[20rpx] px-[12rpx] py-[4rpx] rounded-full">
              {{ item.tag }}
            </div>
          </div>

          <!-- Content -->
          <div class="p-[20rpx] flex flex-col flex-1">
            <!-- Title -->
            <div class="text-[#1F2937] text-[28rpx] font-medium leading-[1.4] line-clamp-2 mb-[16rpx]">
              {{ item.title }}
            </div>

            <!-- Desc -->
            <div class="mt-auto self-start text-[22rpx] px-[12rpx] py-[4rpx] rounded-full"
              :class="[getDescColor(item.id).bg, getDescColor(item.id).text]">
              {{ item.desc }}
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- Tab Bar -->
    <!-- <TabBar current="home" /> -->
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import NavHeader from '@/components/NavHeader.vue'
import TabBar from '@/components/TabBar.vue'
import { useListItemClick, ListType } from '@/composables/useListItemClick'

const activeTab = ref(0)
const tabs = ['全部产品', '人寿保险', '医疗保险', '意外保险']

/**
 * Desc 颜色调色板
 *
 * @description 为不同描述提供柔和的背景色和对应的文字颜色
 */
const descColorPalette = [
  { bg: 'bg-blue-50', text: 'text-blue-600' },      // 蓝色
  { bg: 'bg-green-50', text: 'text-green-600' },    // 绿色
  { bg: 'bg-purple-50', text: 'text-purple-600' },  // 紫色
  { bg: 'bg-orange-50', text: 'text-orange-600' },  // 橙色
  { bg: 'bg-pink-50', text: 'text-pink-600' },     // 粉色
  { bg: 'bg-teal-50', text: 'text-teal-600' },     // 青色
  { bg: 'bg-indigo-50', text: 'text-indigo-600' },  // 靛蓝色
  { bg: 'bg-red-50', text: 'text-red-600' },       // 红色
]

/**
 * 获取 desc 的颜色样式
 *
 * @description 根据 ID 获取固定的背景色和文字颜色
 * @param {number} id - 产品 ID
 * @returns {Object} 包含 bg 和 text 属性的颜色对象
 */
const getDescColor = (id) => {
  const index = id % descColorPalette.length
  return descColorPalette[index]
}

/**
 * 生成产品数据
 *
 * @description 生成模拟产品列表数据,每个产品包含唯一 id
 * @returns {Array} 产品列表
 */
const generateProducts = () => {
  return [
    { id: 1, title: '终身寿险尊享版', tag: '热卖', desc: '5年超值', image: `https://picsum.photos/seed/1/200/200` },
    { id: 2, title: '百万医疗保险计划', desc: '收益率3.5%', image: `https://picsum.photos/seed/2/200/200` },
    { id: 3, title: '意外伤害保障计划', desc: '保证收益万能', image: `https://picsum.photos/seed/3/200/200` },
    { id: 4, title: '分红型年金保险', tag: '热卖', desc: '保证收益万能', image: `https://picsum.photos/seed/4/200/200` },
    { id: 5, title: '重大疾病保险', desc: '收益率4.2%', image: `https://picsum.photos/seed/5/200/200` },
    { id: 6, title: '少儿教育金保险', tag: '热卖', desc: '教育专属', image: `https://picsum.photos/seed/6/200/200` },
    { id: 7, title: '高端医疗服务', desc: '尊享服务', image: `https://picsum.photos/seed/7/200/200` },
    { id: 8, title: '家庭财产保险', desc: '全家无忧', image: `https://picsum.photos/seed/8/200/200` },
  ]
}

const products = ref(generateProducts())

/**
 * 根据当前标签筛选产品
 *
 * @description 根据选中的标签页筛选显示对应产品
 */
const filteredProducts = computed(() => {
  if (activeTab.value === 0) return products.value
  // Mock filtering
  return products.value.filter((_, i) => (i + activeTab.value) % 2 === 0)
})

/**
 * 使用产品列表点击处理器
 *
 * @description 配置为产品类型列表,点击时跳转到产品详情页
 */
const { handleClick: handleProductClick } = useListItemClick({
  listType: ListType.PRODUCT,
  onAfterClick: (item) => {
    console.log('用户查看了产品:', item.title)
  }
})
</script>

<style>
.no-scrollbar::-webkit-scrollbar {
  display: none;
}

.no-scrollbar {
  -ms-overflow-style: none;
  scrollbar-width: none;
}
</style>