index.vue 11.4 KB
<template>
  <view class="relative w-full min-h-screen overflow-y-auto overflow-x-hidden bg-[#F9FAFB] pb-[200rpx]">
    <!-- Header Section -->
    <view class="absolute left-0 top-0 w-full h-[544rpx] z-0">
      <image class="w-full h-full" src="https://picsum.photos/seed/header/750/544" mode="aspectFill" />
      <view class="absolute inset-0 bg-gradient-to-b from-blue-600/80 to-transparent"></view>
    </view>

    <view class="relative z-10 px-[32rpx] pt-[180rpx]">
      <text class="block text-white text-[44rpx] font-bold mb-[40rpx] text-center">臻奇智荟圈</text>

      <!-- Search Bar -->
      <view
        class="flex items-center w-full h-[88rpx] bg-white/20 backdrop-blur-md rounded-full px-[32rpx] border border-white/30"
        @tap="go('/pages/search/index')"
      >
        <IconFont name="search" class="text-white/80 mr-[16rpx]" size="18" />
        <text class="text-white/80 text-[28rpx]">搜索培训资料、案例...</text>
      </view>
    </view>

    <!-- Main Content -->
    <view class="relative z-10 mt-[40rpx] px-[24rpx]">
      <!-- Grid Icons -->
      <view class="bg-white rounded-[32rpx] shadow-sm p-[40rpx] mb-[24rpx]">
        <view class="flex flex-wrap">
          <view
            class="flex flex-col items-center w-1/3 mb-[40rpx]"
            v-for="(item, index) in loopNav"
            :key="index"
            @tap="handleGridNav(item)"
          >
            <view class="w-[88rpx] h-[88rpx] rounded-[24rpx] bg-blue-50 flex items-center justify-center mb-[16rpx]">
              <IconFont :name="item.icon" class="text-blue-600" size="24" />
            </view>
            <text class="text-gray-800 text-[26rpx]">{{ item.name }}</text>
          </view>
        </view>
      </view>

      <!-- Hot Products -->
      <view class="bg-white rounded-[32rpx] shadow-sm p-[32rpx] mb-[24rpx]">
        <view class="flex justify-between items-center mb-[24rpx]">
          <text class="text-gray-900 text-[32rpx] font-bold">热卖产品</text>
          <view class="flex items-center text-blue-600" @tap="go('/pages/knowledge-base/index')">
            <text class="text-[26rpx] mr-[4rpx]">查看更多</text>
            <IconFont name="rectRight" size="12" />
          </view>
        </view>

        <!-- 动态产品列表 -->
        <view
          v-for="(product, index) in hotProducts"
          :key="product.id"
          class="bg-gray-50 rounded-[24rpx] p-[28rpx]"
          :class="{ 'mb-[24rpx]': index < hotProducts.length - 1 }"
        >
          <text class="block text-gray-800 text-[28rpx] font-medium mb-[20rpx]">{{ product.product_name }}</text>

          <!-- 动态标签 -->
          <view v-if="product.tags && product.tags.length" class="flex flex-wrap gap-[12rpx] mb-[24rpx]">
            <view
              v-for="tag in product.tags"
              :key="tag.id"
              class="rounded-[8rpx] px-[16rpx] py-[6rpx]"
              :style="{
                backgroundColor: tag.bg_color,
                color: tag.text_color
              }"
            >
              <text class="text-[22rpx]">{{ tag.name }}</text>
            </view>
          </view>

          <view class="flex justify-between gap-[24rpx]">
            <nut-button
              plain
              color="#2563EB"
              class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0 !border-blue-600"
              @tap="goToProductDetail(product.id)"
            >
              产品详情
            </nut-button>
            <nut-button
              color="#2563EB"
              class="flex-1 !h-[64rpx] !rounded-[16rpx] !text-[26rpx] !m-0"
              @tap="openPlanPopup(product.id)"
            >
              计划书
            </nut-button>
          </view>
        </view>
      </view>

      <!-- Hot Materials -->
      <view class="bg-white rounded-[32rpx] shadow-sm p-[32rpx] mb-[48rpx]">
        <view class="flex justify-between items-center mb-[24rpx]">
          <text class="text-gray-900 text-[32rpx] font-bold">本周热门资料</text>
          <view class="flex items-center text-blue-600" @tap="go('/pages/material-list/index')">
            <text class="text-[26rpx] mr-[4rpx]">查看更多</text>
            <IconFont name="rectRight" size="12" />
          </view>
        </view>

        <!-- Material List -->
        <view class="flex flex-col gap-[24rpx]">
          <!-- Material Items -->
          <view v-for="(item, index) in hotMaterials" :key="index"
            class="flex flex-row bg-white rounded-[24rpx] p-[24rpx] border border-gray-50">

            <!-- 左侧图标 -->
            <view class="w-[88rpx] h-[88rpx] mr-[24rpx] flex-shrink-0 flex items-center justify-center bg-gradient-to-br from-blue-50 to-blue-100 rounded-[20rpx] shadow-inner self-start">
              <image :src="getDocumentIcon(item.fileName)" class="w-[48rpx] h-[48rpx]" mode="aspectFit" />
            </view>

            <!-- 内容区域 -->
            <view class="flex-1 min-w-0">
              <text class="text-[#1F2937] text-[30rpx] font-bold leading-[1.4] line-clamp-2 mb-[8rpx]">
                {{ item.title }}
              </text>
              <view class="flex items-center gap-[12rpx] mb-[16rpx]">
                <view class="inline-flex items-center justify-center px-[12rpx] py-[4rpx] bg-gray-100 text-gray-500 text-[20rpx] font-medium rounded-[8rpx]">
                  <text>{{ getDocumentLabel(item.fileName) }}</text>
                </view>
                <text class="text-[#9CA3AF] text-[22rpx]">{{ item.learners }}</text>
              </view>

              <!-- 分割线 -->
              <view class="h-[1rpx] bg-gray-100 my-[20rpx]"></view>

              <!-- 操作按钮 -->
              <ListItemActions
                :viewable="true"
                :collectable="true"
                :deletable="false"
                :collected="item.collected"
                @view="onViewMaterial(item)"
                @collect="toggleMaterialCollect(item)"
              />
            </view>
          </view>
        </view>
      </view>
    </view>

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

    <!-- Plan Popup -->
    <PlanPopup v-model:visible="showPlanPopup">
      <SchemeA
        v-if="currentScheme === 'A'"
        @close="showPlanPopup = false"
        @submit="handlePlanSubmit"
      />
      <SchemeB
        v-if="currentScheme === 'B'"
        @close="showPlanPopup = false"
        @submit="handlePlanSubmit"
      />
    </PlanPopup>
  </view>
