From 0fc854cd33a568d2a69c8b5a3c8da27e38c28f5f Mon Sep 17 00:00:00 2001 From: kk <875203880@qq.com> Date: Fri, 10 Jul 2026 18:34:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=94=A8=E6=88=B7=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E9=80=BB=E8=BE=91=E5=85=88=E9=9D=99=E9=BB=98=E6=8E=88?= =?UTF-8?q?=E6=9D=83=EF=BC=8C=E7=82=B9=E5=87=BB=E6=88=91=E7=9A=84=E6=97=B6?= =?UTF-8?q?=E6=89=8D=E9=9D=9E=E9=9D=99=E9=BB=98=E6=8E=88=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/dev.js | 2 +- src/pages/auth/loading.vue | 110 ++++++++++++++++---------------- src/pages/index/index.vue | 91 ++++++++++++++++++++------ src/pages/register/register.vue | 53 ++++++++------- 4 files changed, 159 insertions(+), 97 deletions(-) diff --git a/src/config/dev.js b/src/config/dev.js index a508572..14ff15b 100644 --- a/src/config/dev.js +++ b/src/config/dev.js @@ -29,7 +29,7 @@ const dev = { user_info: { user_id: 'mock_user_001', phone: '13264706088', - open_id: 'test_open_id', + open_id: 'mock_openid_002', union_id: 'test_union_id', nickname: '测试用户', avatar: 'https://img.wewemivending.com/vms/us/img/uploads/2025/12/18/6943d37c7d82b3439.jpeg', diff --git a/src/pages/auth/loading.vue b/src/pages/auth/loading.vue index a11cd91..7faf22d 100644 --- a/src/pages/auth/loading.vue +++ b/src/pages/auth/loading.vue @@ -51,7 +51,7 @@ export default { }, methods: { /** - * 发起 OAuth 授权 + * 发起 OAuth 授权(静默授权,只获取 openid) */ async startAuth() { const platform = detectPlatform(); @@ -71,15 +71,16 @@ export default { window.location.origin.replace(/^http:/, 'https:') + window.location.pathname ); + // 使用 snsapi_base 静默授权,不弹窗 const res = await gatewayGet('/api/v1/user/auth/url', { app_no: appNo, - scopes: 'snsapi_userinfo', + scopes: 'snsapi_base', 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' }); @@ -93,7 +94,7 @@ export default { }, /** - * 处理授权回调(从 URL 中获取 code 后调用后端 /login) + * 处理授权回调(从 URL 中获取 code 后换取 openid,再用 openid 登录) */ async handleCallback(code) { const appNo = uni.getStorageSync('app_no') || getAppNo(detectPlatform()); @@ -107,6 +108,7 @@ export default { try { this.statusText = '正在验证身份...'; + // 用 code 换取 openid(后端处理,前端只传 code) const res = await gatewayPost('/api/v1/user/login', { app_no: appNo, code: code, @@ -125,17 +127,17 @@ export default { url.searchParams.delete('state'); window.history.replaceState({}, '', url.toString()); + // 存储 openid + uni.setStorageSync('openid', result.openid); + if (result.register) { // 已注册 → 缓存 JWT → 跳转首页 uni.setStorageSync('token', result.token); - uni.setStorageSync('user_info', result.user_info); - console.log('[loading] stored user_info:', JSON.stringify(result.user_info, null, 2)); + // 不再存储 user_info,点击"我的"时再获取 this.goToHome(); } else { // 未注册 → 缓存临时数据 → 跳转注册页 uni.setStorageSync('temp_token', result.temp_token); - uni.setStorageSync('auth_info', result.auth_info); - console.log('[loading] stored auth_info:', JSON.stringify(result.auth_info, null, 2)); this.goToRegister(); } } else { @@ -176,60 +178,60 @@ export default { }, /** - * Mock 登录(开发环境模拟不同用户状态) + * Mock 登录(跳过微信授权,调用真实登录接口) */ async mockLogin() { const mode = config.mockWechatLogin; const mock = config.mockUser; + const mockOpenid = mock.user_info.open_id; - if (mode === 'register' || mode === 'login') { - // 调用真实登录接口,用测试 code - this.statusText = '模拟:获取授权信息...'; - const appNo = uni.getStorageSync('app_no') || getAppNo(detectPlatform()) || config.mockAppNo; - - try { - const res = await gatewayPost('/api/v1/user/login', { - app_no: appNo, - code: 'test_code', - }); - - const data = res.data || {}; - if (data.code === 0 && data.data) { - const result = data.data; - - if (result.register) { - // 已注册 - uni.setStorageSync('token', result.token); - uni.setStorageSync('user_info', result.user_info); - console.log('[Auth] Mock: existing user → home'); - this.goToHome(); - } else { - // 未注册 → 存真实的 temp_token,合并 mock 头像昵称 - const authInfo = { - ...mock.user_info, - ...result.auth_info, - }; - uni.setStorageSync('temp_token', result.temp_token); - uni.setStorageSync('auth_info', authInfo); - console.log('[Auth] Mock: new user → register, temp_token:', result.temp_token); - this.goToRegister(); - } - } else { - uni.showToast({ title: data.message || '登录接口返回异常', icon: 'none' }); - console.error('[Auth] Mock login failed:', data); - } - } catch (e) { - console.error('[Auth] Mock login error:', e); - uni.showToast({ title: '网络请求失败', icon: 'none' }); - } - - } else { - // 'skip' → 直接登录 + // 'skip' 模式直接登录,不调接口 + if (mode === 'skip') { this.statusText = '模拟登录中...'; uni.setStorageSync('token', mock.token); - uni.setStorageSync('user_info', mock.user_info); - console.log('[Auth] Mock: skip → home'); + uni.setStorageSync('openid', mockOpenid); + console.log('[Auth] Mock skip → home'); setTimeout(() => this.goToHome(), 500); + return; + } + + // 'register' / 'login' 模式:调用真实登录接口,传 mock openid + this.statusText = '模拟:调用登录接口...'; + const appNo = uni.getStorageSync('app_no') || config.mockAppNo; + + try { + const res = await gatewayPost('/api/v1/user/login', { + app_no: appNo, + openid: mockOpenid, + }); + + const data = res.data || {}; + console.log('[Auth] Mock login response:', JSON.stringify(data, null, 2)); + + if (data.code === 0 && data.data) { + const result = data.data; + + // 存储 openid + uni.setStorageSync('openid', result.openid || mockOpenid); + + if (result.register) { + // 已注册 → 存 token → 跳首页 + uni.setStorageSync('token', result.token); + console.log('[Auth] Mock: existing user → home'); + this.goToHome(); + } else { + // 未注册 → 存 temp_token → 跳注册页 + uni.setStorageSync('temp_token', result.temp_token); + console.log('[Auth] Mock: new user → register'); + this.goToRegister(); + } + } else { + uni.showToast({ title: data.message || '登录失败', icon: 'none' }); + console.error('[Auth] Mock login failed:', data); + } + } catch (e) { + console.error('[Auth] Mock login error:', e); + uni.showToast({ title: '网络请求失败', icon: 'none' }); } }, }, diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue index b626e9c..3b98eb0 100644 --- a/src/pages/index/index.vue +++ b/src/pages/index/index.vue @@ -2,11 +2,6 @@ - - - 智能货柜{{ deviceId ? '-' + deviceId : '' }} - - import PageNavBar from '@/components/page-nav-bar/page-nav-bar.vue'; import config from '@/config/env.js'; -import { get } from '@/utils/request.js'; +import { get, gatewayGet } from '@/utils/request.js'; import { checkLoginWithPrompt, getCachedUserInfo } from '@/utils/auth-guard.js'; import { isVConsoleEnabled, showVConsole, hideVConsole } from '@/utils/vconsole'; @@ -236,10 +231,14 @@ export default { this.currentTab = 'mine'; // 记录来源:从其他页面跳转过来的 this.fromPage = 'navigate'; + // 获取用户信息 + this.fetchUserInfo(); } if (options.device_id) { this.deviceId = options.device_id; + // 动态设置导航栏标题 + uni.setNavigationBarTitle({ title: `智能货柜-${this.deviceId}` }); this.fetchProducts(); } else if (!options.tab) { // 无设备编号且非 tab 跳转,提示并跳至扫码页 @@ -272,6 +271,8 @@ export default { // 记录来源:从 tab 切换的 if (tab === 'mine') { this.fromPage = 'tab'; + // 获取用户信息 + this.fetchUserInfo(); } }, switchCategory(cat) { this.activeCategory = cat; }, @@ -291,6 +292,71 @@ export default { } console.log('[index] this.userInfo:', JSON.stringify(this.userInfo, null, 2)); }, + // 从接口获取用户信息(点击"我的"时调用) + async fetchUserInfo() { + const appNo = uni.getStorageSync('app_no') || config.mockAppNo; + + if (!appNo) { + console.warn('[index] 无法获取应用信息'); + return; + } + + // Mock 模式下,从缓存读取用户信息 + if (config.mockWechatLogin) { + console.log('[index] Mock 模式,从缓存读取用户信息'); + const cached = getCachedUserInfo(); + if (cached) { + // 有缓存(注册后存储的),直接使用 + this.userInfo = { ...this.userInfo, ...cached }; + } else { + // 无缓存,使用 mock 数据(已注册用户) + this.userInfo = { + nickname: config.mockUser.user_info.nickname || '', + phone: config.mockUser.user_info.phone || '', + avatar: config.mockUser.user_info.avatar || '', + }; + uni.setStorageSync('user_info', this.userInfo); + } + return; + } + + try { + // 调用接口获取用户信息 + const res = await gatewayGet('/api/v1/user/info', { + app_no: appNo, + }); + + const data = res.data || {}; + console.log('[index] fetchUserInfo response:', JSON.stringify(data, null, 2)); + + if (data.code === 0 && data.data) { + const userInfo = data.data; + this.userInfo = { + nickname: userInfo.nickname || '', + phone: userInfo.phone || '', + avatar: userInfo.avatar || '', + }; + // 存入缓存 + uni.setStorageSync('user_info', this.userInfo); + console.log('[index] fetchUserInfo success:', JSON.stringify(this.userInfo, null, 2)); + } else if (data.code === 1010) { + // 用户未注册,需要重新走授权流程获取 temp_token + console.warn('[index] 用户未注册,重新授权'); + uni.removeStorageSync('token'); + uni.removeStorageSync('user_info'); + // 跳转到 loading 页重新授权(会获取 temp_token 后跳注册页) + const deviceId = this.deviceId || ''; + const loadingUrl = deviceId + ? `/pages/auth/loading?device_id=${deviceId}` + : '/pages/auth/loading'; + uni.redirectTo({ url: loadingUrl }); + } else { + console.warn('[index] fetchUserInfo failed:', data.message); + } + } catch (e) { + console.error('[index] fetchUserInfo error:', e); + } + }, async fetchProducts() { this.loading = true; @@ -405,19 +471,6 @@ page { height: 100%; background-color: #fff; } /* ====== 首页样式 ====== */ .home-page { display: flex; flex-direction: column; height: 100%; } -/* 顶部标题栏 */ -.page-header { - padding: 24rpx 32rpx; - background-color: #fff; - border-bottom: 1rpx solid #f0f0f0; -} - -.page-title { - font-size: 32rpx; - font-weight: bold; - color: #333; -} - .product-area { flex: 1; overflow-y: auto; height: 0; } /* 热销商品标题 + 装饰 */ diff --git a/src/pages/register/register.vue b/src/pages/register/register.vue index 0a0bc29..7767c25 100644 --- a/src/pages/register/register.vue +++ b/src/pages/register/register.vue @@ -69,6 +69,7 @@