核心业务3:借款人借款申请

核心业务3:借款人借款申请

1.借款人借款申请业务流程图

2.借款项数据库绑定

---------------------借款申请流程----------------------

3.借款申请流程

4.前端代码逻辑

5.后端代码逻辑

---------------------借款申请流程----------------------
---------------------管理员审核----------------------

6.管理员审核流程业务图

7.管理员审核流程

8.前端代码逻辑

9.后端代码逻辑

---------------------管理员审核----------------------

10.创建标的TODO

核心业务3:借款人借款申请

1.借款人借款申请业务流程图

在这里插入图片描述

①此时用户已经获得了积分,可以在额度申请页面点击我要借款

在这里插入图片描述

②点击我要借款后展示借款信息填写页

在这里插入图片描述

③借款信息提交后显示等待审核

在这里插入图片描述

④后台管理员审核技术后获取审核结果

在这里插入图片描述

2.借款项数据库绑定

①数据库表

borrow_info
在这里插入图片描述
integral_grade
在这里插入图片描述

②关联

  • borrow_info表通过user_id与user_info关联,即一个user只能发起一次借款
  • user_info的积分字段可查integral_grade表获取对应额度,然后borrow_info根据user_info的额度来发起借款
  • borrow表和borrow_info表无关,两者都只是通过user_id与user_info关联,一个是借款额度申请表单,一个是借款申请表单

3.借款申请流程

①前端

  • 用户在注册登陆绑定数据和获得额度之后,可以发起我要借款
  • 进入界面判断借款的状态,如果未借款进入表单界面,如果其他状态跳到响应的界面
  • 表单数据的填写,用户可以看到自己的额度(调用api),用户也可以再下拉列表里填写数据(调用api)
  • 用户填写完表单后提交后台

②后端

  • 用户刚进入借款页面判断用户借款状态(通过user_id查询borrow_info看用户借款状态)
  • 用户未发起借款,需要返回数据字典数据初始化下拉列表,需要返回用户的借款额度
  • 用户提交表单,需要校验(防止恶意用户跳过入口直接访问后台),然后保存数据到borrow_info表

4.前端代码逻辑

①前端封装表单对象

在这里插入图片描述

②前端调用接口

在这里插入图片描述

