2025-06-05 11:52:12 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view>
|
|
|
|
|
|
<up-tabs
|
|
|
|
|
|
:list="list"
|
|
|
|
|
|
@click="click"
|
|
|
|
|
|
class="mx-4"
|
|
|
|
|
|
lineWidth="300rpx"
|
2025-07-29 11:07:43 +08:00
|
|
|
|
lineColor="#4777ee"
|
2025-06-05 11:52:12 +08:00
|
|
|
|
:activeStyle="{
|
2025-07-29 11:07:43 +08:00
|
|
|
|
color: '#4777ee',
|
2025-06-05 11:52:12 +08:00
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
|
transform: 'scale(1.05)'
|
|
|
|
|
|
}"
|
|
|
|
|
|
itemStyle="width: 343rpx;height: 108rpx;font-size: 32rpx"
|
|
|
|
|
|
></up-tabs>
|
|
|
|
|
|
<view class="mx-6 mt-10">
|
|
|
|
|
|
<view class="mt-4 flex items-center w-full" @click="toJump('countryList')">
|
|
|
|
|
|
<view class="w-200">国家/地区</view>
|
|
|
|
|
|
<view class="text-#63b8af">
|
|
|
|
|
|
{{ country.name }}
|
|
|
|
|
|
<span v-if="type === 1">+{{ country.code }}</span>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="mt-4">
|
|
|
|
|
|
<up-input
|
|
|
|
|
|
:placeholder="type === 1 ? '请输入手机号' : '请输入邮箱'"
|
|
|
|
|
|
fontSize="32rpx"
|
|
|
|
|
|
:placeholderStyle="{
|
|
|
|
|
|
color: '#333333',
|
|
|
|
|
|
fontSize: '32rpx'
|
|
|
|
|
|
}"
|
|
|
|
|
|
:customStyle="{
|
|
|
|
|
|
padding: '0',
|
|
|
|
|
|
height: '80rpx'
|
|
|
|
|
|
}"
|
|
|
|
|
|
border="bottom"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
v-model="username"
|
|
|
|
|
|
:maxlength="50"
|
|
|
|
|
|
@change="handleUsernameInput"
|
|
|
|
|
|
></up-input>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="mt-4">
|
|
|
|
|
|
<up-input
|
|
|
|
|
|
fontSize="32rpx"
|
|
|
|
|
|
:placeholderStyle="{
|
|
|
|
|
|
color: '#333333',
|
|
|
|
|
|
fontSize: '32rpx'
|
|
|
|
|
|
}"
|
|
|
|
|
|
:customStyle="{
|
|
|
|
|
|
padding: '0',
|
|
|
|
|
|
height: '80rpx'
|
|
|
|
|
|
}"
|
2025-06-06 13:50:48 +08:00
|
|
|
|
placeholder="请输入密码"
|
2025-06-05 11:52:12 +08:00
|
|
|
|
type="password"
|
|
|
|
|
|
border="bottom"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
v-model="password"
|
|
|
|
|
|
:maxlength="20"
|
|
|
|
|
|
@change="handlePasswordInput"
|
|
|
|
|
|
></up-input>
|
|
|
|
|
|
<view class="text-#999999 text-sm mt-1">
|
|
|
|
|
|
密码必须是8-20位,至少包括数字/字母/符号中的2种
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="mt-4">
|
|
|
|
|
|
<up-input
|
|
|
|
|
|
fontSize="32rpx"
|
|
|
|
|
|
:placeholderStyle="{
|
|
|
|
|
|
color: '#333333',
|
|
|
|
|
|
fontSize: '32rpx'
|
|
|
|
|
|
}"
|
|
|
|
|
|
:customStyle="{
|
|
|
|
|
|
padding: '0',
|
|
|
|
|
|
height: '80rpx'
|
|
|
|
|
|
}"
|
|
|
|
|
|
placeholder="确认密码"
|
|
|
|
|
|
type="password"
|
|
|
|
|
|
border="bottom"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
v-model="confirmPassword"
|
|
|
|
|
|
:maxlength="20"
|
|
|
|
|
|
@change="handleConfirmPasswordInput"
|
|
|
|
|
|
></up-input>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="mt-4 flex items-center">
|
|
|
|
|
|
<up-input
|
|
|
|
|
|
fontSize="32rpx"
|
|
|
|
|
|
:placeholderStyle="{
|
|
|
|
|
|
color: '#333333',
|
|
|
|
|
|
fontSize: '32rpx'
|
|
|
|
|
|
}"
|
|
|
|
|
|
:customStyle="{
|
|
|
|
|
|
padding: '0',
|
|
|
|
|
|
height: '80rpx'
|
|
|
|
|
|
}"
|
|
|
|
|
|
placeholder="请输入验证码"
|
2025-06-06 13:50:48 +08:00
|
|
|
|
type="number"
|
2025-06-05 11:52:12 +08:00
|
|
|
|
border="bottom"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
v-model="code"
|
|
|
|
|
|
:maxlength="20"
|
|
|
|
|
|
@change="handleCodeInput"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #suffix>
|
|
|
|
|
|
<up-button @tap="getCode" :disabled="!canGetCode" color="#63b8af">
|
|
|
|
|
|
{{ tips }}
|
|
|
|
|
|
</up-button>
|
|
|
|
|
|
<up-code
|
|
|
|
|
|
:seconds="seconds"
|
|
|
|
|
|
ref="uCodeRef"
|
|
|
|
|
|
changeText="X秒后重新获取"
|
|
|
|
|
|
endText="获取验证码"
|
|
|
|
|
|
@change="codeChange"
|
|
|
|
|
|
></up-code
|
|
|
|
|
|
></template>
|
|
|
|
|
|
</up-input>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="my-6 flex items-center text-sm" @click="agreeAgreement">
|
|
|
|
|
|
<image
|
|
|
|
|
|
class="w-35 h-35"
|
|
|
|
|
|
v-if="select"
|
|
|
|
|
|
src="https://oss-lock.xhjcn.ltd/mp/icon_select.png"
|
|
|
|
|
|
></image>
|
|
|
|
|
|
<image
|
|
|
|
|
|
v-else
|
|
|
|
|
|
class="w-35 h-35"
|
|
|
|
|
|
src="https://oss-lock.xhjcn.ltd/mp/icon_not_select.png"
|
|
|
|
|
|
></image>
|
|
|
|
|
|
<view class="ml-2">
|
|
|
|
|
|
我已阅读并同意
|
|
|
|
|
|
<span class="text-#63b8af" @click="toWebview('userAgreement')">《用户协议》 </span>
|
|
|
|
|
|
<span class="text-#63b8af" @click="toWebview('privacy')">《隐私协议》</span>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="w-full rounded-full h-88 text-center leading-[88rpx] text-white"
|
2025-07-29 11:07:43 +08:00
|
|
|
|
:class="[canRegister ? 'bg-#4777ee' : 'bg-#9d9da1']"
|
2025-06-05 11:52:12 +08:00
|
|
|
|
@click="register"
|
|
|
|
|
|
>
|
|
|
|
|
|
注册
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, computed, onMounted } from 'vue'
|
|
|
|
|
|
import { useBasicStore } from '@/stores/basic'
|
|
|
|
|
|
import { PHONE_REG, EMAIL_REG, PASSWORD_REG } from '@/constant/reg'
|
|
|
|
|
|
import { useUserStore } from '@/stores/user'
|
|
|
|
|
|
|
|
|
|
|
|
const $basic = useBasicStore()
|
|
|
|
|
|
const $user = useUserStore()
|
|
|
|
|
|
|
|
|
|
|
|
const list = ref([
|
|
|
|
|
|
{ name: '手机', receiverType: 1 },
|
|
|
|
|
|
{ name: '邮箱', receiverType: 2 }
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
const type = ref(1)
|
|
|
|
|
|
const username = ref('')
|
|
|
|
|
|
const password = ref('')
|
|
|
|
|
|
const confirmPassword = ref('')
|
|
|
|
|
|
const code = ref('')
|
|
|
|
|
|
|
|
|
|
|
|
const tips = ref('')
|
|
|
|
|
|
const seconds = ref(120)
|
|
|
|
|
|
const uCodeRef = ref(null)
|
|
|
|
|
|
const select = ref(false)
|
|
|
|
|
|
|
2025-06-10 14:23:50 +08:00
|
|
|
|
const pending = ref(false)
|
|
|
|
|
|
|
2025-06-05 11:52:12 +08:00
|
|
|
|
onMounted(async () => {
|
|
|
|
|
|
const res = await $basic.getDeviceInfo()
|
|
|
|
|
|
if (res.language !== 'zh-CN') {
|
|
|
|
|
|
list.value.reverse()
|
|
|
|
|
|
type.value = 2
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const codeChange = text => {
|
|
|
|
|
|
tips.value = text
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getCode = () => {
|
|
|
|
|
|
if (!uCodeRef.value.canGetCode) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
account: username.value,
|
|
|
|
|
|
codeType: 1,
|
|
|
|
|
|
channel: type.value,
|
|
|
|
|
|
countryCode: country.value.code
|
|
|
|
|
|
}
|
|
|
|
|
|
$basic.routeJump({
|
|
|
|
|
|
name: 'safeVerify',
|
|
|
|
|
|
events: {
|
|
|
|
|
|
successEvent() {
|
|
|
|
|
|
uCodeRef.value.start()
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
params
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const country = ref({
|
|
|
|
|
|
countryId: 0,
|
|
|
|
|
|
name: '中国',
|
|
|
|
|
|
code: '86',
|
|
|
|
|
|
flag: 'https://lock.xhjcn.ltd/storage/country-flags/86.png',
|
|
|
|
|
|
abbreviation: 'CN',
|
|
|
|
|
|
group: 'Z'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const isValidUsername = computed(() => {
|
|
|
|
|
|
if (!username.value) return false
|
|
|
|
|
|
if (type.value === 1) {
|
|
|
|
|
|
return PHONE_REG.test(username.value)
|
|
|
|
|
|
}
|
|
|
|
|
|
return EMAIL_REG.test(username.value)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const isValidPassword = computed(() => {
|
|
|
|
|
|
if (!password.value) return false
|
|
|
|
|
|
return PASSWORD_REG.test(password.value)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const isValidConfirmPassword = computed(() => {
|
|
|
|
|
|
if (!confirmPassword.value) return false
|
|
|
|
|
|
return confirmPassword.value === password.value
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const isValidCode = computed(() => {
|
|
|
|
|
|
if (!code.value) return false
|
|
|
|
|
|
return code.value.length === 6
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const canGetCode = computed(() => {
|
|
|
|
|
|
return isValidUsername.value
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const canRegister = computed(() => {
|
|
|
|
|
|
return (
|
|
|
|
|
|
isValidUsername.value &&
|
|
|
|
|
|
isValidPassword.value &&
|
|
|
|
|
|
isValidConfirmPassword.value &&
|
|
|
|
|
|
isValidCode.value
|
|
|
|
|
|
)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const agreeAgreement = () => {
|
|
|
|
|
|
select.value = !select.value
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const register = async () => {
|
|
|
|
|
|
if (!canRegister.value) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!select.value) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '请先同意用户协议及隐私协议',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-06-10 14:23:50 +08:00
|
|
|
|
if (pending.value) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pending.value = true
|
2025-06-05 11:52:12 +08:00
|
|
|
|
const res = await $user.register({
|
|
|
|
|
|
account: username.value,
|
|
|
|
|
|
password: password.value,
|
|
|
|
|
|
receiverType: type.value,
|
|
|
|
|
|
countryCode: country.value.code,
|
|
|
|
|
|
verificationCode: code.value
|
|
|
|
|
|
})
|
2025-06-10 14:23:50 +08:00
|
|
|
|
pending.value = false
|
2025-06-05 11:52:12 +08:00
|
|
|
|
if (res) {
|
|
|
|
|
|
$basic.routeJump({
|
|
|
|
|
|
name: 'home',
|
|
|
|
|
|
type: 'reLaunch'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const click = item => {
|
|
|
|
|
|
type.value = item.receiverType
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleUsernameInput = text => {
|
|
|
|
|
|
username.value = text
|
|
|
|
|
|
}
|
|
|
|
|
|
const handlePasswordInput = text => {
|
|
|
|
|
|
password.value = text
|
|
|
|
|
|
}
|
|
|
|
|
|
const handleConfirmPasswordInput = text => {
|
|
|
|
|
|
confirmPassword.value = text
|
|
|
|
|
|
}
|
|
|
|
|
|
const handleCodeInput = text => {
|
|
|
|
|
|
code.value = text
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const toJump = path => {
|
|
|
|
|
|
$basic.routeJump({
|
|
|
|
|
|
name: path,
|
|
|
|
|
|
events: {
|
|
|
|
|
|
country(data) {
|
|
|
|
|
|
country.value = data
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const toWebview = type => {
|
|
|
|
|
|
$basic.routeJump({
|
|
|
|
|
|
name: 'webview',
|
|
|
|
|
|
params: {
|
|
|
|
|
|
type
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|