index.vue
8.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
<!--
* @Date: 2026-01-30
* @Description: 产品详情页
-->
<template>
<div class="min-h-screen bg-[#F9FAFB] pb-[calc(160rpx+env(safe-area-inset-bottom))]">
<NavHeader title="产品详情" />
<!-- Banner Image -->
<div class="w-full h-[420rpx] relative">
<img
class="w-full h-full object-cover"
:src="bannerImage"
mode="aspectFill"
/>
<div class="absolute top-[32rpx] right-[32rpx] flex items-center gap-[16rpx]">
<!-- Hot Tag -->
<div class="bg-red-500 text-white text-[24rpx] px-[20rpx] py-[10rpx] rounded-full shadow-sm backdrop-blur-sm bg-opacity-90">
热卖
</div>
</div>
</div>
<!-- Product Header -->
<div class="relative mt-[-40rpx] bg-white rounded-t-[40rpx] px-[40rpx] pt-[48rpx] pb-[40rpx] z-10">
<div class="flex items-start justify-between mb-[24rpx]">
<h1 class="text-[#1F2937] text-[44rpx] font-bold flex-1 mr-[24rpx] leading-[1.2]">终身寿险尊享版</h1>
<!-- Favorite Button -->
<div
class="w-[72rpx] h-[72rpx] flex-shrink-0 flex items-center justify-center rounded-full bg-gray-50 active:scale-95 transition-transform"
@tap="toggleCollect"
>
<IconFont
:name="isCollected ? 'heart-fill' : 'heart'"
size="24"
:color="isCollected ? '#EF4444' : '#9CA3AF'"
/>
</div>
</div>
<div class="flex flex-wrap gap-[16rpx]">
<div class="px-[16rpx] py-[6rpx] bg-red-50 rounded-[8rpx]">
<span class="text-red-600 text-[24rpx]">收益率3.5%</span>
</div>
<div class="px-[16rpx] py-[6rpx] bg-orange-50 rounded-[8rpx]">
<span class="text-orange-600 text-[24rpx]">5年超值</span>
</div>
<div class="px-[16rpx] py-[6rpx] bg-green-50 rounded-[8rpx]">
<span class="text-green-600 text-[24rpx]">保证收益万能</span>
</div>
</div>
</div>
<!-- Stats Grid -->
<div class="px-[32rpx] mt-[24rpx]">
<div class="grid grid-cols-2 gap-[24rpx]">
<div
v-for="(item, index) in stats"
:key="index"
class="bg-white rounded-[24rpx] p-[32rpx] border border-gray-100"
>
<div class="text-[#6B7280] text-[24rpx] mb-[12rpx]">{{ item.label }}</div>
<div class="text-[#1F2937] text-[30rpx] font-medium">{{ item.value }}</div>
</div>
</div>
</div>
<!-- Product Features -->
<div class="px-[32rpx] mt-[32rpx]">
<div class="bg-white rounded-[32rpx] p-[40rpx]">
<h2 class="text-[#1F2937] text-[32rpx] font-bold mb-[32rpx]">产品特色</h2>
<div class="flex flex-col gap-[32rpx]">
<div v-for="(feature, index) in features" :key="index" class="flex items-start">
<div class="w-[48rpx] h-[48rpx] rounded-full bg-blue-50 flex items-center justify-center mr-[24rpx] flex-shrink-0">
<IconFont name="Check" size="14" color="#2563EB" />
</div>
<div class="flex-1">
<div class="text-[#1F2937] text-[28rpx] font-medium leading-[1.4]">{{ feature.title }}</div>
<div class="text-[#6B7280] text-[24rpx] mt-[8rpx] leading-[1.4]">{{ feature.desc }}</div>
</div>
</div>
</div>
</div>
</div>
<!-- Attachments -->
<div class="px-[32rpx] mt-[32rpx]">
<div class="bg-white rounded-[32rpx] p-[40rpx]">
<h2 class="text-[#1F2937] text-[32rpx] font-bold mb-[32rpx]">相关附件</h2>
<div class="flex flex-col gap-[24rpx]">
<div
v-for="(file, index) in files"
:key="index"
class="flex flex-col p-[24rpx] bg-gray-50 rounded-[16rpx]"
>
<div class="flex items-center justify-between mb-[8rpx]">
<div class="flex items-center flex-1 mr-[24rpx]">
<image
:src="getDocumentIcon(file.fileName)"
class="w-[48rpx] h-[48rpx] mr-[24rpx]"
mode="aspectFit"
/>
<div class="flex flex-col">
<span class="text-[#1F2937] text-[28rpx] font-medium mb-[4rpx] line-clamp-1">{{ file.name }}</span>
<span class="text-[#9CA3AF] text-[24rpx]">{{ file.size }}</span>
</div>
</div>
<IconFont name="eye" size="20" color="#2563EB" @tap="viewFile(file)" />
</div>
</div>
</div>
</div>
</div>
<!-- TabBar -->
<!-- <TabBar /> -->
</div>
</template>
<script setup>
import { ref } from 'vue'
import NavHeader from '@/components/NavHeader.vue'
import TabBar from '@/components/TabBar.vue'
import IconFont from '@/components/IconFont.vue'
import { useFileOperation } from '@/composables/useFileOperation'
import Taro, { useLoad } from '@tarojs/taro'
import { getDocumentIcon } from '@/utils/documentIcons'
const { viewFile } = useFileOperation()
// 接收页面参数
const productId = ref(null)
useLoad((options) => {
console.log('产品详情页参数:', options)
if (options.id) {
productId.value = options.id
console.log('产品ID:', productId.value)
// TODO: 根据 productId 获取产品详情数据
// 这里可以调用 API 获取对应产品的数据
fetchProductDetail(options.id)
} else {
console.warn('未接收到产品ID')
Taro.showToast({
title: '产品ID不存在',
icon: 'none',
duration: 2000
})
}
})
// 根据 ID 获取产品详情(模拟)
const fetchProductDetail = async (id) => {
console.log('正在获取产品ID', id, '的详情...')
// TODO: 实际调用 API
// const res = await getProductDetailAPI({ i: id })
// if (res.code === 1) {
// // 更新产品数据
// }
// 模拟根据不同ID显示不同产品
const productNames = {
'1': '家庭财富传承保障计划(分红)',
'2': '儿童教育金储备方案(分红)'
}
if (productNames[id]) {
console.log('产品名称:', productNames[id])
}
}
// Random banner image
const bannerImage = `https://picsum.photos/seed/${Math.floor(Math.random() * 1000)}/750/420`
const stats = ref([
{ label: '投保年龄', value: '30天-70周岁' },
{ label: '保障期限', value: '终身' },
{ label: '缴费方式', value: '3/5/10年交' },
{ label: '起投金额', value: '10000元起' }
])
const features = ref([
{ title: '身故保险金', desc: '赔付100%基本保额,给家人留爱不留债' },
{ title: '全残保险金', desc: '赔付100%基本保额,生活有保障' },
{ title: '保费豁免', desc: '确诊重疾后免交剩余保费,保障继续有效' },
{ title: '保单贷款', desc: '最高可贷现金价值80%,资金周转灵活' }
])
const files = ref([
{
name: '产品条款.pdf',
size: '2.3MB',
fileName: '产品条款.pdf',
downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/test.pdf',
iconName: 'order',
iconColor: '#EF4444',
fileType: 'pdf',
showTip: false,
tipText: ''
},
{
name: '投保须知.docx',
size: '1.8MB',
fileName: '投保须知.docx',
downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/%E7%94%A8%E6%88%B7%E5%8D%8F%E8%AE%AE%E6%9C%80%E7%BB%88v3.1.docx',
iconName: 'order',
iconColor: '#2563EB',
fileType: 'docx',
showTip: true,
tipText: 'Word 文档可能无法正常显示,建议打开后点击右上角"..."菜单选择"发送给朋友"保存到电脑查看'
},
{
name: '健康告知.pptx',
size: '3.2MB',
fileName: '健康告知.pptx',
downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/%E8%82%A1%E5%88%A4%E5%90%88%E5%8F%8B%E7%94%A8%E7%9F%A5%E8%AF%86%E8%AF%B4%E6%98%8E20240112110417414.pptx',
iconName: 'order',
iconColor: '#F59E0B',
fileType: 'pptx',
showTip: true,
tipText: 'PPT 文档可能无法正常显示,建议打开后点击右上角"..."菜单选择"发送给朋友"保存到电脑查看'
},
{
name: '保险责任说明.xlsx',
size: '1.5MB',
fileName: '保险责任说明.xlsx',
downloadUrl: 'https://cdn.ipadbiz.cn/manulife/document/%E7%94%A8%E6%88%B7%E5%8D%8F%E8%AE%AE%E6%9C%80%E7%BB%88v3.1.docx',
iconName: 'order',
iconColor: '#10B981',
fileType: 'xlsx',
showTip: true,
tipText: 'Excel 文档可能无法正常显示,建议打开后点击右上角"..."菜单选择"发送给朋友"保存到电脑查看'
}
])
// 收藏状态
const isCollected = ref(false)
// 切换收藏状态
const toggleCollect = () => {
isCollected.value = !isCollected.value
if (isCollected.value) {
Taro.showToast({
title: '已收藏',
icon: 'success'
})
} else {
Taro.showToast({
title: '已取消收藏',
icon: 'none'
})
}
}
</script>