Merge remote-tracking branch 'origin/main'

main
liulianbuqu 2 months ago
commit dbdd037ed7

@ -2,12 +2,7 @@
<view class="debate-component"> <view class="debate-component">
<!-- 动态背景元素 --> <!-- 动态背景元素 -->
<view class="animated-bg"> <view class="animated-bg">
<view <view v-for="i in 6" :key="i" class="bg-circle" :style="getRandomCircleStyle()"></view>
v-for="i in 6"
:key="i"
class="bg-circle"
:style="getRandomCircleStyle()"
></view>
</view> </view>
<!-- 顶部卡片 - 可收缩 --> <!-- 顶部卡片 - 可收缩 -->
@ -15,27 +10,18 @@
<view class="card-header" @click="toggleCard"> <view class="card-header" @click="toggleCard">
<view class="card-icon-wrapper"> <view class="card-icon-wrapper">
<view class="card-icon"> <view class="card-icon">
<image <image src="/static/icons/robot-2-line.png" mode="aspectFit"></image>
src="/static/icons/robot-2-line.png"
mode="aspectFit"
></image>
</view> </view>
</view> </view>
<view class="card-text"> <view class="card-text">
<view class="card-title">模拟辩论</view> <view class="card-title">模拟辩论</view>
<view class="card-content" v-if="!isCardCollapsed" <view class="card-content" v-if="!isCardCollapsed">AI</view>
>与AI进行实时辩论对练提升应变能力</view
>
</view> </view>
<view class="collapse-icon"> <view class="collapse-icon">
<image <image :src="isCardCollapsed
:src=" ? '/static/icons/arrow-down-s-line.png'
isCardCollapsed : '/static/icons/arrow-up-s-line.png'
? '/static/icons/arrow-down-s-line.png' " mode="aspectFit"></image>
: '/static/icons/arrow-up-s-line.png'
"
mode="aspectFit"
></image>
</view> </view>
</view> </view>
</view> </view>
@ -43,32 +29,17 @@
<!-- 辩论主题选择器 --> <!-- 辩论主题选择器 -->
<view class="topic-selector" v-if="!isCardCollapsed"> <view class="topic-selector" v-if="!isCardCollapsed">
<scroll-view scroll-x class="topic-scroll" show-scrollbar="false"> <scroll-view scroll-x class="topic-scroll" show-scrollbar="false">
<view <view v-for="(topic, idx) in debateTopics" :key="idx" :class="['topic-pill', { active: selectedTopic === idx }]"
v-for="(topic, idx) in debateTopics" @click="selectTopic(idx)">
:key="idx"
:class="['topic-pill', { active: selectedTopic === idx }]"
@click="selectTopic(idx)"
>
{{ topic }} {{ topic }}
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
<!-- 聊天展示区 --> <!-- 聊天展示区 -->
<scroll-view <scroll-view class="chat-area" scroll-y :scroll-into-view="scrollToView" scroll-with-animation>
class="chat-area" <view v-for="(msg, index) in messages" :key="index" :id="'msg' + index" class="chat-message"
scroll-y :class="msg.role === 'user' ? 'from-user' : 'from-ai'" @longpress="onLongPress()">
: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="avatar" v-if="msg.role === 'ai'">AI</view>
<view class="bubble"> <view class="bubble">
<block v-if="msg.loading"> <block v-if="msg.loading">
@ -86,22 +57,37 @@
</view> </view>
</scroll-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>
</view>
</view>
<!-- 输入框与发送按钮 --> <!-- 输入框与发送按钮 -->
<view class="chat-input"> <view class="chat-input">
<view class="input-group"> <view class="input-group">
<view class="textarea-container"> <view class="textarea-container">
<textarea <textarea class="textarea-box" v-model="content" placeholder="输入你的辩论观点与AI进行思辨交锋" auto-height
class="textarea-box" maxlength="1000" />
v-model="content"
placeholder="输入你的辩论观点与AI进行思辨交锋"
auto-height
maxlength="1000"
/>
<button class="send-button-embedded" @click="sendMessage()"> <button class="send-button-embedded" @click="sendMessage()">
<image <image src="/static/icons/send-plane-fill.png" mode="aspectFit"></image>
src="/static/icons/send-plane-fill.png"
mode="aspectFit"
></image>
</button> </button>
</view> </view>
</view> </view>
@ -110,13 +96,40 @@
<!-- 底部安全区域 --> <!-- 底部安全区域 -->
<view class="safe-area-bottom"></view> <view class="safe-area-bottom"></view>
<Popup <Popup :visible="showSheet" buttonText="开始复盘" buttonIcon="🧠" @close="showSheet = false"
:visible="showSheet" @click="handleSheetClick" />
buttonText="开始复盘"
buttonIcon="🧠" <!-- 轮数选择弹窗 -->
@close="showSheet = false" <view v-if="showRoundsPopup" class="rounds-popup-mask" @click="showRoundsPopup = false">
@click="handleSheetClick" <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" @click="confirmRounds"></button>
</view>
</view>
</view> </view>
</template> </template>
@ -136,13 +149,20 @@ export default {
mounted() { mounted() {
const pinia = this.$pinia; const pinia = this.$pinia;
const store = useArgumentStore(pinia); const store = useArgumentStore(pinia);
this.content = store.selectedArgument.content; if (store.selectedArgument && store.selectedArgument.content) {
this.content = store.selectedArgument.content;
} else {
this.content = "";
}
//
this.showRoundsPopup = true;
}, },
data() { data() {
return { return {
showSheet:false, showSheet: false,
StoreHistory:"", StoreHistory: "",
input: "", input: "",
messages: [ messages: [
{ {
@ -151,6 +171,14 @@ export default {
"在这里你可以和我进行辩论,现在,辩论开始!请选择一个话题或提出你想讨论的观点。", "在这里你可以和我进行辩论,现在,辩论开始!请选择一个话题或提出你想讨论的观点。",
}, },
], ],
//
showRoundsPopup: false, //
roundsSelected: false, //
debateRounds: 0, //
currentRound: 0, //
selectedOption: 0, //
scrollToView: "", scrollToView: "",
content: "", content: "",
debateTopics: [ debateTopics: [
@ -165,6 +193,14 @@ export default {
isCardCollapsed: false, // isCardCollapsed: false, //
}; };
}, },
computed: {
//
progressPercentage() {
if (this.debateRounds === 0) return 0;
return (this.currentRound / this.debateRounds) * 100;
},
},
methods: { methods: {
handleSheetClick() { handleSheetClick() {
const pinia = this.$pinia; const pinia = this.$pinia;
@ -244,7 +280,28 @@ export default {
}, },
async sendMessage() { async sendMessage() {
if (!this.content.trim()) return; //
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() || this.currentRound >= this.debateRounds) return;
// //
this.messages.push({ this.messages.push({
@ -279,6 +336,20 @@ export default {
// loading AI // loading AI
this.messages.splice(aiIndex, 1, { role: "ai", content: reply }); this.messages.splice(aiIndex, 1, { role: "ai", content: reply });
this.scrollToBottom(); this.scrollToBottom();
//----------------------
//
this.currentRound++;
//
if (this.currentRound >= this.debateRounds) {
this.messages.push({
role: "ai",
content: `本轮辩论已完成(${this.debateRounds}回合)。您可以点击消息进行复盘分析。`,
});
};
}, },
async callAI(history, content) { async callAI(history, content) {
@ -320,6 +391,50 @@ export default {
this.scrollToView = "msg" + (this.messages.length - 1); 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.message = [{
role: 'ai',
content: `已选择 ${this.debateRounds} 回合辩论!请分享你的观点,我们开始吧!`
}];
this.scrollToBottom();
},
}, },
}; };
</script> </script>
@ -334,7 +449,8 @@ export default {
background: linear-gradient(135deg, #4338ca 0%, #7c3aed 100%); background: linear-gradient(135deg, #4338ca 0%, #7c3aed 100%);
overflow-x: hidden; overflow-x: hidden;
box-sizing: border-box; box-sizing: border-box;
padding-bottom: 180rpx; /* 为底部TabBar留出空间 */ padding-bottom: 180rpx;
/* 为底部TabBar留出空间 */
position: relative; position: relative;
} }
@ -352,11 +468,9 @@ export default {
.bg-circle { .bg-circle {
position: absolute; position: absolute;
border-radius: 50%; border-radius: 50%;
background: linear-gradient( background: linear-gradient(135deg,
135deg, rgba(255, 255, 255, 0.05),
rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02));
rgba(255, 255, 255, 0.02)
);
animation: float 20s infinite ease-in-out; animation: float 20s infinite ease-in-out;
opacity: 0.4; opacity: 0.4;
/* 添加过渡效果 */ /* 添加过渡效果 */
@ -364,16 +478,20 @@ export default {
} }
@keyframes float { @keyframes float {
0%, 0%,
100% { 100% {
transform: translate(0, 0) scale(1); transform: translate(0, 0) scale(1);
} }
25% { 25% {
transform: translate(5%, 10%) scale(1.05); transform: translate(5%, 10%) scale(1.05);
} }
50% { 50% {
transform: translate(10%, 5%) scale(0.95); transform: translate(10%, 5%) scale(0.95);
} }
75% { 75% {
transform: translate(5%, 15%) scale(1.1); transform: translate(5%, 15%) scale(1.1);
} }
@ -426,6 +544,7 @@ export default {
opacity: 0; opacity: 0;
transform: translateY(-30rpx); transform: translateY(-30rpx);
} }
to { to {
opacity: 1; opacity: 1;
transform: translateY(0); transform: translateY(0);
@ -462,12 +581,10 @@ export default {
left: -50%; left: -50%;
width: 200%; width: 200%;
height: 200%; height: 200%;
background: linear-gradient( background: linear-gradient(to bottom right,
to bottom right, rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0) 100%);
rgba(255, 255, 255, 0) 100%
);
transform: rotate(45deg); transform: rotate(45deg);
animation: shine 3s infinite; animation: shine 3s infinite;
} }
@ -476,6 +593,7 @@ export default {
0% { 0% {
transform: translateX(-100%) rotate(45deg); transform: translateX(-100%) rotate(45deg);
} }
20%, 20%,
100% { 100% {
transform: translateX(100%) rotate(45deg); transform: translateX(100%) rotate(45deg);
@ -582,6 +700,7 @@ export default {
opacity: 0; opacity: 0;
transform: translateY(20rpx); transform: translateY(20rpx);
} }
to { to {
opacity: 1; opacity: 1;
transform: translateY(0); transform: translateY(0);
@ -628,7 +747,8 @@ export default {
word-break: break-word; word-break: break-word;
box-shadow: 0 4rpx 15rpx rgba(0, 0, 0, 0.1); box-shadow: 0 4rpx 15rpx rgba(0, 0, 0, 0.1);
position: relative; position: relative;
transition: all 0.3s ease; /* 添加过渡效果 */ transition: all 0.3s ease;
/* 添加过渡效果 */
} }
.from-user .bubble { .from-user .bubble {
@ -647,7 +767,8 @@ export default {
height: 0; height: 0;
border-left: 16rpx solid #f59e0b; border-left: 16rpx solid #f59e0b;
border-top: 16rpx solid transparent; border-top: 16rpx solid transparent;
transition: all 0.3s ease; /* 添加过渡效果 */ transition: all 0.3s ease;
/* 添加过渡效果 */
} }
.from-ai .bubble { .from-ai .bubble {
@ -666,7 +787,8 @@ export default {
height: 0; height: 0;
border-right: 16rpx solid rgba(255, 255, 255, 0.2); border-right: 16rpx solid rgba(255, 255, 255, 0.2);
border-top: 16rpx solid transparent; border-top: 16rpx solid transparent;
transition: all 0.3s ease; /* 添加过渡效果 */ transition: all 0.3s ease;
/* 添加过渡效果 */
} }
/* 加载动画 */ /* 加载动画 */
@ -695,16 +817,143 @@ export default {
} }
@keyframes bounce { @keyframes bounce {
0%, 0%,
80%, 80%,
100% { 100% {
transform: scale(0); transform: scale(0);
} }
40% { 40% {
transform: scale(1); 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 { .chat-input {
display: flex; display: flex;
@ -721,13 +970,15 @@ export default {
.textarea-box { .textarea-box {
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.2);
border-radius: 20rpx; border-radius: 20rpx;
padding: 16rpx 20rpx 16rpx 90rpx; /* 增加左侧内边距为发送按钮留出空间 */ padding: 16rpx 20rpx 16rpx 90rpx;
/* 增加左侧内边距为发送按钮留出空间 */
font-size: 28rpx; font-size: 28rpx;
color: #ffffff; color: #ffffff;
border: 1px solid rgba(255, 255, 255, 0.3); border: 1px solid rgba(255, 255, 255, 0.3);
transition: all 0.3s; transition: all 0.3s;
min-height: 70rpx; min-height: 70rpx;
max-height: 180rpx; /* 限制最大高度 */ max-height: 180rpx;
/* 限制最大高度 */
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
} }
@ -797,14 +1048,154 @@ export default {
.send-button-embedded image { .send-button-embedded image {
width: 40rpx; width: 40rpx;
height: 40rpx; height: 40rpx;
filter: invert(72%) sepia(87%) saturate(1242%) hue-rotate(325deg) filter: invert(72%) sepia(87%) saturate(1242%) hue-rotate(325deg) brightness(101%) contrast(96%);
brightness(101%) contrast(96%);
} }
/* 底部安全区域 */ /* 底部安全区域 */
.safe-area-bottom { .safe-area-bottom {
height: 20rpx; height: 20rpx;
height: calc(20rpx + constant(safe-area-inset-bottom)); /* iOS 11.0-11.2 */ height: calc(20rpx + constant(safe-area-inset-bottom));
height: calc(20rpx + env(safe-area-inset-bottom)); /* iOS 11.2+ */ /* 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 {
background: #6839E0;
color: white;
border-radius: 0;
height: 100rpx;
line-height: 100rpx;
font-size: 32rpx;
font-weight: 600;
border: none;
} }
</style> </style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Loading…
Cancel
Save