414 lines
14 KiB
Vue
414 lines
14 KiB
Vue
<!-- src/views/EnterpriseRealNameAuth.vue -->
|
||
<template>
|
||
<div class="enterprise-real-name-auth">
|
||
<!-- 步骤条 -->
|
||
<div style="width: 300px;display: flex;align-items: center;gap:16px;">
|
||
<div style="color:#666;cursor: pointer;" @click="router.back()">
|
||
<ArrowLeftOutlined /> 返回
|
||
</div>
|
||
<div style="color:#666;">|</div>
|
||
<div style="font-size: 18px;">企业认证</div>
|
||
</div>
|
||
<div style="color: #666;margin: 30px 0;">Fast亼算云严格遵守国家相关个人信息隐私保护规定,并不存储使用您的个人信息,请完成相关认证。</div>
|
||
<div style="width: 100%;height: 1px;background: #c9c9c9;margin-bottom: 30px;"></div>
|
||
<!-- 表单 -->
|
||
<a-form ref="formRef" :model="formState" layout="horizontal" class="auth-form" style="max-width: 600px;">
|
||
<a-form-item label="企业证件类型:" name="companyDocumentType" :rules="[{ required: true, message: '请选择企业证件类型' }]">
|
||
<a-select v-model:value="formState.companyDocumentType" placeholder="请选择">
|
||
<a-select-option value="business_license">营业执照</a-select-option>
|
||
<!-- 可扩展其他类型 -->
|
||
</a-select>
|
||
</a-form-item>
|
||
<a-form-item label="上传证件照:" :rules="[{ required: true, validator: validateBusinessLicense }]">
|
||
<div class="upload-area" style="display: flex;justify-items: flex-start;align-items: center;">
|
||
<div>
|
||
<a-upload name="file" list-type="picture-card" :show-upload-list="false" :before-upload="beforeUpload"
|
||
@change="handleBusinessLicenseChange" accept="image/png,image/jpeg" class="avatar-uploader3">
|
||
<div class="upload-placeholder">
|
||
<img src="@/assets/camer.png" alt="" srcset="" width="30px">
|
||
<div style="margin-top: 8px">上传营业执照</div>
|
||
</div>
|
||
</a-upload>
|
||
<div v-if="formState.company_license" class="upload-preview">
|
||
<img :src="formState.company_license" alt="营业执照" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="upload-tips">支持 jpg、jpeg、png 格式图片,大小不超过 10M</div>
|
||
</a-form-item>
|
||
<a-form-item label="企业名称" name="company_name" :rules="[{ required: true, message: '请输入企业名称' }]">
|
||
<a-input v-model:value="formState.company_name" placeholder="请输入企业名称" />
|
||
</a-form-item>
|
||
<a-form-item label="统一社会信用代码" name="unified_social_credit_code"
|
||
:rules="[{ required: true, message: '请输入统一社会信用代码' }]">
|
||
<a-input v-model:value="formState.unified_social_credit_code" placeholder="请输入统一社会信用代码" />
|
||
</a-form-item>
|
||
<hr class="dashed-line" style="border-top: 1px dashed #c9c9c9; margin: 20px 0;">
|
||
<a-form-item label="您的身份" name="identity" :rules="[{ required: true, message: '请输入真实姓名' }]">
|
||
<a-radio-group v-model:value="formState.identity" name="identity">
|
||
<a-radio value="LegalPerson">企业法人</a-radio>
|
||
<a-radio value="AuthorizedPerson">被授权人</a-radio>
|
||
</a-radio-group>
|
||
</a-form-item>
|
||
<a-form-item label="真实姓名" name="realName" :rules="[{ required: true, message: '请输入真实姓名' }]">
|
||
<a-input v-model:value="formState.realName" placeholder="请输入真实姓名" />
|
||
</a-form-item>
|
||
<a-form-item label="证件类型:" name="documentType" :rules="[{ required: true, message: '请选择企业证件类型' }]">
|
||
<a-select v-model:value="formState.documentType" placeholder="请选择">
|
||
<a-select-option value="身份证">中国大陆二代居民身份证</a-select-option>
|
||
<!-- 可扩展其他类型 -->
|
||
</a-select>
|
||
</a-form-item>
|
||
<a-form-item label="上传证件照:" :rules="[{ required: true, validator: validateBusinessLicense }]">
|
||
<div class="upload-area" style="display: flex;justify-items: flex-start;align-items: center;">
|
||
<div>
|
||
<a-upload name="file" list-type="picture-card" :show-upload-list="false" :before-upload="beforeUpload"
|
||
@change="handleBusinessLicenseChange" accept="image/png,image/jpeg" class="avatar-uploader">
|
||
<div class="upload-placeholder">
|
||
<img src="@/assets/camer.png" alt="" srcset="" width="30px">
|
||
<div style="margin-top: 8px">拍摄身份证正面</div>
|
||
</div>
|
||
</a-upload>
|
||
<div v-if="formState.id_card_front" class="upload-preview">
|
||
<img :src="formState.id_card_front" alt="身份证正面" />
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<a-upload name="file" list-type="picture-card" :show-upload-list="false" :before-upload="beforeUpload"
|
||
@change="handleBusinessLicenseChange" accept="image/png,image/jpeg" class="avatar-uploader2">
|
||
<div class="upload-placeholder">
|
||
<img src="@/assets/camer.png" alt="" srcset="" width="30px">
|
||
<div style="margin-top: 8px">拍摄身份证正面</div>
|
||
</div>
|
||
</a-upload>
|
||
<div v-if="formState.id_card_back" class="upload-preview">
|
||
<img :src="formState.id_card_back" alt="身份证反面" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="upload-tips">支持 jpg、jpeg、png 格式图片,大小不超过 10M</div>
|
||
</a-form-item>
|
||
|
||
<a-form-item label="身份证号" name="id_card"
|
||
:rules="[{ required: true, message: '请输入身份证号' }, { pattern: /^\d{17}[\dXx]$/, message: '请输入有效的18位身份证号码' }]">
|
||
<a-input v-model:value="formState.id_card" placeholder="请输入身份证号" />
|
||
</a-form-item>
|
||
|
||
<a-form-item label="证件有效期" name="creditCode"
|
||
:rules="[{ required: true, message: '请选择证件有效期' }, { type: 'array', message: '请选择证件有效期' }]">
|
||
<a-range-picker v-model:value="formState.creditCode" style="width: 100%;" />
|
||
</a-form-item>
|
||
<a-form-item v-if="formState.identity === 'AuthorizedPerson'" label="授权书" name="book"
|
||
:rules="[{ required: true, message: '请上传授权书' }]">
|
||
<a-upload name="file" list-type="picture-card" :show-upload-list="false" :before-upload="beforeUpload"
|
||
@change="handleBusinessLicenseChange" accept="image/png,image/jpeg">
|
||
<div class="upload-placeholder">
|
||
<div style="margin-top: 8px">上传授权书</div>
|
||
</div>
|
||
</a-upload>
|
||
<div v-if="formState.power_of_attorney" class="upload-preview">
|
||
<img :src="formState.power_of_attorney" alt="授权书" />
|
||
</div>
|
||
<div style="color:#1677ff;">
|
||
<DownloadOutlined />
|
||
授权书下载
|
||
</div>
|
||
</a-form-item>
|
||
<a-form-item name="phone" label="手机号" :rules="[{ required: true, message: '请输入手机号!' }]">
|
||
<SmsCodeInput v-model:value="formState.phone" />
|
||
</a-form-item>
|
||
<a-form-item name="code" label="验证码" :rules="[{ required: true, message: '请输入验证码!' }]">
|
||
<a-input v-model:value="formState.code" placeholder="请输入验证码" />
|
||
</a-form-item>
|
||
<!-- 协议同意 -->
|
||
<div>
|
||
<a-checkbox v-model:checked="formState.agreed">
|
||
您理解并同意
|
||
<a href="/docs/real_name_cert/" target="_blank">《实名认证协议》</a>,
|
||
Fast亼算云有权自行或委托第三方,审查您在实名认证时提供的信息是否真实、准确及有效。若提供虚假信息,由此带来的后果全部由您承担。
|
||
</a-checkbox>
|
||
</div>
|
||
<div style="margin-top: 20px;text-align: center;">
|
||
<a-button type="primary" @click="handleSubmit" block :loading="btnLoading">立即认证</a-button>
|
||
</div>
|
||
</a-form>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import {
|
||
ref,
|
||
reactive,
|
||
} from 'vue';
|
||
import {
|
||
message,
|
||
FormInstance,
|
||
UploadProps
|
||
} from 'ant-design-vue';
|
||
import {
|
||
UserOutlined,
|
||
IdcardOutlined,
|
||
ArrowLeftOutlined,
|
||
DownloadOutlined
|
||
|
||
} from '@ant-design/icons-vue';
|
||
import { useRouter } from 'vue-router';
|
||
import { enterpriseCertification } from '@/apis/certification';
|
||
import SmsCodeInput from '@/components/SmsCodeInput.vue';
|
||
import { fetchUserInfo } from '@/apis/modules/login';
|
||
import dayjs from 'dayjs'
|
||
const router = useRouter();
|
||
// 表单引用
|
||
const formRef = ref<FormInstance>();
|
||
const btnLoading = ref(false);
|
||
// 表单数据
|
||
interface FormState {
|
||
companyDocumentType: string | null;
|
||
documentType: string | null;
|
||
company_name: string;
|
||
unified_social_credit_code: string;
|
||
identity: 'LegalPerson' | 'AuthorizedPerson' | null;
|
||
name: string;
|
||
idNumber: string;
|
||
agreed: boolean;
|
||
phone: string;
|
||
code: string;
|
||
realName: string;
|
||
company_license: string | null;
|
||
power_of_attorney: string | null;
|
||
id_card_back: string | null;
|
||
id_card_front: string | null;
|
||
id_card: string | null;
|
||
certification_start?: string;
|
||
certification_end?: string;
|
||
creditCode?: any[];
|
||
}
|
||
|
||
const formState = reactive<FormState>({
|
||
companyDocumentType: '',
|
||
documentType: null,
|
||
company_name: '',
|
||
unified_social_credit_code: '',
|
||
identity: 'LegalPerson',
|
||
id_card_back: "",
|
||
id_card_front: "",
|
||
name: '',
|
||
idNumber: '',
|
||
agreed: false,
|
||
phone: '',
|
||
code: '',
|
||
realName: '',
|
||
company_license: "",
|
||
power_of_attorney: "",
|
||
id_card: "",
|
||
certification_start: '',
|
||
certification_end: ''
|
||
});
|
||
|
||
// 文件大小限制:10MB
|
||
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
||
|
||
// 上传前校验
|
||
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
||
const isLt10M = file.size < MAX_FILE_SIZE;
|
||
if (!isLt10M) {
|
||
message.error('文件大小不能超过 10MB!');
|
||
}
|
||
const isValidType = ['image/jpeg', 'image/png'].includes(file.type);
|
||
if (!isValidType) {
|
||
message.error('仅支持 JPG/PNG 格式!');
|
||
}
|
||
return isLt10M && isValidType;
|
||
};
|
||
|
||
// 处理营业执照上传
|
||
const handleBusinessLicenseChange = (info: UploadChangeParam<UploadFile>) => {
|
||
if (info.file.status === 'done') {
|
||
// 模拟获取 URL(实际应调用上传接口)
|
||
const url = URL.createObjectURL(info.file.originFileObj!);
|
||
formState.id_card_front = url;
|
||
}
|
||
};
|
||
|
||
// 处理身份证正面
|
||
const handleIdCardFrontChange = (info: UploadChangeParam<UploadFile>) => {
|
||
if (info.file.status === 'done') {
|
||
const url = URL.createObjectURL(info.file.originFileObj!);
|
||
formState.idCardFrontUrl = url;
|
||
}
|
||
};
|
||
|
||
// 处理身份证背面
|
||
const handleIdCardBackChange = (info: UploadChangeParam<UploadFile>) => {
|
||
if (info.file.status === 'done') {
|
||
const url = URL.createObjectURL(info.file.originFileObj!);
|
||
formState.idCardBackUrl = url;
|
||
}
|
||
};
|
||
|
||
// 自定义校验函数
|
||
const validateBusinessLicense = () => {
|
||
if (!formState.id_card_front) {
|
||
return Promise.reject(new Error('请上传证件照'));
|
||
}
|
||
return Promise.resolve();
|
||
};
|
||
|
||
const validateIdCardFront = () => {
|
||
if (!formState.idCardFrontUrl) {
|
||
return Promise.reject(new Error('请上传身份证正面'));
|
||
}
|
||
return Promise.resolve();
|
||
};
|
||
|
||
const validateIdCardBack = () => {
|
||
if (!formState.idCardBackUrl) {
|
||
return Promise.reject(new Error('请上传身份证背面'));
|
||
}
|
||
return Promise.resolve();
|
||
};
|
||
|
||
// 提交
|
||
const handleSubmit = async () => {
|
||
|
||
formRef.value?.validateFields().then(async () => {
|
||
try {
|
||
if (!formState.agreed) {
|
||
message.error('请阅读并同意协议');
|
||
return;
|
||
}
|
||
btnLoading.value = true;
|
||
formState.id_card_front = 'https://example.com/id_card_front.jpg'
|
||
formState.id_card_back = 'https://example.com/id_card_back.jpg'
|
||
if (formState.creditCode) {
|
||
formState.certification_start = dayjs(formState.creditCode[0]).format('YYYY-MM-DD');
|
||
formState.certification_end = dayjs(formState.creditCode[1]).format('YYYY-MM-DD');
|
||
}
|
||
const res = await enterpriseCertification(formState);
|
||
btnLoading.value = false;
|
||
message.success('认证提交成功');
|
||
const userRes = await fetchUserInfo();
|
||
localStorage.setItem('userInfo', JSON.stringify(userRes));
|
||
router.push('/layout/admin/realnameAuth');
|
||
} catch (error: any) {
|
||
console.log('Validation failed:', error);
|
||
message.error(error)
|
||
btnLoading.value = false;
|
||
}
|
||
|
||
});
|
||
// TODO: 调用 API 提交表单
|
||
|
||
};
|
||
|
||
// 取消
|
||
const handleCancel = () => {
|
||
// TODO: 返回上一页或重置
|
||
message.info('已取消');
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.enterprise-real-name-auth {
|
||
padding: 24px;
|
||
background-color: #fff;
|
||
/* min-height: 100vh; */
|
||
}
|
||
|
||
.steps {
|
||
max-width: 800px;
|
||
margin-bottom: 32px;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #1f2937;
|
||
margin: 24px 0 16px;
|
||
}
|
||
|
||
.upload-area {
|
||
display: inline-block;
|
||
margin-right: 24px;
|
||
position: relative;
|
||
}
|
||
|
||
.upload-placeholder {
|
||
text-align: center;
|
||
color: #666;
|
||
}
|
||
|
||
.upload-placeholder i {
|
||
font-size: 24px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.upload-preview {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.upload-preview img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.id-card-uploads {
|
||
display: flex;
|
||
gap: 24px;
|
||
}
|
||
|
||
.upload-tips {
|
||
margin-top: 8px;
|
||
font-size: 12px;
|
||
color: #666;
|
||
}
|
||
|
||
/* 响应式 */
|
||
@media (max-width: 768px) {
|
||
.auth-form :deep(.ant-form-item-label) {
|
||
text-align: left;
|
||
}
|
||
|
||
.id-card-uploads {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.upload-area {
|
||
margin-right: 0;
|
||
}
|
||
}
|
||
|
||
::v-deep .avatar-uploader .ant-upload.ant-upload-select {
|
||
width: 200px;
|
||
overflow: hidden;
|
||
border: none !important;
|
||
background: url("@/assets/card1.png") no-repeat center;
|
||
background-size: contain;
|
||
/* 或者 'contain' 根据需求选择 */
|
||
}
|
||
|
||
::v-deep .avatar-uploader2 .ant-upload.ant-upload-select {
|
||
width: 200px;
|
||
overflow: hidden;
|
||
border: none !important;
|
||
background: url("@/assets/card2.png") no-repeat center;
|
||
background-size: contain;
|
||
/* 或者 'contain' 根据需求选择 */
|
||
}
|
||
|
||
::v-deep .avatar-uploader3 .ant-upload.ant-upload-select {
|
||
width: 200px;
|
||
overflow: hidden;
|
||
border: none !important;
|
||
background: url("@/assets/yyzz.png") no-repeat center;
|
||
background-size: contain;
|
||
/* 或者 'contain' 根据需求选择 */
|
||
}
|
||
</style>
|