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.

699 lines
16 KiB

<template>
3 weeks ago
<view class="radius-login">
<view class="ambient ambient-one"></view>
<view class="ambient ambient-two"></view>
<view class="ambient ambient-three"></view>
<view class="float-bubble bubble-a">刚刚有人拼成奶茶</view>
<view class="float-bubble bubble-b">夜宵局启动中</view>
<view class="float-bubble bubble-c">附近同学正在拼饭</view>
<view class="hero">
<view class="brand-mark">
<view class="brand-dot"></view>
<text>半径里</text>
</view>
3 weeks ago
<view class="brand-title">拼团更省钱半径更精彩</view>
<view class="brand-subtitle">校园万物 · 皆可拼团</view>
</view>
<view class="ip-stage">
<view class="halo"></view>
<view class="squirrel-card">
<image class="squirrel" src="/static/images/img/loading.gif" mode="aspectFit"></image>
<view class="squirrel-mask"></view>
</view>
3 weeks ago
<view class="sticker sticker-phone">邀你拼团</view>
<view class="sticker sticker-tea">奶茶 +1</view>
<view class="emoji emoji-food">🍱</view>
<view class="emoji emoji-run">🏃</view>
</view>
<view class="login-card">
<view class="card-title">进入你的校园半径</view>
3 weeks ago
<view class="card-desc">美好 · 快乐 · 都在半径里发生</view>
3 weeks ago
<button
v-if="!needPhoneAuth"
class="primary-btn"
:class="{ loading: loginLoading }"
:disabled="loginLoading"
hover-class="primary-btn-hover"
@tap="wxLogin"
>
<text class="btn-icon">微信</text>
<text>{{ loginLoading ? '正在进入半径里' : '微信半径里' }}</text>
</button>
<button
v-else
class="primary-btn phone-btn"
:class="{ loading: phoneLoading }"
:disabled="phoneLoading"
open-type="getPhoneNumber"
hover-class="primary-btn-hover"
@getphonenumber="getPhoneNumber"
>
<text>{{ phoneLoading ? '正在绑定手机号' : '绑定手机号,解锁完整半径' }}</text>
</button>
<view class="login-tip">
{{ needPhoneAuth ? '最后一步,绑定后即可进入主页' : '使用微信身份轻松进入校园生活世界' }}
</view>
3 weeks ago
<view class="tui-protocol" hover-class="opcity" :hover-stay-time="150">
3 weeks ago
<checkbox-group @change="xieyi" class="protocol-check">
<label>
3 weeks ago
<checkbox value="agree" :checked="xieyidata" color="#46bf8c" style="transform:scale(0.7)" />
</label>
</checkbox-group>
3 weeks ago
<text>已阅读并同意</text>
<text class="tui-protocol-red" @tap.stop="protocol('1')">用户协议</text>
<text class="tui-protocol-red" @tap.stop="protocol('2')">隐私政策</text>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
3 weeks ago
xieyidata: false,
loginLoading: false,
phoneLoading: false,
needPhoneAuth: false,
customId: '',
2 days ago
saleId: '',
redirectKey: ''
}
},
onLoad(option) {
2 days ago
if (option.redirect) {
this.redirectKey = option.redirect
}
3 weeks ago
if (option.saleId) {
this.saleId = option.saleId
}
3 weeks ago
if (option.customId) {
this.customId = option.customId
}
3 weeks ago
if (uni.getStorageSync('hiver_token')) {
uni.reLaunch({
3 weeks ago
url: '/pages/index/index'
})
}
},
methods: {
3 weeks ago
wxLogin() {
if (!this.xieyidata) {
this.tui.toast('请阅读并同意用户协议和隐私政策')
return
}
3 weeks ago
if (this.loginLoading) return
const that = this
this.loginLoading = true
uni.login({
provider: 'weixin',
3 weeks ago
success(loginRes) {
that.getWechatProfile().then((profile) => {
that.tui.request('/user/login', 'post', {
jsCode: loginRes.code,
customId: that.customId,
wechatName: profile.nickName || '半径里同学',
userType: '2'
}, false, false).then((res) => {
that.loginLoading = false
if (res.code == 200) {
3 weeks ago
that.saveLoginResult(res.result)
if (!res.result.user || res.result.user.mobile == null || res.result.user.mobile === '') {
that.needPhoneAuth = true
that.tui.toast('绑定手机号,解锁完整半径')
} else {
that.enterHome()
}
} else {
that.tui.toast(res.message)
}
3 weeks ago
}).catch(() => {
that.loginLoading = false
that.tui.toast('登录失败,请稍后再试')
})
})
},
fail() {
that.loginLoading = false
that.tui.toast('微信登录失败,请稍后再试')
}
3 weeks ago
})
},
3 weeks ago
getWechatProfile() {
return new Promise((resolve) => {
if (uni.getUserProfile) {
uni.getUserProfile({
desc: '用于完善半径里校园身份',
success: (res) => resolve(res.userInfo || {}),
fail: () => resolve({})
})
return
}
3 weeks ago
uni.getUserInfo({
provider: 'weixin',
success: (res) => resolve(res.userInfo || {}),
fail: () => resolve({})
})
})
},
3 weeks ago
getPhoneNumber(e) {
if (this.phoneLoading) return
if (!e.detail.code) {
this.tui.toast('需要绑定手机号后进入主页')
return
}
3 weeks ago
this.phoneLoading = true
this.tui.request('/social/wechat/getPhone', 'POST', {
code: e.detail.code
}, false, true).then((res) => {
this.phoneLoading = false
if (res.code == 200) {
if (res.result) {
if (res.result.accessToken) {
uni.setStorageSync('hiver_token', res.result.accessToken)
}
if (res.result.mobile) {
uni.setStorageSync('mobile', res.result.mobile)
}
}
this.enterHome()
} else {
this.tui.toast(res.message || '手机号绑定失败')
}
}).catch(() => {
this.phoneLoading = false
this.tui.toast('手机号绑定失败,请稍后再试')
})
},
3 weeks ago
saveLoginResult(result) {
if (!result) return
if (result.accessToken) uni.setStorageSync('hiver_token', result.accessToken)
if (result.worker !== undefined) uni.setStorageSync('worker', result.worker)
uni.setStorageSync('wayValue', '0')
if (result.user) {
uni.setStorageSync('nickname', result.user.nickname)
uni.setStorageSync('id', result.user.id)
uni.setStorageSync('unionid', result.user.unionid)
uni.setStorageSync('miniProgramOpenid', result.user.miniProgramOpenid)
uni.setStorageSync('officialAccountOpenid', result.user.officialAccountOpenid)
if (result.user.mobile) {
uni.setStorageSync('mobile', result.user.mobile)
}
}
if (result.shop !== undefined) uni.setStorageSync('schoolShop', result.shop)
if (result.waimaiData !== undefined) uni.setStorageSync('waimaiData', result.waimaiData)
if (result.kuaidiData !== undefined) uni.setStorageSync('kuaidiData', result.kuaidiData)
},
3 weeks ago
enterHome() {
this.tui.toast('登录成功', 2000, true)
setTimeout(() => {
2 days ago
const pendingPath = this.redirectKey ? uni.getStorageSync(this.redirectKey) : ''
if (pendingPath) {
uni.removeStorageSync(this.redirectKey)
uni.redirectTo({
url: pendingPath
})
return
}
3 weeks ago
uni.reLaunch({
url: '/pages/index/index'
})
3 weeks ago
}, 200)
},
3 weeks ago
protocol(num) {
uni.navigateTo({
url: num == '1' ? '/package2/login/protocol' : '/package2/login/privacy'
})
},
3 weeks ago
xieyi(e) {
this.xieyidata = e.detail.value.length > 0
}
}
}
</script>
<style lang="scss" scoped>
3 weeks ago
.radius-login {
position: relative;
min-height: 100vh;
box-sizing: border-box;
overflow: hidden;
padding: 96rpx 44rpx 52rpx;
color: #17372d;
background:
radial-gradient(circle at 12% 14%, rgba(255, 255, 255, 0.96) 0, rgba(255, 255, 255, 0) 270rpx),
radial-gradient(circle at 88% 6%, rgba(199, 248, 219, 0.72) 0, rgba(199, 248, 219, 0) 260rpx),
linear-gradient(160deg, #f8f5e8 0%, #eefbe8 42%, #e7f8ef 68%, #fbf7ed 100%);
}
3 weeks ago
.ambient {
position: absolute;
border-radius: 999rpx;
pointer-events: none;
}
3 weeks ago
.ambient-one {
top: 88rpx;
left: -84rpx;
width: 260rpx;
height: 260rpx;
background: rgba(255, 255, 255, 0.55);
box-shadow: 0 0 80rpx rgba(255, 255, 255, 0.74);
animation: softFloat 8s ease-in-out infinite;
}
3 weeks ago
.ambient-two {
top: 260rpx;
right: -70rpx;
width: 210rpx;
height: 210rpx;
background: rgba(192, 245, 221, 0.52);
box-shadow: 0 0 90rpx rgba(137, 220, 177, 0.28);
animation: softFloat 10s ease-in-out infinite reverse;
}
3 weeks ago
.ambient-three {
left: 122rpx;
bottom: 238rpx;
width: 120rpx;
height: 120rpx;
background: rgba(255, 240, 199, 0.48);
box-shadow: 0 0 70rpx rgba(255, 213, 127, 0.26);
animation: ambientPulse 7s ease-in-out infinite;
}
.float-bubble {
position: absolute;
z-index: 2;
padding: 14rpx 22rpx;
border: 1rpx solid rgba(255, 255, 255, 0.68);
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.45);
box-shadow: 0 16rpx 42rpx rgba(95, 150, 121, 0.12);
color: rgba(38, 81, 67, 0.58);
font-size: 21rpx;
line-height: 1;
backdrop-filter: blur(16rpx);
animation: bubbleFloat 9s ease-in-out infinite;
}
.bubble-a {
top: 286rpx;
right: 34rpx;
}
.bubble-b {
top: 488rpx;
left: 34rpx;
animation-delay: -2s;
}
.bubble-c {
top: 640rpx;
right: 30rpx;
animation-delay: -4s;
}
.hero {
position: relative;
z-index: 3;
}
.brand-mark {
display: inline-flex;
align-items: center;
height: 54rpx;
padding: 0 22rpx;
border: 1rpx solid rgba(255, 255, 255, 0.72);
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.42);
box-shadow: 0 12rpx 34rpx rgba(69, 131, 99, 0.1);
color: rgba(26, 69, 55, 0.68);
font-size: 24rpx;
3 weeks ago
font-weight: 600;
backdrop-filter: blur(18rpx);
}
.brand-dot {
width: 14rpx;
height: 14rpx;
margin-right: 12rpx;
border-radius: 50%;
background: #54c990;
box-shadow: 0 0 20rpx rgba(84, 201, 144, 0.75);
}
.brand-title {
width: 100%;
3 weeks ago
margin-top: 38rpx;
font-size: 42rpx;
font-weight: 700;
letter-spacing: 0;
line-height: 1.25;
color: #17372d;
white-space: nowrap;
}
3 weeks ago
.brand-subtitle {
margin-top: 18rpx;
color: rgba(43, 88, 73, 0.62);
font-size: 25rpx;
letter-spacing: 4rpx;
}
.ip-stage {
position: relative;
z-index: 3;
height: 440rpx;
margin-top: 26rpx;
}
.halo {
position: absolute;
left: 50%;
top: 94rpx;
width: 380rpx;
height: 210rpx;
border-radius: 50%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.82), rgba(245, 225, 177, 0.18) 64%, rgba(255, 255, 255, 0));
transform: translateX(-50%);
animation: lightPulse 6s ease-in-out infinite;
}
3 weeks ago
.squirrel-card {
position: absolute;
left: 50%;
top: 18rpx;
width: 360rpx;
height: 360rpx;
border-radius: 64rpx;
overflow: hidden;
z-index: 3;
transform: translateX(-50%);
filter: drop-shadow(0 34rpx 34rpx rgba(80, 103, 79, 0.16));
animation: ipBreath 5.8s ease-in-out infinite;
}
.squirrel-card::after {
content: '';
position: absolute;
left: 44rpx;
right: 44rpx;
bottom: 14rpx;
height: 34rpx;
border-radius: 50%;
background: rgba(126, 159, 126, 0.12);
filter: blur(10rpx);
}
.squirrel {
width: 100%;
3 weeks ago
height: 100%;
transform: scale(1.02) translateY(4rpx);
}
.squirrel-mask {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 92rpx;
background: linear-gradient(180deg, rgba(237, 249, 234, 0) 0%, rgba(237, 249, 234, 0.68) 58%, rgba(237, 249, 234, 0.96) 100%);
pointer-events: none;
}
.sticker,
.emoji {
position: absolute;
z-index: 2;
border: 1rpx solid rgba(255, 255, 255, 0.72);
background: rgba(255, 255, 255, 0.58);
box-shadow: 0 18rpx 48rpx rgba(93, 132, 101, 0.14);
backdrop-filter: blur(16rpx);
animation: stickerFloat 7s ease-in-out infinite;
}
.sticker {
padding: 12rpx 20rpx;
border-radius: 28rpx;
color: #2e6955;
font-size: 21rpx;
font-weight: 600;
opacity: 0.72;
}
.sticker-phone {
left: 4rpx;
top: 140rpx;
transform: rotate(-6deg);
}
.sticker-tea {
right: 0;
top: 264rpx;
color: #9c6f3e;
transform: rotate(5deg);
animation-delay: -2s;
}
.emoji {
display: flex;
align-items: center;
justify-content: center;
3 weeks ago
width: 62rpx;
height: 62rpx;
border-radius: 24rpx;
font-size: 30rpx;
}
.emoji-food {
right: 96rpx;
top: 72rpx;
animation-delay: -1s;
}
.emoji-run {
left: 94rpx;
top: 286rpx;
animation-delay: -3s;
}
.login-card {
position: relative;
z-index: 5;
box-sizing: border-box;
3 weeks ago
margin-top: -10rpx;
padding: 42rpx 36rpx 30rpx;
border: 1rpx solid rgba(255, 255, 255, 0.72);
border-radius: 44rpx;
background: rgba(255, 255, 255, 0.56);
box-shadow:
0 28rpx 70rpx rgba(62, 116, 91, 0.16),
inset 0 1rpx 0 rgba(255, 255, 255, 0.7);
backdrop-filter: blur(26rpx);
animation: cardLift 6s ease-in-out infinite;
}
.card-title {
color: #183a30;
font-size: 34rpx;
font-weight: 700;
text-align: center;
}
3 weeks ago
.card-desc {
width: 500rpx;
margin: 16rpx auto 34rpx;
color: rgba(42, 80, 66, 0.58);
font-size: 24rpx;
line-height: 1.55;
text-align: center;
}
3 weeks ago
.primary-btn {
display: flex;
align-items: center;
justify-content: center;
3 weeks ago
width: 420rpx;
margin: 0 auto;
3 weeks ago
height: 96rpx;
padding: 0;
border: 0;
border-radius: 999rpx;
background: linear-gradient(90deg, rgba(227, 255, 150, 0.98), rgba(166, 255, 234, 0.98));
box-shadow:
0 18rpx 44rpx rgba(13, 114, 82, 0.2),
0 0 44rpx rgba(166, 255, 234, 0.62),
0 0 18rpx rgba(227, 255, 150, 0.5);
color: #073d33;
font-size: 30rpx;
font-weight: 700;
line-height: 96rpx;
letter-spacing: 1rpx;
animation: btnGlow 4.8s ease-in-out infinite;
}
3 weeks ago
.primary-btn::after {
border: 0;
}
3 weeks ago
.primary-btn-hover {
transform: scale(0.985);
opacity: 0.92;
}
3 weeks ago
.primary-btn.loading {
opacity: 0.82;
}
3 weeks ago
.btn-icon {
display: inline-flex;
align-items: center;
justify-content: center;
3 weeks ago
height: 42rpx;
margin-right: 16rpx;
padding: 0 16rpx;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.46);
font-size: 22rpx;
font-weight: 600;
line-height: 42rpx;
}
3 weeks ago
.phone-btn {
background: linear-gradient(90deg, rgba(227, 255, 150, 0.98), rgba(166, 255, 234, 0.98));
}
3 weeks ago
.login-tip {
margin-top: 22rpx;
color: rgba(43, 83, 70, 0.52);
font-size: 22rpx;
text-align: center;
}
3 weeks ago
.tui-protocol {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
margin-top: 24rpx;
color: rgba(39, 75, 63, 0.55);
font-size: 22rpx;
line-height: 1.8;
}
.protocol-check {
display: inline-flex;
align-items: center;
}
.tui-protocol-red {
color: #2caf79;
font-weight: 600;
}
@keyframes ipBreath {
0%,
100% {
transform: translateX(-50%) translateY(0) scale(1);
}
50% {
transform: translateX(-50%) translateY(-16rpx) scale(1.025);
}
3 weeks ago
}
@keyframes softFloat {
0%,
100% {
transform: translate3d(0, 0, 0);
}
50% {
transform: translate3d(18rpx, -22rpx, 0);
}
}
@keyframes bubbleFloat {
0%,
100% {
transform: translateY(0);
opacity: 0.72;
}
50% {
transform: translateY(-18rpx);
opacity: 0.96;
}
}
@keyframes stickerFloat {
0%,
100% {
margin-top: 0;
}
50% {
margin-top: -14rpx;
}
}
@keyframes lightPulse {
0%,
100% {
opacity: 0.58;
transform: translateX(-50%) scale(1);
}
50% {
opacity: 0.9;
transform: translateX(-50%) scale(1.06);
}
}
@keyframes ambientPulse {
0%,
100% {
opacity: 0.58;
transform: scale(1);
}
50% {
opacity: 0.9;
transform: scale(1.08);
}
}
@keyframes btnGlow {
0%,
100% {
box-shadow:
0 18rpx 44rpx rgba(13, 114, 82, 0.2),
0 0 44rpx rgba(166, 255, 234, 0.62),
0 0 18rpx rgba(227, 255, 150, 0.5);
}
50% {
box-shadow:
0 24rpx 58rpx rgba(13, 114, 82, 0.26),
0 0 64rpx rgba(166, 255, 234, 0.82),
0 0 28rpx rgba(227, 255, 150, 0.68);
}
}
@keyframes cardLift {
0%,
100% {
transform: translateY(0);
}
3 weeks ago
50% {
transform: translateY(-8rpx);
}
}
3 weeks ago
</style>