feat(hjc): 企业注册一站式——证件材料同事务入库 + 阿里云OCR识别 + 匿名注册上传

- HjcEnterprise 新增 idCardNo(经办人身份证号),配套迁移:
  src/main/resources/sql/hjc_enterprise_add_id_card_no.sql(需在目标库执行)
- HjcAuthRequest 新增 idCardNo / materials;/hjc/auth/register 同事务保存 4 类证件材料,
  并按「企业联系电话、企业地址选填,其余必填」补充后端校验
- 新增 POST /hjc/auth/upload:注册页登录前的匿名证件上传(复用 FileServerUtil,
  按 setting:upload 决定自建文件服 / OSS 域名;不写 file_record 表)
- 新增 POST /hjc/ocr/recognize:阿里云文字识别 OCR(aliyun-java-sdk-ocr 1.0.6)
  · idcard_front → agentName / idCardNo
  · license → creditCode / address(企业名称与法定代表人仅返回,供前端只读核对)
  · AK 走 aliyun.ocr.*,当前为占位空值;未配置时返回失败,由前端提示手动填写、不阻断注册
- SecurityConfig:/hjc/auth/upload 与 /hjc/ocr/recognize 匿名放行(与后台 /file/upload 隔离)
This commit is contained in:
2026-09-10 13:12:10 +08:00
parent 9d188d304b
commit 08138f1f04
14 changed files with 372 additions and 2 deletions
+6
View File
@@ -213,6 +213,12 @@
<artifactId>aliyun-java-sdk-core</artifactId> <artifactId>aliyun-java-sdk-core</artifactId>
<version>4.4.3</version> <version>4.4.3</version>
</dependency> </dependency>
<!--阿里云文字识别 OCR(身份证/营业执照识别)-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-ocr</artifactId>
<version>1.0.6</version>
</dependency>
<!--阿里支付 老版本 SDK--> <!--阿里支付 老版本 SDK-->
<dependency> <dependency>
<groupId>com.alipay.sdk</groupId> <groupId>com.alipay.sdk</groupId>
@@ -82,7 +82,10 @@ public class SecurityConfig {
"/api/shop/order-delivery/notify", "/api/shop/order-delivery/notify",
"/api/hjc/push/project", "/api/hjc/push/project",
"/api/hjc/auth/register", "/api/hjc/auth/register",
"/api/hjc/auth/login" "/api/hjc/auth/login",
// 注册页专用:证件上传与 OCR 识别在登录前发生
"/api/hjc/auth/upload",
"/api/hjc/ocr/recognize"
) )
.permitAll() .permitAll()
.anyRequest() .anyRequest()
@@ -1,10 +1,13 @@
package com.gxwebsoft.hjc.controller; package com.gxwebsoft.hjc.controller;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gxwebsoft.common.core.config.ConfigProperties; import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.security.JwtSubject; import com.gxwebsoft.common.core.security.JwtSubject;
import com.gxwebsoft.common.core.security.JwtUtil; import com.gxwebsoft.common.core.security.JwtUtil;
import com.gxwebsoft.common.core.utils.FileServerUtil;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController; import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.Role; import com.gxwebsoft.common.system.entity.Role;
@@ -16,6 +19,8 @@ import com.gxwebsoft.common.system.service.UserRoleService;
import com.gxwebsoft.common.system.service.UserService; import com.gxwebsoft.common.system.service.UserService;
import com.gxwebsoft.hjc.dto.HjcAuthRequest; import com.gxwebsoft.hjc.dto.HjcAuthRequest;
import com.gxwebsoft.hjc.entity.HjcEnterprise; import com.gxwebsoft.hjc.entity.HjcEnterprise;
import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial;
import com.gxwebsoft.hjc.service.HjcEnterpriseMaterialService;
import com.gxwebsoft.hjc.service.HjcEnterpriseService; import com.gxwebsoft.hjc.service.HjcEnterpriseService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -23,9 +28,16 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* 汇吉采 网站企业 注册/登录(企业名称+密码) * 汇吉采 网站企业 注册/登录(企业名称+密码)
@@ -45,14 +57,61 @@ public class HjcAuthController extends BaseController {
private ConfigProperties configProperties; private ConfigProperties configProperties;
@Resource @Resource
private HjcEnterpriseService hjcEnterpriseService; private HjcEnterpriseService hjcEnterpriseService;
@Resource
private HjcEnterpriseMaterialService hjcEnterpriseMaterialService;
@Resource
private RedisUtil redisUtil;
@Operation(summary = "企业注册(企业名称+密码,注册后待审核)") /** 注册必传的资质证件材料类型 */
private static final List<String> REQUIRED_MATERIAL_TYPES =
Arrays.asList("idcard_front", "idcard_back", "handbook", "license");
@Operation(summary = "注册证件上传(匿名,注册页专用,不写文件表)")
@PostMapping("/upload")
public ApiResult<Map<String, Object>> upload(@RequestParam("file") MultipartFile file) {
if (file == null || file.isEmpty()) {
return fail("上传文件不能为空", null);
}
try {
String dir = configProperties.getUploadPath();
File upload = FileServerUtil.upload(file, dir, Boolean.TRUE.equals(configProperties.getUploadUuidName()));
String path = upload.getAbsolutePath().replace("\\", "/").substring(dir.length() - 1);
// 默认走自建文件服务器
String url = configProperties.getFileServer() + "/api/file" + path;
// 云存储(OSS)时改用 bucketDomain
Integer tenantId = getTenantId();
if (tenantId != null) {
JSONObject setting = JSONObject.parseObject(redisUtil.get("setting:upload:" + tenantId));
if (setting != null) {
String uploadMethod = setting.getString("uploadMethod");
String bucketDomain = setting.getString("bucketDomain");
if (StrUtil.isNotBlank(uploadMethod) && !"file".equals(uploadMethod)
&& StrUtil.isNotBlank(bucketDomain)) {
url = bucketDomain + path;
}
}
}
Map<String, Object> data = new HashMap<>(4);
data.put("url", url);
data.put("name", file.getOriginalFilename());
return success(data);
} catch (Exception e) {
e.printStackTrace();
return fail("上传失败", null);
}
}
@Operation(summary = "企业注册(一站式:企业+经办人+授权+证件,提交后待审核)")
@PostMapping("/register") @PostMapping("/register")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ApiResult<LoginResult> register(@RequestBody HjcAuthRequest request) { public ApiResult<LoginResult> register(@RequestBody HjcAuthRequest request) {
if (StrUtil.isBlank(request.getEnterpriseName()) || StrUtil.isBlank(request.getPassword())) { if (StrUtil.isBlank(request.getEnterpriseName()) || StrUtil.isBlank(request.getPassword())) {
return fail("企业名称和密码不能为空", null); return fail("企业名称和密码不能为空", null);
} }
String invalid = validateRegister(request);
if (invalid != null) {
return fail(invalid, null);
}
Integer tenantId = getTenantId(); Integer tenantId = getTenantId();
if (tenantId == null) { if (tenantId == null) {
return fail("租户ID不能为空", null); return fail("租户ID不能为空", null);
@@ -97,16 +156,69 @@ public class HjcAuthController extends BaseController {
enterprise.setAgentName(request.getAgentName()); enterprise.setAgentName(request.getAgentName());
enterprise.setAgentEmail(request.getAgentEmail()); enterprise.setAgentEmail(request.getAgentEmail());
enterprise.setAgentPhone(request.getAgentPhone()); enterprise.setAgentPhone(request.getAgentPhone());
enterprise.setIdCardNo(request.getIdCardNo());
enterprise.setAuthorizeExpire(request.getAuthorizeExpire()); enterprise.setAuthorizeExpire(request.getAuthorizeExpire());
enterprise.setAuthStatus(0); enterprise.setAuthStatus(0);
enterprise.setTenantId(tenantId); enterprise.setTenantId(tenantId);
hjcEnterpriseService.save(enterprise); hjcEnterpriseService.save(enterprise);
// 一站式注册:同事务保存资质证件材料
List<HjcEnterpriseMaterial> materials = request.getMaterials();
if (materials != null) {
for (HjcEnterpriseMaterial m : materials) {
if (StrUtil.isBlank(m.getFileUrl())) {
continue;
}
m.setId(null);
m.setEnterpriseId(enterprise.getId());
m.setTenantId(tenantId);
hjcEnterpriseMaterialService.save(m);
}
}
String token = JwtUtil.buildToken(new JwtSubject(user.getUsername(), user.getTenantId()), String token = JwtUtil.buildToken(new JwtSubject(user.getUsername(), user.getTenantId()),
configProperties.getTokenExpireTime(), configProperties.getTokenKey()); configProperties.getTokenExpireTime(), configProperties.getTokenKey());
return success("注册成功", new LoginResult(token, user)); return success("注册成功", new LoginResult(token, user));
} }
/**
* 注册必填校验:企业联系电话、企业地址选填,其余必填;4 类证件必传
*
* @return 错误信息;校验通过返回 null
*/
private String validateRegister(HjcAuthRequest request) {
if (StrUtil.isBlank(request.getCreditCode())) {
return "纳税人识别号不能为空";
}
if (StrUtil.isBlank(request.getContactEmail())) {
return "企业邮箱不能为空";
}
if (StrUtil.isBlank(request.getAgentName())) {
return "经办人姓名不能为空";
}
if (StrUtil.isBlank(request.getAgentEmail())) {
return "经办人邮箱不能为空";
}
if (StrUtil.isBlank(request.getAgentPhone())) {
return "经办人手机号不能为空";
}
if (StrUtil.isBlank(request.getIdCardNo())) {
return "经办人身份证号不能为空";
}
if (request.getAuthorizeExpire() == null) {
return "授权到期时间不能为空";
}
List<HjcEnterpriseMaterial> materials = request.getMaterials();
for (String type : REQUIRED_MATERIAL_TYPES) {
boolean present = materials != null && materials.stream()
.anyMatch(m -> type.equals(m.getMaterialType()) && StrUtil.isNotBlank(m.getFileUrl()));
if (!present) {
return "请上传全部证件(身份证正反面、授权委托书、营业执照)";
}
}
return null;
}
@Operation(summary = "企业登录(企业名称+密码)") @Operation(summary = "企业登录(企业名称+密码)")
@PostMapping("/login") @PostMapping("/login")
public ApiResult<LoginResult> login(@RequestBody HjcAuthRequest request) { public ApiResult<LoginResult> login(@RequestBody HjcAuthRequest request) {
@@ -0,0 +1,41 @@
package com.gxwebsoft.hjc.controller;
import cn.hutool.core.util.StrUtil;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.hjc.dto.HjcOcrRecognizeRequest;
import com.gxwebsoft.hjc.dto.HjcOcrResult;
import com.gxwebsoft.hjc.service.HjcOcrService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 汇吉采 证件 OCR 识别(注册页在登录前调用,SecurityConfig 已匿名放行)
*/
@Tag(name = "汇吉采-证件OCR")
@RestController
@RequestMapping("/api/hjc/ocr")
public class HjcOcrController extends BaseController {
@Resource
private HjcOcrService hjcOcrService;
@Operation(summary = "识别证件(身份证人像面/营业执照),回填表单字段")
@PostMapping("/recognize")
public ApiResult<HjcOcrResult> recognize(@RequestBody HjcOcrRecognizeRequest request) {
if (StrUtil.isBlank(request.getMaterialType()) || StrUtil.isBlank(request.getFileUrl())) {
return fail("materialType 与 fileUrl 不能为空", null);
}
HjcOcrResult result = hjcOcrService.recognize(request.getMaterialType(), request.getFileUrl());
if (result == null) {
return fail("识别失败或该类型无需识别,请手动填写", null);
}
return success(result);
}
}
@@ -1,10 +1,12 @@
package com.gxwebsoft.hjc.dto; package com.gxwebsoft.hjc.dto;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
/** /**
* 汇吉采 网站企业 注册/登录 请求(企业名称+密码) * 汇吉采 网站企业 注册/登录 请求(企业名称+密码)
@@ -40,7 +42,13 @@ public class HjcAuthRequest {
@Schema(description = "经办人手机号") @Schema(description = "经办人手机号")
private String agentPhone; private String agentPhone;
@Schema(description = "经办人身份证号")
private String idCardNo;
@Schema(description = "授权委托书到期时间") @Schema(description = "授权委托书到期时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime authorizeExpire; private LocalDateTime authorizeExpire;
@Schema(description = "资质证件材料")
private List<HjcEnterpriseMaterial> materials;
} }
@@ -0,0 +1,18 @@
package com.gxwebsoft.hjc.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 汇吉采 证件 OCR 识别请求
*/
@Data
@Schema(name = "HjcOcrRecognizeRequest", description = "汇吉采证件OCR识别请求")
public class HjcOcrRecognizeRequest {
@Schema(description = "材料类型:idcard_front(身份证人像面)/ license(营业执照)", required = true)
private String materialType;
@Schema(description = "已上传证件的可访问地址(fileUrl)", required = true)
private String fileUrl;
}
@@ -0,0 +1,36 @@
package com.gxwebsoft.hjc.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 汇吉采 证件 OCR 识别结果
*
* <p>字段按材料类型填写:营业执照填 enterpriseName/creditCode/address/legalPerson
* 身份证人像面填 agentName/idCardNo;未识别到的字段为 null。</p>
*/
@Data
@Schema(name = "HjcOcrResult", description = "汇吉采证件OCR识别结果")
public class HjcOcrResult {
@Schema(description = "材料类型:idcard_front / license")
private String materialType;
@Schema(description = "营业执照-企业名称(仅作只读核对,不覆盖登录账号)")
private String enterpriseName;
@Schema(description = "营业执照-统一社会信用代码")
private String creditCode;
@Schema(description = "营业执照-住所/企业地址")
private String address;
@Schema(description = "营业执照-法定代表人(仅展示供人工参考)")
private String legalPerson;
@Schema(description = "身份证-经办人姓名")
private String agentName;
@Schema(description = "身份证-经办人身份证号")
private String idCardNo;
}
@@ -55,6 +55,9 @@ public class HjcEnterprise implements Serializable {
@Schema(description = "经办人手机号") @Schema(description = "经办人手机号")
private String agentPhone; private String agentPhone;
@Schema(description = "经办人身份证号")
private String idCardNo;
@Schema(description = "授权委托书到期时间") @Schema(description = "授权委托书到期时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime authorizeExpire; private LocalDateTime authorizeExpire;
@@ -0,0 +1,18 @@
package com.gxwebsoft.hjc.service;
import com.gxwebsoft.hjc.dto.HjcOcrResult;
/**
* 汇吉采 证件 OCR 识别(阿里云文字识别 OCR,服务端调用)
*/
public interface HjcOcrService {
/**
* 识别证件
*
* @param materialType 材料类型:idcard_front(身份证人像面)/ license(营业执照)
* @param fileUrl 已上传证件的可访问地址
* @return 识别结果;不支持的材料类型或识别失败返回 null
*/
HjcOcrResult recognize(String materialType, String fileUrl);
}
@@ -0,0 +1,107 @@
package com.gxwebsoft.hjc.service.impl;
import cn.hutool.core.util.StrUtil;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.ocr.model.v20191230.RecognizeBusinessLicenseRequest;
import com.aliyuncs.ocr.model.v20191230.RecognizeBusinessLicenseResponse;
import com.aliyuncs.ocr.model.v20191230.RecognizeIdentityCardRequest;
import com.aliyuncs.ocr.model.v20191230.RecognizeIdentityCardResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.gxwebsoft.hjc.dto.HjcOcrResult;
import com.gxwebsoft.hjc.service.HjcOcrService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* 汇吉采 证件 OCR 识别实现(阿里云文字识别 OCR)
*
* <p>AK 需具备 OCR 服务权限;未配置(占位值为空)时直接返回 null,由前端提示「识别失败,请手动填写」,
* 不阻断注册流程。</p>
*/
@Service
public class HjcOcrServiceImpl implements HjcOcrService {
/** 材料类型:身份证人像面 */
public static final String MATERIAL_IDCARD_FRONT = "idcard_front";
/** 材料类型:营业执照 */
public static final String MATERIAL_LICENSE = "license";
@Value("${aliyun.ocr.access-key-id:}")
private String accessKeyId;
@Value("${aliyun.ocr.access-key-secret:}")
private String accessKeySecret;
@Value("${aliyun.ocr.region:cn-hangzhou}")
private String region;
@Value("${aliyun.ocr.endpoint:ocr-api.cn-hangzhou.aliyuncs.com}")
private String endpoint;
@Override
public HjcOcrResult recognize(String materialType, String fileUrl) {
if (StrUtil.isBlank(materialType) || StrUtil.isBlank(fileUrl)) {
return null;
}
if (StrUtil.isBlank(accessKeyId) || StrUtil.isBlank(accessKeySecret)) {
// OCR 未配置 AK(占位),不阻断注册
System.out.println("HjcOcr: aliyun.ocr 未配置 AccessKey,跳过识别");
return null;
}
try {
IAcsClient client = createClient();
if (MATERIAL_IDCARD_FRONT.equals(materialType)) {
return recognizeIdCard(client, fileUrl);
}
if (MATERIAL_LICENSE.equals(materialType)) {
return recognizeBusinessLicense(client, fileUrl);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private IAcsClient createClient() throws Exception {
DefaultProfile profile = DefaultProfile.getProfile(region, accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint(region, region, "ocr", endpoint);
return new DefaultAcsClient(profile);
}
/** 身份证人像面:回填经办人姓名 + 身份证号 */
private HjcOcrResult recognizeIdCard(IAcsClient client, String fileUrl) throws Exception {
RecognizeIdentityCardRequest request = new RecognizeIdentityCardRequest();
request.setImageURL(fileUrl);
request.setSide("face");
RecognizeIdentityCardResponse response = client.getAcsResponse(request);
if (response == null || response.getData() == null
|| response.getData().getFrontResult() == null) {
return null;
}
RecognizeIdentityCardResponse.Data.FrontResult front = response.getData().getFrontResult();
HjcOcrResult result = new HjcOcrResult();
result.setMaterialType(MATERIAL_IDCARD_FRONT);
result.setAgentName(front.getName());
result.setIdCardNo(front.getIDNumber());
return result;
}
/** 营业执照:回填统一社会信用代码 + 企业地址;企业名称/法定代表人仅作展示提示 */
private HjcOcrResult recognizeBusinessLicense(IAcsClient client, String fileUrl) throws Exception {
RecognizeBusinessLicenseRequest request = new RecognizeBusinessLicenseRequest();
request.setImageURL(fileUrl);
RecognizeBusinessLicenseResponse response = client.getAcsResponse(request);
if (response == null || response.getData() == null) {
return null;
}
RecognizeBusinessLicenseResponse.Data data = response.getData();
HjcOcrResult result = new HjcOcrResult();
result.setMaterialType(MATERIAL_LICENSE);
result.setEnterpriseName(data.getName());
result.setCreditCode(data.getRegisterNumber());
result.setAddress(data.getAddress());
result.setLegalPerson(data.getLegalPerson());
return result;
}
}
+6
View File
@@ -77,3 +77,9 @@ aliyun:
access-key-id: LTAI5tEsyhW4GCKbds1qsopg access-key-id: LTAI5tEsyhW4GCKbds1qsopg
access-key-secret: zltFlQrYVAoq2KMFDWgLa3GhkMNeyO access-key-secret: zltFlQrYVAoq2KMFDWgLa3GhkMNeyO
endpoint: mt.cn-hangzhou.aliyuncs.com endpoint: mt.cn-hangzhou.aliyuncs.com
# 阿里云文字识别 OCR(身份证/营业执照识别),AK 需具备 OCR 服务权限;未开通前为占位值
ocr:
access-key-id: ""
access-key-secret: ""
region: cn-hangzhou
endpoint: ocr-api.cn-hangzhou.aliyuncs.com
+8
View File
@@ -105,6 +105,14 @@ config:
bucketDomain: https://oss.wsdns.cn bucketDomain: https://oss.wsdns.cn
aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com aliyunDomain: https://oss-gxwebsoft.oss-cn-shenzhen.aliyuncs.com
# 阿里云文字识别 OCR(身份证/营业执照识别),AK 需具备 OCR 服务权限;未开通前为占位值
aliyun:
ocr:
access-key-id: ""
access-key-secret: ""
region: cn-hangzhou
endpoint: ocr-api.cn-hangzhou.aliyuncs.com
# 商城订单配置 # 商城订单配置
shop: shop:
order: order:
@@ -0,0 +1,3 @@
-- 汇吉采:企业资质新增「经办人身份证号」字段(注册/资质认证页,身份证人像面 OCR 回填)
ALTER TABLE `hjc_enterprise`
ADD COLUMN `id_card_no` varchar(64) DEFAULT NULL COMMENT '经办人身份证号' AFTER `agent_phone`;
+1
View File
@@ -51,6 +51,7 @@ CREATE TABLE `hjc_enterprise` (
`agent_name` varchar(64) DEFAULT NULL COMMENT '经办人姓名', `agent_name` varchar(64) DEFAULT NULL COMMENT '经办人姓名',
`agent_email` varchar(128) DEFAULT NULL COMMENT '经办人邮箱', `agent_email` varchar(128) DEFAULT NULL COMMENT '经办人邮箱',
`agent_phone` varchar(32) DEFAULT NULL COMMENT '经办人手机号', `agent_phone` varchar(32) DEFAULT NULL COMMENT '经办人手机号',
`id_card_no` varchar(64) DEFAULT NULL COMMENT '经办人身份证号',
`authorize_expire` datetime DEFAULT NULL COMMENT '授权委托书到期时间', `authorize_expire` datetime DEFAULT NULL COMMENT '授权委托书到期时间',
`auth_status` tinyint(4) DEFAULT 0 COMMENT '资质状态:0待审核 1已通过 2已驳回', `auth_status` tinyint(4) DEFAULT 0 COMMENT '资质状态:0待审核 1已通过 2已驳回',
`reject_reason` varchar(500) DEFAULT NULL COMMENT '驳回原因', `reject_reason` varchar(500) DEFAULT NULL COMMENT '驳回原因',