let GlbGames = null; const AngerBar = { props: ['angerLevel', 'angerName'], computed: { barColor() { if (this.angerLevel < 30) return 'bg-yellow-300'; if (this.angerLevel < 60) return 'bg-yellow-500'; return 'bg-red-500'; } }, template: `
{{angerLevel}}
{{ angerName }}
` }; const ProudBar = { props: ['proudLevel', 'proudName'], computed: { barColor() { if (this.proudLevel < 30) return 'bg-blue-200'; if (this.proudLevel < 60) return 'bg-blue-300'; return 'bg-blue-500'; } }, template: `
{{proudLevel}}
{{ proudName }}
` }; const FloatingNumber = { props: ['value', 'proud', 'init'], data() { return { isVisible: false } }, mounted() { if (!this.init) { this.animate(); } }, methods: { animate() { this.isVisible = true; setTimeout(() => { this.isVisible = false; }, 2000); } }, template: `
😎{{proud}}
😭{{ value }}
` }; const CountdownTimer = { props: ['duration', 'onTimeout'], data() { return { remainingTime: this.duration, intervalId: null, isStopped: false }; }, methods: { startTimer() { this.remainingTime = this.duration; this.intervalId = setInterval(() => { if (!this.isStopped) { this.remainingTime--; if (this.remainingTime <= 0) { this.stopTimer(); this.onTimeout(); } } }, 1000); }, stopTimer() { clearInterval(this.intervalId); this.isStopped = true; }, resetTimer() { this.stopTimer(); this.isStopped = false; this.startTimer(); } }, mounted() { this.startTimer(); }, beforeUnmount() { this.stopTimer(); }, template: `
倒计时: {{ Math.floor(remainingTime / 60) }}:{{ (remainingTime % 60).toString().padStart(2, '0') }}
` }; const ProfilePanel = { props: { message: Object, characterInfo: Object, closeProfile: Function, showFullSizeImage: Function }, template: `

{{ message.name }}

{{ characterInfo.bio }}

{{ characterInfo.YS_key }}

{{ characterInfo.YS }}

{{ characterInfo.ZB_key }}

{{ characterInfo.ZB }}

` }; const ChatInterface = { components: { AngerBar, ProudBar, CountdownTimer, FloatingNumber, ProfilePanel }, data() { return { allGamesInfo: null, showIntro: true, showDirectBTHButton: false, isGoalExpanded: false, goalText: "自由探索", beforeSendMessage : true, characterInfo : null, myself: null, myselfName: null, isLoading: false, stoppingOldChat: false, showOverlay: false, overlayImage: '', overlayText: '', overlayOwner: '', overlayOwnerText: '', showFullSizeAvatar: false, showClearCacheConfirm: false, showForceEndConfirm: false, dontForceEndConfirmAgain: false, endSessionText: "确认结束对话?", activeProfileId: null, fullSizeAvatarUrl: '', longPressTimer: null, longPressThreshold: 500, // **双击头像 start*** lastTap: 0, tapTimeout: 300, // **双击头像 end*** isTimeout: false, isSidebarActive: false, isMembersPanelActive: false, isHelpPanelActive: false, isMobile: false, newMessage: '', textareaHeight: '35px', // 设置初始高度 minHeight: '35px', // 设置最小高度 maxHeight: '150px', // 设置最大高度 showPopup: false, popupMessage: '敬请期待!', mentionList: [], mentionListIndex: -1, // New: Index to track the selected mention in the list showMentionList: false, selectedMention: null, countdownDuration: 5 * 60, conversionCount: 0, maxGameRound: 0, contacts: [], currentChat: { activeGameType: 0, name: '', messages: [], members: [], updatedAt: 0, isUpdatingMessage: false, isStopped: false, }, } }, methods: { async resetData(gameType) { Object.assign(this.$data, this.$options.data.call(this)); this.showIntro = false; this.currentChat.activeGameType = gameType; await this.fetchAllGames(); this.getActiveGameInfo(gameType); console.log("characterInfo"); console.log(this.characterInfo); window.utils.setActiveGameType(this.currentChat.activeGameType); this.resetCountdown(); }, getActiveGameInfo(gameType) { for (let i = 0; i < this.allGamesInfo.length; i++) { const gameInfo = this.allGamesInfo[i]; if (gameInfo.type === gameType) { this.currentChat.name = gameInfo.name; this.characterInfo = gameInfo.roles; this.myself = this.characterInfo[gameInfo.myself]; this.myselfName = gameInfo.myself; this.maxGameRound = gameInfo.max_game_round; } } }, toggleSidebar() { this.isSidebarActive = !this.isSidebarActive; }, toggleMembersPanel() { this.isMembersPanelActive = !this.isMembersPanelActive; }, toggleHelpPanel() { this.isHelpPanelActive = !this.isHelpPanelActive; }, toggleShowIntro() { this.showIntro = !this.showIntro; }, backToHome() { const dont = window.utils.getDontShowConfirm(); if (dont) { this.showIntro = true; } else { if (!this.getBeforeSendMessage()) { this.showForceEnd('本局仍在进行中,您是否要先结束对话?', true); } else { this.showIntro = true; } } }, getCharacterInfo(role) { return this.characterInfo[role] || {}; }, getBeforeSendMessage() { return this.beforeSendMessage; }, toggleGoal() { this.isGoalExpanded = true; setTimeout(() => { this.isGoalExpanded = false; }, 5000); }, closeGoal() { this.isGoalExpanded = false; }, showFullSizeImage(avatarUrl) { this.fullSizeAvatarUrl = avatarUrl; this.showFullSizeAvatar = true; }, closeFullSizeImage() { this.showFullSizeAvatar = false; }, toggleProfile(messageId) { if (this.activeProfileId === messageId) { this.activeProfileId = null; } else { this.activeProfileId = messageId; } }, closeProfile() { this.activeProfileId = null; }, startLongPress(event, message) { event.preventDefault(); event.stopPropagation(); this.isLongPress = false; this.longPressTimer = setTimeout(() => { this.isLongPress = true; this.mentionUser(message); }, this.longPressThreshold); }, endLongPress(event, message) { event.preventDefault(); event.stopPropagation(); if (this.longPressTimer) { clearTimeout(this.longPressTimer); } this.isLongPress = false; }, preventDefaultTouch(event) { event.stopPropagation(); event.preventDefault(); }, handleAvatarInteraction(event, message) { if (event.type === 'dblclick') { event.preventDefault(); event.stopPropagation(); this.mentionUser(message); } else if (event.type === 'touchend') { // 移动端快速点击 const currentTime = new Date().getTime(); const tapLength = currentTime - this.lastTap; if (tapLength < this.tapTimeout && tapLength > 0) { this.mentionUser(message); event.preventDefault(); event.stopPropagation(); } this.lastTap = currentTime; } }, mentionUser(message) { if (message.role !== this.myselfName) { const atIndex = this.newMessage.lastIndexOf('@'); if (atIndex !== -1) { this.newMessage = this.newMessage.slice(0, atIndex); } this.newMessage += `@${message.name} `; this.selectedMention = this.currentChat.members.find(member => member.refId === message.role); // this.$refs.messageInput.focus(); this.$nextTick(() => { this.$refs.messageInput.focus(); }); } }, showFullScreenOverlay(imageUrl, text, owner, ownerText) { this.overlayImage = imageUrl; this.overlayText = text; if (owner) { const info = this.characterInfo[owner]; if (info) { this.overlayOwner = info['name']; } } if (ownerText) { this.overlayOwnerText = ownerText; } this.showOverlay = true; }, closeOverlay() { this.showOverlay = false; }, showPopMessage(content) { this.popupMessage = content; this.showPopup = true; }, closePopMessage() { this.showPopup = false; }, showAutoPopMessage(content) { this.showPopMessage(content); setTimeout(() => { this.closePopMessage(); }, 1000); }, toggleClearCacheConfirm() { this.showClearCacheConfirm = !this.showClearCacheConfirm; }, clearCache() { document.cookie.split(";").forEach((c) => { document.cookie = c .replace(/^ +/, "") .replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/"); }); localStorage.clear(); // 尝试清除浏览器缓存 if ('caches' in window) { caches.keys().then((names) => { names.forEach(name => { caches.delete(name); }); }); } this.showClearCacheConfirm = false; // Show feedback to user this.showPopMessage("缓存已清除,页面即将刷新"); setTimeout(() => { this.closePopMessage(); window.location.href = window.location.pathname + '?t=' + Date.now(); }, 1000); }, updateAngerLevel(role, scores) { const change = scores[1] - this.characterInfo[role].angerLevel; const proudChange = scores[0] - this.characterInfo[role].proudLevel; this.characterInfo[role].proudLevel = scores[0]; this.characterInfo[role].angerLevel = scores[1]; this.characterInfo[role].angerChange = change; this.characterInfo[role].proudChange = proudChange; }, async updateMessage(json_res, isStart=true) { try { this.currentChat.isUpdatingMessage = true; if (json_res && json_res.status === 0) { const data = json_res.data; const allowSpeakers = data.allowed_speaker; if (allowSpeakers && allowSpeakers.length > 0) { this.currentChat.members = []; for (const speaker of allowSpeakers) { const member = this.characterInfo[speaker]; this.currentChat.members.push(member); } } if (data.target && data.target.length > 0) { this.goalText = data.target; if (isStart) { this.toggleGoal(); } } this.conversionCount = data.game_round; const messages = data.messages; const updatedAt = data.timestamp; if (messages.length > 0 && updatedAt > this.currentChat.updatedAt) { this.currentChat.updatedAt = updatedAt; const agentScores = data.agent_scores; for (const [role, scoreArr] of Object.entries(agentScores)) { this.updateAngerLevel(role, scoreArr); } if (isStart) { //切换游戏要清空历史 this.currentChat.messages = []; } for (let index = this.currentChat.messages.length; index < messages.length; index++) { const message = messages[index]; const id = index + 1; const content = message.content; const role = message.name; const name = this.characterInfo[role].name; let sent = false; if (role === this.myselfName) { sent = true; } const avatar = this.characterInfo[role].avatar; let data = { id: id, content: content, sent: sent, name: name, avatar: avatar, role: role, angerLevel: this.characterInfo[role].angerLevel, proudLevel: this.characterInfo[role].proudLevel, angerChange: this.characterInfo[role].angerChange, angerName: this.characterInfo[role].ZB_key, proudChange: this.characterInfo[role].proudChange, proudName: this.characterInfo[role].YS_key, }; this.currentChat.messages.push(data); if (!isStart) { await new Promise(resolve => setTimeout(resolve, 500)); } } this.$nextTick(() => { this.scrollToBottom(); }); } } } finally { this.currentChat.isUpdatingMessage = false; } }, scrollToBottom() { const chatContainer = this.$refs.chatContainer; if (chatContainer) { chatContainer.scrollTop = chatContainer.scrollHeight; } }, async startSession(gameType = 0) { try { if (gameType === this.currentChat.activeGameType && !this.currentChat.isStopped) { this.showIntro = false; return; } // 刚刷新的时候,this.currentChat.activeGameType=0,不会触发stop // 切换游戏的时候,this.currentChat.activeGameType > 0,会触发stop if (this.currentChat.activeGameType > 0) { // try { this.stoppingOldChat = true; await this.stop(this.currentChat.activeGameType); } finally { this.stoppingOldChat = false; } } this.showIntro = false; await this.resetData(gameType); this.showPopMessage("加载中..."); const json_res = await window.utils.start(gameType); if (json_res) { await this.updateMessage(json_res); } else { window.alert("Oops~😭请重新再刷新一次!") } } finally { this.closePopMessage(); } }, adjustTextareaHeight(isFirstLoad=true) { const textarea = this.$refs.messageInput; if (!textarea) { return; } textarea.style.height = this.minHeight; // 首先设置为最小高度 if (isFirstLoad) { textarea.style.height = this.minHeight; this.textareaHeight = this.minHeight; } else { textarea.style.height = this.minHeight; // 首先设置为最小高度 const newHeight = Math.max( parseInt(this.minHeight), Math.min(textarea.scrollHeight, parseInt(this.maxHeight)) ); textarea.style.height = `${newHeight}px`; this.textareaHeight = `${newHeight}px`; } }, resetTextareaHeight() { this.textareaHeight = this.minHeight; this.$nextTick(() => { this.adjustTextareaHeight(); }); }, handleInput(event) { this.adjustTextareaHeight(false); const atIndex = this.newMessage.lastIndexOf('@'); if (atIndex !== -1 && atIndex === this.newMessage.length - 1) { this.showMentionList = true; this.mentionList = this.currentChat.members.filter(member => member.name !== this.characterInfo[this.myselfName].name); this.mentionListIndex = -1; // Reset the index when showing the list } else if (atIndex !== -1) { const query = this.newMessage.slice(atIndex + 1).toLowerCase(); this.mentionList = this.currentChat.members.filter(member => member.name !== this.myself.name && member.name.toLowerCase().includes(query) ); this.showMentionList = this.mentionList.length > 0; this.mentionListIndex = -1; // Reset the index when filtering the list } else { this.showMentionList = false; this.mentionListIndex = -1; // Reset the index when hiding the list } }, async handleKeydown(event) { if (this.showMentionList) { switch (event.key) { case 'Tab': event.preventDefault(); // Prevent default tab behavior this.mentionListIndex = (this.mentionListIndex + 1) % this.mentionList.length; break; case 'Enter': event.preventDefault(); // Prevent sending the message if (this.mentionListIndex !== -1) { this.selectMention(this.mentionList[this.mentionListIndex]); } break; case 'Escape': this.closeMentionList(); break; } } else if (event.key === 'Enter') { await this.sendMessage(); } }, selectMention(member) { const atIndex = this.newMessage.lastIndexOf('@'); this.newMessage = this.newMessage.slice(0, atIndex) + '@' + member.name + ' '; this.closeMentionList(); this.selectedMention = member; this.mentionListIndex = -1; // Reset the index after selection this.$refs.messageInput.focus(); }, closeMentionList() { this.showMentionList = false; this.selectedMention = null; this.mentionListIndex = -1; }, resetCountdown() { if (this.$refs.countdownTimer) { this.$refs.countdownTimer.resetTimer(); } }, async handleTimeout() { this.isTimeout = true; this.showFullScreenOverlay("https://pic1.imgdb.cn/item/677e4b69d0e0a243d4f1f6d1.png", "会话已过期", null, null); }, async sendMessage() { if (this.newMessage.trim() && !this.showMentionList) { this.beforeSendMessage = false; this.resetCountdown(); const data = { id: this.currentChat.messages.length + 1, content: this.newMessage, sent: true, role: this.myselfName, name: this.myself.name, avatar: this.myself.avatar }; this.currentChat.messages.push(data); this.resetTextareaHeight(); this.$nextTick(() => { this.scrollToBottom(); }); const messageData = this.newMessage; this.newMessage = ''; const user_tag = this.selectedMention ? this.selectedMention.refId : null; this.closeMentionList(); // Start loading this.isLoading = true; try{ await window.utils.send(messageData, user_tag, this.currentChat.activeGameType); const his_json_res = await window.utils.history(this.currentChat.activeGameType); if (his_json_res) { await this.updateMessage(his_json_res, false); const data = his_json_res.data; if (data && data.is_finished) { this.$refs.countdownTimer.stopTimer(); // Stop the timer this.showFullScreenOverlay( "https://pic1.imgdb.cn/item/677e4b69d0e0a243d4f1f6cf.png", data.player_finial_title, data.summary_character, data.summary_content); await this.stop(this.currentChat.activeGameType); } } }finally { this.isLoading = false; } } }, async restart(gameType){ try { this.showIntro = false; await this.resetData(gameType); this.showPopMessage("加载中...") const json_res = await window.utils.restart(gameType); if (json_res) { await this.updateMessage(json_res); } else { window.alert("Oops~😭请重新再刷新一次!") } } finally { this.closePopMessage(); } }, async stop(gameType) { await window.utils.stop(gameType); this.currentChat.isStopped = true; }, showForceEnd(content, isDirectBackToHome=false) { if (isDirectBackToHome) { this.showDirectBTHButton = true; } this.endSessionText = content; this.showForceEndConfirm = true; }, closeForceEndConfirm() { this.showForceEndConfirm = false; }, directBackToHome() { this.closeForceEndConfirm(); this.showDirectBTHButton = false; this.showIntro = true; this.dontForceEndConfirmAgain = true; window.utils.setDontShowConfirm(this.dontForceEndConfirmAgain); }, backToHomeFromEnd() { this.closeOverlay(); this.showIntro = true; }, async endSession(gameType) { try{ this.closeForceEndConfirm(); const json_res = await window.utils.forceEnd(gameType); if (json_res && json_res.status === 0) { const data = json_res.data; if (data && data.is_finished) { this.$refs.countdownTimer.stopTimer(); // Stop the timer this.showFullScreenOverlay( "https://pic1.imgdb.cn/item/677e4b69d0e0a243d4f1f6cf.png", data.player_finial_title, data.summary_character, data.summary_content); } await this.stop(gameType); } } finally { this.isLoading = false; } }, async refreshPage() { this.resetCountdown(); location.reload(); }, checkScreenSize() { this.isMobile = window.innerWidth <= 768; if (!this.isMobile) { this.isSidebarActive = false; } }, async fetchAllGames() { if (!GlbGames) { GlbGames = await window.utils.games(); console.log("GlbGames"); console.log(GlbGames); } this.allGamesInfo = GlbGames; console.log("allGamesInfo"); console.log(this.allGamesInfo); this.contacts = []; for (let i = 0; i < this.allGamesInfo.length; i++) { const gameInfo = this.allGamesInfo[i]; this.contacts.push( { type: gameInfo.type, name: gameInfo.name, lastMessage: '最后一条消息', time: '12:00', avatar: 'https://www.helloimg.com/i/2024/12/31/677383e08a592.jpg', active: (gameInfo.type === this.currentChat.activeGameType), } ); } }, async restoreActiveGame() { const activeType = window.utils.getActiveGameType(); if (activeType > 0) { await this.startSession(activeType); } }, }, async mounted() { this.$nextTick(() => { this.adjustTextareaHeight(); }); this.checkScreenSize(); window.addEventListener('resize', this.checkScreenSize); await this.fetchAllGames(); await this.restoreActiveGame(); window.addEventListener('beforeunload', this.resetCountdown); }, updated() { this.scrollToBottom(); }, unmounted() { window.removeEventListener('resize', this.checkScreenSize); window.removeEventListener('beforeunload', this.resetCountdown); }, template: `

群成员

{{ member.name }}
{{ member.bio }}

帮助

帮助手册
清除缓存
返回首页
查看局内目标
重新开始
结算本局
查看群成员
输入语音
输入表情

🎉🎉过年大作战🎉🎉

{{contact.name}}

进行中

敬请期待

© 2023 - 2025 ACT Inc. All Rights Reserved

对话(轮): {{conversionCount}}/{{maxGameRound}}
{{currentChat.name}}

本局目标:{{ goalText }}

{{ message.name }}
{{ message.content }}