|
|
@@ -69,13 +69,14 @@
|
|
|
</div>
|
|
|
<!-- 考试工坊主界面 -->
|
|
|
<div v-if="!showExamDetail" class="exam-workshop-card app-container">
|
|
|
- <!-- 中间主操作区 -->
|
|
|
- <main class="main-content" style="padding-top: 36px;">
|
|
|
+ <!-- 中间主操作区 -->
|
|
|
+ <main class="main-content" style="padding-top: 36px; position: relative;">
|
|
|
+ <!-- 返回AI问答按钮 -->
|
|
|
+ <button v-if="!showExamDetail" class="return-ai-btn has-before" @click="handleReturnToAI">
|
|
|
+ 返回AI问答
|
|
|
+ </button>
|
|
|
+
|
|
|
<div class="form-group" style="position: relative;">
|
|
|
- <!-- 返回AI问答按钮 -->
|
|
|
- <button v-if="hideSidebar && !showExamDetail" class="return-ai-btn" @click="handleReturnToAI">
|
|
|
- 返回AI问答
|
|
|
- </button>
|
|
|
<label class="form-label">试卷名称</label>
|
|
|
<input type="text" class="form-control" v-model="examName" maxlength="32" placeholder="请输入试卷名称..." :disabled="isGenerating">
|
|
|
<div class="char-count">{{ examName?.length || 0 }}/32</div>
|
|
|
@@ -83,23 +84,27 @@
|
|
|
|
|
|
<div class="form-group">
|
|
|
<label class="form-label">出题依据内容</label>
|
|
|
- <textarea class="form-control" v-model="questionBasis" placeholder="在此输入知识点、章节或培训内容..." :disabled="isGenerating || selectedFile"></textarea>
|
|
|
+ <textarea class="form-control" v-model="questionBasis" placeholder="在此输入知识点、章节或培训内容..." :disabled="isGenerating || uploadedFiles.length > 0"></textarea>
|
|
|
|
|
|
- <div class="ppt-upload-section" @click="!isGenerating && !selectedFile ? triggerFileUpload() : null">
|
|
|
- <div class="ppt-upload-content">
|
|
|
- <div class="ppt-upload-icon-wrapper">
|
|
|
- <el-icon style="font-size: 28px; color: #4b5563;"><UploadFilled /></el-icon>
|
|
|
- </div>
|
|
|
- <div class="ppt-upload-text-wrapper">
|
|
|
- <div class="ppt-upload-title">从PPT生成考题</div>
|
|
|
- <div class="ppt-upload-hint">上传培训PPT,智能提取关键内容生成考题(单个文件可上传20M内)</div>
|
|
|
+ <div class="ppt-upload-section" style="flex-direction: column; align-items: flex-start;" @click="!isGenerating ? triggerFileUpload() : null">
|
|
|
+ <div style="display: flex; width: 100%; justify-content: space-between; align-items: center;">
|
|
|
+ <div class="ppt-upload-content">
|
|
|
+ <div class="ppt-upload-icon-wrapper">
|
|
|
+ <el-icon style="font-size: 28px; color: #4b5563;"><UploadFilled /></el-icon>
|
|
|
+ </div>
|
|
|
+ <div class="ppt-upload-text-wrapper">
|
|
|
+ <div class="ppt-upload-title">从PPT生成考题</div>
|
|
|
+ <div class="ppt-upload-hint">上传培训PPT,智能提取关键内容生成考题(支持多文件,单文件20M内)</div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+ <el-icon class="ppt-arrow"><ArrowRight /></el-icon>
|
|
|
</div>
|
|
|
- <el-icon class="ppt-arrow"><ArrowRight /></el-icon>
|
|
|
|
|
|
- <div v-if="selectedFile" class="file-status-badge" @click.stop>
|
|
|
- <span class="file-name truncate">已上传: {{ selectedFile.name }}</span>
|
|
|
- <span @click.stop="removeSelectedFile" class="remove-btn">×</span>
|
|
|
+ <div v-if="uploadedFiles.length > 0" class="files-list" @click.stop style="width: 100%; display: flex; flex-wrap: wrap; gap: 8px;">
|
|
|
+ <div v-for="(file, index) in uploadedFiles" :key="index" class="file-status-badge">
|
|
|
+ <span class="file-name truncate">已上传: {{ file.name }}</span>
|
|
|
+ <span @click.stop="removeSelectedFile(index)" class="remove-btn">×</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -209,12 +214,11 @@
|
|
|
<!-- 详情页头部 -->
|
|
|
<div class="detail-header">
|
|
|
<div class="header-left">
|
|
|
- <button class="back-btn" @click="backToConfig" :disabled="isGenerating">
|
|
|
- <span class="back-arrow">←</span>
|
|
|
+ </div>
|
|
|
+ <div class="header-right" style="display: flex; align-items: center; gap: 12px;">
|
|
|
+ <button class="return-ai-btn has-before" style="position: static;" @click="backToConfig" :disabled="isGenerating">
|
|
|
返回修改
|
|
|
</button>
|
|
|
- </div>
|
|
|
- <div class="header-right">
|
|
|
<!-- <button class="save-btn" @click="saveExam" :disabled="isGenerating">
|
|
|
<img :src="saveIcon" alt="保存试卷" class="save-icon" />
|
|
|
</button> -->
|
|
|
@@ -565,6 +569,7 @@
|
|
|
ref="fileInput"
|
|
|
type="file"
|
|
|
accept=".ppt,.pptx"
|
|
|
+ multiple
|
|
|
style="display: none"
|
|
|
@change="handleFileSelect"
|
|
|
/>
|
|
|
@@ -583,6 +588,7 @@
|
|
|
|
|
|
<script setup>
|
|
|
import { ref, computed, onMounted, onUnmounted, reactive, watch, defineProps, defineEmits } from "vue";
|
|
|
+import { useRoute, useRouter } from "vue-router";
|
|
|
import Sidebar from "@/components/Sidebar.vue";
|
|
|
import DeleteConfirmModal from "@/components/DeleteConfirmModal.vue";
|
|
|
import { UploadFilled, ArrowRight, Delete, MagicStick, Loading } from '@element-plus/icons-vue';
|
|
|
@@ -596,6 +602,9 @@ const props = defineProps({
|
|
|
|
|
|
const emit = defineEmits(['return-to-ai']);
|
|
|
|
|
|
+const route = useRoute();
|
|
|
+const router = useRouter();
|
|
|
+
|
|
|
const handleReturnToAI = () => {
|
|
|
emit('return-to-ai');
|
|
|
};
|
|
|
@@ -655,7 +664,7 @@ const editModalData = ref({
|
|
|
|
|
|
// PPT文件上传相关
|
|
|
const fileInput = ref(null);
|
|
|
-const selectedFile = ref(null);
|
|
|
+const uploadedFiles = ref([]);
|
|
|
const isUploadingFile = ref(false);
|
|
|
const fileContent = ref(''); // 存储文件内容
|
|
|
const pptContentDescription = ref(''); // 存储用户输入的PPT内容描述
|
|
|
@@ -693,22 +702,6 @@ const currentExam = ref(null);
|
|
|
const historyData = ref([])
|
|
|
const historyTotal = ref(0) // 历史记录总数
|
|
|
|
|
|
-
|
|
|
-const isExamWorkshopConversation = (conversation = {}) => {
|
|
|
- const content = String(conversation.content || '')
|
|
|
- const title = String(conversation.title || '')
|
|
|
- const examName = String(conversation.exam_name || '')
|
|
|
-
|
|
|
- return (
|
|
|
- Number(conversation.business_type) === 3 ||
|
|
|
- !!examName.trim() ||
|
|
|
- title.includes('技术考核') ||
|
|
|
- content.includes('请根据以下要求直接生成一份完整试卷') ||
|
|
|
- content.includes('"singleChoice"') ||
|
|
|
- content.includes('"totalQuestions"')
|
|
|
- )
|
|
|
-}
|
|
|
-
|
|
|
// 获取历史记录列表
|
|
|
const getHistoryRecordList = async () => {
|
|
|
try {
|
|
|
@@ -717,9 +710,8 @@ const getHistoryRecordList = async () => {
|
|
|
const startTime = performance.now()
|
|
|
|
|
|
const response = await apis.getHistoryRecord({
|
|
|
- // ===== 已删除:user_id - 后端从token解析 =====
|
|
|
- ai_conversation_id: 0, // 0表示获取对话列表
|
|
|
- business_type: 3 // 考试工坊类型
|
|
|
+ ai_conversation_id: 0,
|
|
|
+ business_type: 3
|
|
|
})
|
|
|
|
|
|
const endTime = performance.now()
|
|
|
@@ -727,46 +719,19 @@ const getHistoryRecordList = async () => {
|
|
|
console.log('📋 考试工坊历史记录列表响应:', response)
|
|
|
|
|
|
if (response.statusCode === 200) {
|
|
|
- const directConversations = Array.isArray(response.data) ? response.data : []
|
|
|
- let conversations = [...directConversations]
|
|
|
-
|
|
|
- const fallbackResponse = await apis.getHistoryRecord({
|
|
|
- ai_conversation_id: 0
|
|
|
- })
|
|
|
-
|
|
|
- if (fallbackResponse.statusCode === 200 && Array.isArray(fallbackResponse.data)) {
|
|
|
- const inferredExamConversations = fallbackResponse.data.filter(isExamWorkshopConversation)
|
|
|
- const conversationMap = new Map()
|
|
|
-
|
|
|
- directConversations.concat(inferredExamConversations).forEach((conversation) => {
|
|
|
- if (!conversation?.id) return
|
|
|
- conversationMap.set(conversation.id, conversation)
|
|
|
- })
|
|
|
-
|
|
|
- conversations = Array.from(conversationMap.values()).sort((a, b) => {
|
|
|
- return Number(b.updated_at || 0) - Number(a.updated_at || 0)
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- // 设置历史记录总数
|
|
|
- historyTotal.value = conversations.length
|
|
|
-
|
|
|
- // 转换后端数据为前端格式
|
|
|
- historyData.value = conversations.map(conversation => ({
|
|
|
+ historyTotal.value = response.total || 0
|
|
|
+ historyData.value = response.data.map(conversation => ({
|
|
|
id: conversation.id,
|
|
|
- title: generateConversationTitle(conversation.exam_name || conversation.title || conversation.content),
|
|
|
+ title: generateConversationTitle(conversation.exam_name),
|
|
|
time: formatTime(conversation.updated_at),
|
|
|
businessType: conversation.business_type,
|
|
|
isActive: false,
|
|
|
- // 保存原始数据用于后续查询
|
|
|
rawData: conversation
|
|
|
}))
|
|
|
console.log(`✅ 考试工坊历史记录列表已设置: ${historyData.value.length}条记录,总数: ${historyTotal.value}`)
|
|
|
} else {
|
|
|
console.error('❌ 获取考试工坊历史记录列表失败:', response.statusCode)
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.error('❌ 获取考试工坊历史记录列表失败:', error)
|
|
|
} finally {
|
|
|
isLoadingHistory.value = false
|
|
|
}
|
|
|
@@ -902,7 +867,7 @@ const confirmDeleteHistory = async () => {
|
|
|
|
|
|
if (response.statusCode === 200) {
|
|
|
// 删除成功,从列表中移除
|
|
|
- historyData.value.splice(index, 1)
|
|
|
+ removeExamWorkshopHistory(historyItem.id)
|
|
|
|
|
|
// 如果删除的是当前激活的历史记录,需要清空界面并调用新建任务
|
|
|
if (historyItem.isActive) {
|
|
|
@@ -980,7 +945,7 @@ const createNewChat = async () => {
|
|
|
isRefreshing.value = {};
|
|
|
|
|
|
// 清理文件
|
|
|
- selectedFile.value = null;
|
|
|
+ uploadedFiles.value = [];
|
|
|
pptContentDescription.value = '';
|
|
|
|
|
|
// 清除所有历史记录的选中状态
|
|
|
@@ -1000,25 +965,20 @@ const handleHistoryItem = async (historyItem) => {
|
|
|
isLoadingHistoryItem.value = true;
|
|
|
|
|
|
try {
|
|
|
- // 设置当前点击的历史记录为激活状态
|
|
|
historyData.value.forEach((item) => {
|
|
|
item.isActive = item.id === historyItem.id;
|
|
|
});
|
|
|
|
|
|
- // 获取该历史记录的详细内容
|
|
|
const response = await apis.getHistoryRecord({
|
|
|
- // ===== 已删除:user_id - 后端从token解析 =====
|
|
|
- ai_conversation_id: historyItem.id, // 使用历史记录的ID作为ai_conversation_id
|
|
|
- business_type: 3 // 考试工坊类型
|
|
|
+ ai_conversation_id: historyItem.id,
|
|
|
+ business_type: 3
|
|
|
});
|
|
|
console.log(response.data)
|
|
|
if (response.statusCode === 200 && response.data && response.data.length > 0) {
|
|
|
- // 获取最新的试卷数据(取最新的AI消息)
|
|
|
- const latestRecord = response.data[response.data.length - 1]; // 获取最新记录
|
|
|
+ const latestRecord = response.data[response.data.length - 1];
|
|
|
console.log('获取到的试卷数据:', latestRecord);
|
|
|
console.log('试卷数据结构:', JSON.stringify(latestRecord, null, 2));
|
|
|
currentTime.value = formatTime(latestRecord.created_at)
|
|
|
- // 解析试卷数据并恢复
|
|
|
if (latestRecord && latestRecord.content) {
|
|
|
try {
|
|
|
const examData = extractExamDataFromContent(latestRecord.content);
|
|
|
@@ -1026,24 +986,20 @@ const handleHistoryItem = async (historyItem) => {
|
|
|
showExamDetail.value = true;
|
|
|
} catch (error) {
|
|
|
console.error('解析试卷数据失败:', error);
|
|
|
- // 如果解析失败,显示默认详情页
|
|
|
showExamDetail.value = true;
|
|
|
currentTime.value = historyItem.time;
|
|
|
}
|
|
|
} else {
|
|
|
- // 如果没有内容,显示默认详情页
|
|
|
showExamDetail.value = true;
|
|
|
currentTime.value = historyItem.time;
|
|
|
}
|
|
|
} else {
|
|
|
console.error('获取历史记录详情失败:', response);
|
|
|
- // 显示默认详情页
|
|
|
showExamDetail.value = true;
|
|
|
currentTime.value = historyItem.time;
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('获取历史记录详情失败:', error);
|
|
|
- // 显示默认详情页
|
|
|
showExamDetail.value = true;
|
|
|
currentTime.value = historyItem.time;
|
|
|
} finally {
|
|
|
@@ -1183,7 +1139,7 @@ const generateExam = async () => {
|
|
|
await generateAIExam();
|
|
|
} else {
|
|
|
// PPT生成方式
|
|
|
- if (!selectedFile.value) {
|
|
|
+ if (uploadedFiles.value.length === 0) {
|
|
|
ElMessage.warning("请先上传PPT文件");
|
|
|
return;
|
|
|
}
|
|
|
@@ -1229,17 +1185,14 @@ const generatePPTExam = async () => {
|
|
|
showExamDetail.value = true;
|
|
|
ElMessage.success("PPT试卷生成完成!");
|
|
|
|
|
|
- // AI回复完成后,获取最新的历史记录
|
|
|
await getHistoryRecordList();
|
|
|
|
|
|
- // 如果是新对话,将最新的历史记录设为激活状态
|
|
|
if (ai_conversation_id.value > 0) {
|
|
|
historyData.value.forEach((item) => {
|
|
|
item.isActive = item.id === ai_conversation_id.value;
|
|
|
});
|
|
|
console.log('设置最新历史记录为激活状态,conversationId:', ai_conversation_id.value);
|
|
|
} else {
|
|
|
- // 如果没有对话ID,选中第一条记录
|
|
|
selectLatestHistoryRecord();
|
|
|
}
|
|
|
} else {
|
|
|
@@ -1296,17 +1249,14 @@ const generateAIExam = async () => {
|
|
|
showExamDetail.value = true;
|
|
|
ElMessage.success("AI试卷生成完成!");
|
|
|
|
|
|
- // AI回复完成后,获取最新的历史记录
|
|
|
await getHistoryRecordList();
|
|
|
|
|
|
- // 如果是新对话,将最新的历史记录设为激活状态
|
|
|
if (ai_conversation_id.value > 0) {
|
|
|
historyData.value.forEach((item) => {
|
|
|
item.isActive = item.id === ai_conversation_id.value;
|
|
|
});
|
|
|
console.log('设置最新历史记录为激活状态,conversationId:', ai_conversation_id.value);
|
|
|
} else {
|
|
|
- // 如果没有对话ID,选中第一条记录
|
|
|
selectLatestHistoryRecord();
|
|
|
}
|
|
|
} else {
|
|
|
@@ -1334,6 +1284,9 @@ const fetchExamPrompt = async (mode = 'ai') => {
|
|
|
scorePerQuestion: Number(type.scorePerQuestion) || 0,
|
|
|
}));
|
|
|
|
|
|
+ const pptContents = uploadedFiles.value.map(file => file.content).join('\n\n');
|
|
|
+ const finalContentBasis = pptContents || questionBasis.value || '';
|
|
|
+
|
|
|
const payload = {
|
|
|
mode,
|
|
|
client: 'pc',
|
|
|
@@ -1341,7 +1294,7 @@ const fetchExamPrompt = async (mode = 'ai') => {
|
|
|
examTitle: examName.value,
|
|
|
totalScore: totalScore.value,
|
|
|
questionTypes: normalizedQuestionTypes,
|
|
|
- pptContent: selectedFile.value?.content || questionBasis.value || ''
|
|
|
+ pptContent: finalContentBasis
|
|
|
};
|
|
|
|
|
|
try {
|
|
|
@@ -2893,16 +2846,11 @@ const saveExam = async () => {
|
|
|
|
|
|
console.log('准备保存的试卷数据:', examData);
|
|
|
|
|
|
- // 调用后端保存接口
|
|
|
const response = await apis.saveExam(examData);
|
|
|
|
|
|
if (response.statusCode === 200) {
|
|
|
ElMessage.success("试卷保存成功!");
|
|
|
-
|
|
|
- // 更新历史记录
|
|
|
updateHistoryData(examData);
|
|
|
-
|
|
|
- // 可以在这里刷新历史记录列表
|
|
|
console.log('试卷已保存到历史记录');
|
|
|
} else {
|
|
|
throw new Error('保存失败');
|
|
|
@@ -2987,17 +2935,15 @@ const prepareExamDataForSave = () => {
|
|
|
// 更新历史记录数据
|
|
|
const updateHistoryData = (examData) => {
|
|
|
const newHistoryItem = {
|
|
|
- id: Date.now(), // 使用时间戳作为临时ID
|
|
|
+ id: Date.now(),
|
|
|
title: examData.exam_name,
|
|
|
time: examData.generation_time,
|
|
|
isActive: false,
|
|
|
- examData: examData // 保存完整的试卷数据
|
|
|
+ examData: examData
|
|
|
};
|
|
|
|
|
|
- // 添加到历史记录开头
|
|
|
historyData.value.unshift(newHistoryItem);
|
|
|
|
|
|
- // 限制历史记录数量(比如最多保存20条)
|
|
|
if (historyData.value.length > 20) {
|
|
|
historyData.value = historyData.value.slice(0, 20);
|
|
|
}
|
|
|
@@ -3449,65 +3395,68 @@ PPT文件处理失败,请手动描述PPT的主要内容、关键知识点、
|
|
|
|
|
|
// 处理文件选择
|
|
|
const handleFileSelect = async (event) => {
|
|
|
- const file = event.target.files[0]
|
|
|
- if (!file) return
|
|
|
+ const files = Array.from(event.target.files)
|
|
|
+ if (!files || files.length === 0) return
|
|
|
|
|
|
- try {
|
|
|
- // 验证文件
|
|
|
- const fileExtension = validateFile(file)
|
|
|
-
|
|
|
- isUploadingFile.value = true
|
|
|
- console.log('开始读取文件内容:', file.name)
|
|
|
-
|
|
|
- // 处理PPT文档
|
|
|
- const extractedContent = await readPPTFile(file)
|
|
|
-
|
|
|
- // 创建文件信息对象
|
|
|
- selectedFile.value = {
|
|
|
- file,
|
|
|
- name: file.name,
|
|
|
- size: file.size,
|
|
|
- type: fileExtension,
|
|
|
- icon: getFileIcon(fileExtension),
|
|
|
- content: extractedContent // 存储提取的内容
|
|
|
+ isUploadingFile.value = true
|
|
|
+ let successCount = 0;
|
|
|
+
|
|
|
+ for (const file of files) {
|
|
|
+ try {
|
|
|
+ // 验证文件
|
|
|
+ const fileExtension = validateFile(file)
|
|
|
+ console.log('开始读取文件内容:', file.name)
|
|
|
+
|
|
|
+ // 处理PPT文档
|
|
|
+ const extractedContent = await readPPTFile(file)
|
|
|
+
|
|
|
+ // 创建文件信息对象
|
|
|
+ uploadedFiles.value.push({
|
|
|
+ file,
|
|
|
+ name: file.name,
|
|
|
+ size: file.size,
|
|
|
+ type: fileExtension,
|
|
|
+ icon: getFileIcon(fileExtension),
|
|
|
+ content: extractedContent // 存储提取的内容
|
|
|
+ })
|
|
|
+ successCount++;
|
|
|
+
|
|
|
+ // 如果是第一个上传的文件,且当前试卷名称还是默认状态或为空,使用该文件名作为试卷名称
|
|
|
+ if (uploadedFiles.value.length === 1 && (!examName.value || examName.value.includes('工程施工技术考核'))) {
|
|
|
+ const fileNameWithoutExt = file.name.replace(/\.(ppt|pptx)$/i, '')
|
|
|
+ examName.value = `${fileNameWithoutExt}考试试卷`
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`文件 ${file.name} 读取失败:`, error)
|
|
|
+ ElMessage.error(`${file.name}读取失败: ${error.message || '请重试'}`)
|
|
|
}
|
|
|
-
|
|
|
- // 使用文件名作为试卷名称(去掉扩展名)
|
|
|
- const fileNameWithoutExt = file.name.replace(/\.(ppt|pptx)$/i, '')
|
|
|
- examName.value = `${fileNameWithoutExt}考试试卷`
|
|
|
-
|
|
|
- // 显示提取的内容长度
|
|
|
- const contentLength = extractedContent.length
|
|
|
- console.log('文件内容提取完成,字符数:', contentLength)
|
|
|
- ElMessage.success(`PPT文件读取成功,提取了${contentLength}个字符的内容`)
|
|
|
-
|
|
|
- } catch (error) {
|
|
|
- console.error('文件读取失败:', error)
|
|
|
- ElMessage.error(error.message || '文件读取失败,请重试')
|
|
|
- } finally {
|
|
|
- isUploadingFile.value = false
|
|
|
- event.target.value = ''
|
|
|
}
|
|
|
+
|
|
|
+ if (successCount > 0) {
|
|
|
+ ElMessage.success(`成功读取了 ${successCount} 个文件`)
|
|
|
+ }
|
|
|
+
|
|
|
+ isUploadingFile.value = false
|
|
|
+ event.target.value = ''
|
|
|
}
|
|
|
|
|
|
// 删除选中的文件
|
|
|
-const removeSelectedFile = () => {
|
|
|
- if (selectedFile.value) {
|
|
|
- selectedFile.value = null
|
|
|
- // 清空PPT内容描述
|
|
|
- pptContentDescription.value = ''
|
|
|
- // 重置试卷名称为默认值
|
|
|
- const projectTypeName = projectTypes[selectedProjectType.value].name
|
|
|
- examName.value = `${projectTypeName}工程施工技术考核`
|
|
|
+const removeSelectedFile = (index) => {
|
|
|
+ if (index >= 0 && index < uploadedFiles.value.length) {
|
|
|
+ uploadedFiles.value.splice(index, 1)
|
|
|
+
|
|
|
+ // 如果全部删除了,重置相关状态
|
|
|
+ if (uploadedFiles.value.length === 0) {
|
|
|
+ pptContentDescription.value = ''
|
|
|
+ const projectTypeName = projectTypes[selectedProjectType.value]?.name || '桥梁'
|
|
|
+ examName.value = `${projectTypeName}工程施工技术考核`
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 触发文件上传
|
|
|
const triggerFileUpload = () => {
|
|
|
- if (selectedFile.value) {
|
|
|
- ElMessage.warning('只能上传一个文件,请先删除当前文件')
|
|
|
- return
|
|
|
- }
|
|
|
fileInput.value?.click()
|
|
|
}
|
|
|
|
|
|
@@ -3538,6 +3487,15 @@ onMounted(async () => {
|
|
|
// 获取历史记录列表
|
|
|
await getHistoryRecordList()
|
|
|
|
|
|
+ // 检查URL参数是否有historyId需要加载
|
|
|
+ const historyId = route.query.historyId
|
|
|
+ if (historyId) {
|
|
|
+ const targetItem = historyData.value.find(item => String(item.id) === String(historyId))
|
|
|
+ if (targetItem) {
|
|
|
+ await handleHistoryItem(targetItem)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 添加全局点击事件监听器
|
|
|
document.addEventListener('click', handleClickOutside);
|
|
|
|
|
|
@@ -3731,11 +3689,11 @@ onUnmounted(() => {
|
|
|
/* 工作头部 */
|
|
|
.work-header {
|
|
|
background: transparent;
|
|
|
- padding: 30px 0px 0px 18px;
|
|
|
+ padding: 40px 0px 0px 18px;
|
|
|
|
|
|
h2 {
|
|
|
margin: 0;
|
|
|
- font-size: 20px;
|
|
|
+ font-size: 25px;
|
|
|
font-weight: 600;
|
|
|
color: #2c3e50;
|
|
|
}
|
|
|
@@ -3910,19 +3868,17 @@ onUnmounted(() => {
|
|
|
}
|
|
|
|
|
|
.file-status-badge {
|
|
|
- position: absolute;
|
|
|
- bottom: -40px;
|
|
|
- left: 0;
|
|
|
background: #ebf3ff;
|
|
|
color: var(--primary-color);
|
|
|
- padding: 8px 16px;
|
|
|
+ padding: 5px 12px;
|
|
|
border-radius: 8px;
|
|
|
- font-size: 13px;
|
|
|
+ font-size: 10px;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- gap: 12px;
|
|
|
+ gap: 8px;
|
|
|
border: 1px solid rgba(13, 110, 253, 0.1);
|
|
|
- max-width: 300px;
|
|
|
+ max-width: 100%;
|
|
|
+ margin-top: 12px;
|
|
|
}
|
|
|
|
|
|
.file-name {
|
|
|
@@ -5807,8 +5763,8 @@ onUnmounted(() => {
|
|
|
|
|
|
.return-ai-btn {
|
|
|
position: absolute;
|
|
|
- top: -15px;
|
|
|
- right: 0;
|
|
|
+ top: 10px;
|
|
|
+ right: 20px;
|
|
|
z-index: 100;
|
|
|
background: white;
|
|
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
|
@@ -5823,15 +5779,22 @@ onUnmounted(() => {
|
|
|
align-items: center;
|
|
|
gap: 5px;
|
|
|
transition: all 0.3s ease;
|
|
|
+ height: 36px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.return-ai-btn:disabled {
|
|
|
+ opacity: 0.5;
|
|
|
+ cursor: not-allowed;
|
|
|
}
|
|
|
|
|
|
-.return-ai-btn:hover {
|
|
|
+.return-ai-btn:hover:not(:disabled) {
|
|
|
box-shadow: 0 8px 24px rgba(13, 110, 253, 0.12);
|
|
|
color: #0d6efd;
|
|
|
border-color: rgba(13, 110, 253, 0.2);
|
|
|
}
|
|
|
|
|
|
-.return-ai-btn::before {
|
|
|
+.return-ai-btn.has-before::before {
|
|
|
content: '←';
|
|
|
font-size: 16px;
|
|
|
font-weight: bold;
|