379 lines
8.5 KiB
Vue
379 lines
8.5 KiB
Vue
<template>
|
||
<div class="home-container">
|
||
<!-- 中间内容区:标题、副标题、卡片 -->
|
||
<div class="center-content">
|
||
<!-- 第一行:标题 -->
|
||
<div class="title-section">
|
||
<span class="title-highlight">玄</span>
|
||
<span class="title-normal mr-4">鉴万物</span>
|
||
<span class="title-highlight">鉴</span>
|
||
<span class="title-normal">知明理 </span>
|
||
</div>
|
||
|
||
<!-- 第二行:副标题 -->
|
||
<div class="subtitle-section">本地运行、自主规划、安全可控的AI工作搭子</div>
|
||
|
||
<!-- 第三行:卡片 -->
|
||
<div class="card-section flex gap-8 items-center">
|
||
<div class="feature-card">
|
||
<div class="card-icon">
|
||
<img src="@/assets/icons/document-organization.svg" width="42" height="42" />
|
||
</div>
|
||
<div class="card-title">智能文档处理</div>
|
||
<div class="card-desc">支持多种格式文档的智能解析与处理</div>
|
||
</div>
|
||
<div class="feature-card">
|
||
<div class="card-icon">
|
||
<img src="@/assets/icons/official-document.svg" width="42" height="42" />
|
||
</div>
|
||
<div class="card-title">智能文档处理</div>
|
||
<div class="card-desc">支持多种格式文档的智能解析与处理</div>
|
||
</div>
|
||
<div class="feature-card">
|
||
<div class="card-icon">
|
||
<img src="@/assets/icons/pdf.svg" width="42" height="42" />
|
||
</div>
|
||
<div class="card-title">智能文档处理</div>
|
||
<div class="card-desc">支持多种格式文档的智能解析与处理</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 底部:输入框 -->
|
||
<div class="input-section">
|
||
<div class="input-wrapper">
|
||
<textarea
|
||
v-model="inputText"
|
||
class="input-textarea"
|
||
placeholder="输入 / 调用技能,输入 @ 调用知识库"
|
||
:disabled="isCreating"
|
||
@keydown="handleKeydown"
|
||
@input="autoResize"
|
||
ref="textareaRef"
|
||
></textarea>
|
||
<div class="input-toolbar">
|
||
<div class="toolbar-left">
|
||
<button class="dir-btn">
|
||
<LucideIcon name="folder-input" size="16"></LucideIcon>
|
||
<span>选择工作目录</span>
|
||
</button>
|
||
<el-tooltip content="添加文件或者文件夹作为上下文" placement="top" :show-arrow="false">
|
||
<button class="toolbar-btn icon-btn">
|
||
<LucideIcon name="paperclip" size="16"></LucideIcon>
|
||
</button>
|
||
</el-tooltip>
|
||
<el-tooltip content="使用 / 调用技能" placement="top" :show-arrow="false">
|
||
<button class="toolbar-btn icon-btn">/</button>
|
||
</el-tooltip>
|
||
<el-tooltip content="使用 @ 调用知识库" placement="top" :show-arrow="false">
|
||
<button class="toolbar-btn icon-btn">@</button>
|
||
</el-tooltip>
|
||
</div>
|
||
<div class="toolbar-right">
|
||
<button class="send-btn" :disabled="!inputText.trim() || isCreating" @click="handleSend">
|
||
<LucideIcon name="arrow-up"></LucideIcon>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue';
|
||
import { useRouter } from 'vue-router';
|
||
import { useAppStore } from '@/stores/app';
|
||
import { useHistoryStore } from '@/stores/history';
|
||
import { Document, Plus, Promotion, FolderOpened, Paperclip } from '@element-plus/icons-vue';
|
||
import { ElMessage } from 'element-plus';
|
||
import LucideIcon from '@/components/base/LucideIcon.vue';
|
||
|
||
const router = useRouter();
|
||
const appStore = useAppStore();
|
||
const historyStore = useHistoryStore();
|
||
const inputText = ref('');
|
||
const isCreating = ref(false);
|
||
const textareaRef = ref(null);
|
||
|
||
function autoResize() {
|
||
const el = textareaRef.value;
|
||
if (!el) return;
|
||
el.style.height = 'auto';
|
||
el.style.height = Math.min(el.scrollHeight, 323) + 'px';
|
||
}
|
||
|
||
// 处理发送消息
|
||
async function handleSend() {
|
||
// 检查 opencode 服务是否已启动
|
||
if (appStore.serviceStatus !== appStore.SERVICE_STATUS.RUNNING) {
|
||
ElMessage.warning('暂时没有运行的智能体');
|
||
return;
|
||
}
|
||
const text = inputText.value.trim();
|
||
if (!text || isCreating.value) return;
|
||
|
||
isCreating.value = true;
|
||
try {
|
||
// 创建会话,title 使用用户输入的文本
|
||
const session = await historyStore.createSession(text);
|
||
console.log('创建会话成功:', session);
|
||
|
||
// 清空输入框
|
||
inputText.value = '';
|
||
|
||
// 跳转到对话页面,并将消息文本带入 query
|
||
router.push({
|
||
name: 'Chat',
|
||
params: { id: session.id },
|
||
query: { text: text },
|
||
});
|
||
} catch (err) {
|
||
console.error('创建会话失败:', err);
|
||
} finally {
|
||
isCreating.value = false;
|
||
}
|
||
}
|
||
|
||
// 处理键盘事件
|
||
function handleKeydown(e) {
|
||
// Enter 发送,Shift+Enter 换行
|
||
if (e.key === 'Enter' && !e.shiftKey) {
|
||
e.preventDefault();
|
||
handleSend();
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.home-container {
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
background: #ffffff;
|
||
position: relative;
|
||
}
|
||
|
||
/* 中间内容区 */
|
||
.center-content {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 24px;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 第一行:标题 */
|
||
.title-section {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 0;
|
||
}
|
||
|
||
.title-highlight {
|
||
font-weight: 900;
|
||
font-size: 42px;
|
||
line-height: 48px;
|
||
letter-spacing: -0.39px;
|
||
text-align: center;
|
||
color: #409eff;
|
||
}
|
||
|
||
.title-normal {
|
||
font-weight: 900;
|
||
font-size: 42px;
|
||
line-height: 48px;
|
||
letter-spacing: -0.39px;
|
||
text-align: center;
|
||
color: #303133;
|
||
}
|
||
|
||
/* 第二行:副标题 */
|
||
.subtitle-section {
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
line-height: 22.75px;
|
||
letter-spacing: -0.15px;
|
||
text-align: center;
|
||
color: #606266;
|
||
}
|
||
|
||
/* 第三行:卡片 */
|
||
.card-section {
|
||
margin: 16px 0;
|
||
}
|
||
|
||
.feature-card {
|
||
width: 220px;
|
||
height: 158px;
|
||
border: 1px solid #e4e7ed;
|
||
border-radius: 8px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 16px;
|
||
gap: 8px;
|
||
background: #ffffff;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.card-icon {
|
||
width: 42px;
|
||
height: 42px;
|
||
margin-top: 9px;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.card-icon img {
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.card-icon img:hover {
|
||
transform: rotate(-15deg);
|
||
}
|
||
|
||
.card-title {
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
line-height: 20px;
|
||
letter-spacing: 0.55px;
|
||
color: #1a1a1a;
|
||
}
|
||
|
||
.card-desc {
|
||
font-weight: 400;
|
||
font-size: 12px;
|
||
line-height: 16px;
|
||
color: #8a9097;
|
||
}
|
||
|
||
/* 底部:输入框 */
|
||
.input-section {
|
||
margin-top: auto;
|
||
padding-top: 24px;
|
||
padding-bottom: 32px;
|
||
}
|
||
|
||
.input-wrapper {
|
||
width: 760px;
|
||
border-radius: 12px;
|
||
border: 1px solid #dee0e4;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #ffffff;
|
||
box-shadow: 0px 1px 20px 0px #00000008;
|
||
}
|
||
|
||
.input-textarea {
|
||
width: 758px;
|
||
min-height: 60px;
|
||
max-height: 323px;
|
||
padding: 16px;
|
||
border: none;
|
||
outline: none;
|
||
resize: none;
|
||
overflow-y: auto;
|
||
font-size: 14px;
|
||
line-height: 20px;
|
||
color: #303133;
|
||
background: transparent;
|
||
font-family: inherit;
|
||
}
|
||
|
||
.input-textarea::placeholder {
|
||
color: #c0c4cc;
|
||
}
|
||
|
||
.input-toolbar {
|
||
height: 54px;
|
||
padding: 0 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.toolbar-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.toolbar-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 1px solid #dcdfe6;
|
||
background: #ffffff;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
color: #606266;
|
||
}
|
||
|
||
.toolbar-btn:hover {
|
||
border-color: #409eff;
|
||
color: #409eff;
|
||
}
|
||
|
||
.dir-btn {
|
||
height: 28px;
|
||
gap: 4px;
|
||
padding: 0 8px;
|
||
background: #f5f6f7;
|
||
border-radius: 28px;
|
||
font-size: 12px;
|
||
font-weight: 400;
|
||
line-height: 16px;
|
||
text-align: center;
|
||
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
color: #606266;
|
||
}
|
||
.dir-btn:hover {
|
||
background: #eeeff2;
|
||
}
|
||
|
||
.icon-btn {
|
||
width: 28px;
|
||
height: 28px;
|
||
padding: 0 7px;
|
||
border-radius: 9999px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.toolbar-right {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.send-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
border: none;
|
||
background: #1a1a1a;
|
||
border-radius: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.send-btn:hover {
|
||
background: #333333;
|
||
}
|
||
|
||
.send-btn:disabled {
|
||
background: #8c8c8c;
|
||
cursor: not-allowed;
|
||
}
|
||
</style>
|