前端轮数实现以及后端WxReviewServiceImpl修改

hot-fix
chantouRichard 2 months ago
parent 3a814e1214
commit a89d6bb9ec

@ -64,7 +64,7 @@ public class WxReviewServiceImpl implements WxReviewService {
+ "},"
+ "{"
+ "\"role\": \"" + roleUser + "\","
+ "\"content\": \"" + content + "\""
+ "\"content\": \"" + escapeJson(content) + "\""
+ "}"
+ "],"
+ "\"model\": \"" + model + "\","
@ -106,11 +106,25 @@ public class WxReviewServiceImpl implements WxReviewService {
// 工具方法:转义 JSON 字符串中的特殊字符
private String escapeJson(String input) {
if (input == null) return "";
return input.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
StringBuilder escaped = new StringBuilder();
for (char c : input.toCharArray()) {
switch (c) {
case '"': escaped.append("\\\""); break;
case '\\': escaped.append("\\\\"); break;
case '\b': escaped.append("\\b"); break;
case '\f': escaped.append("\\f"); break;
case '\n': escaped.append("\\n"); break;
case '\r': escaped.append("\\r"); break;
case '\t': escaped.append("\\t"); break;
default:
if (c <= 0x1F) { // 处理其他控制字符
escaped.append(String.format("\\u%04x", (int) c));
} else {
escaped.append(c);
}
}
}
return escaped.toString();
}
@Override

@ -23,7 +23,11 @@
"@dcloudio/uni-mp-weixin": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-xhs": "3.0.0-4040520250104002",
"@dcloudio/uni-quickapp-webview": "3.0.0-4040520250104002",
"markdown-it": "^14.1.0",
"marked": "^15.0.12",
"mini-html-parser2": "^0.3.0",
"pinia": "^3.0.2",
"towxml": "^3.0.6",
"vue": "^3.5.15",
"vue-i18n": "^9.1.9"
},
@ -5670,6 +5674,12 @@
"node_modules/dom-walk": {
"version": "0.1.2"
},
"node_modules/domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmmirror.com/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
"license": "BSD-2-Clause"
},
"node_modules/domexception": {
"version": "2.0.1",
"dev": true,
@ -5691,6 +5701,15 @@
"node": ">=8"
}
},
"node_modules/domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmmirror.com/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "1"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"dev": true,
@ -6276,6 +6295,15 @@
"node": ">= 0.6"
}
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmmirror.com/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/execa": {
"version": "5.1.1",
"dev": true,
@ -7995,6 +8023,15 @@
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
"node_modules/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"license": "MIT",
"dependencies": {
"uc.micro": "^2.0.0"
}
},
"node_modules/load-bmfont": {
"version": "1.4.2",
"license": "MIT",
@ -8148,6 +8185,41 @@
"tmpl": "1.0.5"
}
},
"node_modules/markdown-it": {
"version": "14.1.0",
"resolved": "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.0.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
"linkify-it": "^5.0.0",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
},
"bin": {
"markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/markdown-it/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
"node_modules/marked": {
"version": "15.0.12",
"resolved": "https://registry.npmmirror.com/marked/-/marked-15.0.12.tgz",
"integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"dev": true,
@ -8156,6 +8228,12 @@
"node": ">= 0.4"
}
},
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
"license": "MIT"
},
"node_modules/media-typer": {
"version": "0.3.0",
"dev": true,
@ -8271,6 +8349,22 @@
"dom-walk": "^0.1.0"
}
},
"node_modules/mini-html-parser2": {
"version": "0.3.0",
"resolved": "https://registry.npmmirror.com/mini-html-parser2/-/mini-html-parser2-0.3.0.tgz",
"integrity": "sha512-W4x1MCmtlnAH5M9qQ1WbRn+hTvv7bdrJx4VI+6SD0MUZatW/6K7v213Aidx7VDQmSKoRv+iAn5TswJnesOs71Q==",
"dependencies": {
"domhandler": "^2.4.2",
"entities": "^1.1.1",
"events": "^3.0.0"
}
},
"node_modules/mini-html-parser2/node_modules/entities": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
"license": "BSD-2-Clause"
},
"node_modules/minimatch": {
"version": "3.1.2",
"dev": true,
@ -8965,6 +9059,15 @@
"node": ">=6"
}
},
"node_modules/punycode.js": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/qrcode-reader": {
"version": "1.0.4",
"license": "Apache-2.0"
@ -10137,6 +10240,47 @@
"node": ">= 4.0.0"
}
},
"node_modules/towxml": {
"version": "3.0.6",
"resolved": "https://registry.npmmirror.com/towxml/-/towxml-3.0.6.tgz",
"integrity": "sha512-AiEEyTYemk3xLlypfihR+vr/slyjvQZvZbGGXQdRklwYY8dbDEGUDopFwAtfW7tVkOc09rfZ7yu040vjJU84cw==",
"license": "MIT",
"dependencies": {
"fs-extra": "^8.1.0"
}
},
"node_modules/towxml/node_modules/fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
},
"engines": {
"node": ">=6 <7 || >=8"
}
},
"node_modules/towxml/node_modules/jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
"license": "MIT",
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/towxml/node_modules/universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"license": "MIT",
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/tr46": {
"version": "2.1.0",
"dev": true,
@ -10191,6 +10335,12 @@
"is-typedarray": "^1.0.0"
}
},
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"license": "MIT"
},
"node_modules/ufo": {
"version": "1.5.4",
"license": "MIT"

@ -25,7 +25,11 @@
"@dcloudio/uni-mp-weixin": "3.0.0-4040520250104002",
"@dcloudio/uni-mp-xhs": "3.0.0-4040520250104002",
"@dcloudio/uni-quickapp-webview": "3.0.0-4040520250104002",
"markdown-it": "^14.1.0",
"marked": "^15.0.12",
"mini-html-parser2": "^0.3.0",
"pinia": "^3.0.2",
"towxml": "^3.0.6",
"vue": "^3.5.15",
"vue-i18n": "^9.1.9"
},

