> 文章列表 > 核心业务2:借款人申请借款额度

核心业务2:借款人申请借款额度

核心业务2:借款人申请借款额度

核心业务2:借款人申请借款额度

1.业务流程图

------------截止提交个人信息部分--------

2.借款人申请借款额度数据库设计

3.借款人申请额度流程

4.前端代码逻辑

5.后端代码逻辑

------------截止提交个人信息部分--------

核心业务2:借款人申请借款额度

1.业务流程图

核心业务2:借款人申请借款额度

①用户在注册登陆账户绑定之后,点击立即借款进入到借款认证页

  • A进入到借款认证页后,进入尚融宝判断借款状态来显示步骤
  • B表单中的下拉列表数据在尚融宝查询数据字典获取
  • C在上传照片时利用尚融宝上传数据到aliyun,在删除图片后删除aliyun中数据
  • D点击提交后提交表单到尚融宝更新借款人数据
    核心业务2:借款人申请借款额度

②如果A中已提交未审核则进入审核页

核心业务2:借款人申请借款额度

③如果A中已审核则将结果返回

核心业务2:借款人申请借款额度

2.借款人申请借款额度数据库设计

①用户数据表user_info

核心业务2:借款人申请借款额度

②借款人表borrower

核心业务2:借款人申请借款额度

③借款人绑定表borrower_attach

核心业务2:借款人申请借款额度

④三张表关系

  • user_info通过user_id和borrower的user_id关联
  • borrower的id和borrower_attach的borrow_id关联
  • user_info即如果用户为借款人申请借款额度,用户信息表中包含了该用户为借款人的认证状态。
  • borrower即包含了用户为借款人的基本信息
  • borrower_attach表包含了用户为借款人的四张图片信息(房产证,轿车证,身份证正反面)

3.借款人申请额度流程

①前端

  • 用户注册登陆绑定数据后
  • 第一次借款认证填写信息提交表单
  • 提交后再次访问提交表单页则直接进入认证中或者认证结果

②尚融宝后端

  • 用户访问认证页
  • 判断用户是否认证过,认证的状态。
  • 如果没有认证过则前端显示表单页,后端需要在表单页显示时返回数据字典来初始化表单的下拉列表。
  • 在填写表单时对图片的上传和删除同步到aliyun的oss
  • 在填写完表单之后前端提交表单,后端根据表单数据更新user_info的借款人认证状态,根据token获得user_id以及表单信息来更新borrower和borrower_attach

4.代码逻辑

①前端对应表单对象

核心业务2:借款人申请借款额度

②前端请求接口

  • 判断借款人认证状态
    核心业务2:借款人申请借款额度
  • 请求获取数据字典

核心业务2:借款人申请借款额度

  • 请求上传和删除图片
    核心业务2:借款人申请借款额度

核心业务2:借款人申请借款额度

核心业务2:借款人申请借款额度

  • 提交表单
    核心业务2:借款人申请借款额度

③前端复杂逻辑

  • 需要完善表单信息。
    文件的表单信息需要上传成功后加入到表单中,如果删除文件,对应的也需要删除表单中的文件(删除文件如果删除表单,组件封装了调用成功后的响应结果)
  • 刚进入认证页会先进入表单页再判断是否认证过,前端就算认证过也会闪过表单。
    修改步骤为null,必须查看认证结果后赋值,不会闪表单

④总体代码

  • pages/user/borrow.vue
