|
@@ -130,7 +130,7 @@
|
|
|
|
|
|
<div class="chat">
|
|
<div class="chat">
|
|
<div class="chat-header">
|
|
<div class="chat-header">
|
|
- <h2>智能运维助手</h2>
|
|
|
|
|
|
+ <h2>智能助手</h2>
|
|
<div class="chat-status">
|
|
<div class="chat-status">
|
|
<span class="status-indicator online"></span>
|
|
<span class="status-indicator online"></span>
|
|
<span>在线</span>
|
|
<span>在线</span>
|
|
@@ -350,6 +350,24 @@
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
+ <!-- 推荐问题组件 -->
|
|
|
|
+ <div style="width: 80%;" v-if="message.role === 'assistant' && message.showRecommendedQuestions" class="recommended-questions">
|
|
|
|
+ <div class="questions-header">
|
|
|
|
+ <!-- <img src="../assets/svg/hot-for-ux.svg" alt="推荐" class="hot-icon" /> -->
|
|
|
|
+ <span class="questions-title">可检索问题</span>
|
|
|
|
+ <!-- <div class="questions-subtitle">为您精选的热门问题</div> -->
|
|
|
|
+ </div>
|
|
|
|
+ <div class="questions-list">
|
|
|
|
+ <div
|
|
|
|
+ v-for="(question, index) in recommendedQuestions"
|
|
|
|
+ :key="index"
|
|
|
|
+ class="question-item"
|
|
|
|
+ @click="handleQuestionClick(question.example)"
|
|
|
|
+ >
|
|
|
|
+ {{ question.example }}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
@@ -634,7 +652,7 @@
|
|
</div> -->
|
|
</div> -->
|
|
<!-- 步骤显示区域 -->
|
|
<!-- 步骤显示区域 -->
|
|
<div id="stepsContainer" v-show="showSteps" class="steps-container">
|
|
<div id="stepsContainer" v-show="showSteps" class="steps-container">
|
|
- <h3 class="steps-title">📋 处理步骤</h3>
|
|
|
|
|
|
+ <h3 class="steps-title">处理步骤</h3>
|
|
<div id="stepsList"></div>
|
|
<div id="stepsList"></div>
|
|
</div>
|
|
</div>
|
|
<!-- 结果显示区域 -->
|
|
<!-- 结果显示区域 -->
|
|
@@ -873,6 +891,7 @@ import { useRouter } from 'vue-router'
|
|
import { message } from 'ant-design-vue';
|
|
import { message } from 'ant-design-vue';
|
|
import VueOfficeDocx from '@vue-office/docx';
|
|
import VueOfficeDocx from '@vue-office/docx';
|
|
import VueOfficeExcel from '@vue-office/excel';
|
|
import VueOfficeExcel from '@vue-office/excel';
|
|
|
|
+// import { getRecommendedQuestions } from '../api/report';
|
|
/* import '@vue-office/docx/lib/index.css';
|
|
/* import '@vue-office/docx/lib/index.css';
|
|
import '@vue-office/excel/lib/index.css'; */
|
|
import '@vue-office/excel/lib/index.css'; */
|
|
// 初始化 markdown-it
|
|
// 初始化 markdown-it
|
|
@@ -971,6 +990,10 @@ const formatted_data = ref('');
|
|
const showSteps = ref(false);
|
|
const showSteps = ref(false);
|
|
const steps = ref([]);
|
|
const steps = ref([]);
|
|
|
|
|
|
|
|
+// 推荐问题相关状态
|
|
|
|
+const recommendedQuestions = ref([]);
|
|
|
|
+const showRecommendedQuestions = ref(false);
|
|
|
|
+
|
|
// SSE消息处理函数
|
|
// SSE消息处理函数
|
|
const handleSSEMessage = (event, data) => {
|
|
const handleSSEMessage = (event, data) => {
|
|
// 立即处理每个事件
|
|
// 立即处理每个事件
|
|
@@ -1264,6 +1287,34 @@ const handleQaClick = (qa) => {
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+// 获取推荐问题列表
|
|
|
|
+const fetchRecommendedQuestions = async () => {
|
|
|
|
+ try {
|
|
|
|
+ const response = await axios.get(
|
|
|
|
+ `${import.meta.env.VITE_BASE_AI_API}/api/agents/commands/`,
|
|
|
|
+ {
|
|
|
|
+ headers: {
|
|
|
|
+ 'Authorization': `JWT ${localStorage.getItem('token')}`
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+ console.log(response.data);
|
|
|
|
+ if (response.data) {
|
|
|
|
+ recommendedQuestions.value = response.data.data.commands;
|
|
|
|
+ showRecommendedQuestions.value = true;
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error('获取推荐问题失败:', error);
|
|
|
|
+ showRecommendedQuestions.value = false;
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 处理推荐问题点击事件
|
|
|
|
+const handleQuestionClick = (question) => {
|
|
|
|
+ inputContent.value = question;
|
|
|
|
+ sendMessage();
|
|
|
|
+};
|
|
|
|
+
|
|
// 在组件卸载时清理定时器
|
|
// 在组件卸载时清理定时器
|
|
onUnmounted(() => {
|
|
onUnmounted(() => {
|
|
if (rotationInterval) {
|
|
if (rotationInterval) {
|
|
@@ -1689,6 +1740,15 @@ const summaryHtml=ref('')
|
|
|
|
|
|
handleSSEMessage(currentEvent || 'message', data);
|
|
handleSSEMessage(currentEvent || 'message', data);
|
|
if(currentEvent === 'final_summary'){
|
|
if(currentEvent === 'final_summary'){
|
|
|
|
+ // 检查summary是否以"无效命令:"开头
|
|
|
|
+ if (data.summary && data.summary.startsWith('无效命令:')) {
|
|
|
|
+ // 调用推荐问题接口
|
|
|
|
+ await fetchRecommendedQuestions();
|
|
|
|
+ } else {
|
|
|
|
+ // 隐藏推荐问题
|
|
|
|
+ showRecommendedQuestions.value = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
// 移除临时消息
|
|
// 移除临时消息
|
|
messages.value = messages.value.filter(
|
|
messages.value = messages.value.filter(
|
|
(msg) => msg.id !== tempAiMessage.id
|
|
(msg) => msg.id !== tempAiMessage.id
|
|
@@ -1704,6 +1764,7 @@ const summaryHtml=ref('')
|
|
automation_plan:data.automation_plan,
|
|
automation_plan:data.automation_plan,
|
|
displayContent: "",
|
|
displayContent: "",
|
|
audioData: null,
|
|
audioData: null,
|
|
|
|
+ showRecommendedQuestions:showRecommendedQuestions.value || false
|
|
});
|
|
});
|
|
isTyping.value = true;
|
|
isTyping.value = true;
|
|
summaryHtml.value=data.html_content
|
|
summaryHtml.value=data.html_content
|
|
@@ -3652,6 +3713,9 @@ const updateCollapsedState = () => {
|
|
background: #edf2f7;
|
|
background: #edf2f7;
|
|
color: rgba(0, 0, 0, 0.88);
|
|
color: rgba(0, 0, 0, 0.88);
|
|
}
|
|
}
|
|
|
|
+.assistant{
|
|
|
|
+ flex-direction: column;
|
|
|
|
+}
|
|
|
|
|
|
/* AI消息的气泡样式 */
|
|
/* AI消息的气泡样式 */
|
|
.assistant .message-bubble {
|
|
.assistant .message-bubble {
|
|
@@ -5363,7 +5427,7 @@ button,
|
|
background-color: var(--card-bg);
|
|
background-color: var(--card-bg);
|
|
border-radius: 8px;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
padding: 20px;
|
|
- margin-top: 20px;
|
|
|
|
|
|
+ margin-top: 35px;
|
|
}
|
|
}
|
|
|
|
|
|
:deep(.suggestion-section h3) {
|
|
:deep(.suggestion-section h3) {
|
|
@@ -6226,4 +6290,70 @@ button,
|
|
30% { transform: translateY(-4px); }
|
|
30% { transform: translateY(-4px); }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* 推荐问题组件样式 */
|
|
|
|
+.recommended-questions {
|
|
|
|
+ background: #ffffff;
|
|
|
|
+ border: 1px solid #e1f5fe;
|
|
|
|
+ border-radius: 8px;
|
|
|
|
+ padding: 16px;
|
|
|
|
+ margin: 16px 0;
|
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.questions-header {
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.questions-header .hot-icon {
|
|
|
|
+ width: 16px;
|
|
|
|
+ height: 16px;
|
|
|
|
+ margin-right: 8px;
|
|
|
|
+ vertical-align: middle;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.questions-title {
|
|
|
|
+ font-size: 16px;
|
|
|
|
+ font-weight: 600;
|
|
|
|
+ color: #333;
|
|
|
|
+ margin-right: 8px;
|
|
|
|
+ vertical-align: middle;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.questions-subtitle {
|
|
|
|
+ font-size: 12px;
|
|
|
|
+ color: #666;
|
|
|
|
+ margin-top: 4px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.questions-list {
|
|
|
|
+ display: flex;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ gap: 8px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.question-item {
|
|
|
|
+ padding: 12px 16px;
|
|
|
|
+ background: #f8f9fa;
|
|
|
|
+ border-radius: 6px;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ transition: all 0.2s ease;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ color: #333;
|
|
|
|
+ line-height: 1.4;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.question-item:hover {
|
|
|
|
+ background: #e3f2fd;
|
|
|
|
+ transform: translateY(-1px);
|
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.question-item:nth-child(odd) {
|
|
|
|
+ background: #f1f3f4;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.question-item:nth-child(odd):hover {
|
|
|
|
+ background: #e8f5e8;
|
|
|
|
+}
|
|
|
|
+
|
|
</style>
|
|
</style>
|