Files
sillytavern-repalice/client/src/components/layout/CenterChat.vue

176 lines
3.3 KiB
Vue

<template>
<main class="center-chat">
<!-- 消息列表 -->
<div class="message-list">
<CenterMessageItem
v-for="msg in messages"
:key="msg.id"
:message="msg"
/>
</div>
<!-- 输入区域 -->
<div class="input-area">
<!-- 选项框 -->
<div class="input-options">
<select v-model="sendOptions.role" class="option-select">
<option value="user">用户</option>
<option value="assistant">AI</option>
</select>
</div>
<!-- 输入框 -->
<textarea
v-model="inputMessage"
class="message-input"
placeholder="输入消息..."
@keydown.enter.ctrl="sendMessage"
></textarea>
<!-- 发送/停止按钮 -->
<button
:class="['send-btn', { sending: isSending }]"
@click="isSending ? stopGeneration() : sendMessage()"
>
{{ isSending ? '⏹ 停止' : '📤 发送' }}
</button>
</div>
</main>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import CenterMessageItem from '../features/center/MessageItem.vue';
interface Message {
id: string;
senderName: string;
senderRole: 'user' | 'assistant' | 'system';
mes: string;
timestamp: Date;
}
const messages = ref<Message[]>([
{
id: '1',
senderName: 'Assistant',
senderRole: 'assistant',
mes: '你好!有什么可以帮助你的吗?',
timestamp: new Date(),
},
]);
const inputMessage = ref('');
const isSending = ref(false);
const sendOptions = ref({
role: 'user' as 'user' | 'assistant',
});
function sendMessage() {
if (!inputMessage.value.trim()) return;
const newMessage: Message = {
id: Date.now().toString(),
senderName: sendOptions.value.role === 'user' ? 'User' : 'Assistant',
senderRole: sendOptions.value.role,
mes: inputMessage.value,
timestamp: new Date(),
};
messages.value.push(newMessage);
inputMessage.value = '';
isSending.value = true;
// 模拟 AI 回复
setTimeout(() => {
isSending.value = false;
}, 2000);
}
function stopGeneration() {
isSending.value = false;
}
</script>
<style scoped>
.center-chat {
display: flex;
flex-direction: column;
flex: 1;
background: #ffffff;
overflow: hidden;
}
.message-list {
flex: 1;
overflow-y: auto;
padding: 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.input-area {
display: flex;
align-items: flex-end;
gap: 8px;
padding: 16px;
background: #f8f9fa;
border-top: 2px solid #dee2e6;
flex-shrink: 0;
}
.input-options {
flex-shrink: 0;
}
.option-select {
padding: 8px;
border: 1px solid #ced4da;
border-radius: 4px;
background: white;
font-size: 13px;
}
.message-input {
flex: 1;
padding: 12px;
border: 1px solid #ced4da;
border-radius: 4px;
resize: none;
font-size: 14px;
min-height: 60px;
max-height: 200px;
font-family: inherit;
}
.message-input:focus {
outline: none;
border-color: #3498db;
}
.send-btn {
padding: 12px 20px;
border: none;
border-radius: 4px;
background: #3498db;
color: white;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: background 0.2s;
flex-shrink: 0;
}
.send-btn:hover {
background: #2980b9;
}
.send-btn.sending {
background: #e74c3c;
}
.send-btn.sending:hover {
background: #c0392b;
}
</style>