优化两个小程序

This commit is contained in:
xuqiuyun
2025-09-18 18:23:00 +08:00
parent 57adeaa42c
commit e9f182f2d3
98 changed files with 23288 additions and 6079 deletions

View File

@@ -0,0 +1,72 @@
{
"pages": [
"pages/index/index",
"pages/login/login",
"pages/products/products",
"pages/product-detail/product-detail",
"pages/application/application",
"pages/application-result/application-result",
"pages/my/my",
"pages/policies/policies",
"pages/policy-detail/policy-detail",
"pages/claims/claims",
"pages/claim-detail/claim-detail"
],
"window": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "保险服务",
"navigationBarBackgroundColor": "#1890ff",
"backgroundColor": "#f5f5f5",
"backgroundTextStyle": "dark",
"enablePullDownRefresh": false,
"onReachBottomDistance": 50,
"restartStrategy": "homePage"
},
"tabBar": {
"color": "#666666",
"selectedColor": "#1890ff",
"backgroundColor": "#ffffff",
"borderStyle": "white",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/products/products",
"text": "产品"
},
{
"pagePath": "pages/my/my",
"text": "我的"
}
]
},
"networkTimeout": {
"request": 10000,
"downloadFile": 10000,
"uploadFile": 10000,
"connectSocket": 10000
},
"permission": {
"scope.userLocation": {
"desc": "获取位置信息用于投保地址定位和风险评估"
},
"scope.camera": {
"desc": "使用相机拍摄证件照片和事故现场照片"
},
"scope.album": {
"desc": "选择相册中的证件照片和事故现场照片"
},
"scope.record": {
"desc": "录制语音说明用于理赔申请"
}
},
"lazyCodeLoading": "requiredComponents",
"style": "v2",
"sitemapLocation": "sitemap.json",
"debug": false,
"requiredPrivateInfos": [
"getLocation"
]
}

View File

@@ -0,0 +1,181 @@
// pages/application-result/application-result.js
Page({
/**
* 页面的初始数据
*/
data: {
// 申请结果状态
resultStatus: 'success', // success 或 error
// 结果消息
resultMessage: '',
// 申请信息
applicationInfo: {},
// 温馨提示
tips: []
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('申请结果页加载', options)
const { productId, status } = options
this.setData({
resultStatus: status || 'success'
})
this.loadApplicationInfo(productId)
this.loadTips()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('申请结果页渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('申请结果页显示')
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('申请结果页隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('申请结果页卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
wx.stopPullDownRefresh()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '保险申请结果',
path: '/pages/application-result/application-result',
imageUrl: '/static/images/share-result.jpg'
}
},
/**
* 加载申请信息
*/
loadApplicationInfo(productId) {
console.log('加载申请信息:', productId)
// 模拟申请信息
const mockApplicationInfo = {
productName: '综合意外伤害保险',
applicationNo: 'APP' + Date.now(),
applicantName: '张先生',
coverageAmount: 50,
premium: 299,
applicationTime: this.formatDate(new Date())
}
// 根据状态设置不同的消息
let resultMessage = ''
if (this.data.resultStatus === 'success') {
resultMessage = '您的投保申请已成功提交,请及时完成保费支付以确保保单生效。'
} else {
resultMessage = '投保申请提交失败,请检查信息后重新申请或联系客服。'
}
this.setData({
applicationInfo: mockApplicationInfo,
resultMessage: resultMessage
})
},
/**
* 加载温馨提示
*/
loadTips() {
const tips = this.data.resultStatus === 'success' ? [
'请确保在24小时内完成保费支付逾期将自动取消申请',
'支付完成后电子保单将在1-3个工作日内生成',
'保单生效后,您可以在"我的保单"中查看详细信息',
'如有任何疑问请及时联系客服热线400-123-4567'
] : [
'请仔细检查填写的个人信息是否准确',
'确保身份证号和手机号格式正确',
'健康告知问题请如实回答',
'如问题持续存在,请联系客服协助处理'
]
this.setData({ tips })
},
/**
* 格式化日期
*/
formatDate(date) {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
},
/**
* 返回首页
*/
goToHome() {
console.log('返回首页')
wx.switchTab({
url: '/pages/index/index'
})
},
/**
* 查看保单
*/
goToPolicies() {
console.log('查看保单')
wx.switchTab({
url: '/pages/policies/policies'
})
},
/**
* 重新申请
*/
retryApplication() {
console.log('重新申请')
wx.navigateBack({
delta: 2
})
}
})

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "申请结果",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5"
}

View File

@@ -0,0 +1,129 @@
<!--pages/application-result/application-result.wxml-->
<view class="container">
<!-- 结果状态 -->
<view class="result-section">
<view class="result-icon {{resultStatus === 'success' ? 'success' : 'error'}}">
<text class="icon-text">{{resultStatus === 'success' ? '✓' : '✗'}}</text>
</view>
<view class="result-title">{{resultStatus === 'success' ? '申请提交成功' : '申请提交失败'}}</view>
<view class="result-desc">{{resultMessage}}</view>
</view>
<!-- 申请信息 -->
<view class="info-section">
<view class="section-title">申请信息</view>
<view class="info-card">
<view class="info-item">
<text class="info-label">产品名称</text>
<text class="info-value">{{applicationInfo.productName}}</text>
</view>
<view class="info-item">
<text class="info-label">申请单号</text>
<text class="info-value">{{applicationInfo.applicationNo}}</text>
</view>
<view class="info-item">
<text class="info-label">申请人</text>
<text class="info-value">{{applicationInfo.applicantName}}</text>
</view>
<view class="info-item">
<text class="info-label">保险金额</text>
<text class="info-value">¥{{applicationInfo.coverageAmount}}万</text>
</view>
<view class="info-item">
<text class="info-label">应缴保费</text>
<text class="info-value">¥{{applicationInfo.premium}}</text>
</view>
<view class="info-item">
<text class="info-label">申请时间</text>
<text class="info-value">{{applicationInfo.applicationTime}}</text>
</view>
</view>
</view>
<!-- 下一步操作 -->
<view class="action-section">
<view class="section-title">下一步操作</view>
<view class="action-list">
<view class="action-item" wx:if="{{resultStatus === 'success'}}">
<view class="action-icon">💳</view>
<view class="action-content">
<text class="action-title">支付保费</text>
<text class="action-desc">请在24小时内完成保费支付</text>
</view>
<view class="action-arrow">></view>
</view>
<view class="action-item" wx:if="{{resultStatus === 'success'}}">
<view class="action-icon">📄</view>
<view class="action-content">
<text class="action-title">查看保单</text>
<text class="action-desc">支付完成后可查看电子保单</text>
</view>
<view class="action-arrow">></view>
</view>
<view class="action-item" wx:if="{{resultStatus === 'error'}}">
<view class="action-icon">🔄</view>
<view class="action-content">
<text class="action-title">重新申请</text>
<text class="action-desc">检查信息后重新提交申请</text>
</view>
<view class="action-arrow">></view>
</view>
<view class="action-item">
<view class="action-icon">📞</view>
<view class="action-content">
<text class="action-title">联系客服</text>
<text class="action-desc">如有疑问请联系客服</text>
</view>
<view class="action-arrow">></view>
</view>
</view>
</view>
<!-- 温馨提示 -->
<view class="tips-section">
<view class="tips-title">温馨提示</view>
<view class="tips-list">
<view class="tip-item" wx:for="{{tips}}" wx:key="index">
<text class="tip-icon">💡</text>
<text class="tip-text">{{item}}</text>
</view>
</view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-actions">
<button
class="action-btn secondary"
bindtap="goToHome"
>
返回首页
</button>
<button
class="action-btn primary"
bindtap="goToPolicies"
wx:if="{{resultStatus === 'success'}}"
>
查看保单
</button>
<button
class="action-btn primary"
bindtap="retryApplication"
wx:if="{{resultStatus === 'error'}}"
>
重新申请
</button>
</view>
</view>

View File