<template><div class="personal-main"><div class="personal-pay"><h3><i>借款人信息认证</i></h3><!--步骤导航--><el-steps :active="active" style="margin: 40px"><el-step title="填写借款人信息"></el-step><el-step title="提交平台审核"></el-step><el-step title="等待认证结果"></el-step></el-steps><!--第一步--><div v-if="active === 0" class="user-borrower"><!--个人信息--><h6>个人基本信息</h6><el-form label-width="120px"><el-form-item label="年龄"><el-col :span="5"><el-input v-model="borrower.age" /></el-col></el-form-item><el-form-item label="性别"><el-select v-model="borrower.sex"><el-option :value="1" :label="'男'" /><el-option :value="0" :label="'女'" /></el-select></el-form-item><el-form-item label="婚否"><el-select v-model="borrower.marry"><el-option :value="true" :label="'是'" /><el-option :value="false" :label="'否'" /></el-select></el-form-item><el-form-item label="学历"><el-select v-model="borrower.education"><el-optionv-for="item in educationList":key="item.value":label="item.name":value="item.value"/></el-select></el-form-item><el-form-item label="行业"><el-select v-model="borrower.industry"><el-optionv-for="item in industryList":key="item.value":label="item.name":value="item.value"/></el-select></el-form-item><el-form-item label="月收入"><el-select v-model="borrower.income"><el-optionv-for="item in incomeList":key="item.value":label="item.name":value="item.value"/></el-select></el-form-item><el-form-item label="还款来源"><el-select v-model="borrower.returnSource"><el-optionv-for="item in returnSourceList":key="item.value":label="item.name":value="item.value"/></el-select></el-form-item></el-form><!--联系人信息--><h6>联系人信息</h6><el-form label-width="120px"><el-form-item label="联系人姓名"><el-col :span="5"><el-input v-model="borrower.contactsName" /></el-col></el-form-item><el-form-item label="联系人手机"><el-col :span="5"><el-input v-model="borrower.contactsMobile" /></el-col></el-form-item><el-form-item label="联系人关系"><el-select v-model="borrower.contactsRelation"><el-optionv-for="item in contactsRelationList":key="item.value":label="item.name":value="item.value"/></el-select></el-form-item></el-form><!--身份认证信息--><h6>身份认证信息</h6><!--其中的module是为了区分每个上传文件的位置在OSS--><el-form label-width="120px"><el-form-item label="身份证人像面"><el-upload:on-success="onUploadSuccessIdCard1":on-remove="onUploadRemove":multiple="false":action="uploadUrl":data="{ module: 'idCard1' }":limit="1"list-type="picture-card"><i class="el-icon-plus"></i></el-upload></el-form-item><el-form-item label="身份证国徽面"><el-upload:on-success="onUploadSuccessIdCard2":on-remove="onUploadRemove":multiple="false":action="uploadUrl":data="{ module: 'idCard2' }":limit="1"list-type="picture-card"><i class="el-icon-plus"></i></el-upload></el-form-item></el-form><!--其他信息--><h6>其他信息</h6><el-form label-width="120px"><el-form-item label="房产信息"><el-upload:on-success="onUploadSuccessHouse":on-remove="onUploadRemove":multiple="false":action="uploadUrl":data="{ module: 'house' }"list-type="picture-card"><i class="el-icon-plus"></i></el-upload></el-form-item><el-form-item label="车辆信息"><el-upload:on-success="onUploadSuccessCar":on-remove="onUploadRemove":multiple="false":action="uploadUrl":data="{ module: 'car' }"list-type="picture-card"><i class="el-icon-plus"></i></el-upload></el-form-item></el-form><el-form label-width="120px"><el-form-item><el-buttontype="primary":disabled="submitBtnDisabled"@click="save">提交</el-button></el-form-item></el-form></div><!--第二步--><div v-if="active === 1"><div style="margin-top:40px;"><el-alerttitle="您的认证申请已成功提交,请耐心等待"type="warning"show-icon:closable="false">我们将在2小时内完成审核,审核时间为周一至周五8:0020:00</el-alert></div></div><!--第三步--><div v-if="active === 2"><div style="margin-top:40px;"><el-alertv-if="borrowerStatus === 2"title="您的认证审批已通过"type="success"show-icon:closable="false"></el-alert><el-alertv-if="borrowerStatus === -1"title="您的认证审批未通过"type="error"show-icon:closable="false"></el-alert></div></div></div></div>
</template>
<script>
export default {data() {let BASE_API = process.env.BASE_APIreturn {//为什么不设置为0?//因为只有当判断完成用户的认证状态才能确定在哪一步,如果写0的话如果用户状态为待审核由于ajax异步操作,会闪一下第一个列表active: null, //步骤borrowerStatus: null, //认证状态submitBtnDisabled: false, //提交按钮的修饰,防止表单重复提交,点击save然后不能提交//借款人信息borrower: {borrowerAttachList: [], //存储文件数据的基本信息},educationList: [], //学历列表industryList: [], //行业列表incomeList: [], //月收入列表returnSourceList: [], //还款来源列表contactsRelationList: [], //联系人关系uploadUrl: BASE_API + '/api/oss/file/upload', //文件上传地址}},methods: {//保存表单提交的信息save() {// debuggerthis.submitBtnDisabled = truethis.$axios.$post('/api/core/borrower/auth/save', this.borrower).then((response) => {this.active = 1})},//根据上传文件得到的结果,封装borrowerAttachList存储文件的基本信息(响应结果,文件参数)onUploadSuccessIdCard1(response, file) {this.onUploadSuccess(response, file, 'idCard1')},onUploadSuccessIdCard2(response, file) {this.onUploadSuccess(response, file, 'idCard2')},onUploadSuccessHouse(response, file) {this.onUploadSuccess(response, file, 'house')},onUploadSuccessCar(response, file) {this.onUploadSuccess(response, file, 'car')},onUploadSuccess(response, file, type) {// debuggerif (response.code !== 0) {//上传失败,返回响应结果this.$message.error(response.message)return}// 上传成功,填充上传文件列表this.borrower.borrowerAttachList.push({imageName: file.name,imageUrl: response.data.url,imageType: type,})//console.log(this.borrower.borrowerAttachList)},//将oss系统删除文件(文件参数)file参数组装了上传的响应结果onUploadRemove(file, fileList) {console.log('file', file)console.log('fileList', fileList)//删除oss服务器上的内容//调用远程的删除接口this.$axios.$delete('/api/oss/file/remove?url=' + file.response.data.url).then((response) => {// debuggerconsole.log('远程删除文件成功')//从 this.borrower.borrowerAttachList列表中删除该文件//将过滤的结果回填到原来列表this.borrower.borrowerAttachList = this.borrower.borrowerAttachList.filter(function(item) {console.log('item', item)//两个地址相等则返回true,不删除return item.imageUrl != file.response.data.url})})},//根据查询的数据字典初始化下拉列表initSelected() {//学历列表this.$axios.$get('/api/core/dict/findByDictCode/education').then((response) => {this.educationList = response.data.dictList})//行业列表this.$axios.$get('/api/core/dict/findByDictCode/industry').then((response) => {this.industryList = response.data.dictList})//收入列表this.$axios.$get('/api/core/dict/findByDictCode/income').then((response) => {this.incomeList = response.data.dictList})//还款来源列表this.$axios.$get('/api/core/dict/findByDictCode/returnSource').then((response) => {this.returnSourceList = response.data.dictList})//联系人关系列表this.$axios.$get('/api/core/dict/findByDictCode/relation').then((response) => {this.contactsRelationList = response.data.dictList})},getUserInfo() {this.$axios.$get('/api/core/borrower/auth/getBorrowerStatus').then((response) => {this.borrowerStatus = response.data.borrowerStatusif (this.borrowerStatus == 0) {//未认证,展示下拉列表this.active = 0this.initSelected()} else if (this.borrowerStatus == 1) {//审批中this.active = 1} else if (this.borrowerStatus == 2) {//审批通过this.active = 2} else if (this.borrowerStatus == -1) {//审批没通过this.active = 2}})},},created() {//更改为判断借款状态this.getUserInfo()},
}
</script>

5.后端代码逻辑

①前端调用的接口

  • 开发接口
    核心业务2:借款人申请借款额度
  • 调用的接口
    核心业务2:借款人申请借款额度

②后端复杂逻辑

  • 获取下拉列表时根据dict_code去查对应的子节点
    需要先查询到dict_code的id然后根据此id去查父id为此id的数据返回(调用之前写的根据父id查询的service)
  • 保存存款人信息时需要获取user_id绑定
    即需要用户先登录,此时可以从token中解析出user_id
  • 根据表单信息更新借款人表单时
    需要先根据user_id查询出user_info的基本信息,补充表单信息更新borrower表
  • 根据表单信息更新借款人附件表单时
    需要先查询借款人的id然后在附件表单中绑定借款人id
  • 提交表单后也需要更新user_info的借款人认证状态
  • 获取借款人认证状态
    可以从已登录的token中获取。然后根据id从borrower表中查询status,查询出数据则说明不是未认证返回status(1认证中2认证成功-1认证失败),查询不出数据则是未认证返回status(0未认证)

③后端创建的接受前端对象

package com.atguigu.srb.core.pojo.vo;import com.atguigu.srb.core.pojo.entity.BorrowerAttach;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.List;@Data
@ApiModel(description="借款人认证信息")
public class BorrowerVO{@ApiModelProperty(value = "性别(1:男 0:女)")private Integer sex;@ApiModelProperty(value = "年龄")private Integer age;@ApiModelProperty(value = "学历")private Integer education;@ApiModelProperty(value = "是否结婚(1:是 0:否)")private Boolean marry;@ApiModelProperty(value = "行业")private Integer industry;@ApiModelProperty(value = "月收入")private Integer income;@ApiModelProperty(value = "还款来源")private Integer returnSource;@ApiModelProperty(value = "联系人名称")private String contactsName;@ApiModelProperty(value = "联系人手机")private String contactsMobile;@ApiModelProperty(value = "联系人关系")private Integer contactsRelation;@ApiModelProperty(value = "借款人附件资料")private List<BorrowerAttach> borrowerAttachList;
}

④获取数据字典业务

  • controller
package com.atguigu.srb.core.controller.api;import com.atguigu.common.result.R;
import com.atguigu.srb.core.pojo.entity.Dict;
import com.atguigu.srb.core.service.DictService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.util.List;@Api(tags = "数据字典")
@RestController
@RequestMapping("/api/core/dict")
@Slf4j
public class DictController {@Resourceprivate DictService dictService;@ApiOperation("根据DictCode获取下级节点")@GetMapping("/findByDictCode/{dictCode}")public R findByDictCode(@ApiParam("节点编码")@PathVariable("dictCode") String dictCode){List<Dict> list =  dictService.findByDictCode(dictCode);return R.ok().data("dictList",list);}
}
  • service(前三种方法是admin管理系统调用的Dict方法)
package com.atguigu.srb.core.service;import com.atguigu.srb.core.pojo.dto.ExcelDictDTO;
import com.atguigu.srb.core.pojo.entity.Dict;
import com.baomidou.mybatisplus.extension.service.IService;import java.io.InputStream;
import java.util.List;/* <p>* 数据字典 服务类* </p> @author Likejin* @since 2023-04-09*/
public interface DictService extends IService<Dict> {void importData(InputStream inputStream);List<ExcelDictDTO> listDictData();List<Dict> listByParentId(Long parentId);/* @param dictCode:* @return List<Dict>* @author Likejin* @description 根据dictCode编码查询其下级节点* @date 2023/4/15 20:00*/List<Dict> findByDictCode(String dictCode);
}

com.atguigu.srb.core.service.impl.DictServiceImpl类下加入方法

    /* @param dictCode:* @return List<Dict>* @author Likejin* @description 根据dictCode编码查询其下级节点* @date 2023/4/15 20:00*/@Overridepublic List<Dict> findByDictCode(String dictCode) {QueryWrapper<Dict> dictQueryWrapper = new QueryWrapper<>();dictQueryWrapper.eq("dict_code",dictCode);Dict dict = baseMapper.selectOne(dictQueryWrapper);//拿到父dict的id,然后根据该id去查父id等于这个id的list<Dict>return this.listByParentId(dict.getId());}

⑤借款人业务(获取认证状态)(保存借款人信息)

  • controller
package com.atguigu.srb.core.controller.api;import com.atguigu.common.result.R;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.core.pojo.vo.BorrowerVO;
import com.atguigu.srb.core.service.BorrowerService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;@Api(tags = "借款人")
@RestController
@RequestMapping("/api/core/borrower")
@Slf4j
public class BorrowerController {@Resourceprivate BorrowerService borrowerService;@ApiOperation("保存借款人信息")@PostMapping("/auth/save")public R save(@RequestBody BorrowerVO borrowerVO, HttpServletRequest request) {//获取已经登录人的idString token = request.getHeader("token");Long userId = JwtUtils.getUserId(token);//存储表单信息borrowerService.saveBorrowerVOByUserId(borrowerVO, userId);return R.ok().message("信息提交成功");}@ApiOperation("获取借款人认证状态")@GetMapping("/auth/getBorrowerStatus")public R getBorrowerStatus(HttpServletRequest httpServletRequest){String token = httpServletRequest.getHeader("token");Long userId = JwtUtils.getUserId(token);Integer status = borrowerService.getStatusByUserId(userId);return R.ok().data("borrowerStatus",status);}
}
  • service
package com.atguigu.srb.core.service;import com.atguigu.srb.core.pojo.entity.Borrower;
import com.atguigu.srb.core.pojo.vo.BorrowerVO;
import com.baomidou.mybatisplus.extension.service.IService;/* <p>* 借款人 服务类* </p> @author Likejin* @since 2023-04-09*/
public interface BorrowerService extends IService<Borrower> {void saveBorrowerVOByUserId(BorrowerVO borrowerVO, Long userId);Integer getStatusByUserId(Long userId);
}
package com.atguigu.srb.core.service.impl;import com.atguigu.srb.core.enums.BorrowerStatusEnum;
import com.atguigu.srb.core.mapper.BorrowerAttachMapper;
import com.atguigu.srb.core.mapper.UserInfoMapper;
import com.atguigu.srb.core.pojo.entity.Borrower;
import com.atguigu.srb.core.mapper.BorrowerMapper;
import com.atguigu.srb.core.pojo.entity.BorrowerAttach;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.pojo.vo.BorrowerVO;
import com.atguigu.srb.core.service.BorrowerService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.util.List;/* <p>* 借款人 服务实现类* </p> @author Likejin* @since 2023-04-09*/
@Service
public class BorrowerServiceImpl extends ServiceImpl<BorrowerMapper, Borrower> implements BorrowerService {@Resourceprivate UserInfoMapper userInfoMapper;@Resourceprivate BorrowerAttachMapper borrowerAttachMapper;/* @param borrowerVO:* @param userId:* @return void* @author Likejin* @description 根据前端传输对象保存数据到数据库* @date 2023/4/15 20:15*/@Override@Transactional(rollbackFor = Exception.class)public void saveBorrowerVOByUserId(BorrowerVO borrowerVO, Long userId) {//获取用户基本信息UserInfo userInfo = userInfoMapper.selectById(userId);//拷贝信息到borrower//保存借款人信息(根据id查询用户基本信息,然后根据表单信息更新borrower表)Borrower borrower = new Borrower();BeanUtils.copyProperties(borrowerVO,borrower);borrower.setUserId(userId);borrower.setName(userInfo.getName());borrower.setIdCard(userInfo.getIdCard());borrower.setMobile(userInfo.getMobile());borrower.setStatus(BorrowerStatusEnum.AUTH_RUN.getStatus());baseMapper.insert(borrower);//保存附件信息到borrow——attach表List<BorrowerAttach> borrowerAttachList = borrowerVO.getBorrowerAttachList();borrowerAttachList.forEach(borrowerAttach -> {borrowerAttach.setBorrowerId(borrower.getId());borrowerAttachMapper.insert(borrowerAttach);});//更新user_info的借款人认证状态userInfo.setBorrowAuthStatus(BorrowerStatusEnum.AUTH_RUN.getStatus());userInfoMapper.updateById(userInfo);}/* @param userId:* @return Integer* @author Likejin* @description 借款人二次进入认证页面根据token获取认证状态* @date 2023/4/15 20:41*/@Overridepublic Integer getStatusByUserId(Long userId) {QueryWrapper<Borrower> borrowerQueryWrapper = new QueryWrapper<>();borrowerQueryWrapper.select("status").eq("user_id",userId);//selectObjs一般用于查询一个字段,list存的是statusList<Object> objects = baseMapper.selectObjs(borrowerQueryWrapper);if(objects.size()==0){//一条记录没取出来,说明没有提交额度信息,需要填写表单return BorrowerStatusEnum.NO_AUTH.getStatus();}//取出来一条,说明已经提交了额度信息,判断此时状态Integer status = (Integer) objects.get(0);return status;}
}

未更新

未更新

未更新

未更新

未更新

未更新

未更新

未更新

未更新