# 微信隐私授权与用户信息功能实现计划

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** 接入微信隐私授权 API，进入首页时检查隐私授权状态；分享时获取用户头像昵称并上传服务端

**Architecture:** 
- WxSDK 工具类新增隐私授权和用户信息获取方法
- StorageManager 新增用户信息本地缓存
- PageHome 接入隐私授权检查
- PageWriteLevels 接入用户信息获取与上传
- ApiConfig 新增用户信息 API 端点

**Tech Stack:** Cocos Creator 3.8.8, TypeScript, 微信小游戏 API

---

## 文件变更概览

| 文件 | 变更类型 |
|------|----------|
| `assets/scripts/config/ApiConfig.ts` | 新增端点 |
| `assets/scripts/utils/StorageManager.ts` | 新增用户信息存取方法 |
| `assets/scripts/utils/WxSDK.ts` | 新增隐私授权、用户信息获取方法 |
| `assets/prefabs/PageHome.ts` | 接入隐私授权检查 |
| `assets/prefabs/PageWriteLevels.ts` | 接入用户信息获取与上传 |

---

## Task 1: ApiConfig 新增用户信息 API 端点

**Files:**
- Modify: `assets/scripts/config/ApiConfig.ts`

- [ ] **Step 1: 添加用户信息 API 端点**

打开文件 `assets/scripts/config/ApiConfig.ts`，在 `API_ENDPOINTS` 对象中添加：

```typescript
USER_INFO: `${API_BASE}/user/info`,
```

最终文件应如下：

```typescript
export const API_ENDPOINTS = {
    WX_LOGIN: `${API_BASE}/auth/wx-login`,
    USER_ASSETS: `${API_BASE}/user/assets`,
    USER_ASSETS_CONSUME: `${API_BASE}/user/assets/consume`,
    USER_ASSETS_EARN: `${API_BASE}/user/assets/earn`,
    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;
```

- [ ] **Step 2: 提交代码**

```bash
git add assets/scripts/config/ApiConfig.ts
git commit -m "feat: 新增用户信息 API 端点"
```

---

## Task 2: StorageManager 新增用户信息缓存方法

**Files:**
- Modify: `assets/scripts/utils/StorageManager.ts`

- [ ] **Step 1: 添加用户信息存储相关常量**

打开 `assets/scripts/utils/StorageManager.ts`，在文件顶部找到存储 key 定义的位置，添加：

```typescript
const STORAGE_KEYS = {
    // ... 现有 keys
    USER_INFO: 'user_info',
} as const;
```

- [ ] **Step 2: 新增用户信息存取方法**

在 StorageManager 类中添加以下方法：

```typescript
/**
 * 保存用户信息（头像、昵称）
 * @param userInfo 用户信息对象 { avatarUrl: string, nickName: string }
 */
static setUserInfo(userInfo: { avatarUrl: string; nickName: string }): void {
    localStorage.setItem(STORAGE_KEYS.USER_INFO, JSON.stringify(userInfo));
}

/**
 * 获取本地缓存的用户信息
 * @returns 用户信息对象或 null
 */
static getUserInfo(): { avatarUrl: string; nickName: string } | null {
    const data = localStorage.getItem(STORAGE_KEYS.USER_INFO);
    if (!data) return null;
    try {
        return JSON.parse(data);
    } catch {
        return null;
    }
}

/**
 * 清除用户信息缓存
 */
static clearUserInfo(): void {
    localStorage.removeItem(STORAGE_KEYS.USER_INFO);
}
```

- [ ] **Step 3: 提交代码**

```bash
git add assets/scripts/utils/StorageManager.ts
git commit -m "feat: StorageManager 新增用户信息缓存方法"
```

---

## Task 3: WxSDK 新增隐私授权和用户信息获取方法

**Files:**
- Modify: `assets/scripts/utils/WxSDK.ts`

- [ ] **Step 1: 添加隐私授权检查方法**

在 WxSDK 类末尾（`}` 之前）添加：

```typescript
// ==================== 隐私授权相关 ====================

/**
 * 检查用户是否已授权隐私
 * @returns Promise<{ needAuthorization: boolean }> needAuthorization 为 false 表示已授权
 */
static checkPrivacySetting(): Promise<{ needAuthorization: boolean }> {
    return new Promise((resolve, reject) => {
        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<void>
 */
static requirePrivacyAuthorize(): Promise<void> {
    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 || '隐私授权失败'));
            }
        });
    });
}
```

- [ ] **Step 2: 添加获取用户头像昵称方法**

在同一文件中继续添加：

```typescript
// ==================== 用户信息相关 ====================

/**
 * 用户信息（头像、昵称）
 */
export interface WxUserInfo {
    avatarUrl: string;
    nickName: string;
    country?: string;
    province?: string;
    city?: string;
    gender?: number;
}

/**
 * 获取用户头像和昵称（需要用户主动授权）
 * @returns Promise<WxUserInfo>
 */
static getUserProfile(): Promise<WxUserInfo> {
    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 || '获取用户信息失败'));
            }
        });
    });
}
```

- [ ] **Step 3: 提交代码**