</template>

<script setup>
import { ref, shallowRef } from 'vue';
import Taro, { useShareAppMessage, useLoad, useDidShow } from '@tarojs/taro';
import { useGo } from '@/hooks/useGo';
import { useListItemClick, ListType } from '@/composables/useListItemClick';
import { getDocumentIcon, getDocumentLabel } from '@/utils/documentIcons';
import { useUserStore } from '@/stores/user';
import TabBar from '@/components/TabBar.vue';
import IconFont from '@/components/IconFont.vue';
import PlanPopup from '@/components/PlanPopup/index.vue';
import SchemeA from '@/components/PlanSchemes/SchemeA.vue';
import SchemeB from '@/components/PlanSchemes/SchemeB.vue';
import ListItemActions from '@/components/ListItemActions/index.vue';
import { listAPI } from '@/api/get_product';

// User Store
const userStore = useUserStore();

// Plan Popup State
const showPlanPopup = ref(false);
const currentScheme = ref('A');

const openPlanPopup = (scheme) => {
  currentScheme.value = scheme;
  showPlanPopup.value = true;
};

/**
 * 处理计划书提交
 * @description 模拟提交计划书,跳转到结果页面
 * @param {Object} formData - 表单数据
 */
const handlePlanSubmit = (formData) => {
  console.log(`方案${currentScheme.value}提交:`, formData);

  // 关闭弹窗
  showPlanPopup.value = false;

  // 模拟提交成功,跳转到结果页面
  // TODO: 后续接入真实API
  go('/pages/plan-submit-result/index', {
    success: 'true'
  });
};

