|
|
@@ -1,240 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="attachment-upload">
|
|
|
- <!-- 上传按钮 -->
|
|
|
- <el-upload
|
|
|
- action="#"
|
|
|
- :file-list="uploadFileList"
|
|
|
- :before-upload="beforeUpload"
|
|
|
- :http-request="handleUpload"
|
|
|
- :show-file-list="false"
|
|
|
- :multiple="true"
|
|
|
- :disabled="!canUpload"
|
|
|
- >
|
|
|
- <el-button type="primary" :disabled="!canUpload">
|
|
|
- <el-icon><UploadFilled /></el-icon>
|
|
|
- 添加附件
|
|
|
- </el-button>
|
|
|
- </el-upload>
|
|
|
-
|
|
|
- <!-- 已上传附件列表 -->
|
|
|
- <div v-if="localFileList.length > 0" class="attachment-list">
|
|
|
- <div v-for="file in localFileList" :key="file.id" class="attachment-item">
|
|
|
- <div class="attachment-row-top">
|
|
|
- <el-icon :size="18" class="file-icon"><Document /></el-icon>
|
|
|
- <span class="file-name">{{ file.fileName }}</span>
|
|
|
- </div>
|
|
|
- <div class="attachment-row-bottom">
|
|
|
- <span class="upload-time" v-if="file.createTime">{{ formatDate(file.createTime) }}</span>
|
|
|
- <div class="attachment-actions">
|
|
|
- <el-button type="primary" link size="small" @click="handlePreview(file)">
|
|
|
- <el-icon><View /></el-icon>
|
|
|
- 预览
|
|
|
- </el-button>
|
|
|
- <el-button type="primary" link size="small" @click="handleDownload(file)">
|
|
|
- <el-icon><Download /></el-icon>
|
|
|
- 下载
|
|
|
- </el-button>
|
|
|
- <el-button type="danger" link size="small" @click="handleDelete(file)">
|
|
|
- <el-icon><Delete /></el-icon>
|
|
|
- 删除
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script setup lang="ts">
|
|
|
-import { ref, onMounted } from 'vue'
|
|
|
-import { UploadFilled, Document, View, Download, Delete } from '@element-plus/icons-vue'
|
|
|
-import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
-import { TaskOrderFileApi } from '@/api/pressure2/taskOrderFile'
|
|
|
-import { buildFileUrl } from '@/utils'
|
|
|
-import { formatDate } from '@/utils/formatTime'
|
|
|
-import request from '@/config/axios'
|
|
|
-
|
|
|
-const props = defineProps({
|
|
|
- /** 任务单ID */
|
|
|
- orderId: {
|
|
|
- type: String,
|
|
|
- default: ''
|
|
|
- },
|
|
|
- /** 检验设备单ID */
|
|
|
- orderItemId: {
|
|
|
- type: String,
|
|
|
- default: ''
|
|
|
- },
|
|
|
- /** 设备类型 200锅炉 300管道 */
|
|
|
- equipMainType: {
|
|
|
- type: Number,
|
|
|
- default: 0
|
|
|
- },
|
|
|
- /** 是否可上传 */
|
|
|
- canUpload: {
|
|
|
- type: Boolean,
|
|
|
- default: true
|
|
|
- }
|
|
|
-})
|
|
|
-
|
|
|
-// 本地文件列表
|
|
|
-const localFileList = ref<Recordable[]>([])
|
|
|
-// 上传组件显示用的空列表
|
|
|
-const uploadFileList = ref<Recordable[]>([])
|
|
|
-
|
|
|
-// 页面加载时自动获取附件列表
|
|
|
-onMounted(() => {
|
|
|
- fetchFileList()
|
|
|
-})
|
|
|
-
|
|
|
-const beforeUpload = (file: File) => {
|
|
|
- const maxSize = 50 * 1024 * 1024
|
|
|
- if (file.size > maxSize) {
|
|
|
- ElMessage.error('文件大小不能超过50MB')
|
|
|
- return false
|
|
|
- }
|
|
|
- return true
|
|
|
-}
|
|
|
-
|
|
|
-// 处理文件上传
|
|
|
-const handleUpload = async (options: Recordable) => {
|
|
|
- const { file } = options
|
|
|
- const formData = new FormData()
|
|
|
- formData.append('file', file)
|
|
|
- formData.append('orderId', props.orderId || '')
|
|
|
- formData.append('orderItemId', props.orderItemId || '')
|
|
|
- formData.append('equipMainType', String(props.equipMainType))
|
|
|
-
|
|
|
- try {
|
|
|
- const res = await TaskOrderFileApi.uploadAndCreate(formData)
|
|
|
- if (res) {
|
|
|
- ElMessage.success('文件上传成功')
|
|
|
- fetchFileList()
|
|
|
- }
|
|
|
- } catch (error: any) {
|
|
|
- ElMessage.error(error?.message || '文件上传失败')
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 预览附件
|
|
|
-const handlePreview = (file: Recordable) => {
|
|
|
- const url = buildFileUrl(file.fileUrl)
|
|
|
- window.open(url, '_blank')
|
|
|
-}
|
|
|
-
|
|
|
-// 下载附件 - 使用 blob 方式确保触发下载而不是浏览器打开
|
|
|
-const handleDownload = async (file: Recordable) => {
|
|
|
- try {
|
|
|
- const url = buildFileUrl(file.fileUrl)
|
|
|
- const blob = await request.download({ url })
|
|
|
- const blobUrl = URL.createObjectURL(blob as unknown as Blob)
|
|
|
- const link = document.createElement('a')
|
|
|
- link.href = blobUrl
|
|
|
- link.download = file.fileName || '下载文件'
|
|
|
- document.body.appendChild(link)
|
|
|
- link.click()
|
|
|
- document.body.removeChild(link)
|
|
|
- URL.revokeObjectURL(blobUrl)
|
|
|
- } catch (error: any) {
|
|
|
- ElMessage.error('下载失败')
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 删除附件
|
|
|
-const handleDelete = async (file: Recordable) => {
|
|
|
- try {
|
|
|
- await ElMessageBox.confirm('确认删除该附件?', '提示', {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning'
|
|
|
- })
|
|
|
- await TaskOrderFileApi.deleteFile(file.id)
|
|
|
- ElMessage.success('删除成功')
|
|
|
- fetchFileList()
|
|
|
- } catch (error: any) {
|
|
|
- if (error !== 'cancel') {
|
|
|
- ElMessage.error(error?.message || '删除失败')
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 刷新附件列表
|
|
|
-const fetchFileList = async () => {
|
|
|
- if (!props.orderItemId) return
|
|
|
- try {
|
|
|
- const res = await TaskOrderFileApi.getPage({
|
|
|
- orderItemId: props.orderItemId,
|
|
|
- pageNo: 1,
|
|
|
- pageSize: 100
|
|
|
- })
|
|
|
- if (res?.list) {
|
|
|
- localFileList.value = res.list
|
|
|
- }
|
|
|
- } catch (error: any) {
|
|
|
- console.error('获取附件列表失败:', error)
|
|
|
- }
|
|
|
-}
|
|
|
-</script>
|
|
|
-
|
|
|
-<style lang="scss" scoped>
|
|
|
-.attachment-upload {
|
|
|
- .attachment-list {
|
|
|
- margin-top: 12px;
|
|
|
-
|
|
|
- .attachment-item {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- padding: 10px 12px;
|
|
|
- margin-bottom: 8px;
|
|
|
- border: 1px solid var(--el-border-color-light);
|
|
|
- border-radius: 4px;
|
|
|
- background-color: var(--el-fill-color-lighter);
|
|
|
- transition: background-color 0.2s;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- background-color: var(--el-fill-color-light);
|
|
|
- }
|
|
|
-
|
|
|
- .attachment-row-top {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- gap: 8px;
|
|
|
- margin-bottom: 6px;
|
|
|
-
|
|
|
- .file-icon {
|
|
|
- flex-shrink: 0;
|
|
|
- margin-top: 2px;
|
|
|
- color: var(--el-color-primary);
|
|
|
- }
|
|
|
-
|
|
|
- .file-name {
|
|
|
- flex: 1;
|
|
|
- font-size: 13px;
|
|
|
- line-height: 1.5;
|
|
|
- word-break: break-all;
|
|
|
- color: var(--el-text-color-primary);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .attachment-row-bottom {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- padding-left: 26px;
|
|
|
-
|
|
|
- .upload-time {
|
|
|
- font-size: 12px;
|
|
|
- color: var(--el-text-color-secondary);
|
|
|
- }
|
|
|
-
|
|
|
- .attachment-actions {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 4px;
|
|
|
- margin-left: auto;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|