③前端代码

  • 增加按钮到借款额度申请成功页
    srb-site\pages\user\borrower.vue
    添加按钮到审批通过组件下
 <!--在审批通过后,增加我要借款按钮,进入借款信息页面-->
          <NuxtLink to="/user/apply" v-if="borrowerStatus === 2">
            <el-button style="margin-top:20px;" type="success">
              我要借款
            </el-button>
          </NuxtLink>
  • 借款申请页面
    srb-site\pages\user\apply.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">
        <el-form label-width="120px">
          <el-form-item label="借款金额">
            <el-col :span="6">
              <el-input v-model="borrowInfo.amount" />
            </el-col>
            <el-col :span="6">
              &nbsp;&nbsp;您最多可借款{{ borrowAmount }}</el-col>
          </el-form-item>

          <el-form-item label="期数">
            <el-select v-model="borrowInfo.period">
              <el-option :value="1" label="1个月" />
              <el-option :value="3" label="3个月" />
              <el-option :value="6" label="6个月" />
              <el-option :value="9" label="9个月" />
              <el-option :value="12" label="12个月" />
              <el-option :value="24" label="24个月" />
            </el-select>
          </el-form-item>

          <el-form-item label="还款方式">
            <el-select v-model="borrowInfo.returnMethod">
              <el-option
                v-for="item in returnMethodList"
                :key="item.value"
                :label="item.name"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="资金用途">
            <el-select v-model="borrowInfo.moneyUse">
              <el-option
                v-for="item in moneyUseList"
                :key="item.value"
                :label="item.name"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="年利率">
            <el-col :span="6">
              <el-input v-model="borrowInfo.borrowYearRate">
                <template slot="append">%</template>
              </el-input>
            </el-col>
            <el-col :span="8">
              &nbsp;&nbsp;年利率越高,借款越容易成功。
            </el-col>
          </el-form-item>
          <el-form-item>
            <el-button
              type="primary"
              :disabled="submitBtnDisabled"
              @click="save"
            >
              提交
            </el-button>
          </el-form-item>
        </el-form>
        <el-alert
          title="您提供的任何信息尚融宝都承诺予以保护,不会挪作他用。"
          type="warning"
          :closable="false"
        >
        </el-alert>
      </div>

      <div v-if="active === 1">
        <div style="margin-top:40px;">
          <el-alert
            title="您的借款申请已成功提交,请耐心等待"
            type="warning"
            show-icon
            :closable="false"
          >
            我们将在10分钟内完成审核,审核时间为周一至周五8:0020:00</el-alert>
        </div>
      </div>

      <div v-if="active === 2">
        <div style="margin-top:40px;">
          <el-alert
            v-if="borrowInfoStatus === 2"
            title="您的借款申请审批已通过"
            type="success"
            show-icon
            :closable="false"
          >
          </el-alert>

          <el-alert
            v-if="borrowInfoStatus === -1"
            title="您的借款申请审批未通过"
            type="error"
            show-icon
            :closable="false"
          >
          </el-alert>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      active: null, //步骤
      borrowInfoStatus: null, //审批状态
      //借款申请
      borrowInfo: {
        borrowYearRate: '12',
      },
      borrowAmount: 0, //借款额度
      submitBtnDisabled: false,
      returnMethodList: [], //还款方式列表
      moneyUseList: [], //资金用途列表
    }
  },
  methods: {
    //初始化下拉列表的数据
    initSelected() {
      //还款方式列表
      this.$axios
        .$get('/api/core/dict/findByDictCode/returnMethod')
        .then((response) => {
          this.returnMethodList = response.data.dictList
        })

      //资金用途列表
      this.$axios
        .$get('/api/core/dict/findByDictCode/moneyUse')
        .then((response) => {
          this.moneyUseList = response.data.dictList
        })
    },
    //获取借款额度
    getBorrowAmount() {
      this.$axios
        .$get('/api/core/borrowInfo/auth/getBorrowAmount')
        .then((response) => {
          this.borrowAmount = response.data.borrowAmount
        })
    },
    //提交借款申请
    save() {
      // this.submitBtnDisabled = true
      this.$axios
        .$post('/api/core/borrowInfo/auth/save', this.borrowInfo)
        .then((response) => {
          this.active = 1
        })
    },
    //获取借款审批状态
    getBorrowInfoStatus() {
      this.$axios
        .$get('/api/core/borrowInfo/auth/getBorrowInfoStatus')
        .then((response) => {
          this.borrowInfoStatus = response.data.borrowInfoStatus
          if (this.borrowInfoStatus === 0) {
            //未认证
            this.active = 0
            //获取借款额度
            this.getBorrowAmount()
            //初始化下拉列表
            this.initSelected()
          } else if (this.borrowInfoStatus === 1) {
            //审批中
            this.active = 1
          } else if (this.borrowInfoStatus === 2) {
            //审批成功
            this.active = 2
          } else if (this.borrowInfoStatus === -1) {
            //审批失败
            this.active = 2
          }
        })
    },
  },
  created() {
    //created方法默认情况下在前端服务器执行,而不是在浏览器执行,前端服务器端执行失败,在浏览器端还会再发起请求(浏览器端成功)
    //即在nuxt前端服务器初始化时候并没有带token,故可以用mounted渲染,mounted一定在浏览器端执行(渲染完成后执行)

    //获取借款额度
    //this.getBorrowAmount()

    //初始化下拉列表
    //this.initSelected()

    //获取审批状态
    this.getBorrowInfoStatus()
  },
  //监听某一个值,如果这一值一旦改变则调用
  watch: {
    'borrowInfo.amount'(value) {
      if (value > this.borrowAmount) {
        let _this = this
        this.$alert('您的借款额度不足!', {
          type: 'error',
          //当错误信息弹出完毕之后点击确定,然后执行回调函数
          callback() {
            //this的作用域和外部的作用域不一样(callback的作用域和外面的this不一样,需要传入this)
            _this.borrowInfo.amount = _this.borrowAmount
          },
        })
      }
    },
  },
}
</script>

④前端代码逻辑难点

  • 需要监听额度字段如果超过最大额度设置其值为最大额度
    用watch方法监听字段
    在这里插入图片描述

5.后端代码逻辑

①后端对象

  • borrow_info对象即可不需要专门创建vo对象

②后端接口

在这里插入图片描述

③后端代码

  • 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.entity.BorrowInfo;
import com.atguigu.srb.core.service.BorrowInfoService;
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;
import java.math.BigDecimal;

@Api(tags = "借款信息")
@RestController
@RequestMapping("/api/core/borrowInfo")
@Slf4j
public class BorrowInfoController {

    @Resource
    private BorrowInfoService borrowInfoService;


