smart-bid-web/src/views/enterpriseLibrary/qualification/components/child/QualificationFormChild.vue

427 lines
12 KiB
Vue
Raw Normal View History

<template>
<div class="qualification-form">
<el-form
:model="formData"
:rules="rules"
ref="qualificationForm"
label-width="110px"
label-position="top"
class="form-wrapper"
>
<!-- 资质证书上传 -->
<el-form-item label="资质证书附件" prop="files">
<UploadFile
ref="uploadFileComp"
:fileList="formData.files"
:fileUploadRule="qualificationUploadRule"
@file-change="(files, type) => handleFileChange(files, type)"
@del-file="handleDelFile"
:uploadType="uploadType"
:maxFileTips="maxFileTips"
type="qualification_certificate"
/>
</el-form-item>
<!-- 证书名称 -->
<el-form-item label="证书名称" prop="certificateName">
<el-input
v-model="formData.certificateName"
placeholder="文件上传后自动提取"
class="form-control"
maxlength="50"
></el-input>
</el-form-item>
<!-- 证书编号 -->
<el-form-item label="证书编号" prop="certificateCode">
<el-input
v-model="formData.certificateCode"
placeholder="文件上传后自动提取"
class="form-control"
maxlength="32"
></el-input>
</el-form-item>
<!-- 发证日期 -->
<el-form-item label="发证日期" prop="certificateDate">
<el-date-picker
v-model="formData.certificateDate"
type="date"
placeholder="文件上传后自动提取"
value-format="yyyy-MM-dd"
class="form-control"
/>
</el-form-item>
<!-- 证书有效截止日期 -->
<el-form-item label="证书有效截止日期" prop="certificateEndDate">
<el-date-picker
v-model="formData.certificateEndDate"
type="date"
placeholder="文件上传后自动提取"
value-format="yyyy-MM-dd"
class="form-control"
/>
</el-form-item>
<!-- 发证机构 -->
<el-form-item label="发证机构" prop="certificateInstitution">
<el-input
v-model="formData.certificateInstitution"
placeholder="文件上传后自动提取"
class="form-control"
maxlength="64"
></el-input>
</el-form-item>
<!-- 资质类型 -->
<el-form-item label="资质类型" prop="qualificationType">
<el-select
v-model="formData.qualificationType"
placeholder="请选择资质类型"
clearable
class="form-control"
>
<el-option
v-for="item in qualificationTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-form>
</div>
</template>
<script>
import UploadFile from '@/views/common/UploadFile.vue'
export default {
name: 'QualificationFormChild',
components: { UploadFile },
dicts: ['identification_tag'],
data() {
return {
uploadType: 'docx',
maxFileTips: '100MB',
ocrRuleList: ['qualification_certificate'], // 资质证书OCR识别规则
fileUploadList: [],
// OCR识别结果映射关系
ocrResultParams: {
"证书名称": "certificateName",
"证书编号": "certificateCode",
"发证日期": "certificateDate",
"证书有效截止日期": "certificateEndDate",
"发证机构": "certificateInstitution"
},
formData: {
files: [],
certificateName: '',
certificateCode: '',
certificateDate: '',
certificateEndDate: '',
certificateInstitution: '',
qualificationType: '',
delFileList: []
},
qualificationTypeOptions: [],
rules: {
files: [
{ required: true, message: '请上传资质证书附件', trigger: 'change' }
],
certificateName: [
{ required: true, message: '请输入证书名称', trigger: 'blur' }
],
certificateCode: [
{ required: true, message: '请输入证书编号', trigger: 'blur' }
],
certificateDate: [
{ required: true, message: '请选择发证日期', trigger: 'change' }
],
certificateEndDate: [
{ required: true, message: '请选择有效截止日期', trigger: 'change' }
],
qualificationType: [
{ required: true, message: '请选择资质类型', trigger: 'change' }
]
}
};
},
computed: {
qualificationUploadRule() {
return this.fileUploadList[0]
}
},
watch: {
'dict.type.identification_tag': {
handler(newVal) {
if (newVal && newVal.length > 0) {
this.addOcrRule()
}
},
immediate: true
}
},
methods: {
loadQualificationTypeDict() {
// getDicts 的参数是字典类型编码qualification_type
this.getDicts('qualification_type').then(response => {
this.qualificationTypeOptions = response.data.map(item => ({
label: item.dictLabel,
value: item.dictValue
}))
}).catch(error => {
console.error('加载电压等级字典失败:', error)
})
},
// 接收父组件数据并回显
setFormData(data) {
// 1. 过滤“资质证书类型”的文件,排除其他业务类型文件
const qualificationFiles = Array.isArray(data.fileList)
? data.fileList.filter(file =>
file && file.businessType === 'qualification_certificate' // 严格匹配业务类型
).map(file => ({
// 2. 补充文件预览和显示所需的完整元数据
...file,
// 确保 UploadFile 组件需要的字段存在(参考 UploadFile 组件的 fileList 格式)
uid: file.uid || Date.now() + Math.random().toString(36).substr(2, 9), // 生成唯一ID
name: file.fileName || file.name || '未命名文件', // 文件名(适配后端可能的字段名)
lsFilePath: file.lsFilePath || file.fileUrl || '', // 预览路径(关键:用于文件预览)
filePath: file.filePath || file.uploadPath || '', // 文件存储路径(用于删除)
status: 'success', // 标记为已上传状态,避免组件显示“上传中”
response: {
fileRes: {
fileName: file.fileName || file.name,
filePath: file.filePath || file.uploadPath,
uploadPath: file.filePath || file.uploadPath
}
}
}))
: [];
// 3. 赋值表单数据,确保文件列表格式正确
this.formData = {
...data,
files: qualificationFiles, // 子表单绑定的文件列表字段
delFileList: [] // 清空待删除列表
};
// 4. 触发 UploadFile 组件重新渲染(避免数据更新但视图未同步)
this.$nextTick(() => {
if (this.$refs.uploadFileComp && this.$refs.uploadFileComp.updatePreview) {
this.$refs.uploadFileComp.updatePreview(qualificationFiles); // 若 UploadFile 有预览更新方法,主动调用
}
});
},
// 处理文件变更
handleFileChange(files, type) {
if (type === 'qualification_certificate') {
const markedFiles = files.map(file => ({
...file,
businessType: 'qualification_certificate'
}))
this.formData.files = markedFiles
// 触发OCR识别
this.handleOcrResult(markedFiles)
}
},
// 处理OCR识别结果
handleOcrResult(files) {
if (!files || !Array.isArray(files) || files.length === 0) return
this.$bus.$emit('startUpload', '正在识别证书信息')
try {
const firstFile = files[0]
if (firstFile.response?.ocrResult) {
const ocrResult = firstFile.response.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 && chat_res[key]) {
// 日期格式处理
if (['certificateDate', 'certificateEndDate'].includes(formField)) {
// 简单日期格式转换(可根据实际识别结果调整)
const dateStr = chat_res[key].replace(/[^\d-]/g, '')
this.formData[formField] = dateStr || ''
} else {
this.formData[formField] = chat_res[key] || ''
}
}
})
this.$message.success('OCR识别成功已自动填充证书信息')
// 触发表单验证
Object.keys(this.ocrResultParams).forEach(key => {
const formField = this.ocrResultParams[key]
this.$refs.qualificationForm.validateField(formField)
})
}
} else {
this.$message.error(`识别失败: ${ocrResult.status_msg || '未知错误'}`)
}
}
} catch (error) {
this.$message.error(`处理识别结果失败: ${error.message}`)
} finally {
this.$bus.$emit('endUpload')
}
},
// 处理文件删除
handleDelFile(file) {
const filePath = file.response?.fileRes?.uploadPath || file.filePath
if (filePath && !this.formData.delFileList.includes(filePath)) {
this.formData.delFileList.push(filePath)
}
// 删除文件后清空关联字段
if (this.formData.files.length === 0) {
this.formData.certificateName = ''
this.formData.certificateCode = ''
this.formData.certificateDate = ''
this.formData.certificateEndDate = ''
this.formData.certificateInstitution = ''
}
},
// 表单验证
validate() {
return new Promise((resolve, reject) => {
if (!this.$refs.qualificationForm) {
reject(new Error('表单实例未加载完成'))
return
}
this.$refs.qualificationForm.validate((valid) => {
if (valid) {
resolve(this.formData)
} else {
reject(new Error('资质证书信息填写不完整'))
}
})
})
},
// 重置表单
resetForm() {
const oldFileList = [...this.formData.files]; // 拷贝旧文件列表
this.$nextTick(async () => {
this.formData.files = oldFileList;
await this.$nextTick();
if (oldFileList.length > 0 && this.$refs.uploadFileComp) {
const uploadInnerFiles = this.$refs.uploadFileComp.files;
uploadInnerFiles.forEach(file => {
this.$refs.uploadFileComp.handleRemove(file, []);
});
}
this.formData.files = [];
if (this.$refs.qualificationForm) {
this.$refs.qualificationForm.resetFields();
}
// 步骤5清空其他表单字段保持原有逻辑
this.formData = {
...this.formData,
certificateName: '',
certificateCode: '',
certificateDate: '',
certificateEndDate: '',
certificateInstitution: '',
qualificationType: '',
delFileList: []
};
});
},
// 初始化OCR识别规则
addOcrRule() {
this.ocrRuleList.forEach(item => {
this.ocrRule(item)
})
},
// 获取OCR识别规则
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)
},
},
created() {
this.loadQualificationTypeDict();
}
};
</script>
<style scoped lang="scss">
.basic-info-title {
display: flex;
align-items: center;
margin: 0 0 20px 0;
span {
margin: 0 5px;
font-size: 20px;
color: #333;
}
img {
width: 24px;
height: 24px;
object-fit: contain;
}
}
.qualification-form {
padding: 0;
}
.el-form {
margin-top: 15px;
}
.form-control {
width: 100%;
}
.el-form-item {
margin-bottom: 20px;
}
::v-deep .el-form-item__label {
color: #4e5969;
font-weight: 500;
}
.form-wrapper {
padding: 24px;
background: #fff;
}
</style>