@@ -0,0 +1,289 @@
/* pages/application-result/application-result.wxss */
.container {
background: #f5f5f5;
min-height: 100vh;
padding-bottom: 120rpx;
}
/* 结果状态 */
.result-section {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 60rpx 30rpx;
text-align: center;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.result-icon {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
margin: 0 auto 30rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 60rpx;
font-weight: bold;
}
.result-icon.success {
background: #f6ffed;
color: #52c41a;
border: 4rpx solid #b7eb8f;
}
.result-icon.error {
background: #fff2f0;
color: #ff4d4f;
border: 4rpx solid #ffccc7;
}
.icon-text {
font-size: 60rpx;
}
.result-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 15rpx;
}
.result-desc {
font-size: 26rpx;
color: #666;
line-height: 1.5;
}
/* 申请信息 */
.info-section {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 25rpx;
padding-bottom: 15rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.info-card {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
.info-item:last-child {
border-bottom: none;
}
.info-label {
font-size: 26rpx;
color: #666;
}
.info-value {
font-size: 26rpx;
color: #333;
font-weight: 500;
}
/* 下一步操作 */
.action-section {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.action-list {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.action-item {
display: flex;
align-items: center;
padding: 20rpx;
background: #f8f9fa;
border-radius: 12rpx;
transition: all 0.3s;
}
.action-item:active {
background: #e6f7ff;
transform: scale(0.98);
}
.action-icon {
font-size: 40rpx;
margin-right: 20rpx;
}
.action-content {
flex: 1;
}
.action-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 5rpx;
display: block;
}
.action-desc {
font-size: 24rpx;
color: #666;
}
.action-arrow {
font-size: 24rpx;
color: #999;
}
/* 温馨提示 */
.tips-section {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.tips-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 25rpx;
padding-bottom: 15rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.tips-list {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.tip-item {
display: flex;
align-items: flex-start;
font-size: 24rpx;
color: #666;
line-height: 1.5;
}
.tip-icon {
font-size: 24rpx;
margin-right: 15rpx;
margin-top: 2rpx;
}
.tip-text {
flex: 1;
}
/* 底部操作栏 */
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: white;
padding: 20rpx 30rpx;
border-top: 1rpx solid #e8e8e8;
display: flex;
gap: 20rpx;
z-index: 100;
}
.action-btn {
flex: 1;
height: 80rpx;
border-radius: 40rpx;
font-size: 28rpx;
font-weight: bold;
border: none;
transition: all 0.3s;
}
.action-btn.primary {
background: #1890ff;
color: white;
}
.action-btn.secondary {
background: #f0f0f0;
color: #666;
}
.action-btn::after {
border: none;
}
.action-btn:active {
transform: scale(0.95);
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.result-section,
.info-section,
.action-section,
.tips-section {
margin: 15rpx;
padding: 20rpx;
}
.bottom-actions {
padding: 15rpx 20rpx;
}
}
/* 动画效果 */
.result-icon {
animation: bounceIn 0.6s ease-out;
}
@keyframes bounceIn {
0% {
transform: scale(0.3);
opacity: 0;
}
50% {
transform: scale(1.05);
}
70% {
transform: scale(0.9);
}
100% {
transform: scale(1);
opacity: 1;
}
}
.action-item {
transition: all 0.3s ease;
}
.action-item:hover {
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}

View File

@@ -0,0 +1,384 @@
// pages/application/application.js
Page({
/**
* 页面的初始数据
*/
data: {
// 产品ID
productId: '',
// 产品信息
productInfo: {},
// 表单数据
formData: {
insuredName: '',
idCard: '',
phone: '',
gender: '',
birthDate: '',
beneficiaryRelationIndex: 0,
beneficiaryName: '',
coverageAmount: 10,
paymentMethod: 'annual',
healthAnswers: []
},
// 受益人关系选项
beneficiaryRelations: [
'本人',
'配偶',
'子女',
'父母',
'兄弟姐妹',
'其他'
],
// 保险金额选项
coverageAmounts: [10, 20, 30, 50, 100],
// 健康告知问题
healthQuestions: [
{
question: '您是否患有或曾经患有恶性肿瘤、白血病、淋巴瘤等恶性疾病?'
},
{
question: '您是否患有或曾经患有心脏病、心肌梗塞、冠心病、高血压等心血管疾病?'
},
{
question: '您是否患有或曾经患有糖尿病、甲状腺疾病、肾病等内分泌或代谢疾病?'
},
{
question: '您是否患有或曾经患有肝炎、肝硬化、肝癌等肝脏疾病?'
},
{
question: '您是否患有或曾经患有精神疾病、癫痫、帕金森病等神经系统疾病?'
}
],
// 计算出的保费
calculatedPremium: 0,
// 是否同意协议
agreeTerms: false,
// 是否可以提交
canSubmit: false,
// 加载状态
loading: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('投保申请页加载', options)
const { productId } = options
if (productId) {
this.setData({ productId })
this.loadProductInfo(productId)
} else {
wx.showToast({
title: '产品ID不能为空',
icon: 'none'
})
setTimeout(() => {
wx.navigateBack()
}, 1500)
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('投保申请页渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('投保申请页显示')
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('投保申请页隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('投保申请页卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
this.loadProductInfo(this.data.productId)
wx.stopPullDownRefresh()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '保险投保申请',
path: `/pages/application/application?productId=${this.data.productId}`,
imageUrl: '/static/images/share-application.jpg'
}
},
/**
* 加载产品信息
*/
loadProductInfo(productId) {
console.log('加载产品信息:', productId)
// 模拟产品信息
const mockProduct = {
id: productId,
name: '综合意外伤害保险',
subtitle: '全面保障,安心出行',
image: '/static/images/product-1.jpg',
minPremium: 99,
insurancePeriod: '1年'
}
this.setData({ productInfo: mockProduct })
this.calculatePremium()
},
/**
* 被保险人姓名输入
*/
onInsuredNameInput(e) {
this.setData({
'formData.insuredName': e.detail.value
})
this.validateForm()
},
/**
* 身份证号输入
*/
onIdCardInput(e) {
this.setData({
'formData.idCard': e.detail.value
})
this.validateForm()
},
/**
* 手机号输入
*/
onPhoneInput(e) {
this.setData({
'formData.phone': e.detail.value
})
this.validateForm()
},
/**
* 选择性别
*/
selectGender(e) {
const gender = e.currentTarget.dataset.gender
this.setData({
'formData.gender': gender
})
this.validateForm()
},
/**
* 出生日期选择
*/
onBirthDateChange(e) {
this.setData({
'formData.birthDate': e.detail.value
})
this.validateForm()
},
/**
* 受益人关系选择
*/
onBeneficiaryRelationChange(e) {
this.setData({
'formData.beneficiaryRelationIndex': e.detail.value
})
},
/**
* 受益人姓名输入
*/
onBeneficiaryNameInput(e) {
this.setData({
'formData.beneficiaryName': e.detail.value
})
},
/**
* 选择保险金额
*/
selectCoverageAmount(e) {
const amount = parseInt(e.currentTarget.dataset.amount)
this.setData({
'formData.coverageAmount': amount
})
this.calculatePremium()
},
/**
* 选择缴费方式
*/
selectPaymentMethod(e) {
const method = e.currentTarget.dataset.method
this.setData({
'formData.paymentMethod': method
})
this.calculatePremium()
},
/**
* 选择健康告知答案
*/
selectHealthAnswer(e) {
const { index, answer } = e.currentTarget.dataset
const healthAnswers = [...this.data.formData.healthAnswers]
healthAnswers[index] = answer
this.setData({
'formData.healthAnswers': healthAnswers
})
this.validateForm()
},
/**
* 协议同意状态改变
*/
onAgreeTermsChange(e) {
this.setData({
agreeTerms: e.detail.value
})
this.validateForm()
},
/**
* 计算保费
*/
calculatePremium() {
const { coverageAmount, paymentMethod } = this.data.formData
const { minPremium } = this.data.productInfo
// 简单的保费计算逻辑
let basePremium = minPremium * (coverageAmount / 10)
if (paymentMethod === 'monthly') {
basePremium = basePremium / 12
}
this.setData({
calculatedPremium: Math.round(basePremium)
})
},
/**
* 验证表单
*/
validateForm() {
const { formData } = this.data
const { agreeTerms } = this.data
// 验证必填字段
const requiredFields = [
formData.insuredName,
formData.idCard,
formData.phone,
formData.gender,
formData.birthDate
]
const isFormValid = requiredFields.every(field => field && field.trim() !== '')
// 验证健康告知是否全部回答
const healthAnswersComplete = this.data.healthQuestions.length === formData.healthAnswers.length &&
formData.healthAnswers.every(answer => answer !== undefined && answer !== '')
// 验证身份证号格式
const idCardValid = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/.test(formData.idCard)
// 验证手机号格式
const phoneValid = /^1[3-9]\d{9}$/.test(formData.phone)
const canSubmit = isFormValid && healthAnswersComplete && idCardValid && phoneValid && agreeTerms
this.setData({ canSubmit })
},
/**
* 提交投保申请
*/
submitApplication() {
const { canSubmit, loading } = this.data
if (!canSubmit || loading) return
this.setData({ loading: true })
console.log('提交投保申请:', this.data.formData)
// 模拟提交申请
setTimeout(() => {
this.setData({ loading: false })
wx.showToast({
title: '申请提交成功',
icon: 'success'
})
// 跳转到申请结果页面
setTimeout(() => {
wx.redirectTo({
url: `/pages/application-result/application-result?productId=${this.data.productId}&status=success`
})
}, 1500)
}, 2000)
},
/**
* 跳转到条款页面
*/
goToTerms() {
console.log('跳转到条款页面')
wx.navigateTo({
url: '/pages/terms/terms'
})
},
/**
* 跳转到隐私政策页面
*/
goToPrivacy() {
console.log('跳转到隐私政策页面')
wx.navigateTo({
url: '/pages/privacy/privacy'
})
}
})

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "投保申请",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5"
}

View File

@@ -0,0 +1,259 @@
<!--pages/application/application.wxml-->
<view class="container">
<!-- 产品信息卡片 -->
<view class="product-card">
<view class="product-info">
<image src="{{productInfo.image}}" class="product-img" mode="aspectFill" />
<view class="product-details">
<text class="product-name">{{productInfo.name}}</text>
<text class="product-desc">{{productInfo.subtitle}}</text>
<view class="price-info">
<text class="price">¥{{productInfo.minPremium}}</text>
<text class="price-unit">起</text>
</view>
</view>
</view>
</view>
<!-- 投保表单 -->
<view class="form-section">
<view class="section-title">投保信息</view>
<!-- 被保险人信息 -->
<view class="form-group">
<view class="group-title">被保险人信息</view>
<view class="form-item">
<text class="label required">姓名</text>
<input
class="form-input"
placeholder="请输入真实姓名"
value="{{formData.insuredName}}"
bindinput="onInsuredNameInput"
/>
</view>
<view class="form-item">
<text class="label required">身份证号</text>
<input
class="form-input"
placeholder="请输入身份证号码"
value="{{formData.idCard}}"
bindinput="onIdCardInput"
/>
</view>
<view class="form-item">
<text class="label required">手机号</text>
<input
class="form-input"
type="number"
placeholder="请输入手机号码"
value="{{formData.phone}}"
bindinput="onPhoneInput"
/>
</view>
<view class="form-item">
<text class="label required">性别</text>
<view class="radio-group">
<view
class="radio-item {{formData.gender === 'male' ? 'active' : ''}}"
bindtap="selectGender"
data-gender="male"
>
<text class="radio-icon">{{formData.gender === 'male' ? '●' : '○'}}</text>
<text class="radio-text">男</text>
</view>
<view
class="radio-item {{formData.gender === 'female' ? 'active' : ''}}"
bindtap="selectGender"
data-gender="female"
>
<text class="radio-icon">{{formData.gender === 'female' ? '●' : '○'}}</text>
<text class="radio-text">女</text>
</view>
</view>
</view>
<view class="form-item">
<text class="label required">出生日期</text>
<picker
mode="date"
value="{{formData.birthDate}}"
bindchange="onBirthDateChange"
class="date-picker"
>
<view class="picker-text">{{formData.birthDate || '请选择出生日期'}}</view>
</picker>
</view>
</view>
<!-- 受益人信息 -->
<view class="form-group">
<view class="group-title">受益人信息</view>
<view class="form-item">
<text class="label">受益人关系</text>
<picker
range="{{beneficiaryRelations}}"
value="{{formData.beneficiaryRelationIndex}}"
bindchange="onBeneficiaryRelationChange"
class="picker"
>
<view class="picker-text">{{beneficiaryRelations[formData.beneficiaryRelationIndex] || '请选择关系'}}</view>
</picker>
</view>
<view class="form-item">
<text class="label">受益人姓名</text>
<input
class="form-input"
placeholder="请输入受益人姓名"
value="{{formData.beneficiaryName}}"
bindinput="onBeneficiaryNameInput"
/>
</view>
</view>
<!-- 保险信息 -->
<view class="form-group">
<view class="group-title">保险信息</view>
<view class="form-item">
<text class="label required">保险金额</text>
<view class="amount-selector">
<view
class="amount-option {{formData.coverageAmount === item ? 'active' : ''}}"
wx:for="{{coverageAmounts}}"
wx:key="index"
bindtap="selectCoverageAmount"
data-amount="{{item}}"
>
<text class="amount-text">¥{{item}}万</text>
</view>
</view>
</view>
<view class="form-item">
<text class="label required">缴费方式</text>
<view class="radio-group">
<view
class="radio-item {{formData.paymentMethod === 'annual' ? 'active' : ''}}"
bindtap="selectPaymentMethod"
data-method="annual"
>
<text class="radio-icon">{{formData.paymentMethod === 'annual' ? '●' : '○'}}</text>
<text class="radio-text">年缴</text>
</view>
<view
class="radio-item {{formData.paymentMethod === 'monthly' ? 'active' : ''}}"
bindtap="selectPaymentMethod"
data-method="monthly"
>
<text class="radio-icon">{{formData.paymentMethod === 'monthly' ? '●' : '○'}}</text>
<text class="radio-text">月缴</text>
</view>
</view>
</view>
<view class="form-item">
<text class="label">保险期间</text>
<view class="period-info">
<text class="period-text">{{productInfo.insurancePeriod || '1年'}}</text>
</view>
</view>
</view>
<!-- 健康告知 -->
<view class="form-group">
<view class="group-title">健康告知</view>
<view class="health-notice">
<text class="notice-text">请如实回答以下问题,如有隐瞒可能影响理赔</text>
</view>
<view class="health-questions">
<view class="question-item" wx:for="{{healthQuestions}}" wx:key="index">
<text class="question-text">{{item.question}}</text>
<view class="answer-options">
<view
class="option-item {{formData.healthAnswers[index] === 'yes' ? 'active' : ''}}"
bindtap="selectHealthAnswer"
data-index="{{index}}"
data-answer="yes"
>
<text class="option-icon">{{formData.healthAnswers[index] === 'yes' ? '●' : '○'}}</text>
<text class="option-text">是</text>
</view>
<view
class="option-item {{formData.healthAnswers[index] === 'no' ? 'active' : ''}}"
bindtap="selectHealthAnswer"
data-index="{{index}}"
data-answer="no"
>
<text class="option-icon">{{formData.healthAnswers[index] === 'no' ? '●' : '○'}}</text>
<text class="option-text">否</text>
</view>
</view>
</view>
</view>
</view>
<!-- 保费计算 -->
<view class="premium-section">
<view class="premium-card">
<view class="premium-title">保费计算</view>
<view class="premium-details">
<view class="premium-item">
<text class="premium-label">保险金额:</text>
<text class="premium-value">¥{{formData.coverageAmount}}万</text>
</view>
<view class="premium-item">
<text class="premium-label">缴费方式:</text>
<text class="premium-value">{{formData.paymentMethod === 'annual' ? '年缴' : '月缴'}}</text>
</view>
<view class="premium-item total">
<text class="premium-label">应缴保费:</text>
<text class="premium-value">¥{{calculatedPremium}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 协议确认 -->
<view class="agreement-section">
<view class="agreement-item">
<checkbox
checked="{{agreeTerms}}"
bindchange="onAgreeTermsChange"
color="#1890ff"
/>
<text class="agreement-text">
我已阅读并同意
<text class="link" bindtap="goToTerms">《保险条款》</text>
<text class="link" bindtap="goToPrivacy">《隐私政策》</text>
</text>
</view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-actions">
<button
class="submit-btn {{canSubmit ? 'active' : 'disabled'}}"
bindtap="submitApplication"
disabled="{{!canSubmit || loading}}"
>
{{loading ? '提交中...' : '确认投保'}}
</button>
</view>
</view>
<!-- 加载状态 -->
<view wx:if="{{loading}}" class="loading-overlay">
<view class="loading-content">
<view class="loading-spinner"></view>
<text class="loading-text">处理中...</text>
</view>
</view>

View File

@@ -0,0 +1,454 @@
/* pages/application/application.wxss */
.container {
background: #f5f5f5;
min-height: 100vh;
padding-bottom: 120rpx;
}
/* 产品信息卡片 */
.product-card {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.product-info {
display: flex;
align-items: center;
gap: 20rpx;
}
.product-img {
width: 120rpx;
height: 120rpx;
border-radius: 12rpx;
}
.product-details {
flex: 1;
}
.product-name {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.product-desc {
font-size: 24rpx;
color: #666;
margin-bottom: 15rpx;
display: block;
}
.price-info {
display: flex;
align-items: baseline;
}
.price {
font-size: 36rpx;
font-weight: bold;
color: #ff4757;
}
.price-unit {
font-size: 24rpx;
color: #999;
margin-left: 5rpx;
}
/* 表单区域 */
.form-section {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 30rpx;
padding-bottom: 15rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.form-group {
margin-bottom: 40rpx;
}
.group-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 25rpx;
padding-left: 15rpx;
border-left: 4rpx solid #1890ff;
}
.form-item {
margin-bottom: 25rpx;
}
.label {
font-size: 26rpx;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.label.required::after {
content: '*';
color: #ff4757;
margin-left: 5rpx;
}
.form-input {
width: 100%;
height: 80rpx;
background: #f8f9fa;
border-radius: 12rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #333;
border: 2rpx solid transparent;
transition: all 0.3s;
}
.form-input:focus {
border-color: #1890ff;
background: white;
}
/* 单选按钮组 */
.radio-group {
display: flex;
gap: 30rpx;
}
.radio-item {
display: flex;
align-items: center;
padding: 15rpx 25rpx;
background: #f8f9fa;
border-radius: 25rpx;
border: 2rpx solid transparent;
transition: all 0.3s;
}
.radio-item.active {
background: #e6f7ff;
border-color: #1890ff;
}
.radio-icon {
font-size: 24rpx;
color: #1890ff;
margin-right: 10rpx;
}
.radio-text {
font-size: 26rpx;
color: #333;
}
/* 选择器 */
.picker, .date-picker {
width: 100%;
height: 80rpx;
background: #f8f9fa;
border-radius: 12rpx;
padding: 0 20rpx;
display: flex;
align-items: center;
border: 2rpx solid transparent;
transition: all 0.3s;
}
.picker:active, .date-picker:active {
border-color: #1890ff;
background: white;
}
.picker-text {
font-size: 28rpx;
color: #333;
}
/* 保险金额选择器 */
.amount-selector {
display: flex;
flex-wrap: wrap;
gap: 15rpx;
}
.amount-option {
padding: 15rpx 25rpx;
background: #f8f9fa;
border-radius: 25rpx;
border: 2rpx solid transparent;
transition: all 0.3s;
}
.amount-option.active {
background: #e6f7ff;
border-color: #1890ff;
}
.amount-text {
font-size: 26rpx;
color: #333;
}
/* 健康告知 */
.health-notice {
background: #fff7e6;
padding: 20rpx;
border-radius: 12rpx;
margin-bottom: 25rpx;
border-left: 4rpx solid #faad14;
}
.notice-text {
font-size: 24rpx;
color: #d48806;
line-height: 1.5;
}
.health-questions {
display: flex;
flex-direction: column;
gap: 25rpx;
}
.question-item {
padding: 25rpx;
background: #f8f9fa;
border-radius: 12rpx;
}
.question-text {
font-size: 26rpx;
color: #333;
margin-bottom: 15rpx;
display: block;
line-height: 1.5;
}
.answer-options {
display: flex;
gap: 20rpx;
}
.option-item {
display: flex;
align-items: center;
padding: 10rpx 20rpx;
background: white;
border-radius: 20rpx;
border: 2rpx solid #e8e8e8;
transition: all 0.3s;
}
.option-item.active {
background: #e6f7ff;
border-color: #1890ff;
}
.option-icon {
font-size: 20rpx;
color: #1890ff;
margin-right: 8rpx;
}
.option-text {
font-size: 24rpx;
color: #333;
}
/* 保费计算 */
.premium-section {
margin-top: 30rpx;
}
.premium-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 16rpx;
padding: 30rpx;
color: white;
}
.premium-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 20rpx;
text-align: center;
}
.premium-details {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.premium-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 26rpx;
}
.premium-item.total {
font-size: 32rpx;
font-weight: bold;
padding-top: 15rpx;
border-top: 1rpx solid rgba(255, 255, 255, 0.3);
}
.premium-label {
color: rgba(255, 255, 255, 0.9);
}
.premium-value {
color: white;
font-weight: bold;
}
/* 协议确认 */
.agreement-section {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.agreement-item {
display: flex;
align-items: flex-start;
font-size: 24rpx;
color: #666;
line-height: 1.5;
}
.agreement-text {
margin-left: 15rpx;
flex: 1;
}
.link {
color: #1890ff;
}
/* 底部操作栏 */
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: white;
padding: 20rpx 30rpx;
border-top: 1rpx solid #e8e8e8;
z-index: 100;
}
.submit-btn {
width: 100%;
height: 80rpx;
border-radius: 40rpx;
font-size: 32rpx;
font-weight: bold;
border: none;
transition: all 0.3s;
}
.submit-btn.active {
background: #1890ff;
color: white;
}
.submit-btn.disabled {
background: #f0f0f0;
color: #ccc;
}
.submit-btn::after {
border: none;
}
/* 加载状态 */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.loading-content {
background: white;
padding: 40rpx;
border-radius: 16rpx;
display: flex;
flex-direction: column;
align-items: center;
gap: 20rpx;
}
.loading-spinner {
width: 60rpx;
height: 60rpx;
border: 4rpx solid #f0f0f0;
border-top: 4rpx solid #1890ff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-text {
font-size: 28rpx;
color: #666;
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.product-card,
.form-section,
.agreement-section {
margin: 15rpx;
padding: 20rpx;
}
.bottom-actions {
padding: 15rpx 20rpx;
}
}
/* 动画效果 */
.radio-item,
.amount-option,
.option-item {
transition: all 0.3s ease;
}
.radio-item:active,
.amount-option:active,
.option-item:active {
transform: scale(0.95);
}

View File

@@ -0,0 +1,339 @@
// pages/claim-detail/claim-detail.js
Page({
/**
* 页面的初始数据
*/
data: {
// 理赔ID
claimId: '',
// 理赔信息
claimInfo: {}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('理赔详情页加载', options)
const { id } = options
if (id) {
this.setData({ claimId: id })
this.loadClaimDetail(id)
} else {
wx.showToast({
title: '理赔ID不能为空',
icon: 'none'
})
setTimeout(() => {
wx.navigateBack()
}, 1500)
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('理赔详情页渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('理赔详情页显示')
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('理赔详情页隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('理赔详情页卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
this.loadClaimDetail(this.data.claimId)
wx.stopPullDownRefresh()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '理赔详情',
path: `/pages/claim-detail/claim-detail?id=${this.data.claimId}`,
imageUrl: '/static/images/share-claim-detail.jpg'
}
},
/**
* 加载理赔详情
*/
loadClaimDetail(claimId) {
console.log('加载理赔详情:', claimId)
// 模拟理赔详情数据
const mockClaimInfo = this.getMockClaimDetail(claimId)
this.setData({ claimInfo: mockClaimInfo })
},
/**
* 获取模拟理赔详情数据
*/
getMockClaimDetail(claimId) {
const mockClaims = {
'1': {
id: '1',
claimNo: 'CLM20240115001',
claimType: '意外伤害理赔',
status: 'pending',
statusIcon: '⏳',
statusText: '待处理',
statusDesc: '您的理赔申请已提交,正在等待审核',
applicationTime: '2024-01-15 14:30',
claimAmount: 5000,
policyNo: 'POL20240115001',
insuredName: '张先生',
currentStep: 1,
progressSteps: [
{
title: '申请提交',
desc: '理赔申请已成功提交',
time: '2024-01-15 14:30'
},
{
title: '材料审核',
desc: '正在审核相关材料',
time: ''
},
{
title: '现场查勘',
desc: '安排现场查勘',
time: ''
},
{
title: '理赔决定',
desc: '做出理赔决定',
time: ''
},
{
title: '赔款支付',
desc: '完成赔款支付',
time: ''
}
],
accidentDesc: '在上班途中发生交通事故,导致右腿骨折',
accidentTime: '2024-01-15 08:30',
accidentLocation: '北京市朝阳区建国路与东三环交叉口',
hospitalName: '北京协和医院',
diagnosis: '右腿胫骨骨折,需要手术治疗',
materials: [
{
icon: '📄',
name: '理赔申请书',
status: 'uploaded',
statusText: '已上传'
},
{
icon: '🏥',
name: '医院诊断证明',
status: 'uploaded',
statusText: '已上传'
},
{
icon: '💰',
name: '医疗费用发票',
status: 'pending',
statusText: '待上传'
},
{
icon: '📋',
name: '事故证明',
status: 'uploaded',
statusText: '已上传'
}
],
records: [
{
time: '2024-01-15 14:30',
title: '申请提交',
desc: '用户提交理赔申请',
operator: '张先生'
},
{
time: '2024-01-15 15:00',
title: '申请确认',
desc: '系统确认收到申请',
operator: '系统'
}
]
},
'2': {
id: '2',
claimNo: 'CLM20240110002',
claimType: '医疗费用理赔',
status: 'processing',
statusIcon: '🔄',
statusText: '处理中',
statusDesc: '您的理赔申请正在处理中预计3-5个工作日完成',
applicationTime: '2024-01-10 09:15',
claimAmount: 12000,
policyNo: 'POL20240110002',
insuredName: '李女士',
currentStep: 3,
progressSteps: [
{
title: '申请提交',
desc: '理赔申请已成功提交',
time: '2024-01-10 09:15'
},
{
title: '材料审核',
desc: '材料审核已完成',
time: '2024-01-11 10:30'
},
{
title: '现场查勘',
desc: '正在安排现场查勘',
time: ''
},
{
title: '理赔决定',
desc: '做出理赔决定',
time: ''
},
{
title: '赔款支付',
desc: '完成赔款支付',
time: ''
}
],
accidentDesc: '因急性阑尾炎住院治疗',
accidentTime: '2024-01-08 20:00',
accidentLocation: '家中',
hospitalName: '北京友谊医院',
diagnosis: '急性阑尾炎,已进行阑尾切除手术',
materials: [
{
icon: '📄',
name: '理赔申请书',
status: 'uploaded',
statusText: '已上传'
},
{
icon: '🏥',
name: '医院诊断证明',
status: 'uploaded',
statusText: '已上传'
},
{
icon: '💰',
name: '医疗费用发票',
status: 'uploaded',
statusText: '已上传'
},
{
icon: '📋',
name: '住院病历',
status: 'uploaded',
statusText: '已上传'
}
],
records: [
{
time: '2024-01-10 09:15',
title: '申请提交',
desc: '用户提交理赔申请',
operator: '李女士'
},
{
time: '2024-01-10 10:00',
title: '申请确认',
desc: '系统确认收到申请',
operator: '系统'
},
{
time: '2024-01-11 10:30',
title: '材料审核',
desc: '材料审核通过',
operator: '审核员'
}
]
}
}
return mockClaims[claimId] || mockClaims['1']
},
/**
* 预览材料
*/
previewMaterial(e) {
const index = e.currentTarget.dataset.index
const material = this.data.claimInfo.materials[index]
console.log('预览材料:', material.name)
wx.showToast({
title: '材料预览功能开发中',
icon: 'none'
})
},
/**
* 联系客服
*/
contactService() {
console.log('联系客服')
wx.showModal({
title: '联系客服',
content: '客服电话400-123-4567\n工作时间9:00-18:00',
confirmText: '拨打电话',
success: (res) => {
if (res.confirm) {
wx.makePhoneCall({
phoneNumber: '400-123-4567'
})
}
}
})
},
/**
* 提交补充材料
*/
submitSupplement() {
console.log('提交补充材料')
wx.navigateTo({
url: '/pages/supplement-materials/supplement-materials?claimId=' + this.data.claimId
})
},
/**
* 返回上一页
*/
goBack() {
console.log('返回上一页')
wx.navigateBack()
}
})

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "理赔详情",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5"
}

View File

@@ -0,0 +1,170 @@
<!--pages/claim-detail/claim-detail.wxml-->
<view class="container">
<!-- 理赔状态卡片 -->
<view class="status-card">
<view class="status-icon {{claimInfo.status}}">
<text class="icon-text">{{claimInfo.statusIcon}}</text>
</view>
<view class="status-content">
<text class="status-title">{{claimInfo.statusText}}</text>
<text class="status-desc">{{claimInfo.statusDesc}}</text>
</view>
</view>
<!-- 理赔基本信息 -->
<view class="info-section">
<view class="section-title">理赔信息</view>
<view class="info-card">
<view class="info-item">
<text class="info-label">理赔单号</text>
<text class="info-value">{{claimInfo.claimNo}}</text>
</view>
<view class="info-item">
<text class="info-label">理赔类型</text>
<text class="info-value">{{claimInfo.claimType}}</text>
</view>
<view class="info-item">
<text class="info-label">申请时间</text>
<text class="info-value">{{claimInfo.applicationTime}}</text>
</view>
<view class="info-item">
<text class="info-label">理赔金额</text>
<text class="info-value amount">¥{{claimInfo.claimAmount}}</text>
</view>
<view class="info-item">
<text class="info-label">保单号</text>
<text class="info-value">{{claimInfo.policyNo}}</text>
</view>
<view class="info-item">
<text class="info-label">被保险人</text>
<text class="info-value">{{claimInfo.insuredName}}</text>
</view>
</view>
</view>
<!-- 理赔进度 -->
<view class="progress-section">
<view class="section-title">理赔进度</view>
<view class="progress-timeline">
<view
class="timeline-item {{index <= claimInfo.currentStep ? 'active' : ''}}"
wx:for="{{claimInfo.progressSteps}}"
wx:key="index"
>
<view class="timeline-dot">
<text class="dot-icon">{{index < claimInfo.currentStep ? '✓' : (index + 1)}}</text>
</view>
<view class="timeline-content">
<text class="timeline-title">{{item.title}}</text>
<text class="timeline-desc">{{item.desc}}</text>
<text class="timeline-time" wx:if="{{item.time}}">{{item.time}}</text>
</view>
</view>
</view>
</view>
<!-- 理赔详情 -->
<view class="detail-section">
<view class="section-title">理赔详情</view>
<view class="detail-card">
<view class="detail-item">
<text class="detail-label">事故描述</text>
<text class="detail-value">{{claimInfo.accidentDesc}}</text>
</view>
<view class="detail-item">
<text class="detail-label">事故发生时间</text>
<text class="detail-value">{{claimInfo.accidentTime}}</text>
</view>
<view class="detail-item">
<text class="detail-label">事故发生地点</text>
<text class="detail-value">{{claimInfo.accidentLocation}}</text>
</view>
<view class="detail-item">
<text class="detail-label">医院名称</text>
<text class="detail-value">{{claimInfo.hospitalName}}</text>
</view>
<view class="detail-item">
<text class="detail-label">诊断结果</text>
<text class="detail-value">{{claimInfo.diagnosis}}</text>
</view>
</view>
</view>
<!-- 相关材料 -->
<view class="materials-section">
<view class="section-title">相关材料</view>
<view class="materials-list">
<view class="material-item" wx:for="{{claimInfo.materials}}" wx:key="index">
<view class="material-icon">{{item.icon}}</view>
<view class="material-info">
<text class="material-name">{{item.name}}</text>
<text class="material-status {{item.status}}">{{item.statusText}}</text>
</view>
<view class="material-actions">
<button
class="action-btn small"
bindtap="previewMaterial"
data-index="{{index}}"
>
查看
</button>
</view>
</view>
</view>
</view>
<!-- 处理记录 -->
<view class="records-section" wx:if="{{claimInfo.records.length > 0}}">
<view class="section-title">处理记录</view>
<view class="records-list">
<view class="record-item" wx:for="{{claimInfo.records}}" wx:key="index">
<view class="record-time">{{item.time}}</view>
<view class="record-content">
<text class="record-title">{{item.title}}</text>
<text class="record-desc">{{item.desc}}</text>
</view>
<view class="record-operator">{{item.operator}}</view>
</view>
</view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-actions">
<button
class="action-btn secondary"
bindtap="goBack"
>
返回
</button>
<button
class="action-btn primary"
bindtap="contactService"
wx:if="{{claimInfo.status === 'pending' || claimInfo.status === 'processing'}}"
>
联系客服
</button>
<button
class="action-btn primary"
bindtap="submitSupplement"
wx:if="{{claimInfo.status === 'pending'}}"
>
补充材料
</button>
</view>
</view>

View File

@@ -0,0 +1,414 @@
/* pages/claim-detail/claim-detail.wxss */
.container {
background: #f5f5f5;
min-height: 100vh;
padding-bottom: 120rpx;
}
/* 理赔状态卡片 */
.status-card {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 40rpx 30rpx;
display: flex;
align-items: center;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.status-icon {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 30rpx;
font-size: 50rpx;
font-weight: bold;
}
.status-icon.pending {
background: #fff7e6;
color: #d48806;
}
.status-icon.processing {
background: #e6f7ff;
color: #1890ff;
}
.status-icon.completed {
background: #f6ffed;
color: #52c41a;
}
.status-icon.rejected {
background: #fff2f0;
color: #ff4d4f;
}
.icon-text {
font-size: 50rpx;
}
.status-content {
flex: 1;
}
.status-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.status-desc {
font-size: 24rpx;
color: #666;
line-height: 1.4;
}
/* 信息区域 */
.info-section,
.progress-section,
.detail-section,
.materials-section,
.records-section {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 25rpx;
padding-bottom: 15rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.info-card,
.detail-card {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.info-item,
.detail-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
.info-item:last-child,
.detail-item:last-child {
border-bottom: none;
}
.info-label,
.detail-label {
font-size: 26rpx;
color: #666;
min-width: 150rpx;
}
.info-value,
.detail-value {
font-size: 26rpx;
color: #333;
font-weight: 500;
text-align: right;
flex: 1;
}
.info-value.amount,
.detail-value.amount {
color: #ff4757;
font-weight: bold;
font-size: 28rpx;
}
/* 理赔进度 */
.progress-timeline {
position: relative;
padding-left: 40rpx;
}
.progress-timeline::before {
content: '';
position: absolute;
left: 20rpx;
top: 0;
bottom: 0;
width: 2rpx;
background: #e8e8e8;
}
.timeline-item {
position: relative;
margin-bottom: 40rpx;
display: flex;
align-items: flex-start;
}
.timeline-item:last-child {
margin-bottom: 0;
}
.timeline-dot {
position: absolute;
left: -30rpx;
top: 0;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background: #e8e8e8;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
.timeline-item.active .timeline-dot {
background: #1890ff;
color: white;
}
.timeline-item.active .timeline-dot .dot-icon {
color: white;
}
.dot-icon {
font-size: 20rpx;
font-weight: bold;
color: #999;
}
.timeline-content {
flex: 1;
padding-left: 20rpx;
}
.timeline-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
display: block;
}
.timeline-desc {
font-size: 24rpx;
color: #666;
margin-bottom: 5rpx;
display: block;
line-height: 1.4;
}
.timeline-time {
font-size: 22rpx;
color: #999;
}
/* 相关材料 */
.materials-list {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.material-item {
display: flex;
align-items: center;
padding: 20rpx;
background: #f8f9fa;
border-radius: 12rpx;
}
.material-icon {
font-size: 40rpx;
margin-right: 20rpx;
}
.material-info {
flex: 1;
}
.material-name {
font-size: 26rpx;
color: #333;
margin-bottom: 5rpx;
display: block;
}
.material-status {
font-size: 22rpx;
padding: 4rpx 12rpx;
border-radius: 12rpx;
display: inline-block;
}
.material-status.uploaded {
background: #f6ffed;
color: #52c41a;
}
.material-status.pending {
background: #fff7e6;
color: #d48806;
}
.material-status.rejected {
background: #fff2f0;
color: #ff4d4f;
}
.material-actions {
margin-left: 20rpx;
}
/* 处理记录 */
.records-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.record-item {
display: flex;
align-items: flex-start;
padding: 20rpx;
background: #f8f9fa;
border-radius: 12rpx;
}
.record-time {
font-size: 22rpx;
color: #999;
margin-right: 20rpx;
min-width: 120rpx;
}
.record-content {
flex: 1;
margin-right: 20rpx;
}
.record-title {
font-size: 26rpx;
font-weight: bold;
color: #333;
margin-bottom: 5rpx;
display: block;
}
.record-desc {
font-size: 24rpx;
color: #666;
line-height: 1.4;
}
.record-operator {
font-size: 22rpx;
color: #999;
min-width: 80rpx;
text-align: right;
}
/* 底部操作栏 */
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: white;
padding: 20rpx 30rpx;
border-top: 1rpx solid #e8e8e8;
display: flex;
gap: 20rpx;
z-index: 100;
}
.action-btn {
flex: 1;
height: 80rpx;
border-radius: 40rpx;
font-size: 28rpx;
font-weight: bold;
border: none;
transition: all 0.3s;
}
.action-btn.primary {
background: #1890ff;
color: white;
}
.action-btn.secondary {
background: #f0f0f0;
color: #666;
}
.action-btn.small {
padding: 12rpx 24rpx;
font-size: 22rpx;
border-radius: 20rpx;
min-width: 100rpx;
height: auto;
}
.action-btn::after {
border: none;
}
.action-btn:active {
transform: scale(0.95);
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.status-card,
.info-section,
.progress-section,
.detail-section,
.materials-section,
.records-section {
margin: 15rpx;
padding: 20rpx;
}
.bottom-actions {
padding: 15rpx 20rpx;
}
}
/* 动画效果 */
.timeline-item {
transition: all 0.3s ease;
}
.material-item {
transition: all 0.3s ease;
}
.material-item:active {
background: #e6f7ff;
transform: scale(0.98);
}
.record-item {
transition: all 0.3s ease;
}
.record-item:active {
background: #e6f7ff;
transform: scale(0.98);
}

View File

@@ -0,0 +1,260 @@
// pages/claims/claims.js
Page({
/**
* 页面的初始数据
*/
data: {
// 当前激活的标签
activeTab: 'all',
// 理赔列表
claimsList: [],
// 过滤后的理赔列表
filteredClaims: [],
// 加载状态
loading: false,
// 是否有更多数据
hasMore: true,
// 当前页码
currentPage: 1
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('理赔申请页加载', options)
this.loadClaimsList()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('理赔申请页渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('理赔申请页显示')
this.loadClaimsList()
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('理赔申请页隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('理赔申请页卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
this.setData({
currentPage: 1,
hasMore: true
})
this.loadClaimsList()
wx.stopPullDownRefresh()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
if (this.data.hasMore && !this.data.loading) {
this.loadMore()
}
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '保险理赔申请',
path: '/pages/claims/claims',
imageUrl: '/static/images/share-claims.jpg'
}
},
/**
* 加载理赔列表
*/
loadClaimsList() {
this.setData({ loading: true })
console.log('加载理赔列表')
// 模拟API调用
setTimeout(() => {
const mockClaims = this.getMockClaims()
this.setData({
claimsList: mockClaims,
filteredClaims: this.filterClaims(mockClaims, this.data.activeTab),
loading: false
})
}, 1000)
},
/**
* 获取模拟理赔数据
*/
getMockClaims() {
return [
{
id: '1',
title: '意外伤害理赔',
description: '交通事故导致的人身伤害',
status: 'pending',
statusText: '待处理',
applicationTime: '2024-01-15 14:30',
claimAmount: 5000,
policyNo: 'POL20240115001'
},
{
id: '2',
title: '医疗费用理赔',
description: '住院医疗费用报销',
status: 'processing',
statusText: '处理中',
applicationTime: '2024-01-10 09:15',
claimAmount: 12000,
policyNo: 'POL20240110002'
},
{
id: '3',
title: '重疾理赔',
description: '重大疾病保险金申请',
status: 'completed',
statusText: '已完成',
applicationTime: '2024-01-05 16:45',
claimAmount: 300000,
policyNo: 'POL20240105003'
},
{
id: '4',
title: '意外身故理赔',
description: '意外身故保险金申请',
status: 'rejected',
statusText: '已拒绝',
applicationTime: '2024-01-01 11:20',
claimAmount: 500000,
policyNo: 'POL20240101004'
},
{
id: '5',
title: '住院津贴理赔',
description: '住院期间津贴申请',
status: 'pending',
statusText: '待处理',
applicationTime: '2024-01-20 08:30',
claimAmount: 2000,
policyNo: 'POL20240120005'
}
]
},
/**
* 过滤理赔列表
*/
filterClaims(claims, status) {
if (status === 'all') {
return claims
}
return claims.filter(claim => claim.status === status)
},
/**
* 切换标签
*/
switchTab(e) {
const tab = e.currentTarget.dataset.tab
console.log('切换标签:', tab)
this.setData({
activeTab: tab,
filteredClaims: this.filterClaims(this.data.claimsList, tab)
})
},
/**
* 跳转到理赔详情
*/
goToClaimDetail(e) {
const claimId = e.currentTarget.dataset.id
console.log('跳转到理赔详情:', claimId)
wx.navigateTo({
url: `/pages/claim-detail/claim-detail?id=${claimId}`
})
},
/**
* 跳转到新理赔申请
*/
goToNewClaim() {
console.log('跳转到新理赔申请')
wx.navigateTo({
url: '/pages/new-claim/new-claim'
})
},
/**
* 加载更多
*/
loadMore() {
if (this.data.loading || !this.data.hasMore) return
this.setData({ loading: true })
console.log('加载更多理赔数据')
// 模拟加载更多数据
setTimeout(() => {
const newClaims = this.getMockClaims().map((claim, index) => ({
...claim,
id: (this.data.claimsList.length + index + 1).toString(),
applicationTime: this.formatDate(new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000))
}))
const updatedClaims = [...this.data.claimsList, ...newClaims]
this.setData({
claimsList: updatedClaims,
filteredClaims: this.filterClaims(updatedClaims, this.data.activeTab),
loading: false,
hasMore: updatedClaims.length < 20 // 模拟最多20条数据
})
}, 1000)
},
/**
* 格式化日期
*/
formatDate(date) {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
}
})

View File

@@ -0,0 +1,8 @@
{
"usingComponents": {},
"navigationBarTitleText": "理赔申请",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5",
"onReachBottomDistance": 50
}

View File

@@ -0,0 +1,120 @@
<!--pages/claims/claims.wxml-->
<view class="container">
<!-- 页面头部 -->
<view class="header">
<view class="header-content">
<text class="header-title">理赔申请</text>
<text class="header-desc">快速申请理赔,专业服务保障</text>
</view>
<view class="header-actions">
<button class="action-btn" bindtap="goToNewClaim">
<text class="btn-icon">+</text>
<text class="btn-text">申请理赔</text>
</button>
</view>
</view>
<!-- 筛选标签 -->
<view class="filter-tabs">
<view
class="tab-item {{activeTab === 'all' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="all"
>
<text>全部</text>
</view>
<view
class="tab-item {{activeTab === 'pending' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="pending"
>
<text>待处理</text>
</view>
<view
class="tab-item {{activeTab === 'processing' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="processing"
>
<text>处理中</text>
</view>
<view
class="tab-item {{activeTab === 'completed' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="completed"
>
<text>已完成</text>
</view>
</view>
<!-- 理赔列表 -->
<view class="claims-list">
<view
class="claim-item"
wx:for="{{filteredClaims}}"
wx:key="id"
bindtap="goToClaimDetail"
data-id="{{item.id}}"
>
<view class="claim-header">
<view class="claim-info">
<text class="claim-title">{{item.title}}</text>
<text class="claim-desc">{{item.description}}</text>
</view>
<view class="claim-status {{item.status}}">
<text class="status-text">{{item.statusText}}</text>
</view>
</view>
<view class="claim-details">
<view class="detail-item">
<text class="detail-label">申请时间:</text>
<text class="detail-value">{{item.applicationTime}}</text>
</view>
<view class="detail-item">
<text class="detail-label">理赔金额:</text>
<text class="detail-value amount">¥{{item.claimAmount}}</text>
</view>
<view class="detail-item" wx:if="{{item.policyNo}}">
<text class="detail-label">保单号:</text>
<text class="detail-value">{{item.policyNo}}</text>
</view>
</view>
<view class="claim-actions">
<button
class="action-btn small"
bindtap="goToClaimDetail"
data-id="{{item.id}}"
catchtap="true"
>
查看详情
</button>
<button
class="action-btn small primary"
bindtap="goToClaimDetail"
data-id="{{item.id}}"
catchtap="true"
wx:if="{{item.status === 'pending'}}"
>
继续申请
</button>
</view>
</view>
</view>
<!-- 空状态 -->
<view wx:if="{{filteredClaims.length === 0}}" class="empty-state">
<view class="empty-icon">📋</view>
<text class="empty-title">暂无理赔记录</text>
<text class="empty-desc">您还没有任何理赔申请记录</text>
<button class="empty-btn" bindtap="goToNewClaim">
立即申请理赔
</button>
</view>
<!-- 加载更多 -->
<view wx:if="{{hasMore && filteredClaims.length > 0}}" class="load-more">
<view class="loading-text" wx:if="{{loading}}">加载中...</view>
<view class="load-more-btn" wx:else bindtap="loadMore">加载更多</view>
</view>
</view>

View File

@@ -0,0 +1,342 @@
/* pages/claims/claims.wxss */
.container {
background: #f5f5f5;
min-height: 100vh;
}
/* 页面头部 */
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
color: white;
}
.header-content {
flex: 1;
}
.header-title {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 10rpx;
display: block;
}
.header-desc {
font-size: 24rpx;
opacity: 0.9;
display: block;
}
.header-actions {
margin-left: 20rpx;
}
.action-btn {
display: flex;
align-items: center;
padding: 15rpx 25rpx;
background: rgba(255, 255, 255, 0.2);
border: 2rpx solid rgba(255, 255, 255, 0.3);
border-radius: 25rpx;
color: white;
font-size: 24rpx;
transition: all 0.3s;
}
.action-btn::after {
border: none;
}
.action-btn:active {
background: rgba(255, 255, 255, 0.3);
transform: scale(0.95);
}
.btn-icon {
font-size: 28rpx;
margin-right: 8rpx;
}
.btn-text {
font-size: 24rpx;
}
/* 筛选标签 */
.filter-tabs {
background: white;
display: flex;
padding: 0 30rpx;
border-bottom: 1rpx solid #e8e8e8;
}
.tab-item {
flex: 1;
text-align: center;
padding: 30rpx 0;
font-size: 28rpx;
color: #666;
position: relative;
transition: all 0.3s;
}
.tab-item.active {
color: #1890ff;
font-weight: bold;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background: #1890ff;
border-radius: 2rpx;
}
/* 理赔列表 */
.claims-list {
padding: 20rpx;
}
.claim-item {
background: white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
transition: all 0.3s;
}
.claim-item:active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
}
.claim-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 20rpx;
}
.claim-info {
flex: 1;
}
.claim-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
display: block;
}
.claim-desc {
font-size: 24rpx;
color: #666;
line-height: 1.4;
}
.claim-status {
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: bold;
}
.claim-status.pending {
background: #fff7e6;
color: #d48806;
}
.claim-status.processing {
background: #e6f7ff;
color: #1890ff;
}
.claim-status.completed {
background: #f6ffed;
color: #52c41a;
}
.claim-status.rejected {
background: #fff2f0;
color: #ff4d4f;
}
.status-text {
font-size: 22rpx;
}
/* 理赔详情 */
.claim-details {
margin-bottom: 25rpx;
}
.detail-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
font-size: 24rpx;
}
.detail-item:last-child {
margin-bottom: 0;
}
.detail-label {
color: #666;
}
.detail-value {
color: #333;
font-weight: 500;
}
.detail-value.amount {
color: #ff4757;
font-weight: bold;
font-size: 26rpx;
}
/* 理赔操作 */
.claim-actions {
display: flex;
gap: 15rpx;
justify-content: flex-end;
}
.action-btn.small {
padding: 12rpx 24rpx;
font-size: 22rpx;
border-radius: 20rpx;
min-width: 120rpx;
}
.action-btn.small.primary {
background: #1890ff;
color: white;
border: none;
}
.action-btn.small:not(.primary) {
background: #f0f0f0;
color: #666;
border: none;
}
.action-btn.small::after {
border: none;
}
.action-btn.small:active {
transform: scale(0.95);
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 100rpx 40rpx;
}
.empty-icon {
font-size: 120rpx;
margin-bottom: 30rpx;
opacity: 0.5;
}
.empty-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 15rpx;
display: block;
}
.empty-desc {
font-size: 26rpx;
color: #666;
margin-bottom: 40rpx;
display: block;
}
.empty-btn {
background: #1890ff;
color: white;
border: none;
border-radius: 25rpx;
padding: 20rpx 40rpx;
font-size: 28rpx;
font-weight: bold;
}
.empty-btn::after {
border: none;
}
.empty-btn:active {
transform: scale(0.95);
}
/* 加载更多 */
.load-more {
text-align: center;
padding: 30rpx;
}
.loading-text {
font-size: 24rpx;
color: #666;
}
.load-more-btn {
font-size: 26rpx;
color: #1890ff;
padding: 15rpx 30rpx;
background: white;
border-radius: 25rpx;
display: inline-block;
border: 2rpx solid #1890ff;
transition: all 0.3s;
}
.load-more-btn:active {
background: #e6f7ff;
transform: scale(0.95);
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.header {
padding: 20rpx;
}
.claims-list {
padding: 15rpx;
}
.claim-item {
padding: 20rpx;
}
}
/* 动画效果 */
.claim-item {
transition: all 0.3s ease;
}
.tab-item {
transition: all 0.3s ease;
}
.action-btn {
transition: all 0.3s ease;
}

View File

@@ -0,0 +1,213 @@
// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
// 热门产品数据
hotProducts: [
{
id: 1,
name: '综合意外险',
description: '全面保障意外伤害,保费低廉',
min_premium: 99,
icon: '🛡️'
},
{
id: 2,
name: '重疾保险',
description: '重大疾病保障,安心无忧',
min_premium: 299,
icon: '🏥'
},
{
id: 3,
name: '车险',
description: '车辆全面保障,理赔快速',
min_premium: 1999,
icon: '🚗'
},
{
id: 4,
name: '旅行险',
description: '出行安全保障,全球覆盖',
min_premium: 59,
icon: '✈️'
}
],
// 新闻资讯数据
newsList: [
{
id: 1,
title: '2024年保险新政策解读',
summary: '了解最新的保险政策变化,为您的保障规划提供参考',
date: '2024-01-15'
},
{
id: 2,
title: '如何选择适合自己的保险产品',
summary: '专业指导帮助您选择最合适的保险方案',
date: '2024-01-12'
},
{
id: 3,
title: '理赔流程优化,服务更便捷',
summary: '我们持续优化理赔流程,让您的理赔更加便捷快速',
date: '2024-01-10'
}
]
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('首页加载完成')
this.loadPageData()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('首页渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('首页显示')
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('首页隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('首页卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
this.loadPageData()
// 停止下拉刷新
setTimeout(() => {
wx.stopPullDownRefresh()
}, 1000)
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
// 可以在这里加载更多数据
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '保险服务 - 专业安全的保险平台',
path: '/pages/index/index',
imageUrl: '/static/images/share-cover.jpg'
}
},
/**
* 加载页面数据
*/
loadPageData() {
console.log('加载首页数据')
// 这里可以调用API获取数据
// 目前使用模拟数据
},
/**
* 跳转到产品详情页
*/
goToProductDetail(e) {
const productId = e.currentTarget.dataset.id
console.log('跳转到产品详情页:', productId)
wx.navigateTo({
url: `/pages/product-detail/product-detail?id=${productId}`
})
},
/**
* 跳转到产品列表页
*/
goToProducts() {
console.log('跳转到产品列表页')
wx.switchTab({
url: '/pages/products/products'
})
},
/**
* 跳转到我的页面
*/
goToMy() {
console.log('跳转到我的页面')
wx.switchTab({
url: '/pages/my/my'
})
},
/**
* 跳转到理赔申请页
*/
goToClaims() {
console.log('跳转到理赔申请页')
wx.navigateTo({
url: '/pages/claims/claims'
})
},
/**
* 显示客服服务
*/
goToService() {
console.log('显示客服服务')
wx.showModal({
title: '客服服务',
content: '客服电话400-888-8888\n服务时间周一至周日 9:00-18:00',
showCancel: false,
confirmText: '知道了'
})
},
/**
* 跳转到新闻列表页
*/
goToNews() {
console.log('跳转到新闻列表页')
wx.navigateTo({
url: '/pages/news/news'
})
},
/**
* 跳转到新闻详情页
*/
goToNewsDetail(e) {
const newsId = e.currentTarget.dataset.id
console.log('跳转到新闻详情页:', newsId)
wx.navigateTo({
url: `/pages/news-detail/news-detail?id=${newsId}`
})
}
})

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "保险服务",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5"
}

View File

@@ -0,0 +1,106 @@
<!--pages/index/index.wxml-->
<view class="container">
<!-- 欢迎横幅 -->
<view class="welcome-banner">
<text class="welcome-title">欢迎使用保险服务</text>
<text class="welcome-subtitle">专业、安全、便捷的保险服务平台</text>
</view>
<!-- 快捷入口 -->
<view class="quick-actions">
<view class="action-item" bindtap="goToProducts">
<view class="action-icon">📋</view>
<text class="action-text">保险产品</text>
</view>
<view class="action-item" bindtap="goToMy">
<view class="action-icon">📄</view>
<text class="action-text">我的保单</text>
</view>
<view class="action-item" bindtap="goToClaims">
<view class="action-icon">💰</view>
<text class="action-text">理赔申请</text>
</view>
<view class="action-item" bindtap="goToService">
<view class="action-icon">📞</view>
<text class="action-text">客服服务</text>
</view>
</view>
<!-- 热门产品 -->
<view class="section">
<view class="section-header">
<text class="section-title">热门产品</text>
<text class="section-more" bindtap="goToProducts">更多 ></text>
</view>
<view class="product-grid">
<view
wx:for="{{hotProducts}}"
wx:key="id"
class="product-card"
bindtap="goToProductDetail"
data-id="{{item.id}}"
>
<view class="product-icon">{{item.icon}}</view>
<view class="product-info">
<text class="product-name">{{item.name}}</text>
<text class="product-desc">{{item.description}}</text>
<view class="product-price">
<text class="price-label">起保费:</text>
<text class="price-value">¥{{item.min_premium}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 服务优势 -->
<view class="section">
<view class="section-header">
<text class="section-title">服务优势</text>
</view>
<view class="advantage-grid">
<view class="advantage-item">
<view class="advantage-icon">🛡️</view>
<text class="advantage-title">专业保障</text>
<text class="advantage-desc">专业团队提供全方位保险咨询</text>
</view>
<view class="advantage-item">
<view class="advantage-icon">⚡</view>
<text class="advantage-title">快速理赔</text>
<text class="advantage-desc">7x24小时快速理赔服务</text>
</view>
<view class="advantage-item">
<view class="advantage-icon">🔒</view>
<text class="advantage-title">安全可靠</text>
<text class="advantage-desc">银行级安全保障体系</text>
</view>
</view>
</view>
<!-- 新闻资讯 -->
<view class="section">
<view class="section-header">
<text class="section-title">最新资讯</text>
<text class="section-more" bindtap="goToNews">更多 ></text>
</view>
<view class="news-list">
<view
wx:for="{{newsList}}"
wx:key="id"
class="news-item"
bindtap="goToNewsDetail"
data-id="{{item.id}}"
>
<view class="news-content">
<text class="news-title">{{item.title}}</text>
<text class="news-summary">{{item.summary}}</text>
<text class="news-date">{{item.date}}</text>
</view>
<view class="news-arrow">></view>
</view>
</view>
</view>
</view>

View File

@@ -0,0 +1,233 @@
/* pages/index/index.wxss */
.container {
background-color: #f5f5f5;
min-height: 100vh;
}
/* 欢迎横幅 */
.welcome-banner {
background: linear-gradient(135deg, #1890ff, #40a9ff);
padding: 60rpx 30rpx;
text-align: center;
color: white;
}
.welcome-title {
font-size: 48rpx;
font-weight: bold;
display: block;
margin-bottom: 20rpx;
}
.welcome-subtitle {
font-size: 28rpx;
opacity: 0.9;
display: block;
}
/* 快捷入口 */
.quick-actions {
display: flex;
justify-content: space-around;
padding: 40rpx 20rpx;
background: #fff;
margin-bottom: 20rpx;
}
.action-item {
display: flex;
flex-direction: column;
align-items: center;
}
.action-icon {
font-size: 60rpx;
margin-bottom: 20rpx;
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f0f8ff;
border-radius: 50%;
}
.action-text {
font-size: 24rpx;
color: #666;
}
/* 通用区块 */
.section {
margin-bottom: 20rpx;
background: #fff;
padding: 30rpx;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.section-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
.section-more {
color: #1890ff;
font-size: 28rpx;
}
/* 产品网格 */
.product-grid {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.product-card {
display: flex;
padding: 30rpx;
border: 1px solid #eee;
border-radius: 12rpx;
background: #fafafa;
}
.product-icon {
font-size: 60rpx;
width: 120rpx;
height: 120rpx;
margin-right: 30rpx;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f0f8ff;
}
.product-info {
flex: 1;
}
.product-name {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 10rpx;
color: #333;
}
.product-desc {
font-size: 28rpx;
color: #666;
margin-bottom: 15rpx;
}
.product-price {
display: flex;
align-items: center;
}
.price-label {
font-size: 24rpx;
color: #999;
}
.price-value {
font-size: 32rpx;
color: #ff6b35;
font-weight: bold;
}
/* 优势网格 */
.advantage-grid {
display: flex;
justify-content: space-between;
}
.advantage-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 0 20rpx;
}
.advantage-icon {
font-size: 60rpx;
width: 100rpx;
height: 100rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f0f8ff;
border-radius: 50%;
}
.advantage-title {
font-size: 28rpx;
font-weight: bold;
margin-bottom: 10rpx;
color: #333;
}
.advantage-desc {
font-size: 24rpx;
color: #666;
line-height: 1.4;
}
/* 新闻列表 */
.news-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.news-item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1px solid #f0f0f0;
}
.news-item:last-child {
border-bottom: none;
}
.news-content {
flex: 1;
}
.news-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.news-summary {
font-size: 26rpx;
color: #666;
margin-bottom: 10rpx;
display: block;
line-height: 1.4;
}
.news-date {
font-size: 22rpx;
color: #999;
display: block;
}
.news-arrow {
font-size: 24rpx;
color: #ccc;
margin-left: 20rpx;
}

View File

@@ -0,0 +1,404 @@
// pages/login/login.js
Page({
/**
* 页面的初始数据
*/
data: {
// 登录方式password 或 sms
loginType: 'password',
// 表单数据
formData: {
phone: '',
password: '',
smsCode: ''
},
// 密码显示状态
showPassword: false,
// 记住密码
rememberMe: false,
// 同意协议
agreeTerms: false,
// 加载状态
loading: false,
// 短信倒计时
smsCountdown: 0,
// 手机号是否有效
isValidPhone: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('登录页面加载完成')
this.loadSavedData()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('登录页面渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('登录页面显示')
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('登录页面隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('登录页面卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
wx.stopPullDownRefresh()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '保险服务 - 专业安全的保险平台',
path: '/pages/login/login',
imageUrl: '/static/images/share-login.jpg'
}
},
/**
* 加载保存的数据
*/
loadSavedData() {
const savedPhone = wx.getStorageSync('savedPhone')
const savedPassword = wx.getStorageSync('savedPassword')
const rememberMe = wx.getStorageSync('rememberMe')
if (savedPhone && rememberMe) {
this.setData({
'formData.phone': savedPhone,
'formData.password': savedPassword || '',
rememberMe: rememberMe
})
this.validateForm()
}
},
/**
* 切换登录方式
*/
switchLoginType(e) {
const type = e.currentTarget.dataset.type
console.log('切换登录方式:', type)
this.setData({
loginType: type,
'formData.smsCode': ''
})
},
/**
* 手机号输入
*/
onPhoneInput(e) {
const phone = e.detail.value
this.setData({
'formData.phone': phone
})
this.validateForm()
},
/**
* 密码输入
*/
onPasswordInput(e) {
const password = e.detail.value
this.setData({
'formData.password': password
})
this.validateForm()
},
/**
* 验证码输入
*/
onSmsCodeInput(e) {
const smsCode = e.detail.value
this.setData({
'formData.smsCode': smsCode
})
this.validateForm()
},
/**
* 切换密码显示
*/
togglePassword() {
this.setData({
showPassword: !this.data.showPassword
})
},
/**
* 记住密码切换
*/
onRememberChange(e) {
this.setData({
rememberMe: e.detail.value
})
},
/**
* 同意协议切换
*/
onAgreeChange(e) {
this.setData({
agreeTerms: e.detail.value
})
},
/**
* 验证表单
*/
validateForm() {
const { phone, password, smsCode } = this.data.formData
const { loginType } = this.data
// 验证手机号
const isValidPhone = /^1[3-9]\d{9}$/.test(phone)
this.setData({ isValidPhone })
// 验证密码登录
if (loginType === 'password') {
const canLogin = isValidPhone && password.length >= 6
this.setData({ canLogin })
}
// 验证短信登录
if (loginType === 'sms') {
const canSmsLogin = isValidPhone && smsCode.length === 6
this.setData({ canSmsLogin })
}
},
/**
* 发送短信验证码
*/
sendSmsCode() {
const { phone } = this.data.formData
const { isValidPhone, smsCountdown } = this.data
if (!isValidPhone) {
wx.showToast({
title: '请输入正确的手机号',
icon: 'none'
})
return
}
if (smsCountdown > 0) {
return
}
console.log('发送短信验证码:', phone)
// 模拟发送验证码
wx.showLoading({
title: '发送中...'
})
setTimeout(() => {
wx.hideLoading()
wx.showToast({
title: '验证码已发送',
icon: 'success'
})
// 开始倒计时
this.startCountdown()
}, 1000)
},
/**
* 开始倒计时
*/
startCountdown() {
let countdown = 60
this.setData({ smsCountdown: countdown })
const timer = setInterval(() => {
countdown--
this.setData({ smsCountdown: countdown })
if (countdown <= 0) {
clearInterval(timer)
}
}, 1000)
},
/**
* 密码登录
*/
onPasswordLogin() {
const { phone, password } = this.data.formData
const { canLogin, loading, agreeTerms } = this.data
if (!canLogin || loading) return
if (!agreeTerms) {
wx.showToast({
title: '请先同意用户协议',
icon: 'none'
})
return
}
console.log('密码登录:', phone)
this.performLogin('password', { phone, password })
},
/**
* 短信登录
*/
onSmsLogin() {
const { phone, smsCode } = this.data.formData
const { canSmsLogin, loading, agreeTerms } = this.data
if (!canSmsLogin || loading) return
if (!agreeTerms) {
wx.showToast({
title: '请先同意用户协议',
icon: 'none'
})
return
}
console.log('短信登录:', phone, smsCode)
this.performLogin('sms', { phone, smsCode })
},
/**
* 执行登录
*/
performLogin(type, data) {
this.setData({ loading: true })
// 模拟登录API调用
setTimeout(() => {
this.setData({ loading: false })
// 模拟登录成功
const mockUserInfo = {
id: 1,
nickname: '用户' + data.phone.slice(-4),
phone: data.phone,
avatar: ''
}
// 保存登录信息
wx.setStorageSync('token', 'mock_token_' + Date.now())
wx.setStorageSync('userInfo', mockUserInfo)
// 保存密码(如果选择记住密码)
if (this.data.rememberMe && type === 'password') {
wx.setStorageSync('savedPhone', data.phone)
wx.setStorageSync('savedPassword', data.password)
wx.setStorageSync('rememberMe', true)
}
wx.showToast({
title: '登录成功',
icon: 'success'
})
// 延迟跳转
setTimeout(() => {
wx.switchTab({
url: '/pages/my/my'
})
}, 1500)
}, 2000)
},
/**
* 微信登录
*/
onWechatLogin() {
console.log('微信登录')
wx.showToast({
title: '微信登录功能开发中',
icon: 'none'
})
},
/**
* 跳转到注册页
*/
goToRegister() {
console.log('跳转到注册页')
wx.navigateTo({
url: '/pages/register/register'
})
},
/**
* 跳转到忘记密码页
*/
goToForgotPassword() {
console.log('跳转到忘记密码页')
wx.navigateTo({
url: '/pages/forgot-password/forgot-password'
})
},
/**
* 跳转到用户协议页
*/
goToTerms() {
console.log('跳转到用户协议页')
wx.navigateTo({
url: '/pages/terms/terms'
})
},
/**
* 跳转到隐私政策页
*/
goToPrivacy() {
console.log('跳转到隐私政策页')
wx.navigateTo({
url: '/pages/privacy/privacy'
})
}
})

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "登录",
"navigationStyle": "custom",
"backgroundColor": "#667eea",
"backgroundTextStyle": "light"
}

View File

@@ -0,0 +1,165 @@
<!--pages/login/login.wxml-->
<view class="container">
<!-- 顶部装饰 -->
<view class="header-decoration">
<view class="decoration-circle circle-1"></view>
<view class="decoration-circle circle-2"></view>
<view class="decoration-circle circle-3"></view>
</view>
<!-- 登录表单 -->
<view class="login-form">
<!-- Logo区域 -->
<view class="logo-section">
<view class="logo-icon">🛡️</view>
<text class="app-name">保险服务</text>
<text class="app-slogan">专业、安全、便捷的保险平台</text>
</view>
<!-- 登录方式切换 -->
<view class="login-tabs">
<view
class="tab-item {{loginType === 'password' ? 'active' : ''}}"
bindtap="switchLoginType"
data-type="password"
>
<text>密码登录</text>
</view>
<view
class="tab-item {{loginType === 'sms' ? 'active' : ''}}"
bindtap="switchLoginType"
data-type="sms"
>
<text>短信登录</text>
</view>
</view>
<!-- 密码登录表单 -->
<view wx:if="{{loginType === 'password'}}" class="form-content">
<view class="input-group">
<view class="input-wrapper">
<view class="input-icon">📱</view>
<input
class="form-input"
type="number"
placeholder="请输入手机号"
value="{{formData.phone}}"
bindinput="onPhoneInput"
maxlength="11"
/>
</view>
<view class="input-wrapper">
<view class="input-icon">🔒</view>
<input
class="form-input"
type="{{showPassword ? 'text' : 'password'}}"
placeholder="请输入密码"
value="{{formData.password}}"
bindinput="onPasswordInput"
/>
<view class="password-toggle" bindtap="togglePassword">
<text>{{showPassword ? '👁️' : '👁️‍🗨️'}}</text>
</view>
</view>
</view>
<view class="form-options">
<view class="remember-me">
<checkbox
checked="{{rememberMe}}"
bindchange="onRememberChange"
color="#1890ff"
/>
<text class="remember-text">记住密码</text>
</view>
<text class="forgot-password" bindtap="goToForgotPassword">忘记密码?</text>
</view>
<button
class="login-btn {{canLogin ? 'active' : 'disabled'}}"
bindtap="onPasswordLogin"
disabled="{{!canLogin || loading}}"
>
{{loading ? '登录中...' : '登录'}}
</button>
</view>
<!-- 短信登录表单 -->
<view wx:if="{{loginType === 'sms'}}" class="form-content">
<view class="input-group">
<view class="input-wrapper">
<view class="input-icon">📱</view>
<input
class="form-input"
type="number"
placeholder="请输入手机号"
value="{{formData.phone}}"
bindinput="onPhoneInput"
maxlength="11"
/>
</view>
<view class="input-wrapper sms-input">
<view class="input-icon">📨</view>
<input
class="form-input"
type="number"
placeholder="请输入验证码"
value="{{formData.smsCode}}"
bindinput="onSmsCodeInput"
maxlength="6"
/>
<button
class="sms-btn {{smsCountdown > 0 ? 'disabled' : 'active'}}"
bindtap="sendSmsCode"
disabled="{{smsCountdown > 0 || !isValidPhone}}"
>
{{smsCountdown > 0 ? smsCountdown + 's' : '获取验证码'}}
</button>
</view>
</view>
<button
class="login-btn {{canSmsLogin ? 'active' : 'disabled'}}"
bindtap="onSmsLogin"
disabled="{{!canSmsLogin || loading}}"
>
{{loading ? '登录中...' : '登录'}}
</button>
</view>
<!-- 其他登录方式 -->
<view class="other-login">
<view class="divider">
<text class="divider-text">其他登录方式</text>
</view>
<view class="social-login">
<button class="social-btn wechat-btn" bindtap="onWechatLogin">
<text class="social-icon">💬</text>
<text class="social-text">微信登录</text>
</button>
</view>
</view>
<!-- 注册提示 -->
<view class="register-tip">
<text class="tip-text">还没有账号?</text>
<text class="register-link" bindtap="goToRegister">立即注册</text>
</view>
<!-- 用户协议 -->
<view class="agreement">
<checkbox
checked="{{agreeTerms}}"
bindchange="onAgreeChange"
color="#1890ff"
/>
<text class="agreement-text">
我已阅读并同意
<text class="link" bindtap="goToTerms">《用户协议》</text>
<text class="link" bindtap="goToPrivacy">《隐私政策》</text>
</text>
</view>
</view>
</view>

View File

@@ -0,0 +1,356 @@
/* pages/login/login.wxss */
.container {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: relative;
overflow: hidden;
}
/* 顶部装饰 */
.header-decoration {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 200rpx;
overflow: hidden;
}
.decoration-circle {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
}
.circle-1 {
width: 200rpx;
height: 200rpx;
top: -100rpx;
right: -50rpx;
}
.circle-2 {
width: 150rpx;
height: 150rpx;
top: 50rpx;
left: -75rpx;
}
.circle-3 {
width: 100rpx;
height: 100rpx;
top: 20rpx;
right: 100rpx;
}
/* 登录表单 */
.login-form {
position: relative;
z-index: 10;
padding: 100rpx 60rpx 60rpx;
}
/* Logo区域 */
.logo-section {
text-align: center;
margin-bottom: 80rpx;
}
.logo-icon {
font-size: 120rpx;
margin-bottom: 30rpx;
}
.app-name {
font-size: 48rpx;
font-weight: bold;
color: white;
margin-bottom: 20rpx;
display: block;
}
.app-slogan {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
display: block;
}
/* 登录方式切换 */
.login-tabs {
display: flex;
background: rgba(255, 255, 255, 0.1);
border-radius: 50rpx;
padding: 8rpx;
margin-bottom: 60rpx;
}
.tab-item {
flex: 1;
text-align: center;
padding: 20rpx;
border-radius: 42rpx;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.7);
transition: all 0.3s;
}
.tab-item.active {
background: white;
color: #1890ff;
font-weight: bold;
}
/* 表单内容 */
.form-content {
background: white;
border-radius: 20rpx;
padding: 60rpx 40rpx;
box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.1);
}
.input-group {
margin-bottom: 40rpx;
}
.input-wrapper {
position: relative;
margin-bottom: 30rpx;
display: flex;
align-items: center;
background: #f8f9fa;
border-radius: 12rpx;
padding: 0 20rpx;
border: 2rpx solid transparent;
transition: all 0.3s;
}
.input-wrapper:focus-within {
border-color: #1890ff;
background: white;
}
.input-icon {
font-size: 32rpx;
margin-right: 20rpx;
color: #999;
}
.form-input {
flex: 1;
height: 80rpx;
font-size: 30rpx;
color: #333;
background: transparent;
}
.password-toggle {
padding: 10rpx;
font-size: 32rpx;
color: #999;
}
.sms-input {
padding-right: 0;
}
.sms-btn {
background: #1890ff;
color: white;
border: none;
border-radius: 8rpx;
font-size: 24rpx;
padding: 20rpx 30rpx;
margin-left: 20rpx;
white-space: nowrap;
}
.sms-btn.disabled {
background: #ccc;
color: #999;
}
.sms-btn::after {
border: none;
}
/* 表单选项 */
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 40rpx;
}
.remember-me {
display: flex;
align-items: center;
}
.remember-text {
font-size: 26rpx;
color: #666;
margin-left: 10rpx;
}
.forgot-password {
font-size: 26rpx;
color: #1890ff;
}
/* 登录按钮 */
.login-btn {
width: 100%;
height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: bold;
border: none;
margin-bottom: 40rpx;
transition: all 0.3s;
}
.login-btn.active {
background: #1890ff;
color: white;
}
.login-btn.disabled {
background: #f0f0f0;
color: #ccc;
}
.login-btn::after {
border: none;
}
/* 其他登录方式 */
.other-login {
margin-bottom: 40rpx;
}
.divider {
text-align: center;
margin-bottom: 30rpx;
position: relative;
}
.divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1rpx;
background: #e8e8e8;
}
.divider-text {
background: white;
padding: 0 30rpx;
font-size: 24rpx;
color: #999;
position: relative;
z-index: 1;
}
.social-login {
display: flex;
justify-content: center;
}
.social-btn {
display: flex;
align-items: center;
padding: 20rpx 40rpx;
border-radius: 25rpx;
font-size: 26rpx;
border: 2rpx solid #e8e8e8;
background: white;
color: #333;
}
.social-btn::after {
border: none;
}
.wechat-btn {
border-color: #07c160;
color: #07c160;
}
.social-icon {
font-size: 32rpx;
margin-right: 10rpx;
}
.social-text {
font-size: 26rpx;
}
/* 注册提示 */
.register-tip {
text-align: center;
margin-bottom: 30rpx;
}
.tip-text {
font-size: 26rpx;
color: #666;
}
.register-link {
font-size: 26rpx;
color: #1890ff;
margin-left: 10rpx;
}
/* 用户协议 */
.agreement {
display: flex;
align-items: flex-start;
font-size: 22rpx;
color: #999;
line-height: 1.5;
}
.agreement-text {
margin-left: 10rpx;
flex: 1;
}
.link {
color: #1890ff;
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.login-form {
padding: 80rpx 40rpx 40rpx;
}
.form-content {
padding: 40rpx 30rpx;
}
}
/* 动画效果 */
.tab-item {
transition: all 0.3s ease;
}
.input-wrapper {
transition: all 0.3s ease;
}
.login-btn {
transition: all 0.3s ease;
}
.social-btn:active {
transform: scale(0.95);
}
/* 加载状态 */
.login-btn:disabled {
opacity: 0.6;
}