    @ApiOperation("获取借款额度")
    @GetMapping("/auth/getBorrowAmount")
    public R getBorrowAmount(HttpServletRequest request) {
        String token = request.getHeader("token");
        Long userId = JwtUtils.getUserId(token);
        BigDecimal borrowAmount = borrowInfoService.getBorrowAmount(userId);
        return R.ok().data("borrowAmount", borrowAmount);
    }


    @ApiOperation("提交借款申请")
    @PostMapping("/auth/save")
    public R save(@RequestBody BorrowInfo borrowInfo, HttpServletRequest request) {

        //目标就是把用户提交的数据保存到数据表borrow_info中


        //该接口防止恶意攻击
        //前端不提供入口 + 后端进行校验(是否绑定,是否审批借款申请)
        String token = request.getHeader("token");
        Long userId = JwtUtils.getUserId(token);
        //将借款信息存储数据库,校验用户是否绑定和审批
        borrowInfoService.saveBorrowInfo(borrowInfo, userId);
        return R.ok().message("提交成功");
    }



    @ApiOperation("获取借款申请审批状态")
    @GetMapping("/auth/getBorrowInfoStatus")
    public R getBorrowerStatus(HttpServletRequest request){
        String token = request.getHeader("token");
        Long userId = JwtUtils.getUserId(token);
        Integer status = borrowInfoService.getStatusByUserId(userId);
        return R.ok().data("borrowInfoStatus", status);
    }
}
  • service
package com.atguigu.srb.core.service;

import com.atguigu.srb.core.pojo.entity.BorrowInfo;
import com.baomidou.mybatisplus.extension.service.IService;

import java.math.BigDecimal;

/**
 * <p>
 * 借款信息表 服务类
 * </p>
 *
 * @author Likejin
 * @since 2023-04-09
 */
public interface BorrowInfoService extends IService<BorrowInfo> {

    BigDecimal getBorrowAmount(Long userId);

    void saveBorrowInfo(BorrowInfo borrowInfo, Long userId);

    Integer getStatusByUserId(Long userId);
}

package com.atguigu.srb.core.service.impl;

import com.atguigu.common.exception.Assert;
import com.atguigu.common.result.ResponseEnum;
import com.atguigu.srb.core.enums.BorrowInfoStatusEnum;
import com.atguigu.srb.core.enums.BorrowerStatusEnum;
import com.atguigu.srb.core.enums.UserBindEnum;
import com.atguigu.srb.core.mapper.BorrowInfoMapper;
import com.atguigu.srb.core.mapper.IntegralGradeMapper;
import com.atguigu.srb.core.mapper.UserInfoMapper;
import com.atguigu.srb.core.pojo.entity.BorrowInfo;
import com.atguigu.srb.core.pojo.entity.IntegralGrade;
import com.atguigu.srb.core.pojo.entity.UserInfo;
import com.atguigu.srb.core.service.BorrowInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

/**
 * <p>
 * 借款信息表 服务实现类
 * </p>
 *
 * @author Likejin
 * @since 2023-04-09
 */
@Service
public class BorrowInfoServiceImpl extends ServiceImpl<BorrowInfoMapper, BorrowInfo> implements BorrowInfoService {

    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private IntegralGradeMapper integralGradeMapper;

    /**
     * @param userId:
     * @return BigDecimal
     * @author Likejin
     * @description 根据用户id查询用户积分,根据积分获取用户额度
     * @date 2023/4/16 14:30
     */

    @Override
    public BigDecimal getBorrowAmount(Long userId) {
        //获取用户积分
        UserInfo userInfo = userInfoMapper.selectById(userId);
        Assert.notNull(userInfo, ResponseEnum.LOGIN_MOBILE_ERROR);
        Integer integral = userInfo.getIntegral();

        //根据积分获取用户额度
        QueryWrapper<IntegralGrade> integralGradeQueryWrapper = new QueryWrapper<>();
        //做一个区间比较,le为大于左边,ge为小于右边
        integralGradeQueryWrapper
                .le("integral_start",integral)
                .ge("integral_end",integral);
        IntegralGrade integralGrade = integralGradeMapper.selectOne(integralGradeQueryWrapper);
        if(integralGrade == null){
            return new BigDecimal("0");
        }
        return integralGrade.getBorrowAmount();
    }

    /**
     * @param borrowInfo:
     * @param userId:
     * @return void
     * @author Likejin
     * @description 将借款信息存储数据库,校验用户是否绑定和审批
     * @date 2023/4/16 15:11
     */