// Grid navigation data with routes
const loopNav = shallowRef([
  { icon: 'order', name: '计划书', route: '/pages/plan/index' },
  { icon: 'my', name: '入职相关', route: '/pages/onboarding/index' },
  { icon: 'cart', name: '签单相关', route: '/pages/signing/index' },
  { icon: 'home', name: '家办相关', route: '/pages/family-office/index' },
  { icon: 'category', name: '产品知识库', route: '/pages/knowledge-base/index' },
  { icon: 'star', name: '客户服务', route: null }, // 待开发
]);

/**
 * 热卖产品数据
 *
 * @description 从服务器获取的热卖产品列表
 */
const hotProducts = ref([]);

/**
 * 获取热卖产品列表
 *
 * @description 调用产品列表API,recommend参数为hot
 */
const fetchHotProducts = async () => {
  try {
    const res = await listAPI({
      recommend: 'hot'
    });

    if (res.code === 1 && res.data && res.data.list) {
      hotProducts.value = res.data.list;
    }
  } catch (err) {
    console.error('获取热卖产品失败:', err);
  }
};

/**
 * 热门资料数据
 *
 * @description 本周热门资料列表数据,包含不同类型的文件
 */
const hotMaterials = ref([
  {
    title: '2024年保险市场趋势分析报告',
    learners: '256人学习',
    progress: '78%',
    collected: false,
    // PDF 文件
    fileName: '2024年保险市场趋势分析报告.pdf',
    downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/test.pdf'
  },
  {
    title: '高净值客户产品配置方案模板',
    learners: '189人学习',
    progress: '65%',
    collected: true,
    // Word 文件
    fileName: '高净值客户产品配置方案模板.docx',
    downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/test.pdf'
  },
  {
    title: '产品收益率测算表(2024版)',
    learners: '142人学习',
    progress: '52%',
    collected: false,
    // Excel 文件
    fileName: '产品收益率测算表.xlsx',
    downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/test.pdf'
  }
]);

// Navigation
const go = useGo();

/**
 * 使用文件列表点击处理器
 *
 * @description 配置为文件类型列表,点击时打开文件预览
 */
const { handleClick: onViewMaterial } = useListItemClick({
  listType: ListType.FILE,
  onAfterClick: (item) => {
    console.log('用户打开了资料:', item.title);
  }
});

/**
 * 切换资料收藏状态
 *
 * @description 切换热门资料的收藏状态
 * @param {Object} item - 资料项
 */
const toggleMaterialCollect = (item) => {
  item.collected = !item.collected;
  Taro.showToast({
    title: item.collected ? '已收藏' : '已取消收藏',
    icon: 'success',
    duration: 1000
  });
};

// Handle grid navigation click
const handleGridNav = (item) => {
  if (!item.route) {
    Taro.showToast({
      title: '功能开发中',
      icon: 'none',
      duration: 2000
    });
    return;
  }

  go(item.route);
};

// 跳转到产品详情页
const goToProductDetail = (productId) => {
  go('/pages/product-detail/index', {
    id: productId
  });
};

// Open webview with URL
const openWebView = (url) => {
  go('/pages/webview/index', {
    url: encodeURIComponent(url)
  });
};

// 页面加载时获取热卖产品
useLoad(() => {
  fetchHotProducts();
});

// 页面显示时刷新用户信息(更新 TabBar 红点状态)
useDidShow(() => {
  // 只在已登录状态下刷新
  if (userStore.isLoggedIn) {
    userStore.fetchUserInfo().catch(err => {
      console.error('刷新用户信息失败:', err);
    });
  }
});

useShareAppMessage(() => {
  return {
    title: '臻奇智荟圈',
    path: '/pages/index/index'
  };
});
</script>