xiangyixiangqin/miniapp/components/Popup/index.vue
2026-01-02 18:00:49 +08:00

390 lines
8.5 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="gender-options">
<view class="gender-option male" @click="handleGenderSelect(1)">
<view class="gender-icon">♂</view>
<text>看男生</text>
</view>
<view class="gender-option female" @click="handleGenderSelect(2)">
<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="aspectFit"
@click="handleImageClick"
/>
<view v-if="title" class="popup-title">{{ title }}</view>
<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>
<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', '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()
}
},
handleButtonClick() {
if (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.setClipboardData({
data: this.linkUrl,
success: () => {
uni.showToast({ title: '链接已复制', icon: 'success' })
}
})
}
}
}
}
</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: 30rpx;
}
.popup-content {
font-size: 28rpx;
color: #666;
text-align: center;
margin-bottom: 30rpx;
line-height: 1.6;
}
.popup-image {
width: 100%;
height: 300rpx;
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-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, #e3f2fd 0%, #bbdefb 100%);
.gender-icon {
color: #2196f3;
}
}
&.female {
background: linear-gradient(135deg, #fce4ec 0%, #f8bbd9 100%);
.gender-icon {
color: #e91e63;
}
}
}
}
}
// 解锁弹窗样式
.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;
}
}
}
</style>