From 1adad45bfb7b2c0a511179fe86e8f6de143ce788 Mon Sep 17 00:00:00 2001 From: Shijia Huang Date: Wed, 11 Mar 2026 22:14:38 +1100 Subject: [PATCH 1/2] move the nickname input --- .../packageA/pages/waiting-room/index.ts | 140 +++++++++++++++--- .../packageA/pages/waiting-room/index.wxml | 60 ++++++++ .../packageA/pages/waiting-room/index.wxss | 104 +++++++++++++ miniprogram/pages/welcome/index.ts | 113 +------------- miniprogram/pages/welcome/index.wxml | 60 -------- miniprogram/pages/welcome/index.wxss | 103 ------------- 6 files changed, 293 insertions(+), 287 deletions(-) diff --git a/miniprogram/packageA/pages/waiting-room/index.ts b/miniprogram/packageA/pages/waiting-room/index.ts index fbb2a82..b12929a 100644 --- a/miniprogram/packageA/pages/waiting-room/index.ts +++ b/miniprogram/packageA/pages/waiting-room/index.ts @@ -32,7 +32,13 @@ type ErrorType = 'length' | 'not_found' | 'full' | 'started' | null; */ interface IWaitingRoomPageData { viewMode: ViewMode; - // 弹窗相关 + // 昵称弹窗相关 + showNicknameModal: boolean; + nicknameInput: string; + nicknameCharCount: number; + isNicknameConfirmDisabled: boolean; + nicknameModalAnimation: WechatMiniprogram.AnimationExportResult; + // 加入房间弹窗相关 showJoinModal: boolean; roomCodeInput: string; roomCodeDisplay: string[]; @@ -68,6 +74,7 @@ interface IWaitingRoomCustomOption extends WechatMiniprogram.Page.CustomOption { confirmButtonAnim: WechatMiniprogram.Animation | null; isCreatingRoom: boolean; isJoiningRoom: boolean; + pendingRoomId: string | null; } /** @@ -94,7 +101,13 @@ const WAITING_TEXTS: string[] = [ Page({ data: { viewMode: 'entry', - // 弹窗相关 + // 昵称弹窗相关 + showNicknameModal: false, + nicknameInput: '', + nicknameCharCount: 0, + isNicknameConfirmDisabled: true, + nicknameModalAnimation: {} as WechatMiniprogram.AnimationExportResult, + // 加入房间弹窗相关 showJoinModal: false, roomCodeInput: '', roomCodeDisplay: ['', '', '', '', '', ''], @@ -128,6 +141,7 @@ Page({ // 请求锁 isCreatingRoom: false, isJoiningRoom: false, + pendingRoomId: null, onLoad(options: Record): void { this.initAnimations(); @@ -138,22 +152,16 @@ Page({ message: '退出后房间将失效,确定要离开吗?', }); - const roomId = options['room_id']; - if (roomId) { - const value = roomId.replace(/\D/g, '').slice(0, 6); - const display: string[] = []; - for (let i = 0; i < 6; i++) { - display.push(value[i] || ''); - } - this.setData({ - showJoinModal: true, - roomCodeInput: value, - roomCodeDisplay: display, - inputFocus: false, - errorType: null, - errorMessage: '', - isJoinButtonDisabled: value.length !== 6, - }); + const roomId = options['room_id'] ?? null; + const storedNick: string = wx.getStorageSync('userNickName') || ''; + + if (!storedNick) { + // 未设置昵称:先弹昵称框,房间号暂存 + this.pendingRoomId = roomId; + this.openNicknameModal(); + } else if (roomId) { + // 已有昵称且是分享链接进入:直接弹加入房间框 + this.showJoinModalWithCode(roomId); } }, @@ -206,6 +214,102 @@ Page({ }); }, + /** + * 预填房间号并弹出加入房间弹窗 + */ + showJoinModalWithCode(roomId: string): void { + const value = roomId.replace(/\D/g, '').slice(0, 6); + const display: string[] = []; + for (let i = 0; i < 6; i++) { + display.push(value[i] || ''); + } + this.setData({ + showJoinModal: true, + roomCodeInput: value, + roomCodeDisplay: display, + inputFocus: false, + errorType: null, + errorMessage: '', + isJoinButtonDisabled: value.length !== 6, + }); + }, + + /** + * 打开昵称弹窗并播放上滑动画 + */ + openNicknameModal(): void { + this.setData({ + showNicknameModal: true, + nicknameInput: '', + nicknameCharCount: 0, + isNicknameConfirmDisabled: true, + }); + + const anim = wx.createAnimation({ + duration: 350, + timingFunction: 'ease-out', + }); + anim.translateY(0).step(); + this.setData({ nicknameModalAnimation: anim.export() }); + }, + + /** + * 昵称输入框变化 + */ + onNicknameInput(e: WechatMiniprogram.Input): void { + const value: string = e.detail.value; + this.setData({ + nicknameInput: value, + nicknameCharCount: value.length, + isNicknameConfirmDisabled: !nicknameService.validate(value), + }); + }, + + /** + * 「击鼓申冤!」确认按钮 + */ + onNicknameConfirm(): void { + const { nicknameInput } = this.data; + if (!nicknameService.validate(nicknameInput)) { + return; + } + + nicknameService.saveNickName(nicknameInput); + this.initUser(); + + this.setData({ showNicknameModal: false }); + + if (this.pendingRoomId) { + const rid = this.pendingRoomId; + this.pendingRoomId = null; + this.showJoinModalWithCode(rid); + } + }, + + /** + * 「稍后再说」次级按钮:使用默认昵称进入,不保存到 Storage + */ + onNicknameSkip(): void { + const app = getApp(); + app.globalData.userInfo.nickName = DEFAULT_NICK_NAME; + + this.setData({ showNicknameModal: false }); + + if (this.pendingRoomId) { + const rid = this.pendingRoomId; + this.pendingRoomId = null; + this.showJoinModalWithCode(rid); + } + }, + + /** + * 点击遮罩关闭昵称弹窗(不保存) + */ + onNicknameModalMaskTap(): void { + this.setData({ showNicknameModal: false }); + this.pendingRoomId = null; + }, + /** * 初始化动画实例 */ diff --git a/miniprogram/packageA/pages/waiting-room/index.wxml b/miniprogram/packageA/pages/waiting-room/index.wxml index f680f13..d0009fe 100644 --- a/miniprogram/packageA/pages/waiting-room/index.wxml +++ b/miniprogram/packageA/pages/waiting-room/index.wxml @@ -219,3 +219,63 @@ bindcomplete="onCountdownComplete" > + + + + + + + + + + + + + + + + 堂下何人,报上名来! + + + + + + {{ nicknameCharCount }}/12 + + + + + + + 稍后再说 + + + + diff --git a/miniprogram/packageA/pages/waiting-room/index.wxss b/miniprogram/packageA/pages/waiting-room/index.wxss index b6c78d0..a8d6657 100644 --- a/miniprogram/packageA/pages/waiting-room/index.wxss +++ b/miniprogram/packageA/pages/waiting-room/index.wxss @@ -326,3 +326,107 @@ .waiting-room__participant-name--me { color: #ffd000; } + +/* ======================================== + 昵称设置弹窗 + ======================================== */ +.nickname-modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; +} + +.nickname-modal__overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); +} + +.nickname-modal__panel { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + background-color: #fffef7; + border-radius: 32rpx 32rpx 0 0; + padding: 0 40rpx 60rpx; + box-sizing: border-box; + display: flex; + flex-direction: column; + align-items: center; + transform: translateY(100%); +} + +.nickname-modal__drag-bar { + width: 100%; + display: flex; + justify-content: center; + padding: 20rpx 0; +} + +.nickname-modal__drag-line { + width: 80rpx; + height: 8rpx; + border-radius: 4rpx; + background-color: #d9d9d9; +} + +.nickname-modal__title { + margin: 24rpx 0 40rpx; + text-align: center; +} + +.nickname-modal__title-text { + font-size: 40rpx; + font-weight: bold; + color: #8b4513; +} + +.nickname-modal__input-wrapper { + width: 100%; + position: relative; + margin-bottom: 48rpx; + background-color: #fff8e1; + border: 2rpx solid #ffe58f; + border-radius: 16rpx; + padding: 28rpx 80rpx 28rpx 32rpx; + box-sizing: border-box; +} + +.nickname-modal__input { + width: 100%; + font-size: 34rpx; + color: #333333; + line-height: 1.4; +} + +.nickname-modal__char-count { + position: absolute; + right: 24rpx; + bottom: 20rpx; + font-size: 24rpx; + color: #999999; +} + +.nickname-modal__actions { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: 24rpx; +} + +.nickname-modal__skip { + padding: 16rpx 40rpx; +} + +.nickname-modal__skip-text { + font-size: 28rpx; + color: #999999; +} diff --git a/miniprogram/pages/welcome/index.ts b/miniprogram/pages/welcome/index.ts index 41c765e..0d78533 100644 --- a/miniprogram/pages/welcome/index.ts +++ b/miniprogram/pages/welcome/index.ts @@ -8,12 +8,6 @@ interface WelcomePageData { ctaAnimation: AnimationResult; // 控制初始隐藏状态 isEntranceReady: boolean; - // 昵称弹窗 - showNicknameModal: boolean; - nicknameInput: string; - nicknameCharCount: number; - isNicknameConfirmDisabled: boolean; - nicknameModalAnimation: WechatMiniprogram.AnimationExportResult; } // 动画时序配置(毫秒) @@ -35,24 +29,13 @@ Page({ taglineAnimation: {} as AnimationResult, ctaAnimation: {} as AnimationResult, isEntranceReady: false, - // 昵称弹窗 - showNicknameModal: false, - nicknameInput: '', - nicknameCharCount: 0, - isNicknameConfirmDisabled: true, - nicknameModalAnimation: {} as WechatMiniprogram.AnimationExportResult, }, hasPlayedEntrance: false, onLoad(): void { - // 初始化用户 ID 和昵称 + // 初始化用户 ID nicknameService.getUserId(); - const storedNick: string = wx.getStorageSync('userNickName') || ''; - if (storedNick) { - const app = getApp(); - app.globalData.userInfo.nickName = storedNick; - } wx.request({ url: 'https://panleme.fun/health', @@ -152,95 +135,13 @@ Page({ }, /** - * 「我要申冤!」点击处理 - * 有昵称 → 直接跳转;无昵称 → 弹出昵称设置弹窗 + * 「我要申冤!」点击处理 → 直接跳转等待室(昵称在等待室处理) */ handleStartJudge(): void { - const app = getApp(); - const nickName: string = app.globalData.userInfo.nickName; - - if (nickName) { - // 已有昵称,直接跳转 - setTimeout(() => { - void wx.navigateTo({ - url: '/packageA/pages/waiting-room/index', - }); - }, 250); - } else { - // 无昵称,弹出昵称设置弹窗 - this.openNicknameModal(); - } - }, - - /** - * 打开昵称弹窗并播放上滑动画 - */ - openNicknameModal(): void { - this.setData({ - showNicknameModal: true, - nicknameInput: '', - nicknameCharCount: 0, - isNicknameConfirmDisabled: true, - }); - - // 弹窗上滑入场动画 - const anim = wx.createAnimation({ - duration: 350, - timingFunction: 'ease-out', - }); - anim.translateY(0).step(); - this.setData({ nicknameModalAnimation: anim.export() }); - }, - - /** - * 昵称输入框变化 - */ - onNicknameInput(e: WechatMiniprogram.Input): void { - const value: string = e.detail.value; - this.setData({ - nicknameInput: value, - nicknameCharCount: value.length, - isNicknameConfirmDisabled: !nicknameService.validate(value), - }); - }, - - /** - * 「击鼓申冤!」确认按钮 - */ - onNicknameConfirm(): void { - const { nicknameInput } = this.data; - if (!nicknameService.validate(nicknameInput)) { - return; - } - - nicknameService.saveNickName(nicknameInput); - - this.setData({ showNicknameModal: false }); - - void wx.navigateTo({ - url: '/packageA/pages/waiting-room/index', - }); - }, - - /** - * 「稍后再说」次级按钮 - * 使用默认值「申冤人」进入,不保存缓存 - */ - onNicknameSkip(): void { - const app = getApp(); - app.globalData.userInfo.nickName = '申冤人'; - - this.setData({ showNicknameModal: false }); - - void wx.navigateTo({ - url: '/packageA/pages/waiting-room/index', - }); - }, - - /** - * 点击遮罩关闭弹窗(不保存) - */ - onNicknameModalMaskTap(): void { - this.setData({ showNicknameModal: false }); + setTimeout(() => { + void wx.navigateTo({ + url: '/packageA/pages/waiting-room/index', + }); + }, 250); }, }); diff --git a/miniprogram/pages/welcome/index.wxml b/miniprogram/pages/welcome/index.wxml index 1569380..9f3005a 100644 --- a/miniprogram/pages/welcome/index.wxml +++ b/miniprogram/pages/welcome/index.wxml @@ -43,63 +43,3 @@ - - - - - - - - - - - - - - - - 堂下何人,报上名来! - - - - - - {{ nicknameCharCount }}/12 - - - - - - - 稍后再说 - - - - diff --git a/miniprogram/pages/welcome/index.wxss b/miniprogram/pages/welcome/index.wxss index b648c14..a4bb9e3 100644 --- a/miniprogram/pages/welcome/index.wxss +++ b/miniprogram/pages/welcome/index.wxss @@ -97,106 +97,3 @@ transform: scale(0); } -/* ======================================== - 昵称设置弹窗 - ======================================== */ -.nickname-modal { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 1000; -} - -.nickname-modal__overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); -} - -.nickname-modal__panel { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - background-color: #fffef7; - border-radius: 32rpx 32rpx 0 0; - padding: 0 40rpx 60rpx; - box-sizing: border-box; - display: flex; - flex-direction: column; - align-items: center; - transform: translateY(100%); -} - -.nickname-modal__drag-bar { - width: 100%; - display: flex; - justify-content: center; - padding: 20rpx 0; -} - -.nickname-modal__drag-line { - width: 80rpx; - height: 8rpx; - border-radius: 4rpx; - background-color: #d9d9d9; -} - -.nickname-modal__title { - margin: 24rpx 0 40rpx; - text-align: center; -} - -.nickname-modal__title-text { - font-size: 40rpx; - font-weight: bold; - color: #8b4513; -} - -.nickname-modal__input-wrapper { - width: 100%; - position: relative; - margin-bottom: 48rpx; - background-color: #fff8e1; - border: 2rpx solid #ffe58f; - border-radius: 16rpx; - padding: 28rpx 80rpx 28rpx 32rpx; - box-sizing: border-box; -} - -.nickname-modal__input { - width: 100%; - font-size: 34rpx; - color: #333333; - line-height: 1.4; -} - -.nickname-modal__char-count { - position: absolute; - right: 24rpx; - bottom: 20rpx; - font-size: 24rpx; - color: #999999; -} - -.nickname-modal__actions { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - gap: 24rpx; -} - -.nickname-modal__skip { - padding: 16rpx 40rpx; -} - -.nickname-modal__skip-text { - font-size: 28rpx; - color: #999999; -} From f62a17b38774b7f92989e859fc02161d9634f6f9 Mon Sep 17 00:00:00 2001 From: Shijia Huang Date: Wed, 11 Mar 2026 22:59:24 +1100 Subject: [PATCH 2/2] fix the LLM bug --- .../services/core/verdict-mapper.service.ts | 36 +++++++++++++------ miniprogram/packageA/pages/drum-room/index.ts | 2 +- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/backend/src/services/core/verdict-mapper.service.ts b/backend/src/services/core/verdict-mapper.service.ts index e966618..683881d 100644 --- a/backend/src/services/core/verdict-mapper.service.ts +++ b/backend/src/services/core/verdict-mapper.service.ts @@ -57,8 +57,8 @@ export class VerdictMapperService { */ mapJudgmentToVerdict( judgment: IJudgmentResponse, - _hostUserId: string, - _participants: IParticipant[] + hostUserId: string, + participants: IParticipant[] ): IVerdictResult { // 1. Map dimension scores const hostScores = this.mapDimensionScores(judgment.radarChart.player1); @@ -79,19 +79,33 @@ export class VerdictMapperService { const winnerId = hostWins ? 'host' : 'guest'; const loserId = hostWins ? 'guest' : 'host'; - // 4. Use LLM-generated punishment task - const punishmentTask = { - role: loserId as 'host' | 'guest', - task: judgment.punishmentTask, - }; - - // 5. Generate secret reports + // 4. Generate secret reports const secretReports = [ this.generateSecretReport('host', hostScores), this.generateSecretReport('guest', guestScores), ]; - // 6. Build verdict result + // 5. Replace 玩家1/玩家2 with actual nicknames in text fields + const hostParticipant = participants.find( + p => p.user.userId === hostUserId + ); + const guestParticipant = participants.find( + p => p.user.userId !== hostUserId + ); + const hostNickName = hostParticipant?.user.nickname ?? 'player1'; + const guestNickName = guestParticipant?.user.nickname ?? 'player2'; + const replaceNames = (text: string): string => + text + .replace(/玩家1/gi, hostNickName) + .replace(/玩家2/gi, guestNickName); + + const verdictText = replaceNames(judgment.verdict); + const punishmentTask = { + role: loserId as 'host' | 'guest', + task: replaceNames(judgment.punishmentTask), + }; + + // 7. Build verdict result return { caseNumber: judgment.caseNumber, winnerId: winnerId as 'host' | 'guest', @@ -107,7 +121,7 @@ export class VerdictMapperService { host: hostScores, guest: guestScores, }, - verdict: judgment.verdict, + verdict: verdictText, punishmentTask, secretReports, }; diff --git a/miniprogram/packageA/pages/drum-room/index.ts b/miniprogram/packageA/pages/drum-room/index.ts index 3be625d..cfd3833 100644 --- a/miniprogram/packageA/pages/drum-room/index.ts +++ b/miniprogram/packageA/pages/drum-room/index.ts @@ -116,7 +116,7 @@ function getScoreKey(role: EPlayerRole): 'organizerScore' | 'joinerScore' { const RUNNING_DURATION_MS: number = 10000; const RESULT_DISPLAY_MS: number = 2000; const FLY_TEXT_DURATION_MS: number = 800; -const MAX_TAPS: number = 30; +const MAX_TAPS: number = 60; const MAX_SCORE_FOR_PROGRESS: number = MAX_TAPS; Page({