194 lines
5.0 KiB
Vue
194 lines
5.0 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="loading-page">
|
|||
|
|
<view class="loading-spinner"></view>
|
|||
|
|
<text class="loading-text">{{ statusText }}</text>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import config from '@/config/env.js';
|
|||
|
|
import { gatewayGet, gatewayPost } from '@/utils/request.js';
|
|||
|
|
import { detectPlatform, getAppNo } from '@/utils/env.js';
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
statusText: '正在登录...',
|
|||
|
|
deviceId: '',
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
onLoad(options) {
|
|||
|
|
this.deviceId = options.device_id || '';
|
|||
|
|
|
|||
|
|
// #ifdef H5
|
|||
|
|
// 检查 URL 中是否有授权回调的 code
|
|||
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|||
|
|
const code = urlParams.get('code');
|
|||
|
|
|
|||
|
|
if (code) {
|
|||
|
|
// 有 code → 调用后端登录
|
|||
|
|
this.handleCallback(code);
|
|||
|
|
} else {
|
|||
|
|
// 无 code → 发起 OAuth 授权
|
|||
|
|
this.startAuth();
|
|||
|
|
}
|
|||
|
|
// #endif
|
|||
|
|
|
|||
|
|
// #ifndef H5
|
|||
|
|
// 小程序环境暂不支持,跳回扫码页
|
|||
|
|
uni.redirectTo({ url: '/pages/index/scan' });
|
|||
|
|
// #endif
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
/**
|
|||
|
|
* 发起 OAuth 授权
|
|||
|
|
*/
|
|||
|
|
async startAuth() {
|
|||
|
|
const platform = detectPlatform();
|
|||
|
|
const appNo = getAppNo(platform);
|
|||
|
|
|
|||
|
|
if (!appNo) {
|
|||
|
|
// 非微信环境,跳转注册页(手机号注册)
|
|||
|
|
this.goToRegister();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
this.statusText = '正在获取授权...';
|
|||
|
|
|
|||
|
|
// 构建回调地址(当前页面地址)
|
|||
|
|
const redirectUri = encodeURIComponent(
|
|||
|
|
window.location.origin + window.location.pathname
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
const res = await gatewayGet('/api/v1/user/auth/url', {
|
|||
|
|
app_no: appNo,
|
|||
|
|
scopes: 'snsapi_userinfo',
|
|||
|
|
redirect_uri: redirectUri,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const data = res.data || {};
|
|||
|
|
if (data.code === 0 && data.data && data.data.auth_url) {
|
|||
|
|
// 跳转微信授权页
|
|||
|
|
window.location.href = data.data.auth_url;
|
|||
|
|
} else {
|
|||
|
|
uni.showToast({ title: data.message || '获取授权失败', icon: 'none' });
|
|||
|
|
setTimeout(() => this.goToScan(), 1500);
|
|||
|
|
}
|
|||
|
|
} catch (e) {
|
|||
|
|
console.error('[Auth] startAuth error:', e);
|
|||
|
|
uni.showToast({ title: '网络请求失败', icon: 'none' });
|
|||
|
|
setTimeout(() => this.goToScan(), 1500);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理授权回调(从 URL 中获取 code 后调用后端 /login)
|
|||
|
|
*/
|
|||
|
|
async handleCallback(code) {
|
|||
|
|
const appNo = uni.getStorageSync('app_no') || getAppNo(detectPlatform());
|
|||
|
|
|
|||
|
|
if (!appNo) {
|
|||
|
|
uni.showToast({ title: '无法获取应用信息', icon: 'none' });
|
|||
|
|
this.goToScan();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
this.statusText = '正在验证身份...';
|
|||
|
|
|
|||
|
|
const res = await gatewayPost('/api/v1/user/login', {
|
|||
|
|
app_no: appNo,
|
|||
|
|
code: code,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const data = res.data || {};
|
|||
|
|
if (data.code === 0 && data.data) {
|
|||
|
|
const result = data.data;
|
|||
|
|
|
|||
|
|
// 清除 URL 中的 code 参数,避免刷新重复处理
|
|||
|
|
const url = new URL(window.location.href);
|
|||
|
|
url.searchParams.delete('code');
|
|||
|
|
url.searchParams.delete('state');
|
|||
|
|
window.history.replaceState({}, '', url.toString());
|
|||
|
|
|
|||
|
|
if (result.register) {
|
|||
|
|
// 已注册 → 缓存 JWT → 跳转首页
|
|||
|
|
uni.setStorageSync('token', result.token);
|
|||
|
|
uni.setStorageSync('user_info', result.user_info);
|
|||
|
|
this.goToHome();
|
|||
|
|
} else {
|
|||
|
|
// 未注册 → 缓存临时数据 → 跳转注册页
|
|||
|
|
uni.setStorageSync('temp_token', result.temp_token);
|
|||
|
|
uni.setStorageSync('auth_info', result.auth_info);
|
|||
|
|
this.goToRegister();
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
uni.showToast({ title: data.message || '登录失败', icon: 'none' });
|
|||
|
|
setTimeout(() => this.goToScan(), 1500);
|
|||
|
|
}
|
|||
|
|
} catch (e) {
|
|||
|
|
console.error('[Auth] login error:', e);
|
|||
|
|
uni.showToast({ title: '网络请求失败', icon: 'none' });
|
|||
|
|
setTimeout(() => this.goToScan(), 1500);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
goToHome() {
|
|||
|
|
const url = this.deviceId
|
|||
|
|
? `/pages/index/index?device_id=${this.deviceId}`
|
|||
|
|
: '/pages/index/index';
|
|||
|
|
uni.redirectTo({ url });
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
goToRegister() {
|
|||
|
|
const url = this.deviceId
|
|||
|
|
? `/pages/register/register?device_id=${this.deviceId}`
|
|||
|
|
: '/pages/register/register';
|
|||
|
|
uni.redirectTo({ url });
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
goToScan() {
|
|||
|
|
uni.redirectTo({ url: '/pages/index/scan' });
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
page {
|
|||
|
|
height: 100%;
|
|||
|
|
background-color: #fff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-page {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
height: 100vh;
|
|||
|
|
background-color: #fff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-spinner {
|
|||
|
|
width: 64rpx;
|
|||
|
|
height: 64rpx;
|
|||
|
|
border: 6rpx solid #e5e5e5;
|
|||
|
|
border-top-color: #2979ff;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
animation: spin 0.8s linear infinite;
|
|||
|
|
margin-bottom: 32rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@keyframes spin {
|
|||
|
|
to {
|
|||
|
|
transform: rotate(360deg);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.loading-text {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #999;
|
|||
|
|
}
|
|||
|
|
</style>
|