主要更新uniapp相关功能
This commit is contained in:
1 parent
aa92ca40a2
commit
5b4dbb2b46
65 files changed
+8532
-1921
No files matched your search
+110
-60
@@ -30,7 +30,7 @@
|
||||
@tap="chooseTenant(item)"
|
||||
>
|
||||
<view class="tenant-avatar">
|
||||
<FaIcon name="building" color="#3973ff" :size="18" />
|
||||
<FaIcon name="building" color="#2563eb" :size="18" />
|
||||
</view>
|
||||
<view class="tenant-info">
|
||||
<text class="tenant-name">{{ item.tenant_name || `企业${item.tid}` }}</text>
|
||||
@@ -45,17 +45,40 @@
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- ============ 账号密码登录 ============ -->
|
||||
<!-- ============ 登录(小程序端微信认证优先,其次账号密码;H5/APK 仅账号密码) ============ -->
|
||||
<block v-else>
|
||||
<view class="panel-head">
|
||||
<text class="panel-title">欢迎登录</text>
|
||||
<text class="panel-sub">请输入您的账号与密码以继续</text>
|
||||
<text class="panel-sub">{{ showMiniLogin ? '使用微信一键登录,或使用账号密码继续' : '请输入您的账号与密码以继续' }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="errorMsg" class="error-box">
|
||||
<text class="error-text">{{ errorMsg }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 微信小程序:微信认证登录为主入口 -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<block v-if="showMiniLogin">
|
||||
<button
|
||||
class="btn-wechat"
|
||||
open-type="getPhoneNumber"
|
||||
:class="{ disabled: submitting }"
|
||||
@getphonenumber="onGetPhoneNumber"
|
||||
>
|
||||
<FaIcon name="weixin" type="brands" color="#ffffff" :size="18" />
|
||||
<text>微信手机号一键登录</text>
|
||||
</button>
|
||||
<view class="tip-row">
|
||||
<text class="tip-text">首次使用请先用账号密码登录一次,自动完成微信绑定后即可一键登录</text>
|
||||
</view>
|
||||
<view class="divider">
|
||||
<view class="divider-line" />
|
||||
<text class="divider-text">使用账号密码登录</text>
|
||||
<view class="divider-line" />
|
||||
</view>
|
||||
</block>
|
||||
<!-- #endif -->
|
||||
|
||||
<view class="field">
|
||||
<text class="field-label">账号</text>
|
||||
<view class="input-wrap">
|
||||
@@ -110,31 +133,6 @@
|
||||
<text class="agree-tip-text">请先阅读并勾选同意《用户协议》和《隐私政策》</text>
|
||||
</view>
|
||||
|
||||
<!-- 微信小程序一键登录 -->
|
||||
<block v-if="showMiniLogin">
|
||||
<view class="divider">
|
||||
<view class="divider-line" />
|
||||
<text class="divider-text">其他登录方式</text>
|
||||
<view class="divider-line" />
|
||||
</view>
|
||||
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<button
|
||||
class="btn-wechat"
|
||||
open-type="getPhoneNumber"
|
||||
:class="{ disabled: submitting }"
|
||||
@getphonenumber="onGetPhoneNumber"
|
||||
>
|
||||
<FaIcon name="weixin" type="brands" color="#ffffff" :size="18" />
|
||||
<text>微信手机号一键登录</text>
|
||||
</button>
|
||||
<!-- #endif -->
|
||||
|
||||
<view class="tip-row">
|
||||
<text class="tip-text">首次使用将自动绑定当前微信手机号对应的云泽账号</text>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view class="back-row">
|
||||
<text class="tip-text">还没有账号?</text>
|
||||
<text class="link" @tap="goRegister">立即注册</text>
|
||||
@@ -167,7 +165,8 @@ import {
|
||||
fetchUserInfo,
|
||||
getAuthVerifyConfig,
|
||||
getMiniappLoginConfig,
|
||||
loginByMiniapp
|
||||
loginByMiniapp,
|
||||
bindMiniapp
|
||||
} from '@/api/auth.js'
|
||||
import {
|
||||
loginSuccess,
|
||||
@@ -202,6 +201,18 @@ const verifyCfg = ref({ needGeetest: false, captchaId: '' })
|
||||
/** 仅微信小程序端且服务端已开通时展示「一键登录」入口 */
|
||||
const showMiniLogin = ref(false)
|
||||
|
||||
/** 运行端检测:h5 / apk(app-plus) / mp-weixin,决定登录方式优先级 */
|
||||
const platform = ref('')
|
||||
// #ifdef H5
|
||||
platform.value = 'h5'
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
platform.value = 'apk'
|
||||
// #endif
|
||||
// #ifdef MP-WEIXIN
|
||||
platform.value = 'mp-weixin'
|
||||
// #endif
|
||||
|
||||
onMounted(async () => {
|
||||
if (isLoggedIn()) {
|
||||
uni.reLaunch({ url: '/pages/nav/nav' })
|
||||
@@ -231,25 +242,33 @@ async function loadVerifyConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 小程序一键登录是否已开通(未开通则隐藏入口) */
|
||||
/** 小程序一键登录是否已开通(仅微信端拉取,未开通则回退账号密码登录) */
|
||||
async function loadMiniLoginConfig() {
|
||||
// #ifdef MP-WEIXIN
|
||||
if (platform.value !== 'mp-weixin') return
|
||||
try {
|
||||
const data = await getMiniappLoginConfig()
|
||||
showMiniLogin.value = !!data?.enabled
|
||||
} catch {
|
||||
showMiniLogin.value = false
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
/* ==================== 登录主流程 ==================== */
|
||||
|
||||
async function handleLogin() {
|
||||
if (submitting.value) return
|
||||
console.log('[login] tap handleLogin', { submitting: submitting.value, agreed: agreed.value })
|
||||
if (submitting.value) {
|
||||
uni.showToast({ title: '登录处理中,请稍候', icon: 'none' })
|
||||
return
|
||||
}
|
||||
// 未勾选协议:弹窗确认,确认后自动勾选并继续登录
|
||||
if (!agreed.value) {
|
||||
const ok = await confirmAgreement()
|
||||
let ok = false
|
||||
try {
|
||||
ok = await confirmAgreement()
|
||||
} catch {
|
||||
ok = false
|
||||
}
|
||||
if (!ok) {
|
||||
showAgreementTip.value = true
|
||||
return
|
||||
@@ -269,7 +288,8 @@ async function handleLogin() {
|
||||
errorMsg.value = ''
|
||||
try {
|
||||
let captcha = null
|
||||
if (verifyCfg.value.needGeetest) {
|
||||
// 小程序端无极验 SDK:不弹验证,后端对 yz-miniapp 客户端也跳过校验
|
||||
if (verifyCfg.value.needGeetest && platform.value !== 'mp-weixin') {
|
||||
if (!verifyCfg.value.captchaId) {
|
||||
errorMsg.value = '人机验证未配置,请联系管理员'
|
||||
return
|
||||
@@ -376,6 +396,9 @@ async function finishLogin(tokens, tenantList, tid, fallbackAccount = '') {
|
||||
}
|
||||
})
|
||||
|
||||
// 微信端:登录成功后静默绑定 openid,认证中/无手机号能力时一键登录靠它认人
|
||||
await silentBindMiniapp()
|
||||
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '登录成功', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
@@ -399,20 +422,35 @@ function uniLoginCode() {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信端登录成功后静默把当前 openid 绑到该账号。
|
||||
* 小程序认证中 / 未开通手机号能力时,一键登录拿不到手机号,
|
||||
* 后端按这条绑定认人;绑定失败不阻塞登录。
|
||||
*/
|
||||
async function silentBindMiniapp() {
|
||||
if (platform.value !== 'mp-weixin') return
|
||||
try {
|
||||
const code = await uniLoginCode()
|
||||
await bindMiniapp({ code })
|
||||
} catch {
|
||||
/* 静默:不影响已完成的登录 */
|
||||
}
|
||||
}
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
/** getPhoneNumber 授权回调:动态 code + uni.login code 一起换登录态 */
|
||||
async function onGetPhoneNumber(e) {
|
||||
if (submitting.value) return
|
||||
const detail = (e && e.detail) || {}
|
||||
if (detail.errMsg && detail.errMsg.indexOf('fail') !== -1) {
|
||||
if (detail.errMsg.indexOf('deny') !== -1) {
|
||||
uni.showToast({ title: '你已取消手机号授权', icon: 'none' })
|
||||
}
|
||||
const errMsg = detail.errMsg || ''
|
||||
if (errMsg.indexOf('deny') !== -1) {
|
||||
uni.showToast({ title: '你已取消手机号授权', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!detail.code) {
|
||||
uni.showToast({ title: '未获取到手机号凭证,请重试', icon: 'none' })
|
||||
return
|
||||
// 认证中 / 未开通手机号能力:拿不到动态 code 时降级为「按已绑定 openid 登录」
|
||||
const phoneCode = detail.code && errMsg.indexOf('fail') === -1 ? detail.code : ''
|
||||
if (!phoneCode) {
|
||||
uni.showToast({ title: '手机号能力暂不可用,按已绑定账号登录', icon: 'none' })
|
||||
}
|
||||
if (!agreed.value) {
|
||||
const ok = await confirmAgreement()
|
||||
@@ -426,7 +464,7 @@ async function onGetPhoneNumber(e) {
|
||||
errorMsg.value = ''
|
||||
try {
|
||||
const code = await uniLoginCode()
|
||||
const data = await loginByMiniapp({ code, phoneCode: detail.code })
|
||||
const data = await loginByMiniapp({ code, phoneCode })
|
||||
await handleAuthResult(data)
|
||||
} catch (err) {
|
||||
handleMiniError(err)
|
||||
@@ -441,12 +479,10 @@ function handleMiniError(err) {
|
||||
if (reason === 'identity_not_found') {
|
||||
uni.showModal({
|
||||
title: '尚未绑定云泽账号',
|
||||
content: '当前微信手机号未注册云泽账号,请先使用账号密码登录或注册后再使用一键登录。',
|
||||
content: '当前微信未绑定云泽账号,且手机号能力暂不可用。请先在下方用账号密码登录一次(会自动完成微信绑定),之后即可一键登录。',
|
||||
showCancel: false,
|
||||
confirmText: '去注册',
|
||||
success: (res) => {
|
||||
if (res.confirm) goRegister()
|
||||
}
|
||||
// 微信小程序 showModal 的 confirmText 上限为 4 个汉字,超限会导致 API 失败、弹窗不显示
|
||||
confirmText: '密码登录'
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -494,28 +530,42 @@ function showAgreement() {
|
||||
|
||||
/**
|
||||
* 未勾选协议时的二次确认弹窗。
|
||||
* 点「同意并登录」→ 自动勾选协议并返回 true,调用方继续登录;
|
||||
* 点「同意登录」→ 自动勾选协议并返回 true,调用方继续登录;
|
||||
* 点「再看看」→ 返回 false,停在当前页并高亮提示。
|
||||
* 兜底:部分端 showModal 既不回调 success 也不回调 fail,会导致 await 永久挂起、
|
||||
* 点击登录「没反应」,这里用超时保证一定会返回,绝不阻塞。
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
function confirmAgreement() {
|
||||
return new Promise((resolve) => {
|
||||
let settled = false
|
||||
let timer = null
|
||||
const finish = (val) => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
if (timer) clearTimeout(timer)
|
||||
resolve(val)
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
console.warn('[login] confirmAgreement 超时未回调,按未同意处理')
|
||||
finish(false)
|
||||
}, 8000)
|
||||
uni.showModal({
|
||||
title: '请确认用户协议',
|
||||
content: '登录即表示您已阅读并同意《用户协议》与《隐私政策》,是否同意并继续登录?',
|
||||
confirmText: '同意并登录',
|
||||
confirmText: '同意登录',
|
||||
cancelText: '再看看',
|
||||
confirmColor: '#3973ff',
|
||||
confirmColor: '#2563eb',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
agreed.value = true
|
||||
showAgreementTip.value = false
|
||||
resolve(true)
|
||||
finish(true)
|
||||
} else {
|
||||
resolve(false)
|
||||
finish(false)
|
||||
}
|
||||
},
|
||||
fail: () => resolve(false)
|
||||
fail: () => finish(false)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -530,7 +580,7 @@ function goForget() {
|
||||
|
||||
.login-page {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(160deg, #1b3b8f 0%, #2f6fe4 52%, #52a8ff 100%);
|
||||
background: linear-gradient(160deg, #1e3a8a 0%, #2563eb 100%);
|
||||
padding: 0 32rpx calc(env(safe-area-inset-bottom, 0px) + 40rpx);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -703,7 +753,7 @@ function goForget() {
|
||||
.btn {
|
||||
height: 92rpx;
|
||||
border-radius: $radius-md;
|
||||
background: linear-gradient(135deg, #3973ff 0%, #52a8ff 100%);
|
||||
background: linear-gradient(135deg, #2563eb 0%, #60a5fa 100%);
|
||||
color: #ffffff;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
@@ -781,7 +831,7 @@ function goForget() {
|
||||
|
||||
.link {
|
||||
font-size: 26rpx;
|
||||
color: #3973ff;
|
||||
color: #2563eb;
|
||||
}
|
||||
|
||||
/* ---------- 企业选择 ---------- */
|
||||
@@ -801,7 +851,7 @@ function goForget() {
|
||||
background: #fbfcff;
|
||||
|
||||
&:active {
|
||||
border-color: #3973ff;
|
||||
border-color: #2563eb;
|
||||
background: #f5f9ff;
|
||||
}
|
||||
|
||||
@@ -878,8 +928,8 @@ function goForget() {
|
||||
height: 16rpx;
|
||||
margin-left: -5rpx;
|
||||
transform: translateY(-50%) rotate(45deg);
|
||||
border-right: 3rpx solid #1b3b8f;
|
||||
border-bottom: 3rpx solid #1b3b8f;
|
||||
border-right: 3rpx solid #1e3a8a;
|
||||
border-bottom: 3rpx solid #1e3a8a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user