View File

@@ -0,0 +1,336 @@
// pages/my/my.js
Page({
/**
* 页面的初始数据
*/
data: {
// 登录状态
isLoggedIn: false,
// 用户信息
userInfo: {
nickname: '',
phone: '',
avatar: ''
},
// 统计数据
stats: {
policyCount: 0,
applicationCount: 0,
claimCount: 0,
favoriteCount: 0
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('我的页面加载完成')
this.checkLoginStatus()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('我的页面渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('我的页面显示')
this.checkLoginStatus()
if (this.data.isLoggedIn) {
this.loadUserData()
}
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('我的页面隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('我的页面卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
this.checkLoginStatus()
if (this.data.isLoggedIn) {
this.loadUserData()
}
// 停止下拉刷新
setTimeout(() => {
wx.stopPullDownRefresh()
}, 1000)
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '保险服务 - 专业安全的保险平台',
path: '/pages/my/my',
imageUrl: '/static/images/share-my.jpg'
}
},
/**
* 检查登录状态
*/
checkLoginStatus() {
const token = wx.getStorageSync('token')
const userInfo = wx.getStorageSync('userInfo')
if (token && userInfo) {
this.setData({
isLoggedIn: true,
userInfo: userInfo
})
} else {
this.setData({
isLoggedIn: false,
userInfo: {
nickname: '',
phone: '',
avatar: ''
}
})
}
},
/**
* 加载用户数据
*/
loadUserData() {
console.log('加载用户数据')
// 模拟加载用户统计数据
this.setData({
stats: {
policyCount: 3,
applicationCount: 2,
claimCount: 1,
favoriteCount: 5
}
})
},
/**
* 跳转到登录页
*/
goToLogin() {
console.log('跳转到登录页')
wx.navigateTo({
url: '/pages/login/login'
})
},
/**
* 跳转到个人资料页
*/
goToProfile() {
console.log('跳转到个人资料页')
if (!this.data.isLoggedIn) {
this.goToLogin()
return
}
wx.navigateTo({
url: '/pages/profile/profile'
})
},
/**
* 跳转到我的保单页
*/
goToPolicies() {
console.log('跳转到我的保单页')
if (!this.data.isLoggedIn) {
this.goToLogin()
return
}
wx.navigateTo({
url: '/pages/policies/policies'
})
},
/**
* 跳转到投保申请页
*/
goToApplications() {
console.log('跳转到投保申请页')
if (!this.data.isLoggedIn) {
this.goToLogin()
return
}
wx.navigateTo({
url: '/pages/application/application'
})
},
/**
* 跳转到理赔申请页
*/
goToClaims() {
console.log('跳转到理赔申请页')
if (!this.data.isLoggedIn) {
this.goToLogin()
return
}
wx.navigateTo({
url: '/pages/claims/claims'
})
},
/**
* 跳转到收藏产品页
*/
goToFavorites() {
console.log('跳转到收藏产品页')
if (!this.data.isLoggedIn) {
this.goToLogin()
return
}
wx.navigateTo({
url: '/pages/favorites/favorites'
})
},
/**
* 跳转到设置页
*/
goToSettings() {
console.log('跳转到设置页')
wx.navigateTo({
url: '/pages/settings/settings'
})
},
/**
* 跳转到安全中心页
*/
goToSecurity() {
console.log('跳转到安全中心页')
if (!this.data.isLoggedIn) {
this.goToLogin()
return
}
wx.navigateTo({
url: '/pages/security/security'
})
},
/**
* 跳转到帮助中心页
*/
goToHelp() {
console.log('跳转到帮助中心页')
wx.navigateTo({
url: '/pages/help/help'
})
},
/**
* 联系客服
*/
goToContact() {
console.log('联系客服')
wx.showModal({
title: '联系客服',
content: '客服电话400-888-8888\n服务时间周一至周日 9:00-18:00\n\n您也可以在线咨询客服',
showCancel: true,
cancelText: '取消',
confirmText: '拨打电话',
success: (res) => {
if (res.confirm) {
wx.makePhoneCall({
phoneNumber: '400-888-8888'
})
}
}
})
},
/**
* 跳转到意见反馈页
*/
goToFeedback() {
console.log('跳转到意见反馈页')
wx.navigateTo({
url: '/pages/feedback/feedback'
})
},
/**
* 跳转到关于我们页
*/
goToAbout() {
console.log('跳转到关于我们页')
wx.navigateTo({
url: '/pages/about/about'
})
},
/**
* 退出登录
*/
onLogout() {
console.log('退出登录')
wx.showModal({
title: '确认退出',
content: '确定要退出登录吗?',
showCancel: true,
cancelText: '取消',
confirmText: '确定',
success: (res) => {
if (res.confirm) {
// 清除本地存储
wx.removeStorageSync('token')
wx.removeStorageSync('userInfo')
// 更新页面状态
this.setData({
isLoggedIn: false,
userInfo: {
nickname: '',
phone: '',
avatar: ''
},
stats: {
policyCount: 0,
applicationCount: 0,
claimCount: 0,
favoriteCount: 0
}
})
wx.showToast({
title: '已退出登录',
icon: 'success'
})
}
}
})
}
})

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "我的",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5"
}

View File

@@ -0,0 +1,132 @@
<!--pages/my/my.wxml-->
<view class="container">
<!-- 用户信息区域 -->
<view class="user-section">
<view class="user-info" bindtap="goToProfile">
<view class="avatar">
<image wx:if="{{userInfo.avatar}}" src="{{userInfo.avatar}}" class="avatar-img" />
<text wx:else class="avatar-text">{{userInfo.nickname ? userInfo.nickname.charAt(0) : '未'}}</text>
</view>
<view class="user-details">
<text class="username">{{userInfo.nickname || '未登录'}}</text>
<text class="user-phone">{{userInfo.phone || '点击登录'}}</text>
</view>
<view class="arrow-icon">></view>
</view>
<!-- 登录状态 -->
<view wx:if="{{!isLoggedIn}}" class="login-prompt">
<button class="login-btn" bindtap="goToLogin">立即登录</button>
</view>
</view>
<!-- 数据统计 -->
<view wx:if="{{isLoggedIn}}" class="stats-section">
<view class="stats-grid">
<view class="stat-item" bindtap="goToPolicies">
<text class="stat-number">{{stats.policyCount}}</text>
<text class="stat-label">我的保单</text>
</view>
<view class="stat-item" bindtap="goToApplications">
<text class="stat-number">{{stats.applicationCount}}</text>
<text class="stat-label">投保申请</text>
</view>
<view class="stat-item" bindtap="goToClaims">
<text class="stat-number">{{stats.claimCount}}</text>
<text class="stat-label">理赔申请</text>
</view>
<view class="stat-item" bindtap="goToFavorites">
<text class="stat-number">{{stats.favoriteCount}}</text>
<text class="stat-label">收藏产品</text>
</view>
</view>
</view>
<!-- 功能菜单 -->
<view class="menu-section">
<!-- 我的服务 -->
<view class="menu-group">
<view class="group-title">我的服务</view>
<view class="menu-list">
<view class="menu-item" bindtap="goToPolicies">
<view class="menu-icon">📄</view>
<text class="menu-text">我的保单</text>
<view class="menu-badge" wx:if="{{stats.policyCount > 0}}">{{stats.policyCount}}</view>
<view class="menu-arrow">></view>
</view>
<view class="menu-item" bindtap="goToApplications">
<view class="menu-icon">📝</view>
<text class="menu-text">投保申请</text>
<view class="menu-badge" wx:if="{{stats.applicationCount > 0}}">{{stats.applicationCount}}</view>
<view class="menu-arrow">></view>
</view>
<view class="menu-item" bindtap="goToClaims">
<view class="menu-icon">💰</view>
<text class="menu-text">理赔申请</text>
<view class="menu-badge" wx:if="{{stats.claimCount > 0}}">{{stats.claimCount}}</view>
<view class="menu-arrow">></view>
</view>
<view class="menu-item" bindtap="goToFavorites">
<view class="menu-icon">❤️</view>
<text class="menu-text">收藏产品</text>
<view class="menu-badge" wx:if="{{stats.favoriteCount > 0}}">{{stats.favoriteCount}}</view>
<view class="menu-arrow">></view>
</view>
</view>
</view>
<!-- 账户管理 -->
<view class="menu-group">
<view class="group-title">账户管理</view>
<view class="menu-list">
<view class="menu-item" bindtap="goToProfile">
<view class="menu-icon">👤</view>
<text class="menu-text">个人资料</text>
<view class="menu-arrow">></view>
</view>
<view class="menu-item" bindtap="goToSettings">
<view class="menu-icon">⚙️</view>
<text class="menu-text">设置</text>
<view class="menu-arrow">></view>
</view>
<view class="menu-item" bindtap="goToSecurity">
<view class="menu-icon">🔒</view>
<text class="menu-text">安全中心</text>
<view class="menu-arrow">></view>
</view>
</view>
</view>
<!-- 帮助支持 -->
<view class="menu-group">
<view class="group-title">帮助支持</view>
<view class="menu-list">
<view class="menu-item" bindtap="goToHelp">
<view class="menu-icon">❓</view>
<text class="menu-text">帮助中心</text>
<view class="menu-arrow">></view>
</view>
<view class="menu-item" bindtap="goToContact">
<view class="menu-icon">📞</view>
<text class="menu-text">联系客服</text>
<view class="menu-arrow">></view>
</view>
<view class="menu-item" bindtap="goToFeedback">
<view class="menu-icon">💬</view>
<text class="menu-text">意见反馈</text>
<view class="menu-arrow">></view>
</view>
<view class="menu-item" bindtap="goToAbout">
<view class="menu-icon"></view>
<text class="menu-text">关于我们</text>
<view class="menu-arrow">></view>
</view>
</view>
</view>
</view>
<!-- 退出登录 -->
<view wx:if="{{isLoggedIn}}" class="logout-section">
<button class="logout-btn" bindtap="onLogout">退出登录</button>
</view>
</view>

View File

@@ -0,0 +1,219 @@
/* pages/my/my.wxss */
.container {
background-color: #f5f5f5;
min-height: 100vh;
}
/* 用户信息区域 */
.user-section {
background: linear-gradient(135deg, #1890ff, #40a9ff);
padding: 40rpx 30rpx 60rpx;
color: white;
}
.user-info {
display: flex;
align-items: center;
margin-bottom: 30rpx;
}
.avatar {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
background: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
margin-right: 30rpx;
overflow: hidden;
}
.avatar-img {
width: 100%;
height: 100%;
border-radius: 60rpx;
}
.avatar-text {
font-size: 48rpx;
font-weight: bold;
color: white;
}
.user-details {
flex: 1;
}
.username {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 10rpx;
display: block;
}
.user-phone {
font-size: 28rpx;
opacity: 0.8;
display: block;
}
.arrow-icon {
font-size: 32rpx;
opacity: 0.8;
}
.login-prompt {
text-align: center;
}
.login-btn {
background: rgba(255, 255, 255, 0.2);
color: white;
border: 2rpx solid rgba(255, 255, 255, 0.3);
border-radius: 30rpx;
font-size: 28rpx;
padding: 20rpx 60rpx;
}
/* 数据统计 */
.stats-section {
background: white;
margin: -30rpx 30rpx 20rpx;
border-radius: 12rpx;
padding: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.stats-grid {
display: flex;
justify-content: space-around;
}
.stat-item {
text-align: center;
flex: 1;
}
.stat-number {
font-size: 48rpx;
font-weight: bold;
color: #1890ff;
display: block;
margin-bottom: 10rpx;
}
.stat-label {
font-size: 24rpx;
color: #666;
display: block;
}
/* 功能菜单 */
.menu-section {
padding: 0 30rpx;
}
.menu-group {
margin-bottom: 30rpx;
}
.group-title {
font-size: 28rpx;
color: #999;
margin-bottom: 20rpx;
padding-left: 10rpx;
}
.menu-list {
background: white;
border-radius: 12rpx;
overflow: hidden;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
}
.menu-item {
display: flex;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
position: relative;
}
.menu-item:last-child {
border-bottom: none;
}
.menu-icon {
font-size: 40rpx;
margin-right: 30rpx;
width: 50rpx;
text-align: center;
}
.menu-text {
flex: 1;
font-size: 30rpx;
color: #333;
}
.menu-badge {
background: #ff4d4f;
color: white;
font-size: 20rpx;
padding: 4rpx 12rpx;
border-radius: 20rpx;
margin-right: 20rpx;
min-width: 30rpx;
text-align: center;
}
.menu-arrow {
font-size: 24rpx;
color: #ccc;
}
/* 退出登录 */
.logout-section {
padding: 30rpx;
}
.logout-btn {
background: #ff4d4f;
color: white;
border: none;
border-radius: 12rpx;
font-size: 30rpx;
padding: 25rpx;
width: 100%;
}
.logout-btn::after {
border: none;
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.stats-grid {
flex-wrap: wrap;
}
.stat-item {
width: 50%;
margin-bottom: 20rpx;
}
}
/* 动画效果 */
.menu-item {
transition: background-color 0.3s;
}
.menu-item:active {
background-color: #f8f8f8;
}
.stat-item:active {
transform: scale(0.95);
transition: transform 0.2s;
}

View File

@@ -0,0 +1,316 @@
// pages/policies/policies.js
Page({
/**
* 页面的初始数据
*/
data: {
// 当前激活的标签
activeTab: 'all',
// 保单列表
policiesList: [],
// 过滤后的保单列表
filteredPolicies: [],
// 统计数据
stats: {
totalPolicies: 0,
activePolicies: 0,
expiringPolicies: 0
},
// 加载状态
loading: false,
// 是否有更多数据
hasMore: true,
// 当前页码
currentPage: 1
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('我的保单页加载', options)
this.loadPoliciesList()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('我的保单页渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('我的保单页显示')
this.loadPoliciesList()
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('我的保单页隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('我的保单页卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
this.setData({
currentPage: 1,
hasMore: true
})
this.loadPoliciesList()
wx.stopPullDownRefresh()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
if (this.data.hasMore && !this.data.loading) {
this.loadMore()
}
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '我的保单',
path: '/pages/policies/policies',
imageUrl: '/static/images/share-policies.jpg'
}
},
/**
* 加载保单列表
*/
loadPoliciesList() {
this.setData({ loading: true })
console.log('加载保单列表')
// 模拟API调用
setTimeout(() => {
const mockPolicies = this.getMockPolicies()
this.setData({
policiesList: mockPolicies,
filteredPolicies: this.filterPolicies(mockPolicies, this.data.activeTab),
stats: this.calculateStats(mockPolicies),
loading: false
})
}, 1000)
},
/**
* 获取模拟保单数据
*/
getMockPolicies() {
return [
{
id: '1',
name: '综合意外伤害保险',
description: '全面保障,安心出行',
status: 'active',
statusText: '有效',
policyNo: 'POL20240115001',
coverageAmount: 50,
premium: 299,
effectiveDate: '2024-01-15',
expiryDate: '2025-01-15'
},
{
id: '2',
name: '重大疾病保险',
description: '重疾保障,守护健康',
status: 'active',
statusText: '有效',
policyNo: 'POL20240110002',
coverageAmount: 30,
premium: 1200,
effectiveDate: '2024-01-10',
expiryDate: '2025-01-10'
},
{
id: '3',
name: '定期寿险',
description: '家庭保障,责任担当',
status: 'expiring',
statusText: '即将到期',
policyNo: 'POL20231201003',
coverageAmount: 100,
premium: 800,
effectiveDate: '2023-12-01',
expiryDate: '2024-12-01'
},
{
id: '4',
name: '医疗保险',
description: '医疗费用,安心报销',
status: 'expired',
statusText: '已过期',
policyNo: 'POL20221101004',
coverageAmount: 20,
premium: 500,
effectiveDate: '2022-11-01',
expiryDate: '2023-11-01'
},
{
id: '5',
name: '车险',
description: '车辆保障,出行无忧',
status: 'active',
statusText: '有效',
policyNo: 'POL20240120005',
coverageAmount: 200,
premium: 3000,
effectiveDate: '2024-01-20',
expiryDate: '2025-01-20'
}
]
},
/**
* 过滤保单列表
*/
filterPolicies(policies, status) {
if (status === 'all') {
return policies
}
return policies.filter(policy => policy.status === status)
},
/**
* 计算统计数据
*/
calculateStats(policies) {
const totalPolicies = policies.length
const activePolicies = policies.filter(policy => policy.status === 'active').length
const expiringPolicies = policies.filter(policy => policy.status === 'expiring').length
return {
totalPolicies,
activePolicies,
expiringPolicies
}
},
/**
* 切换标签
*/
switchTab(e) {
const tab = e.currentTarget.dataset.tab
console.log('切换标签:', tab)
this.setData({
activeTab: tab,
filteredPolicies: this.filterPolicies(this.data.policiesList, tab)
})
},
/**
* 跳转到保单详情
*/
goToPolicyDetail(e) {
const policyId = e.currentTarget.dataset.id
console.log('跳转到保单详情:', policyId)
wx.navigateTo({
url: `/pages/policy-detail/policy-detail?id=${policyId}`
})
},
/**
* 跳转到新保单投保
*/
goToNewPolicy() {
console.log('跳转到新保单投保')
wx.switchTab({
url: '/pages/products/products'
})
},
/**
* 跳转到续保
*/
goToRenewal(e) {
const policyId = e.currentTarget.dataset.id
console.log('跳转到续保:', policyId)
wx.navigateTo({
url: `/pages/renewal/renewal?policyId=${policyId}`
})
},
/**
* 跳转到理赔申请
*/
goToClaim(e) {
const policyId = e.currentTarget.dataset.id
console.log('跳转到理赔申请:', policyId)
wx.navigateTo({
url: `/pages/claims/claims?policyId=${policyId}`
})
},
/**
* 加载更多
*/
loadMore() {
if (this.data.loading || !this.data.hasMore) return
this.setData({ loading: true })
console.log('加载更多保单数据')
// 模拟加载更多数据
setTimeout(() => {
const newPolicies = this.getMockPolicies().map((policy, index) => ({
...policy,
id: (this.data.policiesList.length + index + 1).toString(),
policyNo: 'POL' + (Date.now() + index),
effectiveDate: this.formatDate(new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000)),
expiryDate: this.formatDate(new Date(Date.now() + Math.random() * 365 * 24 * 60 * 60 * 1000))
}))
const updatedPolicies = [...this.data.policiesList, ...newPolicies]
this.setData({
policiesList: updatedPolicies,
filteredPolicies: this.filterPolicies(updatedPolicies, this.data.activeTab),
stats: this.calculateStats(updatedPolicies),
loading: false,
hasMore: updatedPolicies.length < 20 // 模拟最多20条数据
})
}, 1000)
},
/**
* 格式化日期
*/
formatDate(date) {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
})

View File

@@ -0,0 +1,8 @@
{
"usingComponents": {},
"navigationBarTitleText": "我的保单",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5",
"onReachBottomDistance": 50
}

View File

@@ -0,0 +1,155 @@
<!--pages/policies/policies.wxml-->
<view class="container">
<!-- 页面头部 -->
<view class="header">
<view class="header-content">
<text class="header-title">我的保单</text>
<text class="header-desc">管理您的保险保单</text>
</view>
<view class="header-actions">
<button class="action-btn" bindtap="goToNewPolicy">
<text class="btn-icon">+</text>
<text class="btn-text">投保</text>
</button>
</view>
</view>
<!-- 保单统计 -->
<view class="stats-section">
<view class="stats-card">
<view class="stat-item">
<text class="stat-number">{{stats.totalPolicies}}</text>
<text class="stat-label">总保单数</text>
</view>
<view class="stat-item">
<text class="stat-number">{{stats.activePolicies}}</text>
<text class="stat-label">有效保单</text>
</view>
<view class="stat-item">
<text class="stat-number">{{stats.expiringPolicies}}</text>
<text class="stat-label">即将到期</text>
</view>
</view>
</view>
<!-- 筛选标签 -->
<view class="filter-tabs">
<view
class="tab-item {{activeTab === 'all' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="all"
>
<text>全部</text>
</view>
<view
class="tab-item {{activeTab === 'active' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="active"
>
<text>有效</text>
</view>
<view
class="tab-item {{activeTab === 'expired' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="expired"
>
<text>已过期</text>
</view>
<view
class="tab-item {{activeTab === 'expiring' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="expiring"
>
<text>即将到期</text>
</view>
</view>
<!-- 保单列表 -->
<view class="policies-list">
<view
class="policy-item"
wx:for="{{filteredPolicies}}"
wx:key="id"
bindtap="goToPolicyDetail"
data-id="{{item.id}}"
>
<view class="policy-header">
<view class="policy-info">
<text class="policy-name">{{item.name}}</text>
<text class="policy-desc">{{item.description}}</text>
</view>
<view class="policy-status {{item.status}}">
<text class="status-text">{{item.statusText}}</text>
</view>
</view>
<view class="policy-details">
<view class="detail-item">
<text class="detail-label">保单号:</text>
<text class="detail-value">{{item.policyNo}}</text>
</view>
<view class="detail-item">
<text class="detail-label">保险金额:</text>
<text class="detail-value amount">¥{{item.coverageAmount}}万</text>
</view>
<view class="detail-item">
<text class="detail-label">保费:</text>
<text class="detail-value">¥{{item.premium}}/年</text>
</view>
<view class="detail-item">
<text class="detail-label">生效日期:</text>
<text class="detail-value">{{item.effectiveDate}}</text>
</view>
<view class="detail-item">
<text class="detail-label">到期日期:</text>
<text class="detail-value">{{item.expiryDate}}</text>
</view>
</view>
<view class="policy-actions">
<button
class="action-btn small"
bindtap="goToPolicyDetail"
data-id="{{item.id}}"
catchtap="true"
>
查看详情
</button>
<button
class="action-btn small primary"
bindtap="goToRenewal"
data-id="{{item.id}}"
catchtap="true"
wx:if="{{item.status === 'expiring' || item.status === 'expired'}}"
>
续保
</button>
<button
class="action-btn small secondary"
bindtap="goToClaim"
data-id="{{item.id}}"
catchtap="true"
wx:if="{{item.status === 'active'}}"
>
申请理赔
</button>
</view>
</view>
</view>
<!-- 空状态 -->
<view wx:if="{{filteredPolicies.length === 0}}" class="empty-state">
<view class="empty-icon">📄</view>
<text class="empty-title">暂无保单</text>
<text class="empty-desc">您还没有任何保险保单</text>
<button class="empty-btn" bindtap="goToNewPolicy">
立即投保
</button>
</view>
<!-- 加载更多 -->
<view wx:if="{{hasMore && filteredPolicies.length > 0}}" class="load-more">
<view class="loading-text" wx:if="{{loading}}">加载中...</view>
<view class="load-more-btn" wx:else bindtap="loadMore">加载更多</view>
</view>
</view>

View File

@@ -0,0 +1,374 @@
/* pages/policies/policies.wxss */
.container {
background: #f5f5f5;
min-height: 100vh;
}
/* 页面头部 */
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
color: white;
}
.header-content {
flex: 1;
}
.header-title {
font-size: 36rpx;
font-weight: bold;
margin-bottom: 10rpx;
display: block;
}
.header-desc {
font-size: 24rpx;
opacity: 0.9;
display: block;
}
.header-actions {
margin-left: 20rpx;
}
.action-btn {
display: flex;
align-items: center;
padding: 15rpx 25rpx;
background: rgba(255, 255, 255, 0.2);
border: 2rpx solid rgba(255, 255, 255, 0.3);
border-radius: 25rpx;
color: white;
font-size: 24rpx;
transition: all 0.3s;
}
.action-btn::after {
border: none;
}
.action-btn:active {
background: rgba(255, 255, 255, 0.3);
transform: scale(0.95);
}
.btn-icon {
font-size: 28rpx;
margin-right: 8rpx;
}
.btn-text {
font-size: 24rpx;
}
/* 保单统计 */
.stats-section {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.stats-card {
display: flex;
justify-content: space-around;
}
.stat-item {
text-align: center;
}
.stat-number {
font-size: 48rpx;
font-weight: bold;
color: #1890ff;
margin-bottom: 10rpx;
display: block;
}
.stat-label {
font-size: 24rpx;
color: #666;
}
/* 筛选标签 */
.filter-tabs {
background: white;
display: flex;
padding: 0 30rpx;
border-bottom: 1rpx solid #e8e8e8;
}
.tab-item {
flex: 1;
text-align: center;
padding: 30rpx 0;
font-size: 28rpx;
color: #666;
position: relative;
transition: all 0.3s;
}
.tab-item.active {
color: #1890ff;
font-weight: bold;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background: #1890ff;
border-radius: 2rpx;
}
/* 保单列表 */
.policies-list {
padding: 20rpx;
}
.policy-item {
background: white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
transition: all 0.3s;
}
.policy-item:active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
}
.policy-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 20rpx;
}
.policy-info {
flex: 1;
}
.policy-name {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
display: block;
}
.policy-desc {
font-size: 24rpx;
color: #666;
line-height: 1.4;
}
.policy-status {
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: bold;
}
.policy-status.active {
background: #f6ffed;
color: #52c41a;
}
.policy-status.expiring {
background: #fff7e6;
color: #d48806;
}
.policy-status.expired {
background: #fff2f0;
color: #ff4d4f;
}
.status-text {
font-size: 22rpx;
}
/* 保单详情 */
.policy-details {
margin-bottom: 25rpx;
}
.detail-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
font-size: 24rpx;
}
.detail-item:last-child {
margin-bottom: 0;
}
.detail-label {
color: #666;
}
.detail-value {
color: #333;
font-weight: 500;
}
.detail-value.amount {
color: #ff4757;
font-weight: bold;
font-size: 26rpx;
}
/* 保单操作 */
.policy-actions {
display: flex;
gap: 15rpx;
justify-content: flex-end;
}
.action-btn.small {
padding: 12rpx 24rpx;
font-size: 22rpx;
border-radius: 20rpx;
min-width: 120rpx;
}
.action-btn.small.primary {
background: #1890ff;
color: white;
border: none;
}
.action-btn.small.secondary {
background: #52c41a;
color: white;
border: none;
}
.action-btn.small:not(.primary):not(.secondary) {
background: #f0f0f0;
color: #666;
border: none;
}
.action-btn.small::after {
border: none;
}
.action-btn.small:active {
transform: scale(0.95);
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 100rpx 40rpx;
}
.empty-icon {
font-size: 120rpx;
margin-bottom: 30rpx;
opacity: 0.5;
}
.empty-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 15rpx;
display: block;
}
.empty-desc {
font-size: 26rpx;
color: #666;
margin-bottom: 40rpx;
display: block;
}
.empty-btn {
background: #1890ff;
color: white;
border: none;
border-radius: 25rpx;
padding: 20rpx 40rpx;
font-size: 28rpx;
font-weight: bold;
}
.empty-btn::after {
border: none;
}
.empty-btn:active {
transform: scale(0.95);
}
/* 加载更多 */
.load-more {
text-align: center;
padding: 30rpx;
}
.loading-text {
font-size: 24rpx;
color: #666;
}
.load-more-btn {
font-size: 26rpx;
color: #1890ff;
padding: 15rpx 30rpx;
background: white;
border-radius: 25rpx;
display: inline-block;
border: 2rpx solid #1890ff;
transition: all 0.3s;
}
.load-more-btn:active {
background: #e6f7ff;
transform: scale(0.95);
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.header {
padding: 20rpx;
}
.policies-list {
padding: 15rpx;
}
.policy-item {
padding: 20rpx;
}
}
/* 动画效果 */
.policy-item {
transition: all 0.3s ease;
}
.tab-item {
transition: all 0.3s ease;
}
.action-btn {
transition: all 0.3s ease;
}

