|
|
@@ -143,8 +143,17 @@
|
|
|
@close="resetForm"
|
|
|
>
|
|
|
<div class="dialog-content">
|
|
|
- <el-form :model="formData" ref="formRef" label-width="100px">
|
|
|
- <el-form-item label="📝 文档标题" :rules="[{ required: true, message: '请输入标题', trigger: 'blur' }]">
|
|
|
+ <!-- 输入方式切换 -->
|
|
|
+ <div class="input-mode-switch">
|
|
|
+ <el-radio-group v-model="inputMode" size="large" @change="handleModeChange">
|
|
|
+ <el-radio-button label="text">📝 文本输入</el-radio-button>
|
|
|
+ <el-radio-button label="pdf">📄 PDF上传</el-radio-button>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-form :model="formData" ref="formRef" label-width="140px">
|
|
|
+ <el-form-item v-if="inputMode === 'text'" label="📝 文档标题"
|
|
|
+ :rules="[{ required: inputMode === 'text', message: '请输入标题', trigger: 'blur' }]">
|
|
|
<el-input
|
|
|
v-model="formData.title"
|
|
|
placeholder="请输入文档标题"
|
|
|
@@ -152,7 +161,12 @@
|
|
|
></el-input>
|
|
|
</el-form-item>
|
|
|
|
|
|
- <el-form-item label="📄 文档内容" :rules="[{ required: true, message: '请输入文本内容', trigger: 'blur' }]">
|
|
|
+ <!-- 文本输入模式 -->
|
|
|
+ <el-form-item
|
|
|
+ v-if="inputMode === 'text'"
|
|
|
+ label="📄 文档内容"
|
|
|
+ :rules="[{ required: inputMode === 'text', message: '请输入文本内容', trigger: 'blur' }]"
|
|
|
+ >
|
|
|
<el-input
|
|
|
type="textarea"
|
|
|
v-model="formData.text"
|
|
|
@@ -162,7 +176,43 @@
|
|
|
></el-input>
|
|
|
</el-form-item>
|
|
|
|
|
|
- <el-form-item label="🔗 是否分块">
|
|
|
+ <!-- PDF上传模式 -->
|
|
|
+ <el-form-item
|
|
|
+ v-else
|
|
|
+ label="📄 PDF文件"
|
|
|
+ :rules="[{ required: inputMode === 'pdf', message: '请选择PDF文件', trigger: 'change' }]"
|
|
|
+ >
|
|
|
+ <div class="upload-area">
|
|
|
+ <el-upload
|
|
|
+ ref="uploadRef"
|
|
|
+ class="pdf-upload"
|
|
|
+ :action="uploadAction"
|
|
|
+ :file-list="fileList"
|
|
|
+ :before-upload="beforeUpload"
|
|
|
+ :on-success="handleUploadSuccess"
|
|
|
+ :limit="100"
|
|
|
+ accept=".pdf"
|
|
|
+ :auto-upload="true"
|
|
|
+ >
|
|
|
+ <template #trigger>
|
|
|
+ <div class="upload-trigger">
|
|
|
+ <div class="upload-icon">📎</div>
|
|
|
+ <div class="upload-text">
|
|
|
+ <p class="upload-title">点击选择PDF文件</p>
|
|
|
+ <!-- <p class="upload-subtitle">或拖拽文件到此处</p>-->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #tip>
|
|
|
+ <div class="upload-tip">
|
|
|
+ 支持上传单个PDF文件,大小不超过100MB
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-upload>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item v-if="inputMode === 'text'" label="🔗 是否分块">
|
|
|
<el-switch
|
|
|
v-model="formData.isChunk"
|
|
|
active-text="启用分块"
|
|
|
@@ -173,7 +223,7 @@
|
|
|
</div>
|
|
|
|
|
|
<template #footer>
|
|
|
- <div class="dialog-footer">
|
|
|
+ <div v-if="inputMode === 'text'" class="dialog-footer">
|
|
|
<el-button
|
|
|
class="action-btn secondary"
|
|
|
@click="dialogVisible = false"
|
|
|
@@ -183,9 +233,10 @@
|
|
|
<el-button
|
|
|
type="primary"
|
|
|
class="action-btn primary"
|
|
|
+ :loading="submitting"
|
|
|
@click="submitData"
|
|
|
>
|
|
|
- 💾 保存文档
|
|
|
+ 💾 {{ submitting ? '提交中...' : '保存文档' }}
|
|
|
</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
@@ -304,6 +355,7 @@ import {defineComponent, onMounted, ref, computed} from 'vue';
|
|
|
import {useRouter} from 'vue-router';
|
|
|
import axios from 'axios';
|
|
|
import {ElMessage, ElMessageBox} from 'element-plus';
|
|
|
+import type {UploadProps, UploadUserFile, UploadInstance} from 'element-plus';
|
|
|
|
|
|
interface Item {
|
|
|
doc_id: string;
|
|
|
@@ -330,13 +382,23 @@ export default defineComponent({
|
|
|
|
|
|
const allItems = ref<Item[]>([]);
|
|
|
|
|
|
+ // 输入模式:text 或 pdf
|
|
|
+ const inputMode = ref('text');
|
|
|
+ const uploadRef = ref<UploadInstance>();
|
|
|
+ const fileList = ref<UploadUserFile[]>([]);
|
|
|
+
|
|
|
// 新知识表单数据
|
|
|
const formData = ref({
|
|
|
title: '',
|
|
|
text: '',
|
|
|
- isChunk: true
|
|
|
+ isChunk: true,
|
|
|
+ fileId: '' // 用于存储上传后的文件ID
|
|
|
});
|
|
|
|
|
|
+ // 上传相关配置
|
|
|
+ const uploadAction = `${API_BASE_URL}/upload/file`;
|
|
|
+
|
|
|
+
|
|
|
const dialogVisible = ref(false);
|
|
|
const formRef = ref();
|
|
|
|
|
|
@@ -425,6 +487,29 @@ export default defineComponent({
|
|
|
formData.value.text = '';
|
|
|
};
|
|
|
|
|
|
+ // 文件上传前的验证
|
|
|
+ const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
|
|
+ if (rawFile.type !== 'application/pdf') {
|
|
|
+ ElMessage.error('只能上传PDF文件!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (rawFile.size / 1024 / 1024 > 100) {
|
|
|
+ ElMessage.error('文件大小不能超过100MB!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 文件上传成功处理
|
|
|
+ const handleUploadSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
|
|
|
+ // 根据实际返回数据结构判断
|
|
|
+ if (response.status_code === 200) {
|
|
|
+ ElMessage.success('文件上传成功!');
|
|
|
+ } else {
|
|
|
+ ElMessage.error(response.detail || '文件上传失败');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
// 提交表单数据
|
|
|
const submitData = async () => {
|
|
|
if (!formData.value.title || !formData.value.text) {
|
|
|
@@ -560,21 +645,27 @@ export default defineComponent({
|
|
|
statusDesc,
|
|
|
formRef,
|
|
|
goBack,
|
|
|
- handleSizeChange
|
|
|
+ handleSizeChange,
|
|
|
+ // 新增的上传相关
|
|
|
+ inputMode,
|
|
|
+ uploadRef,
|
|
|
+ fileList,
|
|
|
+ uploadAction,
|
|
|
+ beforeUpload,
|
|
|
+ handleUploadSuccess,
|
|
|
};
|
|
|
},
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-/* 基础样式 */
|
|
|
+/* 基础样式 - 保持不变 */
|
|
|
.app-container {
|
|
|
min-height: 100vh;
|
|
|
background: linear-gradient(135deg, rgba(102, 126, 234, 0.6) 0%, rgba(118, 75, 162, 0.4) 100%);
|
|
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
}
|
|
|
|
|
|
-/* 顶部导航样式 */
|
|
|
.app-header {
|
|
|
background: rgba(255, 255, 255, 0.1);
|
|
|
backdrop-filter: blur(20px);
|
|
|
@@ -620,12 +711,6 @@ export default defineComponent({
|
|
|
box-shadow: 0 8px 25px rgba(255, 255, 255, 0.2);
|
|
|
}
|
|
|
|
|
|
-.back-icon {
|
|
|
- color: white;
|
|
|
- margin-right: 6px;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
-
|
|
|
.header-titles {
|
|
|
flex: 1;
|
|
|
}
|
|
|
@@ -795,25 +880,6 @@ export default defineComponent({
|
|
|
white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
-.document-status {
|
|
|
- font-size: 0.75rem;
|
|
|
- font-weight: 500;
|
|
|
- padding: 2px 8px;
|
|
|
- border-radius: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.document-status.available {
|
|
|
- background: #f0fff4;
|
|
|
- color: #2f855a;
|
|
|
- border: 1px solid #c6f6d5;
|
|
|
-}
|
|
|
-
|
|
|
-.document-status.unavailable {
|
|
|
- background: #fed7d7;
|
|
|
- color: #c53030;
|
|
|
- border: 1px solid #feb2b2;
|
|
|
-}
|
|
|
-
|
|
|
.document-actions {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
@@ -853,10 +919,6 @@ export default defineComponent({
|
|
|
margin: 0;
|
|
|
}
|
|
|
|
|
|
-.custom-pagination :deep(.el-pagination) {
|
|
|
- justify-content: flex-end;
|
|
|
-}
|
|
|
-
|
|
|
/* 主内容区样式 */
|
|
|
.content-area {
|
|
|
flex: 1;
|
|
|
@@ -984,9 +1046,8 @@ export default defineComponent({
|
|
|
}
|
|
|
|
|
|
.content-dialog :deep(.el-dialog__header) {
|
|
|
- padding: 0;
|
|
|
+ padding: 24px 24px 0;
|
|
|
margin: 0;
|
|
|
- border-bottom: 1px solid #e2e8f0;
|
|
|
}
|
|
|
|
|
|
.content-dialog :deep(.el-dialog__headerbtn) {
|
|
|
@@ -1009,7 +1070,7 @@ export default defineComponent({
|
|
|
}
|
|
|
|
|
|
.dialog-content {
|
|
|
- padding: 0;
|
|
|
+ padding: 0 24px;
|
|
|
}
|
|
|
|
|
|
.content-dialog :deep(.el-form-item__label) {
|
|
|
@@ -1037,7 +1098,7 @@ export default defineComponent({
|
|
|
}
|
|
|
|
|
|
.dialog-footer {
|
|
|
- padding: 0;
|
|
|
+ padding: 0 24px 24px;
|
|
|
margin-top: 24px;
|
|
|
display: flex;
|
|
|
justify-content: flex-end;
|
|
|
@@ -1075,7 +1136,105 @@ export default defineComponent({
|
|
|
box-shadow: 0 4px 12px rgba(66, 153, 225, 0.3);
|
|
|
}
|
|
|
|
|
|
-/* 分段弹窗样式 */
|
|
|
+/* 新增的上传相关样式 */
|
|
|
+.input-mode-switch {
|
|
|
+ margin-bottom: 24px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.input-mode-switch :deep(.el-radio-group) {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.input-mode-switch :deep(.el-radio-button) {
|
|
|
+ width: 50%;
|
|
|
+}
|
|
|
+
|
|
|
+.input-mode-switch :deep(.el-radio-button__inner) {
|
|
|
+ width: 100%;
|
|
|
+ padding: 12px 20px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-area {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-upload {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-upload :deep(.el-upload) {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-upload :deep(.el-upload-dragger) {
|
|
|
+ width: 100%;
|
|
|
+ height: 160px;
|
|
|
+ border: 2px dashed #e2e8f0;
|
|
|
+ border-radius: 12px;
|
|
|
+ background: #fafbfc;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-upload :deep(.el-upload-dragger:hover) {
|
|
|
+ border-color: #4299e1;
|
|
|
+ background: #f0f9ff;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-trigger {
|
|
|
+ text-align: center;
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-icon {
|
|
|
+ font-size: 2.5rem;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ opacity: 0.7;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-title {
|
|
|
+ font-size: 1.1rem;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #2d3748;
|
|
|
+ margin: 0 0 6px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-subtitle {
|
|
|
+ font-size: 0.9rem;
|
|
|
+ color: #718096;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-tip {
|
|
|
+ margin-top: 12px;
|
|
|
+ text-align: center;
|
|
|
+ color: #a0aec0;
|
|
|
+ font-size: 0.85rem;
|
|
|
+}
|
|
|
+
|
|
|
+/* 文件列表样式 */
|
|
|
+.pdf-upload :deep(.el-upload-list) {
|
|
|
+ margin-top: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-upload :deep(.el-upload-list__item) {
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.pdf-upload :deep(.el-upload-list__item:hover) {
|
|
|
+ background-color: #f7fafc;
|
|
|
+}
|
|
|
+
|
|
|
+/* 分段弹窗样式 - 保持不变 */
|
|
|
.chunk-content {
|
|
|
padding: 0;
|
|
|
}
|
|
|
@@ -1209,6 +1368,19 @@ export default defineComponent({
|
|
|
.add-btn {
|
|
|
width: 100%;
|
|
|
}
|
|
|
+
|
|
|
+ .input-mode-switch :deep(.el-radio-button__inner) {
|
|
|
+ padding: 10px 16px;
|
|
|
+ font-size: 13px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-trigger {
|
|
|
+ padding: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-icon {
|
|
|
+ font-size: 2rem;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@media (max-width: 480px) {
|
|
|
@@ -1331,12 +1503,6 @@ export default defineComponent({
|
|
|
gap: 20px;
|
|
|
}
|
|
|
|
|
|
-.stat-item {
|
|
|
- color: #64748b;
|
|
|
- font-size: 0.9rem;
|
|
|
- font-weight: 500;
|
|
|
-}
|
|
|
-
|
|
|
.chunk-content {
|
|
|
flex: 1;
|
|
|
overflow: auto;
|
|
|
@@ -1397,25 +1563,6 @@ export default defineComponent({
|
|
|
padding-right: 8px;
|
|
|
}
|
|
|
|
|
|
-/* 自定义滚动条 */
|
|
|
-.full-content::-webkit-scrollbar {
|
|
|
- width: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.full-content::-webkit-scrollbar-track {
|
|
|
- background: #f1f5f9;
|
|
|
- border-radius: 2px;
|
|
|
-}
|
|
|
-
|
|
|
-.full-content::-webkit-scrollbar-thumb {
|
|
|
- background: #cbd5e1;
|
|
|
- border-radius: 2px;
|
|
|
-}
|
|
|
-
|
|
|
-.full-content::-webkit-scrollbar-thumb:hover {
|
|
|
- background: #94a3b8;
|
|
|
-}
|
|
|
-
|
|
|
.status-tag {
|
|
|
border: none;
|
|
|
font-weight: 600;
|
|
|
@@ -1423,33 +1570,6 @@ export default defineComponent({
|
|
|
border-radius: 20px;
|
|
|
}
|
|
|
|
|
|
-.empty-chunks {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- height: 300px;
|
|
|
- color: #64748b;
|
|
|
-}
|
|
|
-
|
|
|
-.empty-icon {
|
|
|
- font-size: 4rem;
|
|
|
- margin-bottom: 16px;
|
|
|
- opacity: 0.5;
|
|
|
-}
|
|
|
-
|
|
|
-.empty-chunks h3 {
|
|
|
- margin: 0 0 8px 0;
|
|
|
- color: #475569;
|
|
|
- font-size: 1.25rem;
|
|
|
- font-weight: 600;
|
|
|
-}
|
|
|
-
|
|
|
-.empty-chunks p {
|
|
|
- margin: 0;
|
|
|
- font-size: 0.9rem;
|
|
|
-}
|
|
|
-
|
|
|
.pagination-section {
|
|
|
padding: 20px 24px;
|
|
|
background: #f8fafc;
|
|
|
@@ -1461,25 +1581,4 @@ export default defineComponent({
|
|
|
.pagination-section :deep(.el-pagination) {
|
|
|
justify-content: center;
|
|
|
}
|
|
|
-
|
|
|
-.pagination-section :deep(.el-pagination .btn-prev),
|
|
|
-.pagination-section :deep(.el-pagination .btn-next) {
|
|
|
- border-radius: 8px;
|
|
|
- border: 1px solid #d1d5db;
|
|
|
-}
|
|
|
-
|
|
|
-.pagination-section :deep(.el-pagination .number) {
|
|
|
- border-radius: 8px;
|
|
|
- border: 1px solid #d1d5db;
|
|
|
-}
|
|
|
-
|
|
|
-.pagination-section :deep(.el-pagination .number.active) {
|
|
|
- background: #3b82f6;
|
|
|
- border-color: #3b82f6;
|
|
|
- color: white;
|
|
|
-}
|
|
|
-
|
|
|
-.pagination-section :deep(.el-pagination .el-select .el-input) {
|
|
|
- border-radius: 8px;
|
|
|
-}
|
|
|
</style>
|