feat:导出文件命名+旧图标隐藏

This commit is contained in:
liailing1026
2026-03-13 16:43:26 +08:00
parent 01cdb71903
commit 05f6a07d26
8 changed files with 73 additions and 57 deletions

View File

@@ -3049,11 +3049,9 @@ def ensure_export_dir(task_id: str) -> str:
def generate_export_file_name(task_name: str, export_type: str) -> str: def generate_export_file_name(task_name: str, export_type: str) -> str:
"""生成导出文件名""" """生成导出文件名"""
from datetime import datetime
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# 清理文件名中的非法字符 # 清理文件名中的非法字符
safe_name = "".join(c for c in task_name if c.isalnum() or c in (' ', '-', '_')).strip() safe_name = "".join(c for c in task_name if c.isalnum() or c in (' ', '-', '_')).strip()
return f"{safe_name}_{export_type}_{timestamp}" return f"{safe_name}_{export_type}"
@socketio.on('export') @socketio.on('export')
@@ -3243,7 +3241,7 @@ def handle_get_export_list(data):
# ==================== REST API 接口 ==================== # ==================== REST API 接口 ====================
@app.route('/api/export/<int:record_id>/download', methods=['GET']) @app.route('/export/<int:record_id>/download', methods=['GET'])
def download_export(record_id: int): def download_export(record_id: int):
"""下载导出文件""" """下载导出文件"""
try: try:
@@ -3270,7 +3268,7 @@ def download_export(record_id: int):
return jsonify({'error': str(e)}), 500 return jsonify({'error': str(e)}), 500
@app.route('/api/export/<int:record_id>/preview', methods=['GET']) @app.route('/export/<int:record_id>/preview', methods=['GET'])
def preview_export(record_id: int): def preview_export(record_id: int):
"""预览导出文件""" """预览导出文件"""
try: try:
@@ -3332,7 +3330,7 @@ def preview_export(record_id: int):
return jsonify({'error': str(e)}), 500 return jsonify({'error': str(e)}), 500
@app.route('/api/export/<int:record_id>/share', methods=['GET']) @app.route('/export/<int:record_id>/share', methods=['GET'])
def share_export(record_id: int): def share_export(record_id: int):
"""生成分享链接""" """生成分享链接"""
try: try:
@@ -3355,7 +3353,7 @@ def share_export(record_id: int):
return jsonify({'error': str(e)}), 500 return jsonify({'error': str(e)}), 500
@app.route('/api/export/<int:record_id>/share/info', methods=['GET']) @app.route('/export/<int:record_id>/share/info', methods=['GET'])
def get_share_info(record_id: int): def get_share_info(record_id: int):
"""获取分享文件信息(无需登录验证)""" """获取分享文件信息(无需登录验证)"""
try: try:
@@ -3407,7 +3405,7 @@ def get_shared_plan_page(share_token: str):
return jsonify({'error': str(e)}), 500 return jsonify({'error': str(e)}), 500
@app.route('/api/share/<share_token>/check', methods=['GET']) @app.route('/share/<share_token>/check', methods=['GET'])
def check_share_code(share_token: str): def check_share_code(share_token: str):
"""检查分享链接是否需要提取码""" """检查分享链接是否需要提取码"""
try: try:
@@ -3431,7 +3429,7 @@ def check_share_code(share_token: str):
return jsonify({'error': str(e)}), 500 return jsonify({'error': str(e)}), 500
@app.route('/api/share/<share_token>', methods=['GET']) @app.route('/share/<share_token>', methods=['GET'])
def get_shared_plan_info(share_token: str): def get_shared_plan_info(share_token: str):
"""获取分享任务详情API 接口,无需登录验证)""" """获取分享任务详情API 接口,无需登录验证)"""
# 获取URL参数中的提取码 # 获取URL参数中的提取码
@@ -3473,7 +3471,7 @@ def get_shared_plan_info(share_token: str):
return jsonify({'error': str(e)}), 500 return jsonify({'error': str(e)}), 500
@app.route('/api/share/import', methods=['POST']) @app.route('/share/import', methods=['POST'])
def import_shared_plan(): def import_shared_plan():
"""导入分享的任务到自己的历史记录HTTP API无需 WebSocket""" """导入分享的任务到自己的历史记录HTTP API无需 WebSocket"""
try: try:
@@ -3537,7 +3535,7 @@ def import_shared_plan():
return jsonify({'error': str(e)}), 500 return jsonify({'error': str(e)}), 500
@app.route('/api/export/<int:record_id>', methods=['DELETE']) @app.route('/export/<int:record_id>', methods=['DELETE'])
def delete_export(record_id: int): def delete_export(record_id: int):
"""删除导出记录""" """删除导出记录"""
try: try:

