删除无用代码
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">支持 PDF、Word、TXT 格式</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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user