542 lines
12 KiB
Vue
542 lines
12 KiB
Vue
<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>
|