• 【金融项目】尚融宝项目(十四)


    27、放款

    27.1、需求介绍

    27.1.1、平台放款

    1、需求描述

    标的募资时间到,平台会操作放款或撤标,如果达到放款条件则操作放款

    说明:撤标过程与放款过程一致,处理业务相对简单,只是将出借金额返回给出借人即可,同学可以自行完成

    2、相关数据库表

    还款人还款记录:lend_return

    投资人回款记录:lend_item_return

    3、参考文档

    参考《汇付宝商户账户技术文档》3.11满标放款

    27.1.2、具体步骤

    step1:放款

    放款是一个同步接口,如果放款返回成功,那么我们要处理平台业务

    step2:处理业务如下

    (1)标的状态和标的平台收益

    (2)给借款账号转入金额

    (3)增加借款交易流水

    (4)解冻并扣除投资人资金

    (5)增加投资人交易流水

    (6)生成借款人还款计划和出借人回款计划

    27.2、管理平台放款

    27.2.1、后端接口

    1、Controller

    AdminLendController

    @ApiOperation("放款")
    @GetMapping("/makeLoan/{id}")
    public R makeLoan(
        @ApiParam(value = "标的id", required = true)
        @PathVariable("id") Long id) {
        lendService.makeLoan(id);
        return R.ok().message("放款成功");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2、满标放款

    接口:LendService

    /**
         * 满标放款
         * @param lendId
         */
    void makeLoan(Long lendId);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实现:LendServiceImpl

    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private UserAccountMapper userAccountMapper;
    @Resource
    private LendItemService lendItemService;
    @Resource
    private TransFlowService transFlowService;
    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void makeLoan(Long lendId) {
        //获取标的信息
        Lend lend = baseMapper.selectById(lendId);
        //放款接口调用
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("agentId", HfbConst.AGENT_ID);
        paramMap.put("agentProjectCode", lend.getLendNo());//标的编号
        String agentBillNo = LendNoUtils.getLoanNo();//放款编号
        paramMap.put("agentBillNo", agentBillNo);
        //平台收益,放款扣除,借款人借款实际金额=借款金额-平台收益
        //月年化
        BigDecimal monthRate = lend.getServiceRate().divide(new BigDecimal(12), 8, RoundingMode.DOWN);
        //平台实际收益 = 已投金额 * 月年化 * 标的期数
        BigDecimal realAmount = lend.getInvestAmount().multiply(monthRate).multiply(new BigDecimal(lend.getPeriod()));
        paramMap.put("mchFee", realAmount); //商户手续费(平台实际收益)
        paramMap.put("timestamp", RequestHelper.getTimestamp());
        String sign = RequestHelper.getSign(paramMap);
        paramMap.put("sign", sign);
        log.info("放款参数:" + JSONObject.toJSONString(paramMap));
        //发送同步远程调用
        JSONObject result = RequestHelper.sendRequest(paramMap, HfbConst.MAKE_LOAD_URL);
        log.info("放款结果:" + result.toJSONString());
        //放款失败
        if (!"0000".equals(result.getString("resultCode"))) {
            throw new BusinessException(result.getString("resultMsg"));
        }
        //更新标的信息
        lend.setRealAmount(realAmount);
        lend.setStatus(LendStatusEnum.PAY_RUN.getStatus());
        lend.setPaymentTime(LocalDateTime.now());
        baseMapper.updateById(lend);
        //获取借款人信息
        Long userId = lend.getUserId();
        UserInfo userInfo = userInfoMapper.selectById(userId);
        String bindCode = userInfo.getBindCode();
        //给借款账号转入金额
        BigDecimal total = new BigDecimal(result.getString("voteAmt"));
        userAccountMapper.updateAccount(bindCode, total, new BigDecimal(0));
        //新增借款人交易流水
        TransFlowBO transFlowBO = new TransFlowBO(
            agentBillNo,
            bindCode,
            total,
            TransTypeEnum.BORROW_BACK,
            "借款放款到账,编号:" + lend.getLendNo());//项目编号
        transFlowService.saveTransFlow(transFlowBO);
        //获取投资列表信息
        List<LendItem> lendItemList = lendItemService.selectByLendId(lendId, 1);
        lendItemList.stream().forEach(item -> {
            //获取投资人信息
            Long investUserId = item.getInvestUserId();
            UserInfo investUserInfo = userInfoMapper.selectById(investUserId);
            String investBindCode = investUserInfo.getBindCode();
            //投资人账号冻结金额转出
            BigDecimal investAmount = item.getInvestAmount(); //投资金额
            userAccountMapper.updateAccount(investBindCode, new BigDecimal(0), investAmount.negate());
            //新增投资人交易流水
            TransFlowBO investTransFlowBO = new TransFlowBO(
                LendNoUtils.getTransNo(),
                investBindCode,
                investAmount,
                TransTypeEnum.INVEST_UNLOCK,
                "冻结资金转出,出借放款,编号:" + lend.getLendNo());//项目编号
            transFlowService.saveTransFlow(investTransFlowBO);
        });
        //放款成功生成借款人还款计划和投资人回款计划
        // TODO
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    3、根据lendId获取投资记录

    接口:LendItemService

    List<LendItem> selectByLendId(Long lendId, Integer status);
    
    • 1

    实现:LendItemServiceImpl

    @Override
    public List<LendItem> selectByLendId(Long lendId, Integer status) {
        QueryWrapper<LendItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("lend_id", lendId);
        queryWrapper.eq("status", status);
        return baseMapper.selectList(queryWrapper);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    27.2.2、前端整合

    srb-admin

    1、定义api

    创建 src/api/core/lend.js

      makeLoan(id) {
        return request({
          url: `/admin/core/lend/makeLoan/${id}`,
          method: 'get'
        })
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2、页面模板

    src/views/core/lend/list.vue

    <el-button v-if="scope.row.status == 1" type="warning" size="mini" @click="makeLoan(scope.row.id)">
        放款
    el-button>
    
    • 1
    • 2
    • 3

    3、页面脚本

    src/views/core/lend/list.vue

    makeLoan(id) {
      this.$confirm('确定放款吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          return lendApi.makeLoan(id)
        })
        .then(response => {
          //放款成功则重新获取数据列表
          this.fetchData()
          this.$message({
            type: 'success',
            message: response.message
          })
        })
        .catch(error => {
          console.log('取消', error)
          if (error === 'cancel') {
            this.$message({
              type: 'info',
              message: '已取消放款'
            })
          }
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    27.3、还款计划和回款计划

    27.31、生成还款计划

    LendServiceImpl

    @Resource
    private LendReturnService lendReturnService;
    @Resource
    private LendItemReturnService lendItemReturnService;
    
    /**
    * 生成还款计划
    * @param lend 标的对象
    */
    private void repaymentPlan(Lend lend) {
        // 还款计划列表
        List<LendReturn> lendReturnList = new ArrayList<>();
        // 按还款时间生成还款计划
        int len = lend.getPeriod();
        for (int i = 1; i <= len; i++) {
            // 创建还款计划对象
            LendReturn lendReturn = new LendReturn();
            lendReturn.setReturnNo(LendNoUtils.getReturnNo());
            lendReturn.setLendId(lend.getId());
            lendReturn.setBorrowInfoId(lend.getBorrowInfoId());
            lendReturn.setUserId(lend.getUserId());
            lendReturn.setAmount(lend.getAmount());
            lendReturn.setBaseAmount(lend.getInvestAmount());
            lendReturn.setLendYearRate(lend.getLendYearRate());
            // 当前期数
            lendReturn.setCurrentPeriod(i);
            lendReturn.setReturnMethod(lend.getReturnMethod());
            lendReturn.setFee(new BigDecimal(0));
            // 第二个月开始还款
            lendReturn.setReturnDate(lend.getLendStartDate().plusMonths(i));
            lendReturn.setOverdue(false);
            // 最后一个月标识为最后一次还款
            lendReturn.setLast(i == len);
            lendReturn.setStatus(0);
            lendReturnList.add(lendReturn);
        }
        // 批量保存
        lendReturnService.saveBatch(lendReturnList);
        // 获取lendReturnList中还款期数与还款计划id对应map
        Map<Integer, Long> lendReturnMap = lendReturnList.stream().collect(
            Collectors.toMap(LendReturn::getCurrentPeriod, LendReturn::getId)
        );
        // 回款计划列表
        List<LendItemReturn> lendItemReturnAllList = new ArrayList<>();
        // 获取投资成功的投资记录
        List<LendItem> lendItemList = lendItemService.selectByLendId(lend.getId(), 1);
        for (LendItem lendItem : lendItemList) {
            // 创建回款计划列表
            List<LendItemReturn> lendItemReturnList = this.returnInvest(lendItem, lendReturnMap, lend);
            lendItemReturnAllList.addAll(lendItemReturnList);
        }
        // 更新还款计划中的相关金额数据
        for (LendReturn lendReturn : lendReturnList) {
            BigDecimal sumPrincipal = lendItemReturnAllList.stream()
                // 过滤条件:当回款计划中的还款计划id == 当前还款计划id的时候
                .filter(item -> item.getLendReturnId().longValue() == lendReturn.getId().longValue())
                // 将所有回款计划中计算的每月应收本金相加
                .map(LendItemReturn::getPrincipal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal sumInterest = lendItemReturnAllList.stream()
                .filter(item -> item.getLendReturnId().longValue() == lendReturn.getId().longValue())
                .map(LendItemReturn::getInterest)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal sumTotal = lendItemReturnAllList.stream()
                .filter(item -> item.getLendReturnId().longValue() == lendReturn.getId().longValue())
                .map(LendItemReturn::getTotal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 每期还款本金
            lendReturn.setPrincipal(sumPrincipal);
            // 每期还款利息
            lendReturn.setInterest(sumInterest);
            // 每期还款本息
            lendReturn.setTotal(sumTotal);
        }
        lendReturnService.updateBatchById(lendReturnList);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    27.3.2、生成回款计划

    LendServiceImpl

    /**
    * 生成回款记录
    * @param lendItem 出借记录
    * @param lendReturnMap 还款期数与还款计划ID对应Map
    * @param lend 标的对象
    * @return 回款记录集合
    */
    public List<LendItemReturn> returnInvest(LendItem lendItem, Map<Integer, Long> lendReturnMap, Lend lend) {
        // 投资金额
        BigDecimal amount = lendItem.getInvestAmount();
        // 年化利率
        BigDecimal yearRate = lendItem.getLendYearRate();
        // 投资期数
        int totalMonth = lend.getPeriod();
        // 还款期数 -> 利息
        Map<Integer, BigDecimal> mapInterest;
        // 还款期数 -> 本金
        Map<Integer, BigDecimal> mapPrincipal;
        // 根据还款方式计算本金和利息
        if (lend.getReturnMethod().intValue() == ReturnMethodEnum.ONE.getMethod()) {
            // 利息
            mapInterest = Amount1Helper.getPerMonthInterest(amount, yearRate, totalMonth);
            // 本金
            mapPrincipal = Amount1Helper.getPerMonthPrincipal(amount, yearRate, totalMonth);
        } else if (lend.getReturnMethod().intValue() == ReturnMethodEnum.TWO.getMethod()) {
            mapInterest = Amount2Helper.getPerMonthInterest(amount, yearRate, totalMonth);
            mapPrincipal = Amount2Helper.getPerMonthPrincipal(amount, yearRate, totalMonth);
        } else if (lend.getReturnMethod().intValue() == ReturnMethodEnum.THREE.getMethod()) {
            mapInterest = Amount3Helper.getPerMonthInterest(amount, yearRate, totalMonth);
            mapPrincipal = Amount3Helper.getPerMonthPrincipal(amount, yearRate, totalMonth);
        } else {
            mapInterest = Amount4Helper.getPerMonthInterest(amount, yearRate, totalMonth);
            mapPrincipal = Amount4Helper.getPerMonthPrincipal(amount, yearRate, totalMonth);
        }
        // 创建回款计划列表
        List<LendItemReturn> lendItemReturnList = new ArrayList<>();
        for (Map.Entry<Integer, BigDecimal> entry : mapInterest.entrySet()) {
            Integer currentPeriod = entry.getKey();
            // 根据还款期数获取还款计划的id
            Long lendReturnId = lendReturnMap.get(currentPeriod);
            LendItemReturn lendItemReturn = new LendItemReturn();
            lendItemReturn.setLendReturnId(lendReturnId);
            lendItemReturn.setLendItemId(lendItem.getId());
            lendItemReturn.setInvestUserId(lendItem.getInvestUserId());
            lendItemReturn.setLendId(lendItem.getLendId());
            lendItemReturn.setInvestAmount(lendItem.getInvestAmount());
            lendItemReturn.setLendYearRate(lend.getLendYearRate());
            lendItemReturn.setCurrentPeriod(currentPeriod);
            lendItemReturn.setReturnMethod(lend.getReturnMethod());
            // 最后一次本金,利息计算
            if (lendItemReturnList.size() > 0 && currentPeriod.intValue() == lend.getPeriod().intValue()) {
                // 本金
                BigDecimal sumPrincipal = lendItemReturnList.stream()
                    .map(LendItemReturn::getPrincipal)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                // 最后一期应还本金 = 用当前投资人的总投资金额 - 除了最后一期前面期数计算出来的所有的应还本金
                BigDecimal lastPrincipal = lendItem.getInvestAmount().subtract(sumPrincipal);
                lendItemReturn.setPrincipal(lastPrincipal);
                // 利息
                BigDecimal sumInterest = lendItemReturnList.stream()
                    .map(LendItemReturn::getInterest)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal lastInterest = lendItem.getExpectAmount().subtract(sumInterest);
                lendItemReturn.setPrincipal(lastPrincipal);
                lendItemReturn.setInterest(lastInterest);
            } else {
                // 本金
                lendItemReturn.setPrincipal(mapPrincipal.get(currentPeriod));
                // 利息
                lendItemReturn.setInterest(mapInterest.get(currentPeriod));
            }
            lendItemReturn.setTotal(lendItemReturn.getPrincipal().add(lendItemReturn.getInterest()));
            lendItemReturn.setFee(new BigDecimal("0"));
            lendItemReturn.setReturnDate(lend.getLendStartDate().plusMonths(currentPeriod));
            // 是否逾期,默认未逾期
            lendItemReturn.setOverdue(false);
            lendItemReturn.setStatus(0);
            lendItemReturnList.add(lendItemReturn);
        }
        lendItemReturnService.saveBatch(lendItemReturnList);
        return lendItemReturnList;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    27.3.3、在makeLoan中调用

    LendServiceImpl

    //放款成功生成借款人还款计划和投资人回款计划
    this.repaymentPlan(lend);
    
    • 1
    • 2

    28、投资列表展示

    28.1、管理端显示投资记录

    28.1.1、后端接口

    1、Controller

    创建 AdminLendItemController

    package com.atguigu.srb.core.controller.admin;
    
    @Api(tags = "标的的投资")
    @RestController
    @RequestMapping("/admin/core/lendItem")
    @Slf4j
    public class AdminLendItemController {
        @Resource
        private LendItemService lendItemService;
        @ApiOperation("获取列表")
        @GetMapping("/list/{lendId}")
        public R list(
                @ApiParam(value = "标的id", required = true)
                @PathVariable Long lendId) {
            List<LendItem> list = lendItemService.selectByLendId(lendId);
            return R.ok().data("list", list);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2、Service

    接口:LendItemService

    List<LendItem> selectByLendId(Long lendId);
    
    • 1

    实现:LendItemServiceImpl

    @Override
    public List<LendItem> selectByLendId(Long lendId) {
        QueryWrapper<LendItem> queryWrapper = new QueryWrapper();
        queryWrapper.eq("lend_id", lendId);
        List<LendItem> lendItemList = baseMapper.selectList(queryWrapper);
        return lendItemList;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    28.1.2、前端

    1、创建api

    api/core/lend-item.js

    import request from '@/utils/request'
    
    export default {
      getList(lendId) {
        return request({
          url: `/admin/core/lendItem/list/` + lendId,
          method: 'get'
        })
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、页面脚本

    views/core/lend/detail.vue

    import lendItemApi from '@/api/core/lend-item'
    
    data() {
      return {
        ......,
        lendItemList: [] //投资列表
      }
    },
    created() {
      if (this.$route.params.id) {
        ......
        // 投资记录
        this.fetchLendItemList()
      }
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    methods

    fetchLendItemList() {
      lendItemApi.getList(this.$route.params.id).then(response => {
        this.lendItemList = response.data.list
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、页面模板

    views/core/lend/detail.vue

    将投资记录放在借款人信息后面

    <h4>投资记录h4>
    <el-table :data="lendItemList" stripe style="width: 100%" border>
        <el-table-column type="index" label="序号" width="70" align="center" />
        <el-table-column prop="lendItemNo" label="投资编号" />
        <el-table-column prop="investName" label="投资用户" />
        <el-table-column prop="investAmount" label="投资金额" />
        <el-table-column label="年化利率">
            <template slot-scope="scope">
                {{ scope.row.lendYearRate * 100 }}%
            template>
        el-table-column>
        <el-table-column prop="investTime" label="投资时间" />
        <el-table-column prop="lendStartDate" label="开始日期" />
        <el-table-column prop="lendEndDate" label="结束日期" />
        <el-table-column prop="expectAmount" label="预期收益" />
        <el-table-column prop="investTime" label="投资时间" />
    el-table>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    28.2、网站端显示投资记录

    28.2.1、后端接口

    Controller

    LendItemController

    @ApiOperation("获取列表")
    @GetMapping("/list/{lendId}")
    public R list(
        @ApiParam(value = "标的id", required = true)
        @PathVariable Long lendId) {
        List<LendItem> list = lendItemService.selectByLendId(lendId);
        return R.ok().data("list", list);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    28.2.2、前端

    页面脚本

    pages/lend/_id.vue

    async asyncData({ $axios, params }) {
        ......
        
        //投资记录
        let responseLendItemList = await $axios.$get(
          '/api/core/lendItem/list/' + lendId
        )
        return {
          ......,
          lendItemList: responseLendItemList.data.list, //投资记录
        }
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    28.3、管理端显示还款计划

    28.3.1、后端接口

    1、Controller

    创建AdminLendReturnController

    package com.atguigu.srb.core.controller.admin;
    
    @Api(tags = "还款记录")
    @RestController
    @RequestMapping("/admin/core/lendReturn")
    @Slf4j
    public class AdminLendReturnController {
        @Resource
        private LendReturnService lendReturnService;
        @ApiOperation("获取列表")
        @GetMapping("/list/{lendId}")
        public R list(
                @ApiParam(value = "标的id", required = true)
                @PathVariable Long lendId) {
            List<LendReturn> list = lendReturnService.selectByLendId(lendId);
            return R.ok().data("list", list);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2、Service

    接口:LendReturnService

    List<LendReturn> selectByLendId(Long lendId);
    
    • 1

    实现:LendReturnServiceImpl

    @Override
    public List<LendReturn> selectByLendId(Long lendId) {
        QueryWrapper<LendReturn> queryWrapper = new QueryWrapper();
        queryWrapper.eq("lend_id", lendId);
        List<LendReturn> lendReturnList = baseMapper.selectList(queryWrapper);
        return lendReturnList;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    28.3.2、前端

    1、创建api

    api/core/lend-return.js

    import request from '@/utils/request'
    
    export default {
      getList(lendId) {
        return request({
          url: `/admin/core/lendReturn/list/` + lendId,
          method: 'get'
        })
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、页面脚本

    views/core/lend/detail.vue

    import lendReturnApi from '@/api/core/lend-return'
    
    data() {
      return {
        ......,
        lendReturnList: [] //还款计划列表
      }
    },
    created() {
      if (this.$route.params.id) {
        ......
        // 还款计划
        this.fetchLendReturnList()
      }
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    methods

    fetchLendReturnList() {
        lendReturnApi.getList(this.$route.params.id).then(response => {
            this.lendReturnList = response.data.list
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、页面模板

    views/core/lend/detail.vue

    将还款计划放在投资记录后面

    <h4>还款计划h4>
    <el-table :data="lendReturnList" stripe style="width: 100%" border>
        <el-table-column type="index" label="序号" width="70" align="center" />
        <el-table-column prop="currentPeriod" label="当前的期数" />
        <el-table-column prop="principal" label="本金" />
        <el-table-column prop="interest" label="利息" />
        <el-table-column prop="total" label="本息" />
        <el-table-column prop="returnDate" label="还款日期" width="150" />
        <el-table-column prop="realReturnTime" label="实际还款时间" />
        <el-table-column label="是否逾期">
            <template slot-scope="scope">
                <span v-if="scope.row.overdue">
                    是(逾期金额:{{ scope.row.overdueTotal }}元)
                span>
                <span v-else>span>
            template>
        el-table-column>
        <el-table-column label="状态" width="80">
            <template slot-scope="scope">
                {{ scope.row.status === 0 ? '未还款' : '已还款' }}
            template>
        el-table-column>
    el-table>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    28.4、网站端显示还款计划

    28.4.1、后端接口

    Controller

    创建 LendReturnController

    package com.atguigu.srb.core.controller.api;
    
    @Api(tags = "还款计划")
    @RestController
    @RequestMapping("/api/core/lendReturn")
    @Slf4j
    public class LendReturnController {
        @Resource
        private LendReturnService lendReturnService;
        @ApiOperation("获取列表")
        @GetMapping("/list/{lendId}")
        public R list(
                @ApiParam(value = "标的id", required = true)
                @PathVariable Long lendId) {
            List<LendReturn> list = lendReturnService.selectByLendId(lendId);
            return R.ok().data("list", list);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    28.4.2、前端

    页面脚本

    pages/lend/_id.vue

    async asyncData({ $axios, params }) {
        ......
        
        //还款计划
        let responseLendReturnList = await $axios.$get(
          '/api/core/lendReturn/list/' + lendId
        )
        return {
          ......,
          lendReturnList: responseLendReturnList.data.list, //还款计划
        }
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    28.5、网站端显示回款计划

    28.5.1、后端接口

    1、Controller

    创建 LendItemReturnController

    package com.atguigu.srb.core.controller.api;
    
    @Api(tags = "回款计划")
    @RestController
    @RequestMapping("/api/core/lendItemReturn")
    @Slf4j
    public class LendItemReturnController {
        @Resource
        private LendItemReturnService lendItemReturnService;
        @ApiOperation("获取列表")
        @GetMapping("/auth/list/{lendId}")
        public R list(
                @ApiParam(value = "标的id", required = true)
                @PathVariable Long lendId, HttpServletRequest request) {
            String token = request.getHeader("token");
            Long userId = JwtUtils.getUserId(token);
            List<LendItemReturn> list = lendItemReturnService.selectByLendId(lendId, userId);
            return R.ok().data("list", list);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2、Service

    接口:LendItemReturnService

    List<LendItemReturn> selectByLendId(Long lendId, Long userId);
    
    • 1

    实现:LendItemReturnServiceImpl

    @Override
    public List<LendItemReturn> selectByLendId(Long lendId, Long userId) {
        QueryWrapper<LendItemReturn> queryWrapper = new QueryWrapper<>();
        queryWrapper
            .eq("lend_id", lendId)
            .eq("invest_user_id", userId)
            .orderByAsc("current_period");
        return baseMapper.selectList(queryWrapper);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    28.5.2、前端

    1、页面脚本

    pages/lend/_id.vue

    data() {
      return {
        ......,
        lendItemReturnList: [], //回款计划
      }
    },
    mounted() {
      ......
      //回款计划
      this.fetchLendItemReturnList()
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    methods

    //回款计划
    fetchLendItemReturnList() {
        this.$axios
            .$get('/api/core/lendItemReturn/auth/list/' + this.$route.params.id)
            .then((response) => {
            this.lendItemReturnList = response.data.list
        })
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2、页面模板

    pages/lend/_id.vue

    
    <div class="item-detail-body clearfix mrt30 ui-tab">
        <div class="ui-tab-nav hd">
            <ul>
                <li class="nav_li active">
                    <a href="javascript:;">回款计划a>
                li>
            ul>
        div>
        <div class="bd">
            <div class="ui-tab-item active" style="display: block;">
                <div class="repayment-list">
                    <table border="0" cellpadding="0" cellspacing="0" width="100%">
                        <thead>
                            <tr>
                                <th>期数th>
                                <th>本金(元)th>
                                <th>利息(元)th>
                                <th>本息(元)th>
                                <th>计划回款日期th>
                                <th>实际回款日期th>
                                <th>状态th>
                                <th>是否逾期th>
                            tr>
                        thead>
                        <tbody id="repayment_content">
                            <tr
                                v-for="lendItemReturn in lendItemReturnList"
                                :key="lendItemReturn.id"
                                >
                                <td>{{ lendItemReturn.currentPeriod }}td>
                                <td class="c-orange">¥{{ lendItemReturn.principal }}td>
                                <td class="c-orange">¥{{ lendItemReturn.interest }}td>
                                <td class="c-orange">¥{{ lendItemReturn.total }}td>
                                <td>{{ lendItemReturn.returnDate }}td>
                                <td>{{ lendItemReturn.realReturnTime }}td>
                                <td>
                                    {{ lendItemReturn.status === 0 ? '未还款' : '已还款' }}
                                td>
                                <td>
                                    <span v-if="lendItemReturn.overdue">
                                        是(逾期金额:{{ lendReturn.overdueTotal }}元)
                                    span>
                                    <span v-else>span>
                                td>
                            tr>
                        tbody>
                    table>
                div>
            div>
        div>
    div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    本文章参考B站 尚硅谷《尚融宝》Java微服务分布式金融项目,仅供个人学习使用,部分内容为本人自己见解,与尚硅谷无关。

  • 相关阅读:
    (七)Flask之路由转换器
    Python应用爬虫下载QQ音乐歌曲!
    源代码转换:Tangible Software Solutions v22.10.20
    0036力扣507题---完美数
    K8S Pod Sidecar 应用场景之一-加入 NGINX Sidecar 做反代和 web 服务器
    【迁移学习】迁移学习的基本概念与应用
    宜搭,怎么在公式编辑中计算百分比的和?
    SpringBoot+Vue项目疫情防控期间某村外出务工人员信息管理系统
    ElasticSearch--分片和副本--原理
    力扣第47题 全排列 || c++ 回溯 双层去重 思路+注释
  • 原文地址:https://blog.csdn.net/Chovy_pyc/article/details/127947249