Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions backend/src/services/core/verdict-mapper.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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',
Expand All @@ -107,7 +121,7 @@ export class VerdictMapperService {
host: hostScores,
guest: guestScores,
},
verdict: judgment.verdict,
verdict: verdictText,
punishmentTask,
secretReports,
};
Expand Down
2 changes: 1 addition & 1 deletion miniprogram/packageA/pages/drum-room/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<IDrumPageData, WechatMiniprogram.Page.CustomOption & PrivateState>({
Expand Down
140 changes: 122 additions & 18 deletions miniprogram/packageA/pages/waiting-room/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down Expand Up @@ -68,6 +74,7 @@ interface IWaitingRoomCustomOption extends WechatMiniprogram.Page.CustomOption {
confirmButtonAnim: WechatMiniprogram.Animation | null;
isCreatingRoom: boolean;
isJoiningRoom: boolean;
pendingRoomId: string | null;
}

/**
Expand All @@ -94,7 +101,13 @@ const WAITING_TEXTS: string[] = [
Page<IWaitingRoomPageData, IWaitingRoomCustomOption>({
data: {
viewMode: 'entry',
// 弹窗相关
// 昵称弹窗相关
showNicknameModal: false,
nicknameInput: '',
nicknameCharCount: 0,
isNicknameConfirmDisabled: true,
nicknameModalAnimation: {} as WechatMiniprogram.AnimationExportResult,
// 加入房间弹窗相关
showJoinModal: false,
roomCodeInput: '',
roomCodeDisplay: ['', '', '', '', '', ''],
Expand Down Expand Up @@ -128,6 +141,7 @@ Page<IWaitingRoomPageData, IWaitingRoomCustomOption>({
// 请求锁
isCreatingRoom: false,
isJoiningRoom: false,
pendingRoomId: null,

onLoad(options: Record<string, string | undefined>): void {
this.initAnimations();
Expand All @@ -138,22 +152,16 @@ Page<IWaitingRoomPageData, IWaitingRoomCustomOption>({
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);
}
},

Expand Down Expand Up @@ -206,6 +214,102 @@ Page<IWaitingRoomPageData, IWaitingRoomCustomOption>({
});
},

/**
* 预填房间号并弹出加入房间弹窗
*/
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<IAppOption>();
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;
},

/**
* 初始化动画实例
*/
Expand Down
60 changes: 60 additions & 0 deletions miniprogram/packageA/pages/waiting-room/index.wxml
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,63 @@
bindcomplete="onCountdownComplete"
></countdown>
</view>

<!-- 昵称设置弹窗 -->
<view
wx:if="{{ showNicknameModal }}"
class="nickname-modal"
catchtouchmove="onNicknameModalMaskTap"
>
<!-- 遮罩层 -->
<view
class="nickname-modal__overlay"
bindtap="onNicknameModalMaskTap"
></view>

<!-- 弹窗面板 -->
<view
class="nickname-modal__panel"
animation="{{ nicknameModalAnimation }}"
catchtap=""
>
<!-- 拖拽指示条 -->
<view class="nickname-modal__drag-bar">
<view class="nickname-modal__drag-line"></view>
</view>

<!-- 标题 -->
<view class="nickname-modal__title">
<text class="nickname-modal__title-text">堂下何人,报上名来!</text>
</view>

<!-- 昵称输入框 -->
<view class="nickname-modal__input-wrapper">
<input
class="nickname-modal__input"
type="nickname"
placeholder="点击从微信昵称中选择"
maxlength="12"
value="{{ nicknameInput }}"
bindinput="onNicknameInput"
/>
<text class="nickname-modal__char-count">{{ nicknameCharCount }}/12</text>
</view>

<!-- 确认按钮 -->
<view class="nickname-modal__actions">
<styled-button
text="击鼓申冤!"
color="red"
disabled="{{ isNicknameConfirmDisabled }}"
showShine="{{ !isNicknameConfirmDisabled }}"
bindtap="onNicknameConfirm"
></styled-button>
<view
class="nickname-modal__skip"
bindtap="onNicknameSkip"
>
<text class="nickname-modal__skip-text">稍后再说</text>
</view>
</view>
</view>
</view>
Loading
Loading