feat:导出面板动态编写一半
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import websocket from '@/utils/websocket'
|
||||
import type { Agent, IApiStepTask, IRawPlanResponse, IRawStepTask } from '@/stores'
|
||||
import { withRetry } from '@/utils/retry'
|
||||
import request from '@/utils/request'
|
||||
import { useConfigStoreHook } from '@/stores'
|
||||
|
||||
export interface ActionHistory {
|
||||
ID: string
|
||||
@@ -770,6 +772,209 @@ class Api {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 导出功能 ====================
|
||||
|
||||
/**
|
||||
* 导出任务为指定格式
|
||||
*/
|
||||
exportTask = async (params: {
|
||||
task_id: string
|
||||
export_type: string
|
||||
user_id?: string
|
||||
}): Promise<{
|
||||
record_id: number
|
||||
file_name: string
|
||||
file_url: string
|
||||
file_size: number
|
||||
export_type: string
|
||||
}> => {
|
||||
if (!websocket.connected) {
|
||||
throw new Error('WebSocket未连接')
|
||||
}
|
||||
|
||||
const rawResponse = await websocket.send('export', {
|
||||
task_id: params.task_id,
|
||||
export_type: params.export_type,
|
||||
user_id: params.user_id || 'anonymous',
|
||||
})
|
||||
|
||||
const response = this.extractResponse<{
|
||||
record_id: number
|
||||
file_name: string
|
||||
file_url: string
|
||||
file_size: number
|
||||
export_type: string
|
||||
}>(rawResponse)
|
||||
|
||||
if (response) {
|
||||
console.log('导出成功:', response)
|
||||
return response
|
||||
}
|
||||
throw new Error('导出失败')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取导出记录列表
|
||||
*/
|
||||
getExportList = async (params: {
|
||||
task_id: string
|
||||
}): Promise<{
|
||||
list: Array<{
|
||||
id: number
|
||||
task_id: string
|
||||
user_id: string
|
||||
export_type: string
|
||||
file_name: string
|
||||
file_path: string
|
||||
file_url: string
|
||||
file_size: number
|
||||
created_at: string
|
||||
}>
|
||||
total: number
|
||||
}> => {
|
||||
if (!websocket.connected) {
|
||||
throw new Error('WebSocket未连接')
|
||||
}
|
||||
|
||||
const rawResponse = await websocket.send('get_export_list', {
|
||||
task_id: params.task_id,
|
||||
})
|
||||
|
||||
const response = this.extractResponse<{
|
||||
list: Array<{
|
||||
id: number
|
||||
task_id: string
|
||||
user_id: string
|
||||
export_type: string
|
||||
file_name: string
|
||||
file_path: string
|
||||
file_url: string
|
||||
file_size: number
|
||||
created_at: string
|
||||
}>
|
||||
total: number
|
||||
}>(rawResponse)
|
||||
|
||||
if (response) {
|
||||
return response
|
||||
}
|
||||
return { list: [], total: 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载导出文件
|
||||
*/
|
||||
downloadExport = async (recordId: number): Promise<void> => {
|
||||
const configStore = useConfigStoreHook()
|
||||
const baseURL = configStore.config.apiBaseUrl || ''
|
||||
const url = `${baseURL}/api/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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预览导出文件
|
||||
*/
|
||||
previewExport = async (recordId: number): Promise<{
|
||||
content?: string
|
||||
file_url?: string
|
||||
file_name?: string
|
||||
type: string
|
||||
}> => {
|
||||
const configStore = useConfigStoreHook()
|
||||
const baseURL = configStore.config.apiBaseUrl || ''
|
||||
const url = `${baseURL}/api/export/${recordId}/preview`
|
||||
|
||||
const response = await request<{
|
||||
content?: string
|
||||
file_url?: string
|
||||
file_name?: string
|
||||
type: string
|
||||
}>({
|
||||
url,
|
||||
method: 'GET',
|
||||
})
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成分享链接
|
||||
*/
|
||||
shareExport = async (recordId: number): Promise<{
|
||||
share_url: string
|
||||
file_name: string
|
||||
expired_at: string | null
|
||||
}> => {
|
||||
const configStore = useConfigStoreHook()
|
||||
const baseURL = configStore.config.apiBaseUrl || ''
|
||||
const url = `${baseURL}/api/export/${recordId}/share`
|
||||
|
||||
const response = await request<{
|
||||
share_url: string
|
||||
file_name: string
|
||||
expired_at: string | null
|
||||
}>({
|
||||
url,
|
||||
method: 'GET',
|
||||
})
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除导出记录
|
||||
*/
|
||||
deleteExport = async (recordId: number): Promise<boolean> => {
|
||||
const configStore = useConfigStoreHook()
|
||||
const baseURL = configStore.config.apiBaseUrl || ''
|
||||
const url = `${baseURL}/api/export/${recordId}`
|
||||
|
||||
try {
|
||||
await request({
|
||||
url,
|
||||
method: 'DELETE',
|
||||
})
|
||||
console.log('删除导出记录成功:', recordId)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('删除导出记录失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new Api()
|
||||
|
||||
@@ -20,7 +20,7 @@ onMounted(async () => {
|
||||
agentsStore.setAgents(res)
|
||||
}
|
||||
await api.setAgents(
|
||||
agentsStore.agents.map(item => pick(item, ['Name', 'Profile', 'apiUrl', 'apiKey', 'apiModel']))
|
||||
agentsStore.agents.map(item => pick(item, ['Name', 'Profile', 'Icon', 'Classification', 'apiUrl', 'apiKey', 'apiModel']))
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
v-for="item in exportStyles"
|
||||
:key="item.type"
|
||||
class="export-style-item"
|
||||
:class="{ 'is-loading': loadingTypes.includes(item.type) }"
|
||||
@click="handleSelect(item)"
|
||||
>
|
||||
<div class="style-icon" :style="{ color: item.color }">
|
||||
@@ -18,13 +19,13 @@
|
||||
<!-- 导出结果列表 -->
|
||||
<div class="export-result-section">
|
||||
<div v-if="exportResults.length > 0" class="result-list">
|
||||
<div v-for="(result, index) in exportResults" :key="index" class="result-item">
|
||||
<div v-for="(result, index) in exportResults" :key="result.id || index" class="result-item">
|
||||
<div class="result-icon" :style="{ color: result.color }">
|
||||
<SvgIcon :icon-class="result.icon" size="30px" />
|
||||
</div>
|
||||
<div class="result-info">
|
||||
<div class="result-name">{{ result.name }}</div>
|
||||
<div class="result-time">{{ formatTime(result.exportTime || Date.now()) }}</div>
|
||||
<div class="result-time">{{ formatTime(result.exportTime || result.created_at) }}</div>
|
||||
</div>
|
||||
<div class="result-actions">
|
||||
<el-popover
|
||||
@@ -71,18 +72,53 @@
|
||||
content="删除后,该记录无法恢复 !"
|
||||
@confirm="confirmDelete"
|
||||
/>
|
||||
|
||||
<!-- 预览弹窗 -->
|
||||
<el-dialog
|
||||
v-model="previewVisible"
|
||||
:title="previewData?.file_name || '文件预览'"
|
||||
width="80%"
|
||||
:close-on-click-modal="true"
|
||||
class="preview-dialog"
|
||||
>
|
||||
<div class="preview-content">
|
||||
<div v-if="previewLoading" class="preview-loading">
|
||||
<el-icon class="is-loading"><Loading /></el-icon>
|
||||
<span>加载中...</span>
|
||||
</div>
|
||||
<div v-else-if="previewData?.type === 'markdown'" class="preview-markdown">
|
||||
<pre>{{ previewData?.content }}</pre>
|
||||
</div>
|
||||
<div v-else-if="previewData?.file_url" class="preview-iframe">
|
||||
<iframe :src="previewData?.file_url" frameborder="0"></iframe>
|
||||
<div class="preview-tip">该文件类型暂不支持直接预览,请下载查看</div>
|
||||
</div>
|
||||
<div v-else class="preview-empty">无法预览此文件</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="previewVisible = false">关闭</el-button>
|
||||
<el-button type="primary" @click="handlePreviewDownload">下载</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue'
|
||||
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog/index.vue'
|
||||
import { useAgentsStore } from '@/stores'
|
||||
import api from '@/api'
|
||||
|
||||
const agentsStore = useAgentsStore()
|
||||
|
||||
// Props 接收大任务ID(数据库主键)
|
||||
const props = defineProps<{
|
||||
TaskID?: string // 大任务ID,用于导出整个任务的执行结果
|
||||
}>()
|
||||
|
||||
// 事件定义
|
||||
const emit = defineEmits<{
|
||||
(e: 'close'): void
|
||||
@@ -96,13 +132,19 @@ interface ExportStyle {
|
||||
color: string
|
||||
}
|
||||
|
||||
// 导出结果类型
|
||||
// 导出结果类型(与后端返回的数据结构匹配)
|
||||
interface ExportResult {
|
||||
id?: number
|
||||
record_id?: number
|
||||
name: string
|
||||
icon: string
|
||||
type: string
|
||||
color: string
|
||||
exportTime?: number // 时间戳
|
||||
exportTime?: number
|
||||
created_at?: string
|
||||
file_url?: string
|
||||
file_name?: string
|
||||
export_type?: string
|
||||
}
|
||||
|
||||
// 导出样式数据
|
||||
@@ -118,14 +160,40 @@ const exportStyles = ref<ExportStyle[]>([
|
||||
// 导出结果列表
|
||||
const exportResults = ref<ExportResult[]>([])
|
||||
|
||||
// 加载中的导出类型
|
||||
const loadingTypes = ref<string[]>([])
|
||||
|
||||
// 删除对话框相关
|
||||
const dialogVisible = ref(false)
|
||||
const resultToDelete = ref<ExportResult | null>(null)
|
||||
|
||||
// 预览相关
|
||||
const previewVisible = ref(false)
|
||||
const previewLoading = ref(false)
|
||||
const previewData = ref<{
|
||||
content?: string
|
||||
file_url?: string
|
||||
file_name?: string
|
||||
type: string
|
||||
}>({ type: '' })
|
||||
|
||||
// 格式化时间显示
|
||||
const formatTime = (timestamp: number): string => {
|
||||
const formatTime = (timestamp: any): string => {
|
||||
if (!timestamp) return '未知时间'
|
||||
|
||||
let time: number
|
||||
|
||||
// 如果是 ISO 字符串,转换为时间戳
|
||||
if (typeof timestamp === 'string') {
|
||||
time = new Date(timestamp).getTime()
|
||||
} else if (typeof timestamp === 'number') {
|
||||
time = timestamp
|
||||
} else {
|
||||
return '未知时间'
|
||||
}
|
||||
|
||||
const now = Date.now()
|
||||
const diff = now - timestamp
|
||||
const diff = now - time
|
||||
const minutes = Math.floor(diff / 60000)
|
||||
const hours = Math.floor(diff / 3600000)
|
||||
const days = Math.floor(diff / 86400000)
|
||||
@@ -135,25 +203,133 @@ const formatTime = (timestamp: number): string => {
|
||||
if (hours < 24) return `${hours}小时前`
|
||||
if (days < 7) return `${days}天前`
|
||||
|
||||
const date = new Date(timestamp)
|
||||
const date = new Date(time)
|
||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(
|
||||
date.getDate()
|
||||
).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
// 获取导出记录列表
|
||||
const fetchExportList = async () => {
|
||||
// 使用大任务ID(从 TaskTemplate 传入的 props.TaskID)
|
||||
const taskId = props.TaskID
|
||||
if (!taskId) {
|
||||
console.warn('没有任务ID,无法获取导出列表')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await api.getExportList({ task_id: taskId })
|
||||
|
||||
// 转换为前端显示格式
|
||||
exportResults.value = result.list.map((item) => {
|
||||
const style = exportStyles.value.find((s) => s.type === item.export_type)
|
||||
return {
|
||||
id: item.id,
|
||||
record_id: item.id,
|
||||
name: item.file_name,
|
||||
icon: style?.icon || 'DOCX',
|
||||
type: item.export_type,
|
||||
color: style?.color || '#999',
|
||||
exportTime: new Date(item.created_at).getTime(),
|
||||
created_at: item.created_at,
|
||||
file_url: item.file_url,
|
||||
file_name: item.file_name,
|
||||
export_type: item.export_type,
|
||||
}
|
||||
})
|
||||
|
||||
console.log('获取导出列表成功:', exportResults.value)
|
||||
} catch (error) {
|
||||
console.error('获取导出列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 预览文件
|
||||
const previewResult = (_result: ExportResult) => {
|
||||
ElMessage.success('预览功能开发中')
|
||||
const previewResult = async (result: ExportResult) => {
|
||||
const recordId = result.id || result.record_id
|
||||
if (!recordId) {
|
||||
ElMessage.error('无法获取文件ID')
|
||||
return
|
||||
}
|
||||
|
||||
// 先初始化数据,再显示对话框,避免渲染时属性不存在
|
||||
previewData.value = {
|
||||
content: '',
|
||||
file_url: '',
|
||||
file_name: result.file_name || '文件预览',
|
||||
type: result.type || ''
|
||||
}
|
||||
previewVisible.value = true
|
||||
previewLoading.value = true
|
||||
|
||||
try {
|
||||
const data = await api.previewExport(recordId)
|
||||
previewData.value = {
|
||||
...previewData.value,
|
||||
...data,
|
||||
}
|
||||
previewLoading.value = false
|
||||
} catch (error) {
|
||||
console.error('预览失败:', error)
|
||||
ElMessage.error('预览失败')
|
||||
previewLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 预览弹窗中的下载按钮
|
||||
const handlePreviewDownload = () => {
|
||||
const fileName = previewData.value?.file_name
|
||||
const recordId = fileName ? exportResults.value.find(
|
||||
(r) => r.file_name === fileName
|
||||
)?.id : null
|
||||
|
||||
if (recordId) {
|
||||
downloadById(recordId)
|
||||
}
|
||||
previewVisible.value = false
|
||||
}
|
||||
|
||||
// 下载文件(根据ID)
|
||||
const downloadById = async (recordId: number) => {
|
||||
try {
|
||||
await api.downloadExport(recordId)
|
||||
ElMessage.success('开始下载')
|
||||
} catch (error) {
|
||||
console.error('下载失败:', error)
|
||||
ElMessage.error('下载失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 下载文件
|
||||
const downloadResult = (_result: ExportResult) => {
|
||||
ElMessage.success('下载功能开发中')
|
||||
const downloadResult = (result: ExportResult) => {
|
||||
const recordId = result.id || result.record_id
|
||||
if (!recordId) {
|
||||
ElMessage.error('无法获取文件ID')
|
||||
return
|
||||
}
|
||||
|
||||
downloadById(recordId)
|
||||
}
|
||||
|
||||
// 分享
|
||||
const shareResult = (_result: ExportResult) => {
|
||||
ElMessage.success('分享功能开发中')
|
||||
const shareResult = async (result: ExportResult) => {
|
||||
const recordId = result.id || result.record_id
|
||||
if (!recordId) {
|
||||
ElMessage.error('无法获取文件ID')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await api.shareExport(recordId)
|
||||
// 将分享链接复制到剪贴板
|
||||
const fullUrl = window.location.origin + data.share_url
|
||||
await navigator.clipboard.writeText(fullUrl)
|
||||
ElMessage.success('分享链接已复制到剪贴板')
|
||||
} catch (error) {
|
||||
console.error('分享失败:', error)
|
||||
ElMessage.error('分享失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 删除
|
||||
@@ -163,44 +339,104 @@ const deleteResult = (result: ExportResult) => {
|
||||
}
|
||||
|
||||
// 确认删除
|
||||
const confirmDelete = () => {
|
||||
const confirmDelete = async () => {
|
||||
if (!resultToDelete.value) return
|
||||
|
||||
const index = exportResults.value.indexOf(resultToDelete.value)
|
||||
if (index > -1) {
|
||||
exportResults.value.splice(index, 1)
|
||||
ElMessage.success('删除成功')
|
||||
const recordId = resultToDelete.value.id || resultToDelete.value.record_id
|
||||
if (!recordId) {
|
||||
ElMessage.error('无法获取文件ID')
|
||||
dialogVisible.value = false
|
||||
resultToDelete.value = null
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const success = await api.deleteExport(recordId)
|
||||
if (success) {
|
||||
// 从列表中移除
|
||||
const index = exportResults.value.findIndex(
|
||||
(r) => (r.id || r.record_id) === recordId
|
||||
)
|
||||
if (index > -1) {
|
||||
exportResults.value.splice(index, 1)
|
||||
}
|
||||
ElMessage.success('删除成功')
|
||||
} else {
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error('删除失败')
|
||||
}
|
||||
|
||||
dialogVisible.value = false
|
||||
resultToDelete.value = null
|
||||
}
|
||||
|
||||
// 选择导出样式
|
||||
const handleSelect = (item: ExportStyle) => {
|
||||
const currentTask = agentsStore.currentTask
|
||||
if (!currentTask) {
|
||||
const handleSelect = async (item: ExportStyle) => {
|
||||
// 使用大任务ID(从 TaskTemplate 传入的 props.TaskID)
|
||||
const taskId = props.TaskID
|
||||
console.log('导出任务 - TaskID:', taskId)
|
||||
|
||||
if (!taskId) {
|
||||
ElMessage.warning('请先选择任务')
|
||||
return
|
||||
}
|
||||
|
||||
// 生成导出名称:任务名称 + 样式名称
|
||||
const taskName = currentTask.StepName || '未知任务'
|
||||
const exportName = `${taskName}${item.name}`
|
||||
|
||||
// 添加到导出结果列表(添加到最前面)
|
||||
const newItem = {
|
||||
name: exportName,
|
||||
icon: item.icon,
|
||||
type: item.type,
|
||||
color: item.color,
|
||||
exportTime: Date.now()
|
||||
// 防止重复点击
|
||||
if (loadingTypes.value.includes(item.type)) {
|
||||
return
|
||||
}
|
||||
|
||||
exportResults.value.unshift(newItem)
|
||||
// 添加加载状态
|
||||
loadingTypes.value.push(item.type)
|
||||
|
||||
console.log('导出任务:', { task: currentTask, style: item })
|
||||
ElMessage.success(`已开始导出: ${item.name}`)
|
||||
try {
|
||||
// 调用后端接口导出(导出整个大任务的执行结果)
|
||||
console.log('开始导出 - task_id:', taskId, 'type:', item.type)
|
||||
const result = await api.exportTask({
|
||||
task_id: taskId,
|
||||
export_type: item.type,
|
||||
user_id: 'current_user', // TODO: 获取实际用户ID
|
||||
})
|
||||
console.log('导出结果:', result)
|
||||
|
||||
// 添加到导出结果列表(添加到最前面)
|
||||
const newItem: ExportResult = {
|
||||
id: result.record_id,
|
||||
record_id: result.record_id,
|
||||
name: result.file_name,
|
||||
icon: item.icon,
|
||||
type: item.type,
|
||||
color: item.color,
|
||||
exportTime: Date.now(),
|
||||
created_at: new Date().toISOString(),
|
||||
file_url: result.file_url,
|
||||
file_name: result.file_name,
|
||||
export_type: item.type,
|
||||
}
|
||||
|
||||
exportResults.value.unshift(newItem)
|
||||
|
||||
console.log('导出成功:', result)
|
||||
ElMessage.success(`导出成功: ${item.name}`)
|
||||
} catch (error) {
|
||||
console.error('导出失败:', error)
|
||||
ElMessage.error(`导出失败: ${item.name}`)
|
||||
} finally {
|
||||
// 移除加载状态
|
||||
const idx = loadingTypes.value.indexOf(item.type)
|
||||
if (idx > -1) {
|
||||
loadingTypes.value.splice(idx, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 组件挂载时获取导出列表
|
||||
onMounted(() => {
|
||||
fetchExportList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -239,6 +475,11 @@ const handleSelect = (item: ExportStyle) => {
|
||||
background: var(--color-bg-content-hover);
|
||||
}
|
||||
|
||||
&.is-loading {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.style-icon {
|
||||
flex-shrink: 0;
|
||||
color: var(--color-text-plan-item);
|
||||
@@ -362,6 +603,69 @@ const handleSelect = (item: ExportStyle) => {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
// 预览内容样式
|
||||
.preview-content {
|
||||
min-height: 300px;
|
||||
max-height: 60vh;
|
||||
overflow: auto;
|
||||
|
||||
.preview-loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 300px;
|
||||
gap: 12px;
|
||||
color: var(--color-text-placeholder);
|
||||
|
||||
.el-icon {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-markdown {
|
||||
padding: 16px;
|
||||
background: var(--color-bg-detail);
|
||||
border-radius: 8px;
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-iframe {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: var(--color-bg-detail);
|
||||
}
|
||||
|
||||
.preview-tip {
|
||||
margin-top: 12px;
|
||||
color: var(--color-text-placeholder);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 200px;
|
||||
color: var(--color-text-placeholder);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -415,4 +719,11 @@ const handleSelect = (item: ExportStyle) => {
|
||||
border-radius: 0 0 8px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
// 预览弹窗样式
|
||||
.preview-dialog {
|
||||
.el-dialog__body {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -174,7 +174,7 @@ defineExpose({
|
||||
</div>
|
||||
<div class="h-[1px] w-full bg-[var(--color-border-separate)] my-[8px]"></div>
|
||||
<div class="export-drawer-body">
|
||||
<ExportList @close="exportDialogVisible = false" />
|
||||
<ExportList :TaskID="TaskID" @close="exportDialogVisible = false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user