Tcode平台改造升级-AI助手增加工具菜单
This commit is contained in:
@@ -345,6 +345,19 @@ export default [
|
||||
asideMenu: 'drawer' // 左侧菜单抽屉模式
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/model-chat',
|
||||
name: 'ModelChat',
|
||||
component: () => import('@/views/Jyh/ModelChat/index.vue'),
|
||||
meta: {
|
||||
title: 'ModelChat',
|
||||
reportTitle: 'ModelChat',
|
||||
className: 'w-full min-w-full',
|
||||
hiddenFooter: true,
|
||||
hasMobile: true,
|
||||
asideMenu: 'drawer' // 左侧菜单抽屉模式
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/LinePage',
|
||||
name: 'LinePage',
|
||||
|
||||
@@ -131,6 +131,7 @@ import {
|
||||
fetchDeleteConversation,
|
||||
fetchToggleConversationCollect
|
||||
} from '@/api/jyh';
|
||||
import {useRouter} from "vue-router";
|
||||
|
||||
// --- Props & Emits ---
|
||||
const props = defineProps(['username', 'CONV_ID']);
|
||||
@@ -200,11 +201,19 @@ const handleSelect = (item) => {
|
||||
if (item.isEditing) return; // 编辑中不触发选中
|
||||
emit('select-conv', item.conversationId);
|
||||
};
|
||||
|
||||
// 4. 菜单点击
|
||||
const router = useRouter();
|
||||
// 4. 菜单点击 - 修改为跳转逻辑
|
||||
const handleMenuClick = (menu) => {
|
||||
console.log('点击菜单:', menu.title);
|
||||
// 路由跳转或功能触发逻辑
|
||||
|
||||
// 使用 router.push 跳转,并通过 query 传递参数
|
||||
router.push({
|
||||
path: '/model-chat', // 对应路由中的 path
|
||||
query: {
|
||||
id: menu.id,
|
||||
title: menu.title
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 5. 编辑/重命名逻辑
|
||||
|
||||
318
src/views/Jyh/ModelChat/index.vue
Normal file
318
src/views/Jyh/ModelChat/index.vue
Normal file
@@ -0,0 +1,318 @@
|
||||
<template>
|
||||
<div class="model-chat-container">
|
||||
<div class="chat-header">
|
||||
<div class="left">
|
||||
<d-icon name="icon-arrow-left" class="back-icon" @click="goBack"></d-icon>
|
||||
<div class="model-info">
|
||||
<span class="title">{{ currentTitle }}</span>
|
||||
<span class="subtitle">智能辅助模型</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<d-button variant="text" icon="icon-delete" @click="clearHistory">清空</d-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-content" ref="scrollRef">
|
||||
<div v-if="messages.length === 0" class="empty-placeholder">
|
||||
<d-icon name="icon-robot" size="48px" color="#ccc"></d-icon>
|
||||
<p>我是 {{ currentTitle }} 助手,请告诉我您的需求。</p>
|
||||
</div>
|
||||
|
||||
<div v-for="(msg, index) in messages" :key="index" :class="['message-row', msg.role]">
|
||||
<div class="avatar">
|
||||
<d-icon :name="msg.role === 'user' ? 'icon-user' : 'icon-robot'" size="24px"></d-icon>
|
||||
</div>
|
||||
<div class="message-bubble">
|
||||
<div class="text">{{ msg.content }}</div>
|
||||
<div class="time" v-if="msg.time">{{ msg.time }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="loading" class="message-row ai">
|
||||
<div class="avatar"><d-icon name="icon-robot" size="24px"></d-icon></div>
|
||||
<div class="message-bubble loading">
|
||||
<span>正在思考...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-footer">
|
||||
<div class="input-wrapper">
|
||||
<d-textarea
|
||||
v-model="inputText"
|
||||
placeholder="请输入您的问题..."
|
||||
:rows="2"
|
||||
class="chat-input"
|
||||
@keydown.enter.prevent="handleSend"
|
||||
></d-textarea>
|
||||
<d-button
|
||||
class="send-btn"
|
||||
variant="solid"
|
||||
:disabled="loading || !inputText.trim()"
|
||||
@click="handleSend"
|
||||
>
|
||||
<d-icon name="icon-publish" color="#fff"></d-icon>
|
||||
</d-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, nextTick } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useTimeFormat } from '@/utils/hooks/useTimeFormat'; // 假设你在这个路径有工具
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { formatTime } = useTimeFormat();
|
||||
|
||||
// 状态
|
||||
const currentTitle = ref('');
|
||||
const currentModelId = ref('');
|
||||
const inputText = ref('');
|
||||
const loading = ref(false);
|
||||
const scrollRef = ref(null);
|
||||
const messages = ref([]);
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
// 从路由参数获取当前选中的功能信息
|
||||
currentTitle.value = route.query.title || '智能对话';
|
||||
currentModelId.value = route.query.id || 'default';
|
||||
|
||||
// 模拟一条欢迎语
|
||||
messages.value.push({
|
||||
role: 'ai',
|
||||
content: `您好,欢迎使用 ${currentTitle.value} 功能,有什么可以帮您?`,
|
||||
time: getCurrentTime()
|
||||
});
|
||||
});
|
||||
|
||||
// 获取当前时间
|
||||
const getCurrentTime = () => {
|
||||
const now = new Date();
|
||||
return `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
router.back();
|
||||
};
|
||||
|
||||
// 清空历史
|
||||
const clearHistory = () => {
|
||||
messages.value = [];
|
||||
};
|
||||
|
||||
// 滚动到底部
|
||||
const scrollToBottom = async () => {
|
||||
await nextTick();
|
||||
if (scrollRef.value) {
|
||||
scrollRef.value.scrollTop = scrollRef.value.scrollHeight;
|
||||
}
|
||||
};
|
||||
|
||||
// 发送消息
|
||||
const handleSend = async () => {
|
||||
const text = inputText.value.trim();
|
||||
if (!text || loading.value) return;
|
||||
|
||||
// 1. 添加用户消息
|
||||
messages.value.push({
|
||||
role: 'user',
|
||||
content: text,
|
||||
time: getCurrentTime()
|
||||
});
|
||||
inputText.value = '';
|
||||
scrollToBottom();
|
||||
|
||||
// 2. 模拟请求后端 API
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
// TODO: 这里替换为你真实的 API 调用,传入 currentModelId.value
|
||||
// const res = await fetchModelChat({ model: currentModelId.value, prompt: text });
|
||||
|
||||
// 模拟延迟响应
|
||||
setTimeout(() => {
|
||||
messages.value.push({
|
||||
role: 'ai',
|
||||
content: `这是针对“${currentTitle.value}”功能的模拟回复:您发送了“${text}”。`,
|
||||
time: getCurrentTime()
|
||||
});
|
||||
loading.value = false;
|
||||
scrollToBottom();
|
||||
}, 1000);
|
||||
|
||||
} catch (error) {
|
||||
messages.value.push({
|
||||
role: 'ai',
|
||||
content: '服务暂时不可用,请稍后再试。',
|
||||
time: getCurrentTime()
|
||||
});
|
||||
loading.value = false;
|
||||
scrollToBottom();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.model-chat-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh; /* 或者 100% 视父容器而定 */
|
||||
background-color: #f5f7fa;
|
||||
|
||||
.chat-header {
|
||||
height: 60px;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 20px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.back-icon {
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
&:hover { background: #f0f0f0; border-radius: 4px; }
|
||||
}
|
||||
|
||||
.model-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.title { font-weight: bold; font-size: 16px; color: #333; }
|
||||
.subtitle { font-size: 12px; color: #999; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
.empty-placeholder {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.message-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
max-width: 80%;
|
||||
|
||||
.avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: #e0e0e0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.message-bubble {
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
|
||||
.time {
|
||||
font-size: 10px;
|
||||
color: rgba(0,0,0,0.4);
|
||||
margin-top: 4px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
/* AI 样式 */
|
||||
&.ai {
|
||||
align-self: flex-start;
|
||||
.avatar { background: #e6f7ff; color: #1890ff; }
|
||||
.message-bubble {
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
color: #333;
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 用户样式 */
|
||||
&.user {
|
||||
align-self: flex-end;
|
||||
flex-direction: row-reverse;
|
||||
.avatar { background: #fff0f6; color: #eb2f96; }
|
||||
.message-bubble {
|
||||
background: #1890ff;
|
||||
color: #fff;
|
||||
border-top-right-radius: 0;
|
||||
.time { color: rgba(255,255,255,0.7); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-footer {
|
||||
background: #fff;
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #eee;
|
||||
|
||||
.input-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 10px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
background: #fff;
|
||||
transition: border-color 0.3s;
|
||||
|
||||
&:focus-within {
|
||||
border-color: #1890ff;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
flex: 1;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 4px;
|
||||
/* 去除 DevUI textarea 默认样式 */
|
||||
::v-deep .devui-textarea {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.send-btn {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user