优化uniapp
This commit is contained in:
1 parent
4f1acaa451
commit
8fc52c574f
49 files changed
+1952
-197
No files matched your search
@@ -0,0 +1,402 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="hero">
|
||||
<text class="eyebrow">YUNZE WORKSPACE</text>
|
||||
<text class="title">加入企业</text>
|
||||
<text class="desc">使用业务功能需要先创建企业,或申请挂靠已有企业</text>
|
||||
</view>
|
||||
|
||||
<!-- 审核状态 -->
|
||||
<view v-if="status" class="status-card" :class="statusClass">
|
||||
<text class="status-title">{{ statusTitle }}</text>
|
||||
<text class="status-desc">{{ statusDesc }}</text>
|
||||
</view>
|
||||
|
||||
<view class="tabs">
|
||||
<view class="tab" :class="{ active: tab === 'create' }" @tap="tab = 'create'">创建企业</view>
|
||||
<view class="tab" :class="{ active: tab === 'join' }" @tap="tab = 'join'">挂靠企业</view>
|
||||
</view>
|
||||
|
||||
<!-- ============ 创建企业:沿用完整字段与后端校验 ============ -->
|
||||
<view v-if="tab === 'create'" class="card">
|
||||
<view class="field">
|
||||
<text class="label">企业全称 <text class="required">*</text></text>
|
||||
<input v-model="createForm.tenant_name" class="input" placeholder="营业执照上的公司全称" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">统一社会信用代码 <text class="required">*</text></text>
|
||||
<input v-model="createForm.credit_code" class="input" :maxlength="18" placeholder="18 位大写字母或数字" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">法定代表人 <text class="required">*</text></text>
|
||||
<input v-model="createForm.legal_person" class="input" placeholder="姓名" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">营业执照 <text class="required">*</text></text>
|
||||
<view class="upload" @tap="chooseLicense">
|
||||
<text>{{ licenseName || '点击上传 JPG / PNG,不超过 5MB' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">联系人 <text class="required">*</text></text>
|
||||
<input v-model="createForm.contact_person" class="input" placeholder="姓名" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">联系电话 <text class="required">*</text></text>
|
||||
<input v-model="createForm.contact_phone" class="input" type="number" :maxlength="11" placeholder="手机号" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">电子邮箱 <text class="required">*</text></text>
|
||||
<input v-model="createForm.contact_email" class="input" placeholder="用于接收审核结果" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">企业地址</text>
|
||||
<input v-model="createForm.address" class="input" placeholder="选填" />
|
||||
</view>
|
||||
<text class="hint">提交后由平台管理员审核,通过后自动成为该企业管理员</text>
|
||||
</view>
|
||||
|
||||
<!-- ============ 挂靠企业 ============ -->
|
||||
<view v-else class="card">
|
||||
<view class="field">
|
||||
<text class="label">企业全称 <text class="required">*</text></text>
|
||||
<view class="search-row">
|
||||
<input v-model="keyword" class="input search-input" placeholder="输入企业全称后搜索" />
|
||||
<view class="search-btn" @tap="searchTenants">搜索</view>
|
||||
</view>
|
||||
<view v-if="tenantList.length" class="result-list">
|
||||
<view v-for="t in tenantList" :key="t.tid" class="result-row" @tap="chooseTenant(t)">
|
||||
<text>{{ t.tenant_name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else-if="searched" class="no-result">未找到企业,请核对全称或改走「创建企业」</view>
|
||||
<text v-if="selectedTenant" class="selected">已选:{{ selectedTenant.tenant_name }}</text>
|
||||
</view>
|
||||
|
||||
<view class="field">
|
||||
<text class="label">部门 <text class="required">*</text></text>
|
||||
<picker :range="deptNames" :value="deptIndex" :disabled="!selectedTenant || !deptNames.length" @change="onDeptChange">
|
||||
<view class="picker-value">{{ deptName() }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">职位 <text class="required">*</text></text>
|
||||
<picker :range="positionNames" :value="positionIndex" :disabled="!positionNames.length" @change="onPositionChange">
|
||||
<view class="picker-value">{{ positionName() }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">姓名 <text class="required">*</text></text>
|
||||
<input v-model="applicantName" class="input" placeholder="真实姓名" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<text class="label">手机号</text>
|
||||
<view class="readonly"><text>{{ mobileMask || '微信已验证' }}</text><text class="readonly-tag">不可修改</text></view>
|
||||
</view>
|
||||
<text class="hint">提交后由该企业管理员审核,通过后即可使用业务功能</text>
|
||||
</view>
|
||||
|
||||
<view v-if="errorMsg" class="error"><text>{{ errorMsg }}</text></view>
|
||||
<button class="submit" :disabled="loading || (status && status.has_tenant)" @tap="handleSubmit">
|
||||
{{ loading ? '提交中…' : (tab === 'create' ? '提交创建申请' : '提交挂靠申请') }}
|
||||
</button>
|
||||
<view class="back" @tap="goBack"><text>返回工作台</text></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 需企业模块的引导页:创建企业(平台审核) / 挂靠企业(租户管理员审核)。
|
||||
* 手机号由后端从微信验证结果读取,前端只读展示,不接受输入。
|
||||
*/
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import {
|
||||
getOnboardingStatus, searchOnboardingTenants, getOnboardingDepartments,
|
||||
getOnboardingPositions, applyCreate, applyJoin
|
||||
} from '@/api/onboarding.js'
|
||||
import { getBaseURL } from '@/api/request.js'
|
||||
|
||||
const tab = ref('create')
|
||||
const status = ref(null)
|
||||
const loading = ref(false)
|
||||
const errorMsg = ref('')
|
||||
const mobileMask = ref('')
|
||||
|
||||
const createForm = reactive({
|
||||
tenant_name: '', credit_code: '', legal_person: '', license_file: '',
|
||||
contact_person: '', contact_phone: '', contact_email: '', address: ''
|
||||
})
|
||||
const licenseName = ref('')
|
||||
|
||||
const keyword = ref('')
|
||||
const searched = ref(false)
|
||||
const tenantList = ref([])
|
||||
const selectedTenant = ref(null)
|
||||
const deptList = ref([])
|
||||
const positionList = ref([])
|
||||
const deptIndex = ref(0)
|
||||
const positionIndex = ref(0)
|
||||
const applicantName = ref('')
|
||||
|
||||
const deptNames = computed(() => deptList.value.map((d) => d.name))
|
||||
const positionNames = computed(() => positionList.value.map((p) => p.name))
|
||||
|
||||
const statusClass = computed(() => {
|
||||
if (!status.value) return ''
|
||||
if (status.value.has_tenant) return 'passed'
|
||||
const a = status.value.apply
|
||||
if (!a) return ''
|
||||
return a.status === 0 ? 'pending' : (a.status === 2 ? 'rejected' : 'passed')
|
||||
})
|
||||
const statusTitle = computed(() => {
|
||||
if (!status.value) return ''
|
||||
if (status.value.has_tenant) return '已加入 ' + (status.value.tenant_name || '企业')
|
||||
const a = status.value.apply
|
||||
if (!a) return '尚未提交申请'
|
||||
if (a.status === 0) return '审核中'
|
||||
if (a.status === 2) return '申请已驳回'
|
||||
return '审核已通过'
|
||||
})
|
||||
const statusDesc = computed(() => {
|
||||
if (!status.value) return ''
|
||||
if (status.value.has_tenant) return '返回工作台即可使用业务功能'
|
||||
const a = status.value.apply
|
||||
if (!a) return '请选择「创建企业」或「挂靠企业」并提交资料'
|
||||
if (a.status === 0) return '请等待管理员审核,通过后即可使用业务功能'
|
||||
if (a.status === 2) return (a.reject_reason || '资料不符合要求') + ',可修改后重新提交'
|
||||
return '审核已通过,返回工作台重新进入即可'
|
||||
})
|
||||
|
||||
onShow(() => { loadStatus() })
|
||||
|
||||
async function loadStatus() {
|
||||
try {
|
||||
const res = await getOnboardingStatus()
|
||||
status.value = res || null
|
||||
mobileMask.value = (res && res.mobile_mask) || ''
|
||||
} catch (e) {
|
||||
console.warn('[onboarding] status failed:', e)
|
||||
}
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
uni.reLaunch({ url: '/pages/nav/nav' })
|
||||
}
|
||||
|
||||
function chooseLicense() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: (res) => {
|
||||
const filePath = res.tempFilePaths && res.tempFilePaths[0]
|
||||
if (!filePath) return
|
||||
uni.showLoading({ title: '上传中...', mask: true })
|
||||
uni.uploadFile({
|
||||
url: getBaseURL().replace(/\/$/, '') + '/auth/register/upload-license',
|
||||
filePath,
|
||||
name: 'file',
|
||||
success: (r) => {
|
||||
try {
|
||||
const body = JSON.parse(r.data || '{}')
|
||||
if (body.code === 200 && body.data && body.data.url) {
|
||||
createForm.license_file = body.data.url
|
||||
licenseName.value = body.data.name || '已上传'
|
||||
} else {
|
||||
uni.showToast({ title: body.msg || '上传失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '上传失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
fail: () => uni.showToast({ title: '上传失败', icon: 'none' }),
|
||||
complete: () => uni.hideLoading()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function searchTenants() {
|
||||
const kw = keyword.value.trim()
|
||||
if (!kw) {
|
||||
errorMsg.value = '请输入企业全称'
|
||||
return
|
||||
}
|
||||
errorMsg.value = ''
|
||||
try {
|
||||
const res = await searchOnboardingTenants(kw)
|
||||
tenantList.value = (res && res.list) || []
|
||||
searched.value = true
|
||||
selectedTenant.value = null
|
||||
deptList.value = []
|
||||
positionList.value = []
|
||||
} catch (e) {
|
||||
errorMsg.value = (e && e.message) || '企业搜索失败'
|
||||
}
|
||||
}
|
||||
|
||||
async function chooseTenant(t) {
|
||||
selectedTenant.value = t
|
||||
keyword.value = t.tenant_name
|
||||
deptIndex.value = 0
|
||||
positionIndex.value = 0
|
||||
positionList.value = []
|
||||
try {
|
||||
const res = await getOnboardingDepartments(t.tid)
|
||||
deptList.value = (res && res.list) || []
|
||||
if (deptList.value.length) await loadPositions()
|
||||
} catch (e) {
|
||||
errorMsg.value = (e && e.message) || '部门列表加载失败'
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPositions() {
|
||||
const dept = deptList.value[deptIndex.value]
|
||||
if (!selectedTenant.value || !dept) return
|
||||
try {
|
||||
const res = await getOnboardingPositions(selectedTenant.value.tid, dept.id)
|
||||
positionList.value = (res && res.list) || []
|
||||
positionIndex.value = 0
|
||||
} catch (e) {
|
||||
errorMsg.value = (e && e.message) || '职位列表加载失败'
|
||||
}
|
||||
}
|
||||
|
||||
function onDeptChange(e) {
|
||||
deptIndex.value = Number(e.detail.value) || 0
|
||||
loadPositions()
|
||||
}
|
||||
|
||||
function onPositionChange(e) {
|
||||
positionIndex.value = Number(e.detail.value) || 0
|
||||
}
|
||||
|
||||
function deptName() {
|
||||
const d = deptList.value[deptIndex.value]
|
||||
return d ? d.name : (selectedTenant.value ? '请选择部门' : '请先搜索并选择企业')
|
||||
}
|
||||
|
||||
function positionName() {
|
||||
const p = positionList.value[positionIndex.value]
|
||||
return p ? p.name : (deptList.value.length ? '请选择职位' : '请先选择部门')
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (loading.value) return
|
||||
errorMsg.value = ''
|
||||
if (status.value && status.value.has_tenant) {
|
||||
goBack()
|
||||
return
|
||||
}
|
||||
if (tab.value === 'create') await submitCreate()
|
||||
else await submitJoin()
|
||||
}
|
||||
|
||||
async function submitCreate() {
|
||||
const f = createForm
|
||||
f.tenant_name = f.tenant_name.trim()
|
||||
f.credit_code = f.credit_code.trim().toUpperCase()
|
||||
if (!f.tenant_name || !/^[0-9A-Z]{18}$/.test(f.credit_code) || !f.legal_person.trim() ||
|
||||
!f.license_file || !f.contact_person.trim() || !/^1\d{10}$/.test(f.contact_phone.trim()) ||
|
||||
!f.contact_email.includes('@')) {
|
||||
errorMsg.value = '请完整填写企业信息:信用代码 18 位、营业执照、法人、联系人、11 位手机号与邮箱为必填'
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
await applyCreate({
|
||||
tenant_name: f.tenant_name,
|
||||
credit_code: f.credit_code,
|
||||
legal_person: f.legal_person.trim(),
|
||||
license_file: f.license_file,
|
||||
contact_person: f.contact_person.trim(),
|
||||
contact_phone: f.contact_phone.trim(),
|
||||
contact_email: f.contact_email.trim(),
|
||||
address: f.address.trim()
|
||||
})
|
||||
uni.showToast({ title: '已提交,等待平台审核', icon: 'none' })
|
||||
await loadStatus()
|
||||
} catch (e) {
|
||||
errorMsg.value = (e && e.message) || '提交失败,请重试'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function submitJoin() {
|
||||
if (!selectedTenant.value) {
|
||||
errorMsg.value = '请先搜索并选择要挂靠的企业'
|
||||
return
|
||||
}
|
||||
const dept = deptList.value[deptIndex.value]
|
||||
const pos = positionList.value[positionIndex.value]
|
||||
if (!dept || !pos || !applicantName.value.trim()) {
|
||||
errorMsg.value = '请选择部门、职位并填写姓名'
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
await applyJoin({
|
||||
tid: selectedTenant.value.tid,
|
||||
applicant_name: applicantName.value.trim(),
|
||||
department_id: dept.id,
|
||||
department_name: dept.name,
|
||||
position_id: pos.id,
|
||||
position_name: pos.name
|
||||
})
|
||||
uni.showToast({ title: '已提交,等待企业管理员审核', icon: 'none' })
|
||||
await loadStatus()
|
||||
} 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: #f5f8fd; }
|
||||
.hero { padding: 100rpx 8rpx 40rpx; }
|
||||
.eyebrow { display: block; font-size: 20rpx; font-weight: 700; letter-spacing: 3rpx; color: #6e9de5; }
|
||||
.title { display: block; margin-top: 14rpx; font-size: 44rpx; font-weight: 700; color: #17345f; }
|
||||
.desc { display: block; margin-top: 14rpx; font-size: 25rpx; line-height: 1.6; color: #64748b; }
|
||||
|
||||
.status-card { @include card; padding: 26rpx 28rpx; margin-bottom: 28rpx; border-left: 8rpx solid #94a3b8; }
|
||||
.status-card.pending { border-left-color: #f59e0b; }
|
||||
.status-card.rejected { border-left-color: #ef4444; }
|
||||
.status-card.passed { border-left-color: #10b981; }
|
||||
.status-title { display: block; font-size: 30rpx; font-weight: 700; color: #0f172a; }
|
||||
.status-desc { display: block; margin-top: 8rpx; font-size: 23rpx; line-height: 1.6; color: #64748b; }
|
||||
|
||||
.tabs { display: flex; gap: 12rpx; padding: 8rpx; margin-bottom: 24rpx; border-radius: $radius-full; background: #e8eef8; }
|
||||
.tab { flex: 1; height: 76rpx; display: flex; align-items: center; justify-content: center; border-radius: $radius-full; font-size: 27rpx; color: #64748b; }
|
||||
.tab.active { background: #ffffff; color: #2563eb; font-weight: 700; box-shadow: 0 4rpx 14rpx rgba(15, 23, 42, .08); }
|
||||
|
||||
.card { @include card; padding: 32rpx 28rpx 36rpx; }
|
||||
.field { margin-bottom: 26rpx; }
|
||||
.label { display: block; margin-bottom: 12rpx; font-size: 25rpx; font-weight: 600; color: #334155; }
|
||||
.required { color: #ef4444; }
|
||||
.input { height: 84rpx; padding: 0 22rpx; border: 1rpx solid #dce7f7; border-radius: $radius-md; background: #fbfdff; font-size: 27rpx; color: $color-text; box-sizing: border-box; }
|
||||
.hint { display: block; font-size: 22rpx; line-height: 1.6; color: $color-text-muted; }
|
||||
.error { margin-top: 24rpx; font-size: 24rpx; color: $color-danger; }
|
||||
|
||||
.upload { min-height: 88rpx; padding: 24rpx 22rpx; border: 1rpx dashed #b9d2ff; border-radius: $radius-md; background: #f7faff; font-size: 24rpx; color: #2563eb; }
|
||||
.search-row { display: flex; gap: 14rpx; }
|
||||
.search-input { flex: 1; }
|
||||
.search-btn { width: 140rpx; height: 84rpx; display: flex; align-items: center; justify-content: center; border-radius: $radius-md; background: #2563eb; color: #fff; font-size: 26rpx; }
|
||||
.result-list { margin-top: 14rpx; border: 1rpx solid #e2e8f0; border-radius: $radius-md; overflow: hidden; }
|
||||
.result-row { padding: 20rpx 22rpx; font-size: 26rpx; color: #334155; border-bottom: 1rpx solid #eef2f7; }
|
||||
.result-row:last-child { border-bottom: none; }
|
||||
.no-result { margin-top: 14rpx; font-size: 23rpx; color: #94a3b8; }
|
||||
.selected { display: block; margin-top: 14rpx; font-size: 24rpx; color: #2563eb; }
|
||||
.picker-value { height: 84rpx; line-height: 84rpx; padding: 0 22rpx; border: 1rpx solid #dce7f7; border-radius: $radius-md; background: #fbfdff; font-size: 27rpx; color: $color-text; }
|
||||
.readonly { height: 84rpx; display: flex; align-items: center; justify-content: space-between; padding: 0 22rpx; border: 1rpx solid #e2e8f0; border-radius: $radius-md; background: #f1f5f9; font-size: 27rpx; color: #475569; }
|
||||
.readonly-tag { font-size: 21rpx; color: #94a3b8; }
|
||||
|
||||
.submit { margin-top: 36rpx; height: 92rpx; line-height: 92rpx; border: none; border-radius: $radius-full; background: linear-gradient(135deg, #60a5fa, #2563eb); color: #fff; font-size: 30rpx; font-weight: 600; box-shadow: 0 10rpx 24rpx rgba(37, 99, 235, .22);
|
||||
&::after { border: none; }
|
||||
&[disabled] { opacity: .6; }
|
||||
}
|
||||
.back { margin-top: 28rpx; text-align: center; font-size: 25rpx; color: #94a3b8; }
|
||||
</style>
|
||||
@@ -0,0 +1,150 @@
|
||||
<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>
|
||||
Reference in new issue
Block a user