feat: H5 WeChat one-tap authorize login/register and UI polish
Replace QR login with OAuth button; auto-authorize register/bind; follow OA in settings; advisor text styling. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
bd97ed76fd
commit
37d534edc3
@ -69,6 +69,12 @@ export async function wxLogin(loginUuid: string): Promise<WxLoginResult> {
|
|||||||
return unwrapOrSelf<WxLoginResult>(res.data);
|
return unwrapOrSelf<WxLoginResult>(res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 微信网页授权登录(H5 点按钮,无需扫码) */
|
||||||
|
export async function wxOAuthLogin(code: string): Promise<WxLoginResult> {
|
||||||
|
const res = await axiosInstance.post('/rbac/auth/wx-oauth-login', { code });
|
||||||
|
return unwrapOrSelf<WxLoginResult>(res.data);
|
||||||
|
}
|
||||||
|
|
||||||
/** OAuth code 换取微信用户信息 */
|
/** OAuth code 换取微信用户信息 */
|
||||||
export async function getOAuthUserInfo(code: string): Promise<WeChatOAuthUserInfo> {
|
export async function getOAuthUserInfo(code: string): Promise<WeChatOAuthUserInfo> {
|
||||||
const res = await axiosInstance.post(omsUrl('/wechat/oauth/user-info'), { code });
|
const res = await axiosInstance.post(omsUrl('/wechat/oauth/user-info'), { code });
|
||||||
|
|||||||
@ -955,7 +955,7 @@
|
|||||||
|
|
||||||
.ai-msg-row--assistant .ai-msg-bubble {
|
.ai-msg-row--assistant .ai-msg-bubble {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: var(--kc-primary, #1b2a6b);
|
color: #1d2129;
|
||||||
border: 1px solid rgba(27, 42, 107, 0.08);
|
border: 1px solid rgba(27, 42, 107, 0.08);
|
||||||
box-shadow: 0 2px 8px rgba(27, 42, 107, 0.04);
|
box-shadow: 0 2px 8px rgba(27, 42, 107, 0.04);
|
||||||
border-bottom-left-radius: 6px;
|
border-bottom-left-radius: 6px;
|
||||||
@ -1055,7 +1055,7 @@
|
|||||||
padding: 11px 4px 11px 12px;
|
padding: 11px 4px 11px 12px;
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--kc-primary, #1b2a6b);
|
color: #1d2129;
|
||||||
/* ≥16px:避免 iOS/微信聚焦输入框时整页缩放 */
|
/* ≥16px:避免 iOS/微信聚焦输入框时整页缩放 */
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
@ -1069,7 +1069,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ai-composer-input::placeholder {
|
.ai-composer-input::placeholder {
|
||||||
color: rgba(106, 117, 184, 0.7);
|
color: #c9cdd4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-composer-send {
|
.ai-composer-send {
|
||||||
@ -1121,8 +1121,9 @@
|
|||||||
.ai-composer-hint {
|
.ai-composer-hint {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
color: var(--kc-secondary, #6a75b8);
|
color: #86909c;
|
||||||
opacity: 0.85;
|
opacity: 0.72;
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-composer-human {
|
.ai-composer-human {
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
stashInviteRef,
|
stashInviteRef,
|
||||||
} from '@/utils/inviteRefStorage';
|
} from '@/utils/inviteRefStorage';
|
||||||
|
|
||||||
export type WeChatH5Page = 'register' | 'bind';
|
export type WeChatH5Page = 'register' | 'bind' | 'login';
|
||||||
|
|
||||||
const DEFAULT_MP_APP_ID = 'wxd5141ba46c856e1f';
|
const DEFAULT_MP_APP_ID = 'wxd5141ba46c856e1f';
|
||||||
|
|
||||||
@ -59,14 +59,37 @@ export function resolveWeChatInviteRef(query: Record<string, unknown>): string {
|
|||||||
return readStashedInviteRef();
|
return readStashedInviteRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 跳转微信 OAuth;邀请码写入 state + 7 天暂存,回调后带回 */
|
function resolveOAuthRedirectPath(page: WeChatH5Page): string {
|
||||||
export function redirectToWeChatOAuth(page: WeChatH5Page, inviteCode?: string | null): void {
|
if (page === 'login') {
|
||||||
const appId = resolveWeChatMpAppId();
|
return `${window.location.origin}/h5/login`;
|
||||||
const code = String(inviteCode ?? '').trim() || readStashedInviteRef();
|
}
|
||||||
if (code) stashInviteRef(code);
|
return `${window.location.origin}/wechat/${page}`;
|
||||||
|
}
|
||||||
|
|
||||||
const redirectUri = encodeURIComponent(`${window.location.origin}/wechat/${page}`);
|
/**
|
||||||
const state = code ? `${page}:${encodeURIComponent(code)}` : page;
|
* 跳转微信 OAuth。
|
||||||
|
* - register/bind:邀请码写入 state + 7 天暂存
|
||||||
|
* - login:可选把登录后回跳路径写入 state(login:/h5/orders)
|
||||||
|
*/
|
||||||
|
export function redirectToWeChatOAuth(
|
||||||
|
page: WeChatH5Page,
|
||||||
|
inviteCode?: string | null,
|
||||||
|
options?: { afterLoginPath?: string | null },
|
||||||
|
): void {
|
||||||
|
const appId = resolveWeChatMpAppId();
|
||||||
|
const redirectUri = encodeURIComponent(resolveOAuthRedirectPath(page));
|
||||||
|
|
||||||
|
let state = page;
|
||||||
|
if (page === 'login') {
|
||||||
|
const after = String(options?.afterLoginPath ?? '').trim();
|
||||||
|
if (after.startsWith('/h5')) {
|
||||||
|
state = `login:${encodeURIComponent(after)}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const code = String(inviteCode ?? '').trim() || readStashedInviteRef();
|
||||||
|
if (code) stashInviteRef(code);
|
||||||
|
state = code ? `${page}:${encodeURIComponent(code)}` : page;
|
||||||
|
}
|
||||||
|
|
||||||
window.location.replace(
|
window.location.replace(
|
||||||
`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}` +
|
`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}` +
|
||||||
@ -74,3 +97,17 @@ export function redirectToWeChatOAuth(page: WeChatH5Page, inviteCode?: string |
|
|||||||
`&response_type=code&scope=snsapi_userinfo&state=${state}#wechat_redirect`,
|
`&response_type=code&scope=snsapi_userinfo&state=${state}#wechat_redirect`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 从 OAuth state 解析登录后回跳路径 */
|
||||||
|
export function parseAfterLoginPathFromOAuthState(state: unknown): string {
|
||||||
|
const raw = String(state ?? '').trim();
|
||||||
|
const match = raw.match(/^login:(.+)$/i);
|
||||||
|
if (!match?.[1]) return '';
|
||||||
|
try {
|
||||||
|
const path = decodeURIComponent(match[1]).trim();
|
||||||
|
return path.startsWith('/h5') ? path : '';
|
||||||
|
} catch {
|
||||||
|
const path = match[1].trim();
|
||||||
|
return path.startsWith('/h5') ? path : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -310,6 +310,16 @@ function clearPriceContext() {
|
|||||||
|
|
||||||
:deep(.ai-composer-hint) {
|
:deep(.ai-composer-hint) {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
color: #86909c;
|
||||||
|
opacity: 0.72;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ai-msg-row--assistant .ai-msg-bubble) {
|
||||||
|
color: #1d2129;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ai-composer-input) {
|
||||||
|
color: #1d2129;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ai-msg-bubble) {
|
:deep(.ai-msg-bubble) {
|
||||||
|
|||||||
@ -0,0 +1,86 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { IconWechat } from '@arco-design/web-vue/es/icon';
|
||||||
|
import { isWeChatBrowser } from '@/utils/device';
|
||||||
|
import { redirectToWeChatOAuth } from '@/utils/wechatOAuth';
|
||||||
|
|
||||||
|
defineOptions({ name: 'WechatOAuthLoginButton' });
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
afterLoginPath?: string;
|
||||||
|
long?: boolean;
|
||||||
|
size?: 'mini' | 'small' | 'medium' | 'large';
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
afterLoginPath: '/h5/orders',
|
||||||
|
long: true,
|
||||||
|
size: 'large',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const jumping = ref(false);
|
||||||
|
const inWeChat = computed(() => isWeChatBrowser());
|
||||||
|
|
||||||
|
function handleClick() {
|
||||||
|
if (jumping.value) return;
|
||||||
|
if (!inWeChat.value) return;
|
||||||
|
jumping.value = true;
|
||||||
|
redirectToWeChatOAuth('login', null, { afterLoginPath: props.afterLoginPath });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="wx-oauth-login">
|
||||||
|
<a-button
|
||||||
|
v-if="inWeChat"
|
||||||
|
type="primary"
|
||||||
|
class="wx-oauth-login__btn"
|
||||||
|
:long="long"
|
||||||
|
:size="size"
|
||||||
|
:loading="jumping"
|
||||||
|
@click="handleClick"
|
||||||
|
>
|
||||||
|
<template #icon><icon-wechat /></template>
|
||||||
|
{{ jumping ? t('h5.login.oauthRedirecting') : t('h5.login.oauthLogin') }}
|
||||||
|
</a-button>
|
||||||
|
<template v-else>
|
||||||
|
<p class="wx-oauth-login__tip">{{ t('h5.login.openInWechat') }}</p>
|
||||||
|
<a-button type="primary" class="wx-oauth-login__btn" :long="long" :size="size" disabled>
|
||||||
|
<template #icon><icon-wechat /></template>
|
||||||
|
{{ t('h5.login.oauthLogin') }}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.wx-oauth-login {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wx-oauth-login__btn {
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
background: #07c160 !important;
|
||||||
|
border-color: #07c160 !important;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
background: #06ad56 !important;
|
||||||
|
border-color: #06ad56 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wx-oauth-login__tip {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -144,12 +144,12 @@ export default {
|
|||||||
|
|
||||||
'h5.me.guestTitle': 'Welcome to Customer Center',
|
'h5.me.guestTitle': 'Welcome to Customer Center',
|
||||||
'h5.me.guestDesc':
|
'h5.me.guestDesc':
|
||||||
'Long-press the QR code in WeChat to sign in. New users can register or bind first.',
|
'Tap authorize in WeChat to sign in. New users can register or bind first.',
|
||||||
'h5.me.register': 'WeChat register',
|
'h5.me.register': 'WeChat register',
|
||||||
'h5.me.bind': 'Bind existing account',
|
'h5.me.bind': 'Bind existing account',
|
||||||
'h5.me.passwordLogin': 'Password login',
|
'h5.me.passwordLogin': 'Password login',
|
||||||
'h5.me.needLogin': 'Please register or sign in first',
|
'h5.me.needLogin': 'Please register or sign in first',
|
||||||
'h5.me.scanLogin': 'WeChat QR sign-in',
|
'h5.me.scanLogin': 'WeChat authorize sign-in',
|
||||||
|
|
||||||
'h5.wxQr.loading': 'Loading QR code…',
|
'h5.wxQr.loading': 'Loading QR code…',
|
||||||
'h5.wxQr.loadFailed': 'Failed to load QR code. Please refresh.',
|
'h5.wxQr.loadFailed': 'Failed to load QR code. Please refresh.',
|
||||||
@ -164,10 +164,15 @@ export default {
|
|||||||
|
|
||||||
'h5.login.title': 'Sign in',
|
'h5.login.title': 'Sign in',
|
||||||
'h5.login.brand': 'Customer Center',
|
'h5.login.brand': 'Customer Center',
|
||||||
'h5.login.tab.wechat': 'WeChat QR',
|
'h5.login.tab.wechat': 'WeChat',
|
||||||
'h5.login.tab.password': 'Account',
|
'h5.login.tab.password': 'Account',
|
||||||
'h5.login.switchPassword': 'Sign in with password',
|
'h5.login.switchPassword': 'Sign in with password',
|
||||||
'h5.login.switchWechat': 'WeChat QR sign-in',
|
'h5.login.switchWechat': 'WeChat authorize sign-in',
|
||||||
|
'h5.login.oauthLogin': 'Sign in with WeChat',
|
||||||
|
'h5.login.oauthRedirecting': 'Opening WeChat authorization…',
|
||||||
|
'h5.login.oauthLoggingIn': 'Authorized. Signing you in…',
|
||||||
|
'h5.login.oauthFailed': 'WeChat sign-in failed. Please retry.',
|
||||||
|
'h5.login.openInWechat': 'Open this page in WeChat, then tap the button below to authorize.',
|
||||||
'h5.login.accountPlaceholder': 'Phone / email / customer code',
|
'h5.login.accountPlaceholder': 'Phone / email / customer code',
|
||||||
'h5.login.passwordPlaceholder': 'Enter password',
|
'h5.login.passwordPlaceholder': 'Enter password',
|
||||||
'h5.login.accountRequired': 'Please enter account',
|
'h5.login.accountRequired': 'Please enter account',
|
||||||
@ -181,9 +186,9 @@ export default {
|
|||||||
'h5.login.submitting': 'Signing in...',
|
'h5.login.submitting': 'Signing in...',
|
||||||
'h5.login.success': 'Signed in',
|
'h5.login.success': 'Signed in',
|
||||||
'h5.login.failed': 'Sign-in failed. Check your account and password.',
|
'h5.login.failed': 'Sign-in failed. Check your account and password.',
|
||||||
'h5.login.newUserHint': 'New here? Register or bind an account first',
|
'h5.login.newUserHint': 'No account? Authorize in WeChat to register or bind',
|
||||||
'h5.login.goRegister': 'Register',
|
'h5.login.goRegister': 'Authorize & register',
|
||||||
'h5.login.goBind': 'Bind account',
|
'h5.login.goBind': 'Authorize & bind',
|
||||||
|
|
||||||
'h5.recharge.title': 'Recharge',
|
'h5.recharge.title': 'Recharge',
|
||||||
'h5.recharge.amount': 'Amount',
|
'h5.recharge.amount': 'Amount',
|
||||||
@ -537,7 +542,9 @@ export default {
|
|||||||
'h5.me.editProfile': 'Edit profile',
|
'h5.me.editProfile': 'Edit profile',
|
||||||
'h5.me.addressManage': 'Addresses',
|
'h5.me.addressManage': 'Addresses',
|
||||||
'h5.me.resetPassword': 'Change password',
|
'h5.me.resetPassword': 'Change password',
|
||||||
'h5.me.language': 'Language',
|
'h5.me.language': 'Switch language',
|
||||||
|
'h5.me.followOfficial': 'Follow official account',
|
||||||
|
'h5.me.followOfficialMissing': 'Official account link is not configured. Please contact support.',
|
||||||
'h5.me.logout': 'Sign out',
|
'h5.me.logout': 'Sign out',
|
||||||
'h5.me.logoutConfirm': 'Sign out now?',
|
'h5.me.logoutConfirm': 'Sign out now?',
|
||||||
'h5.me.customerCode': 'Code',
|
'h5.me.customerCode': 'Code',
|
||||||
|
|||||||
@ -143,12 +143,12 @@ export default {
|
|||||||
'h5.orders.detail.predeclareFailed': '预报失败',
|
'h5.orders.detail.predeclareFailed': '预报失败',
|
||||||
|
|
||||||
'h5.me.guestTitle': '欢迎使用客户中心',
|
'h5.me.guestTitle': '欢迎使用客户中心',
|
||||||
'h5.me.guestDesc': '微信内长按二维码识别即可登录;新用户可先注册或绑定',
|
'h5.me.guestDesc': '微信内点击授权即可登录;新用户请先注册或绑定',
|
||||||
'h5.me.register': '微信注册',
|
'h5.me.register': '微信注册',
|
||||||
'h5.me.bind': '绑定已有账号',
|
'h5.me.bind': '绑定已有账号',
|
||||||
'h5.me.passwordLogin': '账号密码登录',
|
'h5.me.passwordLogin': '账号密码登录',
|
||||||
'h5.me.needLogin': '请先注册或登录后使用',
|
'h5.me.needLogin': '请先注册或登录后使用',
|
||||||
'h5.me.scanLogin': '微信扫码登录',
|
'h5.me.scanLogin': '微信授权登录',
|
||||||
|
|
||||||
'h5.wxQr.loading': '二维码加载中…',
|
'h5.wxQr.loading': '二维码加载中…',
|
||||||
'h5.wxQr.loadFailed': '二维码加载失败,请刷新重试',
|
'h5.wxQr.loadFailed': '二维码加载失败,请刷新重试',
|
||||||
@ -163,10 +163,15 @@ export default {
|
|||||||
|
|
||||||
'h5.login.title': '登录',
|
'h5.login.title': '登录',
|
||||||
'h5.login.brand': '客户中心',
|
'h5.login.brand': '客户中心',
|
||||||
'h5.login.tab.wechat': '微信扫码',
|
'h5.login.tab.wechat': '微信登录',
|
||||||
'h5.login.tab.password': '账号登录',
|
'h5.login.tab.password': '账号登录',
|
||||||
'h5.login.switchPassword': '账号密码登录',
|
'h5.login.switchPassword': '账号密码登录',
|
||||||
'h5.login.switchWechat': '微信扫码登录',
|
'h5.login.switchWechat': '微信授权登录',
|
||||||
|
'h5.login.oauthLogin': '微信授权登录',
|
||||||
|
'h5.login.oauthRedirecting': '正在打开微信授权…',
|
||||||
|
'h5.login.oauthLoggingIn': '授权成功,正在登录…',
|
||||||
|
'h5.login.oauthFailed': '微信授权登录失败,请重试',
|
||||||
|
'h5.login.openInWechat': '请在微信内打开本页,点击下方按钮一键授权登录',
|
||||||
'h5.login.accountPlaceholder': '手机号 / 邮箱 / 客户编号',
|
'h5.login.accountPlaceholder': '手机号 / 邮箱 / 客户编号',
|
||||||
'h5.login.passwordPlaceholder': '请输入密码',
|
'h5.login.passwordPlaceholder': '请输入密码',
|
||||||
'h5.login.accountRequired': '请输入账号',
|
'h5.login.accountRequired': '请输入账号',
|
||||||
@ -180,9 +185,9 @@ export default {
|
|||||||
'h5.login.submitting': '登录中...',
|
'h5.login.submitting': '登录中...',
|
||||||
'h5.login.success': '登录成功',
|
'h5.login.success': '登录成功',
|
||||||
'h5.login.failed': '登录失败,请检查账号密码',
|
'h5.login.failed': '登录失败,请检查账号密码',
|
||||||
'h5.login.newUserHint': '还没有账号?新客户请先注册或绑定',
|
'h5.login.newUserHint': '还没有账号?微信内可一键授权注册或绑定',
|
||||||
'h5.login.goRegister': '注册新账号',
|
'h5.login.goRegister': '微信授权注册',
|
||||||
'h5.login.goBind': '绑定已有账号',
|
'h5.login.goBind': '微信授权绑定',
|
||||||
|
|
||||||
'h5.recharge.title': '账户充值',
|
'h5.recharge.title': '账户充值',
|
||||||
'h5.recharge.amount': '充值金额',
|
'h5.recharge.amount': '充值金额',
|
||||||
@ -535,7 +540,9 @@ export default {
|
|||||||
'h5.me.editProfile': '编辑资料',
|
'h5.me.editProfile': '编辑资料',
|
||||||
'h5.me.addressManage': '地址管理',
|
'h5.me.addressManage': '地址管理',
|
||||||
'h5.me.resetPassword': '修改密码',
|
'h5.me.resetPassword': '修改密码',
|
||||||
'h5.me.language': '语言',
|
'h5.me.language': '切换语言',
|
||||||
|
'h5.me.followOfficial': '关注公众号',
|
||||||
|
'h5.me.followOfficialMissing': '暂未配置公众号跳转链接,请联系客服',
|
||||||
'h5.me.logout': '退出登录',
|
'h5.me.logout': '退出登录',
|
||||||
'h5.me.logoutConfirm': '确定退出登录?',
|
'h5.me.logoutConfirm': '确定退出登录?',
|
||||||
'h5.me.customerCode': '编号',
|
'h5.me.customerCode': '编号',
|
||||||
|
|||||||
@ -44,11 +44,9 @@
|
|||||||
:class="{ 'is-active': activeTab === 'wechat' }"
|
:class="{ 'is-active': activeTab === 'wechat' }"
|
||||||
:aria-hidden="activeTab !== 'wechat'"
|
:aria-hidden="activeTab !== 'wechat'"
|
||||||
>
|
>
|
||||||
<WechatQrPanel
|
<WechatOAuthLoginButton :after-login-path="resolveRedirectPath()" />
|
||||||
compact
|
<p v-if="oauthLoading" class="h5-login-oauth-status">{{ t('h5.login.oauthLoggingIn') }}</p>
|
||||||
:active="activeTab === 'wechat'"
|
<p v-else-if="errorBox && activeTab === 'wechat'" class="h5-login-error">{{ errorBox }}</p>
|
||||||
@success="onWxLoginSuccess"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
@ -137,15 +135,20 @@ import { useRoute, useRouter } from 'vue-router';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { IconLeft, IconUserAdd, IconLink } from '@arco-design/web-vue/es/icon';
|
import { IconLeft, IconUserAdd, IconLink } from '@arco-design/web-vue/es/icon';
|
||||||
import { OmsLoginType, type LoginResultDto } from '@/api/rbac';
|
import { OmsLoginType } from '@/api/rbac';
|
||||||
import { isLogin, setToken } from '@/utils/auth';
|
import { isLogin, setToken } from '@/utils/auth';
|
||||||
import { applyRbacUserToUserStore } from '@/utils/enter-system';
|
import { applyRbacUserToUserStore } from '@/utils/enter-system';
|
||||||
import { ensureFullLocaleMessages } from '@/locale';
|
import { ensureFullLocaleMessages } from '@/locale';
|
||||||
import { h5Navigate } from '@/utils/device';
|
import { h5Navigate, isWeChatBrowser } from '@/utils/device';
|
||||||
import { useRbacUserStore } from '@/store/modules/rbac-user';
|
import { useRbacUserStore } from '@/store/modules/rbac-user';
|
||||||
import logoImg from '@/assets/logo2.png';
|
import logoImg from '@/assets/logo2.png';
|
||||||
import LoginLangToggle from '@/views/login/components/LoginLangToggle.vue';
|
import LoginLangToggle from '@/views/login/components/LoginLangToggle.vue';
|
||||||
import WechatQrPanel from '../components/WechatQrPanel.vue';
|
import WechatOAuthLoginButton from '../components/WechatOAuthLoginButton.vue';
|
||||||
|
import { wxOAuthLogin } from '@/api/wechat';
|
||||||
|
import {
|
||||||
|
parseAfterLoginPathFromOAuthState,
|
||||||
|
redirectToWeChatOAuth,
|
||||||
|
} from '@/utils/wechatOAuth';
|
||||||
|
|
||||||
defineOptions({ name: 'H5Login' });
|
defineOptions({ name: 'H5Login' });
|
||||||
|
|
||||||
@ -158,6 +161,7 @@ const activeTab = ref<'wechat' | 'password'>('wechat');
|
|||||||
const form = reactive({ account: '', password: '' });
|
const form = reactive({ account: '', password: '' });
|
||||||
const agreementChecked = ref(false);
|
const agreementChecked = ref(false);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const oauthLoading = ref(false);
|
||||||
const errorBox = ref('');
|
const errorBox = ref('');
|
||||||
const agreementVisible = ref(false);
|
const agreementVisible = ref(false);
|
||||||
const agreementTitle = ref('');
|
const agreementTitle = ref('');
|
||||||
@ -196,10 +200,18 @@ function goBack() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function goRegister() {
|
function goRegister() {
|
||||||
|
if (isWeChatBrowser()) {
|
||||||
|
redirectToWeChatOAuth('register');
|
||||||
|
return;
|
||||||
|
}
|
||||||
h5Navigate(router, '/wechat/register');
|
h5Navigate(router, '/wechat/register');
|
||||||
}
|
}
|
||||||
|
|
||||||
function goBind() {
|
function goBind() {
|
||||||
|
if (isWeChatBrowser()) {
|
||||||
|
redirectToWeChatOAuth('bind');
|
||||||
|
return;
|
||||||
|
}
|
||||||
h5Navigate(router, '/wechat/bind');
|
h5Navigate(router, '/wechat/bind');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,6 +227,8 @@ function openAgreement(type: 'privacy' | 'terms') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveRedirectPath() {
|
function resolveRedirectPath() {
|
||||||
|
const fromState = parseAfterLoginPathFromOAuthState(route.query.state);
|
||||||
|
if (fromState) return fromState;
|
||||||
const redirect = route.query.redirect;
|
const redirect = route.query.redirect;
|
||||||
if (typeof redirect === 'string' && redirect.startsWith('/h5')) {
|
if (typeof redirect === 'string' && redirect.startsWith('/h5')) {
|
||||||
return redirect;
|
return redirect;
|
||||||
@ -222,6 +236,11 @@ function resolveRedirectPath() {
|
|||||||
return '/h5/orders';
|
return '/h5/orders';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stripOAuthQuery() {
|
||||||
|
const { code: _c, state: _s, ...rest } = route.query;
|
||||||
|
return rest;
|
||||||
|
}
|
||||||
|
|
||||||
async function finishLogin() {
|
async function finishLogin() {
|
||||||
if (!rbacUserStore.userInfo) return;
|
if (!rbacUserStore.userInfo) return;
|
||||||
if (rbacUserStore.token) {
|
if (rbacUserStore.token) {
|
||||||
@ -232,21 +251,35 @@ async function finishLogin() {
|
|||||||
await nextTick();
|
await nextTick();
|
||||||
const target = resolveRedirectPath();
|
const target = resolveRedirectPath();
|
||||||
try {
|
try {
|
||||||
await router.replace(target);
|
await router.replace({ path: target, query: {} });
|
||||||
} catch (navErr) {
|
} catch (navErr) {
|
||||||
console.error('H5 登录跳转失败', navErr);
|
console.error('H5 登录跳转失败', navErr);
|
||||||
await router.replace('/h5/orders').catch(() => undefined);
|
await router.replace('/h5/orders').catch(() => undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onWxLoginSuccess(result: LoginResultDto) {
|
async function consumeOAuthCode(code: string) {
|
||||||
const ok = await rbacUserStore.loginByWxResult(result);
|
if (oauthLoading.value) return;
|
||||||
if (!ok) {
|
oauthLoading.value = true;
|
||||||
Message.error(t('h5.login.failed'));
|
activeTab.value = 'wechat';
|
||||||
return;
|
try {
|
||||||
|
const result = await wxOAuthLogin(code);
|
||||||
|
const ok = await rbacUserStore.loginByWxResult(result);
|
||||||
|
if (!ok) {
|
||||||
|
Message.error(t('h5.login.failed'));
|
||||||
|
await router.replace({ path: route.path, query: stripOAuthQuery() });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Message.success(t('h5.login.success'));
|
||||||
|
await finishLogin();
|
||||||
|
} catch (e: any) {
|
||||||
|
const msg = e?.message || t('h5.login.oauthFailed');
|
||||||
|
Message.error(msg);
|
||||||
|
errorBox.value = msg;
|
||||||
|
await router.replace({ path: route.path, query: stripOAuthQuery() });
|
||||||
|
} finally {
|
||||||
|
oauthLoading.value = false;
|
||||||
}
|
}
|
||||||
Message.success(t('h5.wxQr.success'));
|
|
||||||
await finishLogin();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
@ -292,7 +325,6 @@ async function handleSubmit() {
|
|||||||
watch(
|
watch(
|
||||||
() => route.query.tab,
|
() => route.query.tab,
|
||||||
(tab) => {
|
(tab) => {
|
||||||
// 仅显式 ?tab=password 时进账号登录,其余一律默认微信扫码
|
|
||||||
if (tab === 'password') {
|
if (tab === 'password') {
|
||||||
activeTab.value = 'password';
|
activeTab.value = 'password';
|
||||||
errorBox.value = '';
|
errorBox.value = '';
|
||||||
@ -304,9 +336,21 @@ watch(
|
|||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
if (isLogin()) {
|
if (isLogin()) {
|
||||||
router.replace(resolveRedirectPath());
|
router.replace(resolveRedirectPath());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = typeof route.query.code === 'string' ? route.query.code.trim() : '';
|
||||||
|
if (code) {
|
||||||
|
await consumeOAuthCode(code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 微信内且未带 code:可一键拉起授权(用户点按钮亦可)
|
||||||
|
if (isWeChatBrowser() && route.query.auto === '1') {
|
||||||
|
redirectToWeChatOAuth('login', null, { afterLoginPath: resolveRedirectPath() });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -531,6 +575,13 @@ onMounted(() => {
|
|||||||
animation: h5-login-rise 0.28s var(--login-ease) both;
|
animation: h5-login-rise 0.28s var(--login-ease) both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h5-login-oauth-status {
|
||||||
|
margin: 12px 0 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
|
||||||
.h5-login-agree {
|
.h5-login-agree {
|
||||||
margin: 4px 0 0;
|
margin: 4px 0 0;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h5-me-page" :class="{ 'h5-me-page--guest': !loggedIn }">
|
<div class="h5-me-page" :class="{ 'h5-me-page--guest': !loggedIn }">
|
||||||
<!-- 访客:与 /h5/login 同款扫码入口,避免返回看到旧版多按钮登录 -->
|
<!-- 访客:微信授权登录(无二维码);新用户走注册/绑定 -->
|
||||||
<template v-if="!loggedIn">
|
<template v-if="!loggedIn">
|
||||||
<section class="h5-me-guest h5-enter">
|
<section class="h5-me-guest h5-enter">
|
||||||
<div class="h5-me-guest__brand">
|
<div class="h5-me-guest__brand">
|
||||||
@ -28,7 +28,7 @@
|
|||||||
{{ t('h5.login.tab.password') }}
|
{{ t('h5.login.tab.password') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<WechatQrPanel compact :active="true" @success="onWxLoginSuccess" />
|
<WechatOAuthLoginButton :after-login-path="resolvePostLoginPath()" />
|
||||||
<p v-if="route.query.redirect" class="h5-me-tip">{{ t('h5.me.needLogin') }}</p>
|
<p v-if="route.query.redirect" class="h5-me-tip">{{ t('h5.me.needLogin') }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -184,6 +184,18 @@
|
|||||||
<icon-right />
|
<icon-right />
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="h5-me-list__item"
|
||||||
|
:disabled="followJumping"
|
||||||
|
@click="openOfficialAccount"
|
||||||
|
>
|
||||||
|
<span class="h5-me-list__left">
|
||||||
|
<icon-wechat class="h5-me-list__icon" />
|
||||||
|
{{ t('h5.me.followOfficial') }}
|
||||||
|
</span>
|
||||||
|
<icon-right />
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="h5-me-list__item h5-me-list__item--danger"
|
class="h5-me-list__item h5-me-list__item--danger"
|
||||||
@ -228,18 +240,18 @@ import {
|
|||||||
IconUserAdd,
|
IconUserAdd,
|
||||||
IconLink,
|
IconLink,
|
||||||
IconLanguage,
|
IconLanguage,
|
||||||
|
IconWechat,
|
||||||
} from '@arco-design/web-vue/es/icon';
|
} from '@arco-design/web-vue/es/icon';
|
||||||
import type { CustomerDto } from '@/api/customer';
|
import type { CustomerDto } from '@/api/customer';
|
||||||
import { resolveCurrentCustomer } from '@/api/customer/resolve';
|
import { resolveCurrentCustomer } from '@/api/customer/resolve';
|
||||||
import { postOrderList } from '@/api/order';
|
import { postOrderList } from '@/api/order';
|
||||||
import { getMyCoupons, getMemberOverview } from '@/api/marketing/portal';
|
import { getMyCoupons, getMemberOverview } from '@/api/marketing/portal';
|
||||||
import { type LoginResultDto } from '@/api/rbac';
|
import { isLogin } from '@/utils/auth';
|
||||||
import { isLogin, setToken } from '@/utils/auth';
|
|
||||||
import { resolveAvatarUrl } from '@/utils/avatar';
|
import { resolveAvatarUrl } from '@/utils/avatar';
|
||||||
import { getMapIdFromAccessToken } from '@/utils/jwt';
|
import { getMapIdFromAccessToken } from '@/utils/jwt';
|
||||||
import { applyRbacUserToUserStore } from '@/utils/enter-system';
|
import { h5Navigate, isWeChatBrowser } from '@/utils/device';
|
||||||
import { ensureFullLocaleMessages } from '@/locale';
|
import { redirectToWeChatOAuth } from '@/utils/wechatOAuth';
|
||||||
import { h5Navigate } from '@/utils/device';
|
import { jumpToWechatOfficialAccount } from '@/utils/wechatFollowJump';
|
||||||
import { useUserStore } from '@/store';
|
import { useUserStore } from '@/store';
|
||||||
import { useRbacUserStore } from '@/store/modules/rbac-user';
|
import { useRbacUserStore } from '@/store/modules/rbac-user';
|
||||||
import useLocale from '@/hooks/locale';
|
import useLocale from '@/hooks/locale';
|
||||||
@ -248,7 +260,7 @@ import iconServiceCoupon from '@/assets/icons/h5/service-coupon.svg?url';
|
|||||||
import iconServiceInvite from '@/assets/icons/h5/service-invite.svg?url';
|
import iconServiceInvite from '@/assets/icons/h5/service-invite.svg?url';
|
||||||
import iconServiceCommission from '@/assets/icons/h5/service-commission.svg?url';
|
import iconServiceCommission from '@/assets/icons/h5/service-commission.svg?url';
|
||||||
import iconOrderPickup from '@/assets/icons/h5/order-pickup.svg?url';
|
import iconOrderPickup from '@/assets/icons/h5/order-pickup.svg?url';
|
||||||
import WechatQrPanel from '../components/WechatQrPanel.vue';
|
import WechatOAuthLoginButton from '../components/WechatOAuthLoginButton.vue';
|
||||||
import H5JourneyGuide from '../components/H5JourneyGuide.vue';
|
import H5JourneyGuide from '../components/H5JourneyGuide.vue';
|
||||||
import H5CreateOrderFlow from '../components/H5CreateOrderFlow.vue';
|
import H5CreateOrderFlow from '../components/H5CreateOrderFlow.vue';
|
||||||
import H5RechargeSheet from '../components/H5RechargeSheet.vue';
|
import H5RechargeSheet from '../components/H5RechargeSheet.vue';
|
||||||
@ -284,6 +296,7 @@ const commissionVisible = ref(false);
|
|||||||
const editVisible = ref(false);
|
const editVisible = ref(false);
|
||||||
const pwdVisible = ref(false);
|
const pwdVisible = ref(false);
|
||||||
const addressVisible = ref(false);
|
const addressVisible = ref(false);
|
||||||
|
const followJumping = ref(false);
|
||||||
const pickupVisible = ref(false);
|
const pickupVisible = ref(false);
|
||||||
const pickupCount = ref(0);
|
const pickupCount = ref(0);
|
||||||
const memberOverview = ref<Record<string, unknown> | null>(null);
|
const memberOverview = ref<Record<string, unknown> | null>(null);
|
||||||
@ -434,38 +447,19 @@ function resolvePostLoginPath() {
|
|||||||
return '/h5/orders';
|
return '/h5/orders';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onWxLoginSuccess(result: LoginResultDto) {
|
function goWechatRegister() {
|
||||||
const ok = await rbacUserStore.loginByWxResult(result);
|
if (isWeChatBrowser()) {
|
||||||
if (!ok || !rbacUserStore.userInfo) {
|
redirectToWeChatOAuth('register');
|
||||||
Message.error(t('h5.login.failed'));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (rbacUserStore.token) {
|
|
||||||
setToken(rbacUserStore.token);
|
|
||||||
}
|
|
||||||
applyRbacUserToUserStore(rbacUserStore.userInfo);
|
|
||||||
await ensureFullLocaleMessages();
|
|
||||||
Message.success(t('h5.wxQr.success'));
|
|
||||||
|
|
||||||
const target = resolvePostLoginPath();
|
|
||||||
try {
|
|
||||||
await router.replace(target);
|
|
||||||
} catch (navErr) {
|
|
||||||
// 导航被中断时仍切到已登录态,避免卡在扫码页
|
|
||||||
console.error('H5 扫码登录跳转失败', navErr);
|
|
||||||
}
|
|
||||||
|
|
||||||
loggedIn.value = true;
|
|
||||||
if (route.path.startsWith('/h5/me')) {
|
|
||||||
await loadProfile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function goWechatRegister() {
|
|
||||||
h5Navigate(router, '/wechat/register');
|
h5Navigate(router, '/wechat/register');
|
||||||
}
|
}
|
||||||
|
|
||||||
function goWechatBind() {
|
function goWechatBind() {
|
||||||
|
if (isWeChatBrowser()) {
|
||||||
|
redirectToWeChatOAuth('bind');
|
||||||
|
return;
|
||||||
|
}
|
||||||
h5Navigate(router, '/wechat/bind');
|
h5Navigate(router, '/wechat/bind');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,6 +488,19 @@ function toggleLocale() {
|
|||||||
void changeLocale(next, { silent: true });
|
void changeLocale(next, { silent: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function openOfficialAccount() {
|
||||||
|
if (followJumping.value) return;
|
||||||
|
followJumping.value = true;
|
||||||
|
try {
|
||||||
|
const ok = await jumpToWechatOfficialAccount();
|
||||||
|
if (!ok) {
|
||||||
|
Message.warning(t('h5.me.followOfficialMissing'));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
followJumping.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleLogout() {
|
function handleLogout() {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: t('h5.me.logout'),
|
title: t('h5.me.logout'),
|
||||||
|
|||||||
@ -180,7 +180,7 @@ import { handleApiError } from '@/utils/rbac-error-handler';
|
|||||||
import { redirectToWeChatOAuth } from '@/utils/wechatOAuth';
|
import { redirectToWeChatOAuth } from '@/utils/wechatOAuth';
|
||||||
import { loginCustomerAfterWechatAuth } from '@/utils/wechatAuthLogin';
|
import { loginCustomerAfterWechatAuth } from '@/utils/wechatAuthLogin';
|
||||||
import { isTimeoutError, withTimeout } from '@/utils/withTimeout';
|
import { isTimeoutError, withTimeout } from '@/utils/withTimeout';
|
||||||
import { hideWeChatBrowserNav } from '@/utils/device';
|
import { hideWeChatBrowserNav, isWeChatBrowser } from '@/utils/device';
|
||||||
import { jumpToWechatOfficialAccount } from '@/utils/wechatFollowJump';
|
import { jumpToWechatOfficialAccount } from '@/utils/wechatFollowJump';
|
||||||
import LoginLangToggle from '@/views/login/components/LoginLangToggle.vue';
|
import LoginLangToggle from '@/views/login/components/LoginLangToggle.vue';
|
||||||
|
|
||||||
@ -200,6 +200,10 @@ function goCustomerCenter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function goLogin() {
|
function goLogin() {
|
||||||
|
if (isWeChatBrowser()) {
|
||||||
|
redirectToWeChatOAuth('login', null, { afterLoginPath: '/h5/me' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
router.replace('/h5/login');
|
router.replace('/h5/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,6 +229,10 @@ async function openOfficialAccount() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function goRegister() {
|
function goRegister() {
|
||||||
|
if (isWeChatBrowser()) {
|
||||||
|
redirectToWeChatOAuth('register');
|
||||||
|
return;
|
||||||
|
}
|
||||||
router.replace('/wechat/register');
|
router.replace('/wechat/register');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,8 +362,12 @@ onMounted(() => {
|
|||||||
loadingHint.value = t('wechat.common.loading');
|
loadingHint.value = t('wechat.common.loading');
|
||||||
const code = route.query.code;
|
const code = route.query.code;
|
||||||
if (typeof code !== 'string' || !code) {
|
if (typeof code !== 'string' || !code) {
|
||||||
|
if (!isWeChatBrowser()) {
|
||||||
|
statusCode.value = 'need-auth';
|
||||||
|
return;
|
||||||
|
}
|
||||||
statusCode.value = 'need-auth';
|
statusCode.value = 'need-auth';
|
||||||
authModalVisible.value = true;
|
startOAuth();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void loadOAuthUserInfo(code);
|
void loadOAuthUserInfo(code);
|
||||||
|
|||||||
@ -10,10 +10,10 @@ export default {
|
|||||||
'注册需获取微信昵称与头像,用于创建客户账号。请点击「立即授权」完成微信授权后继续填写资料。',
|
'注册需获取微信昵称与头像,用于创建客户账号。请点击「立即授权」完成微信授权后继续填写资料。',
|
||||||
'wechat.common.authOk': '立即授权',
|
'wechat.common.authOk': '立即授权',
|
||||||
'wechat.common.authLater': '稍后再说',
|
'wechat.common.authLater': '稍后再说',
|
||||||
'wechat.common.authGateTitle': '开始微信注册',
|
'wechat.common.authGateTitle': '微信授权注册',
|
||||||
'wechat.common.authGateTip': '授权后即可填写资料并完成注册',
|
'wechat.common.authGateTip': '正在打开微信授权,授权后即可填写资料完成注册',
|
||||||
'wechat.common.authBindGateTitle': '开始绑定微信',
|
'wechat.common.authBindGateTitle': '微信授权绑定',
|
||||||
'wechat.common.authBindGateTip': '授权后即可验证系统账号并绑定',
|
'wechat.common.authBindGateTip': '正在打开微信授权,授权后即可验证账号并绑定',
|
||||||
|
|
||||||
'wechat.follow.title': '请关注公众号',
|
'wechat.follow.title': '请关注公众号',
|
||||||
'wechat.follow.redirecting': '正在打开公众号,关注后可随时从菜单进入客户中心',
|
'wechat.follow.redirecting': '正在打开公众号,关注后可随时从菜单进入客户中心',
|
||||||
@ -25,11 +25,11 @@ export default {
|
|||||||
'wechat.register.title': '确认注册',
|
'wechat.register.title': '确认注册',
|
||||||
'wechat.register.subtitle': '已带入微信昵称与初始密码,确认后即可完成',
|
'wechat.register.subtitle': '已带入微信昵称与初始密码,确认后即可完成',
|
||||||
'wechat.register.success': '注册成功',
|
'wechat.register.success': '注册成功',
|
||||||
'wechat.register.successDesc': '账号已创建并绑定当前微信;登录可用客户编号或微信扫码',
|
'wechat.register.successDesc': '账号已创建并绑定当前微信;登录可用客户编号或微信授权',
|
||||||
'wechat.register.submit': '确认注册',
|
'wechat.register.submit': '确认注册',
|
||||||
'wechat.register.submitting': '提交中…',
|
'wechat.register.submitting': '提交中…',
|
||||||
'wechat.register.alreadyBound': '该微信已绑定账号,请直接登录',
|
'wechat.register.alreadyBound': '该微信已绑定账号,请直接登录',
|
||||||
'wechat.register.alreadyBoundTip': '请使用微信扫码或账号密码登录',
|
'wechat.register.alreadyBoundTip': '请使用微信授权或账号密码登录',
|
||||||
'wechat.register.alreadyBoundInviteTip':
|
'wechat.register.alreadyBoundInviteTip':
|
||||||
'您已是老用户,邀请礼仅限新注册客户;本次不会改绑引荐关系,请直接登录',
|
'您已是老用户,邀请礼仅限新注册客户;本次不会改绑引荐关系,请直接登录',
|
||||||
'wechat.register.oauthError': '微信授权失败,请重试',
|
'wechat.register.oauthError': '微信授权失败,请重试',
|
||||||
@ -47,7 +47,7 @@ export default {
|
|||||||
'wechat.register.passwordLetterAndDigit': '密码须同时包含字母和数字',
|
'wechat.register.passwordLetterAndDigit': '密码须同时包含字母和数字',
|
||||||
'wechat.register.passwordTipPrefix': '初始密码 ',
|
'wechat.register.passwordTipPrefix': '初始密码 ',
|
||||||
'wechat.register.passwordTipSuffix': ',可直接用,也可改成自己的',
|
'wechat.register.passwordTipSuffix': ',可直接用,也可改成自己的',
|
||||||
'wechat.register.hint': '注册后可用微信扫码或客户编号+密码登录',
|
'wechat.register.hint': '注册后可用微信授权或客户编号+密码登录',
|
||||||
'wechat.register.goCenter': '进入客户中心',
|
'wechat.register.goCenter': '进入客户中心',
|
||||||
'wechat.register.goLogin': '去登录',
|
'wechat.register.goLogin': '去登录',
|
||||||
'wechat.register.hasAccount': '已有系统账号?',
|
'wechat.register.hasAccount': '已有系统账号?',
|
||||||
@ -63,7 +63,7 @@ export default {
|
|||||||
'wechat.register.copyInviteFailed': '复制失败,请手动复制地址栏链接',
|
'wechat.register.copyInviteFailed': '复制失败,请手动复制地址栏链接',
|
||||||
|
|
||||||
'wechat.bind.title': '绑定已有账号',
|
'wechat.bind.title': '绑定已有账号',
|
||||||
'wechat.bind.subtitle': '验证账号后,即可用当前微信扫码登录',
|
'wechat.bind.subtitle': '验证账号后,即可用当前微信授权登录',
|
||||||
'wechat.bind.success': '绑定成功',
|
'wechat.bind.success': '绑定成功',
|
||||||
'wechat.bind.successDesc': '当前微信已关联系统账号,可直接进入客户中心',
|
'wechat.bind.successDesc': '当前微信已关联系统账号,可直接进入客户中心',
|
||||||
'wechat.bind.submit': '验证并绑定',
|
'wechat.bind.submit': '验证并绑定',
|
||||||
@ -74,7 +74,7 @@ export default {
|
|||||||
'wechat.bind.password': '登录密码',
|
'wechat.bind.password': '登录密码',
|
||||||
'wechat.bind.accountPlaceholder': '手机号 / 邮箱 / 客户编号',
|
'wechat.bind.accountPlaceholder': '手机号 / 邮箱 / 客户编号',
|
||||||
'wechat.bind.passwordPlaceholder': '请输入密码',
|
'wechat.bind.passwordPlaceholder': '请输入密码',
|
||||||
'wechat.bind.hint': '绑定后可用微信扫码登录。解绑或重置密码请联系客服。',
|
'wechat.bind.hint': '绑定后可用微信授权登录。解绑或重置密码请联系客服。',
|
||||||
'wechat.bind.goCenter': '进入客户中心',
|
'wechat.bind.goCenter': '进入客户中心',
|
||||||
'wechat.bind.goLogin': '去登录',
|
'wechat.bind.goLogin': '去登录',
|
||||||
'wechat.bind.noAccount': '还没有账号?',
|
'wechat.bind.noAccount': '还没有账号?',
|
||||||
|
|||||||
@ -75,7 +75,7 @@
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<div class="wechat-h5-state-actions">
|
<div class="wechat-h5-state-actions">
|
||||||
<a-button type="primary" long @click="goLogin">{{ t('wechat.register.goLogin') }}</a-button>
|
<a-button type="primary" long @click="goOAuthLogin">{{ t('wechat.register.goLogin') }}</a-button>
|
||||||
<a-button long @click="goCustomerCenter">{{ t('wechat.register.goCenter') }}</a-button>
|
<a-button long @click="goCustomerCenter">{{ t('wechat.register.goCenter') }}</a-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -270,9 +270,17 @@ function goCustomerCenter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function goLogin() {
|
function goLogin() {
|
||||||
|
if (isWeChatBrowser()) {
|
||||||
|
redirectToWeChatOAuth('login', null, { afterLoginPath: '/h5/me' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
router.replace('/h5/login');
|
router.replace('/h5/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goOAuthLogin() {
|
||||||
|
goLogin();
|
||||||
|
}
|
||||||
|
|
||||||
function finishAfterFollow() {
|
function finishAfterFollow() {
|
||||||
if (loggedInAfterRegister.value) {
|
if (loggedInAfterRegister.value) {
|
||||||
goCustomerCenter();
|
goCustomerCenter();
|
||||||
@ -295,6 +303,10 @@ async function openOfficialAccount() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function goBind() {
|
function goBind() {
|
||||||
|
if (isWeChatBrowser()) {
|
||||||
|
redirectToWeChatOAuth('bind');
|
||||||
|
return;
|
||||||
|
}
|
||||||
router.replace('/wechat/bind');
|
router.replace('/wechat/bind');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,9 +511,9 @@ onMounted(() => {
|
|||||||
statusCode.value = 'open-in-wechat';
|
statusCode.value = 'open-in-wechat';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 进入注册页主动弹窗,由用户确认后再跳转 OAuth,避免微信底部「完整服务」被动提示
|
// 微信内直接拉起授权,无需扫码 / 二次弹窗
|
||||||
statusCode.value = 'need-auth';
|
statusCode.value = 'need-auth';
|
||||||
authModalVisible.value = true;
|
startOAuth();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void loadOAuthUserInfo(code);
|
void loadOAuthUserInfo(code);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user