    @Override
    public void saveBorrowInfo(BorrowInfo borrowInfo, Long userId) {
        //校验绑定状态和借款人额度审批状态
        UserInfo userInfo = userInfoMapper.selectById(userId);
        Assert.isTrue(userInfo.getBindStatus().intValue() == UserBindEnum.BIND_OK.getStatus().intValue(),
                ResponseEnum.USER_NO_BIND_ERROR);
        Assert.isTrue(userInfo.getBorrowAuthStatus().intValue() == BorrowerStatusEnum.AUTH_OK.getStatus().intValue(),
                ResponseEnum.USER_NO_AMOUNT_ERROR);

        //判断借款人额度是否充足
        BigDecimal borrowAmount = this.getBorrowAmount(userId);
        Assert.isTrue(borrowInfo.getAmount().doubleValue() <=borrowAmount.doubleValue(),
                ResponseEnum.USER_AMOUNT_LESS_ERROR);


        //存储borrower_info数据
        borrowInfo.setUserId(userId);
        //百分比转小数
        borrowInfo.setBorrowYearRate(borrowInfo.getBorrowYearRate().divide(new BigDecimal(100)));
        //设置借款申请的审核状态
        borrowInfo.setStatus(BorrowInfoStatusEnum.CHECK_RUN.getStatus());
        baseMapper.insert(borrowInfo);
    }

    /**
     * @param userId:
     * @return Integer
     * @author Likejin
     * @description 获取用户申请借款的状态
     * @date 2023/4/16 15:35
     */
    @Override
    public Integer getStatusByUserId(Long userId) {
        //根据user_id查询用户的借款申请状态
        QueryWrapper<BorrowInfo> borrowInfoQueryWrapper = new QueryWrapper<>();
        borrowInfoQueryWrapper.select("status").eq("user_id", userId);
        List<Object> objects = baseMapper.selectObjs(borrowInfoQueryWrapper);

        if(objects.size() == 0){
            //借款人尚未提交信息
            return BorrowInfoStatusEnum.NO_AUTH.getStatus();
        }
        Integer status = (Integer)objects.get(0);
        return status;
    }
}

④后端代码逻辑难点

  • 获取借款额度
    通过token获得user_id,然后通过user_id查询user_info获得积分,在通过查表integral_grade表的的区间查询(根据积分所在的区间查询对应的额度)获取额度
  • 提交借贷申请
    需要从token中拿到user_id,通过user_id校验user是否绑定和是否申请借款额度(防止恶意攻击),还需要通过user_id校验该user的额度是否没被申请的额度超过,封装数据(年利率前端传整型,后端小数,除以100),设置借款流程的状态borrow_info的status,保存数据到数据库。
  • 获取借款流程状态
    直接根据user_id查询borrow_info中的status即可。

6.管理员审核流程业务图

①后台管理系统中展示页面

在这里插入图片描述

②查看可以查看具体信息

在这里插入图片描述

③增加审批按钮

在这里插入图片描述

④点击审批按钮出现弹窗表单

在这里插入图片描述

⑤提交确定按钮修改状态隐藏审批按钮

在这里插入图片描述

7.管理员审核流程

①管理员进入管理系统后在借款管理查看借款列表

  • 前端:增加路由导航,访问后端api
  • 后端:查询借款列表所需要的所有信息返回前端

②管理员查看借款列表后可以查看详细信息

  • 前端:增加查看详细信息按钮,访问后端api
  • 后端:查询该借款项具体信息返回给前端

③管理员点击审批按钮

  • 前端:增加审批按钮,能够弹出表单,点击提交时访问后端api
  • 后端:能够根据提交的数据修改审批状态,生成标的

8.前端代码逻辑

①前端封装对象

  • 在借款管理查看借款列表
    在这里插入图片描述
  • 查看借款的详细信息
    在这里插入图片描述
  • 审批对话框
    在这里插入图片描述

②前端调用api

在这里插入图片描述

③前端具体代码

  • 增加路由导航(管理系统右端导航生成)
    srb-admin\src\router\index.js
//借款列表子路由(放在借款管理的children里面)
      {
        path: 'info-list',
        name: 'coreBorrowInfoList',
        component: () => import('@/views/core/borrow-info/list'),
        meta: { title: '借款列表' },
      },
      {
        path: 'info-detail/:id',
        name: 'coreBorrowInfoDetail',
        component: () => import('@/views/core/borrow-info/detail'),
        meta: { title: '借款详情' },
        hidden: true,
      },
  • 增加api方法
    srb-admin\src\api\core\borrow-info.js
import request from '@/utils/request'

