From c88e93a2a1994bf947393b3a56537e42a5b08597 Mon Sep 17 00:00:00 2001 From: cwchen <1048842385@qq.com> Date: Fri, 24 Oct 2025 19:48:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=BA=E5=91=98=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../personnel/components/PersonnelForm.vue | 162 ++++++++++++++-- .../personnel/components/child/BasicInfo.vue | 55 ++++-- .../personnel/components/child/OtherInfo.vue | 96 ++++++++- .../components/child/QualificationInfo.vue | 183 ++++++++++++++++-- .../enterpriseLibrary/personnel/index.vue | 15 +- 5 files changed, 452 insertions(+), 59 deletions(-) diff --git a/src/views/enterpriseLibrary/personnel/components/PersonnelForm.vue b/src/views/enterpriseLibrary/personnel/components/PersonnelForm.vue index ecf3b52..6978c80 100644 --- a/src/views/enterpriseLibrary/personnel/components/PersonnelForm.vue +++ b/src/views/enterpriseLibrary/personnel/components/PersonnelForm.vue @@ -47,6 +47,7 @@ import { encryptWithSM4,decryptWithSM4 } from '@/utils/sm' import BasicInfoPersonnel from './child/BasicInfo.vue' import QualificationInfoPersonnel from './child/QualificationInfo.vue' import OtherInfoPersonnel from './child/OtherInfo.vue' +import { addDataAPI, editDataAPI, getDetailDataAPI } from '@/api/enterpriseLibrary/personnel/personnel' export default { name: 'PersonnelForm', components: { @@ -87,34 +88,173 @@ export default { handlePersonnelPosition(data) { this.personnelPosition = data; }, + // 获取资源文件 + getResourceFilePo(fileList) { + let resourceFiles = fileList.map(file => { + return file?.response?.fileRes ? { + ...file.response.fileRes, + } : null; + }).filter(item => item !== null); + return resourceFiles && resourceFiles.length > 0 ? resourceFiles[0] : null; + }, + // 获取建造师证书数据 + getBuilderCertificateData(raw) { + return { + professionalType: raw.professionalType, + certificateCode: raw.certificateCode, + certificateLevel: raw.certificateLevel, + certificateValidityPeriod: raw.certificateValidityPeriod[0] + '-' + raw.certificateValidityPeriod[1], + useValidityPeriod: raw.useValidityPeriod[0] + '-' + raw.useValidityPeriod[1], + certificateType:'econstructor_certificate' + + } + }, + // 获取证书类型 + getCertificateType(fileList) { + let resourceFiles = fileList.map(file => { + return file?.response?.fileRes ? { + ...file.response.fileRes, + } : { ...file }; + }); + return resourceFiles && resourceFiles.length > 0 ? (resourceFiles[0].businessType || resourceFiles[0].fileType) : ''; + }, + // 获取 B证、C证、其他证书数据 + getOtherCertificateData(raw) { + return { + certificateCode: raw.certificateCode2, + certificateValidityPeriod: raw.certificateValidityPeriod2[0] + '-' + raw.certificateValidityPeriod2[1], + registerProfessional: raw.registerProfessional, + certificateType: this.getCertificateType(raw.fileList2) + } + }, + // 获取职称证书数据 + getTitleData(raw) { + return { + titleName: raw.professionalType, + professionalName: raw.professionalType, + certificateCode: raw.certificateCode, + certificateType:'professional_title_certificate' + } + }, // 保存 - async handleSave() { + async handleSave() { + // 如果正在保存中,直接返回 + if (this.isSaving) { + return + } + + this.isSaving = true + this.showSaveAnimation = true + try { // 并行校验所有表单 - const [basicInfoPersonnelData, qualificationInfoPersonnelData, otherInfoPersonnelData] = await Promise.all([ + const [basicInfoData, qualificationData, otherData] = await Promise.all([ this.$refs.basicInfoPersonnel.validate(), this.$refs.qualificationInfoPersonnel.validate(), this.$refs.otherInfoPersonnel.validate() ]) // 所有校验通过,组装完整数据 - const formData = { - ...basicInfoPersonnelData, - ...qualificationInfoPersonnelData, - ...otherInfoPersonnelData + let formData = { + ...basicInfoData, + allFiles: [ + ...basicInfoData.fileList.map(file => JSON.parse(JSON.stringify(file))), + ...basicInfoData.fileList2.map(file => JSON.parse(JSON.stringify(file))), + ...basicInfoData.fileList3.map(file => JSON.parse(JSON.stringify(file))), + ...basicInfoData.fileList4.map(file => JSON.parse(JSON.stringify(file))), + ], + delFiles: [ + ...basicInfoData.delFileList, + ] } console.log('所有表单校验通过,完整数据:', formData) - // 这里可以调用保存接口 - // await this.saveEnterprise(formData) - this.$message.success('保存成功') + // 人员相关文件 + let allFiles = formData.allFiles.map(file => { + return file?.response?.fileRes ? { + ...file.response.fileRes, + } : null; + }).filter(item => item !== null); + + // 人员相关证书文件 + let personnelCertificateFiles = []; + if(qualificationData.fileList){ + // 建造师证书 + let obj = { + personnelCertificate: this.getBuilderCertificateData(qualificationData), + resourceFilePo: this.getResourceFilePo(qualificationData.fileList), + delFileList: null, + }; + + personnelCertificateFiles.push(obj); + } + if(qualificationData.fileList2){ + // 建造师证书、B证、C证 其他证书 + let obj = { + personnelCertificate: this.getOtherCertificateData(qualificationData), + resourceFilePo: this.getResourceFilePo(qualificationData.fileList2), + delFileList: null, + }; + personnelCertificateFiles.push(obj); + } + if(otherData.fileList){ + // 职称证书 + let obj = { + personnelCertificate: this.getTitleData(otherData), + resourceFilePo: this.getResourceFilePo(otherData.fileList), + delFileList: otherData.delFileList, + }; + personnelCertificateFiles.push(obj); + } + formData.files = allFiles; + formData.enterpriseId = this.enterpriseId; + formData.personnelCertificateFiles = personnelCertificateFiles; + formData.personnelIntroduction = otherData.personnelIntroduction; + // 删除不必要的属性 + delete formData.fileList; + delete formData.fileList2; + delete formData.fileList3; + delete formData.fileList4; + delete formData.delFileList; + delete formData.allFiles; + console.log('所有表单校验通过,完整数据2222222:', formData) + // 保存请求 + /* const res = await this.savePersonnel(formData) + console.log('res:', res); + if (res.code === 200) { + this.$message.success('保存成功') + this.handleClose() + } */ } catch (error) { - // console.error('表单校验失败:', error) - this.$message.error(error.message || '请完善表单信息') + console.error('保存失败:', error) + } finally { + // 无论成功失败,都关闭动画 + this.isSaving = false + this.showSaveAnimation = false } }, + // 保存接口 + async savePersonnel(formData) { + return new Promise((resolve, reject) => { + if (this.type === 'add') { // 新增 + addDataAPI(formData).then(res => { + resolve(res) + }).catch(error => { + reject(error) + }) + } else { // 修改 + formData.personnelId = this.personnelId; + editDataAPI(formData).then(res => { + resolve(res) + }).catch(error => { + reject(error) + }) + } + + }) + }, // 开始上传 handleStartUpload(data) { this.animationText = data diff --git a/src/views/enterpriseLibrary/personnel/components/child/BasicInfo.vue b/src/views/enterpriseLibrary/personnel/components/child/BasicInfo.vue index c71f9ac..783e4a3 100644 --- a/src/views/enterpriseLibrary/personnel/components/child/BasicInfo.vue +++ b/src/views/enterpriseLibrary/personnel/components/child/BasicInfo.vue @@ -19,7 +19,8 @@ - + - + - + @@ -98,15 +102,20 @@ export default { fileList: [], fileList2: [], fileList3: [], - fileList4: [] + fileList4: [], + delFileList: [], }, // OCR 识别规则 - ocrRuleList: ['face_id_card_portrait'], + ocrRuleList: ['face_id_card_portrait','national_emblem_id_card','academic_certificate','labor_contract'], fileUploadList: [], // 根据返回的chat_res对象结构修改映射关系 ocrResultParams: { "姓名": "personnelName", "公民身份号码": "personnelIdCard", + "毕业院校":"graduateSchool", + "毕业专业":"graduationMajor", + "学历":"qualification", + "毕业时间":"graduationDate", }, rules: { personnelPosition: [ @@ -140,16 +149,16 @@ export default { { required: true, message: '请输入联系方式', trigger: 'blur' } ], fileList: [ - { required: true, message: '请上传身份证人面像', trigger: 'blur' } + { required: true, message: '请上传身份证人面像', trigger: 'change' } ], fileList2: [ - { required: true, message: '请上传身份证国徽面', trigger: 'blur' } + { required: true, message: '请上传身份证国徽面', trigger: 'change' } ], fileList3: [ - { required: true, message: '请上传学历证书', trigger: 'blur' } + { required: true, message: '请上传学历证书', trigger: 'change' } ], fileList4: [ - { required: true, message: '请上传劳动合同', trigger: 'blur' } + { required: true, message: '请上传劳动合同', trigger: 'change' } ], } @@ -183,7 +192,7 @@ export default { const foundItem = this.dict.type.identification_tag.find(item => item.value === type); const item = foundItem ? { fileUploadType: foundItem.value, - fields_json: foundItem.raw.remark, + fields_json: type !== 'national_emblem_id_card' ? foundItem.raw.remark : '', suffix: 'personnel_database' } : null; @@ -213,11 +222,17 @@ export default { }); } } - if (type == 'face_id_card_portrait') { + if (type == 'face_id_card_portrait') { // 身份证人面像 this.form.fileList = file; this.$refs.basicInfoForm.validateField(['personnelName', 'personnelIdCard']); - } - + }else if (type == 'national_emblem_id_card') { // 身份证国徽面 + this.form.fileList2 = file; + }else if (type == 'academic_certificate') { // 学历证书 + this.form.fileList3 = file; + this.$refs.basicInfoForm.validateField(['graduateSchool', 'graduationMajor', 'qualification', 'graduationDate']); + }else if (type == 'labor_contract') { // 劳动合同 + this.form.fileList4 = file; + } } }, // 文件删除时触发 @@ -226,6 +241,20 @@ export default { this.form.delFileList.push(file.response.fileRes.uploadPath || file.filePath); }, }, + computed: { + fileUploadRule() { + return this.fileUploadList[0] || {}; + }, + fileUploadRule2() { + return this.fileUploadList[1] || {}; + }, + fileUploadRule3() { + return this.fileUploadList[2] || {}; + }, + fileUploadRule4() { + return this.fileUploadList[3] || {}; + } + }, watch: { // 监听字典数据加载完成 'dict.type.identification_tag': { diff --git a/src/views/enterpriseLibrary/personnel/components/child/OtherInfo.vue b/src/views/enterpriseLibrary/personnel/components/child/OtherInfo.vue index 4c72be3..e1d0ee4 100644 --- a/src/views/enterpriseLibrary/personnel/components/child/OtherInfo.vue +++ b/src/views/enterpriseLibrary/personnel/components/child/OtherInfo.vue @@ -7,20 +7,25 @@ - + - + - + - + + v-model.trim="form.personnelIntroduction" clearable show-word-limit placeholder="请输入人员简介" maxlength="300"> @@ -31,6 +36,13 @@ import UploadFile from '@/views/common/UploadFile.vue' export default { name: 'OtherInfoPersonnel', components: { UploadFile }, + dicts: ['identification_tag'], + props: { + detailData: { + type: Object, + default: () => { } + } + }, data() { return { form: { @@ -39,10 +51,20 @@ export default { professionalName: '', certificateCode: '', personnelIntroduction: '', + delFileList: [], + }, + // OCR 识别规则 + ocrRuleList: ['professional_title_certificate'], + fileUploadList: [], + // 根据返回的chat_res对象结构修改映射关系 + ocrResultParams: { + "职称名称": "titleName", + "证书编号": "certificateCode", + "专业名称": "professionalName", }, rules: { fileList: [ - { required: true, message: '请上传职称证', trigger: 'blur' } + { required: true, message: '请上传职称证', trigger: 'change' } ], titleName: [ { required: true, message: '请输入职称名称', trigger: 'blur' } @@ -53,9 +75,6 @@ export default { certificateCode: [ { required: true, message: '请输入证书编号', trigger: 'blur' } ], - personnelIntroduction: [ - { required: true, message: '请输入人员简介', trigger: 'blur' } - ], } } @@ -73,6 +92,65 @@ export default { }) }) }, + // ocr文件识别规则 + ocrRule(type) { + const foundItem = this.dict.type.identification_tag.find(item => item.value === type); + const item = foundItem ? { + fileUploadType: foundItem.value, + fields_json: foundItem.raw.remark, + suffix: 'personnel_database' + } : null; + this.fileUploadList.push(item) + }, + // 添加ocr文件识别规则 + addOcrRule() { + this.ocrRuleList.forEach(item => { + this.ocrRule(item) + }) + }, + // 文件变化 + handleFileChange(file, type) { + + if (file instanceof Array && file.length > 0 && file[0].response) { + const response = file[0].response; + if (response.ocrResult && response.ocrResult.status_code === 200) { + // ocr识别成功 + const chat_res = response.ocrResult.data?.chat_res; + if (chat_res && typeof chat_res === 'object') { + // 直接遍历chat_res对象的属性 + Object.keys(chat_res).forEach(key => { + let formField = formField = this.ocrResultParams[key]; + if (formField && chat_res[key]) { + this.form[formField] = chat_res[key]; + } + }); + } + } + this.form.fileList = file; + this.$refs.accountOpeningCertificateForm.validateField(['titleName', 'certificateCode', 'professionalName']); + } + }, + // 文件删除时触发 + handleDelFile(file) { + console.log(file); + this.form.delFileList.push(file.response.fileRes.uploadPath || file.filePath); + }, + }, + computed: { + fileUploadRule() { + return this.fileUploadList[0] || {}; + }, + }, + watch: { + // 监听字典数据加载完成 + 'dict.type.identification_tag': { + handler(newVal) { + if (newVal && newVal.length > 0) { + this.addOcrRule(); + } + }, + immediate: true // 立即执行一次 + }, }, } diff --git a/src/views/enterpriseLibrary/personnel/components/child/QualificationInfo.vue b/src/views/enterpriseLibrary/personnel/components/child/QualificationInfo.vue index d204ead..b3b713f 100644 --- a/src/views/enterpriseLibrary/personnel/components/child/QualificationInfo.vue +++ b/src/views/enterpriseLibrary/personnel/components/child/QualificationInfo.vue @@ -4,28 +4,48 @@ 资质信息 资质信息 - + @@ -33,16 +53,26 @@ @@ -57,6 +87,7 @@ import UploadFile from '@/views/common/UploadFile.vue' export default { name: 'QualificationInfoPersonnel', components: { UploadFile }, + dicts: ['personnel_position', 'identification_tag'], props: { personnelPosition: { type: Object, @@ -66,7 +97,10 @@ export default { qualification: '建造师证书、安全考核B证' }) }, - + detailData: { + type: Object, + default: () => { } + } }, data() { return { @@ -81,7 +115,23 @@ export default { registerProfessional: '', fileList: [], fileList2: [], + delFileList: [], }, + // OCR 识别规则 + ocrRuleList: ['constructor_certificate', 'safety_assessment_certificate_b'], + fileUploadList: [], + // 根据返回的chat_res对象结构修改映射关系 + ocrResultParams: { + "专业类型": "professionalType", + "证书编号": "certificateCode", + "级别": "certificateLevel", + }, + ocrResultParams2: { + "证书编号": "certificateCode2", + "注册专业": "registerProfessional", + }, + // 默认为安全考核B证 + otherType:'safety_assessment_certificate_b', rules: { professionalType: [ { required: true, message: '请输入专业类型', trigger: 'blur' } @@ -109,10 +159,10 @@ export default { { required: true, message: '请输入注册专业', trigger: 'blur' } ], fileList: [ - { required: true, message: '请上传建造师证书', trigger: 'blur' } + { required: true, message: '请上传建造师证书', trigger: 'change' } ], fileList2: [ - { required: true, message: '请上传安全考核B证', trigger: 'blur' } + { required: true, message: '请上传安全考核B证', trigger: 'change' } ], } } @@ -120,7 +170,7 @@ export default { methods: { // 切换校验规则 switchValidate(newVal) { - + if (newVal.value === 'project_manager') { this.rules = { professionalType: [ @@ -155,7 +205,7 @@ export default { { required: true, message: '请上传安全考核B证', trigger: 'blur' } ], } - }else{ + } else { this.rules = { certificateCode2: [ { required: true, message: '请输入证书编号', trigger: 'blur' } @@ -173,13 +223,13 @@ export default { } // 清空校验信息 this.$nextTick(() => { - this.$refs.legalPersonForm.clearValidate(); + this.$refs.qualificationInfoForm.clearValidate(); }) }, // 校验规则 validate() { return new Promise((resolve, reject) => { - this.$refs.legalPersonForm.validate((valid) => { + this.$refs.qualificationInfoForm.validate((valid) => { if (valid) { resolve(this.form) // 校验成功返回表单数据 } else { @@ -188,21 +238,103 @@ export default { }) }) }, + getOtherType() { + const result = this.personnelPosition.qualification.split('、').filter(item => !item.includes('建造师证书')); + const firstMatch = this.dict.type.identification_tag.find(item => + result.includes(item.label) + ); + this.otherType = firstMatch ? firstMatch.value : ''; + + const item = this.getRuleItem(this.otherType); + + this.fileUploadList.splice(1, 1, item); + }, + // ocr文件识别规则 + ocrRule(type) { + const item = this.getRuleItem(type); + this.fileUploadList.push(item) + }, + + // 获取ocr识别规则 + getRuleItem(type) { + const foundItem = this.dict.type.identification_tag.find(item => item.value === type); + const item = foundItem ? { + fileUploadType: foundItem.value, + fields_json: foundItem.raw.remark, + suffix: 'personnel_database' + } : null; + return item; + }, + + // 添加ocr文件识别规则 + addOcrRule() { + this.ocrRuleList.forEach(item => { + this.ocrRule(item) + }) + }, + + // 文件变化 + handleFileChange(file, type) { + + if (file instanceof Array && file.length > 0 && file[0].response) { + const response = file[0].response; + if (response.ocrResult && response.ocrResult.status_code === 200) { + // ocr识别成功 + const chat_res = response.ocrResult.data?.chat_res; + if (chat_res && typeof chat_res === 'object') { + // 直接遍历chat_res对象的属性 + Object.keys(chat_res).forEach(key => { + let formField = null; + if(type === this.otherType){ + formField = this.ocrResultParams2[key]; + }else{ + formField = this.ocrResultParams[key]; + } + if (formField && chat_res[key]) { + this.form[formField] = chat_res[key]; + } + }); + } + } + if (type == 'constructor_certificate') { // 建造师证书 + this.form.fileList = file; + this.$refs.qualificationInfoForm.validateField(['professionalType', 'certificateCode', 'certificateLevel']); + }else{ // b证 c证 其他人员证书 + this.form.fileList2 = file; + this.$refs.qualificationInfoForm.validateField(['certificateCode2', 'registerProfessional']); + } + } + }, + // 文件删除时触发 + handleDelFile(file) { + console.log(file); + this.form.delFileList.push(file.response.fileRes.uploadPath || file.filePath); + }, }, watch: { personnelPosition: { handler(newVal) { console.log(newVal); this.switchValidate(newVal); + this.getOtherType(); + this.form.fileList = []; + this.form.fileList2 = []; }, - immediate: true + }, + // 监听字典数据加载完成 + 'dict.type.identification_tag': { + handler(newVal) { + if (newVal && newVal.length > 0) { + this.addOcrRule(); + } + }, + immediate: true // 立即执行一次 }, }, computed: { // 是否是项目经理 isProjectManager() { console.log(this.personnelPosition.value === 'project_manager'); - return this.personnelPosition.value === 'project_manager'; }, // 证书名称 @@ -210,6 +342,14 @@ export default { const result = this.personnelPosition.qualification.split('、').filter(item => !item.includes('建造师证书')); return result[0]; }, + + fileUploadRule() { + return this.fileUploadList[0] || {}; + }, + fileUploadRule2() { + return this.fileUploadList[1] || {}; + }, + } } @@ -225,4 +365,7 @@ export default { font-size: 20px; } } +.form-item { + width: 100%; +} \ No newline at end of file diff --git a/src/views/enterpriseLibrary/personnel/index.vue b/src/views/enterpriseLibrary/personnel/index.vue index bd3ed9a..fb465a6 100644 --- a/src/views/enterpriseLibrary/personnel/index.vue +++ b/src/views/enterpriseLibrary/personnel/index.vue @@ -40,23 +40,23 @@ -
+
-

{{ personnel.name }}

+

{{ item.personnelName }}

职位 - {{ personnel.position }} + {{ item.personnelPosition }}
从业年限 - {{ personnel.experience }} + {{ item.employmentYears }}年
入职时间 - {{ personnel.entryDate }} + {{ item.employmentDate }}
@@ -107,7 +107,8 @@ export default { personnelName: '', personnelPosition: '', pageNum: 1, - pageSize: 10 + pageSize: 10, + enterpriseId: decryptWithSM4(this.$route.query.enterpriseId) }, total: 100, personnelList: [], @@ -120,6 +121,8 @@ export default { methods: { // 获取人员列表 getList() { + console.log(this.queryParams); + listAPI(this.queryParams).then(res => { if (res.code === 200) { this.personnelList = res.rows;