feat: 添加分享模式按钮文案支持,优化通关弹窗功能
This commit is contained in:
@@ -40,7 +40,7 @@ Git 历史采用 Conventional Commits,且摘要多为中文,例如 `feat:
|
||||
<claude-mem-context>
|
||||
# Memory Context
|
||||
|
||||
# $CMEM mp-xieyingeng 2026-05-12 9:37pm GMT+8
|
||||
# $CMEM mp-xieyingeng 2026-05-13 8:06am GMT+8
|
||||
|
||||
Legend: 🎯session 🔴bugfix 🟣feature 🔄refactor ✅change 🔵discovery ⚖️decision
|
||||
Format: ID TIME TYPE TITLE
|
||||
|
||||
@@ -2,17 +2,20 @@ import { _decorator, Node, EditBox, instantiate, Vec3, Button, Label, Sprite, Sp
|
||||
import { BaseView } from 'db://assets/scripts/core/BaseView';
|
||||
import { ViewManager } from 'db://assets/scripts/core/ViewManager';
|
||||
import { StaminaManager } from 'db://assets/scripts/utils/StaminaManager';
|
||||
import { WxSDK } from 'db://assets/scripts/utils/WxSDK';
|
||||
import { WxSDK, getUserProfile, type WxUserInfo } from 'db://assets/scripts/utils/WxSDK';
|
||||
import { LevelDataManager } from 'db://assets/scripts/utils/LevelDataManager';
|
||||
import { AuthManager } from 'db://assets/scripts/utils/AuthManager';
|
||||
import { RuntimeLevelConfig } from 'db://assets/scripts/types/LevelTypes';
|
||||
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 { HttpUtil } from 'db://assets/scripts/utils/HttpUtil';
|
||||
import { API_ENDPOINTS, API_TIMEOUT } from 'db://assets/scripts/config/ApiConfig';
|
||||
import { PassModal } from 'db://assets/prefabs/PassModal';
|
||||
import { WrongModal } from 'db://assets/prefabs/WrongModal';
|
||||
import { TimeoutModal } from 'db://assets/prefabs/TimeoutModal';
|
||||
import { CommonModal } from 'db://assets/prefabs/CommonModal';
|
||||
import { StaminaInfo, NextLevelData, SubmitShareLevel } from 'db://assets/scripts/types/ApiTypes';
|
||||
import { ApiEnvelope, StaminaInfo, NextLevelData, SubmitShareLevel } from 'db://assets/scripts/types/ApiTypes';
|
||||
import { AchievementTitleManager } from 'db://assets/scripts/utils/AchievementTitleManager';
|
||||
import { applyRoundedCorner } from 'db://assets/scripts/utils/roundedMaterial.utils';
|
||||
const { ccclass, property } = _decorator;
|
||||
@@ -72,6 +75,12 @@ export class PageLevel extends BaseView {
|
||||
/** 分享模式只展示提示 1 时,固定放回 TipsLayout 顶部,避免 Layout 把它排到底部被下一题按钮遮挡 */
|
||||
private static readonly SHARE_MODE_TIP1_Y = 120;
|
||||
|
||||
/** 分享模式底部按钮默认文案 */
|
||||
private static readonly SHARE_NEXT_BUTTON_TEXT = '下一题';
|
||||
|
||||
/** 分享模式最后一题提交文案 */
|
||||
private static readonly SHARE_SUBMIT_BUTTON_TEXT = '提交答案';
|
||||
|
||||
// ========== 节点引用 ==========
|
||||
@property(Node)
|
||||
inputLayout: Node | null = null;
|
||||
@@ -302,6 +311,9 @@ export class PageLevel extends BaseView {
|
||||
/** 是否正在提交分享挑战结果 */
|
||||
private _isSubmittingShareResult: boolean = false;
|
||||
|
||||
/** 本场分享挑战是否已经尝试拉取过用户头像昵称,避免结算流程重复弹窗 */
|
||||
private _hasRequestedShareUserInfo: boolean = false;
|
||||
|
||||
/**
|
||||
* 页面首次加载时调用
|
||||
*/
|
||||
@@ -318,6 +330,7 @@ export class PageLevel extends BaseView {
|
||||
this._shareLevelIndex = 0;
|
||||
this._shareSubmissions.clear();
|
||||
this._isSubmittingShareResult = false;
|
||||
this._hasRequestedShareUserInfo = false;
|
||||
console.log('[PageLevel] 进入分享挑战模式');
|
||||
} else {
|
||||
// 从 AuthManager 获取首关数据(由 PageLoading → game-data 提供)
|
||||
@@ -494,6 +507,7 @@ export class PageLevel extends BaseView {
|
||||
// 设置关卡标题
|
||||
this.updateTitleLevelLabel();
|
||||
this.updatePkLevelProgressLabel();
|
||||
this.updatePkNextLevelButtonText();
|
||||
|
||||
// 隐藏包袱答案,通关后再按 punchline 展示
|
||||
this.hidePunchline();
|
||||
@@ -1115,6 +1129,21 @@ export class PageLevel extends BaseView {
|
||||
: `${currentIndex}`;
|
||||
}
|
||||
|
||||
private updatePkNextLevelButtonText(): void {
|
||||
if (!this.pkNextLevelButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
const label = this.pkNextLevelButton.getChildByName('Label')?.getComponent(Label);
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
|
||||
label.string = this._isFinalShareLevel()
|
||||
? PageLevel.SHARE_SUBMIT_BUTTON_TEXT
|
||||
: PageLevel.SHARE_NEXT_BUTTON_TEXT;
|
||||
}
|
||||
|
||||
private _refreshModeUI(): void {
|
||||
const isPkMode = this._isShareMode;
|
||||
|
||||
@@ -1146,6 +1175,7 @@ export class PageLevel extends BaseView {
|
||||
|
||||
this.updateTitleLevelLabel();
|
||||
this.updatePkLevelProgressLabel();
|
||||
this.updatePkNextLevelButtonText();
|
||||
}
|
||||
|
||||
private _refreshTipsModeUI(): void {
|
||||
@@ -1885,11 +1915,20 @@ export class PageLevel extends BaseView {
|
||||
|
||||
passModal.setParams({
|
||||
levelIndex: this.getDisplayLevelNumber(),
|
||||
nextButtonText: this._isShareMode && this._isFinalShareLevel()
|
||||
? PageLevel.SHARE_SUBMIT_BUTTON_TEXT
|
||||
: undefined,
|
||||
titleInfo,
|
||||
previousTitleInfo
|
||||
});
|
||||
passModal.setCallbacks({
|
||||
onNextLevel: () => {
|
||||
if (this._isShareMode) {
|
||||
this._closePassModal();
|
||||
void this.goToNextLevel();
|
||||
return;
|
||||
}
|
||||
|
||||
this._showShareNextConfirmModal(() => {
|
||||
this._closePassModal();
|
||||
void this.goToNextLevel();
|
||||
@@ -2131,9 +2170,12 @@ export class PageLevel extends BaseView {
|
||||
return;
|
||||
}
|
||||
|
||||
const isFinalShareLevel = this._isFinalShareLevel();
|
||||
const modal = CommonModal.show(this.commonModalPrefab, {
|
||||
title: '提示',
|
||||
content: '还有时间\n确认进入下一题吗?',
|
||||
content: isFinalShareLevel
|
||||
? '确认提交挑战答案吗?'
|
||||
: '还有时间\n确认进入下一题吗?',
|
||||
buttonConfirm: '确认',
|
||||
buttonCancel: '再想想',
|
||||
zIndex: CommonModal.MODAL_Z_INDEX + 1,
|
||||
@@ -2216,6 +2258,67 @@ export class PageLevel extends BaseView {
|
||||
return totalLevels > 0 && this._shareLevelIndex >= totalLevels - 1;
|
||||
}
|
||||
|
||||
private async _ensureShareParticipantUserInfo(): Promise<void> {
|
||||
if (!this._isShareMode || this._hasRequestedShareUserInfo) {
|
||||
return;
|
||||
}
|
||||
this._hasRequestedShareUserInfo = true;
|
||||
|
||||
const cachedUserInfo = StorageManager.getUserInfo();
|
||||
if (cachedUserInfo && this._hasUsableUserInfo(cachedUserInfo)) {
|
||||
await this._uploadShareParticipantUserInfo(cachedUserInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WxSDK.isWechat()) {
|
||||
console.log('[PageLevel] 非微信环境,跳过获取用户头像昵称');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const userInfo = await getUserProfile();
|
||||
StorageManager.setUserInfo(userInfo);
|
||||
await this._uploadShareParticipantUserInfo(userInfo);
|
||||
} catch (err) {
|
||||
console.warn('[PageLevel] 获取用户头像昵称失败,继续提交挑战:', err);
|
||||
ToastManager.show('未授权头像昵称,将使用默认资料提交');
|
||||
}
|
||||
}
|
||||
|
||||
private _hasUsableUserInfo(userInfo: WxUserInfo): boolean {
|
||||
return !!userInfo.avatarUrl?.trim()
|
||||
&& !!userInfo.nickName?.trim()
|
||||
&& userInfo.nickName !== '微信用户';
|
||||
}
|
||||
|
||||
private async _uploadShareParticipantUserInfo(userInfo: WxUserInfo): Promise<void> {
|
||||
const userId = AuthManager.instance.userId;
|
||||
if (!userId) {
|
||||
console.warn('[PageLevel] 用户未登录,跳过上传头像昵称');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await HttpUtil.post<ApiEnvelope<unknown>>(
|
||||
API_ENDPOINTS.USER_INFO,
|
||||
{
|
||||
userId,
|
||||
avatarUrl: userInfo.avatarUrl,
|
||||
nickName: userInfo.nickName,
|
||||
},
|
||||
API_TIMEOUT.DEFAULT,
|
||||
);
|
||||
|
||||
if (response.success) {
|
||||
console.log('[PageLevel] 分享挑战用户头像昵称上传成功');
|
||||
} else {
|
||||
console.warn('[PageLevel] 分享挑战用户头像昵称上传失败:', response.message);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[PageLevel] 分享挑战用户头像昵称上传异常:', err);
|
||||
}
|
||||
}
|
||||
|
||||
private async _showShareEndPage(): Promise<void> {
|
||||
if (this._isSubmittingShareResult) {
|
||||
return;
|
||||
@@ -2238,6 +2341,7 @@ export class PageLevel extends BaseView {
|
||||
this._isSubmittingShareResult = true;
|
||||
ToastManager.show('正在结算挑战...');
|
||||
|
||||
await this._ensureShareParticipantUserInfo();
|
||||
const result = await ShareManager.instance.submitShareChallenge(payload);
|
||||
this._isSubmittingShareResult = false;
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ export interface PassModalTitleInfo {
|
||||
|
||||
interface PassModalParams {
|
||||
levelIndex?: number;
|
||||
/** 下一步按钮文案,不传时使用 prefab 默认文案 */
|
||||
nextButtonText?: string;
|
||||
titleInfo?: PassModalTitleInfo;
|
||||
/**
|
||||
* 通关前的称号信息。传入后,本次显示会把进度条从该起点动画到 titleInfo 的终点;
|
||||
@@ -93,6 +95,9 @@ export class PassModal extends BaseModal {
|
||||
/** 进度动画所绑定的对象,用于 Tween.stopAllByTarget */
|
||||
private readonly _progressTweenTarget: { progress: number } = { progress: 0 };
|
||||
|
||||
/** 下一步按钮文案,为 null 时保留 prefab 默认值 */
|
||||
private _nextButtonText: string | null = null;
|
||||
|
||||
/** 进度游标 0% 时的本地 X 坐标,使用 prefab 当前摆放位置作为起点 */
|
||||
private _progressAnchorStartX: number | null = null;
|
||||
|
||||
@@ -107,6 +112,11 @@ export class PassModal extends BaseModal {
|
||||
if (params?.titleInfo) {
|
||||
this.setTitleInfo(params.titleInfo);
|
||||
}
|
||||
|
||||
if (params && 'nextButtonText' in params) {
|
||||
this._nextButtonText = params.nextButtonText ?? null;
|
||||
this._applyNextButtonText();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,6 +154,7 @@ export class PassModal extends BaseModal {
|
||||
super.onViewShow();
|
||||
this._updateWidget();
|
||||
this._refreshTitleView();
|
||||
this._applyNextButtonText();
|
||||
this._playSuccessSound();
|
||||
this._playProgressAnimation();
|
||||
}
|
||||
@@ -234,6 +245,17 @@ export class PassModal extends BaseModal {
|
||||
}
|
||||
}
|
||||
|
||||
private _applyNextButtonText(): void {
|
||||
if (!this.nextLevelButton || this._nextButtonText === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const label = this.nextLevelButton.getChildByName('Label')?.getComponent(Label);
|
||||
if (label) {
|
||||
label.string = this._nextButtonText;
|
||||
}
|
||||
}
|
||||
|
||||
private _applyProgressText(text: string | undefined): void {
|
||||
if (this.progressLabel && text !== undefined) {
|
||||
this.progressLabel.string = text;
|
||||
|
||||
Reference in New Issue
Block a user