bug修复
This commit is contained in:
parent
f75a8d844a
commit
1c6dcbbd84
|
|
@ -37,11 +37,11 @@ export function updatePerformance(data) {
|
|||
}
|
||||
|
||||
// 删除业绩库
|
||||
export function delPerformance(performanceId) {
|
||||
export function delPerformance(data) {
|
||||
return request({
|
||||
url: '/smartBid/performance/delete',
|
||||
method: 'post',
|
||||
data: { performanceId }
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -216,11 +216,6 @@ export default {
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 表格最大高度(像素),默认600px
|
||||
tableMaxHeight: {
|
||||
type: [Number, String],
|
||||
default: 600,
|
||||
},
|
||||
// 是否自动加载数据 默认自动加载
|
||||
autoLoad: {
|
||||
type: Boolean,
|
||||
|
|
@ -253,20 +248,19 @@ export default {
|
|||
},
|
||||
/* 表格卡片动态高度 */
|
||||
tableCardStyle() {
|
||||
const baseHeight = this.showSearch ? 200 : 120 // 搜索区域高度
|
||||
const toolbarHeight = this.showRightTools ? 40 : 0 // 工具栏高度
|
||||
const paginationHeight = 60 // 分页区域高度
|
||||
const availableHeight = `calc(100vh - ${baseHeight + toolbarHeight + paginationHeight + 25
|
||||
}px)`
|
||||
return {
|
||||
height: availableHeight,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
// 去掉固定高度,让卡片自然适应内容
|
||||
}
|
||||
},
|
||||
/* 表格容器样式 */
|
||||
tableContainerStyle() {
|
||||
return {}
|
||||
return {
|
||||
flex: 1, // 占满父元素剩余空间
|
||||
overflow: 'auto', // 超出部分显示滚动条
|
||||
maxHeight: `calc(100vh - 200px)`, // 可根据实际情况调整
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -285,6 +279,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
tableMaxHeight: 'calc(100vh - 220px)', // 动态计算最大高度
|
||||
// 表单校验
|
||||
formRules: {},
|
||||
loading: false,
|
||||
|
|
@ -702,6 +697,8 @@ export default {
|
|||
// 新增表格容器样式
|
||||
.table-container {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
|
||||
::v-deep .el-table {
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -140,21 +140,11 @@ export default {
|
|||
formData.delFiles.push(...financialStatementData.delFileList)
|
||||
}
|
||||
|
||||
// 5. 后续的文件名唯一性校验、接口调用逻辑不变...
|
||||
// if (this.type !== 'add') {
|
||||
// const uniqueCheck = await checkFileNameUnique({
|
||||
// fileName: formData.fileName,
|
||||
// financeId: formData.id ? Number(formData.id) : null,
|
||||
// enterpriseId: this.enterpriseId
|
||||
// })
|
||||
// if (!uniqueCheck) {
|
||||
// throw new Error('同一企业下文件名已存在,请更换')
|
||||
// }
|
||||
// }
|
||||
|
||||
if (this.type === 'add') {
|
||||
console.log('asdad',formData)
|
||||
await addFinance(formData)
|
||||
} else {
|
||||
console.log('年份编辑',formData)
|
||||
await updateFinance(formData)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
<el-col :span="8" class="info-col">
|
||||
<el-form-item label="报告年份" class="info-item">
|
||||
<el-date-picker
|
||||
v-model="formData.reportYear"
|
||||
v-model="formattedReportYear"
|
||||
type="year"
|
||||
format="yyyy"
|
||||
value-format="yyyy"
|
||||
|
|
@ -90,6 +90,18 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
formattedReportYear() {
|
||||
// 如果 reportYear 存在且不为空,则转换为字符串
|
||||
if (this.formData.reportYear) {
|
||||
return String(this.formData.reportYear);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 格式化文件列表:仅保留财务报告类型的附件(解决回显错乱)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
:limitUploadNum="1"
|
||||
type="finance_report"
|
||||
:show-file-list="true"
|
||||
@upload-fail="handleUploadFail"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -38,8 +39,8 @@
|
|||
v-model="formData.fileName"
|
||||
placeholder="文件上传后自动提取"
|
||||
class="form-control"
|
||||
maxlength="100"
|
||||
readonly
|
||||
show-word-limit
|
||||
maxlength="32"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -114,6 +115,16 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
|
||||
handleUploadFail() {
|
||||
|
||||
|
||||
// 将文件名和报告年份置空
|
||||
this.formData.fileName = '';
|
||||
this.formData.reportYear = '';
|
||||
|
||||
|
||||
},
|
||||
|
||||
handleDocxContent(text) {
|
||||
// 模拟OCR返回格式,将docx文本包装成现有逻辑可处理的结构
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
v-model="formData.operatingIncome"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -47,6 +49,8 @@
|
|||
v-model="formData.currentAssets"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -56,6 +60,8 @@
|
|||
v-model="formData.currentLiabilities"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -68,6 +74,8 @@
|
|||
v-model="formData.currentRatio"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -77,6 +85,10 @@
|
|||
v-model="formData.netProfit"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
:precision="2"
|
||||
@change="handleNumberInput('netProfit')"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -86,6 +98,8 @@
|
|||
v-model="formData.shareholdersEquity"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -98,6 +112,8 @@
|
|||
v-model="formData.returnOnNetAssets"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -107,6 +123,8 @@
|
|||
v-model="formData.totalLiabilities"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -116,6 +134,10 @@
|
|||
v-model="formData.totalAssets"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
:precision="2"
|
||||
@change="handleNumberInput('totalAssets')"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -128,6 +150,8 @@
|
|||
v-model="formData.assetLiabilityRatio"
|
||||
placeholder="自动提取"
|
||||
class="form-control auto-input"
|
||||
show-word-limit
|
||||
maxlength="16"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -249,7 +273,7 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
// 从文本中提取财务数据(核心逻辑)
|
||||
// 从文本中提取财务数据(核心逻辑)
|
||||
extractFinancialDataFromText(text) {
|
||||
const data = {};
|
||||
const keywords = Object.keys(this.ocrResultParams); // 获取所有财务指标关键词
|
||||
|
|
@ -269,13 +293,20 @@ export default {
|
|||
return data;
|
||||
},
|
||||
|
||||
// 将提取的财务数据填充到表单
|
||||
// 将提取的财务数据填充到表单
|
||||
fillFormWithFinancialData(financialData) {
|
||||
Object.keys(financialData).forEach(keyword => {
|
||||
const formField = this.ocrResultParams[keyword];
|
||||
if (formField) {
|
||||
// 保留数字、小数点和百分号(清除其他字符)
|
||||
this.formData[formField] = financialData[keyword].replace(/[^\d.%]/g, '');
|
||||
const cleanedValue = financialData[keyword].replace(/[^\d.%]/g, '');
|
||||
|
||||
// 对特定字段进行两位小数格式化
|
||||
if (formField === 'netProfit' || formField === 'totalAssets') {
|
||||
this.formData[formField] = this.formatToTwoDecimalPlaces(cleanedValue);
|
||||
} else {
|
||||
this.formData[formField] = cleanedValue;
|
||||
}
|
||||
}
|
||||
});
|
||||
// 触发表单验证
|
||||
|
|
@ -296,7 +327,16 @@ export default {
|
|||
: [];
|
||||
|
||||
this.formData = {
|
||||
...(data || {}),
|
||||
operatingIncome: data.operatingIncome,
|
||||
currentAssets: data.currentAssets,
|
||||
currentLiabilities: data.currentLiabilities,
|
||||
currentRatio: data.currentRatio,
|
||||
netProfit: data.netProfit,
|
||||
shareholdersEquity: data.shareholdersEquity,
|
||||
returnOnNetAssets: data.returnOnNetAssets,
|
||||
totalLiabilities: data.totalLiabilities,
|
||||
totalAssets: data.totalAssets,
|
||||
assetLiabilityRatio: data.assetLiabilityRatio,
|
||||
fileList: financialFiles,
|
||||
delFileList: []
|
||||
}
|
||||
|
|
@ -363,13 +403,14 @@ export default {
|
|||
Object.keys(chat_res).forEach(key => {
|
||||
const formField = this.ocrResultParams[key]
|
||||
if (formField && chat_res[key]) {
|
||||
if (['operatingIncome', 'currentAssets', 'currentLiabilities', 'currentRatio',
|
||||
'netProfit', 'shareholdersEquity', 'returnOnNetAssets', 'totalLiabilities',
|
||||
'totalAssets', 'assetLiabilityRatio'].includes(formField)) {
|
||||
this.formData[formField] = chat_res[key].replace(/[^\d.]/g, '')
|
||||
} else {
|
||||
this.formData[formField] = chat_res[key]
|
||||
let processedValue = chat_res[key].replace(/[^\d.]/g, '')
|
||||
|
||||
// 对特定字段进行两位小数格式化
|
||||
if (formField === 'netProfit' || formField === 'totalAssets') {
|
||||
processedValue = this.formatToTwoDecimalPlaces(processedValue)
|
||||
}
|
||||
|
||||
this.formData[formField] = processedValue
|
||||
}
|
||||
})
|
||||
this.$message.success('OCR识别成功,已自动填充财务数据')
|
||||
|
|
@ -398,16 +439,12 @@ export default {
|
|||
|
||||
validate() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.$refs.financialStatementForm) {
|
||||
reject(new Error('表单实例未加载完成'))
|
||||
return
|
||||
}
|
||||
|
||||
this.$refs.financialStatementForm.validate((valid) => {
|
||||
if (valid) {
|
||||
resolve(this.formData)
|
||||
} else {
|
||||
reject(new Error('财务报表信息填写不完整'))
|
||||
// 前端验证失败,不继续提交到后端
|
||||
reject(new Error('请完善表单信息'))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -454,7 +491,36 @@ export default {
|
|||
}
|
||||
|
||||
this.fileUploadList.push(item)
|
||||
},
|
||||
|
||||
/**
|
||||
* 将数值格式化为最多保留两位小数的字符串
|
||||
* @param {string|number} value - 需要格式化的数值
|
||||
* @returns {string} 格式化后的字符串
|
||||
*/
|
||||
formatToTwoDecimalPlaces(value) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '';
|
||||
}
|
||||
// 尝试将输入值转换为数字
|
||||
const num = Number(value);
|
||||
// 检查转换是否成功
|
||||
if (isNaN(num)) {
|
||||
return value; // 如果无法转换,返回原始值
|
||||
}
|
||||
// 使用 toFixed(2) 进行四舍五入并保留两位小数
|
||||
// 注意:toFixed会返回一个字符串
|
||||
return num.toFixed(2);
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理数字输入框的change事件,确保格式正确
|
||||
* @param {string} fieldName - 表单字段名
|
||||
*/
|
||||
handleNumberInput(fieldName) {
|
||||
this.formData[fieldName] = this.formatToTwoDecimalPlaces(this.formData[fieldName]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -232,8 +232,9 @@ export default {
|
|||
<style scoped lang="scss">
|
||||
.tool-container {
|
||||
height: calc(100vh - 84px);
|
||||
overflow: hidden;
|
||||
overflow: auto;
|
||||
background: linear-gradient(180deg, #F1F6FF 20%, #E5EFFF 100%);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.back-container {
|
||||
|
|
|
|||
|
|
@ -132,12 +132,16 @@ export default {
|
|||
this.showSaveAnimation = true
|
||||
|
||||
try {
|
||||
await this.$nextTick();
|
||||
// 1. 校验所有子组件表单
|
||||
const [contractData, completionBidData, otherData] = await Promise.all([
|
||||
this.$refs.contractInfo.validate(),
|
||||
this.$refs.completionAndBidInfo.validate(),
|
||||
this.$refs.otherInfo.validate()
|
||||
])
|
||||
console.log('contractData',contractData)
|
||||
console.log('completionBidData',completionBidData)
|
||||
console.log('otherData',otherData)
|
||||
|
||||
// 3. 初始化提交数据
|
||||
const formData = {
|
||||
|
|
@ -150,6 +154,9 @@ export default {
|
|||
delFiles: [] // 统一存储所有删除文件路径
|
||||
}
|
||||
|
||||
console.log('formData',formData)
|
||||
|
||||
|
||||
// 4. 处理合同附件
|
||||
if (contractData.fileList && contractData.fileList.length) {
|
||||
const contractFiles = contractData.fileList.map(file =>
|
||||
|
|
@ -198,8 +205,10 @@ export default {
|
|||
|
||||
// 9. 调用接口
|
||||
if (this.type === 'add') {
|
||||
|
||||
await addPerformance(formData)
|
||||
} else {
|
||||
console.log('编辑后的数据',formData)
|
||||
await updatePerformance(formData)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -169,7 +169,8 @@ export default {
|
|||
: [];
|
||||
|
||||
this.formData = {
|
||||
...(data || {}),
|
||||
startTime:data.startTime,
|
||||
completionTime:data.completionTime,
|
||||
completionReportFileList: completionFiles,
|
||||
bidNoticeFileList: bidFiles,
|
||||
delFileList: []
|
||||
|
|
@ -294,7 +295,7 @@ export default {
|
|||
new Date(this.formData.startTime) > new Date(this.formData.completionTime)) {
|
||||
reject(new Error('开工时间不能晚于竣工时间'))
|
||||
} else {
|
||||
resolve(this.formData)
|
||||
resolve(this.$refs.completionForm.model)
|
||||
}
|
||||
} else {
|
||||
reject(new Error('竣工报告与中标通知书信息填写不完整'))
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
class="form-control"
|
||||
show-word-limit
|
||||
maxlength="32"
|
||||
@input="handleInputTest"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -79,7 +80,7 @@
|
|||
placeholder="请输入建设地点"
|
||||
class="form-control"
|
||||
show-word-limit
|
||||
maxlength="100"
|
||||
maxlength="32"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -91,7 +92,7 @@
|
|||
placeholder="请输入建设单位"
|
||||
class="form-control"
|
||||
show-word-limit
|
||||
maxlength="100"
|
||||
maxlength="32"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -184,7 +185,25 @@ export default {
|
|||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// 使用 $nextTick 确保 el-form 已经完全初始化
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.contractForm) {
|
||||
console.log('el-form 内部的 model 对象:', this.$refs.contractForm.model);
|
||||
console.log('el-form 的 model 是否与组件的 formData 是同一个对象?', this.$refs.contractForm.model === this.formData);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
handleInputTest() {
|
||||
// 在输入时立即打印 formData 的值
|
||||
console.log('formData.proName 在输入时的值:', this.formData.proName);
|
||||
console.log('完整的 formData 对象:', this.formData);
|
||||
},
|
||||
|
||||
setFormData(data) {
|
||||
// 回显文件:不手动生成uid,仅传递基础字段
|
||||
const contractFiles = Array.isArray(data.fileList)
|
||||
|
|
@ -200,6 +219,12 @@ export default {
|
|||
|
||||
this.formData = {
|
||||
...(data || {}),
|
||||
proName:data.proName,
|
||||
contractSigningTime:data.contractSigningTime,
|
||||
contractAmount: data.contractAmount,
|
||||
constructionSite: data.constructionSite,
|
||||
constructionUnit: data.constructionUnit,
|
||||
constructionPhone: data.constructionPhone,
|
||||
fileList: contractFiles,
|
||||
delFileList: []
|
||||
}
|
||||
|
|
@ -296,6 +321,7 @@ export default {
|
|||
|
||||
this.$refs.contractForm.validate((valid) => {
|
||||
if (valid) {
|
||||
console.log('validate',this.formData)
|
||||
resolve(this.formData)
|
||||
} else {
|
||||
reject(new Error('合同信息填写不完整'))
|
||||
|
|
@ -308,17 +334,16 @@ export default {
|
|||
if (this.$refs.contractForm) {
|
||||
this.$refs.contractForm.resetFields()
|
||||
}
|
||||
this.formData = {
|
||||
fileList: [],
|
||||
proName: '',
|
||||
contractSigningTime: '',
|
||||
contractAmount: '',
|
||||
constructionSite: '',
|
||||
constructionUnit: '',
|
||||
constructionPhone: '',
|
||||
delFileList: []
|
||||
}
|
||||
this.isReplacingFile = false
|
||||
this.formData.proName = '';
|
||||
this.formData.contractSigningTime = '';
|
||||
this.formData.contractAmount = '';
|
||||
this.formData.constructionSite = '';
|
||||
this.formData.constructionUnit = '';
|
||||
this.formData.constructionPhone = '';
|
||||
this.formData.fileList = [];
|
||||
this.formData.delFileList = [];
|
||||
|
||||
this.isReplacingFile = false;
|
||||
},
|
||||
|
||||
addOcrRule() {
|
||||
|
|
|
|||
|
|
@ -172,7 +172,10 @@ export default {
|
|||
: [];
|
||||
|
||||
this.formData = {
|
||||
...data,
|
||||
projectManager:data.projectManager,
|
||||
proType:data.proType,
|
||||
voltageLevel:data.voltageLevel,
|
||||
projectOverview:data.projectOverview,
|
||||
performanceFileList: teamFiles,
|
||||
delFileList: []
|
||||
};
|
||||
|
|
|
|||
|
|
@ -248,11 +248,11 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 样式与财务库保持一致,适配组件布局 */
|
||||
.tool-container {
|
||||
height: calc(100vh - 84px);
|
||||
overflow: hidden;
|
||||
overflow: auto;
|
||||
background: linear-gradient(180deg, #F1F6FF 20%, #E5EFFF 100%);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.back-container {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@
|
|||
v-model="formData.certificateName"
|
||||
placeholder="文件上传后自动提取"
|
||||
class="form-control"
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
maxlength="32"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
||||
|
|
@ -38,6 +39,7 @@
|
|||
v-model="formData.certificateCode"
|
||||
placeholder="文件上传后自动提取"
|
||||
class="form-control"
|
||||
show-word-limit
|
||||
maxlength="32"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
|
@ -70,7 +72,8 @@
|
|||
v-model="formData.certificateInstitution"
|
||||
placeholder="文件上传后自动提取"
|
||||
class="form-control"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
maxlength="32"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
||||
|
|
@ -143,7 +146,23 @@ export default {
|
|||
{ required: true, message: '请选择发证日期', trigger: 'change' }
|
||||
],
|
||||
certificateEndDate: [
|
||||
{ required: true, message: '请选择有效截止日期', trigger: 'change' }
|
||||
{ required: true, message: '请选择有效截止日期', trigger: 'change' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (this.formData.certificateDate && value) {
|
||||
const startDate = new Date(this.formData.certificateDate);
|
||||
const endDate = new Date(value);
|
||||
if (startDate > endDate) {
|
||||
callback(new Error('发证日期不能晚于证书有效截止日期'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
callback(); // 若发证日期未选,暂不校验
|
||||
}
|
||||
},
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
qualificationType: [
|
||||
{ required: true, message: '请选择资质类型', trigger: 'change' }
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ export default {
|
|||
enterpriseId: decryptWithSM4(this.$route.query.enterpriseId) || '0',
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
enterpriseId: decryptWithSM4(this.$route.query.enterpriseId) || '0',
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
certificateName: '',
|
||||
|
|
@ -664,31 +665,38 @@ export default {
|
|||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
justify-content: flex-end; /* 关键改动:右对齐 */
|
||||
padding: 20px;
|
||||
margin-top: 20px;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
border-radius: 8px;
|
||||
flex-shrink: 0; /* 关键改动:防止分页栏被压缩 */
|
||||
|
||||
// 以下是从人员库组件复制过来的详细样式
|
||||
.el-pagination {
|
||||
.el-pagination__total {
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-pagination__sizes .el-select .el-input__inner {
|
||||
border-color: #dcdfe6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.el-pager li {
|
||||
border-radius: 4px;
|
||||
margin: 0 2px;
|
||||
|
||||
&.active {
|
||||
background: #409EFF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #409EFF;
|
||||
}
|
||||
&:hover { color: #409EFF; }
|
||||
}
|
||||
.btn-prev, .btn-next {
|
||||
border-radius: 4px;
|
||||
margin: 0 2px;
|
||||
&:hover { color: #409EFF; }
|
||||
}
|
||||
.el-pagination__jump .el-input__inner {
|
||||
border-color: #dcdfe6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
style="color: #DB3E29;" @click="handleDelete(data)">
|
||||
删除
|
||||
</el-button>
|
||||
|
||||
|
||||
</template>
|
||||
</TableModel>
|
||||
</div>
|
||||
|
|
@ -46,12 +46,12 @@
|
|||
<ToolForm ref="toolForm" v-if="isflag" :isAdd="isAdd" :rowData="row" @handleQuery="handleQuery" :title="title"
|
||||
@closeDialog="closeDialog" :width="600" />
|
||||
<!-- 批量导入弹窗 -->
|
||||
<ImportExcelDialog
|
||||
:visible.sync="importExcelDialogVisible"
|
||||
ref="importExcelDialog"
|
||||
<ImportExcelDialog
|
||||
:visible.sync="importExcelDialogVisible"
|
||||
ref="importExcelDialog"
|
||||
title="工器具导入"
|
||||
:upload-url="importExcelDialogUploadUrl"
|
||||
@upload-success="handleImportSuccess"
|
||||
:upload-url="importExcelDialogUploadUrl"
|
||||
@upload-success="handleImportSuccess"
|
||||
@close="handleImportClose"
|
||||
:maxFileTips="maxFileTips"
|
||||
:params = "params"
|
||||
|
|
@ -194,11 +194,13 @@ export default {
|
|||
</script>
|
||||
<style scoped lang="scss">
|
||||
.tool-container {
|
||||
height: calc(100vh - 84px);
|
||||
overflow: hidden;
|
||||
background: linear-gradient(180deg, #F1F6FF 20%, #E5EFFF 100%);
|
||||
height: calc(100vh - 84px);
|
||||
overflow: auto;
|
||||
background: linear-gradient(180deg, #F1F6FF 20%, #E5EFFF 100%);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
|
||||
.back-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
|
|
|||
|
|
@ -41,22 +41,28 @@
|
|||
:type="type"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-col :span="12" class="form-pane">
|
||||
<el-row :gutter="24" class="content-row">
|
||||
<el-col :span="24" class="form-pane">
|
||||
<ProjectFile
|
||||
ref="projectFileRef"
|
||||
title="项目文件"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-col :span="12" class="form-pane">
|
||||
<el-row :gutter="24" class="content-row">
|
||||
<el-col :span="24" class="form-pane">
|
||||
<SectionFile
|
||||
ref="sectionFileRef"
|
||||
title="标段/标包文件"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-col :span="24" class="form-pane">
|
||||
<el-row :gutter="24" class="content-row">
|
||||
<el-col :span="8" class="form-pane">
|
||||
<AnalysisLabel
|
||||
ref="analysisLabelRef"
|
||||
title="解析标签组"
|
||||
|
|
@ -89,7 +95,6 @@ export default {
|
|||
AnalysisLabel
|
||||
},
|
||||
props: {
|
||||
// 仅保留必要的props,移除type和rowData(从路由获取)
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
|
|
@ -101,8 +106,8 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
type: 'add', // 默认为新增,将从路由参数覆盖
|
||||
templateId: null, // 从路由参数解析的模板ID
|
||||
type: 'add',
|
||||
templateId: null,
|
||||
showUploadAnimation: false,
|
||||
showSaveAnimation: false,
|
||||
uploadQueue: 0,
|
||||
|
|
@ -110,33 +115,11 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
// 返回列表页
|
||||
handleBack() {
|
||||
const obj = { path: "/templateInfo/index" };
|
||||
this.$tab.closeOpenPage(obj);
|
||||
},
|
||||
|
||||
// 处理文件数据,提取fileRes中的属性到顶层
|
||||
processFile(file, source) {
|
||||
const baseProps = {
|
||||
compositionName: file.compositionName,
|
||||
businessType: file.businessType,
|
||||
compositionType: file.compositionType,
|
||||
compositionFileType: file.compositionFileType,
|
||||
source: source,
|
||||
fileName: file.response?.fileRes?.fileName || file.name || '',
|
||||
filePath: file.response?.fileRes?.filePath || file.filePath || '',
|
||||
fileSize: file.response?.fileRes?.fileSize || file.size || 0,
|
||||
fileType: file.response?.fileRes?.fileType || '',
|
||||
sourceFileName: file.response?.fileRes?.sourceFileName || file.name || '',
|
||||
suffixName: file.response?.fileRes?.suffixName || '',
|
||||
percentage: file.percentage || 0,
|
||||
status: file.status || ''
|
||||
};
|
||||
delete baseProps.response;
|
||||
return baseProps;
|
||||
},
|
||||
|
||||
// 保存模板信息
|
||||
async handleSave() {
|
||||
if (this.showSaveAnimation) return;
|
||||
|
|
@ -151,60 +134,87 @@ export default {
|
|||
this.$refs.analysisLabelRef.validate()
|
||||
]);
|
||||
|
||||
console.log("project",projectFileData)
|
||||
console.log("section",sectionFileData)
|
||||
|
||||
|
||||
|
||||
|
||||
// 2. 处理文件列表
|
||||
const projectFiles = projectFileData.flatMap(tab =>
|
||||
tab.fileList.map(file => this.processFile(file, 'project'))
|
||||
);
|
||||
const sectionFiles = sectionFileData.flatMap(tab =>
|
||||
tab.fileList.map(file => this.processFile(file, 'section'))
|
||||
);
|
||||
const allFiles = [...projectFiles, ...sectionFiles];
|
||||
|
||||
if (allFiles.length === 0) {
|
||||
throw new Error('请至少上传一个文件');
|
||||
}
|
||||
|
||||
// 3. 处理删除的文件路径
|
||||
const processDelFiles = (delFileList) => {
|
||||
return delFileList.map(path => path.includes('mainDatabase/') ? path : path);
|
||||
};
|
||||
|
||||
// 4. 合并表单数据
|
||||
// 2. 初始化提交数据
|
||||
const formData = {
|
||||
...basicData,
|
||||
...analysisLabelData,
|
||||
templateId: this.type === 'edit' ? this.templateId : null,
|
||||
useState: '0',
|
||||
publishedStatus: '1',
|
||||
files: allFiles,
|
||||
delFiles: [
|
||||
...processDelFiles(projectFileData.flatMap(item => item.delFileList || [])),
|
||||
...processDelFiles(sectionFileData.flatMap(item => item.delFileList || []))
|
||||
]
|
||||
files: [], // 统一存储所有待上传/已上传的文件
|
||||
delFiles: [] // 统一存储所有需要删除的文件路径
|
||||
};
|
||||
console.log('666',formData)
|
||||
|
||||
// --- 新增逻辑:处理文件和删除列表 ---
|
||||
|
||||
// 3. 处理项目文件 (ProjectFile)
|
||||
projectFileData.forEach(tab => {
|
||||
// 3.1 处理上传的文件,为每个文件添加 compositionType
|
||||
if (tab.fileList && tab.fileList.length > 0) {
|
||||
const processedFiles = tab.fileList.map(file => {
|
||||
// 提取 fileRes 对象
|
||||
const fileRes = file.response?.fileRes || {};
|
||||
// 返回一个合并后的新对象,确保 compositionType 被正确添加
|
||||
return {
|
||||
...fileRes,
|
||||
businessType: 'project_file',
|
||||
compositionName: file.compositionName,
|
||||
compositionFileType: file.compositionFileType,
|
||||
compositionType: tab.compositionType, // <-- 核心:添加 Tab 的 compositionType
|
||||
};
|
||||
}).filter(Boolean); // 过滤掉可能的无效数据
|
||||
|
||||
formData.files.push(...processedFiles);
|
||||
}
|
||||
|
||||
// 3.2 处理删除的文件路径
|
||||
if (tab.delFileList && tab.delFileList.length > 0) {
|
||||
formData.delFiles.push(...tab.delFileList);
|
||||
}
|
||||
});
|
||||
|
||||
// 4. 处理标段/标包文件 (SectionFile)
|
||||
sectionFileData.forEach(tab => {
|
||||
// 4.1 处理上传的文件,为每个文件添加 compositionType
|
||||
if (tab.fileList && tab.fileList.length > 0) {
|
||||
const processedFiles = tab.fileList.map(file => {
|
||||
const fileRes = file.response?.fileRes || {};
|
||||
return {
|
||||
...fileRes,
|
||||
businessType: 'section_file',
|
||||
compositionName: file.compositionName,
|
||||
compositionFileType: file.compositionFileType,
|
||||
compositionType: tab.compositionType, // <-- 核心:添加 Tab 的 compositionType
|
||||
};
|
||||
}).filter(Boolean);
|
||||
console.log('123123123',processedFiles)
|
||||
formData.files.push(...processedFiles);
|
||||
}
|
||||
|
||||
// 4.2 处理删除的文件路径
|
||||
if (tab.delFileList && tab.delFileList.length > 0) {
|
||||
formData.delFiles.push(...tab.delFileList);
|
||||
}
|
||||
});
|
||||
|
||||
// --- 新增逻辑结束 ---
|
||||
|
||||
// 5. 校验模板名称唯一性(仅编辑时)
|
||||
if (this.type === 'edit') {
|
||||
const uniqueRes = await checkTemplateNameUnique({
|
||||
templateName: formData.templateName,
|
||||
templateId: formData.templateId
|
||||
});
|
||||
if (uniqueRes.data > 0) {
|
||||
throw new Error('同一行业下模板名称已存在,请更换');
|
||||
}
|
||||
}
|
||||
// if (this.type === 'edit') {
|
||||
// const uniqueRes = await checkTemplateNameUnique({
|
||||
// templateName: formData.templateName,
|
||||
// templateId: formData.templateId
|
||||
// });
|
||||
// if (uniqueRes.data > 0) {
|
||||
// throw new Error('同一行业下模板名称已存在,请更换');
|
||||
// }
|
||||
// }
|
||||
|
||||
// 6. 调用接口保存
|
||||
if (this.type === 'add') {
|
||||
await addTemplateInfo(formData);
|
||||
} else {
|
||||
console.log('12345678',formData)
|
||||
await updateTemplateInfo(formData);
|
||||
}
|
||||
|
||||
|
|
@ -240,10 +250,12 @@ export default {
|
|||
const res = await getTemplateInfoDetail({ templateId: this.templateId });
|
||||
const detail = res.data || {};
|
||||
|
||||
console.log('111',detail)
|
||||
console.log('detail',detail)
|
||||
|
||||
// 向子组件传递数据
|
||||
this.$refs.basicInfoRef.setFormData(detail);
|
||||
// 注意:这里假设 detail.projectFiles 和 detail.sectionFiles 的结构
|
||||
// 与子组件 setFormData 期望的结构一致。
|
||||
this.$refs.projectFileRef.setFormData(detail.projectFiles || []);
|
||||
this.$refs.sectionFileRef.setFormData(detail.sectionFiles || []);
|
||||
this.$refs.analysisLabelRef.setFormData(detail);
|
||||
|
|
@ -258,28 +270,25 @@ export default {
|
|||
this.$bus.$off('endUpload', this.handleEndUpload);
|
||||
this.$bus.$on('endUpload', this.handleEndUpload);
|
||||
|
||||
// 从路由参数中解析type和templateId(核心逻辑)
|
||||
// 从路由参数中解析type和templateId
|
||||
const { type: encryptedType, templateId: encryptedTemplateId } = this.$route.query;
|
||||
|
||||
// 解析并验证type
|
||||
if (encryptedType) {
|
||||
try {
|
||||
const decryptedType = decryptWithSM4(encryptedType);
|
||||
// 确保type只能是add或edit,非法值默认add
|
||||
this.type = ['add', 'edit'].includes(decryptedType) ? decryptedType : 'add';
|
||||
} catch (e) {
|
||||
console.error('解析type失败:', e);
|
||||
this.type = 'add'; // 解析失败默认新增
|
||||
this.type = 'add';
|
||||
}
|
||||
}
|
||||
|
||||
// 解析templateId
|
||||
if (encryptedTemplateId) {
|
||||
try {
|
||||
this.templateId = decryptWithSM4(encryptedTemplateId);
|
||||
} catch (e) {
|
||||
console.error('解析templateId失败:', e);
|
||||
this.templateId = null; // 解析失败置空
|
||||
this.templateId = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -297,6 +306,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 样式部分保持不变 */
|
||||
.app-container {
|
||||
padding: 24px;
|
||||
background: linear-gradient(180deg, #F1F6FF 20%, #E5EFFF 100%);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@
|
|||
label-position="top"
|
||||
class="label-form"
|
||||
>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="解析标签组" prop="analysisLabelId">
|
||||
<el-select
|
||||
v-model="formData.analysisLabelId"
|
||||
|
|
@ -30,6 +33,8 @@
|
|||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
label-position="top"
|
||||
class="basic-form"
|
||||
>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="模板名称" prop="templateName">
|
||||
<el-input
|
||||
v-model="formData.templateName"
|
||||
|
|
@ -20,7 +22,9 @@
|
|||
maxlength="128"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="行业类型" prop="industryType">
|
||||
<el-select
|
||||
v-model="formData.industryType"
|
||||
|
|
@ -35,7 +39,11 @@
|
|||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="描述" prop="templateDesc">
|
||||
<el-input
|
||||
v-model="formData.templateDesc"
|
||||
|
|
@ -45,6 +53,8 @@
|
|||
maxlength="500"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -16,64 +16,77 @@
|
|||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 核心修改:添加 @tab-click 事件监听 -->
|
||||
<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="'文件 ' + (index + 1)"
|
||||
:label="tab.formData.fileName || '文件 ' + (index + 1)"
|
||||
:name="index.toString()"
|
||||
closable
|
||||
>
|
||||
<el-form
|
||||
:model="tab.formData"
|
||||
:rules="rules"
|
||||
:ref="'projectFileForm_' + index"
|
||||
:ref="`projectFileForm_${index}`"
|
||||
label-width="120px"
|
||||
label-position="top"
|
||||
class="file-form"
|
||||
>
|
||||
<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-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-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 :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-form-item label="文件" prop="fileList">
|
||||
<UploadFile
|
||||
:fileList="formatFileList(tab.formData.fileList, index)"
|
||||
:fileUploadRule="fileUploadRule"
|
||||
@file-change="(files, type) => handleFileChange(files, index)"
|
||||
@del-file="(file) => handleDelFile(file, index)"
|
||||
:uploadType="uploadType"
|
||||
:maxFileTips="maxFileTips"
|
||||
type="project_file"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="文件" prop="fileList">
|
||||
<!-- 直接绑定 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="project_file"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
|
@ -94,6 +107,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
tabFiles: [],
|
||||
uploadType: 'doc、docx、pdf、xls、xlsx、wps',
|
||||
maxFileTips: '50MB',
|
||||
fileUploadRule: { fileUploadType: 'project_file', suffix: 'template' },
|
||||
|
|
@ -101,10 +115,10 @@ export default {
|
|||
fileTabs: [
|
||||
{
|
||||
formData: {
|
||||
compositionType: '1', // 项目文件类型标识
|
||||
compositionType: '1',
|
||||
fileName: '',
|
||||
compositionFileType: '',
|
||||
fileList: [], // 存储当前页签的文件列表
|
||||
fileList: [],
|
||||
delFileList: []
|
||||
}
|
||||
}
|
||||
|
|
@ -159,80 +173,62 @@ export default {
|
|||
return
|
||||
}
|
||||
this.fileTabs.splice(index, 1)
|
||||
this.activeTabIndex = '0'
|
||||
},
|
||||
|
||||
// 格式化文件列表,适配UploadFile组件
|
||||
formatFileList(fileList, index) {
|
||||
return (fileList || []).map((file, fileIndex) => {
|
||||
const fileExt = file.fileName
|
||||
? file.fileName.split('.').pop().toLowerCase()
|
||||
: (file.name || '').split('.').pop().toLowerCase() || '';
|
||||
|
||||
return {
|
||||
...file,
|
||||
uid: file.uid || file.filePath || `${Date.now()}-${index}-${fileIndex}`,
|
||||
name: file.name || file.fileName || `未命名文件.${fileExt}`,
|
||||
status: file.status || 'success',
|
||||
percentage: file.percentage || 100,
|
||||
url: file.lsFilePath || file.url,
|
||||
lsFilePath: file.lsFilePath || file.url,
|
||||
filePath: file.filePath || '',
|
||||
fileType: file.fileType || '2'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 处理文件上传/变更
|
||||
handleFileChange(files, index) {
|
||||
const currentType = this.fileTabs[index].formData.compositionFileType
|
||||
const compositionName = this.fileTabs[index].formData.fileName // 取当前fileName
|
||||
this.fileTabs[index].formData.fileList = files.map(file => ({
|
||||
...file,
|
||||
compositionName: compositionName, // 绑定fileName
|
||||
businessType: 'project_file',
|
||||
compositionType: '1',
|
||||
compositionFileType: currentType,
|
||||
filePath: file.response?.fileRes?.uploadPath || file.filePath || '',
|
||||
lsFilePath: file.response?.fileRes?.url || file.lsFilePath || file.url
|
||||
}))
|
||||
},
|
||||
|
||||
// 处理文件类型变更
|
||||
handleTypeChange(index) {
|
||||
const currentType = this.fileTabs[index].formData.compositionFileType
|
||||
const compositionName = this.fileTabs[index].formData.fileName // 取当前fileName
|
||||
this.fileTabs[index].formData.fileList = this.fileTabs[index].formData.fileList.map(file => ({
|
||||
...file,
|
||||
compositionFileType: currentType,
|
||||
compositionName: compositionName // 同步fileName
|
||||
}))
|
||||
},
|
||||
|
||||
// 新增:监听fileName变化,同步更新当前页签所有文件的compositionName
|
||||
handleFileNameChange(index) {
|
||||
const currentFileName = this.fileTabs[index].formData.fileName;
|
||||
// 遍历当前页签的所有文件,更新compositionName
|
||||
this.fileTabs[index].formData.fileList = this.fileTabs[index].formData.fileList.map(file => ({
|
||||
...file,
|
||||
compositionName: currentFileName // 用最新的fileName赋值
|
||||
}));
|
||||
},
|
||||
|
||||
// 处理文件删除
|
||||
handleDelFile(file, index) {
|
||||
const filePath = file.filePath || file.response?.fileRes?.uploadPath || ''
|
||||
if (filePath && !this.fileTabs[index].formData.delFileList.includes(filePath)) {
|
||||
this.fileTabs[index].formData.delFileList.push(filePath)
|
||||
if (this.activeTabIndex === index.toString()) {
|
||||
this.activeTabIndex = '0'
|
||||
}
|
||||
this.fileTabs[index].formData.fileList = this.fileTabs[index].formData.fileList.filter(
|
||||
item => item.filePath !== filePath
|
||||
)
|
||||
},
|
||||
|
||||
// 回显数据
|
||||
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 = 'project_file';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleDelFile(file, index) {
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
// === 核心修改:新增的 tab 切换处理方法 ===
|
||||
handleTabChange(tab, event) {
|
||||
// tab.index 是当前被点击的 tab 的索引
|
||||
const index = tab.index;
|
||||
console.log(`切换到了第 ${index + 1} 个 tab`);
|
||||
this.setFormData(this.tabFiles)
|
||||
},
|
||||
|
||||
setFormData(projectFiles) {
|
||||
this.fileTabs = []
|
||||
this.tabFiles = projectFiles
|
||||
// 1. 清空旧的 tabs,准备接收新数据
|
||||
this.fileTabs = [];
|
||||
|
||||
if (!projectFiles || projectFiles.length === 0) {
|
||||
this.fileTabs.push({
|
||||
|
|
@ -243,40 +239,44 @@ export default {
|
|||
fileList: [],
|
||||
delFileList: []
|
||||
}
|
||||
})
|
||||
this.activeTabIndex = '0'
|
||||
return
|
||||
});
|
||||
this.activeTabIndex = '0';
|
||||
return;
|
||||
}
|
||||
|
||||
projectFiles.forEach((file, index) => {
|
||||
const tabFileName = file.compositionName || file.fileName || '';
|
||||
// 2. 根据传入的数据,创建新的 tabs
|
||||
projectFiles.forEach((file) => {
|
||||
const formattedFile = {
|
||||
name: file.fileName || file.name,
|
||||
size: file.fileSize || file.size,
|
||||
status: 'success',
|
||||
percentage: 100,
|
||||
filePath: file.filePath,
|
||||
lsFilePath: file.lsFilePath,
|
||||
url: file.lsFilePath,
|
||||
compositionName: file.compositionName || file.fileName || '',
|
||||
compositionFileType: file.compositionFileType || '',
|
||||
compositionType: '1',
|
||||
businessType: 'project_file',
|
||||
response: {
|
||||
fileRes: file
|
||||
}
|
||||
};
|
||||
|
||||
this.fileTabs.push({
|
||||
formData: {
|
||||
compositionType: '1',
|
||||
fileName: tabFileName,
|
||||
compositionFileType: file.compositionFileType || '',
|
||||
fileList: [{
|
||||
...file,
|
||||
businessType: 'project_file',
|
||||
compositionType: '1',
|
||||
lsFilePath: file.lsFilePath,
|
||||
url: file.lsFilePath,
|
||||
filePath: file.filePath,
|
||||
name: file.fileName || file.name,
|
||||
fileName: file.fileName || file.name,
|
||||
status: 'success',
|
||||
percentage: 100,
|
||||
compositionName: tabFileName // 初始化时绑定fileName
|
||||
}],
|
||||
fileName: formattedFile.compositionName,
|
||||
compositionFileType: formattedFile.compositionFileType,
|
||||
fileList: [formattedFile],
|
||||
delFileList: []
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
this.activeTabIndex = '0'
|
||||
this.activeTabIndex = '0';
|
||||
},
|
||||
|
||||
// 表单验证
|
||||
validate() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
|
|
@ -308,6 +308,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 样式部分保持不变 */
|
||||
.file-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,12 @@
|
|||
type="card"
|
||||
class="file-tabs"
|
||||
@tab-remove="handleRemoveTab"
|
||||
@tab-click="handleTabChange"
|
||||
>
|
||||
<el-tab-pane
|
||||
v-for="(tab, index) in fileTabs"
|
||||
:key="index"
|
||||
:label="'文件 ' + (index + 1)"
|
||||
:label="tab.formData.fileName || ('文件 ' + (index + 1))"
|
||||
:name="index.toString()"
|
||||
closable
|
||||
>
|
||||
|
|
@ -37,43 +38,55 @@
|
|||
label-position="top"
|
||||
class="file-form"
|
||||
>
|
||||
<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-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-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 :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-form-item label="文件" prop="fileList">
|
||||
<UploadFile
|
||||
:fileList="formatFileList(tab.formData.fileList, index)"
|
||||
:fileUploadRule="fileUploadRule"
|
||||
@file-change="(files, type) => handleFileChange(files, index)"
|
||||
@del-file="(file) => handleDelFile(file, index)"
|
||||
:uploadType="uploadType"
|
||||
:maxFileTips="maxFileTips"
|
||||
type="section_file"
|
||||
/>
|
||||
</el-form-item>
|
||||
<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>
|
||||
|
|
@ -94,6 +107,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
tabFiles: [],
|
||||
uploadType: 'doc、docx、pdf、xls、xlsx、wps',
|
||||
maxFileTips: '50MB',
|
||||
fileUploadRule: { fileUploadType: 'section_file', suffix: 'template' },
|
||||
|
|
@ -101,10 +115,10 @@ export default {
|
|||
fileTabs: [
|
||||
{
|
||||
formData: {
|
||||
compositionType: '2', // 标段文件类型标识
|
||||
compositionType: '2',
|
||||
fileName: '',
|
||||
compositionFileType: '',
|
||||
fileList: [], // 存储当前页签的文件列表
|
||||
fileList: [],
|
||||
delFileList: []
|
||||
}
|
||||
}
|
||||
|
|
@ -159,81 +173,60 @@ export default {
|
|||
return
|
||||
}
|
||||
this.fileTabs.splice(index, 1)
|
||||
this.activeTabIndex = '0'
|
||||
},
|
||||
|
||||
// 格式化文件列表,适配UploadFile组件
|
||||
formatFileList(fileList, index) {
|
||||
return (fileList || []).map((file, fileIndex) => {
|
||||
const fileExt = file.fileName
|
||||
? file.fileName.split('.').pop().toLowerCase()
|
||||
: (file.name || '').split('.').pop().toLowerCase() || '';
|
||||
|
||||
return {
|
||||
...file,
|
||||
uid: file.uid || file.filePath || `${Date.now()}-${index}-${fileIndex}`,
|
||||
name: file.name || file.fileName || `未命名文件.${fileExt}`,
|
||||
status: file.status || 'success',
|
||||
percentage: file.percentage || 100,
|
||||
url: file.lsFilePath || file.url,
|
||||
lsFilePath: file.lsFilePath || file.url,
|
||||
filePath: file.filePath || '',
|
||||
fileType: file.fileType || '2'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 处理文件上传/变更
|
||||
handleFileChange(files, index) {
|
||||
|
||||
const currentType = this.fileTabs[index].formData.compositionFileType
|
||||
const compositionName = this.fileTabs[index].formData.fileName // 取当前fileName
|
||||
this.fileTabs[index].formData.fileList = files.map(file => ({
|
||||
...file,
|
||||
businessType: 'section_file',
|
||||
compositionName: compositionName, // 绑定fileName
|
||||
compositionFileType: currentType,
|
||||
compositionType: '2',
|
||||
filePath: file.response?.fileRes?.uploadPath || file.filePath || '',
|
||||
lsFilePath: file.response?.fileRes?.url || file.lsFilePath || file.url
|
||||
}))
|
||||
|
||||
},
|
||||
|
||||
// 处理文件类型变更
|
||||
handleTypeChange(index) {
|
||||
const currentType = this.fileTabs[index].formData.compositionFileType
|
||||
const compositionName = this.fileTabs[index].formData.fileName // 取当前fileName
|
||||
this.fileTabs[index].formData.fileList = this.fileTabs[index].formData.fileList.map(file => ({
|
||||
...file,
|
||||
compositionFileType: currentType,
|
||||
compositionName: compositionName // 同步fileName
|
||||
}))
|
||||
},
|
||||
|
||||
// 新增:监听fileName变化,同步更新当前页签所有文件的compositionName
|
||||
handleFileNameChange(index) {
|
||||
const currentFileName = this.fileTabs[index].formData.fileName;
|
||||
// 遍历当前页签的所有文件,更新compositionName
|
||||
this.fileTabs[index].formData.fileList = this.fileTabs[index].formData.fileList.map(file => ({
|
||||
...file,
|
||||
compositionName: currentFileName // 用最新的fileName赋值
|
||||
}));
|
||||
},
|
||||
|
||||
// 处理文件删除
|
||||
handleDelFile(file, index) {
|
||||
const filePath = file.filePath || file.response?.fileRes?.uploadPath || ''
|
||||
if (filePath && !this.fileTabs[index].formData.delFileList.includes(filePath)) {
|
||||
this.fileTabs[index].formData.delFileList.push(filePath)
|
||||
if (this.activeTabIndex === index.toString()) {
|
||||
this.activeTabIndex = '0'
|
||||
}
|
||||
this.fileTabs[index].formData.fileList = this.fileTabs[index].formData.fileList.filter(
|
||||
item => item.filePath !== filePath
|
||||
)
|
||||
},
|
||||
|
||||
// 回显数据
|
||||
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) {
|
||||
|
|
@ -250,26 +243,31 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
sectionFiles.forEach((file, index) => {
|
||||
const tabFileName = file.compositionName || file.fileName || '';
|
||||
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: tabFileName,
|
||||
compositionFileType: file.compositionFileType || '',
|
||||
fileList: [{
|
||||
...file,
|
||||
businessType: 'section_file',
|
||||
compositionType: '2',
|
||||
lsFilePath: file.lsFilePath,
|
||||
url: file.lsFilePath,
|
||||
filePath: file.filePath,
|
||||
name: file.fileName || file.name,
|
||||
fileName: file.fileName || file.name,
|
||||
status: 'success',
|
||||
percentage: 100,
|
||||
compositionName: tabFileName // 初始化时绑定fileName
|
||||
}],
|
||||
fileName: formattedFile.compositionName,
|
||||
compositionFileType: formattedFile.compositionFileType,
|
||||
fileList: [formattedFile],
|
||||
delFileList: []
|
||||
}
|
||||
})
|
||||
|
|
@ -278,7 +276,6 @@ export default {
|
|||
this.activeTabIndex = '0'
|
||||
},
|
||||
|
||||
// 表单验证
|
||||
validate() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
|
|
@ -310,6 +307,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 样式部分保持不变 */
|
||||
.file-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export const columnsList = [
|
|||
}
|
||||
},
|
||||
{ t_props: 'industryType', t_label: '行业类型' },
|
||||
{ t_props: 'fileName', t_label: '模板组成' },
|
||||
{ t_props: 'compositionName', t_label: '模板组成' },
|
||||
{ t_props: 'currentVersion', t_label: '当前版本' },
|
||||
{ t_props: 'useState', t_label: '状态', t_slot: 'useState' },
|
||||
{ t_props: 'updateTime', t_label: '更新时间', format: 'yyyy/MM/dd HH:mm' },
|
||||
|
|
|
|||
|
|
@ -141,22 +141,13 @@ export default {
|
|||
processedListTemplateInfo(params) {
|
||||
return listTemplateInfo(params).then(res => {
|
||||
if (res.code === 200 && res.rows && res.rows.length > 0) {
|
||||
console.log('123',res)
|
||||
// 无需额外处理,直接使用后端返回的rows
|
||||
// 若需要去重(如有重复模板ID),仅保留去重逻辑:
|
||||
const groupMap = {};
|
||||
res.rows.forEach(item => {
|
||||
const key = item.templateId;
|
||||
if (!groupMap[key]) {
|
||||
groupMap[key] = { ...item, compositionName: '', compositionList: [] };
|
||||
}
|
||||
if (item.compositionName) {
|
||||
// 处理fileName:去掉后缀
|
||||
const fileNameWithoutExt = item.compositionName.split('.').slice(0, -1).join('.');
|
||||
// 存入compositionList
|
||||
groupMap[key].compositionList.push({ compositionName: fileNameWithoutExt });
|
||||
// 合并无后缀的文件名,用"、"分隔
|
||||
groupMap[key].compositionName = groupMap[key].compositionList
|
||||
.map(comp => comp.compositionName)
|
||||
.join('、');
|
||||
groupMap[key] = item; // 直接赋值,保留后端的compositionName
|
||||
}
|
||||
});
|
||||
res.rows = Object.values(groupMap);
|
||||
|
|
|
|||
Loading…
Reference in New Issue