bug修复

This commit is contained in:
LHD_HY 2025-11-21 14:59:16 +08:00
parent f75a8d844a
commit 1c6dcbbd84
22 changed files with 594 additions and 435 deletions

View File

@ -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
})
}

View File

@ -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%;

View File

@ -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)
}

View File

@ -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: {
/**
* 格式化文件列表仅保留财务报告类型的附件解决回显错乱

View File

@ -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) {
// OCRdocx

View File

@ -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>

View File

@ -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 {

View File

@ -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)
}

View File

@ -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('竣工报告与中标通知书信息填写不完整'))

View File

@ -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() {

View File

@ -172,7 +172,10 @@ export default {
: [];
this.formData = {
...data,
projectManager:data.projectManager,
proType:data.proType,
voltageLevel:data.voltageLevel,
projectOverview:data.projectOverview,
performanceFileList: teamFiles,
delFileList: []
};

View File

@ -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 {

View File

@ -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' }

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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: {
// propstyperowData
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);
// typetemplateId
// typetemplateId
const { type: encryptedType, templateId: encryptedTemplateId } = this.$route.query;
// type
if (encryptedType) {
try {
const decryptedType = decryptWithSM4(encryptedType);
// typeaddeditadd
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%);

View File

@ -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>

View File

@ -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>

View File

@ -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
}))
},
// fileNamecompositionName
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%;
}

View File

@ -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
}))
},
// fileNamecompositionName
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%;
}

View File

@ -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' },

View File

@ -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);