删除无用代码

This commit is contained in:
2025-11-24 16:57:48 +08:00
parent b51faf731a
commit 8702ff621a
6 changed files with 0 additions and 956 deletions

View File

@@ -1,42 +0,0 @@
<template>
<AdminLayout title="智能体管理" subtitle="智能体管理">
<div class="ai-management">
<h1 class="page-title">智能体管理</h1>
<el-tabs v-model="activeTab">
<el-tab-pane label="基础配置" name="config">
<AIConfig />
</el-tab-pane>
<el-tab-pane label="知识库管理" name="knowledge">
<KnowledgeManagement />
</el-tab-pane>
</el-tabs>
</div>
</AdminLayout>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ElTabs, ElTabPane } from 'element-plus';
import AIConfig from './components/AIConfig.vue';
import KnowledgeManagement from './components/KnowledgeManagement.vue';
import { AdminLayout } from '@/views/admin';
defineOptions({
name: 'AIManagementView'
});
const activeTab = ref('config');
</script>
<style lang="scss" scoped>
.ai-management {
padding: 20px;
}
.page-title {
font-size: 28px;
font-weight: 600;
color: #141F38;
margin-bottom: 24px;
}
</style>

View File

@@ -1,202 +0,0 @@
<template>
<div class="ai-assistant-page">
<!-- 悬浮球入口可以通过props控制显示/隐藏 -->
<div class="floating-button" @click="togglePanel" v-if="!isPanelVisible">
<img src="@/assets/imgs/ai-icon.svg" alt="AI助手" />
</div>
<!-- AI助手面板 -->
<transition name="slide">
<div class="assistant-panel" v-if="isPanelVisible">
<div class="panel-header">
<h2>AI思政助手</h2>
<div class="header-actions">
<el-button size="small" @click="handleFileUpload">📎 上传文件</el-button>
<el-button size="small" @click="showHistory">📜 历史记录</el-button>
<el-button size="small" @click="togglePanel"></el-button>
</div>
</div>
<div class="panel-tabs">
<div
class="panel-tab"
v-for="tab in tabs"
:key="tab.key"
:class="{ active: activeTab === tab.key }"
@click="activeTab = tab.key"
>
{{ tab.label }}
</div>
</div>
<div class="panel-content">
<component :is="currentComponent" />
</div>
</div>
</transition>
<!-- 历史对话记录弹窗 -->
<el-dialog v-model="historyVisible" title="历史对话记录" width="600px">
<DialogHistory @load-conversation="loadConversation" />
</el-dialog>
<!-- 文件解读与记录弹窗 -->
<el-dialog v-model="fileDialogVisible" title="文件解读与记录" width="800px">
<FileInterpretation />
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { ElButton, ElDialog } from 'element-plus';
import ChatInterface from './components/ChatInterface.vue';
import KnowledgeBase from './components/KnowledgeBase.vue';
import DialogHistory from './components/DialogHistory.vue';
import FileInterpretation from './components/FileInterpretation.vue';
const isPanelVisible = ref(false);
const activeTab = ref('chat');
const historyVisible = ref(false);
const fileDialogVisible = ref(false);
const tabs = [
{ key: 'chat', label: '对话' },
{ key: 'knowledge', label: '知识库' }
];
const componentMap: Record<string, any> = {
'chat': ChatInterface,
'knowledge': KnowledgeBase
};
const currentComponent = computed(() => componentMap[activeTab.value]);
function togglePanel() {
isPanelVisible.value = !isPanelVisible.value;
}
function showHistory() {
historyVisible.value = true;
}
function handleFileUpload() {
fileDialogVisible.value = true;
}
function loadConversation(conversation: any) {
// TODO: 加载历史对话
historyVisible.value = false;
}
</script>
<style lang="scss" scoped>
.ai-assistant-page {
position: relative;
}
.floating-button {
position: fixed;
bottom: 40px;
right: 40px;
width: 64px;
height: 64px;
background: linear-gradient(135deg, #C62828, #E53935);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 4px 12px rgba(198, 40, 40, 0.4);
transition: all 0.3s;
z-index: 1000;
&:hover {
transform: scale(1.1);
box-shadow: 0 6px 16px rgba(198, 40, 40, 0.5);
}
img {
width: 36px;
height: 36px;
}
}
.assistant-panel {
position: fixed;
bottom: 20px;
right: 20px;
width: 450px;
height: 650px;
background: white;
border-radius: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
display: flex;
flex-direction: column;
z-index: 1000;
overflow: hidden;
}
.panel-header {
padding: 20px;
border-bottom: 1px solid #e0e0e0;
display: flex;
justify-content: space-between;
align-items: center;
background: linear-gradient(135deg, #C62828, #E53935);
color: white;
h2 {
font-size: 18px;
font-weight: 600;
}
}
.header-actions {
display: flex;
gap: 8px;
}
.panel-tabs {
display: flex;
background: #f5f5f5;
padding: 0 16px;
}
.panel-tab {
padding: 12px 20px;
cursor: pointer;
font-size: 14px;
color: #666;
position: relative;
transition: all 0.3s;
&:hover {
color: #C62828;
}
&.active {
color: #C62828;
font-weight: 600;
background: white;
border-radius: 8px 8px 0 0;
}
}
.panel-content {
flex: 1;
overflow: hidden;
}
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
transform: translateY(100%);
opacity: 0;
}
</style>

View File

@@ -1,250 +0,0 @@
<template>
<div class="chat-interface">
<!-- 消息列表 -->
<div class="messages-container" ref="messagesContainer">
<div
class="message"
v-for="message in messages"
:key="message.id"
:class="message.role"
>
<div class="message-avatar">
<img :src="getAvatar(message.role)" :alt="message.role" />
</div>
<div class="message-content">
<div class="message-text" v-html="message.content"></div>
<div class="message-time">{{ message.timestamp }}</div>
</div>
</div>
<!-- 加载中动画 -->
<div class="message assistant" v-if="isLoading">
<div class="message-avatar">
<img src="@/assets/imgs/ai-avatar.svg" alt="AI" />
</div>
<div class="message-content">
<div class="typing-indicator">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
</div>
<!-- 输入框 -->
<div class="input-container">
<el-input
v-model="inputMessage"
type="textarea"
:rows="3"
placeholder="输入您的问题..."
@keydown.enter.prevent="handleSend"
:disabled="isLoading"
/>
<el-button
type="primary"
@click="handleSend"
:loading="isLoading"
:disabled="!inputMessage.trim()"
>
发送
</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, nextTick, onMounted } from 'vue';
import { ElInput, ElButton } from 'element-plus';
const messagesContainer = ref<HTMLElement | null>(null);
const inputMessage = ref('');
const isLoading = ref(false);
const messages = ref<any[]>([
{
id: 1,
role: 'assistant',
content: '您好我是AI思政助手请问有什么可以帮助您的吗',
timestamp: new Date().toLocaleTimeString()
}
]);
onMounted(() => {
// TODO: 加载历史消息
});
async function handleSend() {
if (!inputMessage.value.trim() || isLoading.value) return;
const userMessage = {
id: Date.now(),
role: 'user',
content: inputMessage.value,
timestamp: new Date().toLocaleTimeString()
};
messages.value.push(userMessage);
const question = inputMessage.value;
inputMessage.value = '';
await nextTick();
scrollToBottom();
// 模拟AI回复
isLoading.value = true;
// TODO: 调用AI API
setTimeout(() => {
const aiMessage = {
id: Date.now(),
role: 'assistant',
content: `关于"${question}",我来为您解答...`,
timestamp: new Date().toLocaleTimeString()
};
messages.value.push(aiMessage);
isLoading.value = false;
nextTick(() => {
scrollToBottom();
});
}, 1500);
}
function getAvatar(role: string) {
return role === 'user'
? '@/assets/imgs/user-avatar.svg'
: '@/assets/imgs/ai-avatar.svg';
}
function scrollToBottom() {
if (messagesContainer.value) {
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
}
}
</script>
<style lang="scss" scoped>
.chat-interface {
height: 100%;
display: flex;
flex-direction: column;
}
.messages-container {
flex: 1;
overflow-y: auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 16px;
}
.message {
display: flex;
gap: 12px;
&.user {
flex-direction: row-reverse;
.message-content {
align-items: flex-end;
}
.message-text {
background: #C62828;
color: white;
}
}
&.assistant {
.message-text {
background: #f5f5f5;
color: #333;
}
}
}
.message-avatar {
width: 36px;
height: 36px;
flex-shrink: 0;
border-radius: 50%;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.message-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.message-text {
padding: 12px 16px;
border-radius: 12px;
font-size: 14px;
line-height: 1.6;
max-width: 80%;
word-wrap: break-word;
}
.message-time {
font-size: 12px;
color: #999;
padding: 0 4px;
}
.typing-indicator {
display: flex;
gap: 4px;
padding: 12px 16px;
background: #f5f5f5;
border-radius: 12px;
span {
width: 8px;
height: 8px;
background: #999;
border-radius: 50%;
animation: typing 1.4s infinite;
&:nth-child(2) {
animation-delay: 0.2s;
}
&:nth-child(3) {
animation-delay: 0.4s;
}
}
}
@keyframes typing {
0%, 60%, 100% {
transform: translateY(0);
}
30% {
transform: translateY(-10px);
}
}
.input-container {
padding: 16px;
border-top: 1px solid #e0e0e0;
display: flex;
gap: 12px;
:deep(.el-textarea) {
flex: 1;
}
}
</style>

View File

@@ -1,110 +0,0 @@
<template>
<div class="dialog-history">
<div class="history-list">
<div
class="history-item"
v-for="conversation in conversations"
:key="conversation.id"
@click="$emit('load-conversation', conversation)"
>
<div class="item-header">
<h4>{{ conversation.title }}</h4>
<span class="item-date">{{ conversation.date }}</span>
</div>
<p class="item-preview">{{ conversation.preview }}</p>
<div class="item-footer">
<span class="item-count">{{ conversation.messageCount }} 条消息</span>
<el-button size="small" type="danger" @click.stop="deleteConversation(conversation)">
删除
</el-button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElButton, ElMessage } from 'element-plus';
const conversations = ref<any[]>([]);
defineEmits(['load-conversation']);
onMounted(() => {
// TODO: 加载历史对话列表
});
function deleteConversation(conversation: any) {
// TODO: 删除对话
ElMessage.success('已删除对话');
}
</script>
<style lang="scss" scoped>
.dialog-history {
max-height: 500px;
overflow-y: auto;
}
.history-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.history-item {
padding: 16px;
border: 1px solid #e0e0e0;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
&:hover {
border-color: #C62828;
background: #fff5f5;
}
}
.item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
h4 {
font-size: 16px;
font-weight: 600;
color: #141F38;
}
}
.item-date {
font-size: 12px;
color: #999;
}
.item-preview {
font-size: 14px;
color: #666;
margin-bottom: 12px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.item-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 12px;
border-top: 1px solid #f0f0f0;
}
.item-count {
font-size: 13px;
color: #999;
}
</style>

