xiangyixiangqin/miniapp/components/Popup/index.vue
2026-01-29 02:44:15 +08:00

469 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view v-if="visible" class="popup-mask" @click="handleMaskClick">
<view class="popup-container" :class="[`popup-${type}`]" @click.stop>
<!-- 关闭按钮 -->
<view v-if="showClose" class="close-btn" @click="handleClose">
<text>×</text>
</view>
<!-- 性别选择弹窗 -->
<template v-if="type === 'gender'">
<view class="popup-title">您想找儿媳?还是找女婿?</view>
<view class="popup-subtitle">登录资料后,推荐更精准</view>
<view class="gender-options">
<view class="gender-option male" @click="handleGenderSelect(2)">
<view class="gender-icon">♀</view>
<text>找儿媳</text>
</view>
<view class="gender-option female" @click="handleGenderSelect(1)">
<view class="gender-icon">♂</view>
<text>找女婿</text>
</view>
</view>
</template>
<!-- 每日弹窗 / 会员广告 -->
<template v-else-if="type === 'daily' || type === 'member'">
<image
v-if="imageUrl"
class="popup-image"
:src="imageUrl"
mode="widthFix"
@click="handleImageClick"
/>
<button
v-if="buttonText"
class="popup-btn"
@click="handleButtonClick"
>
{{ buttonText }}
</button>
</template>
<!-- 解锁确认弹窗 -->
<template v-else-if="type === 'unlock'">
<view class="popup-title">解锁联系方式</view>
<view class="unlock-info">
<text class="unlock-desc">解锁后可查看对方联系方式</text>
<text v-if="remainingQuota > 0" class="unlock-quota">剩余免费解锁次数:{{ remainingQuota }}</text>
<text v-else class="unlock-quota no-quota">您的解锁次数已用完</text>
</view>
<view class="popup-buttons">
<button class="popup-btn cancel" @click="handleClose">取消</button>
<button
v-if="remainingQuota > 0"
class="popup-btn confirm"
@click="handleConfirmUnlock"
>
确认解锁
</button>
<button
v-else
class="popup-btn confirm member"
@click="handleGoMember"
>
购买会员
</button>
</view>
</template>
<!-- 资料完善提示弹窗 -->
<template v-else-if="type === 'profile'">
<view class="popup-title">完善资料</view>
<view class="profile-info">
<text class="profile-desc">请先完善您的资料,才能联系对方</text>
</view>
<view class="popup-buttons">
<button class="popup-btn cancel" @click="handleClose">稍后再说</button>
<button class="popup-btn confirm" @click="handleGoProfile">去完善</button>
</view>
</template>
<!-- 资料审核中弹窗 -->
<template v-else-if="type === 'auditing'">
<view class="popup-title">资料审核中</view>
<view class="auditing-info">
<text class="auditing-desc">正在加急审核您的相亲资料,请耐心等待</text>
</view>
<button class="popup-btn auditing-btn" @click="handleClose">确定</button>
</template>
<!-- 服务号关注弹窗 - 样式与每日弹窗一致,只显示图片 -->
<template v-else-if="type === 'serviceAccount'">
<image
v-if="imageUrl"
class="popup-image"
:src="imageUrl"
mode="widthFix"
@click="handleImageClick"
/>
</template>
<!-- 通用弹窗 -->
<template v-else>
<image
v-if="imageUrl"
class="popup-image"
:src="imageUrl"
mode="aspectFit"
/>
<view v-if="title" class="popup-title">{{ title }}</view>
<view v-if="content" class="popup-content">{{ content }}</view>
<button
v-if="buttonText"
class="popup-btn"
@click="handleButtonClick"
>
{{ buttonText }}
</button>
</template>
</view>
</view>
</template>
<script>
export default {
name: 'Popup',
props: {
visible: {
type: Boolean,
default: false
},
type: {
type: String,
default: 'default',
validator: (value) => ['gender', 'daily', 'member', 'unlock', 'profile', 'auditing', 'serviceAccount', 'default'].includes(value)
},
imageUrl: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
buttonText: {
type: String,
default: ''
},
linkUrl: {
type: String,
default: ''
},
showClose: {
type: Boolean,
default: true
},
closeOnMask: {
type: Boolean,
default: true
},
remainingQuota: {
type: Number,
default: 0
}
},
emits: ['close', 'confirm', 'genderSelect', 'unlock', 'goProfile', 'goMember'],
methods: {
handleMaskClick() {
if (this.closeOnMask) {
this.handleClose()
}
},
handleClose() {
this.$emit('close')
},
handleGenderSelect(gender) {
this.$emit('genderSelect', gender)
},
handleImageClick() {
if (this.linkUrl) {
this.navigateToLink()
}
// 服务号弹窗点击图片后关闭弹窗
if (this.type === 'serviceAccount') {
this.$emit('confirm')
}
},
handleButtonClick() {
// 服务号弹窗由父组件处理跳转逻辑,不在这里处理
if (this.type !== 'serviceAccount' && this.linkUrl) {
this.navigateToLink()
}
this.$emit('confirm')
},
handleConfirmUnlock() {
this.$emit('unlock')
},
handleGoProfile() {
this.$emit('goProfile')
},
handleGoMember() {
this.$emit('goMember')
},
navigateToLink() {
if (!this.linkUrl) return
// 判断是内部页面还是外部链接
if (this.linkUrl.startsWith('/pages/')) {
uni.navigateTo({ url: this.linkUrl })
} else if (this.linkUrl.startsWith('http')) {
// 外部链接使用webview打开
uni.navigateTo({
url: `/pages/webview/index?url=${encodeURIComponent(this.linkUrl)}`
})
}
}
}
}
</script>
<style lang="scss" scoped>
.popup-mask {
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: 999;
}
.popup-container {
position: relative;
background: #fff;
border-radius: 24rpx;
padding: 40rpx;
width: 600rpx;
max-width: 90%;
.close-btn {
position: absolute;
top: 20rpx;
right: 20rpx;
width: 48rpx;
height: 48rpx;
display: flex;
align-items: center;
justify-content: center;
text {
font-size: 40rpx;
color: #999;
line-height: 1;
}
}
.popup-title {
font-size: 36rpx;
font-weight: 600;
color: #333;
text-align: center;
margin-bottom: 20rpx;
}
.popup-subtitle {
font-size: 26rpx;
color: #FF5F5F;
text-align: center;
margin-bottom: 30rpx;
}
.popup-content {
font-size: 28rpx;
color: #666;
text-align: center;
margin-bottom: 30rpx;
line-height: 1.6;
}
.popup-image {
width: 100%;
margin-bottom: 20rpx;
border-radius: 12rpx;
}
.popup-btn {
width: 100%;
height: 80rpx;
line-height: 80rpx;
background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
color: #fff;
font-size: 30rpx;
border-radius: 40rpx;
border: none;
&::after {
border: none;
}
&.cancel {
background: #f5f5f5;
color: #666;
}
&.confirm {
background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
color: #fff;
}
}
.popup-buttons {
display: flex;
gap: 20rpx;
.popup-btn {
flex: 1;
}
}
}
// 每日弹窗/会员广告/服务号弹窗样式 - 透明背景只显示图片
.popup-daily,
.popup-member,
.popup-serviceAccount {
background: transparent;
padding: 0;
width: auto;
max-width: 85%;
.popup-image {
width: 600rpx;
border-radius: 24rpx;
margin-bottom: 0;
}
.close-btn {
top: -60rpx;
right: 0;
text {
color: #fff;
font-size: 50rpx;
}
}
.popup-btn {
margin-top: 30rpx;
}
}
// 性别选择弹窗样式
.popup-gender {
.gender-options {
display: flex;
justify-content: space-around;
padding: 20rpx 0;
.gender-option {
display: flex;
flex-direction: column;
align-items: center;
padding: 30rpx 50rpx;
border-radius: 16rpx;
transition: all 0.3s;
&:active {
transform: scale(0.95);
}
.gender-icon {
font-size: 60rpx;
margin-bottom: 16rpx;
}
text {
font-size: 28rpx;
color: #333;
}
&.male {
background: linear-gradient(135deg, #fce4ec 0%, #f8bbd9 100%);
.gender-icon {
color: #e91e63;
}
}
&.female {
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
.gender-icon {
color: #2196f3;
}
}
}
}
}
// 解锁弹窗样式
.popup-unlock {
.unlock-info {
text-align: center;
margin-bottom: 30rpx;
.unlock-desc {
display: block;
font-size: 28rpx;
color: #666;
margin-bottom: 16rpx;
}
.unlock-quota {
display: block;
font-size: 26rpx;
color: #ff6b6b;
&.no-quota {
color: #999;
}
}
}
.popup-btn.member {
background: linear-gradient(135deg, #ffd700 0%, #ffb800 100%);
}
}
// 资料完善弹窗样式
.popup-profile {
.profile-info {
text-align: center;
margin-bottom: 30rpx;
.profile-desc {
font-size: 28rpx;
color: #666;
}
}
}
// 资料审核中弹窗样式
.popup-auditing {
.auditing-info {
text-align: center;
margin-bottom: 30rpx;
.auditing-desc {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
}
.auditing-btn {
background: #e0e0e0;
color: #666;
}
}
</style>