diff --git a/assets/prefabs/PageHome.ts b/assets/prefabs/PageHome.ts index 46e6fc3..5480cd7 100644 --- a/assets/prefabs/PageHome.ts +++ b/assets/prefabs/PageHome.ts @@ -1,7 +1,7 @@ import { _decorator, Node, Button } from 'cc'; import { BaseView } from 'db://assets/scripts/core/BaseView'; import { ViewManager } from 'db://assets/scripts/core/ViewManager'; -import { WxSDK } from 'db://assets/scripts/utils/WxSDK'; +import { WxSDK, checkPrivacySetting, requirePrivacyAuthorize } from 'db://assets/scripts/utils/WxSDK'; const { ccclass, property } = _decorator; /** @@ -23,6 +23,8 @@ export class PageHome extends BaseView { console.log('[PageHome] onViewLoad'); this._initButtons(); this._initWxShare(); + // 检查隐私授权 + this._checkPrivacyAuthorization(); } /** @@ -36,6 +38,28 @@ export class PageHome extends BaseView { }); } + /** + * 检查隐私授权状态 + */ + private async _checkPrivacyAuthorization(): Promise { + if (!WxSDK.isWechat()) { + console.log('[PageHome] 非微信环境,跳过隐私授权检查'); + return; + } + + try { + const { needAuthorization } = await checkPrivacySetting(); + if (needAuthorization) { + console.log('[PageHome] 用户未授权隐私,引导授权'); + await requirePrivacyAuthorize(); + } else { + console.log('[PageHome] 用户已授权隐私'); + } + } catch (err) { + console.warn('[PageHome] 隐私授权检查异常:', err); + } + } + /** * 初始化按钮事件 */ diff --git a/assets/prefabs/PageWriteLevels.ts b/assets/prefabs/PageWriteLevels.ts index fc01a3b..490a817 100644 --- a/assets/prefabs/PageWriteLevels.ts +++ b/assets/prefabs/PageWriteLevels.ts @@ -4,6 +4,10 @@ import { ViewManager } from 'db://assets/scripts/core/ViewManager'; import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager'; import { ToastManager } from 'db://assets/scripts/utils/ToastManager'; import { ShareManager } from 'db://assets/scripts/utils/ShareManager'; +import { StorageManager } from 'db://assets/scripts/utils/StorageManager'; +import { WxSDK, getUserProfile } from 'db://assets/scripts/utils/WxSDK'; +import { API_ENDPOINTS, API_TIMEOUT } from 'db://assets/scripts/config/ApiConfig'; +import { HttpUtil } from 'db://assets/scripts/utils/HttpUtil'; const { ccclass, property } = _decorator; /** @@ -525,6 +529,10 @@ export class PageWriteLevels extends BaseView { } console.log('[PageWriteLevels] 创建分享成功, code:', shareCode); + + // 获取用户头像昵称并上传 + await this._uploadUserInfo(); + ShareManager.instance.triggerWxShare(shareTitle, shareCode); ToastManager.instance.show('分享创建成功!'); } catch (err) { @@ -550,6 +558,49 @@ export class PageWriteLevels extends BaseView { return ids; } + /** + * 获取用户头像昵称并上传到服务端 + */ + private async _uploadUserInfo(): Promise { + // 先检查本地缓存 + const cachedUserInfo = StorageManager.getUserInfo(); + if (cachedUserInfo) { + console.log('[PageWriteLevels] 使用缓存的用户信息'); + return; + } + + if (!WxSDK.isWechat()) { + console.log('[PageWriteLevels] 非微信环境,跳过获取用户信息'); + return; + } + + try { + const userInfo = await getUserProfile(); + + // 本地缓存 + StorageManager.setUserInfo(userInfo); + + // 上传到服务端 + const response = await HttpUtil.post( + API_ENDPOINTS.USER_INFO, + { + avatarUrl: userInfo.avatarUrl, + nickName: userInfo.nickName + }, + API_TIMEOUT.DEFAULT + ); + + if (response.success) { + console.log('[PageWriteLevels] 用户信息上传成功'); + } else { + console.warn('[PageWriteLevels] 用户信息上传失败:', response.message); + } + } catch (err) { + console.warn('[PageWriteLevels] 获取用户信息失败:', err); + // 不阻断主流程 + } + } + onViewHide(): void { console.log('[PageWriteLevels] onViewHide'); } diff --git a/assets/scripts/config/ApiConfig.ts b/assets/scripts/config/ApiConfig.ts index 6925551..36383e6 100644 --- a/assets/scripts/config/ApiConfig.ts +++ b/assets/scripts/config/ApiConfig.ts @@ -15,6 +15,7 @@ export const API_ENDPOINTS = { USER_GAME_DATA: `${API_BASE}/user/game-data`, LEVELS: `${API_BASE}/wechat-game/levels`, SHARE_CREATE: `${API_BASE}/share`, + USER_INFO: `${API_BASE}/user/info`, } as const; /** 构建加入分享的 URL */ diff --git a/assets/scripts/utils/StorageManager.ts b/assets/scripts/utils/StorageManager.ts index 319ae71..c3ffe06 100644 --- a/assets/scripts/utils/StorageManager.ts +++ b/assets/scripts/utils/StorageManager.ts @@ -24,6 +24,9 @@ export class StorageManager { /** 认证 token 存储键 */ private static readonly KEY_TOKEN = 'auth_token'; + /** 用户信息存储键 */ + private static readonly KEY_USER_INFO = 'user_info'; + /** 默认积分 */ private static readonly DEFAULT_POINTS = 10; @@ -264,6 +267,48 @@ export class StorageManager { StorageManager.resetPoints(); StorageManager.resetProgress(); StorageManager.clearToken(); + StorageManager.clearUserInfo(); console.log('[StorageManager] 所有数据已重置'); } + + // ==================== 用户信息管理 ==================== + + /** + * 用户信息结构 + */ + interface UserInfo { + avatarUrl: string; + nickName: string; + } + + /** + * 保存用户信息(头像、昵称) + * @param userInfo 用户信息对象 + */ + static setUserInfo(userInfo: UserInfo): void { + sys.localStorage.setItem(StorageManager.KEY_USER_INFO, JSON.stringify(userInfo)); + console.log('[StorageManager] 用户信息已保存'); + } + + /** + * 获取本地缓存的用户信息 + * @returns 用户信息对象或 null + */ + static getUserInfo(): UserInfo | null { + const data = sys.localStorage.getItem(StorageManager.KEY_USER_INFO); + if (!data) return null; + try { + return JSON.parse(data) as UserInfo; + } catch { + return null; + } + } + + /** + * 清除用户信息缓存 + */ + static clearUserInfo(): void { + sys.localStorage.removeItem(StorageManager.KEY_USER_INFO); + console.log('[StorageManager] 用户信息已清除'); + } } diff --git a/assets/scripts/utils/WxSDK.ts b/assets/scripts/utils/WxSDK.ts index 4c87827..3a28913 100644 --- a/assets/scripts/utils/WxSDK.ts +++ b/assets/scripts/utils/WxSDK.ts @@ -237,3 +237,135 @@ export class WxSDK { return null; } } + +// ==================== 隐私授权相关 ==================== + +/** + * 检查用户是否已授权隐私 + * @returns Promise<{ needAuthorization: boolean }> needAuthorization 为 false 表示已授权 + */ +export async function checkPrivacySetting(): Promise<{ needAuthorization: boolean }> { + return new Promise((resolve) => { + const wxApi = WxSDK.getWx(); + if (!wxApi) { + // 非微信环境,认为已授权 + resolve({ needAuthorization: false }); + return; + } + + if (typeof wxApi.getPrivacySetting !== 'function') { + // 低版本微信,认为已授权 + console.warn('[WxSDK] 当前微信版本不支持 getPrivacySetting'); + resolve({ needAuthorization: false }); + return; + } + + wxApi.getPrivacySetting({ + success: (res: any) => { + console.log('[WxSDK] 隐私授权检查结果:', res); + resolve({ needAuthorization: res.needAuthorization }); + }, + fail: (err: any) => { + console.warn('[WxSDK] 隐私授权检查失败:', err); + // 检查失败时认为需要授权 + resolve({ needAuthorization: true }); + } + }); + }); +} + +/** + * 引导用户进行隐私授权 + * 调用后会弹出微信隐私授权弹窗 + * @returns Promise + */ +export async function requirePrivacyAuthorize(): Promise { + return new Promise((resolve, reject) => { + const wxApi = WxSDK.getWx(); + if (!wxApi) { + console.warn('[WxSDK] 非微信环境,跳过隐私授权'); + resolve(); + return; + } + + if (typeof wxApi.requirePrivacyAuthorize !== 'function') { + console.warn('[WxSDK] 当前微信版本不支持 requirePrivacyAuthorize'); + resolve(); + return; + } + + wxApi.requirePrivacyAuthorize({ + success: () => { + console.log('[WxSDK] 用户已授权隐私'); + resolve(); + }, + fail: (err: any) => { + console.warn('[WxSDK] 用户拒绝或授权失败:', err); + reject(new Error(err.errMsg || '隐私授权失败')); + } + }); + }); +} + +// ==================== 用户信息相关 ==================== + +/** + * 用户信息(头像、昵称) + */ +export interface WxUserInfo { + avatarUrl: string; + nickName: string; + country?: string; + province?: string; + city?: string; + gender?: number; +} + +/** + * 获取用户头像和昵称(需要用户主动授权) + * @returns Promise + */ +export async function getUserProfile(): Promise { + return new Promise((resolve, reject) => { + const wxApi = WxSDK.getWx(); + if (!wxApi) { + // 非微信环境,返回 mock 数据 + console.warn('[WxSDK] 非微信环境,返回 mock 用户信息'); + resolve({ + avatarUrl: '', + nickName: '微信用户' + }); + return; + } + + if (typeof wxApi.getUserProfile !== 'function') { + console.warn('[WxSDK] 当前微信版本不支持 getUserProfile'); + reject(new Error('当前微信版本不支持 getUserProfile')); + return; + } + + wxApi.getUserProfile({ + desc: '用于完善用户资料', + success: (res: any) => { + if (res.userInfo) { + console.log('[WxSDK] 获取用户信息成功'); + resolve({ + avatarUrl: res.userInfo.avatarUrl, + nickName: res.userInfo.nickName, + country: res.userInfo.country, + province: res.userInfo.province, + city: res.userInfo.city, + gender: res.userInfo.gender + }); + } else { + console.error('[WxSDK] 获取用户信息失败: 无 userInfo'); + reject(new Error('获取用户信息失败')); + } + }, + fail: (err: any) => { + console.error('[WxSDK] 获取用户信息失败:', err); + reject(new Error(err.errMsg || '获取用户信息失败')); + } + }); + }); +}