2026-01-06 18:30:25 +08:00

414 lines
14 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.

<!-- 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 />&nbsp;&nbsp;返回
</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>