|
|
@@ -40,39 +40,15 @@
|
|
|
|
|
|
<!-- 我的报告面板 -->
|
|
|
<div class="panel-body reports-panel" v-show="leftPanelTab === 'reports'">
|
|
|
- <!-- 新建报告按钮(带下拉菜单) -->
|
|
|
- <el-popover
|
|
|
- placement="bottom-start"
|
|
|
- :width="240"
|
|
|
- trigger="click"
|
|
|
- popper-class="new-report-popover"
|
|
|
+ <!-- 新建报告按钮 -->
|
|
|
+ <el-button
|
|
|
+ class="new-report-btn"
|
|
|
+ type="primary"
|
|
|
+ :icon="Plus"
|
|
|
+ @click="showNewReportDialog = true"
|
|
|
>
|
|
|
- <template #reference>
|
|
|
- <el-button
|
|
|
- class="new-report-btn"
|
|
|
- type="primary"
|
|
|
- :icon="Plus"
|
|
|
- >
|
|
|
- 新建报告
|
|
|
- </el-button>
|
|
|
- </template>
|
|
|
- <div class="new-report-menu">
|
|
|
- <div class="menu-item" @click="handleCreateReport">
|
|
|
- <div class="menu-icon">📄</div>
|
|
|
- <div class="menu-content">
|
|
|
- <div class="menu-title">创建空白报告</div>
|
|
|
- <div class="menu-desc">从零开始创建新报告</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="menu-item" @click="handleUploadFile">
|
|
|
- <div class="menu-icon">📁</div>
|
|
|
- <div class="menu-content">
|
|
|
- <div class="menu-title">上传文件创建</div>
|
|
|
- <div class="menu-desc">上传 PDF/Word 自动解析</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-popover>
|
|
|
+ 新建报告
|
|
|
+ </el-button>
|
|
|
|
|
|
<!-- 报告搜索 -->
|
|
|
<el-input
|
|
|
@@ -420,6 +396,91 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
+ <!-- 新建报告对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="showNewReportDialog"
|
|
|
+ title="新建报告"
|
|
|
+ width="460"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ class="new-report-dialog"
|
|
|
+ >
|
|
|
+ <div class="new-report-form">
|
|
|
+ <!-- 创建方式选择 -->
|
|
|
+ <div class="create-type-section">
|
|
|
+ <div class="section-label">创建方式</div>
|
|
|
+ <div class="create-type-options">
|
|
|
+ <div
|
|
|
+ class="type-option"
|
|
|
+ :class="{ active: newReportType === 'blank' }"
|
|
|
+ @click="newReportType = 'blank'"
|
|
|
+ >
|
|
|
+ <div class="option-icon">📄</div>
|
|
|
+ <div class="option-content">
|
|
|
+ <div class="option-title">空白报告</div>
|
|
|
+ <div class="option-desc">从零开始创建</div>
|
|
|
+ </div>
|
|
|
+ <div class="option-check" v-if="newReportType === 'blank'">✓</div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="type-option"
|
|
|
+ :class="{ active: newReportType === 'upload' }"
|
|
|
+ @click="newReportType = 'upload'"
|
|
|
+ >
|
|
|
+ <div class="option-icon">📁</div>
|
|
|
+ <div class="option-content">
|
|
|
+ <div class="option-title">上传文件</div>
|
|
|
+ <div class="option-desc">PDF/Word 自动解析</div>
|
|
|
+ </div>
|
|
|
+ <div class="option-check" v-if="newReportType === 'upload'">✓</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 报告名称输入 -->
|
|
|
+ <div class="name-input-section">
|
|
|
+ <div class="section-label">报告名称</div>
|
|
|
+ <el-input
|
|
|
+ v-model="newReportName"
|
|
|
+ placeholder="请输入报告名称"
|
|
|
+ maxlength="50"
|
|
|
+ show-word-limit
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 文件上传区域(仅上传方式显示) -->
|
|
|
+ <div class="upload-section" v-if="newReportType === 'upload'">
|
|
|
+ <div class="section-label">上传文件</div>
|
|
|
+ <el-upload
|
|
|
+ ref="newReportUploadRef"
|
|
|
+ class="report-upload-area"
|
|
|
+ drag
|
|
|
+ :auto-upload="false"
|
|
|
+ :limit="1"
|
|
|
+ :on-change="handleNewReportFileChange"
|
|
|
+ :on-exceed="handleNewReportFileExceed"
|
|
|
+ accept=".pdf,.doc,.docx"
|
|
|
+ >
|
|
|
+ <div class="upload-content">
|
|
|
+ <el-icon class="upload-icon"><Upload /></el-icon>
|
|
|
+ <div class="upload-text">拖拽文件到此处,或<em>点击上传</em></div>
|
|
|
+ <div class="upload-hint">支持 PDF、Word 文档</div>
|
|
|
+ </div>
|
|
|
+ </el-upload>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="showNewReportDialog = false">取消</el-button>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ @click="handleConfirmCreateReport"
|
|
|
+ :disabled="!newReportName.trim()"
|
|
|
+ :loading="creatingReport"
|
|
|
+ >
|
|
|
+ 创建
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
<!-- 添加来源文件对话框 -->
|
|
|
<el-dialog v-model="showAddSourceDialog" title="添加来源文件定义" width="400">
|
|
|
<el-form :model="newSourceFile" label-width="80px">
|
|
|
@@ -577,7 +638,7 @@
|
|
|
import { ref, reactive, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
|
import {
|
|
|
- ArrowLeft, Clock, Share, Check, Plus, Delete, Connection, Refresh, Search, Loading
|
|
|
+ ArrowLeft, Clock, Share, Check, Plus, Delete, Connection, Refresh, Search, Loading, Upload
|
|
|
} from '@element-plus/icons-vue'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
import { useTemplateStore } from '@/stores/template'
|
|
|
@@ -810,50 +871,74 @@ async function loadDocumentById(documentId) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 新建报告
|
|
|
-async function handleCreateReport() {
|
|
|
+// 新建报告对话框 - 文件选择变化
|
|
|
+function handleNewReportFileChange(file) {
|
|
|
+ newReportFile.value = file.raw
|
|
|
+}
|
|
|
+
|
|
|
+// 新建报告对话框 - 文件超出限制
|
|
|
+function handleNewReportFileExceed() {
|
|
|
+ ElMessage.warning('只能上传一个文件')
|
|
|
+}
|
|
|
+
|
|
|
+// 新建报告对话框 - 重置
|
|
|
+function resetNewReportDialog() {
|
|
|
+ newReportType.value = 'blank'
|
|
|
+ newReportName.value = ''
|
|
|
+ newReportFile.value = null
|
|
|
+ if (newReportUploadRef.value) {
|
|
|
+ newReportUploadRef.value.clearFiles()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 新建报告对话框 - 确认创建
|
|
|
+async function handleConfirmCreateReport() {
|
|
|
+ if (!newReportName.value.trim()) {
|
|
|
+ ElMessage.warning('请输入报告名称')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ creatingReport.value = true
|
|
|
try {
|
|
|
- const { value: reportName } = await ElMessageBox.prompt('请输入报告名称', '新建报告', {
|
|
|
- confirmButtonText: '创建',
|
|
|
- cancelButtonText: '取消',
|
|
|
- inputPattern: /\S+/,
|
|
|
- inputErrorMessage: '报告名称不能为空'
|
|
|
- })
|
|
|
+ // 先创建报告
|
|
|
+ const newReport = await templateApi.create({ name: newReportName.value.trim() })
|
|
|
|
|
|
- if (reportName) {
|
|
|
- const newReport = await templateApi.create({ name: reportName })
|
|
|
+ // 如果是上传模式且有文件,上传文件
|
|
|
+ if (newReportType.value === 'upload' && newReportFile.value) {
|
|
|
+ try {
|
|
|
+ await sourceFileApi.upload(newReport.id, newReportFile.value)
|
|
|
+ ElMessage.success('报告创建成功,文件上传中...')
|
|
|
+ } catch (uploadError) {
|
|
|
+ console.error('文件上传失败:', uploadError)
|
|
|
+ ElMessage.warning('报告已创建,但文件上传失败')
|
|
|
+ }
|
|
|
+ } else {
|
|
|
ElMessage.success('报告创建成功')
|
|
|
- // 刷新报告列表
|
|
|
- await loadMyReports()
|
|
|
- // 如果新报告有文档,切换到该报告
|
|
|
- if (newReport && newReport.baseDocumentId) {
|
|
|
- await switchReport(newReport)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 关闭对话框并重置
|
|
|
+ showNewReportDialog.value = false
|
|
|
+ resetNewReportDialog()
|
|
|
+
|
|
|
+ // 刷新报告列表
|
|
|
+ await loadMyReports()
|
|
|
+
|
|
|
+ // 切换到新报告
|
|
|
+ if (newReport) {
|
|
|
+ await switchReport(newReport)
|
|
|
+ // 如果是上传模式,切换到资源 Tab
|
|
|
+ if (newReportType.value === 'upload') {
|
|
|
+ leftPanelTab.value = 'files'
|
|
|
}
|
|
|
}
|
|
|
} catch (error) {
|
|
|
- if (error !== 'cancel') {
|
|
|
- console.error('创建报告失败:', error)
|
|
|
- ElMessage.error('创建报告失败')
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 上传文件入口
|
|
|
-function handleUploadFile() {
|
|
|
- // 先选择一个报告,然后切换到资源 Tab
|
|
|
- if (myReports.value.length > 0) {
|
|
|
- leftPanelTab.value = 'reports'
|
|
|
- ElMessage.info('请先选择一个报告,然后在资源面板上传文件')
|
|
|
- } else {
|
|
|
- ElMessage.info('请先创建一个报告')
|
|
|
+ console.error('创建报告失败:', error)
|
|
|
+ ElMessage.error('创建报告失败')
|
|
|
+ } finally {
|
|
|
+ creatingReport.value = false
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// AI 辅助入口
|
|
|
-function handleAiAssist() {
|
|
|
- ElMessage.info('AI 辅助功能开发中...')
|
|
|
-}
|
|
|
-
|
|
|
// 格式化报告时间
|
|
|
function formatReportTime(dateStr) {
|
|
|
if (!dateStr) return ''
|
|
|
@@ -884,6 +969,14 @@ function getReportStatusText(status) {
|
|
|
return statusMap[status] || '草稿'
|
|
|
}
|
|
|
|
|
|
+// 新建报告对话框
|
|
|
+const showNewReportDialog = ref(false)
|
|
|
+const newReportType = ref('blank') // 'blank' | 'upload'
|
|
|
+const newReportName = ref('')
|
|
|
+const newReportFile = ref(null)
|
|
|
+const newReportUploadRef = ref(null)
|
|
|
+const creatingReport = ref(false)
|
|
|
+
|
|
|
// 来源文件(从 API 获取)
|
|
|
const sourceFiles = ref([])
|
|
|
const selectedFile = ref(null)
|
|
|
@@ -2762,48 +2855,6 @@ onUnmounted(() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 新建报告下拉菜单样式
|
|
|
- .new-report-menu {
|
|
|
- padding: 4px 0;
|
|
|
-
|
|
|
- .menu-item {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- gap: 12px;
|
|
|
- padding: 12px 14px;
|
|
|
- cursor: pointer;
|
|
|
- border-radius: var(--radius-sm);
|
|
|
- transition: all 0.2s;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- background: var(--bg);
|
|
|
- }
|
|
|
-
|
|
|
- .menu-icon {
|
|
|
- font-size: 24px;
|
|
|
- flex-shrink: 0;
|
|
|
- line-height: 1;
|
|
|
- }
|
|
|
-
|
|
|
- .menu-content {
|
|
|
- flex: 1;
|
|
|
- min-width: 0;
|
|
|
- }
|
|
|
-
|
|
|
- .menu-title {
|
|
|
- font-size: 14px;
|
|
|
- font-weight: 500;
|
|
|
- color: var(--text-1);
|
|
|
- margin-bottom: 4px;
|
|
|
- }
|
|
|
-
|
|
|
- .menu-desc {
|
|
|
- font-size: 12px;
|
|
|
- color: var(--text-3);
|
|
|
- line-height: 1.4;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
.report-search {
|
|
|
:deep(.el-input__wrapper) {
|
|
|
@@ -4364,4 +4415,166 @@ onUnmounted(() => {
|
|
|
box-shadow: none;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// ==========================================
|
|
|
+// 新建报告对话框样式
|
|
|
+// ==========================================
|
|
|
+.new-report-dialog {
|
|
|
+ :deep(.el-dialog__header) {
|
|
|
+ padding: 16px 20px;
|
|
|
+ border-bottom: 1px solid var(--border);
|
|
|
+ margin-right: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-dialog__body) {
|
|
|
+ padding: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-dialog__footer) {
|
|
|
+ padding: 12px 20px;
|
|
|
+ border-top: 1px solid var(--border);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.new-report-form {
|
|
|
+ .section-label {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: var(--text-2);
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .create-type-section {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .create-type-options {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .type-option {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ gap: 12px;
|
|
|
+ padding: 14px;
|
|
|
+ background: var(--bg);
|
|
|
+ border: 2px solid var(--border);
|
|
|
+ border-radius: var(--radius-md);
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: var(--primary-light);
|
|
|
+ background: var(--white);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ border-color: var(--primary);
|
|
|
+ background: var(--primary-light);
|
|
|
+
|
|
|
+ .option-title {
|
|
|
+ color: var(--primary);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .option-icon {
|
|
|
+ font-size: 24px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ line-height: 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .option-content {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .option-title {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--text-1);
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .option-desc {
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--text-3);
|
|
|
+ line-height: 1.4;
|
|
|
+ }
|
|
|
+
|
|
|
+ .option-check {
|
|
|
+ position: absolute;
|
|
|
+ top: 8px;
|
|
|
+ right: 8px;
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ background: var(--primary);
|
|
|
+ color: white;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .name-input-section {
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ :deep(.el-input__wrapper) {
|
|
|
+ border-radius: var(--radius-sm);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-section {
|
|
|
+ .report-upload-area {
|
|
|
+ :deep(.el-upload) {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.el-upload-dragger) {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ padding: 24px;
|
|
|
+ border-radius: var(--radius-md);
|
|
|
+ border: 2px dashed var(--border);
|
|
|
+ background: var(--bg);
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: var(--primary);
|
|
|
+ background: var(--primary-light);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-content {
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-icon {
|
|
|
+ font-size: 32px;
|
|
|
+ color: var(--text-3);
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-text {
|
|
|
+ font-size: 14px;
|
|
|
+ color: var(--text-2);
|
|
|
+ margin-bottom: 4px;
|
|
|
+
|
|
|
+ em {
|
|
|
+ color: var(--primary);
|
|
|
+ font-style: normal;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-hint {
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--text-3);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|