View File

@@ -923,41 +923,8 @@ class Api {
downloadExport = async (recordId: number): Promise<void> => { downloadExport = async (recordId: number): Promise<void> => {
const configStore = useConfigStoreHook() const configStore = useConfigStoreHook()
const baseURL = configStore.config.apiBaseUrl || '' const baseURL = configStore.config.apiBaseUrl || ''
const url = `${baseURL}/api/export/${recordId}/download` // 直接使用 window.location.href 跳转下载,浏览器会自动处理文件名
window.location.href = `${baseURL}/export/${recordId}/download`
try {
const response = await fetch(url, {
method: 'GET',
})
if (!response.ok) {
throw new Error('下载失败')
}
// 获取文件名从 Content-Disposition 头
const contentDisposition = response.headers.get('Content-Disposition')
let fileName = 'download'
if (contentDisposition) {
const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
if (match) {
fileName = match[1].replace(/['"]/g, '')
}
}
// 创建 Blob 并下载
const blob = await response.blob()
const downloadUrl = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = downloadUrl
link.download = fileName
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(downloadUrl)
} catch (error) {
console.error('下载失败:', error)
throw error
}
} }
/** /**
@@ -971,7 +938,7 @@ class Api {
}> => { }> => {
const configStore = useConfigStoreHook() const configStore = useConfigStoreHook()
const baseURL = configStore.config.apiBaseUrl || '' const baseURL = configStore.config.apiBaseUrl || ''
const url = `${baseURL}/api/export/${recordId}/preview` const url = `${baseURL}/export/${recordId}/preview`
const response = await request<{ const response = await request<{
content?: string content?: string
@@ -996,7 +963,7 @@ class Api {
}> => { }> => {
const configStore = useConfigStoreHook() const configStore = useConfigStoreHook()
const baseURL = configStore.config.apiBaseUrl || '' const baseURL = configStore.config.apiBaseUrl || ''
const url = `${baseURL}/api/export/${recordId}/share` const url = `${baseURL}/export/${recordId}/share`
const response = await request<{ const response = await request<{
share_url: string share_url: string
@@ -1012,7 +979,7 @@ class Api {
deleteExport = async (recordId: number): Promise<boolean> => { deleteExport = async (recordId: number): Promise<boolean> => {
const configStore = useConfigStoreHook() const configStore = useConfigStoreHook()
const baseURL = configStore.config.apiBaseUrl || '' const baseURL = configStore.config.apiBaseUrl || ''
const url = `${baseURL}/api/export/${recordId}` const url = `${baseURL}/export/${recordId}`
try { try {
await request({ await request({

View File

@@ -244,7 +244,12 @@ async function handleSearch() {
currentGenerationId.value = response.generation_id || '' currentGenerationId.value = response.generation_id || ''
// 从 response.data 中获取 task_idREST API 格式) // 从 response.data 中获取 task_idREST API 格式)
currentTaskID.value = response.data?.task_id || response.task_id || '' currentTaskID.value = response.data?.task_id || response.task_id || ''
console.log('📋 直接格式: generation_id:', currentGenerationId.value, 'TaskID:', currentTaskID.value) console.log(
'📋 直接格式: generation_id:',
currentGenerationId.value,
'TaskID:',
currentTaskID.value
)
} else { } else {
outlineData = response outlineData = response
currentGenerationId.value = '' currentGenerationId.value = ''
@@ -602,7 +607,7 @@ defineExpose({
/> />
</el-button> </el-button>
</div> </div>
<AssignmentButton v-if="planReady" @click="openAgentAllocationDialog" /> <!-- <AssignmentButton v-if="planReady" @click="openAgentAllocationDialog" /> -->
<!-- 设置按钮 --> <!-- 设置按钮 -->
<el-button class="setting-button" circle title="设置" @click="openSettingsPanel"> <el-button class="setting-button" circle title="设置" @click="openSettingsPanel">
<el-icon size="18px"><Setting /></el-icon> <el-icon size="18px"><Setting /></el-icon>

View File

@@ -124,7 +124,9 @@ const agentsStore = useAgentsStore()
<!-- 数据空间 --> <!-- 数据空间 -->
<div class="text-[12px]"> <div class="text-[12px]">
<span class="text-[var(--color-text)] font-bold">数据空间</span> <span class="text-[var(--color-text)] font-bold">数据空间</span>
<div class="text-[var(--color-text-secondary)] mt-1">归属于{{ item.Classification }}数据空间</div> <div class="text-[var(--color-text-secondary)] mt-1">
归属于{{ item.Classification }}数据空间
</div>
</div> </div>
<!-- 分割线 --> <!-- 分割线 -->
<div class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"></div> <div class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"></div>
@@ -158,8 +160,6 @@ const agentsStore = useAgentsStore()
v-if="index1 !== taskProcess.filter(i => i.AgentName === item.Name).length - 1" v-if="index1 !== taskProcess.filter(i => i.AgentName === item.Name).length - 1"
class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]" class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"
></div> ></div>
<AssignmentButton />
</div> </div>
</template> </template>
</div> </div>

View File

@@ -80,8 +80,18 @@
:title="previewData?.file_name || '文件预览'" :title="previewData?.file_name || '文件预览'"
width="80%" width="80%"
:close-on-click-modal="true" :close-on-click-modal="true"
:show-close="false"
class="preview-dialog" class="preview-dialog"
> >
<!-- 自定义关闭按钮 -->
<template #header>
<div class="dialog-header">
<span class="dialog-title">{{ previewData?.file_name || '文件预览' }}</span>
<button class="dialog-close-btn" @click="previewVisible = false">
<SvgIcon icon-class="close" size="18px" />
</button>
</div>
</template>
<div class="preview-content"> <div class="preview-content">
<div v-if="previewLoading" class="preview-loading"> <div v-if="previewLoading" class="preview-loading">
<el-icon class="is-loading"><Loading /></el-icon> <el-icon class="is-loading"><Loading /></el-icon>
@@ -1079,8 +1089,44 @@ onMounted(() => {
// 预览弹窗样式 // 预览弹窗样式
.preview-dialog { .preview-dialog {
.el-dialog__header {
padding: 16px 20px 10px;
margin: 0;
}
.el-dialog__body { .el-dialog__body {
padding: 16px; padding: 16px;
} }
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.dialog-title {
font-size: 16px;
font-weight: 600;
color: var(--color-text-primary);
}
.dialog-close-btn {
background: none;
border: none;
cursor: pointer;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
color: var(--color-text-regular);
transition: transform 0.3s ease;
&:hover {
transform: rotate(180deg);
}
}
} }
</style> </style>

View File

@@ -201,7 +201,7 @@ function handleCancel() {
</div> </div>
</div> </div>
<!-- 按钮点击不会冒泡到卡片 --> <!-- 按钮点击不会冒泡到卡片 -->
<BranchButton :step="step" /> <!-- <BranchButton :step="step" /> -->
</div> </div>
</template> </template>

View File

@@ -366,7 +366,7 @@ defineExpose({
</div> </div>
</div> </div>
</div> </div>
<BranchButton v-if="planReady" @click="openPlanModification" /> <!-- <BranchButton v-if="planReady" @click="openPlanModification" /> -->
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -263,7 +263,7 @@ const downloadFile = async () => {
return return
} }
window.location.href = `${apiBaseUrl}/api/export/${parsed.recordId}/download` window.location.href = `${apiBaseUrl}/export/${parsed.recordId}/download`
} catch (e) { } catch (e) {
console.error('下载失败:', e) console.error('下载失败:', e)
ElMessage.error('下载失败') ElMessage.error('下载失败')