|
|
@@ -3,43 +3,36 @@
|
|
|
<span class="text-orange">按住鼠标拖动文件可进行附件列表排序</span>
|
|
|
</div>
|
|
|
<el-upload
|
|
|
- ref="uploadRef"
|
|
|
- :accept="accept" :action="action" :before-remove="delUploadData" :before-upload="beforeUpload"
|
|
|
- :data="uploadData"
|
|
|
- :disabled="isCanuploadVal" :file-list="fileListData" :headers="getHeader()" :on-error="uploadError"
|
|
|
- :on-exceed="uploadExceed" :on-preview="uploadPreview" :on-progress="uploadprogress"
|
|
|
- :on-remove="uploadRemove" :on-success="uploadSuccess" class="hc-upload-border"
|
|
|
- :class="autoUpload === false ? 'hc-upload-border1' : 'hc-upload-border'"
|
|
|
- drag multiple
|
|
|
- :auto-upload="autoUpload"
|
|
|
- :on-change="handleFileChange"
|
|
|
- :show-file-list="false"
|
|
|
+ ref="uploadRef" :accept="accept" :action="action" :before-remove="delUploadData"
|
|
|
+ :before-upload="beforeUpload" :data="uploadData" :disabled="isCanuploadVal" :file-list="fileListData"
|
|
|
+ :headers="getHeader()" :on-error="uploadError" :on-exceed="uploadExceed" :on-preview="uploadPreview"
|
|
|
+ :on-progress="uploadprogress" :on-remove="uploadRemove" :on-success="uploadSuccess" class="hc-upload-border"
|
|
|
+ :class="autoUpload === false ? 'hc-upload-border1' : 'hc-upload-border'" drag multiple :auto-upload="autoUpload"
|
|
|
+ :on-change="handleFileChange" :show-file-list="false"
|
|
|
>
|
|
|
<!-- 使用file插槽自定义文件列表 -->
|
|
|
<draggable
|
|
|
- v-model="fileListData"
|
|
|
- v-loading="pdfLoading"
|
|
|
- item-key="uid"
|
|
|
- handle=".drag-handle"
|
|
|
- class="file-list-container"
|
|
|
- @end="onDragEnd"
|
|
|
+ v-model="fileListData" v-loading="pdfLoading" item-key="uid" handle=".drag-handle"
|
|
|
+ class="file-list-container" @end="onDragEnd"
|
|
|
>
|
|
|
<template #item="{ element }">
|
|
|
<div class="file-item">
|
|
|
<HcIcon name="drag-move-2" class="drag-handle cursor-move" />
|
|
|
<HcIcon name="file" class="file-icon" />
|
|
|
<span class="file-name cursor-pointer" @click="previewUrl(element)">{{ element.name }}</span>
|
|
|
-
|
|
|
- <HcIcon
|
|
|
- name="close"
|
|
|
- class="float-right cursor-pointer text-red"
|
|
|
- @click.stop="handleRemove(element)"
|
|
|
+
|
|
|
+ <HcIcon
|
|
|
+ name="close" class="float-right cursor-pointer text-red"
|
|
|
+ @click.stop="handleRemove(element)"
|
|
|
/>
|
|
|
</div>
|
|
|
</template>
|
|
|
</draggable>
|
|
|
<template #trigger>
|
|
|
- <div v-loading="uploadDisabled" :element-loading-text="loadingText" class="hc-upload-loading h-full" @click.stop="beforesubmitUpload">
|
|
|
+ <div
|
|
|
+ v-loading="uploadDisabled" :element-loading-text="loadingText" class="hc-upload-loading h-full"
|
|
|
+ @click.stop="beforesubmitUpload"
|
|
|
+ >
|
|
|
<HcIcon name="backup" ui="text-5xl mt-4" />
|
|
|
<div class="el-upload__text">拖动文件到这里 或 <em>点击这里选择文件</em></div>
|
|
|
</div>
|
|
|
@@ -59,7 +52,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { nextTick, onBeforeUpdate, onMounted, ref, watch } from 'vue'
|
|
|
+import { nextTick, onMounted, ref, watch } from 'vue'
|
|
|
import { getHeader } from 'hc-vue3-ui'
|
|
|
import wbsApi from '~api/data-fill/wbs'
|
|
|
import { isFileSize } from 'js-fast-way'
|
|
|
@@ -75,33 +68,33 @@ const props = defineProps({
|
|
|
type: Object,
|
|
|
default: () => ({}),
|
|
|
},
|
|
|
- isCanupload:{
|
|
|
- type:Boolean,
|
|
|
- default:false,
|
|
|
+ isCanupload: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
},
|
|
|
- action:{
|
|
|
- type:String,
|
|
|
- default:'#',
|
|
|
+ action: {
|
|
|
+ type: String,
|
|
|
+ default: '#',
|
|
|
},
|
|
|
- accept:{
|
|
|
- type:String,
|
|
|
- default:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/pdf,.doc,.docx,application/msword',
|
|
|
+ accept: {
|
|
|
+ type: String,
|
|
|
+ default: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/pdf,.doc,.docx,application/msword',
|
|
|
},
|
|
|
- acceptTip:{
|
|
|
- type:String,
|
|
|
- default:'允许格式:pdf/excel/word, 文件大小 小于 60MB',
|
|
|
+ acceptTip: {
|
|
|
+ type: String,
|
|
|
+ default: '允许格式:pdf/excel/word, 文件大小 小于 60MB',
|
|
|
},
|
|
|
- autoUpload:{
|
|
|
- type:Boolean,
|
|
|
- default:true,
|
|
|
+ autoUpload: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
},
|
|
|
- typevalue:{
|
|
|
- type:[String, Number],
|
|
|
- default:'',
|
|
|
+ typevalue: {
|
|
|
+ type: [String, Number],
|
|
|
+ default: '',
|
|
|
}, //附件类型
|
|
|
- isListFile:{
|
|
|
- type:Boolean,
|
|
|
- default:false,
|
|
|
+ isListFile: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
}, //是否列表文件
|
|
|
})
|
|
|
|
|
|
@@ -148,19 +141,19 @@ watch(() => [
|
|
|
// 类型变化监听 - 核心修改:切换类型时将未上传文件添加到文件列表
|
|
|
watch(() => props.typevalue, async (newType, oldType) => {
|
|
|
await nextTick()
|
|
|
-
|
|
|
+
|
|
|
// 保留所有已上传文件(已删除的会被父组件同步移除)
|
|
|
- const uploadedFiles = fileListData.value.filter(file =>
|
|
|
+ const uploadedFiles = fileListData.value.filter(file =>
|
|
|
file.id || file.status === 'success',
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
// 将统一未上传列表中的文件添加到当前文件列表
|
|
|
fileListData.value = [...uploadedFiles, ...unUploadedFiles.value]
|
|
|
}, { immediate: true })
|
|
|
|
|
|
// 深度监听fileList变化
|
|
|
watch(() => props.fileList, (newVal) => {
|
|
|
- fileListData.value = [...newVal]
|
|
|
+ fileListData.value = [...newVal]
|
|
|
}, { deep: true, immediate: true })
|
|
|
|
|
|
onMounted(() => {
|
|
|
@@ -187,7 +180,7 @@ const beforeUpload = async (file) => {
|
|
|
const uploadExceed = () => {
|
|
|
window?.$message?.warning('请上传 jpg/png/pdf/excel/word 的文件,文件大小 不超过60M')
|
|
|
}
|
|
|
-const q = 1
|
|
|
+const q = 1
|
|
|
|
|
|
// 文件变化处理 - 改为统一未上传列表
|
|
|
const handleFileChange = async (file, fileList) => {
|
|
|
@@ -195,19 +188,19 @@ const handleFileChange = async (file, fileList) => {
|
|
|
window?.$message?.warning('文件大小不能超过60M!')
|
|
|
return
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
const processedList = fileList.map((item, index) => ({
|
|
|
...item,
|
|
|
sort: index + q,
|
|
|
url: '',
|
|
|
- })).filter(file =>
|
|
|
+ })).filter(file =>
|
|
|
(file.size !== undefined && isFileSize(file.size, 60)) || file.size === undefined,
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
fileListData.value = [...processedList]
|
|
|
-
|
|
|
+
|
|
|
// 存储未上传文件到统一列表(过滤已上传和上传中的)
|
|
|
- const currentUnUploaded = fileListData.value.filter(file =>
|
|
|
+ const currentUnUploaded = fileListData.value.filter(file =>
|
|
|
!file.id && !['success', 'uploading'].includes(file.status),
|
|
|
)
|
|
|
unUploadedFiles.value = [...currentUnUploaded]
|
|
|
@@ -216,12 +209,33 @@ const handleFileChange = async (file, fileList) => {
|
|
|
//上传文件前预览pdf
|
|
|
const pdfLoading = ref(false)
|
|
|
const getPdfUrl = async (arr) => {
|
|
|
- const formData = new FormData()
|
|
|
- arr.forEach((file) => {
|
|
|
+ console.log(arr)
|
|
|
+ let formData = new FormData()
|
|
|
+ for (let i = 0; i < arr.length; i++) {
|
|
|
+ const file = arr[i]
|
|
|
if (file.raw !== undefined) {
|
|
|
formData.append('file', file.raw)
|
|
|
+ } else {
|
|
|
+
|
|
|
+ const res = await fetch(file.domainUrl)
|
|
|
+ const blob = await res.blob()
|
|
|
+
|
|
|
+ const mimeMap = {
|
|
|
+ pdf: 'application/pdf',
|
|
|
+ xls: 'application/vnd.ms-excel',
|
|
|
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
|
+ doc: 'application/msword',
|
|
|
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
|
+ }
|
|
|
+
|
|
|
+ const ext = file.name.split('.').pop().toLowerCase()
|
|
|
+ const mime = mimeMap[ext] || 'application/octet-stream'
|
|
|
+
|
|
|
+ const f = new File([blob], file.name, { type: mime })
|
|
|
+ formData.append('file', f)
|
|
|
}
|
|
|
- })
|
|
|
+ }
|
|
|
+
|
|
|
pdfLoading.value = true
|
|
|
|
|
|
const { error, code, msg, data } = await wbsApi.previewBussfile(formData)
|
|
|
@@ -261,13 +275,13 @@ const uploadprogress = () => {
|
|
|
const finishFileNum = ref(0)
|
|
|
const uploadSuccess = (response, file) => {
|
|
|
finishFileNum.value++
|
|
|
-
|
|
|
+
|
|
|
// 从统一未上传列表中移除已成功上传的文件
|
|
|
const index = unUploadedFiles.value.findIndex(f => f.uid === file.uid)
|
|
|
if (index !== -1) {
|
|
|
unUploadedFiles.value.splice(index, 1)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (beforeFileNum.value === finishFileNum.value) {
|
|
|
uploadDisabled.value = false
|
|
|
emit('change', { type: 'success' })
|
|
|
@@ -280,12 +294,12 @@ const errorFileNum = ref(0)
|
|
|
const uploadError = (error, file) => {
|
|
|
errorFileNum.value++
|
|
|
window?.$message?.error('上传失败')
|
|
|
-
|
|
|
+
|
|
|
// 确保上传失败的文件保留在未上传列表中
|
|
|
if (!unUploadedFiles.value.some(f => f.uid === file.uid)) {
|
|
|
unUploadedFiles.value.push(file)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
const num = finishFileNum.value + errorFileNum.value
|
|
|
if (beforeFileNum.value === num) {
|
|
|
uploadDisabled.value = false
|
|
|
@@ -299,8 +313,9 @@ const uploadPreview = ({ url }) => {
|
|
|
toPdfPage(url)
|
|
|
}
|
|
|
|
|
|
-const previewUrl = async (item)=>{
|
|
|
+const previewUrl = async (item) => {
|
|
|
const pdfUrLArray = await getPdfUrl([item])
|
|
|
+ console.log('11111111111', pdfUrLArray)
|
|
|
item.url = pdfUrLArray[0]?.url || ''
|
|
|
if (item.url) {
|
|
|
toPdfPage(item.url)
|
|
|
@@ -312,20 +327,20 @@ const uploadRef = ref(null)
|
|
|
// 删除文件 - 核心修改:删除后同步更新父组件fileList
|
|
|
const delUploadData = async (file) => {
|
|
|
const { id, status } = file
|
|
|
-
|
|
|
+
|
|
|
if (!id || status === 'uploading') {
|
|
|
// 处理未上传文件删除
|
|
|
const index = fileListData.value.findIndex(f => f.uid === file.uid)
|
|
|
if (index !== -1) {
|
|
|
fileListData.value.splice(index, 1)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 从统一未上传列表中移除
|
|
|
const unUploadedIndex = unUploadedFiles.value.findIndex(f => f.uid === file.uid)
|
|
|
if (unUploadedIndex !== -1) {
|
|
|
unUploadedFiles.value.splice(unUploadedIndex, 1)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
uploadRef.value.abort()
|
|
|
uploadDisabled.value = false
|
|
|
// 通知父组件更新文件列表
|
|
|
@@ -334,7 +349,7 @@ const delUploadData = async (file) => {
|
|
|
// 处理已上传文件删除
|
|
|
loadingText.value = '删除中...'
|
|
|
uploadDisabled.value = true
|
|
|
- const { error, code, msg } = await (!isListFile.value
|
|
|
+ const { error, code, msg } = await (!isListFile.value
|
|
|
? wbsApi.delTabById({ ids: id })
|
|
|
: wbsApi.removeBussFile({ ids: id }))
|
|
|
uploadDisabled.value = false
|
|
|
@@ -346,7 +361,7 @@ const delUploadData = async (file) => {
|
|
|
fileListData.value.splice(index, 1)
|
|
|
}
|
|
|
// 关键:通知父组件更新fileList,确保切换类型时能获取最新列表
|
|
|
- emit('update', [...fileListData.value])
|
|
|
+ emit('update', [...fileListData.value])
|
|
|
} else {
|
|
|
window?.$message?.error(msg || '操作失败')
|
|
|
}
|
|
|
@@ -389,7 +404,7 @@ const submitUpload = async () => {
|
|
|
formData.append('file', file.raw)
|
|
|
}
|
|
|
})
|
|
|
-
|
|
|
+
|
|
|
function hasFileFields(formData) {
|
|
|
for (let [key, value] of formData.entries()) {
|
|
|
if (value instanceof File || value instanceof Blob) {
|
|
|
@@ -398,7 +413,7 @@ const submitUpload = async () => {
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (hasFileFields(formData)) {
|
|
|
subLoading.value = true
|
|
|
if (isListFile.value) {
|
|
|
@@ -412,12 +427,12 @@ const submitUpload = async () => {
|
|
|
uploadDisabled.value = false
|
|
|
subLoading.value = false
|
|
|
if (!error && code === 200) {
|
|
|
- window?.$message?.success('上传成功')
|
|
|
+ window?.$message?.success('上传成功')
|
|
|
await sortFile()
|
|
|
// 清空统一未上传列表
|
|
|
unUploadedFiles.value = []
|
|
|
emit('change', { type: 'success' })
|
|
|
- emit('update', [...fileListData.value])
|
|
|
+ emit('update', [...fileListData.value])
|
|
|
} else if (code === 413) {
|
|
|
window?.$message?.error('上传文件过大,请上传小于60M的文件')
|
|
|
} else {
|
|
|
@@ -432,12 +447,12 @@ const submitUpload = async () => {
|
|
|
uploadDisabled.value = false
|
|
|
subLoading.value = false
|
|
|
if (!error && code === 200) {
|
|
|
- window?.$message?.success('上传成功')
|
|
|
+ window?.$message?.success('上传成功')
|
|
|
await sortFile()
|
|
|
// 清空统一未上传列表
|
|
|
unUploadedFiles.value = []
|
|
|
emit('change', { type: 'success' })
|
|
|
- emit('update', [...fileListData.value])
|
|
|
+ emit('update', [...fileListData.value])
|
|
|
} else if (code === 413) {
|
|
|
window?.$message?.error('上传文件过大,请上传小于60M的文件')
|
|
|
} else {
|
|
|
@@ -452,7 +467,7 @@ const submitUpload = async () => {
|
|
|
}
|
|
|
|
|
|
//上传文件后排序
|
|
|
-const sortFile = async ()=>{
|
|
|
+const sortFile = async () => {
|
|
|
if (fileListData.value.length <= 0) {
|
|
|
window.$message.warning('请先上传文件')
|
|
|
return
|
|
|
@@ -461,24 +476,24 @@ const sortFile = async ()=>{
|
|
|
fileListData.value.forEach((file) => {
|
|
|
list.push(file.name)
|
|
|
})
|
|
|
-
|
|
|
+
|
|
|
let obj1 = {
|
|
|
- list:list,
|
|
|
- id:uploadData.value.nodeId,
|
|
|
- contractId:uploadData.value.contractId,
|
|
|
- classify:uploadData.value.classify,
|
|
|
- type:uploadData.value.type,
|
|
|
+ list: list,
|
|
|
+ id: uploadData.value.nodeId,
|
|
|
+ contractId: uploadData.value.contractId,
|
|
|
+ classify: uploadData.value.classify,
|
|
|
+ type: uploadData.value.type,
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
let obj2 = {
|
|
|
- list:list,
|
|
|
- id:uploadData.value.pkeyId,
|
|
|
- contractId:uploadData.value.contractId,
|
|
|
- classify:uploadData.value.classify,
|
|
|
- projectId:uploadData.value.projectId,
|
|
|
- type:2,
|
|
|
+ list: list,
|
|
|
+ id: uploadData.value.pkeyId,
|
|
|
+ contractId: uploadData.value.contractId,
|
|
|
+ classify: uploadData.value.classify,
|
|
|
+ projectId: uploadData.value.projectId,
|
|
|
+ type: 2,
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
const { error, code, msg } = await (isListFile.value
|
|
|
? wbsApi.addFileSort(obj2)
|
|
|
: wbsApi.addFileSort(obj1))
|
|
|
@@ -492,88 +507,90 @@ const sortFile = async ()=>{
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss">
|
|
|
-.hc-upload-border1 .el-upload-dragger{
|
|
|
+.hc-upload-border1 .el-upload-dragger {
|
|
|
padding: 0px;
|
|
|
}
|
|
|
-.hc-upload-border1 .el-upload-dragger .el-upload__text{
|
|
|
+
|
|
|
+.hc-upload-border1 .el-upload-dragger .el-upload__text {
|
|
|
padding: 40px;
|
|
|
}
|
|
|
</style>
|
|
|
|
|
|
<style scoped>
|
|
|
.file-list-container {
|
|
|
- margin-top: 16px;
|
|
|
- border: 1px solid #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
- padding: 10px;
|
|
|
- background-color: #f9f9f9;
|
|
|
+ margin-top: 16px;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 10px;
|
|
|
+ background-color: #f9f9f9;
|
|
|
}
|
|
|
|
|
|
.file-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: 8px 12px;
|
|
|
- margin: 6px 0;
|
|
|
- background-color: #fff;
|
|
|
- border-radius: 4px;
|
|
|
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
- transition: all 0.3s ease;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 8px 12px;
|
|
|
+ margin: 6px 0;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
+ transition: all 0.3s ease;
|
|
|
}
|
|
|
|
|
|
.file-item:hover {
|
|
|
- background-color: #f5f7fa;
|
|
|
- transform: translateY(-1px);
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ transform: translateY(-1px);
|
|
|
}
|
|
|
|
|
|
.drag-handle {
|
|
|
- margin-right: 10px;
|
|
|
- cursor: move;
|
|
|
- color: #999;
|
|
|
+ margin-right: 10px;
|
|
|
+ cursor: move;
|
|
|
+ color: #999;
|
|
|
}
|
|
|
|
|
|
.drag-handle:hover {
|
|
|
- color: #409eff;
|
|
|
+ color: #409eff;
|
|
|
}
|
|
|
|
|
|
.file-icon {
|
|
|
- margin-right: 10px;
|
|
|
- color: #409eff;
|
|
|
- font-size: 18px;
|
|
|
+ margin-right: 10px;
|
|
|
+ color: #409eff;
|
|
|
+ font-size: 18px;
|
|
|
}
|
|
|
|
|
|
.file-name {
|
|
|
- flex: 1;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- white-space: nowrap;
|
|
|
- font-size: 14px;
|
|
|
+ flex: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ font-size: 14px;
|
|
|
}
|
|
|
|
|
|
.file-status {
|
|
|
- margin-right: 10px;
|
|
|
- font-size: 12px;
|
|
|
+ margin-right: 10px;
|
|
|
+ font-size: 12px;
|
|
|
}
|
|
|
|
|
|
.uploading-text {
|
|
|
- color: #e6a23c;
|
|
|
+ color: #e6a23c;
|
|
|
}
|
|
|
|
|
|
.success-text {
|
|
|
- color: #67c23a;
|
|
|
+ color: #67c23a;
|
|
|
}
|
|
|
|
|
|
.fail-text {
|
|
|
- color: #f56c6c;
|
|
|
+ color: #f56c6c;
|
|
|
}
|
|
|
|
|
|
.cursor-move {
|
|
|
- cursor: move;
|
|
|
+ cursor: move;
|
|
|
}
|
|
|
|
|
|
-.hc-upload-border1 .el-upload-dragger{
|
|
|
- padding: 0px;
|
|
|
+.hc-upload-border1 .el-upload-dragger {
|
|
|
+ padding: 0px;
|
|
|
}
|
|
|
-.hc-upload-border1 .el-upload-dragger .el-upload__text{
|
|
|
- padding: 40px;
|
|
|
+
|
|
|
+.hc-upload-border1 .el-upload-dragger .el-upload__text {
|
|
|
+ padding: 40px;
|
|
|
}
|
|
|
</style>
|