You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1013 lines
23 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="wrap">
<view class="container">
<view class="user-info">
<view class="user-info-avatar">
<image class="avatar" :src="userInfo.headimgurl ? userInfo.headimgurl : logo" mode="aspectFill"></image>
</view>
<view class="user-info__text">
<view class="name">
{{ userInfo.name || '' }}
</view>
<view class="club">
{{ userInfo.mobile ? userInfo.mobile : '' }}
</view>
</view>
</view>
<view class="menu-list">
<view class="menu-item" @click="toAddress">
<image class="menu-icon" src="@/static/me1.png" mode="aspectFit"></image>
<text class="menu-text">奖品快递地址</text>
<u-icon name="arrow-right" color="#333" size="38rpx"></u-icon>
</view>
<view class="menu-item" @click="torecord">
<image class="menu-icon" src="@/static/me2.png" mode="aspectFit"></image>
<text class="menu-text">答题记录</text>
<u-icon name="arrow-right" color="#333" size="38rpx"></u-icon>
</view>
<view class="menu-item" @click="toWinRecord">
<image class="menu-icon" src="@/static/me3.png" mode="aspectFit"></image>
<text class="menu-text">中奖记录</text>
<u-icon name="arrow-right" color="#333" size="38rpx"></u-icon>
</view>
<view class="menu-item" @click="showtips=true">
<image class="menu-icon" src="@/static/me4.png" mode="aspectFit"></image>
<text class="menu-text">活动详情</text>
<u-icon name="arrow-right" color="#333" size="38rpx"></u-icon>
</view>
</view>
</view>
<!-- 奖品快递地址弹窗 -->
<u-popup v-model="showAddress" :mask-close-able="!forcePrizeAddress" mode="bottom" border-radius="20">
<view class="address-popup">
<view class="address-header">
<text class="address-title">奖品快递地址</text>
<u-icon
v-if="!forcePrizeAddress"
name="close"
@click="showAddress = false"
size="40rpx"
color="#999"
></u-icon>
</view>
<view class="address-form">
<view class="form-item">
<text class="form-label">姓名</text>
<u-input
v-model="addressForm.name"
placeholder="请输入姓名"
:border="false"
:custom-style="{
background: '#f5f5f5',
padding: '20rpx 30rpx',
'border-radius': '10rpx',
'font-size': '28rpx'
}"
:placeholder-style="'color:#999;font-size:28rpx'"
></u-input>
</view>
<view class="form-item">
<text class="form-label">手机号</text>
<u-input
v-model="addressForm.mobile"
placeholder="请输入手机号"
type="number"
:border="false"
:custom-style="{
background: '#f5f5f5',
padding: '20rpx 30rpx',
'border-radius': '10rpx',
'font-size': '28rpx'
}"
:placeholder-style="'color:#999;font-size:28rpx'"
></u-input>
</view>
<view class="form-item">
<text class="form-label">奖品快递地址</text>
<textarea
v-model="addressForm.address"
placeholder="请输入详细的奖品快递地址"
class="address-textarea"
maxlength="200"
></textarea>
</view>
<view class="form-submit">
<u-button
type="primary"
shape="circle"
:custom-style="{
background: 'linear-gradient(to right, #57b0fe, #446efd)',
color: '#fff',
'font-size': '32rpx',
padding: '30rpx',
width: '100%'
}"
@click="submitAddress"
>提交</u-button>
</view>
</view>
</view>
</u-popup>
<!-- 获奖 -->
<u-popup v-model="showwin" mode="center">
<view class="tipwrap">
<view class="tiptitle">
获奖通知
</view>
<view class="tipcenter">
<view>{{userInfo.name?userInfo.name:''}}</view>
<view>请保持通话畅通,工作人员会与您联系</view>
</view>
<view class="answerBtn">
<view @click="showwin=false">知道了</view>
</view>
</view>
</u-popup>
<!-- 活动详情弹窗 -->
<view v-show="showtips" class="popup-mask" @click="showtips = false">
<view class="close-btn" @click="showtips = false">×</view>
<view class="tipwrap" @click.stop>
<!-- 活动时间 -->
<view class="detail-section">
<view class="section-line"></view>
<view class="section-header">
<image
src="@/static/tip_icon.png"
class="section-icon"
mode="aspectFit"
/>
<text class="section-title">活动时间</text>
<image
src="@/static/tip_icon.png"
class="section-icon"
mode="aspectFit"
/>
</view>
<view class="section-content">
<view class="time-item">
<!-- <text class="time-label">征集时间:</text> -->
<text class="time-value">{{ collectionTime }}</text>
</view>
</view>
</view>
<!-- 参与方式 -->
<view class="detail-section">
<view class="section-line"></view>
<view class="section-header">
<image
src="@/static/tip_icon.png"
class="section-icon"
mode="aspectFit"
/>
<text class="section-title">参与方式</text>
<image
src="@/static/tip_icon.png"
class="section-icon"
mode="aspectFit"
/>
</view>
<view class="section-content">
<!-- eslint-disable-next-line vue/no-v-text-v-html-on-component -->
<view v-if="joinContent" v-html="joinContent"></view>
</view>
</view>
<!-- 活动规则 -->
<view class="detail-section">
<view class="section-line"></view>
<view class="section-header">
<image
src="@/static/tip_icon.png"
class="section-icon"
mode="aspectFit"
/>
<text class="section-title">活动规则</text>
<image
src="@/static/tip_icon.png"
class="section-icon"
mode="aspectFit"
/>
</view>
<view class="section-content">
<!-- eslint-disable-next-line vue/no-v-text-v-html-on-component -->
<view v-if="rulesContent" v-html="rulesContent"></view>
</view>
</view>
</view>
</view>
<!-- 中奖记录弹窗 -->
<view v-show="showWinRecord" class="win-record-popup" @click.stop>
<view class="win-record-content">
<!-- 已中奖 -->
<template v-if="hasWon">
<image src="@/static/answer_right.png" class="win-record-image" mode="aspectFit"></image>
<view class="win-record-text">恭喜您已抽中 <text class="prize-text">科普图书</text> 一本!</view>
<view class="win-record-buttons">
<u-button
size="mini"
:throttle-time="1000"
shape="circle"
type="default"
:custom-style="winRecordBtnStyle"
@click="continueAnswer"
>继续答题</u-button>
<u-button
size="mini"
:throttle-time="1000"
shape="circle"
type="default"
:custom-style="winRecordBtnStyle"
@click="closeWinRecord"
>关闭</u-button>
</view>
</template>
<!-- 未中奖 -->
<template v-else>
<image src="@/static/no-win.png" class="win-record-image" mode="aspectFit"></image>
<view class="win-record-text">很遗憾,未中奖</view>
<view class="win-record-buttons">
<u-button
size="mini"
:throttle-time="1000"
shape="circle"
type="default"
:custom-style="winRecordBtnStyle"
@click="continueAnswer"
>继续答题</u-button>
<u-button
size="mini"
:throttle-time="1000"
shape="circle"
type="default"
:custom-style="winRecordBtnStyle"
@click="closeWinRecord"
>关闭</u-button>
</view>
</template>
</view>
</view>
<!-- 底部悬浮继续答题按钮 -->
<view class="float-answer-btn" @click="continueAnswer">
继续答题
</view>
</view>
</template>
<script>
import {
isNull,
toast
} from "@/common/util.js"
export default {
data() {
return {
logo:require('@/static/head.png'),
userInfo: {},
showwin: false,
showtips: false,
open_win: false,
collectionTime: "",
prizeReleaseTime: "",
prizeAnnouncementTime: "",
joinContent: "",
rulesContent: "",
showAddress: false,
fromPrize: false, // 是否从抽奖页跳转
forcePrizeAddress: false, // 是否为从抽奖页跳转过来的奖品地址,必须填写后才能关闭
addressForm: {
name: "",
mobile: "",
address: ""
},
hasWon: false, // 是否中奖
showWinRecord: false, // 中奖记录弹窗
winRecordBtnStyle: {
background: 'linear-gradient(to right, #58b3fe, #446efd)',
color: '#fff',
'font-size': '32rpx',
padding: '30rpx',
width: '45%',
height: '90rpx'
}
};
},
methods: {
openWins() {
if (this.userInfo.pid === 1) {
this.showwin = true
} else {
toast('很遗憾,您未得奖')
}
},
torecord() {
uni.navigateTo({
url: '/pages/record/index'
})
},
async toAddress() {
// 普通入口,允许关闭
this.forcePrizeAddress = false;
// 显示奖品快递地址表单弹窗
this.showAddress = true;
// 从用户信息中预填充表单
this.addressForm = {
name: this.userInfo.name || "",
mobile: this.userInfo.mobile || "",
address: this.userInfo.address || ""
};
},
isOnlyChinese(str) {
const chineseRegex = /^[\u4e00-\u9fa5]+$/;
return chineseRegex.test(str);
},
submitAddress() {
// 表单验证
if (!this.addressForm.name || !this.addressForm.name.trim()) {
toast('请输入姓名');
return;
}
if (!this.isOnlyChinese(this.addressForm.name.trim())) {
toast('请输入中文姓名');
return;
}
if (!this.addressForm.mobile || !this.addressForm.mobile.trim()) {
toast('请输入手机号');
return;
}
if (!uni.$u.test.mobile(this.addressForm.mobile)) {
toast('请输入正确的手机号');
return;
}
if (!this.addressForm.address || !this.addressForm.address.trim()) {
toast('请输入地址');
return;
}
// 提交到 saveUser 接口
this.$u.api.saveUser({
name: this.addressForm.name.trim(),
mobile: this.addressForm.mobile.trim(),
address: this.addressForm.address.trim()
}).then((res) => {
this.$u.vuex('vuex_user', res);
this.userInfo = res;
toast('保存成功');
this.showAddress = false;
this.forcePrizeAddress = false;
// 重新获取用户信息
this.getUserInfo()
}).catch((error) => {
console.error('保存失败:', error);
toast('保存失败,请重试');
});
},
toWinRecord() {
// 显示中奖记录弹窗
this.showWinRecord = true
},
closeWinRecord() {
this.showWinRecord = false
},
continueAnswer() {
this.showWinRecord = false
uni.redirectTo({
url: '/pages/answer/index'
})
},
async getUserInfo(option) {
const res = await this.$u.api.user()
this.$u.vuex('vuex_user', res);
this.userInfo = res;
if (isNull(res.mobile)) {
uni.redirectTo({
url: '/pages/login/index'
})
return
}
// 如果是从抽奖页跳转过来,且当前用户还没有填写奖品快递地址,则在获取到用户信息后再预填地址并弹窗
if (option && option.fromPrize === '1') {
const hasAddress =
res.address &&
typeof res.address === 'string' &&
res.address.trim().length > 0
if (!hasAddress) {
this.fromPrize = true
this.forcePrizeAddress = true;
this.showAddress = true;
this.addressForm = {
name: this.userInfo.name || "",
mobile: this.userInfo.mobile || "",
address: this.userInfo.address || ""
};
}
}
},
async getConfig() {
try {
const res = await this.$u.api.getAppId();
// 从配置中获取其他信息
if (res.config && Array.isArray(res.config)) {
res.config.forEach((item) => {
// 征集时间 - key=active_time
if (item.key === "active_time") {
this.collectionTime = item.value;
}
// 奖项榜单发布 - key=release
if (item.key === "release") {
this.prizeReleaseTime = item.value;
}
// 奖项公布 - key=public
if (item.key === "public") {
this.prizeAnnouncementTime = item.value;
}
// 参与方式 - key=join (富文本)
if (item.key === "join") {
this.joinContent = item.value;
}
// 活动规则 - key=rules (富文本)
if (item.key === "rules") {
this.rulesContent = item.value;
}
if (item.key == 'open_win') {
this.open_win = item.value == 1 ? true : false
}
});
}
} catch (error) {
console.error("获取活动配置失败:", error);
}
},
async getPrize() {
try {
const res = await this.$u.api.getPrize();
console.log('获取奖品信息:', res);
// 判断是否中奖prize数组中是否有任何一项的draw_prize.name === '已中奖'
if (res.prize && Array.isArray(res.prize)) {
this.hasWon = res.prize.some(item => {
return item.draw_prize && item.draw_prize.name === '已中奖'
})
} else {
this.hasWon = false
}
} catch (error) {
console.error('获取奖品信息失败:', error);
this.hasWon = false
}
},
},
onLoad(option) {
this.getConfig()
// 先获取用户信息
this.getUserInfo(option);
// 获取奖品信息
this.getPrize();
},
}
</script>
<style lang="scss" scoped>
.wrap {
height: 100vh;
width: 100vw;
background-image: url('../../static/login_bg.png');
background-size: 100% 100%;
background-repeat: no-repeat;
overflow: scroll;
}
.tipwrap {
width: 650rpx;
// background: #fff;
font-size: 28rpx;
padding:30rpx;
margin-top:320rpx;
.tiptitle {
width: 100%;
text-align: center;
font-size: 36rpx;
}
.tipcenter {
background-color: #fff;
min-height: 200rpx;
line-height: 1.8;
width: 100%;
box-sizing: content-box;
margin-top: -5rpx;
&>view {
padding: 20px;
padding-bottom: 0;
}
}
.answerBtn {
text-align: center;
padding-bottom: 40rpx;
background-color: #fff;
width: 100%;
text-align: center;
margin-top: -5rpx;
padding-top: 40rpx;
position: relative;
top: 0;
left: 0;
&>view {
box-shadow: 1rpx 7rpx 18rpx 0rpx #2754a5;
color: #333;
padding: 16rpx 70rpx;
margin: 10rpx;
font-size: 28rpx;
border-radius: 10rpx;
display: inline-block;
}
&>view:last-child {
color: #fff;
background: linear-gradient(90deg, #2754a5, #2b83bb);
}
}
}
.container {
position: relative;
z-index: 1;
.user-info {
display: flex;
align-items: center;
padding: 82rpx 0 0 54rpx;
.user-info-avatar {
width: 121rpx;
height: 121rpx;
border-radius: 100%;
// object-fit: contain;
// border: 1rpx solid #fff;
// box-sizing: border-box;
}
.avatar {
width: 121rpx;
height: 121rpx;
border-radius: 100%;
// object-fit: contain;
// border: 1rpx solid #fff;
// box-sizing: border-box;
}
&__text {
color: #000;
margin-left: 32rpx;
.name {
font-size: 36rpx;
font-weight: 500;
word-break: keep-all;
line-height: 42rpx;
}
.club {
font-size: 26rpx;
font-weight: 400;
margin-top: 13rpx;
}
}
}
.menu-list {
width: 100%;
background: #fff;
box-sizing: border-box;
border-radius: 40rpx 40rpx 0 0;
filter: drop-shadow(0 0 7.5px rgba(226, 54, 50, 0.1));
margin: 73rpx auto 0 auto;
overflow: hidden;
height: 85vh;
.menu-item {
display: flex;
align-items: center;
padding: 34rpx 50rpx;
position: relative;
&::after {
content: "";
height: 2rpx;
background: #989898;
opacity: 0.302;
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
&:last-child::after {
display: none;
}
.menu-icon {
margin-right: 20rpx;
}
&:nth-child(1) .menu-icon {
width: 29rpx;
height: 32rpx;
}
&:nth-child(2) .menu-icon {
width: 31rpx;
height: 36rpx;
}
&:nth-child(3) .menu-icon {
width: 30rpx;
height: 32rpx;
}
&:nth-child(4) .menu-icon,
&:nth-child(5) .menu-icon {
width: 29rpx;
height: 37rpx;
}
.menu-text {
flex: 1;
font-size: 28rpx;
color: #333;
}
}
}
}
.popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
overflow: scroll;
padding-top: 150rpx;
}
.close-btn {
position: absolute;
top: 80rpx;
right: 20rpx;
width: 60rpx;
height: 60rpx;
line-height: 55rpx;
text-align: center;
font-size: 50rpx;
color: #fff;
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
z-index: 10;
cursor: pointer;
}
.tipwrap {
position: relative;
width: 710rpx;
font-size: 28rpx;
padding: 40rpx 30rpx 30rpx;
margin-bottom: 100rpx;
box-sizing: border-box;
overflow-y: auto;
background: url("../../static/tip_bg.png") no-repeat center center;
background-size: 100% 100%;
.detail-section:first-child {
margin-top: 100rpx;
}
.detail-section {
margin-bottom: 20rpx;
background: #fff;
border-bottom-left-radius: 40rpx;
border-bottom-right-radius: 40rpx;
overflow: hidden;
padding-bottom: 40rpx;
.section-line {
width: 100%;
height: 9rpx;
background: url("../../static/tip_line.png") no-repeat center center;
background-size: 100% 100%;
}
.section-header {
margin: 30rpx;
display: flex;
align-items: center;
// justify-content: center;
.section-icon {
width: 22rpx;
height: 22rpx;
margin: 0 8rpx;
}
.section-title {
font-size: 36rpx;
font-weight: bold;
color: #2f6cf6;
}
}
.section-content {
padding: 0 70rpx;
padding-right: 40rpx;
font-size: 24rpx;
color: #496690;
.time-item {
margin-bottom: 10rpx;
.time-label {
color: #496690;
}
.time-value {
color: #496690;
}
}
::v-deep .time-item {
margin-bottom: 10rpx;
}
::v-deep .time-label {
color: #496690;
}
::v-deep .time-value {
color: #496690;
}
::v-deep .qr-code-wrapper {
display: flex;
justify-content: center;
margin: 20rpx 0;
}
::v-deep .qr-code {
width: 200rpx;
height: 200rpx;
background: #f5f5f5;
}
::v-deep .qr-text {
text-align: center;
font-size: 32rpx;
color: #020726;
margin-bottom: 20rpx;
display: flex;
align-items: center;
justify-content: center;
}
::v-deep .participation-tip {
margin-bottom: 10rpx;
color: #496690;
font-size: 24rpx;
display: flex;
}
::v-deep .highlight {
color: #fd9d0c;
}
::v-deep .rule-item {
display: flex;
margin-bottom: 10rpx;
font-size: 24rpx;
}
::v-deep .rule-number {
color: #496690;
margin-right: 10rpx;
flex-shrink: 0;
}
::v-deep .rule-text {
color: #496690;
flex: 1;
}
}
}
}
.address-popup {
background: #fff;
padding: 40rpx 30rpx;
border-radius: 20rpx 20rpx 0 0;
.address-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 40rpx;
.address-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
}
}
.address-form {
.form-item {
margin-bottom: 30rpx;
.form-label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 20rpx;
}
.address-textarea {
width: 100%;
min-height: 200rpx;
background: #f5f5f5;
border-radius: 10rpx;
padding: 20rpx 30rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
}
}
.form-submit {
margin-top: 40rpx;
}
}
}
// 中奖记录弹窗样式
.win-record-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
.win-record-content {
position: relative;
display: flex;
align-items: center;
justify-content: center;
.win-record-image {
width: 725rpx;
height: 956rpx;
}
.win-record-text {
position: absolute;
top: 35%;
left: 50%;
transform: translateX(-50%);
font-size: 40rpx;
color: #2f6cf6;
font-weight: bold;
text-align: center;
white-space: nowrap;
.prize-text {
color: #fd9d0c;
}
}
.win-record-buttons {
position: absolute;
top: 60%;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 30rpx;
justify-content: center;
align-items: center;
width: 100%;
padding: 0 50rpx;
box-sizing: border-box;
::v-deep .u-btn {
flex: 0 0 auto;
width: 45%!important;
}
}
}
}
/* 底部悬浮继续答题按钮 */
.float-answer-btn {
position: fixed;
left: 50%;
bottom: 40rpx;
transform: translateX(-50%);
z-index: 1000;
min-width: 300rpx;
padding: 20rpx 60rpx;
text-align: center;
font-size: 32rpx;
color: #fff;
background: linear-gradient(to right, #57b0fe, #446efd);
border-radius: 999rpx;
box-shadow: 0 8rpx 20rpx rgba(68, 110, 253, 0.5);
}
</style>
<!-- 非 scoped 样式,用于 v-html 渲染的内容 -->
<style lang="scss">
.section-content {
.time-item {
margin-bottom: 10rpx;
}
.time-label {
color: #496690;
}
.time-value {
color: #496690;
}
.qr-code-wrapper {
display: flex;
justify-content: center;
margin: 20rpx 0;
}
.qr-code {
width: 200rpx;
height: 200rpx;
background: #f5f5f5;
}
.qr-text {
text-align: center;
font-size: 32rpx;
color: #020726;
margin-bottom: 20rpx;
}
.participation-tip {
margin-bottom: 10rpx;
color: #496690;
font-size: 24rpx;
.highlight {
color: #fd9d0c;
}
}
.rule-item {
display: flex;
margin-bottom: 10rpx;
font-size: 24rpx;
}
.rule-number {
color: #496690;
margin-right: 10rpx;
flex-shrink: 0;
}
.rule-text {
color: #496690;
flex: 1;
}
}
</style>