smart-bid-web/src/views/template/templateInfo/components/child/SectionFile.vue

365 lines
9.6 KiB
Vue

<template>
<div class="file-container">
<div class="basic-info-title">
<div class="title-content">
<img src="@/assets/enterpriseLibrary/basic-info.png" alt="标段文件">
<span>{{ title }}</span>
</div>
<el-button
type="text"
icon="el-icon-plus"
class="add-tab-btn"
@click="handleAddTab"
:disabled="fileTabs.length >= 10"
>
添加文件
</el-button>
</div>
<el-tabs
v-model="activeTabIndex"
type="card"
class="file-tabs"
@tab-remove="handleRemoveTab"
@tab-click="handleTabChange"
>
<el-tab-pane
v-for="(tab, index) in fileTabs"
:key="index"
:label="tab.formData.fileName || ('文件 ' + (index + 1))"
:name="index.toString()"
closable
>
<el-form
:model="tab.formData"
:rules="rules"
:ref="'sectionFileForm_' + index"
label-width="120px"
label-position="top"
class="file-form"
>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="组成文件名称" prop="fileName">
<el-input
v-model="tab.formData.fileName"
placeholder="请输入"
maxlength="128"
@input="handleFileNameChange(index)"
@change="handleFileNameChange(index)"
></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="文件类型" prop="compositionFileType">
<el-select
v-model="tab.formData.compositionFileType"
placeholder="请选择文件类型"
clearable
@change="handleTypeChange(index)"
>
<el-option
v-for="item in compositionFileTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="文件" prop="fileList">
<UploadFile
:fileList="tab.formData.fileList"
:fileUploadRule="fileUploadRule"
@file-change="(files, type) => handleFileChange(files, index)"
@del-file="(file) => handleDelFile(file, index)"
:uploadType="uploadType"
:maxFileTips="maxFileTips"
type="section_file"
:limitUploadNum="1"
:show-file-list="true"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import UploadFile from '@/views/common/UploadFile.vue'
export default {
name: 'SectionFile',
components: { UploadFile },
props: {
title: {
type: String,
default: '模板组成-标段/标包文件'
}
},
data() {
return {
tabFiles: [],
uploadType: 'doc、docx、pdf、xls、xlsx、wps',
maxFileTips: '50MB',
fileUploadRule: { fileUploadType: 'section_file', suffix: 'template' },
activeTabIndex: '0',
fileTabs: [
{
formData: {
compositionType: '2',
fileName: '',
compositionFileType: '',
fileList: [],
delFileList: []
}
}
],
rules: {
fileName: [
{ required: true, message: '请输入组成文件名称', trigger: 'blur' }
],
compositionFileType: [
{ required: true, message: '请选择文件类型', trigger: 'change' }
],
fileList: [
{ required: true, message: '请上传文件', trigger: 'change' }
]
},
compositionFileTypeOptions: []
}
},
created() {
this.loadFileTypeDict()
},
methods: {
loadFileTypeDict() {
this.getDicts('file_type').then(response => {
this.compositionFileTypeOptions = response.data.map(item => ({
label: item.dictLabel,
value: item.dictLabel
}))
}).catch(error => {
console.error('加载文件类型字典失败:', error)
})
},
handleAddTab() {
this.fileTabs.push({
formData: {
compositionType: '2',
fileName: '',
compositionFileType: '',
fileList: [],
delFileList: []
}
})
this.activeTabIndex = (this.fileTabs.length - 1).toString()
},
handleRemoveTab(index) {
if (this.fileTabs.length <= 1) {
this.$message.warning('至少保留一个文件')
return
}
this.fileTabs.splice(index, 1)
if (this.activeTabIndex === index.toString()) {
this.activeTabIndex = '0'
}
},
handleFileChange(files, index) {
this.fileTabs[index].formData.fileList = files;
if (files.length > 0 && files[0].status === 'success') {
const currentTab = this.fileTabs[index];
files[0].compositionName = currentTab.formData.fileName;
files[0].compositionFileType = currentTab.formData.compositionFileType;
if (files[0].response) {
files[0].response.businessType = 'section_file';
}
}
},
handleDelFile(file, index) {
// 核心修改:统一从 response.fileRes.filePath 获取路径
const filePath = file.response?.fileRes?.filePath || file.filePath || '';
if (filePath) {
const delFileList = this.fileTabs[index].formData.delFileList;
if (!delFileList.includes(filePath)) {
delFileList.push(filePath)
}
}
},
handleFileNameChange(index) {
const currentTab = this.fileTabs[index];
const fileList = currentTab.formData.fileList;
if (fileList.length > 0) {
fileList[0].compositionName = currentTab.formData.fileName;
}
},
handleTypeChange(index) {
const currentTab = this.fileTabs[index];
const fileList = currentTab.formData.fileList;
if (fileList.length > 0) {
fileList[0].compositionFileType = currentTab.formData.compositionFileType;
}
},
handleTabChange(tab, event) {
// tab.index 是当前被点击的 tab 的索引
const index = tab.index;
console.log(`切换到了第 ${index + 1} 个 tab`);
this.setFormData(this.tabFiles)
},
setFormData(sectionFiles) {
this.tabFiles = sectionFiles
this.fileTabs = []
if (!sectionFiles || sectionFiles.length === 0) {
this.fileTabs.push({
formData: {
compositionType: '2',
fileName: '',
compositionFileType: '',
fileList: [],
delFileList: []
}
})
this.activeTabIndex = '0'
return
}
sectionFiles.forEach((file) => {
const formattedFile = {
name: file.fileName || file.name,
size: file.size,
status: 'success',
percentage: 100,
filePath: file.filePath,
lsFilePath: file.lsFilePath,
url: file.lsFilePath,
compositionName: file.compositionName || file.fileName || '',
compositionFileType: file.compositionFileType || '',
compositionType: '2',
businessType: 'section_file',
// 核心修改:添加 response 属性,与 ProjectFile 组件保持一致
response: {
fileRes: file
}
};
this.fileTabs.push({
formData: {
compositionType: '2',
fileName: formattedFile.compositionName,
compositionFileType: formattedFile.compositionFileType,
fileList: [formattedFile],
delFileList: []
}
})
})
this.activeTabIndex = '0'
},
validate() {
return new Promise(async (resolve, reject) => {
try {
const allFormData = []
for (let i = 0; i < this.fileTabs.length; i++) {
const formRef = this.$refs[`sectionFileForm_${i}`]?.[0]
if (!formRef) continue
await new Promise((validResolve, validReject) => {
formRef.validate((valid) => {
if (valid) {
validResolve()
} else {
this.activeTabIndex = i.toString()
validReject(new Error(`文件 ${i + 1} 信息填写不完整`))
}
})
})
allFormData.push({ ...this.fileTabs[i].formData })
}
resolve(allFormData)
} catch (error) {
reject(error)
}
})
}
}
}
</script>
<style scoped lang="scss">
/* 样式部分保持不变 */
.file-container {
width: 100%;
}
.basic-info-title {
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px 0 20px;
.title-content {
display: flex;
align-items: center;
}
span {
margin-left: 8px;
font-size: 18px;
font-weight: 500;
color: #1d2129;
}
img {
width: 20px;
height: 20px;
object-fit: contain;
}
}
.file-tabs {
margin-bottom: 20px;
width: 100%;
}
.add-tab-btn {
color: #409EFF;
border: 1px dashed #409EFF;
padding: 6px 12px;
border-radius: 4px;
white-space: nowrap;
}
.file-form {
padding: 20px 10px 0;
}
::v-deep .el-tabs__item {
padding: 0 20px;
}
::v-deep .el-tabs__close-btn {
margin-left: 8px;
}
</style>