```bash
git add assets/scripts/utils/WxSDK.ts
git commit -m "feat: WxSDK 新增隐私授权和用户信息获取方法"
```

---

## Task 4: PageHome 接入隐私授权检查

**Files:**
- Modify: `assets/prefabs/PageHome.ts`

- [ ] **Step 1: 在 onViewLoad 中添加隐私授权检查**

打开 `assets/prefabs/PageHome.ts`，在 `onViewLoad` 方法末尾添加：

```typescript
/**
 * 检查隐私授权状态
 */
private async _checkPrivacyAuthorization(): Promise<void> {
    if (!WxSDK.isWechat()) {
        console.log('[PageHome] 非微信环境，跳过隐私授权检查');
        return;
    }

    try {
        const { needAuthorization } = await WxSDK.checkPrivacySetting();
        if (needAuthorization) {
            console.log('[PageHome] 用户未授权隐私，引导授权');
            await WxSDK.requirePrivacyAuthorize();
        } else {
            console.log('[PageHome] 用户已授权隐私');
        }
    } catch (err) {
        console.warn('[PageHome] 隐私授权检查异常:', err);
    }
}
```

- [ ] **Step 2: 在 onViewLoad 中调用隐私授权检查**

在 `onViewLoad` 方法末尾添加调用：

```typescript
onViewLoad(): void {
    console.log('[PageHome] onViewLoad');
    this._initButtons();
    this._initWxShare();
    // 新增：检查隐私授权
    this._checkPrivacyAuthorization();
}
```

- [ ] **Step 3: 提交代码**

```bash
git add assets/prefabs/PageHome.ts
git commit -m "feat: PageHome 接入隐私授权检查"
```

---

## Task 5: PageWriteLevels 接入用户信息获取与上传

**Files:**
- Modify: `assets/prefabs/PageWriteLevels.ts`

- [ ] **Step 1: 添加 HttpUtil import（如果还没有）**

检查文件顶部 import，如果没有 HttpUtil，添加：

```typescript
import { HttpUtil } from 'db://assets/scripts/utils/HttpUtil';
```

- [ ] **Step 2: 在 _onCompleteClick 中添加用户信息获取逻辑**

修改 `_onCompleteClick` 方法，在分享成功后的逻辑中添加用户信息获取：

```typescript
private async _onCompleteClick(): Promise<void> {
    if (!this._validateSelection()) return;

    const shareTitle = this.shareTitleEditBox?.getComponent(EditBox)?.string?.trim() || '';
    if (!shareTitle) {
        ToastManager.instance.show('请输入分享标题');
        return;
    }

    if (this._isSubmitting) return;
    this._isSubmitting = true;

    try {
        const levelIds = this._getSelectedLevelIds();
        if (levelIds.length !== MAX_SELECTION) {
            ToastManager.instance.show('获取关卡数据失败，请重试');
            return;
        }

        const shareCode = await ShareManager.instance.createShare(shareTitle, levelIds);
        if (!shareCode) {
            ToastManager.instance.show('创建分享失败，请重试');
            return;
        }

        console.log('[PageWriteLevels] 创建分享成功, code:', shareCode);
        
        // 获取用户头像昵称并上传
        await this._uploadUserInfo();
        
        ShareManager.instance.triggerWxShare(shareTitle, shareCode);
        ToastManager.instance.show('分享创建成功！');
    } catch (err) {
        console.error('[PageWriteLevels] 完成按钮异常:', err);
        ToastManager.instance.show('操作失败，请重试');
    } finally {
        this._isSubmitting = false;
    }
}
```

- [ ] **Step 3: 添加 _uploadUserInfo 方法**

在 PageWriteLevels 类中添加新方法：

```typescript
/**
 * 获取用户头像昵称并上传到服务端
 */
private async _uploadUserInfo(): Promise<void> {
    // 先检查本地缓存
    const cachedUserInfo = StorageManager.getUserInfo();
    if (cachedUserInfo) {
        console.log('[PageWriteLevels] 使用缓存的用户信息');
        return;
    }

    if (!WxSDK.isWechat()) {
        console.log('[PageWriteLevels] 非微信环境，跳过获取用户信息');
        return;
    }

    try {
        const userInfo = await WxSDK.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);
        // 不阻断主流程
    }
}
```

- [ ] **Step 4: 添加必要的 import**

检查文件顶部 import，添加：

```typescript
import { StorageManager } from 'db://assets/scripts/utils/StorageManager';
import { API_ENDPOINTS, API_TIMEOUT } from 'db://assets/scripts/config/ApiConfig';
```

- [ ] **Step 5: 提交代码**

```bash
git add assets/prefabs/PageWriteLevels.ts
git commit -m "feat: PageWriteLevels 接入用户信息获取与上传"
```

---

## 实现完成

所有任务已完成，实现功能：
1. ✅ PageHome 进入时检查隐私授权状态，未授权则引导用户授权
2. ✅ PageWriteLevels 分享时获取用户头像昵称，本地缓存并上传服务端
3. ✅ 新增用户信息 API 端点
4. ✅ StorageManager 支持用户信息缓存