151 lines
4.6 KiB
Vue
151 lines
4.6 KiB
Vue
<template>
|
||
<view class="page">
|
||
<view class="hero">
|
||
<text class="eyebrow">YUNZE WORKSPACE</text>
|
||
<text class="title">设置登录密码</text>
|
||
<text class="desc">手机号 {{ mobileMask || '已验证' }} 尚未注册,设置密码后即可使用工作台</text>
|
||
</view>
|
||
|
||
<view class="card">
|
||
<view class="field">
|
||
<text class="label">登录密码</text>
|
||
<input v-model="password" class="input" type="password" placeholder="至少 6 位" :maxlength="32" />
|
||
</view>
|
||
<view class="field">
|
||
<text class="label">确认密码</text>
|
||
<input v-model="confirmPassword" class="input" type="password" placeholder="再输入一次" :maxlength="32" />
|
||
</view>
|
||
<text class="hint">密码至少 6 位;微信号会在注册时自动绑定,下次可直接进入</text>
|
||
<view v-if="errorMsg" class="error"><text>{{ errorMsg }}</text></view>
|
||
<button class="submit" :disabled="loading" @tap="handleSubmit">
|
||
{{ loading ? '注册中…' : '完成注册' }}
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
/**
|
||
* 手机号授权后未查到账号:设置密码完成注册(后端同时绑定微信 openid 并签发 tid=0 令牌)。
|
||
* 注册完成后回到工作台,由 nav 自动继续进入刚才点击的模块。
|
||
*/
|
||
import { ref } from 'vue'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
import { onboardingRegister } from '@/api/onboarding.js'
|
||
import { setAuthTokens, setTid, setTenantName } from '@/utils/auth.js'
|
||
import { guestMerge } from '@/api/guest.js'
|
||
import { getGuestToken, clearGuestToken } from '@/utils/guest.js'
|
||
import { clearHomeCache } from '@/api/workspace.js'
|
||
|
||
const token = ref('')
|
||
const mobileMask = ref('')
|
||
const password = ref('')
|
||
const confirmPassword = ref('')
|
||
const loading = ref(false)
|
||
const errorMsg = ref('')
|
||
|
||
onLoad((options = {}) => {
|
||
token.value = options.token || ''
|
||
mobileMask.value = decodeURIComponent(options.mobile_mask || '')
|
||
if (!token.value) {
|
||
errorMsg.value = '授权会话已失效,请返回工作台重新授权手机号'
|
||
}
|
||
})
|
||
|
||
async function handleSubmit() {
|
||
if (loading.value) return
|
||
errorMsg.value = ''
|
||
if (!token.value) {
|
||
errorMsg.value = '授权会话已失效,请返回工作台重新授权手机号'
|
||
return
|
||
}
|
||
if (password.value.length < 6) {
|
||
errorMsg.value = '密码长度不能少于 6 位'
|
||
return
|
||
}
|
||
if (password.value !== confirmPassword.value) {
|
||
errorMsg.value = '两次输入的密码不一致'
|
||
return
|
||
}
|
||
loading.value = true
|
||
try {
|
||
const res = await onboardingRegister({
|
||
token: token.value,
|
||
password: password.value,
|
||
confirmPassword: confirmPassword.value
|
||
})
|
||
if (!res || !res.tokens || !res.tokens.access_token) throw new Error('注册失败,未返回登录态')
|
||
setAuthTokens(res.tokens)
|
||
setTid(0)
|
||
setTenantName('')
|
||
clearHomeCache()
|
||
// 注册前以游客身份产生的数据并入正式账号
|
||
if (getGuestToken()) {
|
||
try {
|
||
await guestMerge()
|
||
} catch (e) {
|
||
console.warn('[onboarding] guest merge failed:', e)
|
||
}
|
||
clearGuestToken()
|
||
}
|
||
uni.showToast({ title: '注册成功', icon: 'success' })
|
||
setTimeout(() => uni.reLaunch({ url: '/pages/nav/nav' }), 500)
|
||
} catch (e) {
|
||
errorMsg.value = (e && e.message) || '注册失败,请重试'
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@import '@/src/styles/page-common.scss';
|
||
|
||
.page {
|
||
min-height: 100vh;
|
||
padding: 0 $page-padding-x 60rpx;
|
||
box-sizing: border-box;
|
||
background: linear-gradient(160deg, #eaf3ff 0%, #f8fafc 42%, #f8fafc 100%);
|
||
}
|
||
|
||
.hero { padding: 120rpx 8rpx 56rpx; }
|
||
.eyebrow { display: block; font-size: 20rpx; font-weight: 700; letter-spacing: 3rpx; color: #6e9de5; }
|
||
.title { display: block; margin-top: 14rpx; font-size: 46rpx; font-weight: 700; color: #17345f; }
|
||
.desc { display: block; margin-top: 16rpx; font-size: 25rpx; line-height: 1.6; color: #64748b; }
|
||
|
||
.card {
|
||
@include card;
|
||
padding: 36rpx 30rpx 40rpx;
|
||
}
|
||
|
||
.field { margin-bottom: 28rpx; }
|
||
.label { display: block; margin-bottom: 12rpx; font-size: 25rpx; font-weight: 600; color: #334155; }
|
||
.input {
|
||
height: 88rpx;
|
||
padding: 0 24rpx;
|
||
border: 1rpx solid #dce7f7;
|
||
border-radius: $radius-md;
|
||
background: #fbfdff;
|
||
font-size: 28rpx;
|
||
color: $color-text;
|
||
box-sizing: border-box;
|
||
}
|
||
.hint { display: block; font-size: 22rpx; line-height: 1.6; color: $color-text-muted; }
|
||
.error { margin-top: 20rpx; font-size: 24rpx; color: $color-danger; }
|
||
.submit {
|
||
margin-top: 40rpx;
|
||
height: 92rpx;
|
||
line-height: 92rpx;
|
||
border: none;
|
||
border-radius: $radius-full;
|
||
background: linear-gradient(135deg, #60a5fa, #2563eb);
|
||
color: #ffffff;
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
box-shadow: 0 10rpx 24rpx rgba(37, 99, 235, .22);
|
||
|
||
&::after { border: none; }
|
||
&[disabled] { opacity: .6; }
|
||
}
|
||
</style>
|