View File

@@ -0,0 +1,283 @@
// pages/policy-detail/policy-detail.js
Page({
/**
* 页面的初始数据
*/
data: {
// 保单ID
policyId: '',
// 保单信息
policyInfo: {}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('保单详情页加载', options)
const { id } = options
if (id) {
this.setData({ policyId: id })
this.loadPolicyDetail(id)
} else {
wx.showToast({
title: '保单ID不能为空',
icon: 'none'
})
setTimeout(() => {
wx.navigateBack()
}, 1500)
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('保单详情页渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('保单详情页显示')
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('保单详情页隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('保单详情页卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
this.loadPolicyDetail(this.data.policyId)
wx.stopPullDownRefresh()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '保单详情',
path: `/pages/policy-detail/policy-detail?id=${this.data.policyId}`,
imageUrl: '/static/images/share-policy-detail.jpg'
}
},
/**
* 加载保单详情
*/
loadPolicyDetail(policyId) {
console.log('加载保单详情:', policyId)
// 模拟保单详情数据
const mockPolicyInfo = this.getMockPolicyDetail(policyId)
this.setData({ policyInfo: mockPolicyInfo })
},
/**
* 获取模拟保单详情数据
*/
getMockPolicyDetail(policyId) {
const mockPolicies = {
'1': {
id: '1',
policyNo: 'POL20240115001',
productName: '综合意外伤害保险',
status: 'active',
statusIcon: '✓',
statusText: '有效',
statusDesc: '您的保单正在有效期内,享受全面保障',
coverageAmount: 50,
premium: 299,
effectiveDate: '2024-01-15',
expiryDate: '2025-01-15',
paymentMethod: '年缴',
insurancePeriod: '1年',
insuredName: '张先生',
idCard: '110101199001011234',
phone: '138****1234',
gender: '男',
birthDate: '1990-01-01',
beneficiary: {
name: '张太太',
relation: '配偶',
idCard: '110101199201011234'
},
coverage: [
{
name: '意外身故',
amount: '50万元',
description: '因意外事故导致身故,给付保险金额'
},
{
name: '意外伤残',
amount: '最高50万元',
description: '因意外事故导致伤残,按伤残等级给付'
},
{
name: '意外医疗',
amount: '5万元',
description: '因意外事故产生的医疗费用,实报实销'
},
{
name: '住院津贴',
amount: '200元/天',
description: '因意外事故住院,每日给付津贴'
}
],
paymentRecords: [
{
period: '2024年保费',
amount: 299,
status: 'paid',
statusText: '已缴费',
paymentDate: '2024-01-15'
}
],
claimsRecords: [
{
type: '意外医疗',
amount: 2500,
status: 'completed',
statusText: '已完成',
date: '2024-01-20'
}
]
},
'2': {
id: '2',
policyNo: 'POL20240110002',
productName: '重大疾病保险',
status: 'active',
statusIcon: '✓',
statusText: '有效',
statusDesc: '您的保单正在有效期内,享受重疾保障',
coverageAmount: 30,
premium: 1200,
effectiveDate: '2024-01-10',
expiryDate: '2025-01-10',
paymentMethod: '年缴',
insurancePeriod: '1年',
insuredName: '李女士',
idCard: '110101198501011234',
phone: '139****5678',
gender: '女',
birthDate: '1985-01-01',
beneficiary: {
name: '李女士',
relation: '本人',
idCard: '110101198501011234'
},
coverage: [
{
name: '重大疾病',
amount: '30万元',
description: '确诊重大疾病,一次性给付保险金额'
},
{
name: '轻症疾病',
amount: '6万元',
description: '确诊轻症疾病给付20%保险金额'
},
{
name: '身故保障',
amount: '30万元',
description: '因疾病或意外身故,给付保险金额'
}
],
paymentRecords: [
{
period: '2024年保费',
amount: 1200,
status: 'paid',
statusText: '已缴费',
paymentDate: '2024-01-10'
}
],
claimsRecords: []
}
}
return mockPolicies[policyId] || mockPolicies['1']
},
/**
* 跳转到续保
*/
goToRenewal() {
console.log('跳转到续保')
wx.navigateTo({
url: `/pages/renewal/renewal?policyId=${this.data.policyId}`
})
},
/**
* 跳转到理赔申请
*/
goToClaim() {
console.log('跳转到理赔申请')
wx.navigateTo({
url: `/pages/claims/claims?policyId=${this.data.policyId}`
})
},
/**
* 下载保单
*/
downloadPolicy() {
console.log('下载保单')
wx.showModal({
title: '下载保单',
content: '是否下载电子保单到本地?',
confirmText: '下载',
success: (res) => {
if (res.confirm) {
wx.showToast({
title: '保单下载中...',
icon: 'loading'
})
// 模拟下载
setTimeout(() => {
wx.showToast({
title: '下载成功',
icon: 'success'
})
}, 2000)
}
}
})
},
/**
* 返回上一页
*/
goBack() {
console.log('返回上一页')
wx.navigateBack()
}
})

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "保单详情",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5"
}

View File

@@ -0,0 +1,199 @@
<!--pages/policy-detail/policy-detail.wxml-->
<view class="container">
<!-- 保单状态卡片 -->
<view class="status-card">
<view class="status-icon {{policyInfo.status}}">
<text class="icon-text">{{policyInfo.statusIcon}}</text>
</view>
<view class="status-content">
<text class="status-title">{{policyInfo.statusText}}</text>
<text class="status-desc">{{policyInfo.statusDesc}}</text>
</view>
</view>
<!-- 保单基本信息 -->
<view class="info-section">
<view class="section-title">保单信息</view>
<view class="info-card">
<view class="info-item">
<text class="info-label">保单号</text>
<text class="info-value">{{policyInfo.policyNo}}</text>
</view>
<view class="info-item">
<text class="info-label">产品名称</text>
<text class="info-value">{{policyInfo.productName}}</text>
</view>
<view class="info-item">
<text class="info-label">保险金额</text>
<text class="info-value amount">¥{{policyInfo.coverageAmount}}万</text>
</view>
<view class="info-item">
<text class="info-label">年缴保费</text>
<text class="info-value amount">¥{{policyInfo.premium}}</text>
</view>
<view class="info-item">
<text class="info-label">生效日期</text>
<text class="info-value">{{policyInfo.effectiveDate}}</text>
</view>
<view class="info-item">
<text class="info-label">到期日期</text>
<text class="info-value">{{policyInfo.expiryDate}}</text>
</view>
<view class="info-item">
<text class="info-label">缴费方式</text>
<text class="info-value">{{policyInfo.paymentMethod}}</text>
</view>
<view class="info-item">
<text class="info-label">保险期间</text>
<text class="info-value">{{policyInfo.insurancePeriod}}</text>
</view>
</view>
</view>
<!-- 被保险人信息 -->
<view class="insured-section">
<view class="section-title">被保险人信息</view>
<view class="insured-card">
<view class="insured-item">
<text class="insured-label">姓名</text>
<text class="insured-value">{{policyInfo.insuredName}}</text>
</view>
<view class="insured-item">
<text class="insured-label">身份证号</text>
<text class="insured-value">{{policyInfo.idCard}}</text>
</view>
<view class="insured-item">
<text class="insured-label">手机号</text>
<text class="insured-value">{{policyInfo.phone}}</text>
</view>
<view class="insured-item">
<text class="insured-label">性别</text>
<text class="insured-value">{{policyInfo.gender}}</text>
</view>
<view class="insured-item">
<text class="insured-label">出生日期</text>
<text class="insured-value">{{policyInfo.birthDate}}</text>
</view>
</view>
</view>
<!-- 受益人信息 -->
<view class="beneficiary-section" wx:if="{{policyInfo.beneficiary}}">
<view class="section-title">受益人信息</view>
<view class="beneficiary-card">
<view class="beneficiary-item">
<text class="beneficiary-label">受益人姓名</text>
<text class="beneficiary-value">{{policyInfo.beneficiary.name}}</text>
</view>
<view class="beneficiary-item">
<text class="beneficiary-label">关系</text>
<text class="beneficiary-value">{{policyInfo.beneficiary.relation}}</text>
</view>
<view class="beneficiary-item">
<text class="beneficiary-label">身份证号</text>
<text class="beneficiary-value">{{policyInfo.beneficiary.idCard}}</text>
</view>
</view>
</view>
<!-- 保障内容 -->
<view class="coverage-section">
<view class="section-title">保障内容</view>
<view class="coverage-list">
<view class="coverage-item" wx:for="{{policyInfo.coverage}}" wx:key="index">
<view class="coverage-header">
<text class="coverage-name">{{item.name}}</text>
<text class="coverage-amount">{{item.amount}}</text>
</view>
<text class="coverage-desc">{{item.description}}</text>
</view>
</view>
</view>
<!-- 缴费记录 -->
<view class="payment-section">
<view class="section-title">缴费记录</view>
<view class="payment-list">
<view class="payment-item" wx:for="{{policyInfo.paymentRecords}}" wx:key="index">
<view class="payment-info">
<text class="payment-period">{{item.period}}</text>
<text class="payment-amount">¥{{item.amount}}</text>
</view>
<view class="payment-status {{item.status}}">
<text class="status-text">{{item.statusText}}</text>
</view>
<view class="payment-date">{{item.paymentDate}}</view>
</view>
</view>
</view>
<!-- 理赔记录 -->
<view class="claims-section" wx:if="{{policyInfo.claimsRecords.length > 0}}">
<view class="section-title">理赔记录</view>
<view class="claims-list">
<view class="claim-item" wx:for="{{policyInfo.claimsRecords}}" wx:key="index">
<view class="claim-info">
<text class="claim-type">{{item.type}}</text>
<text class="claim-amount">¥{{item.amount}}</text>
</view>
<view class="claim-status {{item.status}}">
<text class="status-text">{{item.statusText}}</text>
</view>
<view class="claim-date">{{item.date}}</view>
</view>
</view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-actions">
<button
class="action-btn secondary"
bindtap="goBack"
>
返回
</button>
<button
class="action-btn primary"
bindtap="goToRenewal"
wx:if="{{policyInfo.status === 'expiring' || policyInfo.status === 'expired'}}"
>
续保
</button>
<button
class="action-btn primary"
bindtap="goToClaim"
wx:if="{{policyInfo.status === 'active'}}"
>
申请理赔
</button>
<button
class="action-btn secondary"
bindtap="downloadPolicy"
wx:if="{{policyInfo.status === 'active'}}"
>
下载保单
</button>
</view>
</view>

View File

@@ -0,0 +1,392 @@
/* pages/policy-detail/policy-detail.wxss */
.container {
background: #f5f5f5;
min-height: 100vh;
padding-bottom: 120rpx;
}
/* 保单状态卡片 */
.status-card {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 40rpx 30rpx;
display: flex;
align-items: center;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.status-icon {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 30rpx;
font-size: 50rpx;
font-weight: bold;
}
.status-icon.active {
background: #f6ffed;
color: #52c41a;
}
.status-icon.expiring {
background: #fff7e6;
color: #d48806;
}
.status-icon.expired {
background: #fff2f0;
color: #ff4d4f;
}
.icon-text {
font-size: 50rpx;
}
.status-content {
flex: 1;
}
.status-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.status-desc {
font-size: 24rpx;
color: #666;
line-height: 1.4;
}
/* 信息区域 */
.info-section,
.insured-section,
.beneficiary-section,
.coverage-section,
.payment-section,
.claims-section {
background: white;
margin: 20rpx;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 25rpx;
padding-bottom: 15rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.info-card,
.insured-card,
.beneficiary-card {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.info-item,
.insured-item,
.beneficiary-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #f5f5f5;
}
.info-item:last-child,
.insured-item:last-child,
.beneficiary-item:last-child {
border-bottom: none;
}
.info-label,
.insured-label,
.beneficiary-label {
font-size: 26rpx;
color: #666;
min-width: 150rpx;
}
.info-value,
.insured-value,
.beneficiary-value {
font-size: 26rpx;
color: #333;
font-weight: 500;
text-align: right;
flex: 1;
}
.info-value.amount,
.insured-value.amount,
.beneficiary-value.amount {
color: #ff4757;
font-weight: bold;
font-size: 28rpx;
}
/* 保障内容 */
.coverage-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.coverage-item {
padding: 25rpx;
background: #f8f9fa;
border-radius: 12rpx;
border-left: 4rpx solid #1890ff;
}
.coverage-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
}
.coverage-name {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.coverage-amount {
font-size: 32rpx;
font-weight: bold;
color: #ff4757;
}
.coverage-desc {
font-size: 24rpx;
color: #666;
line-height: 1.5;
}
/* 缴费记录 */
.payment-list {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.payment-item {
display: flex;
align-items: center;
padding: 20rpx;
background: #f8f9fa;
border-radius: 12rpx;
}
.payment-info {
flex: 1;
}
.payment-period {
font-size: 26rpx;
color: #333;
margin-bottom: 5rpx;
display: block;
}
.payment-amount {
font-size: 24rpx;
color: #666;
}
.payment-status {
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: bold;
margin-right: 20rpx;
}
.payment-status.paid {
background: #f6ffed;
color: #52c41a;
}
.payment-status.pending {
background: #fff7e6;
color: #d48806;
}
.payment-status.overdue {
background: #fff2f0;
color: #ff4d4f;
}
.status-text {
font-size: 22rpx;
}
.payment-date {
font-size: 22rpx;
color: #999;
min-width: 120rpx;
text-align: right;
}
/* 理赔记录 */
.claims-list {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.claim-item {
display: flex;
align-items: center;
padding: 20rpx;
background: #f8f9fa;
border-radius: 12rpx;
}
.claim-info {
flex: 1;
}
.claim-type {
font-size: 26rpx;
color: #333;
margin-bottom: 5rpx;
display: block;
}
.claim-amount {
font-size: 24rpx;
color: #666;
}
.claim-status {
padding: 8rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: bold;
margin-right: 20rpx;
}
.claim-status.completed {
background: #f6ffed;
color: #52c41a;
}
.claim-status.processing {
background: #e6f7ff;
color: #1890ff;
}
.claim-status.rejected {
background: #fff2f0;
color: #ff4d4f;
}
.claim-date {
font-size: 22rpx;
color: #999;
min-width: 120rpx;
text-align: right;
}
/* 底部操作栏 */
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: white;
padding: 20rpx 30rpx;
border-top: 1rpx solid #e8e8e8;
display: flex;
gap: 15rpx;
z-index: 100;
}
.action-btn {
flex: 1;
height: 80rpx;
border-radius: 40rpx;
font-size: 26rpx;
font-weight: bold;
border: none;
transition: all 0.3s;
}
.action-btn.primary {
background: #1890ff;
color: white;
}
.action-btn.secondary {
background: #f0f0f0;
color: #666;
}
.action-btn::after {
border: none;
}
.action-btn:active {
transform: scale(0.95);
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.status-card,
.info-section,
.insured-section,
.beneficiary-section,
.coverage-section,
.payment-section,
.claims-section {
margin: 15rpx;
padding: 20rpx;
}
.bottom-actions {
padding: 15rpx 20rpx;
}
}
/* 动画效果 */
.coverage-item {
transition: all 0.3s ease;
}
.coverage-item:hover {
transform: translateY(-2rpx);
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.payment-item {
transition: all 0.3s ease;
}
.payment-item:active {
background: #e6f7ff;
transform: scale(0.98);
}
.claim-item {
transition: all 0.3s ease;
}
.claim-item:active {
background: #e6f7ff;
transform: scale(0.98);
}

View File

@@ -0,0 +1,426 @@
// pages/product-detail/product-detail.js
Page({
/**
* 页面的初始数据
*/
data: {
// 产品ID
productId: '',
// 当前激活的标签页
activeTab: 'overview',
// 产品信息
productInfo: {},
// 相关产品
relatedProducts: [],
// 是否已收藏
isFavorited: false,
// 是否可以投保
canApply: false,
// 加载状态
loading: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('产品详情页加载', options)
const { id } = options
if (id) {
this.setData({ productId: id })
this.loadProductDetail(id)
} else {
wx.showToast({
title: '产品ID不能为空',
icon: 'none'
})
setTimeout(() => {
wx.navigateBack()
}, 1500)
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('产品详情页渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('产品详情页显示')
this.checkLoginStatus()
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('产品详情页隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('产品详情页卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
this.loadProductDetail(this.data.productId)
wx.stopPullDownRefresh()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
const { productInfo } = this.data
return {
title: productInfo.name || '保险产品详情',
path: `/pages/product-detail/product-detail?id=${this.data.productId}`,
imageUrl: productInfo.image || '/static/images/share-product.jpg'
}
},
/**
* 加载产品详情
*/
loadProductDetail(productId) {
this.setData({ loading: true })
console.log('加载产品详情:', productId)
// 模拟API调用
setTimeout(() => {
const mockProduct = this.getMockProductDetail(productId)
this.setData({
productInfo: mockProduct,
relatedProducts: this.getMockRelatedProducts(),
loading: false
})
this.checkFavoritedStatus()
}, 1000)
},
/**
* 获取模拟产品详情数据
*/
getMockProductDetail(productId) {
const mockProducts = {
'1': {
id: '1',
name: '综合意外伤害保险',
subtitle: '全面保障,安心出行',
image: '/static/images/product-1.jpg',
isHot: true,
minPremium: 99,
priceDesc: '年缴保费,保障一年',
description: '本产品为综合意外伤害保险,提供全面的意外伤害保障,包括意外身故、意外伤残、意外医疗等保障内容,让您出行更安心。',
features: [
{ icon: '🛡️', text: '全面保障' },
{ icon: '⚡', text: '快速理赔' },
{ icon: '💰', text: '性价比高' },
{ icon: '📱', text: '在线投保' }
],
targetGroup: [
'18-65周岁身体健康者',
'经常出差或外出人员',
'从事高风险职业者',
'家庭经济支柱'
],
highlights: [
{
icon: '🛡️',
title: '保障全面',
description: '涵盖意外身故、伤残、医疗等多种保障,全方位保护您的安全'
},
{
icon: '⚡',
title: '理赔快速',
description: '7x24小时理赔服务材料齐全3个工作日内完成理赔'
},
{
icon: '💰',
title: '性价比高',
description: '保费低廉,保障全面,是您最经济实惠的选择'
}
],
coverage: [
{
name: '意外身故保险金',
amount: '50万元',
description: '被保险人因意外伤害导致身故,给付意外身故保险金',
conditions: '意外伤害事故发生之日起180日内身故'
},
{
name: '意外伤残保险金',
amount: '最高50万元',
description: '被保险人因意外伤害导致伤残,按伤残等级给付保险金',
conditions: '意外伤害事故发生之日起180日内伤残'
},
{
name: '意外医疗保险金',
amount: '5万元',
description: '被保险人因意外伤害产生的医疗费用,按比例报销',
conditions: '免赔额100元赔付比例90%'
}
],
terms: [
{
title: '保险期间',
content: '本保险合同的保险期间为一年,自保险单载明的保险期间开始日零时起至保险期间届满日二十四时止。'
},
{
title: '等待期',
content: '本保险合同无等待期,自保险期间开始日零时起即承担保险责任。'
},
{
title: '免赔额',
content: '意外医疗保险金免赔额为100元超出部分按90%比例赔付。'
}
],
notices: [
'请仔细阅读保险条款,特别是责任免除条款',
'投保时请如实告知健康状况,否则可能影响理赔',
'保险期间内可随时退保,按日计算退还保费',
'理赔时需提供相关证明材料',
'如有疑问请及时联系客服'
]
},
'2': {
id: '2',
name: '重大疾病保险',
subtitle: '重疾保障,守护健康',
image: '/static/images/product-2.jpg',
isHot: false,
minPremium: 299,
priceDesc: '年缴保费,保障终身',
description: '本产品为重大疾病保险,提供重大疾病保障,包括恶性肿瘤、急性心肌梗塞、脑中风后遗症等重大疾病保障。',
features: [
{ icon: '🏥', text: '重疾保障' },
{ icon: '💊', text: '医疗费用' },
{ icon: '🔄', text: '多次赔付' },
{ icon: '👨‍👩‍👧‍👦', text: '家庭保障' }
],
targetGroup: [
'18-55周岁身体健康者',
'有家族病史者',
'关注健康保障者',
'家庭经济支柱'
],
highlights: [
{
icon: '🏥',
title: '重疾保障',
description: '涵盖100种重大疾病保障范围广泛让您安心无忧'
},
{
icon: '💊',
title: '医疗费用',
description: '提供高额医疗费用保障,减轻家庭经济负担'
},
{
icon: '🔄',
title: '多次赔付',
description: '部分疾病可多次赔付,保障更全面'
}
],
coverage: [
{
name: '重大疾病保险金',
amount: '30万元',
description: '被保险人确诊重大疾病,给付重大疾病保险金',
conditions: '等待期90天确诊即赔'
},
{
name: '轻症疾病保险金',
amount: '6万元',
description: '被保险人确诊轻症疾病,给付轻症疾病保险金',
conditions: '等待期90天最多赔付3次'
},
{
name: '身故保险金',
amount: '30万元',
description: '被保险人身故,给付身故保险金',
conditions: '等待期90天'
}
],
terms: [
{
title: '保险期间',
content: '本保险合同的保险期间为终身,自保险单载明的保险期间开始日零时起至被保险人身故时止。'
},
{
title: '等待期',
content: '本保险合同的等待期为90天等待期内因疾病导致保险事故不承担保险责任。'
},
{
title: '缴费期间',
content: '缴费期间为20年投保人可选择年缴或月缴。'
}
],
notices: [
'请仔细阅读保险条款,特别是责任免除条款',
'投保时请如实告知健康状况,否则可能影响理赔',
'等待期内因疾病导致保险事故,不承担保险责任',
'理赔时需提供医院诊断证明',
'如有疑问请及时联系客服'
]
}
}
return mockProducts[productId] || mockProducts['1']
},
/**
* 获取模拟相关产品数据
*/
getMockRelatedProducts() {
return [
{
id: '2',
name: '重大疾病保险',
image: '/static/images/product-2.jpg',
minPremium: 299
},
{
id: '3',
name: '定期寿险',
image: '/static/images/product-3.jpg',
minPremium: 199
},
{
id: '4',
name: '医疗保险',
image: '/static/images/product-4.jpg',
minPremium: 399
}
]
},
/**
* 检查登录状态
*/
checkLoginStatus() {
const token = wx.getStorageSync('token')
this.setData({
canApply: !!token
})
},
/**
* 检查收藏状态
*/
checkFavoritedStatus() {
const favorites = wx.getStorageSync('favorites') || []
const isFavorited = favorites.includes(this.data.productId)
this.setData({ isFavorited })
},
/**
* 切换标签页
*/
switchTab(e) {
const tab = e.currentTarget.dataset.tab
console.log('切换标签页:', tab)
this.setData({ activeTab: tab })
},
/**
* 添加到收藏
*/
addToFavorites() {
const { productId, isFavorited } = this.data
let favorites = wx.getStorageSync('favorites') || []
if (isFavorited) {
// 取消收藏
favorites = favorites.filter(id => id !== productId)
wx.showToast({
title: '已取消收藏',
icon: 'success'
})
} else {
// 添加收藏
favorites.push(productId)
wx.showToast({
title: '已添加到收藏',
icon: 'success'
})
}
wx.setStorageSync('favorites', favorites)
this.setData({ isFavorited: !isFavorited })
},
/**
* 跳转到咨询页面
*/
goToConsultation() {
console.log('跳转到咨询页面')
wx.navigateTo({
url: '/pages/consultation/consultation'
})
},
/**
* 跳转到投保页面
*/
goToApplication() {
const { canApply, productId } = this.data
if (!canApply) {
wx.showModal({
title: '提示',
content: '请先登录后再进行投保',
confirmText: '去登录',
success: (res) => {
if (res.confirm) {
wx.navigateTo({
url: '/pages/login/login'
})
}
}
})
return
}
console.log('跳转到投保页面:', productId)
wx.navigateTo({
url: `/pages/application/application?productId=${productId}`
})
},
/**
* 跳转到其他产品详情页
*/
goToProductDetail(e) {
const productId = e.currentTarget.dataset.id
console.log('跳转到产品详情页:', productId)
wx.redirectTo({
url: `/pages/product-detail/product-detail?id=${productId}`
})
}
})

View File

@@ -0,0 +1,8 @@
{
"usingComponents": {},
"navigationBarTitleText": "产品详情",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5",
"onReachBottomDistance": 50
}

View File

@@ -0,0 +1,177 @@
<!--pages/product-detail/product-detail.wxml-->
<view class="container">
<!-- 产品头部信息 -->
<view class="product-header">
<view class="product-image">
<image src="{{productInfo.image || '/static/images/product-default.jpg'}}" mode="aspectFill" class="product-img" />
<view class="product-tag" wx:if="{{productInfo.isHot}}">热门</view>
</view>
<view class="product-info">
<view class="product-title">{{productInfo.name}}</view>
<view class="product-subtitle">{{productInfo.subtitle}}</view>
<view class="price-section">
<view class="price-main">
<text class="currency">¥</text>
<text class="price">{{productInfo.minPremium}}</text>
<text class="price-unit">起</text>
</view>
<view class="price-desc">{{productInfo.priceDesc}}</view>
</view>
<view class="product-features">
<view class="feature-item" wx:for="{{productInfo.features}}" wx:key="index">
<text class="feature-icon">{{item.icon}}</text>
<text class="feature-text">{{item.text}}</text>
</view>
</view>
</view>
</view>
<!-- 产品详情标签页 -->
<view class="detail-tabs">
<view
class="tab-item {{activeTab === 'overview' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="overview"
>
<text>产品概述</text>
</view>
<view
class="tab-item {{activeTab === 'coverage' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="coverage"
>
<text>保障内容</text>
</view>
<view
class="tab-item {{activeTab === 'terms' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="terms"
>
<text>条款说明</text>
</view>
</view>
<!-- 产品概述 -->
<view wx:if="{{activeTab === 'overview'}}" class="tab-content">
<view class="overview-section">
<view class="section-title">产品简介</view>
<text class="section-content">{{productInfo.description}}</text>
</view>
<view class="overview-section">
<view class="section-title">适用人群</view>
<view class="target-group">
<view class="group-item" wx:for="{{productInfo.targetGroup}}" wx:key="index">
<text class="group-icon">✓</text>
<text class="group-text">{{item}}</text>
</view>
</view>
</view>
<view class="overview-section">
<view class="section-title">产品特色</view>
<view class="highlights">
<view class="highlight-item" wx:for="{{productInfo.highlights}}" wx:key="index">
<view class="highlight-icon">{{item.icon}}</view>
<view class="highlight-content">
<text class="highlight-title">{{item.title}}</text>
<text class="highlight-desc">{{item.description}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 保障内容 -->
<view wx:if="{{activeTab === 'coverage'}}" class="tab-content">
<view class="coverage-section">
<view class="coverage-item" wx:for="{{productInfo.coverage}}" wx:key="index">
<view class="coverage-header">
<text class="coverage-name">{{item.name}}</text>
<text class="coverage-amount">{{item.amount}}</text>
</view>
<text class="coverage-desc">{{item.description}}</text>
<view class="coverage-conditions" wx:if="{{item.conditions}}">
<text class="condition-label">保障条件:</text>
<text class="condition-text">{{item.conditions}}</text>
</view>
</view>
</view>
</view>
<!-- 条款说明 -->
<view wx:if="{{activeTab === 'terms'}}" class="tab-content">
<view class="terms-section">
<view class="terms-item" wx:for="{{productInfo.terms}}" wx:key="index">
<view class="terms-title">{{item.title}}</view>
<text class="terms-content">{{item.content}}</text>
</view>
</view>
</view>
<!-- 投保须知 -->
<view class="notice-section">
<view class="notice-title">投保须知</view>
<view class="notice-list">
<view class="notice-item" wx:for="{{productInfo.notices}}" wx:key="index">
<text class="notice-number">{{index + 1}}</text>
<text class="notice-text">{{item}}</text>
</view>
</view>
</view>
<!-- 相关产品推荐 -->
<view class="related-products" wx:if="{{relatedProducts.length > 0}}">
<view class="section-title">相关产品推荐</view>
<scroll-view class="product-scroll" scroll-x="true">
<view class="product-list">
<view
class="related-product-item"
wx:for="{{relatedProducts}}"
wx:key="id"
bindtap="goToProductDetail"
data-id="{{item.id}}"
>
<image src="{{item.image}}" class="related-product-img" mode="aspectFill" />
<view class="related-product-info">
<text class="related-product-name">{{item.name}}</text>
<text class="related-product-price">¥{{item.minPremium}}起</text>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-actions">
<view class="action-left">
<button class="action-btn secondary" bindtap="addToFavorites">
<text class="btn-icon">{{isFavorited ? '❤️' : '🤍'}}</text>
<text class="btn-text">{{isFavorited ? '已收藏' : '收藏'}}</text>
</button>
<button class="action-btn secondary" bindtap="goToConsultation">
<text class="btn-icon">💬</text>
<text class="btn-text">咨询</text>
</button>
</view>
<button
class="apply-btn {{canApply ? 'active' : 'disabled'}}"
bindtap="goToApplication"
disabled="{{!canApply}}"
>
{{loading ? '处理中...' : '立即投保'}}
</button>
</view>
</view>
<!-- 加载状态 -->
<view wx:if="{{loading}}" class="loading-overlay">
<view class="loading-content">
<view class="loading-spinner"></view>
<text class="loading-text">加载中...</text>
</view>
</view>

View File

@@ -0,0 +1,575 @@
/* pages/product-detail/product-detail.wxss */
.container {
background: #f5f5f5;
min-height: 100vh;
padding-bottom: 120rpx;
}
/* 产品头部信息 */
.product-header {
background: white;
padding: 30rpx;
margin-bottom: 20rpx;
}
.product-image {
position: relative;
width: 100%;
height: 300rpx;
margin-bottom: 30rpx;
border-radius: 16rpx;
overflow: hidden;
}
.product-img {
width: 100%;
height: 100%;
}
.product-tag {
position: absolute;
top: 20rpx;
right: 20rpx;
background: #ff4757;
color: white;
font-size: 22rpx;
padding: 8rpx 16rpx;
border-radius: 20rpx;
}
.product-info {
padding: 0 10rpx;
}
.product-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
line-height: 1.4;
}
.product-subtitle {
font-size: 26rpx;
color: #666;
margin-bottom: 20rpx;
line-height: 1.4;
}
.price-section {
margin-bottom: 30rpx;
}
.price-main {
display: flex;
align-items: baseline;
margin-bottom: 10rpx;
}
.currency {
font-size: 28rpx;
color: #ff4757;
font-weight: bold;
}
.price {
font-size: 48rpx;
color: #ff4757;
font-weight: bold;
margin: 0 5rpx;
}
.price-unit {
font-size: 24rpx;
color: #999;
}
.price-desc {
font-size: 22rpx;
color: #999;
}
.product-features {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.feature-item {
display: flex;
align-items: center;
background: #f8f9fa;
padding: 12rpx 20rpx;
border-radius: 20rpx;
font-size: 24rpx;
color: #666;
}
.feature-icon {
margin-right: 8rpx;
font-size: 26rpx;
}
.feature-text {
font-size: 24rpx;
}
/* 详情标签页 */
.detail-tabs {
display: flex;
background: white;
margin-bottom: 20rpx;
border-bottom: 1rpx solid #e8e8e8;
}
.tab-item {
flex: 1;
text-align: center;
padding: 30rpx 0;
font-size: 28rpx;
color: #666;
position: relative;
transition: all 0.3s;
}
.tab-item.active {
color: #1890ff;
font-weight: bold;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background: #1890ff;
border-radius: 2rpx;
}
/* 标签页内容 */
.tab-content {
background: white;
padding: 30rpx;
margin-bottom: 20rpx;
}
.overview-section {
margin-bottom: 40rpx;
}
.overview-section:last-child {
margin-bottom: 0;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
padding-bottom: 10rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.section-content {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
.target-group {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.group-item {
display: flex;
align-items: center;
font-size: 26rpx;
color: #666;
}
.group-icon {
color: #52c41a;
margin-right: 15rpx;
font-size: 24rpx;
}
.group-text {
flex: 1;
}
.highlights {
display: flex;
flex-direction: column;
gap: 25rpx;
}
.highlight-item {
display: flex;
align-items: flex-start;
padding: 20rpx;
background: #f8f9fa;
border-radius: 12rpx;
}
.highlight-icon {
font-size: 40rpx;
margin-right: 20rpx;
margin-top: 5rpx;
}
.highlight-content {
flex: 1;
}
.highlight-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
display: block;
}
.highlight-desc {
font-size: 24rpx;
color: #666;
line-height: 1.5;
}
/* 保障内容 */
.coverage-section {
display: flex;
flex-direction: column;
gap: 25rpx;
}
.coverage-item {
padding: 25rpx;
background: #f8f9fa;
border-radius: 12rpx;
border-left: 4rpx solid #1890ff;
}
.coverage-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
}
.coverage-name {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.coverage-amount {
font-size: 32rpx;
font-weight: bold;
color: #ff4757;
}
.coverage-desc {
font-size: 26rpx;
color: #666;
line-height: 1.5;
margin-bottom: 10rpx;
display: block;
}
.coverage-conditions {
font-size: 24rpx;
color: #999;
}
.condition-label {
font-weight: bold;
}
.condition-text {
margin-left: 10rpx;
}
/* 条款说明 */
.terms-section {
display: flex;
flex-direction: column;
gap: 25rpx;
}
.terms-item {
padding: 25rpx;
background: #f8f9fa;
border-radius: 12rpx;
}
.terms-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 15rpx;
}
.terms-content {
font-size: 26rpx;
color: #666;
line-height: 1.6;
}
/* 投保须知 */
.notice-section {
background: white;
padding: 30rpx;
margin-bottom: 20rpx;
}
.notice-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 25rpx;
padding-bottom: 10rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.notice-list {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.notice-item {
display: flex;
align-items: flex-start;
font-size: 26rpx;
color: #666;
line-height: 1.5;
}
.notice-number {
width: 40rpx;
height: 40rpx;
background: #1890ff;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 22rpx;
font-weight: bold;
margin-right: 20rpx;
flex-shrink: 0;
margin-top: 5rpx;
}
.notice-text {
flex: 1;
}
/* 相关产品推荐 */
.related-products {
background: white;
padding: 30rpx;
margin-bottom: 20rpx;
}
.product-scroll {
white-space: nowrap;
}
.product-list {
display: flex;
gap: 20rpx;
padding: 10rpx 0;
}
.related-product-item {
width: 200rpx;
background: #f8f9fa;
border-radius: 12rpx;
overflow: hidden;
flex-shrink: 0;
}
.related-product-img {
width: 100%;
height: 120rpx;
}
.related-product-info {
padding: 15rpx;
}
.related-product-name {
font-size: 24rpx;
color: #333;
margin-bottom: 8rpx;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.related-product-price {
font-size: 22rpx;
color: #ff4757;
font-weight: bold;
}
/* 底部操作栏 */
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: white;
padding: 20rpx 30rpx;
border-top: 1rpx solid #e8e8e8;
display: flex;
align-items: center;
gap: 20rpx;
z-index: 100;
}
.action-left {
display: flex;
gap: 15rpx;
}
.action-btn {
display: flex;
flex-direction: column;
align-items: center;
padding: 15rpx 20rpx;
background: #f8f9fa;
border: none;
border-radius: 12rpx;
font-size: 20rpx;
color: #666;
min-width: 80rpx;
}
.action-btn::after {
border: none;
}
.btn-icon {
font-size: 32rpx;
margin-bottom: 5rpx;
}
.btn-text {
font-size: 20rpx;
}
.apply-btn {
flex: 1;
height: 80rpx;
border-radius: 40rpx;
font-size: 32rpx;
font-weight: bold;
border: none;
transition: all 0.3s;
}
.apply-btn.active {
background: #1890ff;
color: white;
}
.apply-btn.disabled {
background: #f0f0f0;
color: #ccc;
}
.apply-btn::after {
border: none;
}
/* 加载状态 */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.loading-content {
background: white;
padding: 40rpx;
border-radius: 16rpx;
display: flex;
flex-direction: column;
align-items: center;
gap: 20rpx;
}
.loading-spinner {
width: 60rpx;
height: 60rpx;
border: 4rpx solid #f0f0f0;
border-top: 4rpx solid #1890ff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-text {
font-size: 28rpx;
color: #666;
}
/* 响应式设计 */
@media (max-width: 750rpx) {
.product-header {
padding: 20rpx;
}
.product-image {
height: 250rpx;
}
.tab-content {
padding: 20rpx;
}
.bottom-actions {
padding: 15rpx 20rpx;
}
}
/* 动画效果 */
.tab-item {
transition: all 0.3s ease;
}
.coverage-item {
transition: all 0.3s ease;
}
.coverage-item:hover {
transform: translateY(-2rpx);
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
}
.related-product-item:active {
transform: scale(0.95);
}
.action-btn:active {
transform: scale(0.95);
}

View File

@@ -0,0 +1,346 @@
// pages/products/products.js
Page({
/**
* 页面的初始数据
*/
data: {
// 搜索关键词
searchKeyword: '',
// 产品分类
categories: [
{ id: 'all', name: '全部' },
{ id: 'life', name: '寿险' },
{ id: 'health', name: '健康险' },
{ id: 'accident', name: '意外险' },
{ id: 'vehicle', name: '车险' },
{ id: 'property', name: '财产险' },
{ id: 'travel', name: '旅行险' },
{ id: 'pet', name: '宠物险' }
],
// 当前选中的分类
selectedCategory: 'all',
// 排序选项
sortOptions: [
{ value: 'default', label: '默认排序' },
{ value: 'price_asc', label: '价格从低到高' },
{ value: 'price_desc', label: '价格从高到低' },
{ value: 'popular', label: '热门推荐' }
],
// 当前排序方式
sortBy: 'default',
// 视图模式list 或 grid
viewMode: 'list',
// 产品列表
productList: [],
// 分页信息
currentPage: 1,
pageSize: 10,
totalCount: 0,
hasMore: true,
// 加载状态
loading: false
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log('产品页面加载完成')
this.loadProducts()
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
console.log('产品页面渲染完成')
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
console.log('产品页面显示')
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
console.log('产品页面隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('产品页面卸载')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
console.log('下拉刷新')
this.refreshProducts()
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
console.log('上拉触底')
if (this.data.hasMore && !this.data.loading) {
this.loadMore()
}
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
return {
title: '保险产品 - 专业安全的保险平台',
path: '/pages/products/products',
imageUrl: '/static/images/share-products.jpg'
}
},
/**
* 搜索输入事件
*/
onSearchInput(e) {
this.setData({
searchKeyword: e.detail.value
})
},
/**
* 执行搜索
*/
onSearch() {
console.log('执行搜索:', this.data.searchKeyword)
this.refreshProducts()
},
/**
* 分类切换
*/
onCategoryChange(e) {
const category = e.currentTarget.dataset.category
console.log('切换分类:', category)
this.setData({
selectedCategory: category
})
this.refreshProducts()
},
/**
* 排序切换
*/
onSortChange(e) {
const sort = e.currentTarget.dataset.sort
console.log('切换排序:', sort)
this.setData({
sortBy: sort
})
this.refreshProducts()
},
/**
* 视图模式切换
*/
onViewModeChange(e) {
const mode = e.currentTarget.dataset.mode
console.log('切换视图模式:', mode)
this.setData({
viewMode: mode
})
},
/**
* 加载产品数据
*/
loadProducts() {
this.setData({ loading: true })
// 模拟API调用
setTimeout(() => {
const mockProducts = this.getMockProducts()
this.setData({
productList: mockProducts,
totalCount: mockProducts.length,
hasMore: false,
loading: false
})
}, 1000)
},
/**
* 刷新产品数据
*/
refreshProducts() {
this.setData({
currentPage: 1,
productList: [],
hasMore: true
})
this.loadProducts()
},
/**
* 加载更多产品
*/
loadMore() {
if (this.data.loading || !this.data.hasMore) return
this.setData({ loading: true })
// 模拟加载更多
setTimeout(() => {
const moreProducts = this.getMockProducts()
this.setData({
productList: [...this.data.productList, ...moreProducts],
currentPage: this.data.currentPage + 1,
hasMore: false,
loading: false
})
}, 1000)
},
/**
* 获取模拟产品数据
*/
getMockProducts() {
const allProducts = [
{
id: 1,
name: '综合意外险',
description: '全面保障意外伤害,保费低廉,保障全面',
min_premium: 99,
icon: '🛡️',
category: 'accident',
tags: ['热门', '性价比高', '保障全面']
},
{
id: 2,
name: '重疾保险',
description: '重大疾病保障,安心无忧,覆盖多种疾病',
min_premium: 299,
icon: '🏥',
category: 'health',
tags: ['保障全面', '疾病覆盖', '长期保障']
},
{
id: 3,
name: '车险',
description: '车辆全面保障,理赔快速,服务专业',
min_premium: 1999,
icon: '🚗',
category: 'vehicle',
tags: ['必买', '理赔快', '服务好']
},
{
id: 4,
name: '旅行险',
description: '出行安全保障全球覆盖24小时服务',
min_premium: 59,
icon: '✈️',
category: 'travel',
tags: ['短期', '全球', '24小时']
},
{
id: 5,
name: '寿险',
description: '终身保障,家庭责任,财富传承',
min_premium: 599,
icon: '👨‍👩‍👧‍👦',
category: 'life',
tags: ['终身', '家庭', '传承']
},
{
id: 6,
name: '财产险',
description: '家庭财产保障,火灾水灾全覆盖',
min_premium: 199,
icon: '🏠',
category: 'property',
tags: ['家庭', '财产', '全面']
},
{
id: 7,
name: '宠物险',
description: '宠物医疗保障,爱宠健康无忧',
min_premium: 89,
icon: '🐕',
category: 'pet',
tags: ['宠物', '医疗', '贴心']
},
{
id: 8,
name: '高端医疗险',
description: '高端医疗服务VIP待遇全球就医',
min_premium: 1999,
icon: '💎',
category: 'health',
tags: ['高端', 'VIP', '全球']
}
]
// 根据分类筛选
let filteredProducts = allProducts
if (this.data.selectedCategory !== 'all') {
filteredProducts = allProducts.filter(product =>
product.category === this.data.selectedCategory
)
}
// 根据搜索关键词筛选
if (this.data.searchKeyword) {
const keyword = this.data.searchKeyword.toLowerCase()
filteredProducts = filteredProducts.filter(product =>
product.name.toLowerCase().includes(keyword) ||
product.description.toLowerCase().includes(keyword)
)
}
// 根据排序方式排序
switch (this.data.sortBy) {
case 'price_asc':
filteredProducts.sort((a, b) => a.min_premium - b.min_premium)
break
case 'price_desc':
filteredProducts.sort((a, b) => b.min_premium - a.min_premium)
break
case 'popular':
// 模拟热门排序
filteredProducts.sort((a, b) => b.id - a.id)
break
default:
// 默认排序
break
}
return filteredProducts
},
/**
* 跳转到产品详情页
*/
goToProductDetail(e) {
const productId = e.currentTarget.dataset.id
console.log('跳转到产品详情页:', productId)
wx.navigateTo({
url: `/pages/product-detail/product-detail?id=${productId}`
})
}
})

View File

@@ -0,0 +1,8 @@
{
"usingComponents": {},
"navigationBarTitleText": "保险产品",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"backgroundColor": "#f5f5f5",
"onReachBottomDistance": 50
}

View File

@@ -0,0 +1,152 @@
<!--pages/products/products.wxml-->
<view class="container">
<!-- 搜索栏 -->
<view class="search-bar">
<view class="search-input-wrapper">
<input
class="search-input"
placeholder="搜索保险产品"
value="{{searchKeyword}}"
bindinput="onSearchInput"
confirm-type="search"
bindconfirm="onSearch"
/>
<view class="search-icon" bindtap="onSearch">🔍</view>
</view>
</view>
<!-- 分类筛选 -->
<view class="filter-section">
<scroll-view class="category-scroll" scroll-x="true">
<view class="category-list">
<view
wx:for="{{categories}}"
wx:key="id"
class="category-item {{selectedCategory === item.id ? 'active' : ''}}"
bindtap="onCategoryChange"
data-category="{{item.id}}"
>
<text class="category-text">{{item.name}}</text>
</view>
</view>
</scroll-view>
</view>
<!-- 排序选项 -->
<view class="sort-section">
<view class="sort-options">
<view
wx:for="{{sortOptions}}"
wx:key="value"
class="sort-item {{sortBy === item.value ? 'active' : ''}}"
bindtap="onSortChange"
data-sort="{{item.value}}"
>
<text class="sort-text">{{item.label}}</text>
</view>
</view>
</view>
<!-- 产品列表 -->
<view class="products-section">
<view class="products-header">
<text class="products-count">共 {{totalCount}} 个产品</text>
<view class="view-toggle">
<view
class="toggle-item {{viewMode === 'list' ? 'active' : ''}}"
bindtap="onViewModeChange"
data-mode="list"
>
<text>列表</text>
</view>
<view
class="toggle-item {{viewMode === 'grid' ? 'active' : ''}}"
bindtap="onViewModeChange"
data-mode="grid"
>
<text>网格</text>
</view>
</view>
</view>
<!-- 列表视图 -->
<view wx:if="{{viewMode === 'list'}}" class="product-list">
<view
wx:for="{{productList}}"
wx:key="id"
class="product-item-list"
bindtap="goToProductDetail"
data-id="{{item.id}}"
>
<view class="product-icon-large">{{item.icon}}</view>
<view class="product-info">
<text class="product-name">{{item.name}}</text>
<text class="product-desc">{{item.description}}</text>
<view class="product-tags">
<text
wx:for="{{item.tags}}"
wx:key="*this"
class="product-tag"
>{{item}}</text>
</view>
<view class="product-price-row">
<text class="price-label">起保费:</text>
<text class="price-value">¥{{item.min_premium}}</text>
<text class="price-unit">/年</text>
</view>
</view>
<view class="product-actions">
<button class="btn-apply" size="mini" type="primary">立即投保</button>
</view>
</view>
</view>
<!-- 网格视图 -->
<view wx:if="{{viewMode === 'grid'}}" class="product-grid">
<view
wx:for="{{productList}}"
wx:key="id"
class="product-item-grid"
bindtap="goToProductDetail"
data-id="{{item.id}}"
>
<view class="product-card">
<view class="product-icon">{{item.icon}}</view>
<view class="product-info">
<text class="product-name">{{item.name}}</text>
<text class="product-desc">{{item.description}}</text>
<view class="product-tags">
<text
wx:for="{{item.tags}}"
wx:key="*this"
class="product-tag"
>{{item}}</text>
</view>
<view class="product-price">
<text class="price-label">起保费:</text>
<text class="price-value">¥{{item.min_premium}}</text>
</view>
</view>
<button class="btn-apply" size="mini" type="primary">立即投保</button>
</view>
</view>
</view>
<!-- 加载状态 -->
<view wx:if="{{loading}}" class="loading">
<text>加载中...</text>
</view>
<!-- 空状态 -->
<view wx:if="{{!loading && productList.length === 0}}" class="empty-state">
<view class="empty-icon">📦</view>
<text class="empty-text">暂无产品</text>
<text class="empty-desc">请尝试其他筛选条件</text>
</view>
<!-- 加载更多 -->
<view wx:if="{{hasMore && !loading}}" class="load-more">
<button class="btn-load-more" bindtap="loadMore">加载更多</button>
</view>
</view>
</view>

View File

@@ -0,0 +1,367 @@
/* pages/products/products.wxss */
.container {
background-color: #f5f5f5;
min-height: 100vh;
}
/* 搜索栏 */
.search-bar {
background: #fff;
padding: 20rpx 30rpx;
border-bottom: 1px solid #f0f0f0;
}
.search-input-wrapper {
position: relative;
display: flex;
align-items: center;
background: #f8f8f8;
border-radius: 25rpx;
padding: 0 20rpx;
}
.search-input {
flex: 1;
height: 70rpx;
font-size: 28rpx;
padding: 0 20rpx;
}
.search-icon {
font-size: 32rpx;
color: #999;
padding: 10rpx;
}
/* 分类筛选 */
.filter-section {
background: #fff;
padding: 20rpx 0;
border-bottom: 1px solid #f0f0f0;
}
.category-scroll {
white-space: nowrap;
}
.category-list {
display: flex;
padding: 0 30rpx;
}
.category-item {
display: inline-block;
padding: 15rpx 30rpx;
margin-right: 20rpx;
background: #f8f8f8;
border-radius: 25rpx;
font-size: 26rpx;
color: #666;
transition: all 0.3s;
}
.category-item.active {
background: #1890ff;
color: #fff;
}
.category-text {
font-size: 26rpx;
}
/* 排序选项 */
.sort-section {
background: #fff;
padding: 20rpx 30rpx;
border-bottom: 1px solid #f0f0f0;
}
.sort-options {
display: flex;
justify-content: space-around;
}
.sort-item {
padding: 15rpx 30rpx;
border-radius: 20rpx;
font-size: 26rpx;
color: #666;
background: #f8f8f8;
transition: all 0.3s;
}
.sort-item.active {
background: #e6f7ff;
color: #1890ff;
}
.sort-text {
font-size: 26rpx;
}
/* 产品区域 */
.products-section {
padding: 30rpx;
}
.products-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.products-count {
font-size: 28rpx;
color: #666;
}
.view-toggle {
display: flex;
background: #f8f8f8;
border-radius: 20rpx;
overflow: hidden;
}
.toggle-item {
padding: 10rpx 20rpx;
font-size: 24rpx;
color: #666;
background: transparent;
transition: all 0.3s;
}
.toggle-item.active {
background: #1890ff;
color: #fff;
}
/* 列表视图 */
.product-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.product-item-list {
display: flex;
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
align-items: center;
}
.product-icon-large {
font-size: 80rpx;
width: 120rpx;
height: 120rpx;
margin-right: 30rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f0f8ff;
border-radius: 12rpx;
}
.product-info {
flex: 1;
}
.product-name {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.product-desc {
font-size: 26rpx;
color: #666;
margin-bottom: 15rpx;
display: block;
line-height: 1.4;
}
.product-tags {
display: flex;
flex-wrap: wrap;
gap: 10rpx;
margin-bottom: 15rpx;
}
.product-tag {
background: #e6f7ff;
color: #1890ff;
font-size: 20rpx;
padding: 5rpx 15rpx;
border-radius: 15rpx;
}
.product-price-row {
display: flex;
align-items: baseline;
}
.price-label {
font-size: 24rpx;
color: #999;
margin-right: 10rpx;
}
.price-value {
font-size: 36rpx;
color: #ff6b35;
font-weight: bold;
}
.price-unit {
font-size: 24rpx;
color: #999;
margin-left: 5rpx;
}
.product-actions {
margin-left: 20rpx;
}
.btn-apply {
background: #1890ff;
color: #fff;
border: none;
border-radius: 20rpx;
font-size: 24rpx;
padding: 15rpx 30rpx;
}
/* 网格视图 */
.product-grid {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.product-item-grid {
width: calc(50% - 10rpx);
}
.product-card {
background: #fff;
border-radius: 12rpx;
padding: 30rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
text-align: center;
}
.product-icon {
font-size: 60rpx;
width: 100rpx;
height: 100rpx;
margin: 0 auto 20rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f0f8ff;
border-radius: 50%;
}
.product-name {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
display: block;
}
.product-desc {
font-size: 24rpx;
color: #666;
margin-bottom: 15rpx;
display: block;
line-height: 1.4;
}
.product-tags {
display: flex;
flex-wrap: wrap;
gap: 8rpx;
justify-content: center;
margin-bottom: 15rpx;
}
.product-tag {
background: #e6f7ff;
color: #1890ff;
font-size: 18rpx;
padding: 4rpx 12rpx;
border-radius: 12rpx;
}
.product-price {
display: flex;
align-items: baseline;
justify-content: center;
margin-bottom: 20rpx;
}
.price-label {
font-size: 22rpx;
color: #999;
margin-right: 8rpx;
}
.price-value {
font-size: 32rpx;
color: #ff6b35;
font-weight: bold;
}
/* 加载状态 */
.loading {
text-align: center;
padding: 60rpx;
color: #999;
font-size: 28rpx;
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 100rpx 30rpx;
color: #999;
}
.empty-icon {
font-size: 120rpx;
margin-bottom: 30rpx;
opacity: 0.5;
}
.empty-text {
font-size: 32rpx;
color: #666;
margin-bottom: 15rpx;
display: block;
}
.empty-desc {
font-size: 26rpx;
color: #999;
display: block;
}
/* 加载更多 */
.load-more {
text-align: center;
padding: 40rpx;
}
.btn-load-more {
background: #f8f8f8;
color: #666;
border: 1px solid #e8e8e8;
border-radius: 25rpx;
font-size: 26rpx;
padding: 20rpx 60rpx;
}

View File

@@ -0,0 +1,9 @@
{
"desc": "保险小程序的索引配置文件",
"rules": [
{
"action": "allow",
"page": "*"
}
]
}

View File

@@ -1,28 +1,27 @@
<template>
<view class="container">
<!-- 轮播图 -->
<swiper class="banner-swiper" indicator-dots="true" autoplay="true" circular="true">
<swiper-item v-for="banner in banners" :key="banner.id">
<image :src="banner.image" class="banner-image" mode="aspectFill" />
</swiper-item>
</swiper>
<!-- 欢迎横幅 -->
<view class="welcome-banner">
<text class="welcome-title">欢迎使用保险服务</text>
<text class="welcome-subtitle">专业安全便捷的保险服务平台</text>
</view>
<!-- 快捷入口 -->
<view class="quick-actions">
<view class="action-item" @tap="goToProducts">
<image src="/static/images/icon-products.png" class="action-icon" />
<view class="action-icon">📋</view>
<text class="action-text">保险产品</text>
</view>
<view class="action-item" @tap="goToMy">
<image src="/static/images/icon-policy.png" class="action-icon" />
<view class="action-icon">📄</view>
<text class="action-text">我的保单</text>
</view>
<view class="action-item" @tap="goToClaims">
<image src="/static/images/icon-claim.png" class="action-icon" />
<view class="action-icon">💰</view>
<text class="action-text">理赔申请</text>
</view>
<view class="action-item" @tap="goToService">
<image src="/static/images/icon-service.png" class="action-icon" />
<view class="action-icon">📞</view>
<text class="action-text">客服服务</text>
</view>
</view>
@@ -34,14 +33,14 @@
<text class="section-more" @tap="goToProducts">更多 ></text>
</view>
<view class="product-grid" v-if="!loading">
<view class="product-grid">
<view
v-for="item in hotProducts"
v-for="item in mockProducts"
:key="item.id"
class="product-card"
@tap="goToProductDetail(item.id)"
>
<image :src="item.icon || '/static/images/default-product.png'" class="product-icon" />
<view class="product-icon">{{ item.icon }}</view>
<view class="product-info">
<text class="product-name">{{ item.name }}</text>
<text class="product-desc">{{ item.description }}</text>
@@ -52,17 +51,6 @@
</view>
</view>
</view>
<!-- 加载状态 -->
<view v-if="loading" class="loading">
<text>加载中...</text>
</view>
<!-- 空状态 -->
<view v-if="!loading && hotProducts.length === 0" class="empty-state">
<image src="/static/images/empty-products.png" class="empty-icon" />
<text>暂无热门产品</text>
</view>
</view>
<!-- 服务优势 -->
@@ -73,17 +61,17 @@
<view class="advantage-grid">
<view class="advantage-item">
<image src="/static/images/advantage-1.png" class="advantage-icon" />
<view class="advantage-icon">🛡</view>
<text class="advantage-title">专业保障</text>
<text class="advantage-desc">专业团队提供全方位保险咨询</text>
</view>
<view class="advantage-item">
<image src="/static/images/advantage-2.png" class="advantage-icon" />
<view class="advantage-icon"></view>
<text class="advantage-title">快速理赔</text>
<text class="advantage-desc">7x24小时快速理赔服务</text>
</view>
<view class="advantage-item">
<image src="/static/images/advantage-3.png" class="advantage-icon" />
<view class="advantage-icon">🔒</view>
<text class="advantage-title">安全可靠</text>
<text class="advantage-desc">银行级安全保障体系</text>
</view>
@@ -93,55 +81,41 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useInsuranceStore } from '@/store/insurance'
import { ref } from 'vue'
import { onShow } from '@dcloudio/uni-app'
// 状态管理
const insuranceStore = useInsuranceStore()
// 响应式数据
const loading = ref(true)
const banners = ref([
// 模拟数据
const mockProducts = ref([
{
id: 1,
image: '/static/images/banner-1.jpg',
title: '专业保险服务'
name: '综合意外险',
description: '全面保障意外伤害,保费低廉',
min_premium: 99,
icon: '🛡️'
},
{
id: 2,
image: '/static/images/banner-2.jpg',
title: '安心保障'
name: '重疾保险',
description: '重大疾病保障,安心无忧',
min_premium: 299,
icon: '🏥'
},
{
id: 3,
image: '/static/images/banner-3.jpg',
title: '贴心理赔'
name: '车险',
description: '车辆全面保障,理赔快速',
min_premium: 1999,
icon: '🚗'
},
{
id: 4,
name: '旅行险',
description: '出行安全保障,全球覆盖',
min_premium: 59,
icon: '✈️'
}
])
// 计算属性
const hotProducts = computed(() => insuranceStore.getHotProducts)
// 加载页面数据(动态调用保险端后端)
const loadPageData = async () => {
try {
loading.value = true
// 动态调用保险端 /api/insurance-types 接口获取热门产品
await insuranceStore.fetchHotProducts()
console.log('热门产品加载成功:', hotProducts.value)
} catch (error) {
console.error('加载首页数据失败:', error)
uni.showToast({
title: '加载失败',
icon: 'none'
})
} finally {
loading.value = false
}
}
// 页面跳转方法
const goToProductDetail = (id) => {
uni.navigateTo({
@@ -175,42 +149,36 @@ const goToService = () => {
})
}
// 下拉刷新
const onPullDownRefresh = async () => {
try {
await loadPageData()
} finally {
uni.stopPullDownRefresh()
}
}
// 生命周期
onMounted(() => {
loadPageData()
})
// 页面显示时刷新数据
// 页面显示时
onShow(() => {
// 如果数据为空,重新加载
if (hotProducts.value.length === 0) {
loadPageData()
}
console.log('首页显示')
})
</script>
<style scoped>
.container {
background-color: #f5f5f5;
min-height: 100vh;
}
.banner-swiper {
height: 400rpx;
width: 100%;
.welcome-banner {
background: linear-gradient(135deg, #1890ff, #40a9ff);
padding: 60rpx 30rpx;
text-align: center;
color: white;
}
.banner-image {
width: 100%;
height: 100%;
.welcome-title {
font-size: 48rpx;
font-weight: bold;
display: block;
margin-bottom: 20rpx;
}
.welcome-subtitle {
font-size: 28rpx;
opacity: 0.9;
display: block;
}
.quick-actions {
@@ -228,9 +196,15 @@ onShow(() => {
}
.action-icon {
font-size: 60rpx;
margin-bottom: 20rpx;
width: 80rpx;
height: 80rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f0f8ff;
border-radius: 50%;
}
.action-text {
@@ -277,10 +251,15 @@ onShow(() => {
}
.product-icon {
font-size: 60rpx;
width: 120rpx;
height: 120rpx;
margin-right: 30rpx;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f0f8ff;
}
.product-info {
@@ -331,9 +310,15 @@ onShow(() => {
}
.advantage-icon {
font-size: 60rpx;
width: 100rpx;
height: 100rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f0f8ff;
border-radius: 50%;
}
.advantage-title {
@@ -348,25 +333,4 @@ onShow(() => {
color: #666;
line-height: 1.4;
}
.loading {
text-align: center;
padding: 60rpx;
color: #999;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 80rpx 20rpx;
color: #999;
}
.empty-icon {
width: 120rpx;
height: 120rpx;
margin-bottom: 30rpx;
opacity: 0.5;
}
</style>