smart-bid-web/src/views/enterpriseLibrary/finance/components/child/FinanceReportUpload.vue

435 lines
12 KiB
Vue
Raw Normal View History

2025-10-24 18:33:58 +08:00
<template>
<div>
<div class="basic-info-title">
<img src="@/assets/enterpriseLibrary/basic-info.png" alt="财务报告">
<span>财务报告</span>
</div>
<el-form
:model="formData"
:rules="rules"
ref="financeReportForm"
label-width="110px"
label-position="top"
>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="财务报告附件" prop="fileList">
<UploadFile
:fileList="formData.fileList"
:fileUploadRule="financeReportUploadRule"
@file-change="(files, type) => handleFileChange(files, type)"
@del-file="handleDelFile"
:uploadType="uploadType"
:maxFileTips="maxFileTips"
@docx-content="handleDocxContent"
:limitUploadNum="1"
type="finance_report"
:show-file-list="true"
2025-11-21 14:59:16 +08:00
@upload-fail="handleUploadFail"
/>
</el-form-item>
</el-col>
</el-row>
2025-10-24 18:33:58 +08:00
<el-row :gutter="24" class="info-row">
<el-col :span="8" class="info-col">
<el-form-item label="文件名" prop="fileName">
<el-input
v-model="formData.fileName"
placeholder="文件上传后自动提取"
class="form-control"
2025-11-21 14:59:16 +08:00
show-word-limit
2025-11-26 17:56:45 +08:00
maxlength="64"
></el-input>
</el-form-item>
</el-col>
<el-col :span="8" class="info-col">
<el-form-item label="报告年份" prop="reportYear">
<el-date-picker
v-model="formData.reportYear"
type="year"
placeholder="选择年份"
class="form-control"
value-format="yyyy"
:disabled-date="disabledFutureYear"
></el-date-picker>
</el-form-item>
</el-col>
</el-row>
2025-10-24 18:33:58 +08:00
</el-form>
</div>
</template>
<script>
import UploadFile from '@/views/common/UploadFile.vue'
export default {
name: 'FinanceReportUpload',
components: { UploadFile },
dicts: ['identification_tag'],
data() {
return {
uploadType: 'docx',
2025-10-24 18:33:58 +08:00
maxFileTips: '100MB',
ocrRuleList: ['finance_report'],
2025-10-24 18:33:58 +08:00
fileUploadList: [],
ocrResultParams: {
"报告年份": "reportYear"
},
formData: {
fileList: [],
2025-10-24 18:33:58 +08:00
fileName: '',
reportYear: '',
delFileList: []
2025-10-24 18:33:58 +08:00
},
rules: {
fileList: [
2025-11-26 17:56:45 +08:00
{ required: true, message: '请上传财务报告附件', trigger: 'change' },
{ type: 'string', max: 64, message: '长度不能超过64个字符', trigger: 'blur' },
2025-10-24 18:33:58 +08:00
],
fileName: [
{ required: true, message: '文件名需等待文件上传后自动提取', trigger: 'blur' }
2025-10-24 18:33:58 +08:00
],
reportYear: [
{ required: true, message: '请选择报告年份', trigger: 'change' }
2025-10-24 18:33:58 +08:00
]
},
isReplacingFile: false // 新增:标记是否正在替换文件
2025-10-24 18:33:58 +08:00
}
},
computed: {
financeReportUploadRule() {
return this.fileUploadList[0]
}
},
watch: {
'dict.type.identification_tag': {
handler(newVal) {
if (newVal && newVal.length > 0) {
this.addOcrRule()
}
},
immediate: true
}
},
methods: {
2025-11-21 14:59:16 +08:00
handleUploadFail() {
this.formData.fileName = '';
this.formData.reportYear = '';
},
handleDocxContent(text) {
// 模拟OCR返回格式将docx文本包装成现有逻辑可处理的结构
const mockOcrResult = {
status_code: 200,
data: {
chat_res: this.extractInfoFromDocx(text) // 从文本中提取关键信息
}
};
// 复用OCR结果处理逻辑填充报告年份
this.handleOcrResultWithMock(mockOcrResult);
},
// 从docx文本中提取信息核心根据业务规则匹配关键词
extractInfoFromDocx(text) {
console.log("text", text);
// 优化正则匹配“年份2026”“年份:2026”“2026年”“2026年度”等格式
const yearMatch = text.match(
/(年份|报告年份|年度)\s*[:]\s*(\d{4})|(\d{4})\s*(年|年度)/
);
console.log("yearMatch", yearMatch);
// 提取匹配到的年份(优先取冒号后的年份,再取数字+年/年度的格式)
const year = yearMatch ? (yearMatch[2] || yearMatch[3]) : '';
return { "报告年份": year };
},
// 复用原OCR结果处理逻辑
handleOcrResultWithMock(ocrResult) {
if (ocrResult.status_code === 200) {
const chat_res = ocrResult.data?.chat_res;
if (chat_res && typeof chat_res === 'object') {
Object.keys(chat_res).forEach(key => {
const formField = this.ocrResultParams[key];
if (formField === 'reportYear' && chat_res[key]) {
const year = chat_res[key].replace(/[^\d]/g, '');
this.formData[formField] = year.length === 4 ? year : '';
}
});
this.$message.success('docx内容解析成功已自动填充报告年份');
this.$refs.financeReportForm.validateField('reportYear');
}
} else {
this.$message.error(`年份提取失败: ${ocrResult.status_msg || '未找到有效年份'}`);
}
},
setFormData(data) {
2025-11-26 17:56:45 +08:00
// 财务报告文件
const financeFiles = Array.isArray(data.fileList)
2025-10-24 18:33:58 +08:00
? data.fileList.filter(file => file && file.businessType === 'finance_report')
.map(file => ({
name: file.name || file.fileName || '未知文件',
filePath: file.filePath,
lsFilePath: file.lsFilePath,
fileType: file.fileType || '2',
businessType: 'finance_report'
}))
: [];
2025-10-24 18:33:58 +08:00
let reportYear = data.reportYear || '';
if (reportYear) {
if (typeof reportYear === 'string') {
reportYear = reportYear.split('-')[0];
}
if (typeof reportYear === 'number') {
reportYear = reportYear.toString();
}
}
2025-10-24 18:33:58 +08:00
this.formData = {
...(data || {}),
fileList: financeFiles,
fileName: financeFiles.length > 0 ? this.getFileName(financeFiles[0]) : '',
delFileList: [],
reportYear: reportYear,
2025-10-24 18:33:58 +08:00
}
},
getFileName(file) {
const fullName = file.name || file.fileName || '未知文件'
const lastDotIndex = fullName.lastIndexOf('.')
return lastDotIndex > 0 ? fullName.substring(0, lastDotIndex) : fullName
},
getFileExt(file) {
if (!file) return ''
const fileName = file.name || file.fileName || ''
const extMatch = fileName.match(/\.([a-zA-Z0-9]+)$/)
return extMatch ? extMatch[1].toLowerCase() : ''
},
2025-10-24 18:33:58 +08:00
handleFileChange(files, type) {
if (type === 'finance_report' && files instanceof Array) {
if (files.length > 0 && files[0].response) {
this.isReplacingFile = false;
// 处理旧文件删除(保持不变)
if (this.formData.fileList.length > 0) {
const oldFile = this.formData.fileList[0];
const delPath = oldFile?.response?.fileRes?.filePath || oldFile?.filePath || null;
if (delPath && !this.formData.delFileList.includes(delPath)) {
this.formData.delFileList.push(delPath);
}
}
const markedFiles = files.map(file => ({
...file,
businessType: 'finance_report'
})).slice(-1);
this.formData.fileList = markedFiles;
// 提取文件名(保持不变)
if (markedFiles.length > 0) {
const originalFileName = this.getFileName(markedFiles[0])
const safeFileName = originalFileName.replace(/--+/g, '-')
this.formData.fileName = safeFileName
this.$refs.financeReportForm.validateField('fileName')
}
//根据文件类型选择解析方式
const firstFile = markedFiles[0];
const fileExt = this.getFileExt(firstFile).toLowerCase(); // 获取文件后缀
if (['doc', 'docx'].includes(fileExt)) {
// doc/docx文件只执行你的自定义解析不调用OCR
} else if (['pdf', 'jpg', 'jpeg', 'png'].includes(fileExt)) {
// pdf/图片执行原OCR逻辑
this.handleOcrResult(markedFiles);
} else {
// 其他格式:提示不支持
this.$message.warning('不支持的文件格式,无法解析年份');
}
} else if (!this.isReplacingFile) {
this.formData.fileList = [];
this.formData.fileName = '';
}
2025-10-24 18:33:58 +08:00
}
},
handleDelFile(file) {
// 标记为替换操作,保留文件列表结构等待新文件
this.isReplacingFile = true;
const delPath = file?.response?.fileRes?.filePath || file?.filePath || null;
if (delPath && !this.formData.delFileList.includes(delPath)) {
this.formData.delFileList.push(delPath);
}
},
2025-10-24 18:33:58 +08:00
handleOcrResult(files) {
if (!files || !Array.isArray(files) || files.length === 0) return
this.$bus.$emit('startUpload', '正在识别报告年份')
2025-10-24 18:33:58 +08:00
try {
const firstFile = files[0]
if (firstFile.response?.ocrResult) {
const ocrResult = firstFile.response.ocrResult
if (ocrResult.status_code === 200) {
2025-11-24 11:06:21 +08:00
const chat_res = ocrResult.data
2025-10-24 18:33:58 +08:00
if (chat_res && typeof chat_res === 'object') {
Object.keys(chat_res).forEach(key => {
const formField = this.ocrResultParams[key]
if (formField === 'reportYear' && chat_res[key]) {
const year = chat_res[key].replace(/[^\d]/g, '')
this.formData[formField] = year.length === 4 ? year : ''
2025-10-24 18:33:58 +08:00
}
})
this.$message.success('OCR识别成功已自动填充报告年份')
this.$refs.financeReportForm.validateField('reportYear')
2025-10-24 18:33:58 +08:00
}
} else {
this.$message.error(`年份识别失败: ${ocrResult.status_msg || '未知错误'}`)
2025-10-24 18:33:58 +08:00
}
}
} catch (error) {
this.$message.error(`处理年份结果失败: ${error.message}`)
2025-10-24 18:33:58 +08:00
} finally {
this.$bus.$emit('endUpload')
}
},
disabledFutureYear(date) {
return date > new Date(new Date().getFullYear(), 11, 31)
2025-10-24 18:33:58 +08:00
},
validate() {
return new Promise((resolve, reject) => {
if (!this.$refs.financeReportForm) {
reject(new Error('表单实例未加载完成'))
return
}
this.$refs.financeReportForm.validate((valid) => {
if (valid) {
resolve(this.formData)
} else {
reject(new Error('财务报告信息填写不完整'))
}
})
})
},
resetForm() {
if (this.$refs.financeReportForm) {
this.$refs.financeReportForm.resetFields()
}
this.formData = {
fileList: [],
fileName: '',
reportYear: '',
delFileList: []
}
this.isReplacingFile = false;
2025-10-24 18:33:58 +08:00
},
addOcrRule() {
this.ocrRuleList.forEach(item => {
this.ocrRule(item)
})
},
ocrRule(type) {
const foundItem = this.dict.type.identification_tag?.find(item => item.value === type)
if (!foundItem) {
this.$message.warning(`未找到${type}的识别规则配置`)
return
}
const item = {
fileUploadType: foundItem.value,
fields_json: foundItem.raw?.remark,
suffix: 'mainDatabase'
}
this.fileUploadList.push(item)
}
}
}
</script>
<style scoped lang="scss">
.basic-info-title {
display: flex;
align-items: center;
margin: 10px 0;
span {
margin: 0 5px;
font-size: 20px;
}
img {
width: 24px;
height: 24px;
object-fit: contain;
}
}
.el-form {
margin-top: 15px;
padding: 0 15px;
}
.form-control {
width: 100%;
}
.el-form-item {
margin-bottom: 20px;
}
.upload-tip {
color: #909399;
font-size: 12px;
margin-top: 5px;
line-height: 1.5;
2025-10-24 18:33:58 +08:00
}
::v-deep .el-form-item__label {
color: #4e5969;
font-weight: 500;
}
::v-deep .el-input.is-readonly .el-input__inner {
background-color: #f5f7fa;
cursor: default;
}
::v-deep .upload-container {
::v-deep .el-upload-dragger {
height: 180px;
transition: border-color 0.3s;
}
::v-deep .el-upload-list__item {
margin-top: 10px;
}
::v-deep .el-upload-list__item-name {
display: inline-block;
max-width: 80%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
2025-10-24 18:33:58 +08:00
</style>