您现在的位置是:首页 >技术教程 >尚融宝22-提交借款申请网站首页技术教程
尚融宝22-提交借款申请
目录
一、需求介绍
step1:用户在个人中心点击 “立即借款” (http://localhost:3000/user/borrower)
step2:展示借款人信息认证页面
step3:借款人填写信息并提交
step4:展示等待审核页面
step5:平台审核
step6:显示审批结果
二、图片上传
(一)前端页面
<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-option
v-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-option
v-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-option
v-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-option
v-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-option
v-for="item in contactsRelationList"
: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-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-button
type="primary"
:disabled="submitBtnDisabled"
@click="save"
>
提交
</el-button>
</el-form-item>
</el-form>
</div>
<div v-if="active === 1">
<div style="margin-top:40px;">
<el-alert
title="您的认证申请已成功提交,请耐心等待"
type="warning"
show-icon
:closable="false"
>
我们将在2小时内完成审核,审核时间为周一至周五8:00至20:00。
</el-alert>
</div>
</div>
<div v-if="active === 2">
<div style="margin-top:40px;">
<el-alert
v-if="borrowerStatus === 2"
title="您的认证审批已通过"
type="success"
show-icon
:closable="false"
>
</el-alert>
<el-alert
v-if="borrowerStatus === -1"
title="您的认证审批未通过"
type="error"
show-icon
:closable="false"
>
</el-alert>
</div>
</div>
</div>
</div>
</template>
(二)实现图片上传
前面四个success是el文件上传组件成功后的回调函数,response和file是组件为我们自动封装的,传递type的原因是要区别四张图片,上传阿里云时存储在不同文件中
这里前端我们要将整个表单封装到borrow对象中,比如年龄(borrow.age),还有附件(borrower.borrowerAttachList),即四张图片的信息(包括图片名字,图片类型,图片在阿里云上的地址)
其次当用户上传图片又删除后,我们需要删除已经上传阿里云的图片并删除borrower.borrowerAttachList里对应的信息,这里使用filter函数实现
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) {
// debugger
if (response.code !== 0) {
this.$message.error(response.message)
return
}
// 填充上传文件列表
this.borrower.borrowerAttachList.push({
imageName: file.name,
imageUrl: response.data.url,
imageType: type,
})
},
onUploadRemove(file, fileList) {
console.log('fileList', fileList)
//删除oss服务器上的内容
this.$axios
.$delete('/api/oss/file/remove?url=' + file.response.data.url)
.then((response) => {
// debugger
console.log('远程删除')
this.borrower.borrowerAttachList = this.borrower.borrowerAttachList.filter(
function(item) {
console.log('item', item)
return item.imageUrl != file.response.data.url
}
)
})
},
在浏览器通过vue插件查看对象封装情况
三、数据字典展示
对于以下下拉表单选项的内容储存在数据字典dict表中,因此我们去查询数据库将数据字典对应的内容查询出来进行展示
思路:首先根据dict_code查询出该对象的id,然后通过这个id查询下面的子节点(通过子节点parent_id==父节点id)
(一)后端
DictController
@ApiOperation("根据dictCode查询下级节点")
@GetMapping("/findByDictCode/{dictCode}")
public R findByDictCode(
@ApiParam(value = "节点编码", required = true)
@PathVariable String dictCode) {
List<Dict> dictList = dictService.findByDictCode(dictCode);
return R.ok().data("dictList", dictList);
}
DictService
List<Dict> findByDictCode(String dictCode);
DictServiceImpl
@Override
public List<Dict> findByDictCode(String dictCode) {
QueryWrapper<Dict> wrapper = new QueryWrapper<>();
wrapper.eq("dict_code", dictCode);
Dict dict = baseMapper.selectOne(wrapper); // 父节点
return this.listByParentId(dict.getId());
}
@Override
public List<Dict> listByParentId(Long parent_id) {
try {
// 首先查询redis有无数据
List<Dict> dictList = (List<Dict>)redisTemplate.opsForValue().get("src:core:dictList" + parent_id);
// 如果查询到数据直接返回
if(dictList != null) {
log.info("redis查到数据,准备返回");
return dictList;
}
} catch (Exception e) {
log.error("redis服务器异常:" + ExceptionUtils.getStackTrace(e));
}
// redis没有数据就查询数据库
log.info("查询数据库");
QueryWrapper<Dict> wrapper = new QueryWrapper<>();
wrapper.eq("parent_id", parent_id);
List<Dict> dicts = baseMapper.selectList(wrapper);
dicts.forEach(dict -> {
dict.setHasChildren(this.hasChildren(dict.getId()));
});
try {
// 将查询到的数据放入redis
log.info("将数据库查到的数据放入redis");
redisTemplate.opsForValue().set("src:core:dictList" + parent_id, dicts, 5, TimeUnit.MINUTES);
} catch (Exception e) {
log.error("redis服务器异常:" + ExceptionUtils.getStackTrace(e));
}
// 返回查询到的数据
return dicts;
}
(二)前端
pages/user/borrower.vue中调用接口
created() {
this.initSelected()
},
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
})
},
四、表单信息提交
(一)后端
1、VO对象(表单对象)
service-core微服务,创建BorrowerVO,对应的是填写借款申请时的表单对象VO(value object)
@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;
}
2、定义借款认证状态枚举
BorrowerStatusEnum
数据库设计中对应认证状态status (0:未认证,1:认证中, 2:认证通过, -1:认证失败)
@AllArgsConstructor
@Getter
//@ToString
public enum BorrowerStatusEnum {
NO_AUTH(0, "未认证"),
AUTH_RUN(1, "认证中"),
AUTH_OK(2, "认证成功"),
AUTH_FAIL(-1, "认证失败"),
;
private Integer status;
private String msg;
public static String getMsgByStatus(int status) {
BorrowerStatusEnum arrObj[] = BorrowerStatusEnum.values();
for (BorrowerStatusEnum obj : arrObj) {
if (status == obj.getStatus().intValue()) {
return obj.getMsg();
}
}
return "";
}
}
3、controller
borrowerController
@ApiOperation("保存借款人信息")
@PostMapping("/auth/save")
public R save(@RequestBody BorrowerVO borrowerVO, HttpServletRequest request) {
String token = request.getHeader("token");
Long userId = JwtUtils.getUserId(token);
borrowerService.saveBorrowerVOByUserId(borrowerVO, userId);
return R.ok().message("信息保存成功");
}
4、service
BorrowerService
void saveBorrowerVOByUserId(BorrowerVO borrowerVO, Long userId);
BorrowerServiceImpl
@Resource
private BorrowerAttachMapper borrowerAttachMapper;
@Resource
private UserInfoMapper userInfoMapper;
@Transactional(rollbackFor = Exception.class)
@Override
public void saveBorrowerVOByUserId(BorrowerVO borrowerVO, Long userId) {
UserInfo userInfo = userInfoMapper.selectById(userId);
//保存借款人信息
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);
//保存附件
List<BorrowerAttach> borrowerAttachList = borrowerVO.getBorrowerAttachList();
borrowerAttachList.forEach(borrowerAttach -> {
borrowerAttach.setBorrowerId(borrower.getId());
borrowerAttachMapper.insert(borrowerAttach);
});
//更新会员状态,更新为认证中
userInfo.setBorrowAuthStatus(BorrowerStatusEnum.AUTH_RUN.getStatus());
userInfoMapper.updateById(userInfo);
}
(二)前端
pages/user/borrower.vue 脚本
save() {
// debugger
this.submitBtnDisabled = true
this.$axios
.$post('/api/core/borrower/save', this.borrower)
.then((response) => {
this.active = 1
})
},
五、获取借款人状态
当借款人申请后,再一次刷新页面会发现仍然是表单,这里正确的是应该显示认证中,认证成功或者认证失败,所以在加载页面之前我们应该请求后端获取borrowerStatus
这里的认证状态是由active和borrowerstatus共同决定的
(一)后端
1、borrowerController
@ApiOperation("获取借款人认证状态")
@GetMapping("/auth/getBorrowerStatus")
public R getBorrowerStatus(HttpServletRequest request){
String token = request.getHeader("token");
Long userId = JwtUtils.getUserId(token);
Integer status = borrowerService.getStatusByUserId(userId);
return R.ok().data("borrowerStatus", status);
}
2、service
BorrowerService
Integer getStatusByUserId(Long userId);
BorrowerServiceImpl
@Override
public Integer getStatusByUserId(Long userId) {
QueryWrapper<Borrower> borrowerQueryWrapper = new QueryWrapper<>();
borrowerQueryWrapper.select("status").eq("user_id", userId);
List<Object> objects = baseMapper.selectObjs(borrowerQueryWrapper);
if(objects.size() == 0){
//借款人尚未提交信息
return BorrowerStatusEnum.NO_AUTH.getStatus();
}
Integer status = (Integer)objects.get(0);
return status;
}
(二)前端
pages/user/borrower.vue 脚本
created() {
// 这里由initSelected换成getUserInfo,获取borrowerStatus 状态后再决定是否调用initSelected
this.getUserInfo()
},
//获取借款人信息
getUserInfo() {
this.$axios
.$get('/api/core/borrower/auth/getBorrowerStatus')
.then((response) => {
this.borrowerStatus = response.data.borrowerStatus
if (this.borrowerStatus === 0) {
//未认证
this.active = 0
//获取下拉列表
this.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
}
})
}