2025-11-24 16:06:44 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<el-card class="step-card">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<div class="header-icon">
|
|
|
|
|
|
<el-icon class="text-blue-600">
|
|
|
|
|
|
<BuildingOfficeIcon />
|
|
|
|
|
|
</el-icon>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="header-content">
|
|
|
|
|
|
<h2 class="header-title">企业信息</h2>
|
|
|
|
|
|
<p class="header-subtitle">请填写企业基本信息,确保信息真实有效</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="enterprise-form">
|
|
|
|
|
|
<el-form
|
|
|
|
|
|
ref="enterpriseFormRef"
|
|
|
|
|
|
:model="form"
|
|
|
|
|
|
:rules="enterpriseRules"
|
|
|
|
|
|
label-width="10em"
|
|
|
|
|
|
class="enterprise-form-content"
|
|
|
|
|
|
>
|
2026-03-17 17:19:00 +08:00
|
|
|
|
<div class="form-section">
|
2025-11-24 16:06:44 +08:00
|
|
|
|
<h3 class="section-title">基本信息</h3>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 企业名称和OCR识别区域 -->
|
|
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="16">
|
|
|
|
|
|
<el-form-item label="企业名称" prop="companyName">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="form.companyName"
|
|
|
|
|
|
placeholder="请输入企业名称"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="8">
|
|
|
|
|
|
<div class="ocr-compact">
|
|
|
|
|
|
<div class="ocr-header-compact">
|
|
|
|
|
|
<el-icon class="text-green-600"><DocumentIcon /></el-icon>
|
2026-03-17 17:19:00 +08:00
|
|
|
|
<span class="ocr-title-compact">可进行OCR识别,请在下方上传营业执照</span>
|
2025-11-24 16:06:44 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div v-if="ocrLoading" class="ocr-status-compact">
|
|
|
|
|
|
<el-icon class="is-loading"><Loading /></el-icon>
|
|
|
|
|
|
<span>识别中...</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-if="ocrResult" class="ocr-status-compact success">
|
|
|
|
|
|
<el-icon class="text-green-600"><CheckIcon /></el-icon>
|
|
|
|
|
|
<span>识别成功</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-form-item label="统一社会信用代码" prop="unifiedSocialCode">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="form.unifiedSocialCode"
|
|
|
|
|
|
placeholder="请输入统一社会信用代码"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
|
2025-11-24 16:06:44 +08:00
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="法人姓名" prop="legalPersonName">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="form.legalPersonName"
|
|
|
|
|
|
placeholder="请输入法人姓名"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
2026-03-17 17:19:00 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-11-24 16:06:44 +08:00
|
|
|
|
<el-col :span="12">
|
2026-03-17 17:19:00 +08:00
|
|
|
|
<el-form-item label="企业地址" prop="enterpriseAddress">
|
2025-11-24 16:06:44 +08:00
|
|
|
|
<el-input
|
2026-03-17 17:19:00 +08:00
|
|
|
|
v-model="form.enterpriseAddress"
|
|
|
|
|
|
placeholder="请输入企业地址"
|
2025-11-24 16:06:44 +08:00
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
2026-03-17 17:19:00 +08:00
|
|
|
|
<!-- 营业执照图片上传(对应 BusinessLicenseImageURL) -->
|
2025-11-24 16:06:44 +08:00
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="24">
|
2026-03-17 17:19:00 +08:00
|
|
|
|
<el-form-item label="营业执照图片" prop="businessLicenseImageURL">
|
|
|
|
|
|
<el-upload
|
|
|
|
|
|
class="upload-area single-upload-area"
|
|
|
|
|
|
action="#"
|
|
|
|
|
|
list-type="picture-card"
|
|
|
|
|
|
:auto-upload="false"
|
|
|
|
|
|
:file-list="businessLicenseFileList"
|
|
|
|
|
|
:limit="1"
|
|
|
|
|
|
:on-change="handleBusinessLicenseChange"
|
|
|
|
|
|
:on-remove="handleBusinessLicenseRemove"
|
|
|
|
|
|
:before-upload="beforeUpload"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-icon class="upload-icon"><ArrowUpTrayIcon /></el-icon>
|
|
|
|
|
|
<div class="el-upload__text">上传清晰可辨的营业执照图片</div>
|
|
|
|
|
|
</el-upload>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<!-- 办公场地图片上传 -->
|
|
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-form-item label="办公场地照片">
|
|
|
|
|
|
<div class="text-xs mb-1 text-blue-500">
|
2026-03-17 18:30:23 +08:00
|
|
|
|
请在非 IE 浏览器下上传大小不超过 1M 的图片,最多 10 张,需体现门楣 LOGO、办公设备与工作人员。
|
2026-03-17 17:19:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="upload-drop-zone"
|
|
|
|
|
|
:class="{ 'is-dragover': officePlaceDragover }"
|
|
|
|
|
|
@dragover.prevent="officePlaceDragover = true"
|
|
|
|
|
|
@dragleave.prevent="officePlaceDragover = false"
|
|
|
|
|
|
@drop.prevent="onOfficePlaceDrop"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-upload
|
|
|
|
|
|
ref="officePlaceUploadRef"
|
|
|
|
|
|
class="upload-area"
|
|
|
|
|
|
action="#"
|
|
|
|
|
|
list-type="picture-card"
|
|
|
|
|
|
:auto-upload="false"
|
|
|
|
|
|
v-model:file-list="officePlaceFileList"
|
|
|
|
|
|
accept="image/jpeg,image/jpg,image/png,image/webp"
|
|
|
|
|
|
multiple
|
|
|
|
|
|
:limit="10"
|
|
|
|
|
|
:on-change="handleOfficePlaceChange"
|
|
|
|
|
|
:on-remove="handleOfficePlaceRemove"
|
|
|
|
|
|
:before-upload="beforeUpload"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="upload-trigger-inner">
|
|
|
|
|
|
<el-icon class="upload-icon"><ArrowUpTrayIcon /></el-icon>
|
|
|
|
|
|
<div class="el-upload__text">上传办公场地环境照片</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-upload>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="法人身份证号" prop="legalPersonID">
|
2025-11-24 16:06:44 +08:00
|
|
|
|
<el-input
|
2026-03-17 17:19:00 +08:00
|
|
|
|
v-model="form.legalPersonID"
|
|
|
|
|
|
placeholder="请输入法人身份证号"
|
2025-11-24 16:06:44 +08:00
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="法人手机号" prop="legalPersonPhone">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="form.legalPersonPhone"
|
|
|
|
|
|
placeholder="请输入法人手机号"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
maxlength="11"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="验证码" prop="legalPersonCode">
|
|
|
|
|
|
<div class="flex gap-2">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="form.legalPersonCode"
|
|
|
|
|
|
placeholder="请输入验证码"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
maxlength="6"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
:disabled="!canSendCode || sendingCode"
|
|
|
|
|
|
@click="sendCode"
|
|
|
|
|
|
:loading="sendingCode"
|
|
|
|
|
|
class="code-btn"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ countdown > 0 ? `${countdown}s` : '获取验证码' }}
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
2026-03-17 17:19:00 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h3 class="section-title">授权代表信息</h3>
|
|
|
|
|
|
<p class="section-desc">授权代表信息用于证明该人员已获得企业授权,请确保姓名、身份证号、手机号及身份证正反面照片真实有效。</p>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 授权代表信息 -->
|
|
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="8">
|
|
|
|
|
|
<el-form-item label="授权代表姓名" prop="authorizedRepName">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="form.authorizedRepName"
|
|
|
|
|
|
placeholder="请输入授权代表姓名"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="8">
|
|
|
|
|
|
<el-form-item label="授权代表身份证号" prop="authorizedRepID">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="form.authorizedRepID"
|
|
|
|
|
|
placeholder="请输入授权代表身份证号"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="8">
|
|
|
|
|
|
<el-form-item label="授权代表手机号" prop="authorizedRepPhone">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="form.authorizedRepPhone"
|
|
|
|
|
|
placeholder="请输入授权代表手机号"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
maxlength="11"
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 授权代表身份证图片上传 -->
|
|
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="身份证人像面" prop="authorizedRepIDImageURLs">
|
|
|
|
|
|
<el-upload
|
|
|
|
|
|
class="upload-area single-upload-area"
|
|
|
|
|
|
action="#"
|
|
|
|
|
|
list-type="picture-card"
|
|
|
|
|
|
:auto-upload="false"
|
|
|
|
|
|
:file-list="authorizedRepIDFrontFileList"
|
|
|
|
|
|
:limit="1"
|
|
|
|
|
|
:on-change="handleAuthorizedRepIDFrontChange"
|
|
|
|
|
|
:on-remove="handleAuthorizedRepIDFrontRemove"
|
|
|
|
|
|
:before-upload="beforeUpload"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-icon class="upload-icon"><ArrowUpTrayIcon /></el-icon>
|
|
|
|
|
|
<div class="el-upload__text">上传授权代表身份证人像面</div>
|
|
|
|
|
|
</el-upload>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="身份证国徽面" prop="authorizedRepIDImageURLs">
|
|
|
|
|
|
<el-upload
|
|
|
|
|
|
class="upload-area single-upload-area"
|
|
|
|
|
|
action="#"
|
|
|
|
|
|
list-type="picture-card"
|
|
|
|
|
|
:auto-upload="false"
|
|
|
|
|
|
:file-list="authorizedRepIDBackFileList"
|
|
|
|
|
|
:limit="1"
|
|
|
|
|
|
:on-change="handleAuthorizedRepIDBackChange"
|
|
|
|
|
|
:on-remove="handleAuthorizedRepIDBackRemove"
|
|
|
|
|
|
:before-upload="beforeUpload"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-icon class="upload-icon"><ArrowUpTrayIcon /></el-icon>
|
|
|
|
|
|
<div class="el-upload__text">上传授权代表身份证国徽面</div>
|
|
|
|
|
|
</el-upload>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<h3 class="section-title">应用场景填写</h3>
|
|
|
|
|
|
<p class="section-desc">请描述您调用接口的具体业务场景</p>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 接口用途描述(对应 APIUsage) -->
|
|
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-form-item label="应用场景" prop="apiUsage">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="form.apiUsage"
|
|
|
|
|
|
type="textarea"
|
|
|
|
|
|
:rows="4"
|
|
|
|
|
|
placeholder="请描述您调用接口的具体业务场景和用途"
|
|
|
|
|
|
maxlength="500"
|
|
|
|
|
|
show-word-limit
|
|
|
|
|
|
class="form-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 应用场景附件图片上传 -->
|
|
|
|
|
|
<el-row :gutter="16" class="mb-4">
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
|
|
|
|
|
|
<el-form-item label="应用场景附件">
|
|
|
|
|
|
<div class="text-xs mb-1 text-blue-500">
|
2026-03-17 18:30:23 +08:00
|
|
|
|
请在非 IE 浏览器下上传大小不超过 1M 的图片,最多 10 张后台应用截图。
|
2026-03-17 17:19:00 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="upload-drop-zone"
|
|
|
|
|
|
:class="{ 'is-dragover': scenarioDragover }"
|
|
|
|
|
|
@dragover.prevent="scenarioDragover = true"
|
|
|
|
|
|
@dragleave.prevent="scenarioDragover = false"
|
|
|
|
|
|
@drop.prevent="onScenarioDrop"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-upload
|
|
|
|
|
|
ref="scenarioUploadRef"
|
|
|
|
|
|
class="upload-area"
|
|
|
|
|
|
action="#"
|
|
|
|
|
|
list-type="picture-card"
|
|
|
|
|
|
:auto-upload="false"
|
|
|
|
|
|
v-model:file-list="scenarioFileList"
|
|
|
|
|
|
accept="image/jpeg,image/jpg,image/png,image/webp"
|
|
|
|
|
|
multiple
|
|
|
|
|
|
:limit="10"
|
|
|
|
|
|
:on-change="handleScenarioChange"
|
|
|
|
|
|
:on-remove="handleScenarioRemove"
|
|
|
|
|
|
:before-upload="beforeUpload"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="upload-trigger-inner">
|
|
|
|
|
|
<el-icon class="upload-icon"><ArrowUpTrayIcon /></el-icon>
|
|
|
|
|
|
<div class="el-upload__text">上传业务场景相关截图或证明材料</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-upload>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
2025-11-24 16:06:44 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="form-actions">
|
|
|
|
|
|
<el-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
size="default"
|
|
|
|
|
|
@click="submitForm"
|
|
|
|
|
|
:loading="submitting"
|
|
|
|
|
|
class="submit-btn"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-icon class="mr-1"><CheckIcon /></el-icon>
|
|
|
|
|
|
提交企业信息
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { certificationApi } from '@/api'
|
|
|
|
|
|
import { useUserStore } from '@/stores/user'
|
|
|
|
|
|
import { Loading } from '@element-plus/icons-vue'
|
|
|
|
|
|
import {
|
|
|
|
|
|
ArrowUpTrayIcon,
|
|
|
|
|
|
BuildingOfficeIcon,
|
|
|
|
|
|
CheckIcon,
|
|
|
|
|
|
DocumentIcon
|
|
|
|
|
|
} from '@heroicons/vue/24/outline'
|
2026-03-17 17:19:00 +08:00
|
|
|
|
import { ElMessage, ElMessageBox, genFileId } from 'element-plus'
|
2026-02-27 14:49:21 +08:00
|
|
|
|
import { useAliyunCaptcha } from '@/composables/useAliyunCaptcha'
|
2025-11-24 16:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
|
formData: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
default: () => ({
|
|
|
|
|
|
companyName: '',
|
|
|
|
|
|
unifiedSocialCode: '',
|
|
|
|
|
|
legalPersonName: '',
|
|
|
|
|
|
legalPersonID: '',
|
|
|
|
|
|
legalPersonPhone: '',
|
|
|
|
|
|
enterpriseAddress: '',
|
2026-03-17 17:19:00 +08:00
|
|
|
|
legalPersonCode: '',
|
|
|
|
|
|
// 扩展:营业执照 & 办公场地 & 场景
|
|
|
|
|
|
businessLicenseImageURL: '',
|
|
|
|
|
|
officePlaceImageURLs: [],
|
|
|
|
|
|
apiUsage: '',
|
|
|
|
|
|
scenarioAttachmentURLs: [],
|
|
|
|
|
|
// 授权代表信息
|
|
|
|
|
|
authorizedRepName: '',
|
|
|
|
|
|
authorizedRepID: '',
|
|
|
|
|
|
authorizedRepPhone: '',
|
|
|
|
|
|
authorizedRepIDImageURLs: []
|
2025-11-24 16:06:44 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(['submit'])
|
|
|
|
|
|
|
|
|
|
|
|
const userStore = useUserStore()
|
2026-02-27 14:49:21 +08:00
|
|
|
|
const { runWithCaptcha } = useAliyunCaptcha()
|
2025-11-24 16:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
// 表单引用
|
|
|
|
|
|
const enterpriseFormRef = ref()
|
|
|
|
|
|
|
|
|
|
|
|
// 表单数据
|
|
|
|
|
|
const form = ref({
|
|
|
|
|
|
companyName: '',
|
|
|
|
|
|
unifiedSocialCode: '',
|
|
|
|
|
|
legalPersonName: '',
|
|
|
|
|
|
legalPersonID: '',
|
|
|
|
|
|
legalPersonPhone: '',
|
|
|
|
|
|
enterpriseAddress: '',
|
2026-03-17 17:19:00 +08:00
|
|
|
|
legalPersonCode: '',
|
|
|
|
|
|
// 扩展:营业执照 & 办公场地 & 场景
|
|
|
|
|
|
businessLicenseImageURL: '',
|
|
|
|
|
|
officePlaceImageURLs: [],
|
|
|
|
|
|
apiUsage: '',
|
|
|
|
|
|
scenarioAttachmentURLs: [],
|
|
|
|
|
|
// 授权代表信息
|
|
|
|
|
|
authorizedRepName: '',
|
|
|
|
|
|
authorizedRepID: '',
|
|
|
|
|
|
authorizedRepPhone: '',
|
|
|
|
|
|
authorizedRepIDImageURLs: []
|
2025-11-24 16:06:44 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 验证码相关状态
|
|
|
|
|
|
const sendingCode = ref(false)
|
|
|
|
|
|
const countdown = ref(0)
|
|
|
|
|
|
let countdownTimer = null
|
|
|
|
|
|
|
|
|
|
|
|
// 加载状态
|
|
|
|
|
|
const submitting = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
// OCR相关状态
|
|
|
|
|
|
const ocrLoading = ref(false)
|
|
|
|
|
|
const ocrResult = ref(false)
|
|
|
|
|
|
const uploadRef = ref()
|
2026-03-17 17:19:00 +08:00
|
|
|
|
const officePlaceUploadRef = ref()
|
|
|
|
|
|
const scenarioUploadRef = ref()
|
|
|
|
|
|
const officePlaceDragover = ref(false)
|
|
|
|
|
|
const scenarioDragover = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
// 上传文件列表(前端展示用)
|
|
|
|
|
|
const officePlaceFileList = ref([])
|
|
|
|
|
|
const scenarioFileList = ref([])
|
|
|
|
|
|
const businessLicenseFileList = ref([])
|
|
|
|
|
|
const authorizedRepIDFrontFileList = ref([])
|
|
|
|
|
|
const authorizedRepIDBackFileList = ref([])
|
2025-11-24 16:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
// 计算属性
|
|
|
|
|
|
const canSendCode = computed(() => {
|
|
|
|
|
|
return form.value.legalPersonPhone && form.value.legalPersonPhone.length === 11 && countdown.value === 0
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 统一社会信用代码验证函数
|
|
|
|
|
|
const validateUnifiedSocialCode = (rule, value, callback) => {
|
|
|
|
|
|
if (!value) {
|
|
|
|
|
|
callback(new Error('请输入统一社会信用代码'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 统一社会信用代码格式:18位,由数字和大写字母组成
|
|
|
|
|
|
const pattern = /^[0-9A-HJ-NPQRTUWXY]{18}$/
|
|
|
|
|
|
if (!pattern.test(value)) {
|
|
|
|
|
|
callback(new Error('统一社会信用代码格式不正确,应为18位数字和大写字母组合'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
callback()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 身份证号验证函数
|
|
|
|
|
|
const validateIDCard = (rule, value, callback) => {
|
|
|
|
|
|
if (!value) {
|
|
|
|
|
|
callback(new Error('请输入法人身份证号'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 身份证号格式:18位,最后一位可能是X
|
|
|
|
|
|
const pattern = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
|
|
|
|
|
|
if (!pattern.test(value)) {
|
|
|
|
|
|
callback(new Error('身份证号格式不正确'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
callback()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 手机号验证函数
|
|
|
|
|
|
const validatePhone = (rule, value, callback) => {
|
|
|
|
|
|
if (!value) {
|
|
|
|
|
|
callback(new Error('请输入法人手机号'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 手机号格式:11位数字
|
|
|
|
|
|
const pattern = /^1[3-9]\d{9}$/
|
|
|
|
|
|
if (!pattern.test(value)) {
|
|
|
|
|
|
callback(new Error('手机号格式不正确'))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
callback()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 表单验证规则
|
|
|
|
|
|
const enterpriseRules = {
|
|
|
|
|
|
companyName: [
|
|
|
|
|
|
{ required: true, message: '请输入企业名称', trigger: 'blur' },
|
|
|
|
|
|
{ min: 2, max: 100, message: '企业名称长度应在2-100个字符之间', trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
unifiedSocialCode: [
|
|
|
|
|
|
{ required: true, message: '请输入统一社会信用代码', trigger: 'blur' },
|
|
|
|
|
|
{ validator: validateUnifiedSocialCode, trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
legalPersonName: [
|
|
|
|
|
|
{ required: true, message: '请输入法人姓名', trigger: 'blur' },
|
|
|
|
|
|
{ min: 2, max: 20, message: '法人姓名长度应在2-20个字符之间', trigger: 'blur' },
|
|
|
|
|
|
{ pattern: /^[\u4e00-\u9fa5a-zA-Z\s·]+$/, message: '法人姓名只能包含中文、英文和间隔号', trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
legalPersonID: [
|
|
|
|
|
|
{ required: true, message: '请输入法人身份证号', trigger: 'blur' },
|
|
|
|
|
|
{ validator: validateIDCard, trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
legalPersonPhone: [
|
|
|
|
|
|
{ required: true, message: '请输入法人手机号', trigger: 'blur' },
|
|
|
|
|
|
{ validator: validatePhone, trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
enterpriseAddress: [
|
|
|
|
|
|
{ required: true, message: '请输入企业地址', trigger: 'blur' },
|
|
|
|
|
|
{ min: 5, max: 200, message: '企业地址长度应在5-200个字符之间', trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
legalPersonCode: [
|
|
|
|
|
|
{ required: true, message: '请输入验证码', trigger: 'blur' },
|
|
|
|
|
|
{ len: 6, message: '验证码应为6位数字', trigger: 'blur' }
|
2026-03-17 17:19:00 +08:00
|
|
|
|
],
|
|
|
|
|
|
// 扩展字段简单校验(可按需加强)
|
|
|
|
|
|
businessLicenseImageURL: [
|
|
|
|
|
|
{ required: true, message: '请上传营业执照图片', trigger: 'change' }
|
|
|
|
|
|
],
|
|
|
|
|
|
apiUsage: [
|
|
|
|
|
|
{ required: true, message: '请填写接口用途', trigger: 'blur' },
|
|
|
|
|
|
{ min: 5, max: 500, message: '接口用途长度应在5-500个字符之间', trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
// 授权代表信息简单校验(可按需加强)
|
|
|
|
|
|
authorizedRepName: [
|
|
|
|
|
|
{ required: true, message: '请输入授权代表姓名', trigger: 'blur' },
|
|
|
|
|
|
{ min: 2, max: 20, message: '授权代表姓名长度应在2-20个字符之间', trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
authorizedRepID: [
|
|
|
|
|
|
{ required: true, message: '请输入授权代表身份证号', trigger: 'blur' },
|
|
|
|
|
|
{ validator: validateIDCard, trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
authorizedRepPhone: [
|
|
|
|
|
|
{ required: true, message: '请输入授权代表手机号', trigger: 'blur' },
|
|
|
|
|
|
{ validator: validatePhone, trigger: 'blur' }
|
|
|
|
|
|
],
|
|
|
|
|
|
authorizedRepIDImageURLs: [
|
|
|
|
|
|
{ required: true, message: '请上传授权代表身份证正反面图片', trigger: 'change' }
|
2025-11-24 16:06:44 +08:00
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 监听props变化
|
|
|
|
|
|
watch(() => props.formData, (newData) => {
|
|
|
|
|
|
if (newData) {
|
|
|
|
|
|
// 同步父组件传递的数据到本地表单
|
|
|
|
|
|
Object.keys(newData).forEach(key => {
|
|
|
|
|
|
if (newData[key] && Object.prototype.hasOwnProperty.call(form.value, key)) {
|
|
|
|
|
|
form.value[key] = newData[key]
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}, { immediate: true, deep: true })
|
|
|
|
|
|
|
|
|
|
|
|
// 发送验证码
|
|
|
|
|
|
const sendCode = async () => {
|
|
|
|
|
|
if (!canSendCode.value) return
|
|
|
|
|
|
|
|
|
|
|
|
sendingCode.value = true
|
|
|
|
|
|
try {
|
2026-02-27 14:49:21 +08:00
|
|
|
|
await runWithCaptcha(
|
|
|
|
|
|
async (captchaVerifyParam) => {
|
|
|
|
|
|
return await userStore.sendCode(form.value.legalPersonPhone, 'certification', captchaVerifyParam)
|
|
|
|
|
|
},
|
|
|
|
|
|
(res) => {
|
|
|
|
|
|
if (res.success) {
|
|
|
|
|
|
ElMessage.success('验证码发送成功')
|
|
|
|
|
|
startCountdown()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error(res?.error?.message || '验证码发送失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
2025-11-24 16:06:44 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('验证码发送失败:', error)
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
sendingCode.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 开始倒计时
|
|
|
|
|
|
const startCountdown = () => {
|
|
|
|
|
|
countdown.value = 60
|
|
|
|
|
|
countdownTimer = setInterval(() => {
|
|
|
|
|
|
countdown.value--
|
|
|
|
|
|
if (countdown.value <= 0) {
|
|
|
|
|
|
clearInterval(countdownTimer)
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OCR文件上传前验证
|
|
|
|
|
|
const beforeUpload = (file) => {
|
|
|
|
|
|
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']
|
|
|
|
|
|
const isValidType = allowedTypes.includes(file.type)
|
2026-03-17 18:30:23 +08:00
|
|
|
|
const maxSizeMB = 1
|
|
|
|
|
|
const isValidSize = file.size / 1024 / 1024 < maxSizeMB
|
2025-11-24 16:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
if (!isValidType) {
|
|
|
|
|
|
ElMessage.error('只支持 JPG、PNG、WEBP 格式的图片')
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!isValidSize) {
|
2026-03-17 18:30:23 +08:00
|
|
|
|
ElMessage.error(`图片大小不能超过 ${maxSizeMB}MB`)
|
2025-11-24 16:06:44 +08:00
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
// 处理文件变化:触发 OCR,并保存营业执照原图 URL(若有上传地址)
|
2025-11-24 16:06:44 +08:00
|
|
|
|
const handleFileChange = async (file) => {
|
|
|
|
|
|
if (!beforeUpload(file.raw)) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ocrLoading.value = true
|
|
|
|
|
|
ocrResult.value = false
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const formData = new FormData()
|
|
|
|
|
|
formData.append('image', file.raw)
|
|
|
|
|
|
|
|
|
|
|
|
const result = await certificationApi.recognizeBusinessLicense(formData)
|
|
|
|
|
|
|
|
|
|
|
|
if (result.success && result.data) {
|
|
|
|
|
|
// 自动填充表单
|
|
|
|
|
|
const ocrData = result.data
|
|
|
|
|
|
form.value.companyName = ocrData.company_name || ''
|
|
|
|
|
|
form.value.unifiedSocialCode = ocrData.unified_social_code || ''
|
|
|
|
|
|
form.value.legalPersonName = ocrData.legal_person_name || ''
|
|
|
|
|
|
form.value.legalPersonID = ocrData.legal_person_id || ''
|
|
|
|
|
|
form.value.enterpriseAddress = ocrData.address || ''
|
|
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
// 如果后端返回了已保存的营业执照图片URL,可以直接写入
|
|
|
|
|
|
if (ocrData.license_image_url) {
|
|
|
|
|
|
form.value.businessLicenseImageURL = ocrData.license_image_url
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:06:44 +08:00
|
|
|
|
ocrResult.value = true
|
|
|
|
|
|
ElMessage.success('营业执照识别成功,已自动填充表单')
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error('营业执照识别失败,请重试')
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('OCR识别失败:', error)
|
|
|
|
|
|
ElMessage.error('营业执照识别失败,请重试')
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
ocrLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
// 判断是否为前端 blob 预览地址(需上传到服务器后替换为真实 URL)
|
|
|
|
|
|
const isBlobUrl = (url) => typeof url === 'string' && url.startsWith('blob:')
|
|
|
|
|
|
|
|
|
|
|
|
// 上传单张图片到七牛云,返回可访问 URL
|
|
|
|
|
|
const uploadFileToServer = async (file) => {
|
|
|
|
|
|
const res = await certificationApi.uploadFile(file)
|
|
|
|
|
|
if (!res?.success || !res?.data?.url) {
|
|
|
|
|
|
throw new Error(res?.error?.message || '图片上传失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
return res.data.url
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 18:30:23 +08:00
|
|
|
|
// 选择后立即上传:对 el-upload 的 file 对象上传并更新 url/status,不更新表单(由调用方更新)
|
|
|
|
|
|
const uploadFileOnceSelected = async (file) => {
|
|
|
|
|
|
if (!file?.raw) return null
|
|
|
|
|
|
if (file.url && !isBlobUrl(file.url)) return file.url // 已是服务器 URL,不重复上传
|
|
|
|
|
|
file.status = 'uploading'
|
|
|
|
|
|
try {
|
|
|
|
|
|
const url = await uploadFileToServer(file.raw)
|
|
|
|
|
|
file.url = url
|
|
|
|
|
|
file.status = 'success'
|
|
|
|
|
|
if (file.response === undefined) file.response = {}
|
|
|
|
|
|
file.response.url = url
|
|
|
|
|
|
return url
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
file.status = 'fail'
|
|
|
|
|
|
ElMessage.error(err?.message || '图片上传失败')
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
// 提交前将 blob 图片全部上传到七牛云,并更新表单中的 URL
|
|
|
|
|
|
const uploadAllBlobFilesAndFillForm = async () => {
|
|
|
|
|
|
const tasks = []
|
|
|
|
|
|
|
|
|
|
|
|
// 营业执照:若当前是 blob 则上传
|
|
|
|
|
|
if (isBlobUrl(form.value.businessLicenseImageURL) && businessLicenseFileList.value.length > 0 && businessLicenseFileList.value[0].raw) {
|
|
|
|
|
|
tasks.push(
|
|
|
|
|
|
uploadFileToServer(businessLicenseFileList.value[0].raw).then((url) => {
|
|
|
|
|
|
form.value.businessLicenseImageURL = url
|
|
|
|
|
|
})
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 办公场地多图:按顺序上传
|
|
|
|
|
|
if (officePlaceFileList.value.length > 0) {
|
|
|
|
|
|
const files = officePlaceFileList.value.filter((f) => f.raw).map((f) => f.raw)
|
|
|
|
|
|
if (files.length > 0) {
|
|
|
|
|
|
tasks.push(
|
|
|
|
|
|
Promise.all(files.map((f) => uploadFileToServer(f))).then((urls) => {
|
|
|
|
|
|
form.value.officePlaceImageURLs = urls
|
|
|
|
|
|
})
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 应用场景附件多图:按顺序上传
|
|
|
|
|
|
if (scenarioFileList.value.length > 0) {
|
|
|
|
|
|
const files = scenarioFileList.value.filter((f) => f.raw).map((f) => f.raw)
|
|
|
|
|
|
if (files.length > 0) {
|
|
|
|
|
|
tasks.push(
|
|
|
|
|
|
Promise.all(files.map((f) => uploadFileToServer(f))).then((urls) => {
|
|
|
|
|
|
form.value.scenarioAttachmentURLs = urls
|
|
|
|
|
|
})
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 授权代表身份证正反面:人像面 + 国徽面
|
|
|
|
|
|
const frontRaw = authorizedRepIDFrontFileList.value[0]?.raw
|
|
|
|
|
|
const backRaw = authorizedRepIDBackFileList.value[0]?.raw
|
|
|
|
|
|
if (frontRaw || backRaw) {
|
|
|
|
|
|
tasks.push(
|
|
|
|
|
|
(async () => {
|
|
|
|
|
|
const urls = []
|
|
|
|
|
|
if (frontRaw) urls.push(await uploadFileToServer(frontRaw))
|
|
|
|
|
|
if (backRaw) urls.push(await uploadFileToServer(backRaw))
|
|
|
|
|
|
form.value.authorizedRepIDImageURLs = urls
|
|
|
|
|
|
})()
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await Promise.all(tasks)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从 el-upload 的 fileList 中提取 URL 数组(后端接好上传接口后可用 response.url)
|
|
|
|
|
|
const extractUrls = (fileList) => {
|
|
|
|
|
|
return fileList
|
|
|
|
|
|
.map(f => f.url || f.response?.url || f.name)
|
|
|
|
|
|
.filter(Boolean)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 18:30:23 +08:00
|
|
|
|
// 营业执照图片变更:先 OCR 识别,再选择即上传
|
2026-03-17 17:19:00 +08:00
|
|
|
|
const handleBusinessLicenseChange = async (file, fileList) => {
|
|
|
|
|
|
businessLicenseFileList.value = fileList
|
|
|
|
|
|
const urls = extractUrls(fileList)
|
|
|
|
|
|
form.value.businessLicenseImageURL = urls[0] || ''
|
|
|
|
|
|
|
|
|
|
|
|
if (file && file.raw) {
|
|
|
|
|
|
await handleFileChange(file)
|
2026-03-17 18:30:23 +08:00
|
|
|
|
// OCR 若未返回服务器 URL,则选择后立即上传
|
|
|
|
|
|
if (isBlobUrl(form.value.businessLicenseImageURL)) {
|
|
|
|
|
|
const url = await uploadFileOnceSelected(file)
|
|
|
|
|
|
if (url) form.value.businessLicenseImageURL = url
|
|
|
|
|
|
}
|
2026-03-17 17:19:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleBusinessLicenseRemove = (file, fileList) => {
|
|
|
|
|
|
businessLicenseFileList.value = fileList
|
|
|
|
|
|
const urls = extractUrls(fileList)
|
|
|
|
|
|
form.value.businessLicenseImageURL = urls[0] || ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 手动清除营业执照图片(预览区域中的“删除”按钮)
|
|
|
|
|
|
const clearBusinessLicense = () => {
|
|
|
|
|
|
businessLicenseFileList.value = []
|
|
|
|
|
|
form.value.businessLicenseImageURL = ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 18:30:23 +08:00
|
|
|
|
// 授权代表身份证人像面图片变更:选择即上传
|
|
|
|
|
|
const handleAuthorizedRepIDFrontChange = async (file, fileList) => {
|
2026-03-17 17:19:00 +08:00
|
|
|
|
authorizedRepIDFrontFileList.value = fileList
|
2026-03-17 18:30:23 +08:00
|
|
|
|
if (file?.raw && isBlobUrl(file.url)) {
|
|
|
|
|
|
await uploadFileOnceSelected(file)
|
|
|
|
|
|
}
|
2026-03-17 17:19:00 +08:00
|
|
|
|
updateAuthorizedRepIDImageURLs()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleAuthorizedRepIDFrontRemove = (file, fileList) => {
|
|
|
|
|
|
authorizedRepIDFrontFileList.value = fileList
|
|
|
|
|
|
updateAuthorizedRepIDImageURLs()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 18:30:23 +08:00
|
|
|
|
// 授权代表身份证国徽面图片变更:选择即上传
|
|
|
|
|
|
const handleAuthorizedRepIDBackChange = async (file, fileList) => {
|
2026-03-17 17:19:00 +08:00
|
|
|
|
authorizedRepIDBackFileList.value = fileList
|
2026-03-17 18:30:23 +08:00
|
|
|
|
if (file?.raw && isBlobUrl(file.url)) {
|
|
|
|
|
|
await uploadFileOnceSelected(file)
|
|
|
|
|
|
}
|
2026-03-17 17:19:00 +08:00
|
|
|
|
updateAuthorizedRepIDImageURLs()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleAuthorizedRepIDBackRemove = (file, fileList) => {
|
|
|
|
|
|
authorizedRepIDBackFileList.value = fileList
|
|
|
|
|
|
updateAuthorizedRepIDImageURLs()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 手动清除授权代表身份证人像面
|
|
|
|
|
|
const clearAuthorizedRepFront = () => {
|
|
|
|
|
|
authorizedRepIDFrontFileList.value = []
|
|
|
|
|
|
updateAuthorizedRepIDImageURLs()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 手动清除授权代表身份证国徽面
|
|
|
|
|
|
const clearAuthorizedRepBack = () => {
|
|
|
|
|
|
authorizedRepIDBackFileList.value = []
|
|
|
|
|
|
updateAuthorizedRepIDImageURLs()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 汇总授权代表身份证正反面图片URL到一个数组字段
|
|
|
|
|
|
const updateAuthorizedRepIDImageURLs = () => {
|
|
|
|
|
|
const frontUrl = extractUrls(authorizedRepIDFrontFileList.value)[0] || ''
|
|
|
|
|
|
const backUrl = extractUrls(authorizedRepIDBackFileList.value)[0] || ''
|
|
|
|
|
|
const urls = []
|
|
|
|
|
|
if (frontUrl) urls.push(frontUrl)
|
|
|
|
|
|
if (backUrl) urls.push(backUrl)
|
|
|
|
|
|
form.value.authorizedRepIDImageURLs = urls
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 办公场地:拖放文件时通过 handleStart 加入列表
|
|
|
|
|
|
const onOfficePlaceDrop = (e) => {
|
|
|
|
|
|
officePlaceDragover.value = false
|
|
|
|
|
|
const upload = officePlaceUploadRef.value
|
|
|
|
|
|
if (!upload) return
|
|
|
|
|
|
const files = Array.from(e.dataTransfer?.files || []).filter(
|
|
|
|
|
|
(f) => f.type && /^image\/(jpeg|jpg|png|webp)$/i.test(f.type)
|
|
|
|
|
|
)
|
|
|
|
|
|
const limit = 10
|
|
|
|
|
|
const remain = Math.max(0, limit - officePlaceFileList.value.length)
|
|
|
|
|
|
const toAdd = files.slice(0, remain)
|
|
|
|
|
|
for (const file of toAdd) {
|
|
|
|
|
|
if (!beforeUpload(file)) continue
|
|
|
|
|
|
if (typeof file.uid === 'undefined') file.uid = genFileId()
|
|
|
|
|
|
upload.handleStart(file)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (files.length > remain && remain > 0) ElMessage.warning(`最多上传 ${limit} 张,已忽略多余文件`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 应用场景:拖放文件时通过 handleStart 加入列表
|
|
|
|
|
|
const onScenarioDrop = (e) => {
|
|
|
|
|
|
scenarioDragover.value = false
|
|
|
|
|
|
const upload = scenarioUploadRef.value
|
|
|
|
|
|
if (!upload) return
|
|
|
|
|
|
const files = Array.from(e.dataTransfer?.files || []).filter(
|
|
|
|
|
|
(f) => f.type && /^image\/(jpeg|jpg|png|webp)$/i.test(f.type)
|
|
|
|
|
|
)
|
|
|
|
|
|
const limit = 10
|
|
|
|
|
|
const remain = Math.max(0, limit - scenarioFileList.value.length)
|
|
|
|
|
|
const toAdd = files.slice(0, remain)
|
|
|
|
|
|
for (const file of toAdd) {
|
|
|
|
|
|
if (!beforeUpload(file)) continue
|
|
|
|
|
|
if (typeof file.uid === 'undefined') file.uid = genFileId()
|
|
|
|
|
|
upload.handleStart(file)
|
|
|
|
|
|
}
|
|
|
|
|
|
if (files.length > remain && remain > 0) ElMessage.warning(`最多上传 ${limit} 张,已忽略多余文件`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 18:30:23 +08:00
|
|
|
|
// 办公场地图片变更:选择即上传
|
|
|
|
|
|
const handleOfficePlaceChange = async (file, fileList) => {
|
2026-03-17 17:19:00 +08:00
|
|
|
|
officePlaceFileList.value = fileList
|
2026-03-17 18:30:23 +08:00
|
|
|
|
if (file?.raw && isBlobUrl(file.url)) {
|
|
|
|
|
|
await uploadFileOnceSelected(file)
|
|
|
|
|
|
}
|
2026-03-17 17:19:00 +08:00
|
|
|
|
form.value.officePlaceImageURLs = extractUrls(fileList)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleOfficePlaceRemove = (file, fileList) => {
|
|
|
|
|
|
officePlaceFileList.value = fileList
|
|
|
|
|
|
form.value.officePlaceImageURLs = extractUrls(fileList)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 18:30:23 +08:00
|
|
|
|
// 应用场景附件图片变更:选择即上传
|
|
|
|
|
|
const handleScenarioChange = async (file, fileList) => {
|
2026-03-17 17:19:00 +08:00
|
|
|
|
scenarioFileList.value = fileList
|
2026-03-17 18:30:23 +08:00
|
|
|
|
if (file?.raw && isBlobUrl(file.url)) {
|
|
|
|
|
|
await uploadFileOnceSelected(file)
|
|
|
|
|
|
}
|
2026-03-17 17:19:00 +08:00
|
|
|
|
form.value.scenarioAttachmentURLs = extractUrls(fileList)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleScenarioRemove = (file, fileList) => {
|
|
|
|
|
|
scenarioFileList.value = fileList
|
|
|
|
|
|
form.value.scenarioAttachmentURLs = extractUrls(fileList)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:06:44 +08:00
|
|
|
|
// 提交表单
|
|
|
|
|
|
const submitForm = async () => {
|
2026-03-17 17:19:00 +08:00
|
|
|
|
if (submitting.value) return
|
|
|
|
|
|
submitting.value = true
|
2025-11-24 16:06:44 +08:00
|
|
|
|
try {
|
|
|
|
|
|
await enterpriseFormRef.value.validate()
|
|
|
|
|
|
|
2026-02-27 14:49:21 +08:00
|
|
|
|
// 显示确认对话框
|
|
|
|
|
|
await ElMessageBox.confirm(
|
|
|
|
|
|
'提交的信息必须为法人真实信息(包括手机号),如信息有误请联系客服。',
|
|
|
|
|
|
'提交确认',
|
|
|
|
|
|
{
|
|
|
|
|
|
confirmButtonText: '确认提交',
|
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
|
type: 'warning',
|
|
|
|
|
|
distinguishCancelAndClose: true,
|
|
|
|
|
|
customClass: 'submit-confirm-dialog'
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
// 先将所有 blob 图片上传到七牛云,再提交企业信息
|
|
|
|
|
|
try {
|
|
|
|
|
|
await uploadAllBlobFilesAndFillForm()
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
ElMessage.error(err?.message || '图片上传失败,请重试')
|
|
|
|
|
|
submitting.value = false
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调用后端提交接口
|
|
|
|
|
|
const payload = {
|
|
|
|
|
|
company_name: form.value.companyName,
|
|
|
|
|
|
unified_social_code: form.value.unifiedSocialCode,
|
|
|
|
|
|
legal_person_name: form.value.legalPersonName,
|
|
|
|
|
|
legal_person_id: form.value.legalPersonID,
|
|
|
|
|
|
legal_person_phone: form.value.legalPersonPhone,
|
|
|
|
|
|
enterprise_address: form.value.enterpriseAddress,
|
|
|
|
|
|
verification_code: form.value.legalPersonCode,
|
|
|
|
|
|
// 扩展字段
|
|
|
|
|
|
business_license_image_url: form.value.businessLicenseImageURL,
|
|
|
|
|
|
office_place_image_urls: form.value.officePlaceImageURLs,
|
|
|
|
|
|
api_usage: form.value.apiUsage,
|
|
|
|
|
|
scenario_attachment_urls: form.value.scenarioAttachmentURLs,
|
|
|
|
|
|
// 授权代表信息
|
|
|
|
|
|
authorized_rep_name: form.value.authorizedRepName,
|
|
|
|
|
|
authorized_rep_id: form.value.authorizedRepID,
|
|
|
|
|
|
authorized_rep_phone: form.value.authorizedRepPhone,
|
|
|
|
|
|
authorized_rep_id_image_urls: form.value.authorizedRepIDImageURLs
|
|
|
|
|
|
}
|
2025-11-24 16:06:44 +08:00
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
const res = await certificationApi.submitEnterpriseInfo(payload)
|
|
|
|
|
|
if (!res.success) {
|
|
|
|
|
|
throw new Error(res?.error?.message || '提交企业信息失败')
|
|
|
|
|
|
}
|
2025-11-24 16:06:44 +08:00
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
emit('submit', { formData: form.value, response: res })
|
2025-11-24 16:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
2026-02-27 14:49:21 +08:00
|
|
|
|
// 用户点击取消或关闭对话框,不处理
|
|
|
|
|
|
if (error !== 'cancel' && error !== 'close') {
|
|
|
|
|
|
console.error('表单验证失败:', error)
|
|
|
|
|
|
}
|
2025-11-24 16:06:44 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
submitting.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 组件卸载时清理定时器
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
if (countdownTimer) {
|
|
|
|
|
|
clearInterval(countdownTimer)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.step-card {
|
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 卡片头部 */
|
|
|
|
|
|
.card-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-icon {
|
|
|
|
|
|
width: 48px;
|
|
|
|
|
|
height: 48px;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
color: #2563eb;
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-content {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: #1e293b;
|
|
|
|
|
|
margin: 0 0 4px 0;
|
|
|
|
|
|
letter-spacing: -0.025em;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-subtitle {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #64748b;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* OCR紧凑样式 */
|
|
|
|
|
|
.ocr-compact {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: stretch;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
background: linear-gradient(135deg, #f0fdf4 0%, #ecfdf5 100%);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
border: 1px solid rgba(34, 197, 94, 0.2);
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
min-height: 40px;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ocr-header-compact {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
margin-bottom: 4px;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ocr-title-compact {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #166534;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ocr-uploader-compact {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ocr-status-compact {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 3px;
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
color: #166534;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
margin-top: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ocr-status-compact.success {
|
|
|
|
|
|
color: #16a34a;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 表单内容 */
|
|
|
|
|
|
.enterprise-form-content {
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-section {
|
|
|
|
|
|
margin-bottom: 24px;
|
|
|
|
|
|
padding: 24px;
|
|
|
|
|
|
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
border: 1px solid rgba(226, 232, 240, 0.8);
|
|
|
|
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #1e293b;
|
|
|
|
|
|
margin: 0 0 20px 0;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
padding-bottom: 12px;
|
|
|
|
|
|
border-bottom: 2px solid #e2e8f0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.section-title::before {
|
|
|
|
|
|
content: '';
|
|
|
|
|
|
width: 4px;
|
|
|
|
|
|
height: 16px;
|
|
|
|
|
|
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
|
|
|
|
|
border-radius: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
.section-desc {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: #64748b;
|
|
|
|
|
|
margin: 0 0 20px 0;
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:06:44 +08:00
|
|
|
|
/* 表单输入框 */
|
|
|
|
|
|
.form-input :deep(.el-input__wrapper) {
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
border: 1px solid #e2e8f0;
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-input :deep(.el-input__wrapper:hover) {
|
|
|
|
|
|
border-color: #3b82f6;
|
|
|
|
|
|
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-input :deep(.el-input__wrapper.is-focus) {
|
|
|
|
|
|
border-color: #3b82f6;
|
|
|
|
|
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-input :deep(.el-input__inner) {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-17 17:19:00 +08:00
|
|
|
|
/* 拖放区域:包裹 picture-card 上传,支持拖拽图片到整块区域 */
|
|
|
|
|
|
.upload-drop-zone {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
transition: background 0.2s, border-color 0.2s;
|
|
|
|
|
|
}
|
|
|
|
|
|
.upload-drop-zone.is-dragover {
|
|
|
|
|
|
background: var(--el-color-primary-light-9, #ecf5ff);
|
|
|
|
|
|
outline: 2px dashed var(--el-color-primary);
|
|
|
|
|
|
outline-offset: -2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 上传区域基础样式 */
|
|
|
|
|
|
.upload-area {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 保证 picture-card 触发区域整块可点击、可拖拽 */
|
|
|
|
|
|
.upload-trigger-inner {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
min-height: 148px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.upload-icon {
|
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 当已有一张图片时,隐藏单图上传的“+ 选择文件”入口 */
|
|
|
|
|
|
.single-upload-area :deep(.el-upload-list__item + .el-upload--picture-card) {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-24 16:06:44 +08:00
|
|
|
|
/* 验证码按钮 */
|
|
|
|
|
|
.code-btn {
|
|
|
|
|
|
min-width: 100px;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.code-btn:hover:not(:disabled) {
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.code-btn:disabled {
|
|
|
|
|
|
background: #e2e8f0;
|
|
|
|
|
|
color: #94a3b8;
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 表单操作 */
|
|
|
|
|
|
.form-actions {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
padding: 24px;
|
|
|
|
|
|
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
margin-top: 24px;
|
|
|
|
|
|
border: 1px solid rgba(226, 232, 240, 0.8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-btn {
|
|
|
|
|
|
min-width: 200px;
|
|
|
|
|
|
height: 44px;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
box-shadow: 0 4px 16px rgba(59, 130, 246, 0.3);
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-btn:hover {
|
|
|
|
|
|
transform: translateY(-2px);
|
|
|
|
|
|
box-shadow: 0 8px 24px rgba(59, 130, 246, 0.4);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-btn:active {
|
|
|
|
|
|
transform: translateY(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 响应式设计 */
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
|
.enterprise-form-content {
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
padding: 8px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-section {
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 移动端OCR紧凑样式 */
|
|
|
|
|
|
.ocr-compact {
|
|
|
|
|
|
padding: 6px 8px;
|
|
|
|
|
|
min-height: 36px;
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ocr-header-compact {
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
margin-bottom: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ocr-title-compact {
|
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ocr-status-compact {
|
|
|
|
|
|
font-size: 9px;
|
|
|
|
|
|
gap: 2px;
|
|
|
|
|
|
margin-top: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-header {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-icon {
|
|
|
|
|
|
width: 36px;
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-btn {
|
|
|
|
|
|
min-width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.upload-area {
|
|
|
|
|
|
padding: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.upload-icon {
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|
2026-02-27 14:49:21 +08:00
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
|
/* 提交确认对话框样式 */
|
|
|
|
|
|
.submit-confirm-dialog {
|
|
|
|
|
|
max-width: 420px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-confirm-dialog .el-message-box__message {
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
padding: 10px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-confirm-dialog .el-message-box__title {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-confirm-dialog .el-message-box__btns {
|
|
|
|
|
|
padding-top: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-confirm-dialog .el-button--warning {
|
|
|
|
|
|
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-confirm-dialog .el-button--warning:hover {
|
|
|
|
|
|
background: linear-gradient(135deg, #d97706 0%, #b45309 100%);
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(217, 119, 6, 0.3);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-confirm-dialog .el-button--default {
|
|
|
|
|
|
border: 1px solid #dcdfe6;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.submit-confirm-dialog .el-button--default:hover {
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
border-color: #c6e2ff;
|
|
|
|
|
|
background-color: #ecf5ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|