23、标的管理
23.1、需求介绍
23.1.1、借款人申请借款
**1、需求描述 **
2、相关数据库表
lend:标的表
23.1.2、具体步骤
1、标的产生
管理员借款审核通过后,则产生新标的
2、查看标的列表
3、查看标的详情
23.2、生成新标的
23.2.1、后端实现
1、创建枚举
创建 LendStatusEnum
CHECK(0, "待发布"),
INVEST_RUN(1, "募资中"),
PAY_RUN(2, "还款中"),
PAY_OK(3, "已结清"),
FINISH(4, "结标"),
CANCEL(-1, "已撤标"),
;
2、定义编号辅助类
service-core中添加辅助类:util.LendNoUtils
3、Service
BorrowInfoServiceImpl 实现:
@Resource
private LendService lendService;
@Transactional(rollbackFor = Exception.class)
@Override
public void approval(BorrowInfoApprovalVO borrowInfoApprovalVO) {
//修改借款信息状态
......
//审核通过则创建标的
if (borrowInfoApprovalVO.getStatus().intValue() == BorrowInfoStatusEnum.CHECK_OK.getStatus().intValue()) {
//创建标的
lendService.createLend(borrowInfoApprovalVO, borrowInfo);
}
}
LendService 接口:
void createLend(BorrowInfoApprovalVO borrowInfoApprovalVO, BorrowInfo borrowInfo);
LendServiceImpl 实现:生成标的
@Override
public void createLend(BorrowInfoApprovalVO borrowInfoApprovalVO, BorrowInfo borrowInfo) {
// 校验年化利率、平台服务费率(数据库修改为decimal(10,4),仅用年化利率与平台服务费率举例,其他涉及金额的操作都应该谨慎处理)
String lendYearRate = borrowInfoApprovalVO.getLendYearRate().toPlainString();
String[] lendYearRateSplit = lendYearRate.split("\\.");
if (lendYearRateSplit.length > 1 && lendYearRateSplit[1].length() > 2) {
throw new BusinessException("年化利率仅支持到小数点后两位");
}
String serviceRate = borrowInfoApprovalVO.getServiceRate().toPlainString();
String[] serviceRateSplit = serviceRate.split("\\.");
if (lendYearRateSplit.length > 1 && serviceRateSplit[1].length() > 2) {
throw new BusinessException("平台服务费率仅支持到小数点后两位");
}
Lend lend = new Lend();
lend.setUserId(borrowInfo.getUserId());
lend.setBorrowInfoId(borrowInfo.getId());
lend.setLendNo(LendNoUtils.getLendNo());//生成编号
lend.setTitle(borrowInfoApprovalVO.getTitle());
lend.setAmount(borrowInfo.getAmount());
lend.setPeriod(borrowInfo.getPeriod());
lend.setLendYearRate(borrowInfoApprovalVO.getLendYearRate().divide(new BigDecimal(100), 4, RoundingMode.DOWN));//从审批对象中获取
lend.setServiceRate(borrowInfoApprovalVO.getServiceRate().divide(new BigDecimal(100), 4, RoundingMode.DOWN));//从审批对象中获取
lend.setReturnMethod(borrowInfo.getReturnMethod());
lend.setLowestAmount(new BigDecimal(100));
lend.setInvestAmount(new BigDecimal(0));
lend.setInvestNum(0);
lend.setPublishDate(LocalDateTime.now());
//起息日期
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate lendStartDate = LocalDate.parse(borrowInfoApprovalVO.getLendStartDate(), dtf);
lend.setLendStartDate(lendStartDate);
//结束日期
LocalDate lendEndDate = lendStartDate.plusMonths(borrowInfo.getPeriod());
lend.setLendEndDate(lendEndDate);
lend.setLendInfo(borrowInfoApprovalVO.getLendInfo());//描述
//平台预期收益
// 月年化 = 年化 / 12
BigDecimal monthRate = lend.getServiceRate().divide(new BigDecimal(12), 8, RoundingMode.DOWN);
// 平台收益 = 标的金额 * 月年化 * 期数
BigDecimal expectAmount = lend.getAmount().multiply(monthRate).multiply(new BigDecimal(lend.getPeriod()));
lend.setExpectAmount(expectAmount);
//实际收益
lend.setRealAmount(new BigDecimal(0));
//状态
lend.setStatus(LendStatusEnum.INVEST_RUN.getStatus());
//审核时间
lend.setCheckTime(LocalDateTime.now());
//审核人
lend.setCheckAdminId(1L);
baseMapper.insert(lend);
}
23.3、标的列表
23.3.1、后端实现
1、扩展实体对象
在Lend类中扩展以下字段
@ApiModelProperty(value = "其他参数")
@TableField(exist = false)
private Map<String,Object> param = new HashMap<>();
2、Controller
添加 AdminLendController
package com.atguigu.srb.core.controller.admin;
@Api(tags = "标的管理")
@RestController
@RequestMapping("/admin/core/lend")
@Slf4j
public class AdminLendController {
@Resource
private LendService lendService;
@ApiOperation("标的列表")
@GetMapping("/list")
public R list() {
List<Lend> lendList = lendService.selectList();
return R.ok().data("list", lendList);
}
}
3、Service
接口:LendService
List<Lend> selectList();
实现:LendServiceImpl
@Resource
private DictService dictService;
@Override
public List<Lend> selectList() {
List<Lend> lendList = baseMapper.selectList(null);
lendList.forEach(lend -> {
String returnMethod = dictService.getNameByParentDictCodeAndValue("returnMethod", lend.getReturnMethod());
String status = LendStatusEnum.getMsgByStatus(lend.getStatus());
lend.getParam().put("returnMethod", returnMethod);
lend.getParam().put("status", status);
});
return lendList;
}
23.3.2、前端
1、创建页面组件
创建 src/views/core/lend/list.vue
<template>
<div class="app-container">
标的列表
</div>
</template>
<script>
export default {
}
</script>
创建 src/views/core/lend/detail.vue
<template>
<div class="app-container">
标的详情
</div>
</template>
<script>
export default {
}
</script>
2、配置路由
src/router/index.js
{
path: '/core/lend',
component: Layout,
name: 'coreLend',
meta: { title: '标的管理', icon: 'el-icon-s-flag' },
alwaysShow: true,
children: [
{
path: 'list',
name: 'coreLendList',
component: () => import('@/views/core/lend/list'),
meta: { title: '标的列表' }
},
{
path: 'detail/:id',
name: 'coreLendDetail',
component: () => import('@/views/core/lend/detail'),
meta: { title: '标的详情' },
hidden: true
}
]
},
3、定义api
创建 src/api/core/lend.js
import request from '@/utils/request'
export default {
getList() {
return request({
url: `/admin/core/lend/list`,
method: 'get'
})
}
}
4、页面脚本
src/views/core/lend/list.vue
<script>
import lendApi from '@/api/core/lend'
export default {
data() {
return {
list: null // 列表
}
},
created() {
this.fetchData()
},
methods: {
// 加载列表数据
fetchData() {
lendApi.getList().then(response => {
this.list = response.data.list
})
}
}
}
</script>
5、页面模板
src/views/core/lend/list.vue
<template>
<div class="app-container">
<!-- 列表 -->
<el-table :data="list" stripe>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="lendNo" label="标的编号" width="160" />
<el-table-column prop="amount" label="标的金额" />
<el-table-column prop="period" label="投资期数" />
<el-table-column label="年化利率">
<template slot-scope="scope">
{{ scope.row.lendYearRate * 100 }}%
</template>
</el-table-column>
<el-table-column prop="investAmount" label="已投金额" />
<el-table-column prop="investNum" label="投资人数" />
<el-table-column prop="publishDate" label="发布时间" width="150" />
<el-table-column prop="lendStartDate" label="开始日期" />
<el-table-column prop="lendEndDate" label="结束日期" />
<el-table-column prop="param.returnMethod" label="还款方式" />
<el-table-column prop="param.status" label="状态" />
<el-table-column label="操作" width="150" align="center">
<template slot-scope="scope">
<el-button type="primary" size="mini">
<router-link :to="'/core/lend/detail/' + scope.row.id">
查看
</router-link>
</el-button>
<el-button
v-if="scope.row.status == 1"
type="warning"
size="mini"
@click="makeLoan(scope.row.id)"
>
放款
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
23.3、标的详情
23.3.1、后端实现
1、Controller
AdminLendController
@ApiOperation("获取标的信息")
@GetMapping("/show/{id}")
public R show(
@ApiParam(value = "标的id", required = true)
@PathVariable Long id) {
Map<String, Object> result = lendService.getLendDetail(id);
return R.ok().data("lendDetail", result);
}
2、Service
接口:LendService
Map<String, Object> getLendDetail(Long id);
实现:LendServiceImpl
@Resource
private BorrowerMapper borrowerMapper;
@Resource
private BorrowerService borrowerService;
@Override
public Map<String, Object> getLendDetail(Long id) {
//查询标的对象
Lend lend = baseMapper.selectById(id);
//组装数据
String returnMethod = dictService.getNameByParentDictCodeAndValue("returnMethod", lend.getReturnMethod());
String status = LendStatusEnum.getMsgByStatus(lend.getStatus());
lend.getParam().put("returnMethod", returnMethod);
lend.getParam().put("status", status);
//根据user_id获取借款人对象
QueryWrapper<Borrower> borrowerQueryWrapper = new QueryWrapper<Borrower>();
borrowerQueryWrapper.eq("user_id", lend.getUserId());
Borrower borrower = borrowerMapper.selectOne(borrowerQueryWrapper);
//组装借款人对象
BorrowerDetailVO borrowerDetailVO = borrowerService.getBorrowerDetailVOById(borrower.getId());
//组装数据
Map<String, Object> result = new HashMap<>();
result.put("lend", lend);
result.put("borrower", borrowerDetailVO);
return result;
}
23.3.2、前端
1、定义api
src/api/core/lend.js
show(id) {
return request({
url: `/admin/core/lend/show/${id}`,
method: 'get'
})
}
2、页面脚本
src/views/core/lend/detail.vue
<script>
import lendApi from '@/api/core/lend'
import '@/styles/show.css'
export default {
data() {
return {
lendDetail: {
lend: {
param: {}
},
borrower: {}
}
}
},
created() {
if (this.$route.params.id) {
this.fetchDataById()
}
},
methods: {
fetchDataById() {
lendApi.show(this.$route.params.id).then(response => {
this.lendDetail = response.data.lendDetail
})
},
back() {
this.$router.push({ path: '/core/lend/list' })
}
}
}
</script>
3、页面模板
src/views/core/lend/detail.vue
<template>
<div class="app-container">
<h4>标的信息</h4>
<table
class="table table-striped table-condenseda table-bordered"
width="100%"
>
<tbody>
<tr>
<th width="15%">标的编号</th>
<td width="35%">
<b>{{ lendDetail.lend.lendNo }}</b>
</td>
<th width="15%">标题</th>
<td width="35%">{{ lendDetail.lend.title }}</td>
</tr>
<tr>
<th>标的金额</th>
<td>{{ lendDetail.lend.amount }}元</td>
<th>投资期数</th>
<td>{{ lendDetail.lend.period }}个月</td>
</tr>
<tr>
<th>年化利率</th>
<td>
标的:{{ lendDetail.lend.lendYearRate * 100 }}%
<br />
平台:{{ lendDetail.lend.serviceRate * 100 }}%
</td>
<th>还款方式</th>
<td>{{ lendDetail.lend.param.returnMethod }}</td>
</tr>
<tr>
<th>最低投资金额</th>
<td>{{ lendDetail.lend.lowestAmount }}元</td>
<th>发布日期</th>
<td>{{ lendDetail.lend.publishDate }}</td>
</tr>
<tr>
<th>开始日期</th>
<td>{{ lendDetail.lend.lendStartDate }}</td>
<th>结束日期</th>
<td>{{ lendDetail.lend.lendEndDate }}</td>
</tr>
<tr>
<th>已投金额</th>
<td>
<b>{{ lendDetail.lend.investAmount }}元</b>
</td>
<th>投资人数</th>
<td>{{ lendDetail.lend.investNum }}人</td>
</tr>
<tr>
<th>状态</th>
<td>
<b>{{ lendDetail.lend.param.status }}</b>
</td>
<th>创建时间</th>
<td>{{ lendDetail.lend.createTime }}</td>
</tr>
<tr>
<th>说明</th>
<td colspan="3">
<b>{{ lendDetail.lend.lendInfo }}</b>
</td>
</tr>
</tbody>
</table>
<h4>平台收益信息</h4>
<table
class="table table-striped table-condenseda table-bordered"
width="100%"
>
<tbody>
<tr>
<th width="15%">标的预期收益</th>
<td width="35%">
<b>{{ lendDetail.lend.expectAmount }}元</b>
</td>
<th width="15%">标的已获取收益</th>
<td width="35%">{{ lendDetail.lend.realAmount }}元</td>
</tr>
</tbody>
</table>
<h4>借款人信息</h4>
<table
class="table table-striped table-condenseda table-bordered"
width="100%"
>
<tbody>
<tr>
<th width="15%">借款人</th>
<td width="35%">
<b>{{ lendDetail.borrower.name }}</b>
</td>
<th width="15%">手机</th>
<td width="35%">{{ lendDetail.borrower.mobile }}</td>
</tr>
<tr>
<th>身份证</th>
<td>{{ lendDetail.borrower.idCard }}</td>
<th>性别</th>
<td>{{ lendDetail.borrower.sex }}</td>
</tr>
<tr>
<th>年龄</th>
<td>{{ lendDetail.borrower.age }}</td>
<th>是否结婚</th>
<td>{{ lendDetail.borrower.marry }}</td>
</tr>
<tr>
<th>学历</th>
<td>{{ lendDetail.borrower.education }}</td>
<th>行业</th>
<td>{{ lendDetail.borrower.industry }}</td>
</tr>
<tr>
<th>月收入</th>
<td>{{ lendDetail.borrower.income }}</td>
<th>还款来源</th>
<td>{{ lendDetail.borrower.returnSource }}</td>
</tr>
<tr>
<th>创建时间</th>
<td>{{ lendDetail.borrower.createTime }}</td>
<th>状态</th>
<td>{{ lendDetail.borrower.status }}</td>
</tr>
</tbody>
</table>
<el-row style="text-align:center;margin-top: 40px;">
<el-button @click="back">
返回
</el-button>
</el-row>
</div>
</template>
24、我要投资
24.1、投资标的列表
24.1.1、需求
24.1.2、后端实现
Controller
LendController中创建list方法
package com.atguigu.srb.core.controller.api;
@Api(tags = "标的")
@RestController
@RequestMapping("/api/core/lend")
@Slf4j
public class LendController {
@Resource
private LendService lendService;
@ApiOperation("获取标的列表")
@GetMapping("/list")
public R list() {
List<Lend> lendList = lendService.selectList();
return R.ok().data("lendList", lendList);
}
}
24.1.3、前端整合
pages/lend/index.vue
脚本
此处使用了服务器端渲染
async asyncData({ $axios }) {
let response = await $axios.$get('/api/core/lend/list')
return {
lendList: response.data.lendList,
}
},
本文章参考B站 尚硅谷《尚融宝》Java微服务分布式金融项目,仅供个人学习使用,部分内容为本人自己见解,与尚硅谷无关。