xiangyixiangqin/miniapp/pages/profile/preview.vue
2026-01-02 18:00:49 +08:00

542 lines
12 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="profile-preview-page">
<!-- 加载状态 -->
<Loading type="page" :loading="loading" />
<!-- 用户信息区域 -->
<view class="user-header" v-if="profile">
<!-- 照片轮播 -->
<view class="photo-section">
<swiper
v-if="profile.photos && profile.photos.length > 0"
class="photo-swiper"
:indicator-dots="profile.photos.length > 1"
indicator-color="rgba(255,255,255,0.5)"
indicator-active-color="#ffffff"
circular
>
<swiper-item v-for="(photo, index) in profile.photos" :key="index">
<image class="photo-image" :src="photo.photoUrl" mode="aspectFill" />
</swiper-item>
</swiper>
<view v-else class="no-photo">
<text>暂无照片</text>
</view>
<!-- 徽章 -->
<view class="badges">
<view v-if="profile.isMember" class="badge member-badge">会员</view>
<view v-if="profile.isRealName" class="badge realname-badge">已实名</view>
</view>
<!-- 照片公开状态 -->
<view class="photo-status">
<text>{{ profile.isPhotoPublic ? '照片公开' : '照片私密' }}</text>
</view>
</view>
<!-- 基本信息 -->
<view class="basic-info">
<view class="info-header">
<text class="nickname">{{ profile.nickname }}</text>
<text class="xiangqin-no">相亲号: {{ profile.xiangQinNo }}</text>
</view>
<view class="info-tags">
<text class="tag">{{ profile.age }}岁</text>
<text class="tag">{{ profile.workCity }}</text>
<text class="tag">{{ profile.height }}cm</text>
<text class="tag">{{ educationText }}</text>
</view>
</view>
</view>
<!-- 详细资料 -->
<view class="detail-section" v-if="profile">
<view class="section-title">详细资料</view>
<view class="detail-grid">
<view class="detail-item">
<text class="label">职业</text>
<text class="value">{{ profile.occupation || '未填写' }}</text>
</view>
<view class="detail-item">
<text class="label">月收入</text>
<text class="value">{{ incomeText }}</text>
</view>
<view class="detail-item">
<text class="label">学历</text>
<text class="value">{{ educationText }}</text>
</view>
<view class="detail-item">
<text class="label">身高</text>
<text class="value">{{ profile.height ? profile.height + 'cm' : '未填写' }}</text>
</view>
<view class="detail-item">
<text class="label">体重</text>
<text class="value">{{ profile.weight ? profile.weight + 'kg' : '未填写' }}</text>
</view>
<view class="detail-item">
<text class="label">房产</text>
<text class="value">{{ houseText }}</text>
</view>
<view class="detail-item">
<text class="label">车辆</text>
<text class="value">{{ carText }}</text>
</view>
<view class="detail-item">
<text class="label">婚姻状态</text>
<text class="value">{{ marriageText }}</text>
</view>
</view>
</view>
<!-- 自我介绍 -->
<view class="intro-section" v-if="profile && profile.introduction">
<view class="section-title">自我介绍</view>
<view class="intro-content">
<text>{{ profile.introduction }}</text>
</view>
</view>
<!-- 择偶要求 -->
<view class="requirement-section" v-if="profile && profile.requirement">
<view class="section-title">择偶要求</view>
<view class="requirement-content">
<view class="req-item" v-if="requirementAgeText">
<text class="label">年龄</text>
<text class="value">{{ requirementAgeText }}</text>
</view>
<view class="req-item" v-if="requirementHeightText">
<text class="label">身高</text>
<text class="value">{{ requirementHeightText }}</text>
</view>
<view class="req-item" v-if="requirementEducationText">
<text class="label">学历</text>
<text class="value">{{ requirementEducationText }}</text>
</view>
<view class="req-item" v-if="requirementCityText">
<text class="label">意向城市</text>
<text class="value">{{ requirementCityText }}</text>
</view>
</view>
</view>
<!-- 联系方式 -->
<view class="contact-section" v-if="profile">
<view class="section-title">联系方式</view>
<view class="contact-content">
<view class="contact-item">
<text class="label">微信号</text>
<text class="value">{{ profile.weChatNo || '未填写' }}</text>
</view>
</view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-actions">
<button class="btn-share" open-type="share">
<text class="btn-icon">📤</text>
<text>分享资料</text>
</button>
<button class="btn-edit" @click="handleEdit">
<text class="btn-icon"></text>
<text>编辑资料</text>
</button>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useUserStore } from '@/store/user.js'
import { getMyProfile } from '@/api/profile.js'
import { getAge } from '@/utils/format.js'
import Loading from '@/components/Loading/index.vue'
const userStore = useUserStore()
// 状态
const loading = ref(true)
const profile = ref(null)
// 选项映射
const educationMap = {
1: '高中及以下',
2: '大专',
3: '本科',
4: '硕士',
5: '博士'
}
const incomeMap = {
1: '5000以下',
2: '5000-10000',
3: '10000-20000',
4: '20000-50000',
5: '50000以上'
}
const houseMap = {
1: '无房',
2: '有房贷',
3: '有房无贷',
4: '多套房'
}
const carMap = {
1: '无车',
2: '有车贷',
3: '有车无贷'
}
const marriageMap = {
1: '未婚',
2: '离异无孩',
3: '离异有孩',
4: '丧偶'
}
// 计算属性
const educationText = computed(() => {
return educationMap[profile.value?.education] || '未填写'
})
const incomeText = computed(() => {
return incomeMap[profile.value?.monthlyIncome] || '未填写'
})
const houseText = computed(() => {
return houseMap[profile.value?.houseStatus] || '未填写'
})
const carText = computed(() => {
return carMap[profile.value?.carStatus] || '未填写'
})
const marriageText = computed(() => {
return marriageMap[profile.value?.marriageStatus] || '未填写'
})
// 择偶要求文本
const requirementAgeText = computed(() => {
const req = profile.value?.requirement
if (!req) return ''
if (req.ageMin && req.ageMax) return `${req.ageMin}-${req.ageMax}`
if (req.ageMin) return `${req.ageMin}岁以上`
if (req.ageMax) return `${req.ageMax}岁以下`
return ''
})
const requirementHeightText = computed(() => {
const req = profile.value?.requirement
if (!req) return ''
if (req.heightMin && req.heightMax) return `${req.heightMin}-${req.heightMax}cm`
if (req.heightMin) return `${req.heightMin}cm以上`
if (req.heightMax) return `${req.heightMax}cm以下`
return ''
})
const requirementEducationText = computed(() => {
const req = profile.value?.requirement
if (!req || !req.education || req.education.length === 0) return ''
return req.education.map(e => educationMap[e]).filter(Boolean).join('、')
})
const requirementCityText = computed(() => {
const req = profile.value?.requirement
if (!req) return ''
const cities = []
if (req.city1Province && req.city1City) {
cities.push(`${req.city1Province}${req.city1City}`)
}
if (req.city2Province && req.city2City) {
cities.push(`${req.city2Province}${req.city2City}`)
}
return cities.join('、')
})
// 加载我的资料
const loadMyProfile = async () => {
loading.value = true
try {
const res = await getMyProfile()
if (res && res.success && res.data) {
profile.value = {
...res.data,
age: getAge(res.data.birthYear)
}
}
} catch (error) {
console.error('加载资料失败:', error)
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
loading.value = false
}
}
// 编辑资料 (Requirements 9.4)
const handleEdit = () => {
uni.navigateTo({ url: '/pages/profile/edit' })
}
// 页面加载
onMounted(() => {
loadMyProfile()
})
// 分享配置 (Requirements 9.3)
defineExpose({
onShareAppMessage() {
return {
title: profile.value?.nickname ? `${profile.value.nickname}的相亲资料` : '相宜相亲',
path: `/pages/profile/detail?userId=${userStore.userId}`
}
}
})
</script>
<style lang="scss" scoped>
.profile-preview-page {
min-height: 100vh;
background-color: #f8f8f8;
padding-bottom: 140rpx;
}
// 照片区域
.photo-section {
position: relative;
.photo-swiper {
width: 100%;
height: 600rpx;
.photo-image {
width: 100%;
height: 100%;
}
}
.no-photo {
width: 100%;
height: 400rpx;
background-color: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
text {
color: #999;
font-size: 28rpx;
}
}
.badges {
position: absolute;
top: 20rpx;
left: 20rpx;
display: flex;
gap: 12rpx;
.badge {
padding: 8rpx 16rpx;
border-radius: 8rpx;
font-size: 24rpx;
color: #fff;
}
.member-badge {
background: linear-gradient(135deg, #ffd700 0%, #ffb800 100%);
}
.realname-badge {
background: linear-gradient(135deg, #4cd964 0%, #34c759 100%);
}
}
.photo-status {
position: absolute;
bottom: 20rpx;
right: 20rpx;
padding: 8rpx 16rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 8rpx;
text {
color: #fff;
font-size: 24rpx;
}
}
}
// 基本信息
.basic-info {
background-color: #fff;
padding: 30rpx;
.info-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
.nickname {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
.xiangqin-no {
font-size: 24rpx;
color: #999;
}
}
.info-tags {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
.tag {
padding: 8rpx 20rpx;
background-color: #f5f5f5;
border-radius: 20rpx;
font-size: 26rpx;
color: #666;
}
}
}
// 详细资料
.detail-section, .intro-section, .requirement-section, .contact-section {
background-color: #fff;
margin-top: 20rpx;
padding: 30rpx;
.section-title {
font-size: 30rpx;
font-weight: 600;
color: #333;
margin-bottom: 24rpx;
padding-bottom: 16rpx;
border-bottom: 1rpx solid #f0f0f0;
}
}
.detail-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24rpx;
.detail-item {
display: flex;
flex-direction: column;
.label {
font-size: 24rpx;
color: #999;
margin-bottom: 8rpx;
}
.value {
font-size: 28rpx;
color: #333;
}
}
}
// 自我介绍
.intro-content {
text {
font-size: 28rpx;
color: #666;
line-height: 1.8;
}
}
// 择偶要求
.requirement-content {
.req-item {
display: flex;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.label {
width: 120rpx;
font-size: 26rpx;
color: #999;
}
.value {
flex: 1;
font-size: 26rpx;
color: #333;
}
}
}
// 联系方式
.contact-content {
.contact-item {
display: flex;
align-items: center;
.label {
width: 120rpx;
font-size: 26rpx;
color: #999;
}
.value {
flex: 1;
font-size: 28rpx;
color: #333;
}
}
}
// 底部操作栏
.bottom-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
gap: 20rpx;
padding: 20rpx 30rpx;
background-color: #fff;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
button {
flex: 1;
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 44rpx;
font-size: 28rpx;
border: none;
&::after {
border: none;
}
.btn-icon {
margin-right: 8rpx;
}
}
.btn-share {
background-color: #f5f5f5;
color: #666;
}
.btn-edit {
background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
color: #fff;
}
}
</style>