@ -1,13 +1,20 @@
{
"miniprogramRoot": "",
"miniprogramRoot": "./",
"libVersion": "3.0.2",
"appid": "wxdc5c8df2ec2453e4",
"compileType": "miniprogram",
"packOptions": {
"ignore": [],
"ignore": [{ "type": "folder", "value": "node_modules" }],
"include": []
},
"setting": {
"packNpmManmediately": true,
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./"
}
],
"babelSetting": {
"ignore": [],
"disablePlugins": [],
@ -19,4 +26,4 @@
"tabIndent": "insertSpaces",
"tabSize": 2
}
}
}

@ -2,12 +2,7 @@
<view class="debate-component">
<!-- 动态背景元素 -->
<view class="animated-bg">
<view
v-for="i in 6"
:key="i"
class="bg-circle"
:style="getRandomCircleStyle()"
></view>
<view v-for="i in 6" :key="i" class="bg-circle" :style="getRandomCircleStyle()"></view>
</view>
<!-- 顶部卡片 - 可收缩 -->
@ -15,17 +10,12 @@
<view class="card-header" @click="toggleCard">
<view class="card-icon-wrapper">
<view class="card-icon">
<image
src="/static/icons/robot-2-line.png"
mode="aspectFit"
></image>
<image src="/static/icons/robot-2-line.png" mode="aspectFit"></image>
</view>
</view>
<view class="card-text">
<view class="card-title">模拟辩论</view>
<view class="card-content" v-if="!isCardCollapsed"
>与AI进行实时辩论对练提升应变能力</view
>
<view class="card-content" v-if="!isCardCollapsed">AI</view>
</view>
<view class="card-icon-wrapper">
<view class="card-icon" @click.stop="showHistory = true">
@ -33,14 +23,10 @@
</view>
</view>
<view class="collapse-icon">
<image
:src="
isCardCollapsed
? '/static/icons/arrow-down-s-line.png'
: '/static/icons/arrow-up-s-line.png'
"
mode="aspectFit"
></image>
<image :src="isCardCollapsed
? '/static/icons/arrow-down-s-line.png'
: '/static/icons/arrow-up-s-line.png'
" mode="aspectFit"></image>
</view>
</view>
</view>
@ -48,32 +34,17 @@
<!-- 辩论主题选择器 -->
<view class="topic-selector" v-if="!isCardCollapsed">
<scroll-view scroll-x class="topic-scroll" show-scrollbar="false">
<view
v-for="(topic, idx) in debateTopics"
:key="idx"
:class="['topic-pill', { active: selectedTopic === idx }]"
@click="selectTopic(idx)"
>
<view v-for="(topic, idx) in debateTopics" :key="idx" :class="['topic-pill', { active: selectedTopic === idx }]"
@click="selectTopic(idx)">
{{ topic }}
</view>
</scroll-view>
</view>
<!-- 聊天展示区 -->
<scroll-view
class="chat-area"
scroll-y
:scroll-into-view="scrollToView"
scroll-with-animation
>
<view
v-for="(msg, index) in messages"
:key="index"
:id="'msg' + index"
class="chat-message"
:class="msg.role === 'user' ? 'from-user' : 'from-ai'"
@longpress="onLongPress()"
>
<scroll-view class="chat-area" scroll-y :scroll-into-view="scrollToView" scroll-with-animation>
<view v-for="(msg, index) in messages" :key="index" :id="'msg' + index" class="chat-message"
:class="msg.role === 'user' ? 'from-user' : 'from-ai'" @longpress="onLongPress()">
<view class="avatar" v-if="msg.role === 'ai'">AI</view>
<view class="bubble">
<block v-if="msg.loading">
@ -91,22 +62,41 @@
</view>
</scroll-view>
<!-- 轮数选择与进度条区域 -->
<view class="rounds-control" :class="{ 'rounds-selected': debateRounds > 0 }">
<!-- 未选择轮数时显示选择按钮 -->
<view v-if="roundsSelected === false" class="select-rounds-btn" @click="showRoundsPopup = true">
<image src="/static/icons/repeat-line.png" mode="aspectFit"></image>
<text>选择辩论轮数</text>
</view>
<!-- 已选择轮数时显示进度条 -->
<view v-else class="rounds-selected-container">
<view class="rounds-label" @click="showRoundsPopup = true">
<image src="/static/icons/repeat-line.png" mode="aspectFit"></image>
<text>{{ debateRounds }}回合</text>
</view>
<view class="progress-container">
<view class="progress-bar">
<view class="progress-inner" :style="{ width: progressPercentage + '%' }"></view>
</view>
<view class="rounds-counter">{{ currentRound }}/{{ debateRounds }}</view>
<!-- 添加复盘按钮 -->
<view v-if="showReviewButton" class="review-button" @click="showReviewModal">
<image src="/static/icons/file-chart-line.png" mode="aspectFit"></image>
</view>
</view>
</view>
</view>
<!-- 输入框与发送按钮 -->
<view class="chat-input">
<view class="input-group">
<view class="textarea-container">
<textarea
class="textarea-box"
v-model="content"
placeholder="输入你的辩论观点与AI进行思辨交锋"
auto-height
maxlength="1000"
/>
<textarea class="textarea-box" v-model="content" placeholder="输入你的辩论观点与AI进行思辨交锋" auto-height
maxlength="1000" />
<button class="send-button-embedded" @click="sendMessage()">
<image
src="/static/icons/send-plane-fill.png"
mode="aspectFit"
></image>
<image src="/static/icons/send-plane-fill.png" mode="aspectFit"></image>
</button>
</view>
</view>
@ -115,22 +105,59 @@
<!-- 底部安全区域 -->
<view class="safe-area-bottom"></view>
<Popup
:visible="showSheet"
buttonText="开始复盘"
buttonIcon="🧠"
@close="showSheet = false"
@click="handleSheetClick"
/>
<ConversationHistory
:visible="showHistory"
:history-list="chatHistory"
:type="1"
@update:visible="showHistory = $event"
@select="handleSelect"
@createNew="createNew"
/>
<Popup :visible="showSheet" buttonText="开始复盘" buttonIcon="🧠" @close="showSheet = false"
@click="handleSheetClick" />
<!-- 轮数选择弹窗 -->
<view v-if="showRoundsPopup" class="rounds-popup-mask" @click="showRoundsPopup = false">
<view class="rounds-popup" @click.stop>
<view class="popup-header">
<view class="popup-title">选择辩论轮数</view>
<view class="close-icon" @click="showRoundsPopup = false">
<image src="/static/icons/close-line.png" mode="aspectFit"></image>
</view>
</view>
<view class="rounds-options">
<view class="round-option" :class="{ selected: selectedOption === 1 }" @click="selectRounds(1)">
<view class="option-icon"></view>
<view class="option-text">
<view class="option-title">快速交锋</view>
<view class="option-desc">10回合 · 适合快速练习</view>
</view>
</view>
<view class="round-option" :class="{ selected: selectedOption === 2 }" @click="selectRounds(2)">
<view class="option-icon">🔍</view>
<view class="option-text">
<view class="option-title">深度辩论</view>
<view class="option-desc">20回合 · 深入探讨话题</view>
</view>
</view>
</view>
<button class="confirm-button-selectRounds" @click="confirmRounds"></button>
</view>
</view>
<!-- 复盘确认弹窗 -->
<view v-if="showReviewConfirm" class="review-confirm-mask" @click="showReviewConfirm = false">
<view class="review-confirm-popup" @click.stop>
<view class="popup-header">
<view class="popup-title">辩论完成</view>
</view>
<view class="popup-content">
<text>辩论已完成{{ debateRounds }}回合是否立即进行复盘分析</text>
</view>
<view class="popup-buttons">
<button class="cancel-button" @click="showReviewConfirm = false">稍后再说</button>
<button class="confirm-button-gotoReview" @click="startReview"></button>
</view>
</view>
</view>
<ConversationHistory :visible="showHistory" :history-list="chatHistory" :type="1"
@update:visible="showHistory = $event" @select="handleSelect" @createNew="createNew" />
</view>
</template>
@ -142,7 +169,7 @@ import ConversationHistory from "./ConversationHistory.vue";
import { useTokenStore } from "../stores/tokenStore";
export default {
components: { Popup,ConversationHistory },
components: { Popup, ConversationHistory },
props: {
argument: {
type: Object,
@ -152,13 +179,16 @@ export default {
mounted() {
const pinia = this.$pinia;
const store = useArgumentStore(pinia);
if(store.selectedArgument.content)this.content = store.selectedArgument.content;
if (store.selectedArgument.content) this.content = store.selectedArgument.content;
this.getHistoryList();
this.conversationId = useDebateStore().conversationId;
console.log("conversationId:", this.conversationId);
this.messages = useDebateStore().conversation;
//
this.showRoundsPopup = true;
},
data() {
@ -167,8 +197,8 @@ export default {
showHistory: false,
chatHistory: ["test1", "test2"],
showSheet:false,
StoreHistory:"",
showSheet: false,
StoreHistory: "",
input: "",
messages: [
{
@ -189,8 +219,39 @@ export default {
],
selectedTopic: -1,
isCardCollapsed: false, //
//
showRoundsPopup: false, //
roundsSelected: false, //
debateRounds: 0, //
currentRound: 0, //
selectedOption: 0, //
showReviewConfirm: false,//
showReviewButton: false,//
};
},
computed: {
//
progressPercentage() {
if (this.debateRounds === 0) return 0;
return (this.currentRound / this.debateRounds) * 100;
},
},
watch: {
//
currentRound(newVal) {
if (newVal >= this.debateRounds && this.debateRounds > 0) {
//
setTimeout(() => {
this.showReviewConfirm = true;
}, 1000);
}
}
},
methods: {
async getHistoryList() {
return new Promise((resolve, reject) => {
@ -263,15 +324,15 @@ export default {
success: (res) => {
console.log("res:", res);
if (res.statusCode === 200 && res.data.code === 200) {
this.messages=[];
for(let item of res.data.data){
this.messages = [];
for (let item of res.data.data) {
this.messages.push({
role:"user",
content:item.userMessage
role: "user",
content: item.userMessage
});
this.messages.push({
role:"ai",
content:item.content
role: "ai",
content: item.content
});
}
useDebateStore().setConversation(this.messages);
@ -353,6 +414,28 @@ export default {
},
async sendMessage() {
//------
//
if (!this.roundsSelected) {
uni.showToast({
title: "请选择辩论轮数",
icon: "none",
duration: 2000,
});
return;
}
//
if (this.currentRound >= this.debateRounds) {
uni.showToast({
title: "辩论轮数已达上限",
icon: "none",
duration: 2000,
});
return;
}
//--------
if (!this.content.trim()) return;
//
@ -388,6 +471,24 @@ export default {
// loading AI
this.messages.splice(aiIndex, 1, { role: "ai", content: reply });
this.scrollToBottom();
//----------------------
//
this.currentRound++;
//
if (this.currentRound >= this.debateRounds) {
this.messages.push({
role: "ai",
content: `本轮辩论已完成(${this.debateRounds}回合)。您可以点击消息进行复盘分析。`,
});
};
if (this.currentRound >= this.debateRounds) {
//
this.showReviewButton = true;
return;
}
},
async callAI(history, content) {
@ -446,6 +547,82 @@ export default {
this.scrollToView = "msg" + (this.messages.length - 1);
});
},
//------------
//
selectRounds(type) {
this.selectedOption = type;
},
//
confirmRounds() {
if (this.selectedOption === 0) {
uni.showToast({
title: '请选择轮数',
icon: 'none',
duration: 2000
});
return;
}
//
if (this.roundsSelected) {
uni.showToast({
title: '已选择轮数',
icon: 'none',
duration: 2000
});
return;
}
//
if (this.selectedOption === 1) {
this.debateRounds = 10;
} else if (this.selectedOption === 2) {
this.debateRounds = 20;
}
this.currentRound = 0;
this.roundsSelected = true;
this.showRoundsPopup = false;
this.showReviewButton = false;
this.showReviewConfirm = false;
//
this.message = [{
role: 'ai',
content: `已选择 ${this.debateRounds} 回合辩论!请分享你的观点,我们开始吧!`
}];
this.scrollToBottom();
},
//
startReview() {
// //
// let history = this.messages
// .filter((msg) => !msg.loading)
// .map((msg) => {
// if (msg.role === 'user') {
// return '${ msg.content}';
// } else if (msg.role === 'ai') {
// return 'AI ${ msg.content}';
// }
// return '';
// }).join('\n');
//
// //store
// const pinia = this.$pinia;
// const store = useDebateStore(pinia);
// store.setDebate(history);
// //
// this.$emit('tab-change', 3);
this.onLongPress();
//
this.showReviewConfirm = false;
},
//
showReviewModal() {
this.showReviewConfirm = true;
},
},
};
</script>
@ -460,7 +637,8 @@ export default {
background: linear-gradient(135deg, #4338ca 0%, #7c3aed 100%);
overflow-x: hidden;
box-sizing: border-box;
padding-bottom: 180rpx; /* 为底部TabBar留出空间 */
padding-bottom: 180rpx;
/* 为底部TabBar留出空间 */
position: relative;
}
@ -478,11 +656,9 @@ export default {
.bg-circle {
position: absolute;
border-radius: 50%;
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.05),
rgba(255, 255, 255, 0.02)
);
background: linear-gradient(135deg,
rgba(255, 255, 255, 0.05),
rgba(255, 255, 255, 0.02));
animation: float 20s infinite ease-in-out;
opacity: 0.4;
/* 添加过渡效果 */
@ -490,16 +666,20 @@ export default {
}
@keyframes float {
0%,
100% {
transform: translate(0, 0) scale(1);
}
25% {
transform: translate(5%, 10%) scale(1.05);
}
50% {
transform: translate(10%, 5%) scale(0.95);
}
75% {
transform: translate(5%, 15%) scale(1.1);
}
@ -552,6 +732,7 @@ export default {
opacity: 0;
transform: translateY(-30rpx);
}
to {
opacity: 1;
transform: translateY(0);
@ -588,12 +769,10 @@ export default {
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(
to bottom right,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0) 100%
);
background: linear-gradient(to bottom right,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0) 100%);
transform: rotate(45deg);
animation: shine 3s infinite;
}
@ -602,6 +781,7 @@ export default {
0% {
transform: translateX(-100%) rotate(45deg);
}
20%,
100% {
transform: translateX(100%) rotate(45deg);
@ -708,6 +888,7 @@ export default {
opacity: 0;
transform: translateY(20rpx);
}
to {
opacity: 1;
transform: translateY(0);
@ -754,7 +935,8 @@ export default {
word-break: break-word;
box-shadow: 0 4rpx 15rpx rgba(0, 0, 0, 0.1);
position: relative;
transition: all 0.3s ease; /* 添加过渡效果 */
transition: all 0.3s ease;
/* 添加过渡效果 */
}
.from-user .bubble {
@ -773,7 +955,8 @@ export default {
height: 0;
border-left: 16rpx solid #f59e0b;
border-top: 16rpx solid transparent;
transition: all 0.3s ease; /* 添加过渡效果 */
transition: all 0.3s ease;
/* 添加过渡效果 */
}
.from-ai .bubble {
@ -792,7 +975,8 @@ export default {
height: 0;
border-right: 16rpx solid rgba(255, 255, 255, 0.2);
border-top: 16rpx solid transparent;
transition: all 0.3s ease; /* 添加过渡效果 */
transition: all 0.3s ease;
/* 添加过渡效果 */
}
/* 加载动画 */
@ -821,16 +1005,144 @@ export default {
}
@keyframes bounce {
0%,
80%,
100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
/* 轮数控制区域 ------------------------*/
.rounds-control {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background: rgba(255, 255, 255, 0.15);
border-radius: 16rpx;
margin: 0 auto 20rpx;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
animation: slideUp 0.4s ease-out;
width: 70%;
transition: all 0.5s ease;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 选择轮数按钮样式 */
.select-rounds-btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 20rpx;
background: rgba(104, 57, 224, 0.3);
border-radius: 16rpx;
font-size: 28rpx;
color: white;
font-weight: 500;
}
.select-rounds-btn image {
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
filter: brightness(0) invert(1);
}
.rounds-selected-container {
display: flex;
align-items: center;
width: 100%;
}
.rounds-label {
display: flex;
align-items: center;
padding: 10rpx 20rpx;
background: rgba(104, 57, 224, 0.3);
border-radius: 12rpx;
margin-right: 20rpx;
font-size: 26rpx;
color: white;
font-weight: 500;
min-width: 140rpx;
flex-shrink: 0;
margin-right: 20rpx;
}
.rounds-label image {
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
filter: brightness(0) invert(1);
}
.progress-container {
flex: 1;
display: flex;
align-items: center;
}
.progress-bar {
flex: 1;
height: 16rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 8rpx;
overflow: hidden;
margin-right: 20rpx;
}
/* 进度条动画 */
.progress-inner {
height: 100%;
background: linear-gradient(90deg, #f59e0b, #fcd34d);
border-radius: 8rpx;
transition: width 0.5s ease;
}
/* 进度条加载动画 */
@keyframes progress-grow {
from {
width: 0;
}
to {
width: v-bind('progressPercentage + "%"');
}
}
.progress-inner {
animation: progress-grow 0.8s ease-out forwards;
}
.rounds-counter {
font-size: 28rpx;
font-weight: 600;
color: white;
min-width: 80rpx;
text-align: center;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
}
/* 输入区域 */
.chat-input {
display: flex;
@ -847,13 +1159,15 @@ export default {
.textarea-box {
background: rgba(255, 255, 255, 0.2);
border-radius: 20rpx;
padding: 16rpx 20rpx 16rpx 90rpx; /* 增加左侧内边距为发送按钮留出空间 */
padding: 16rpx 20rpx 16rpx 90rpx;
/* 增加左侧内边距为发送按钮留出空间 */
font-size: 28rpx;
color: #ffffff;
border: 1px solid rgba(255, 255, 255, 0.3);
transition: all 0.3s;
min-height: 70rpx;
max-height: 180rpx; /* 限制最大高度 */
max-height: 180rpx;
/* 限制最大高度 */
width: 100%;
box-sizing: border-box;
}
@ -923,14 +1237,252 @@ export default {
.send-button-embedded image {
width: 40rpx;
height: 40rpx;
filter: invert(72%) sepia(87%) saturate(1242%) hue-rotate(325deg)
brightness(101%) contrast(96%);
filter: invert(72%) sepia(87%) saturate(1242%) hue-rotate(325deg) brightness(101%) contrast(96%);
}
/* 底部安全区域 */
.safe-area-bottom {
height: 20rpx;
height: calc(20rpx + constant(safe-area-inset-bottom)); /* iOS 11.0-11.2 */
height: calc(20rpx + env(safe-area-inset-bottom)); /* iOS 11.2+ */
height: calc(20rpx + constant(safe-area-inset-bottom));
/* iOS 11.0-11.2 */
height: calc(20rpx + env(safe-area-inset-bottom));
/* iOS 11.2+ */
}
/* 轮数选择弹窗样式 */
.rounds-popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
animation: fadeIn 0.3s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.rounds-popup {
width: 80%;
max-width: 600rpx;
background: white;
border-radius: 28rpx;
overflow: hidden;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3);
animation: scaleIn 0.3s ease-out;
}
@keyframes scaleIn {
from {
transform: scale(0.9);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
background: #7C3AED;
}
.popup-title {
font-size: 36rpx;
font-weight: 700;
color: white;
}
.close-icon {
width: 50rpx;
height: 50rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.close-icon image {
width: 30rpx;
height: 30rpx;
filter: brightness(0) invert(1);
}
.rounds-options {
padding: 30rpx;
}
.round-option {
display: flex;
align-items: center;
padding: 30rpx;
border-radius: 20rpx;
background: #f8f9ff;
border: 2rpx solid #e6e6ff;
margin-bottom: 25rpx;
transition: all 0.3s;
}
.round-option.selected {
background: #6839E0;
border-color: #6839E0;
transform: translateY(-5rpx);
box-shadow: 0 8rpx 20rpx rgba(104, 57, 224, 0.3);
width: auto;
margin: 0 30rpx 20rpx;
}
.option-icon {
font-size: 50rpx;
margin-right: 25rpx;
width: 80rpx;
text-align: center;
}
.round-option.selected .option-icon {
color: white;
}
.option-title {
font-size: 32rpx;
font-weight: 600;
margin-bottom: 8rpx;
}
.option-desc {
font-size: 26rpx;
color: #666;
}
.round-option.selected .option-title,
.round-option.selected .option-desc {
color: white;
}
.confirm-button-selectRounds {
background: #6839E0;
color: white;
border-radius: 0;
height: 100rpx;
line-height: 100rpx;
font-size: 32rpx;
font-weight: 600;
border: none;
}
/* 复盘确认弹窗样式 */
.review-confirm-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
animation: fadeIn 0.3s;
}
.review-confirm-popup {
width: 80%;
max-width: 600rpx;
background: white;
border-radius: 28rpx;
overflow: hidden;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3);
}
.popup-header {
padding: 30rpx;
background: #7C3AED;
text-align: center;
}
.popup-title {
font-size: 36rpx;
font-weight: 700;
color: white;
}
.popup-content {
padding: 40rpx 30rpx;
font-size: 30rpx;
color: #333;
text-align: center;
line-height: 1.6;
}
.popup-buttons {
display: flex;
padding: 20rpx;
border-top: 1rpx solid #eee;
}
.cancel-button {
flex: 1;
background: #f5f5f5;
color: #666;
border-radius: 12rpx;
margin-right: 15rpx;
height: 80rpx;
line-height: 80rpx;
font-size: 30rpx;
}
.confirm-button-gotoReview {
flex: 1;
background: #6839E0;
color: white;
border-radius: 12rpx;
margin-left: 15rpx;
height: 80rpx;
line-height: 80rpx;
font-size: 30rpx;
}
/* 复盘按钮样式 */
.review-button {
width: 50rpx;
height: 50rpx;
margin-left: 20rpx;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
padding: 8rpx;
}
.review-button image {
width: 100%;
height: 100%;
filter: brightness(0) invert(1);
}
/* 调整进度条容器布局 */
.progress-container {
flex: 1;
display: flex;
align-items: center;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

@ -15,7 +15,7 @@ export const useDebateStore = defineStore('debate', {
}),
actions: {
setDebate(content) {
this.selectedDebate.content = content;
this.selectedDebate = content;
},
setConversationId(id) {
this.conversationId = id;

Loading…
Cancel
Save