smart-bid-web/src/views/enterpriseLibrary/enterprise/components/EnterpriseForm.vue

414 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 企业主体库表单 -->
<template>
<div class="app-container" :class="{ 'no-pointer-events': showUploadAnimation || showSaveAnimation }">
<!-- 全局上传动画 -->
<div v-if="showUploadAnimation" class="global-upload-animation">
<div class="animation-mask"></div>
<div class="animation-content">
<div class="spinner"></div>
<div class="animation-text">{{ animationText }}</div>
<div class="animation-subtext">正在处理文件,请稍候...</div>
</div>
</div>
<!-- 保存动画 -->
<div v-if="showSaveAnimation" class="global-upload-animation">
<div class="animation-mask"></div>
<div class="animation-content">
<div class="spinner"></div>
<div class="animation-text">数据上传中</div>
<div class="animation-subtext">请稍后,正在保存数据...</div>
</div>
</div>
<div class="content-header">
<el-button class="reset-btn" @click="handleClose()">返回</el-button>
<el-button class="search-btn" :loading="isSaving" @click="handleSave()">保存</el-button>
</div>
<div class="content-body">
<el-row :gutter="24" class="content-row">
<!-- 基本信息 -->
<el-col :span="6" class="pane-left">
<BasicInfo ref="basicInfo" :detailData="detailData" />
</el-col>
<!-- 法人信息 -->
<el-col :span="6" class="pane-center">
<LegalPerson ref="legalPerson" :detailData="detailData" />
</el-col>
<!-- 开户证明 -->
<el-col :span="6" class="pane-right">
<AccountOpeningCertificate ref="accountOpeningCertificate" :detailData="detailData" />
</el-col>
</el-row>
</div>
</div>
</template>
<script>
import { decryptWithSM4 } from '@/utils/sm'
import BasicInfo from './child/BasicInfo.vue'
import LegalPerson from './child/LegalPerson.vue'
import AccountOpeningCertificate from './child/AccountOpeningCertificate.vue'
import { addDataAPI, editDataAPI, getDetailDataAPI } from '@/api/enterpriseLibrary/enterprise/enterprise'
export default {
name: 'EnterpriseForm',
components: {
BasicInfo,
LegalPerson,
AccountOpeningCertificate
},
data() {
return {
enterpriseId: decryptWithSM4(this.$route.query.enterpriseId),
type: decryptWithSM4(this.$route.query.type),
showUploadAnimation: false,
showSaveAnimation: false, // 新增:保存动画状态
uploadQueue: 0, // 上传队列计数器
animationText: '识别中',
isSaving: false, // 新增保存按钮loading状态
detailData: {} // 详情数据
}
},
created() {
this.getDetail()
},
methods: {
// 返回
handleClose() {
const obj = { path: "/enterpriseLibrary/enterprise" }
this.$tab.closeOpenPage(obj)
},
// 获取详情
async getDetail() {
const res = await getDetailDataAPI({ enterpriseId: this.enterpriseId })
console.log('res:', res);
this.detailData = res.data;
},
// 保存
async handleSave() {
// 如果正在保存中,直接返回
if (this.isSaving) {
return
}
this.isSaving = true
this.showSaveAnimation = true
try {
// 并行校验所有表单
const [basicInfoData, legalPersonData, accountData] = await Promise.all([
this.$refs.basicInfo.validate(),
this.$refs.legalPerson.validate(),
this.$refs.accountOpeningCertificate.validate()
])
// 所有校验通过,组装完整数据
let formData = {
...basicInfoData,
...legalPersonData,
...accountData,
allFiles: [
...basicInfoData.fileList.map(file => JSON.parse(JSON.stringify(file))),
...legalPersonData.fileList.map(file => JSON.parse(JSON.stringify(file))),
...legalPersonData.fileList2.map(file => JSON.parse(JSON.stringify(file))),
...accountData.fileList.map(file => JSON.parse(JSON.stringify(file)))
],
delFiles: [
...basicInfoData.delFileList,
...legalPersonData.delFileList,
...accountData.delFileList
]
}
console.log('所有表单校验通过,完整数据:', formData)
let allFiles = formData.allFiles.map(file => {
return file?.response?.fileRes ? {
...file.response.fileRes,
} : null;
}).filter(item => item !== null);
formData.files = allFiles;
// 删除不必要的属性
delete formData.fileList;
delete formData.delFileList;
delete formData.allFiles;
delete formData.fileList2;
// 保存请求
const res = await this.saveEnterprise(formData)
console.log('res:', res);
if (res.code === 200) {
this.$message.success('保存成功')
this.handleClose()
}
} catch (error) {
console.error('保存失败:', error)
} finally {
// 无论成功失败,都关闭动画
this.isSaving = false
this.showSaveAnimation = false
}
},
// 保存接口
async saveEnterprise(formData) {
return new Promise((resolve, reject) => {
if (this.type === 'add') { // 新增
addDataAPI(formData).then(res => {
resolve(res)
}).catch(error => {
reject(error)
})
} else { // 修改
formData.enterpriseId = this.enterpriseId;
editDataAPI(formData).then(res => {
resolve(res)
}).catch(error => {
reject(error)
})
}
})
},
// 开始上传
handleStartUpload(data) {
this.animationText = data
this.uploadQueue++
this.showUploadAnimation = true
},
// 结束上传
handleEndUpload(data) {
if (this.uploadQueue > 0) {
this.uploadQueue--
}
// 如果队列为空,隐藏动画
if (this.uploadQueue === 0) {
this.showUploadAnimation = false
}
}
},
mounted() {
// 监听上传开始事件
this.$bus.$on('startUpload', this.handleStartUpload)
// 监听上传结束事件
this.$bus.$on('endUpload', this.handleEndUpload)
},
beforeDestroy() {
// 移除所有事件监听
this.$bus.$off('startUpload', this.handleStartUpload)
this.$bus.$off('endUpload', this.handleEndUpload)
// 重置状态
this.showUploadAnimation = false
this.showSaveAnimation = false
this.uploadQueue = 0
this.animationText = '识别中'
this.isSaving = false
}
}
</script>
<style scoped lang="scss">
.app-container {
padding: 24px;
background: linear-gradient(180deg, #F1F6FF 20%, #E5EFFF 100%);
min-height: 100vh;
overflow-y: auto;
position: relative;
// 当显示动画时禁用页面点击
&.no-pointer-events {
pointer-events: none;
// 子元素也继承禁用点击
* {
pointer-events: none;
}
}
}
// 全局上传动画样式
.global-upload-animation {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
// 动画区域本身可以有点击事件如果需要
pointer-events: auto;
.animation-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.6); // 添加半透明背景
backdrop-filter: blur(4px);
// 遮罩层阻止点击
pointer-events: auto;
}
.animation-content {
position: relative;
z-index: 10000;
text-align: center;
background: linear-gradient(135deg, #ffffff 0%, #f8faff 100%);
padding: 40px 50px;
border-radius: 20px;
box-shadow:
0 10px 40px rgba(31, 114, 234, 0.15),
0 0 0 1px rgba(31, 114, 234, 0.1);
min-width: 280px;
animation: slideInUp 0.3s ease-out;
// 动画内容可以有点击事件
pointer-events: auto;
.spinner {
width: 60px;
height: 60px;
border: 4px solid #f3f7ff;
border-top: 4px solid #1F72EA;
border-radius: 50%;
animation: spin 1.2s linear infinite;
margin: 0 auto 20px;
position: relative;
&::after {
content: '';
position: absolute;
top: -4px;
left: -4px;
right: -4px;
bottom: -4px;
border: 4px solid transparent;
border-top: 4px solid #4A8BFF;
border-radius: 50%;
animation: spin 0.8s linear infinite reverse;
}
}
.animation-text {
font-size: 20px;
font-weight: 600;
color: #1F72EA;
margin-bottom: 8px;
background: linear-gradient(135deg, #1F72EA 0%, #4A8BFF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.animation-subtext {
font-size: 14px;
color: #666;
opacity: 0.8;
}
}
}
.content-body {
margin-top: 20px;
}
.content-row {
margin: 0;
display: flex;
flex-wrap: nowrap;
gap: 16px;
}
.pane-left,
.pane-center,
.pane-right {
background: #fff;
border-radius: 16px 16px 16px 16px;
min-height: 600px;
box-shadow: 0px 4px 20px 0px rgba(31, 35, 55, 0.1);
padding: 0;
margin-bottom: 20px;
flex: 1;
min-width: 0;
}
.content-header {
display: flex;
justify-content: flex-end;
align-items: center;
margin-bottom: 20px;
gap: 12px;
}
.search-btn {
width: 98px;
height: 36px;
background: #1F72EA;
box-shadow: 0px 4px 8px 0px rgba(51, 135, 255, 0.5);
border-radius: 4px;
border: none;
color: #fff;
font-size: 14px;
transition: all 0.3s ease;
&:hover {
background: #4A8BFF;
box-shadow: 0px 6px 12px 0px rgba(51, 135, 255, 0.6);
}
// 当按钮处于loading状态时的样式
&.is-loading {
opacity: 0.7;
pointer-events: none;
}
}
.reset-btn {
width: 98px;
height: 36px;
background: #FFFFFF;
box-shadow: 0px 4px 8px 0px rgba(76, 76, 76, 0.2);
border-radius: 4px;
border: none;
color: #666;
font-size: 14px;
transition: all 0.3s ease;
&:hover {
background: #f5f5f5;
color: #409EFF;
box-shadow: 0px 6px 12px 0px rgba(76, 76, 76, 0.3);
}
}
// 动画定义
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(30px) scale(0.9);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
</style>