hookehuyr

feat: 新增资料知识库页面

- 添加知识库页面路由配置及页面组件
- 实现基于标签的产品分类展示功能
- 使用 Tailwind CSS 构建响应式卡片布局
- 集成统一导航头和底部标签栏组件
- 更新项目变更日志记录新功能
...@@ -10,6 +10,12 @@ All notable changes to this project will be documented in this file. ...@@ -10,6 +10,12 @@ All notable changes to this project will be documented in this file.
10 - 重构图标使用方式:创建 `src/components/IconFont.vue` 组件封装 NutUI 图标库,支持通过字符串 `name` 属性配置图标,彻底移除 `markRaw` 逻辑,简化代码结构并符合用户偏好,同时保留了 SVG 图标的高清与高性能特性。 10 - 重构图标使用方式:创建 `src/components/IconFont.vue` 组件封装 NutUI 图标库,支持通过字符串 `name` 属性配置图标,彻底移除 `markRaw` 逻辑,简化代码结构并符合用户偏好,同时保留了 SVG 图标的高清与高性能特性。
11 11
12 ### Added 12 ### Added
13 +- 新增 "资料知识库" 页面 (`src/pages/knowledge-base`),还原设计稿布局
14 +- 使用 Tailwind CSS 实现页面样式,包括自定义 Tabs 和卡片布局
15 +- 调整卡片布局,将图片移至顶部,优化视觉体验
16 +- 集成 `NavHeader``TabBar` 组件,保持全站风格统一
17 +- 配置新页面路由至 `src/app.config.js`
18 +- 使用随机图片填充内容,模拟真实数据展示
13 - 创建通用导航头组件 `src/components/NavHeader.vue`,统一页面头部样式 19 - 创建通用导航头组件 `src/components/NavHeader.vue`,统一页面头部样式
14 - 重构 "入职相关"、"签单相关"、"家办相关" 页面,使用 `NavHeader` 组件替代硬编码的头部结构 20 - 重构 "入职相关"、"签单相关"、"家办相关" 页面,使用 `NavHeader` 组件替代硬编码的头部结构
15 - 新增 "家办相关" 页面 (`src/pages/family-office`),复用 "入职相关" 页面布局与样式 21 - 新增 "家办相关" 页面 (`src/pages/family-office`),复用 "入职相关" 页面布局与样式
......
...@@ -10,6 +10,7 @@ const pages = [ ...@@ -10,6 +10,7 @@ const pages = [
10 'pages/auth/index', 10 'pages/auth/index',
11 'pages/onboarding/index', 11 'pages/onboarding/index',
12 'pages/family-office/index', 12 'pages/family-office/index',
13 + 'pages/knowledge-base/index',
13 'pages/signing/index', 14 'pages/signing/index',
14 ] 15 ]
15 16
......
1 +export default definePageConfig({
2 + navigationBarTitleText: '资料知识库',
3 + navigationStyle: 'custom'
4 +})
1 +<template>
2 + <div class="min-h-screen bg-[#F9FAFB] pb-[calc(160rpx+env(safe-area-inset-bottom))]">
3 + <!-- Navigation Header -->
4 + <NavHeader title="资料知识库" />
5 +
6 + <!-- Content Area -->
7 + <div class="px-[40rpx] mt-[40rpx]">
8 +
9 + <!-- Filter Tabs -->
10 + <div class="flex overflow-x-auto no-scrollbar mb-[40rpx] space-x-[24rpx]">
11 + <div v-for="(tab, index) in tabs" :key="index"
12 + class="px-[32rpx] py-[16rpx] rounded-full text-[28rpx] whitespace-nowrap transition-colors"
13 + :class="activeTab === index ? 'bg-[#2563EB] text-white' : 'bg-[#F3F4F6] text-[#6B7280]'"
14 + @click="activeTab = index">
15 + {{ tab }}
16 + </div>
17 + </div>
18 +
19 + <!-- Section Title -->
20 + <div class="text-[#1F2937] text-[32rpx] font-bold mb-[24rpx]">
21 + {{ tabs[activeTab] }}
22 + </div>
23 +
24 + <!-- Product Grid -->
25 + <div class="flex flex-wrap justify-between">
26 + <!-- Card Item -->
27 + <div v-for="(item, index) in filteredProducts" :key="index"
28 + class="w-[48%] bg-white rounded-[24rpx] overflow-hidden mb-[24rpx] shadow-sm flex flex-col">
29 + <!-- Image Container -->
30 + <div class="relative w-full h-[200rpx]">
31 + <img :src="item.image" class="w-full h-full object-cover bg-gray-100" referrerpolicy="no-referrer" />
32 + <!-- Tag -->
33 + <div v-if="item.tag"
34 + class="absolute top-[12rpx] right-[12rpx] bg-red-500 text-white text-[20rpx] px-[12rpx] py-[4rpx] rounded-full">
35 + {{ item.tag }}
36 + </div>
37 + </div>
38 +
39 + <!-- Content -->
40 + <div class="p-[20rpx] flex flex-col flex-1">
41 + <!-- Title -->
42 + <div class="text-[#1F2937] text-[28rpx] font-medium leading-[1.4] line-clamp-2 mb-[16rpx]">
43 + {{ item.title }}
44 + </div>
45 +
46 + <!-- Desc -->
47 + <div class="mt-auto self-start bg-[#F3F4F6] text-[#6B7280] text-[22rpx] px-[12rpx] py-[4rpx] rounded-full">
48 + {{ item.desc }}
49 + </div>
50 + </div>
51 + </div>
52 + </div>
53 + </div>
54 +
55 + <!-- Tab Bar -->
56 + <TabBar current="home" />
57 + </div>
58 +</template>
59 +
60 +<script setup>
61 +import { ref, computed } from 'vue'
62 +import NavHeader from '@/components/NavHeader.vue'
63 +import TabBar from '@/components/TabBar.vue'
64 +
65 +const activeTab = ref(0)
66 +const tabs = ['全部产品', '人寿保险', '医疗保险', '意外保险']
67 +
68 +/**
69 + * Mock Data Generation
70 + * @returns {Array} List of products
71 + */
72 +const generateProducts = () => {
73 + return [
74 + { title: '终身寿险尊享版', tag: '热卖', desc: '5年超值', image: `https://picsum.photos/seed/1/200/200` },
75 + { title: '百万医疗保险计划', desc: '收益率3.5%', image: `https://picsum.photos/seed/2/200/200` },
76 + { title: '意外伤害保障计划', desc: '保证收益万能', image: `https://picsum.photos/seed/3/200/200` },
77 + { title: '分红型年金保险', tag: '热卖', desc: '保证收益万能', image: `https://picsum.photos/seed/4/200/200` },
78 + { title: '重大疾病保险', desc: '收益率4.2%', image: `https://picsum.photos/seed/5/200/200` },
79 + { title: '少儿教育金保险', tag: '热卖', desc: '教育专属', image: `https://picsum.photos/seed/6/200/200` },
80 + { title: '高端医疗服务', desc: '尊享服务', image: `https://picsum.photos/seed/7/200/200` },
81 + { title: '家庭财产保险', desc: '全家无忧', image: `https://picsum.photos/seed/8/200/200` },
82 + ]
83 +}
84 +
85 +const products = ref(generateProducts())
86 +
87 +const filteredProducts = computed(() => {
88 + if (activeTab.value === 0) return products.value
89 + // Mock filtering
90 + return products.value.filter((_, i) => (i + activeTab.value) % 2 === 0)
91 +})
92 +</script>
93 +
94 +<style>
95 +.no-scrollbar::-webkit-scrollbar {
96 + display: none;
97 +}
98 +
99 +.no-scrollbar {
100 + -ms-overflow-style: none;
101 + scrollbar-width: none;
102 +}
103 +</style>