View File

@@ -1,205 +0,0 @@
<template>
<div class="file-interpretation">
<el-tabs v-model="activeTab">
<el-tab-pane label="文件上传" name="upload">
<div class="upload-section">
<el-upload
drag
action="#"
:before-upload="beforeUpload"
:on-success="handleUploadSuccess"
multiple
>
<div class="upload-icon">📁</div>
<div class="upload-text">
<p>点击或拖拽文件到此处上传</p>
<p class="upload-hint">支持 PDFWordTXT 格式</p>
</div>
</el-upload>
<!-- 已上传文件列表 -->
<div class="uploaded-files" v-if="uploadedFiles.length">
<h4>已上传文件</h4>
<div class="file-list">
<div class="file-item" v-for="file in uploadedFiles" :key="file.id">
<div class="file-icon">📄</div>
<div class="file-info">
<h5>{{ file.name }}</h5>
<p>{{ file.size }} · {{ file.uploadDate }}</p>
</div>
<el-button size="small" @click="analyzeFile(file)">解读</el-button>
</div>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="历史文件" name="history">
<div class="history-files">
<div class="file-item" v-for="file in historyFiles" :key="file.id">
<div class="file-icon">📄</div>
<div class="file-info">
<h5>{{ file.name }}</h5>
<p>上传时间{{ file.uploadDate }}</p>
<p class="file-summary">{{ file.summary }}</p>
</div>
<div class="file-actions">
<el-button size="small" @click="viewAnalysis(file)">查看解读</el-button>
<el-button size="small" type="danger" @click="deleteFile(file)">删除</el-button>
</div>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElTabs, ElTabPane, ElUpload, ElButton, ElMessage } from 'element-plus';
const activeTab = ref('upload');
const uploadedFiles = ref<any[]>([]);
const historyFiles = ref<any[]>([]);
onMounted(() => {
// TODO: 加载历史文件
});
function beforeUpload(file: File) {
const allowedTypes = ['application/pdf', 'application/msword', 'text/plain',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
if (!allowedTypes.includes(file.type)) {
ElMessage.error('只支持 PDF、Word、TXT 格式');
return false;
}
if (file.size > 10 * 1024 * 1024) {
ElMessage.error('文件大小不能超过 10MB');
return false;
}
return true;
}
function handleUploadSuccess(response: any, file: any) {
uploadedFiles.value.push({
id: Date.now(),
name: file.name,
size: formatFileSize(file.size),
uploadDate: new Date().toLocaleString()
});
ElMessage.success('文件上传成功');
}
function formatFileSize(bytes: number): string {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
}
function analyzeFile(file: any) {
// TODO: 调用文件解读API
ElMessage.info('正在解读文件...');
}
function viewAnalysis(file: any) {
// TODO: 查看文件解读结果
}
function deleteFile(file: any) {
// TODO: 删除文件
ElMessage.success('文件已删除');
}
</script>
<style lang="scss" scoped>
.file-interpretation {
min-height: 400px;
}
.upload-section {
padding: 20px;
}
.upload-icon {
font-size: 64px;
margin-bottom: 16px;
}
.upload-text {
p {
margin: 8px 0;
font-size: 14px;
color: #666;
}
}
.upload-hint {
font-size: 12px;
color: #999;
}
.uploaded-files {
margin-top: 32px;
h4 {
font-size: 16px;
font-weight: 600;
color: #141F38;
margin-bottom: 16px;
}
}
.file-list,
.history-files {
display: flex;
flex-direction: column;
gap: 12px;
}
.file-item {
display: flex;
align-items: center;
gap: 16px;
padding: 16px;
background: #f9f9f9;
border-radius: 8px;
}
.file-icon {
font-size: 32px;
flex-shrink: 0;
}
.file-info {
flex: 1;
h5 {
font-size: 15px;
font-weight: 600;
color: #141F38;
margin-bottom: 4px;
}
p {
font-size: 13px;
color: #666;
margin: 2px 0;
}
}
.file-summary {
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #e0e0e0;
}
.file-actions {
display: flex;
gap: 8px;
flex-shrink: 0;
}
</style>

View File

@@ -1,147 +0,0 @@
<template>
<div class="knowledge-base">
<div class="knowledge-header">
<el-input
v-model="searchKeyword"
placeholder="搜索知识库..."
prefix-icon="Search"
clearable
/>
</div>
<div class="knowledge-list">
<div
class="knowledge-item"
v-for="item in filteredKnowledge"
:key="item.id"
@click="viewKnowledge(item)"
>
<div class="item-icon">{{ item.icon }}</div>
<div class="item-info">
<h4>{{ item.title }}</h4>
<p>{{ item.description }}</p>
<div class="item-meta">
<span class="item-category">{{ item.category }}</span>
<span class="item-date">{{ item.updateDate }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { ElInput } from 'element-plus';
const searchKeyword = ref('');
const knowledgeList = ref<any[]>([]);
const filteredKnowledge = computed(() => {
if (!searchKeyword.value) return knowledgeList.value;
return knowledgeList.value.filter(item =>
item.title.includes(searchKeyword.value) ||
item.description.includes(searchKeyword.value)
);
});
onMounted(() => {
// TODO: 加载知识库数据
knowledgeList.value = [
{
id: 1,
icon: '📚',
title: '党的二十大精神',
description: '深入学习党的二十大精神要点',
category: '党史学习',
updateDate: '2024-01-15'
},
{
id: 2,
icon: '🎯',
title: '社会主义核心价值观',
description: '践行社会主义核心价值观',
category: '理论学习',
updateDate: '2024-01-10'
}
];
});
function viewKnowledge(item: any) {
// TODO: 查看知识详情
}
</script>
<style lang="scss" scoped>
.knowledge-base {
height: 100%;
display: flex;
flex-direction: column;
}
.knowledge-header {
padding: 16px;
border-bottom: 1px solid #e0e0e0;
}
.knowledge-list {
flex: 1;
overflow-y: auto;
padding: 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.knowledge-item {
display: flex;
gap: 12px;
padding: 16px;
background: #f9f9f9;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
&:hover {
background: #ffe6e6;
transform: translateX(4px);
}
}
.item-icon {
font-size: 32px;
flex-shrink: 0;
}
.item-info {
flex: 1;
h4 {
font-size: 15px;
font-weight: 600;
color: #141F38;
margin-bottom: 6px;
}
p {
font-size: 13px;
color: #666;
margin-bottom: 8px;
}
}
.item-meta {
display: flex;
gap: 12px;
font-size: 12px;
}
.item-category {
color: #C62828;
}
.item-date {
color: #999;
}
</style>