| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="dialogVisible" title="é件管ç" width="60%" :before-close="handleClose"> |
| | | <div class="attachment-manager"> |
| | | <!-- ä¸ä¼ åºå --> |
| | | <div class="upload-section"> |
| | | <el-upload |
| | | ref="uploadRef" |
| | | :action="uploadUrl" |
| | | :headers="uploadHeaders" |
| | | :before-upload="handleBeforeUpload" |
| | | :on-success="handleUploadSuccess" |
| | | :on-error="handleUploadError" |
| | | :on-remove="handleRemove" |
| | | :file-list="fileList" |
| | | multiple |
| | | :show-file-list="false" |
| | | :data="{documentId: currentDocumentId}" |
| | | accept=".doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt,.xml,.jpg,.jpeg,.png,.gif,.bmp,.rar,.zip,.7z" |
| | | > |
| | | <el-button type="primary" :icon="Plus">ä¸ä¼ éä»¶</el-button> |
| | | <template #tip> |
| | | <div class="el-upload__tip"> |
| | | æ¯ææ ¼å¼ï¼docï¼docxï¼xlsï¼xlsxï¼pptï¼pptxï¼pdfï¼txtï¼xmlï¼jpgï¼jpegï¼pngï¼gifï¼bmpï¼rarï¼zipï¼7z |
| | | <br>å个æä»¶å¤§å°ä¸è¶
è¿50MB |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | </div> |
| | | |
| | | <!-- éä»¶å表 --> |
| | | <div class="attachment-list"> |
| | | <el-table :data="fileList" border max-height="400px" v-loading="loading"> |
| | | <el-table-column label="åºå·" type="index" width="60" align="center" /> |
| | | <el-table-column label="éä»¶åç§°" prop="name" min-width="200" show-overflow-tooltip /> |
| | | <el-table-column label="æä»¶å¤§å°" prop="size" width="100" align="center"> |
| | | <template #default="scope"> |
| | | {{ formatFileSize(scope.row.size) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä¸ä¼ æ¶é´" prop="uploadTime" width="160" align="center"> |
| | | <template #default="scope"> |
| | | {{ formatDate(scope.row.uploadTime) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¶æ" prop="status" width="80" align="center"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.status === 'success' ? 'success' : 'danger'" size="small"> |
| | | {{ scope.row.status === 'success' ? 'æå' : '失败' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" label="æä½" width="200" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="previewFile(scope.row)"> |
| | | é¢è§ |
| | | </el-button> |
| | | <el-button link type="primary" size="small" @click="downloadFile(scope.row)"> |
| | | ä¸è½½ |
| | | </el-button> |
| | | <el-button link type="danger" size="small" @click="removeFile(scope.row)"> |
| | | å é¤ |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- æä»¶é¢è§ç»ä»¶ --> |
| | | <filePreview ref="filePreviewRef" /> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, computed } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Plus } from '@element-plus/icons-vue' |
| | | import { getToken } from "@/utils/auth" |
| | | import { addDocumentationFile, getDocumentationFileList, deleteDocumentationFile } from '@/api/fileManagement/document' |
| | | import filePreview from '@/components/filePreview/index.vue' |
| | | |
| | | const props = defineProps({ |
| | | // documentId éè¿ open äºä»¶ä¼ å
¥ï¼ä¸éè¦ä½ä¸º props |
| | | }) |
| | | |
| | | const emit = defineEmits(['update:attachments']) |
| | | |
| | | const dialogVisible = ref(false) |
| | | const loading = ref(false) |
| | | const fileList = ref([]) |
| | | const uploadRef = ref() |
| | | const filePreviewRef = ref() |
| | | const currentDocumentId = ref('') // å
é¨ç®¡çå½åææ¡£ID |
| | | |
| | | // ä¸ä¼ é
ç½® |
| | | const uploadUrl = import.meta.env.VITE_APP_BASE_API + "/file/upload" |
| | | const uploadHeaders = computed(() => ({ |
| | | Authorization: "Bearer " + getToken() |
| | | })) |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const open = (attachments = [], documentId = '') => { |
| | | dialogVisible.value = true |
| | | currentDocumentId.value = documentId // 设置å½åææ¡£ID |
| | | // å¦ææææ¡£IDï¼åå è½½éä»¶å表 |
| | | if (documentId) { |
| | | loadAttachmentList(documentId) |
| | | } else { |
| | | fileList.value = attachments || [] |
| | | // total.value = fileList.value.length // Removed total.value |
| | | } |
| | | // currentPage.value = 1 // Removed currentPage.value |
| | | } |
| | | |
| | | // å è½½éä»¶å表 |
| | | const loadAttachmentList = async (documentId) => { |
| | | try { |
| | | loading.value = true |
| | | const params = { |
| | | page: 1, // Always load from page 1 |
| | | size: 1000, // Load all for now |
| | | documentationId: documentId |
| | | } |
| | | |
| | | const res = await getDocumentationFileList(params) |
| | | if (res.code === 200) { |
| | | const records = res.data |
| | | |
| | | // è½¬æ¢æ°æ®æ ¼å¼ |
| | | fileList.value = records.map(item => ({ |
| | | id: item.id, |
| | | name: item.name, |
| | | size: item.fileSize, |
| | | url: item.url, |
| | | uploadTime: item.createTime || item.uploadTime, |
| | | status: 'success', |
| | | uid: item.id |
| | | })) |
| | | |
| | | // total.value = totalCount // Removed total.value |
| | | } else { |
| | | ElMessage.error(res.msg || 'è·åéä»¶å表失败') |
| | | fileList.value = [] |
| | | // total.value = 0 // Removed total.value |
| | | } |
| | | } catch (error) { |
| | | console.error('è·åéä»¶å表失败:', error) |
| | | ElMessage.error('è·åéä»¶å表失败') |
| | | fileList.value = [] |
| | | // total.value = 0 // Removed total.value |
| | | } finally { |
| | | loading.value = false |
| | | } |
| | | } |
| | | |
| | | // å
³éå¼¹æ¡ |
| | | const handleClose = () => { |
| | | dialogVisible.value = false |
| | | emit('update:attachments', fileList.value) |
| | | } |
| | | |
| | | // æä»¶ä¸ä¼ åæ ¡éª |
| | | const handleBeforeUpload = (file) => { |
| | | // æ£æ¥æä»¶å¤§å°ï¼50MBï¼ |
| | | const isLt50M = file.size / 1024 / 1024 < 50 |
| | | if (!isLt50M) { |
| | | ElMessage.error('æä»¶å¤§å°ä¸è½è¶
è¿50MB!') |
| | | return false |
| | | } |
| | | |
| | | // æ£æ¥æä»¶ç±»å |
| | | const allowedTypes = [ |
| | | 'application/msword', |
| | | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', |
| | | 'application/vnd.ms-excel', |
| | | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', |
| | | 'application/vnd.ms-powerpoint', |
| | | 'application/vnd.openxmlformats-officedocument.presentationml.presentation', |
| | | 'application/pdf', |
| | | 'text/plain', |
| | | 'text/xml', |
| | | 'image/jpeg', |
| | | 'image/png', |
| | | 'image/gif', |
| | | 'image/bmp', |
| | | 'application/x-rar-compressed', |
| | | 'application/zip', |
| | | 'application/x-7z-compressed' |
| | | ] |
| | | |
| | | if (!allowedTypes.includes(file.type)) { |
| | | ElMessage.error('䏿¯æçæä»¶ç±»å!') |
| | | return false |
| | | } |
| | | |
| | | return true |
| | | } |
| | | |
| | | // æä»¶ä¸ä¼ æå |
| | | const handleUploadSuccess = (response, file, fileList) => { |
| | | console.log('æä»¶ä¸ä¼ æåååº:', response); |
| | | console.log('æä»¶ä¿¡æ¯:', file); |
| | | |
| | | if (response.code === 200) { |
| | | // æå»ºéä»¶æ°æ® - ç¡®ä¿æ£ç¡®è·åURL |
| | | const attachmentData = { |
| | | name: file.name, |
| | | url: response.data.url || response.data.path || response.data.tempPath || file.url, |
| | | fileSize: file.size, |
| | | documentationId: currentDocumentId.value |
| | | }; |
| | | |
| | | console.log('æå»ºçéä»¶æ°æ®:', attachmentData); |
| | | |
| | | // è°ç¨ä¿åéä»¶æ¥å£ |
| | | saveAttachment(attachmentData, file, fileList); |
| | | } else { |
| | | ElMessage.error(response.msg || 'æä»¶ä¸ä¼ 失败') |
| | | } |
| | | } |
| | | |
| | | // ä¿åéä»¶ä¿¡æ¯ |
| | | const saveAttachment = async (attachmentData, file, fileList) => { |
| | | try { |
| | | console.log('å¼å§ä¿åéä»¶ï¼æ°æ®:', attachmentData); |
| | | |
| | | // ç¡®ä¿URLåæ®µåå¨ä¸ææ |
| | | if (!attachmentData.url) { |
| | | console.error('éä»¶URLä¸ºç©ºï¼æ æ³ä¿å'); |
| | | ElMessage.error('æä»¶URLè·åå¤±è´¥ï¼æ æ³ä¿åéä»¶'); |
| | | return; |
| | | } |
| | | |
| | | const res = await addDocumentationFile(attachmentData); |
| | | console.log('ä¿åéä»¶æ¥å£ååº:', res); |
| | | |
| | | if (res.code === 200) { |
| | | const newFile = { |
| | | id: res.data.id || Date.now(), |
| | | name: attachmentData.name, |
| | | size: attachmentData.fileSize, |
| | | url: attachmentData.url, |
| | | uploadTime: new Date().toISOString(), |
| | | status: 'success', |
| | | uid: file.uid |
| | | } |
| | | |
| | | console.log('åå»ºçæ°æä»¶å¯¹è±¡:', newFile); |
| | | fileList.push(newFile) |
| | | ElMessage.success('æä»¶ä¸ä¼ å¹¶ä¿åæå') |
| | | |
| | | // ä¿åæååå·æ°éä»¶å表 |
| | | if (currentDocumentId.value) { |
| | | await loadAttachmentList(currentDocumentId.value); |
| | | } |
| | | } else { |
| | | ElMessage.error(res.msg || 'ä¿åéä»¶ä¿¡æ¯å¤±è´¥') |
| | | // ä¿å失败æ¶ç§»é¤æä»¶ |
| | | const index = fileList.findIndex(item => item.uid === file.uid) |
| | | if (index > -1) { |
| | | fileList.splice(index, 1) |
| | | } |
| | | } |
| | | } catch (error) { |
| | | console.error('ä¿åé件失败:', error) |
| | | ElMessage.error('ä¿åéä»¶ä¿¡æ¯å¤±è´¥') |
| | | // ä¿å失败æ¶ç§»é¤æä»¶ |
| | | const index = fileList.findIndex(item => item.uid === file.uid) |
| | | if (index > -1) { |
| | | fileList.splice(index, 1) |
| | | } |
| | | } |
| | | } |
| | | |
| | | // æä»¶ä¸ä¼ 失败 |
| | | const handleUploadError = (error, file, fileList) => { |
| | | console.error('æä»¶ä¸ä¼ 失败:', error); |
| | | console.error('失败çæä»¶:', file); |
| | | console.error('å½åæä»¶å表:', fileList); |
| | | |
| | | ElMessage.error('æä»¶ä¸ä¼ 失败ï¼è¯·æ£æ¥ç½ç»è¿æ¥ææä»¶æ ¼å¼') |
| | | } |
| | | |
| | | // ç§»é¤æä»¶ |
| | | const handleRemove = (file, fileList) => { |
| | | const index = fileList.findIndex(item => item.uid === file.uid) |
| | | if (index > -1) { |
| | | fileList.splice(index, 1) |
| | | // total.value = fileList.length // Removed total.value |
| | | } |
| | | } |
| | | |
| | | // å 餿件 |
| | | const removeFile = (file) => { |
| | | ElMessageBox.confirm(`ç¡®å®è¦å 餿件 "${file.name}" åï¼`, 'å é¤ç¡®è®¤', { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | }).then(async () => { |
| | | try { |
| | | // è°ç¨å 餿¥å£ |
| | | const res = await deleteDocumentationFile([file.id]); |
| | | if (res.code === 200) { |
| | | // 仿¬å°å表ä¸ç§»é¤ |
| | | const index = fileList.value.findIndex(item => item.id === file.id); |
| | | if (index > -1) { |
| | | fileList.value.splice(index, 1); |
| | | } |
| | | ElMessage.success('å 餿å'); |
| | | |
| | | // å¦ææææ¡£IDï¼å·æ°éä»¶å表 |
| | | if (currentDocumentId.value) { |
| | | await loadAttachmentList(currentDocumentId.value); |
| | | } |
| | | } else { |
| | | ElMessage.error(res.msg || 'å é¤å¤±è´¥'); |
| | | } |
| | | } catch (error) { |
| | | console.error('å é¤é件失败:', error); |
| | | ElMessage.error('å é¤é件失败'); |
| | | } |
| | | }).catch(() => { |
| | | // åæ¶å é¤ |
| | | }) |
| | | } |
| | | |
| | | // é¢è§æä»¶ |
| | | const previewFile = (file) => { |
| | | if (file.url) { |
| | | filePreviewRef.value.open(file.url) |
| | | } else { |
| | | ElMessage.warning('æä»¶å°åæ æï¼æ æ³é¢è§') |
| | | } |
| | | } |
| | | |
| | | // ä¸è½½æä»¶ |
| | | const downloadFile = (file) => { |
| | | if (file.url) { |
| | | // å建ä¸è½½é¾æ¥ |
| | | const link = document.createElement('a') |
| | | link.href = file.url |
| | | link.download = file.name |
| | | document.body.appendChild(link) |
| | | link.click() |
| | | document.body.removeChild(link) |
| | | ElMessage.success('å¼å§ä¸è½½æä»¶') |
| | | } else { |
| | | ElMessage.warning('æä»¶å°åæ æï¼æ æ³ä¸è½½') |
| | | } |
| | | } |
| | | |
| | | // æ ¼å¼åæä»¶å¤§å° |
| | | const formatFileSize = (bytes) => { |
| | | if (bytes === 0) return '0 B' |
| | | const k = 1024 |
| | | const sizes = ['B', 'KB', 'MB', 'GB'] |
| | | const i = Math.floor(Math.log(bytes) / Math.log(k)) |
| | | return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] |
| | | } |
| | | |
| | | // æ ¼å¼åæ¥æ |
| | | const formatDate = (dateString) => { |
| | | if (!dateString) return '' |
| | | const date = new Date(dateString) |
| | | return date.toLocaleString('zh-CN', { |
| | | year: 'numeric', |
| | | month: '2-digit', |
| | | day: '2-digit', |
| | | hour: '2-digit', |
| | | minute: '2-digit' |
| | | }) |
| | | } |
| | | |
| | | // æµè¯æä»¶ä¸ä¼ |
| | | const testUpload = () => { |
| | | console.log('å½åææ¡£ID:', currentDocumentId.value); |
| | | console.log('ä¸ä¼ URL:', uploadUrl); |
| | | console.log('ä¸ä¼ Headers:', uploadHeaders.value); |
| | | } |
| | | |
| | | // æ´é²æ¹æ³ |
| | | defineExpose({ |
| | | open, |
| | | loadAttachmentList, |
| | | testUpload |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .attachment-manager { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .upload-section { |
| | | margin-bottom: 20px; |
| | | padding: 20px; |
| | | background-color: #f8f9fa; |
| | | border-radius: 8px; |
| | | border: 2px dashed #d9d9d9; |
| | | } |
| | | |
| | | .upload-section:hover { |
| | | border-color: #409eff; |
| | | } |
| | | |
| | | .attachment-list { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .el-upload__tip { |
| | | margin-top: 10px; |
| | | color: #666; |
| | | font-size: 12px; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | :deep(.el-upload) { |
| | | width: 100%; |
| | | } |
| | | |
| | | :deep(.el-upload-dragger) { |
| | | width: 100%; |
| | | height: 120px; |
| | | } |
| | | </style> |