export default {
  //获得借款项的全部列表
  getList() {
    return request({
      url: `/admin/core/borrowInfo/list`,
      method: 'get',
    })
  },
  //展示借款项的详细信息
  show(id) {
    return request({
      url: `/admin/core/borrowInfo/show/${id}`,
      method: 'get',
    })
  },
  //提交审批结果
  approval(borrowInfoApproval) {
    return request({
      url: '/admin/core/borrowInfo/approval',
      method: 'post',
      data: borrowInfoApproval,
    })
  },
}

  • 具体list页面(展示列表和审批对话框)
    srb-admin\src\views\core\borrow-info\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="name" label="借款人姓名" width="90" />
      <el-table-column prop="mobile" label="手机" />
      <el-table-column prop="amount" label="借款金额" />
      <el-table-column label="借款期限" width="90">
        <template slot-scope="scope">{{ scope.row.period }}个月</template>
      </el-table-column>
      <el-table-column prop="param.returnMethod" label="还款方式" width="150" />
      <el-table-column prop="param.moneyUse" label="资金用途" width="100" />
      <el-table-column label="年化利率" width="90">
        <template slot-scope="scope">
          {{ scope.row.borrowYearRate * 100 }}%
        </template>
      </el-table-column>
      <el-table-column prop="param.status" label="状态" width="100" />

      <el-table-column prop="createTime" label="申请时间" width="150" />

      <el-table-column label="操作" width="150" align="center">
        <template slot-scope="scope">
          <el-button type="primary" size="mini">
            <router-link :to="'/core/borrower/info-detail/' + scope.row.id">
              查看
            </router-link>
          </el-button>

          <el-button
            v-if="scope.row.status === 1"
            type="warning"
            size="mini"
            @click="approvalShow(scope.row)"
          >
            审批
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 审批对话框 -->
    <el-dialog title="审批" :visible.sync="dialogVisible" width="490px">
      <el-form label-position="right" label-width="100px">
        <el-form-item label="是否通过">
          <el-radio-group v-model="borrowInfoApproval.status">
            <el-radio :label="2">通过</el-radio>
            <el-radio :label="-1">不通过</el-radio>
          </el-radio-group>
        </el-form-item>

        <el-form-item v-if="borrowInfoApproval.status == 2" label="标的名称">
          <el-input v-model="borrowInfoApproval.title" />
        </el-form-item>

        <el-form-item v-if="borrowInfoApproval.status == 2" label="起息日">
          <el-date-picker
            v-model="borrowInfoApproval.lendStartDate"
            type="date"
            placeholder="选择开始时间"
            value-format="yyyy-MM-dd"
          />
        </el-form-item>

        <el-form-item v-if="borrowInfoApproval.status == 2" label="年化收益率">
          <el-input v-model="borrowInfoApproval.lendYearRate">
            <template slot="append">%</template>
          </el-input>
        </el-form-item>

        <el-form-item v-if="borrowInfoApproval.status == 2" label="服务费率">
          <el-input v-model="borrowInfoApproval.serviceRate">
            <template slot="append">%</template>
          </el-input>
        </el-form-item>

        <el-form-item v-if="borrowInfoApproval.status == 2" label="标的描述">
          <el-input v-model="borrowInfoApproval.lendInfo" type="textarea" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="approvalSubmit">确定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import borrowInfoApi from '@/api/core/borrow-info'

export default {
  data() {
    return {
      list: [],
      dialogVisible: false, //审批对话框 默认不显示
      borrowInfoApproval: {
        status: 2, //默认统一
        serviceRate: 5, //默认收费利率百分之五
        lendYearRate: 0, //初始化,解决表单中数据修改时无法及时渲染的问题(有些浏览器有问题)
      }, //审批对象
    }
  },
  created() {
    this.fetchData()
  },
  methods: {
    fetchData() {
      borrowInfoApi.getList().then((response) => {
        this.list = response.data.list
      })
    },

    //点击审批后发送的时间(预先组装审批对象)
    approvalShow(row) {
      this.dialogVisible = true
      this.borrowInfoApproval.lendYearRate = row.borrowYearRate * 100
      this.borrowInfoApproval.id = row.id
    },
    approvalSubmit() {
      borrowInfoApi.approval(this.borrowInfoApproval).then((response) => {
        this.dialogVisible = false //关闭对话框
        this.$message.success(response.message) //弹出审批结果
        this.fetchData() //关闭对话框后列表页刷新(状态刷新)
      })
    },
  },
}
</script>

  • 借款详情
    srb-admin\src\views\core\borrow-info\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%">{{ borrowInfoDetail.borrowInfo.amount }}</td>
          <th width="15%">借款期限</th>
          <td width="35%">{{ borrowInfoDetail.borrowInfo.period }}个月</td>
        </tr>
        <tr>
          <th>年化利率</th>
          <td>{{ borrowInfoDetail.borrowInfo.borrowYearRate * 100 }}%</td>
          <th>还款方式</th>
          <td>{{ borrowInfoDetail.borrowInfo.param.returnMethod }}</td>
        </tr>

        <tr>
          <th>资金用途</th>
          <td>{{ borrowInfoDetail.borrowInfo.param.moneyUse }}</td>
          <th>状态</th>
          <td>{{ borrowInfoDetail.borrowInfo.param.status }}</td>
        </tr>
        <tr>
          <th>创建时间</th>
          <td>{{ borrowInfoDetail.borrowInfo.createTime }}</td>
          <th></th>
          <td></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>{{ borrowInfoDetail.borrower.name }}</b>
          </td>
          <th width="15%">手机</th>
          <td width="35%">{{ borrowInfoDetail.borrower.mobile }}</td>
        </tr>
        <tr>
          <th>身份证</th>
          <td>{{ borrowInfoDetail.borrower.idCard }}</td>
          <th>性别</th>
          <td>{{ borrowInfoDetail.borrower.sex }}</td>
        </tr>
        <tr>
          <th>年龄</th>
          <td>{{ borrowInfoDetail.borrower.age }}</td>
          <th>是否结婚</th>
          <td>{{ borrowInfoDetail.borrower.marry }}</td>
        </tr>
        <tr>
          <th>学历</th>
          <td>{{ borrowInfoDetail.borrower.education }}</td>
          <th>行业</th>
          <td>{{ borrowInfoDetail.borrower.industry }}</td>
        </tr>
        <tr>
          <th>月收入</th>
          <td>{{ borrowInfoDetail.borrower.income }}</td>
          <th>还款来源</th>
          <td>{{ borrowInfoDetail.borrower.returnSource }}</td>
        </tr>
        <tr>
          <th>创建时间</th>
          <td>{{ borrowInfoDetail.borrower.createTime }}</td>
          <th>状态</th>
          <td>{{ borrowInfoDetail.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>

<script>
import borrowInfoApi from '@/api/core/borrow-info'
import '@/styles/show.css'

export default {
  data() {
    //未定义报错的是数据内部的成员一开始获得不了则未定义,可以在数据对象中显示定义后
    return {
      borrowInfoDetail: {
        borrowInfo: {
          param: {},
        },
        borrower: {},
      },
    }
  },
  created() {
    if (this.$route.params.id) {
      this.fetchDataById()
    }
  },
  methods: {
    fetchDataById() {
      borrowInfoApi.show(this.$route.params.id).then((response) => {
        this.borrowInfoDetail = response.data.borrowInfoDetail
      })
    },
    back() {
      this.$router.push({ path: '/core/borrower/info-list' })
    },
  },
}
</script>

④前端复杂逻辑

  • 封装审批数据
    需要在点击审批后组装后端需要的id和审批单中和外部相同的年利率,注意乘以100
  • 如何检查报错
    如果在浏览器控制台报错xxx未定义,则由于ajax异步操作可能未定义,可以先定义出来则不报错

9.后端代码逻辑

①后端封装对象的方法

  • 如果前端的需要的表单和数据库表不同
  • 第一种方法创建一个vo对象专用数据传输
  • 第二种方法扩展已有的表(扩展确定的字段,扩展不确定的字段hashmap)
  • 第三种直接返回map集合

②后端展示借款列表的对象方法

  • 分析
    对比前后端结果(需要多封装姓名,手机号,以及其他字段的字符串形式(borrow_info存储的是整型数字))
    在这里插入图片描述
    在这里插入图片描述

  • 利用扩展borrow_info表的方法
    com.atguigu.srb.core.pojo.entity.BorrowInfo

//扩展字段
    @ApiModelProperty(value = "姓名")
    @TableField(exist = false)
    private String name;

    @ApiModelProperty(value = "手机")
    @TableField(exist = false)
    private String mobile;

    @ApiModelProperty(value = "其他参数")
    @TableField(exist = false)
    private Map<String,Object> param = new HashMap<>();

③后端展示详细信息的方法

  • 分析
    前端需要展示borrow_info中的所有数据和borrower中的所有数据,直接将两个信息封装为map返回
    在这里插入图片描述

④后端接收提交审核表单的对象

  • 分析
    都为新字段不好扩展,使用vo对象封装
    在这里插入图片描述

⑤封装对象的代码

  • 封装查询借款信息
    com.atguigu.srb.core.pojo.entity.BorrowInfo
    //扩展字段
    @ApiModelProperty(value = "姓名")
    @TableField(exist = false)
    private String name;

    @ApiModelProperty(value = "手机")
    @TableField(exist = false)
    private String mobile;

    @ApiModelProperty(value = "其他参数")
    @TableField(exist = false)
    private Map<String,Object> param = new HashMap<>();
  • 封装提交的审核表单对象
    com.atguigu.srb.core.pojo.vo.BorrowInfoApprovalVO
package com.atguigu.srb.core.pojo.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.math.BigDecimal;

@Data
@ApiModel(description = "借款信息审批")
public class BorrowInfoApprovalVO {

    @ApiModelProperty(value = "id")
    private Long id;

    @ApiModelProperty(value = "状态")
    private Integer status;

    @ApiModelProperty(value = "审批内容")
    private String content;

    @ApiModelProperty(value = "标题")
    private String title;

    @ApiModelProperty(value = "年化利率")
    private BigDecimal lendYearRate;

    @ApiModelProperty(value = "平台服务费率")
    private BigDecimal serviceRate;

    @ApiModelProperty(value = "开始日期")
    private String lendStartDate;

    @ApiModelProperty(value = "描述信息")
    private String lendInfo;
}

⑥业务逻辑代码

  • controller
package com.atguigu.srb.core.controller.admin;

import com.atguigu.common.result.R;
import com.atguigu.srb.core.pojo.entity.BorrowInfo;
import com.atguigu.srb.core.pojo.vo.BorrowInfoApprovalVO;
import com.atguigu.srb.core.service.BorrowInfoService;
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.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Api(tags = "借款管理")
@RestController
@RequestMapping("/admin/core/borrowInfo")
@Slf4j
public class AdminBorrowInfoController {

    @Resource
    private BorrowInfoService borrowInfoService;

    @ApiOperation("借款信息列表")
    @GetMapping("/list")
    public R list() {
        List<BorrowInfo> borrowInfoList = borrowInfoService.selectList();
        return R.ok().data("list", borrowInfoList);
    }

    @ApiOperation("借款信息详情")
    @GetMapping("/show/{id}")
    public R show(
            @ApiParam(value = "借款信息id",required = true)
            @PathVariable Long id){
        Map<String,Object> borrowInfoDetail = borrowInfoService.getBorrowInfoDetail(id);
        return R.ok().data("borrowInfoDetail",borrowInfoDetail);

    }

    @ApiOperation("审批借款信息")
    @PostMapping("/approval")
    public R approval(@RequestBody BorrowInfoApprovalVO borrowInfoApprovalVO) {

        borrowInfoService.approval(borrowInfoApprovalVO);
        return R.ok().message("审批完成");
    }
}
  • service
    com.atguigu.srb.core.service.BorrowInfoService
    List<BorrowInfo> selectList();

    Map<String,Object> getBorrowInfoDetail(Long id);

    void approval(BorrowInfoApprovalVO borrowInfoApprovalVO);
    
 /**
     * @param :
     * @return List<BorrowInfo>
     * @author Likejin
     * @description 获取前端所需的展示借款信息的列表
     * @date 2023/4/16 19:33
     */

    @Override
    public List<BorrowInfo> selectList() {
        //根据user_id可以查询表中每行的其他信息(姓名,手机号码)
        //根据value值来查dict中具体的name(多组数据)
        //根据value值和dict_code来查dict中具体的name

        //两表联查获取需要的数据 borrow_info + mobile + name
        List<BorrowInfo> borrowInfoList = baseMapper.selectBorrowInfoList();
        //封装其他需要的数据
        borrowInfoList.forEach(borrowInfo -> {
            //将编码类型的都转换为字符串
            String returnMethod = dictService.getNameByParentDictCodeAndValue("returnMethod", borrowInfo.getReturnMethod());
            String moneyUse = dictService.getNameByParentDictCodeAndValue("moneyUse", borrowInfo.getMoneyUse());

            //将对应的枚举值转化为枚举字符串
            String msgByStatus = BorrowInfoStatusEnum.getMsgByStatus(borrowInfo.getStatus());

            //加入其他参数
            borrowInfo.getParam().put("status",msgByStatus);
            borrowInfo.getParam().put("returnMethod",returnMethod);
            borrowInfo.getParam().put("moneyUse",moneyUse);
        });

        return borrowInfoList;
    }

    /**
     * @param :
     * @return Map<String,Object>
     * @author Likejin
     * @description 查询借款项的详细内容
     * @date 2023/4/16 20:14
     */
    @Override
    public Map<String, Object> getBorrowInfoDetail(Long id) {



        //查询借款对象borrow_info(根据borrow_info的id查询)
        BorrowInfo borrowInfo = baseMapper.selectById(id);
        //抄袭上面的方法
        //将编码类型的都转换为字符串
        String returnMethod = dictService.getNameByParentDictCodeAndValue("returnMethod", borrowInfo.getReturnMethod());
        String moneyUse = dictService.getNameByParentDictCodeAndValue("moneyUse", borrowInfo.getMoneyUse());
        //将对应的枚举值转化为枚举字符串
        String msgByStatus = BorrowInfoStatusEnum.getMsgByStatus(borrowInfo.getStatus());
        //加入其他参数
        borrowInfo.getParam().put("status",msgByStatus);
        borrowInfo.getParam().put("returnMethod",returnMethod);
        borrowInfo.getParam().put("moneyUse",moneyUse);


        //查询借款人对象borrower (BorrowerDetailVo)
        //根据borrow_info中的user_id查询出一条Borrower
        QueryWrapper<Borrower> borrowerQueryWrapper = new QueryWrapper<>();
        borrowerQueryWrapper.eq("user_id",borrowInfo.getUserId());
        Borrower borrower = borrowerMapper.selectOne(borrowerQueryWrapper);

        BorrowerDetailVO borrowerDetailVO = borrowerService.getBorrowerDetailVOById(borrower.getId());

        //组装集合结果
        Map<String, Object> result = new HashMap<>();
        result.put("borrowInfo",borrowInfo);
        result.put("borrower",borrowerDetailVO);
        return result;
    }

    /**
     * @param borrowInfoApprovalVO:
     * @return void
     * @author Likejin
     * @description 修改借款审核的状态 borrow_info,产生新的标的记录 lend
     * @date 2023/4/16 20:39
     */

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void approval(BorrowInfoApprovalVO borrowInfoApprovalVO) {
        //对borrow_info的审批状态进行修改
        //根据提交的信息得到borrow_info的id
        Long borrowInfoId = borrowInfoApprovalVO.getId();
        BorrowInfo borrowInfo = baseMapper.selectById(borrowInfoId);

        borrowInfo.setStatus(borrowInfoApprovalVO.getStatus());
        baseMapper.updateById(borrowInfo);
        //如果审核通过,生成新的标的(在lend表中)
        if(borrowInfoApprovalVO.getStatus().intValue() == BorrowInfoStatusEnum.CHECK_OK.getStatus().intValue()){
            //创建新标的
            //TODO

        }

    }
  • mapper
package com.atguigu.srb.core.mapper;

import com.atguigu.srb.core.pojo.entity.BorrowInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import java.util.List;

/**
 * <p>
 * 借款信息表 Mapper 接口
 * </p>
 *
 * @author Likejin
 * @since 2023-04-09
 */
public interface BorrowInfoMapper extends BaseMapper<BorrowInfo> {

    List<BorrowInfo> selectBorrowInfoList();

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.srb.core.mapper.BorrowInfoMapper">


    <select id="selectBorrowInfoList" resultType="com.atguigu.srb.core.pojo.entity.BorrowInfo">
        SELECT bi.*,b.name,b.mobile FROM borrow_info AS bi
        LEFT JOIN borrower AS b ON bi.`user_id` = b.`user_id`
        WHERE bi.is_deleted =0
    </select>
</mapper>

⑦后端代码逻辑

  • 封装借款信息列表返回
    利用扩展后的borrow_info
    borrow_info和borrower两表联查以borrow_info为主表多封装两个字段(name,mobile),对应字段存储即可
    然后再利用已有方法(通过dict_code和value查询具体的name)查询Dict表转换编码(returnMethod,moneyUse),将borrow_info的编码也转换为对应字符串存入map字段
  • 返回审批信息详情
    利用一个map集合封装
    用前端传来的具体id查询到borrow_info,将编码信息装换(同上),封装到扩展的borrowInfo,put到map集合中
    根据borrow_info的user_id查询到对应的borrower,组装成之前查询写过的方法返回的对象BorrowerDetailVO,put到map集合中
  • 前端取值
    在这里插入图片描述
borrowInfoDetail.borrower.name
borrowInfoDetail.borrowInfo.param.moneyUse
  • 前端提交审批信息后
    利用前端封装好的对象
    利用封装好的对象的id查询borrow_info(对应其id)对borrow_info中的借款信息的状态修改
    TODO生成新的标的。

未更新

未更新

未更新

未更新

未更新

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值