这一章我们要完成emos系统最后的业务模块:报销管理。按照CRUD的顺序,我们首先要做的肯定是分页查询,这种功能已经难不倒我们了,甚至有的同学闭着眼睛都能把分页查询写出来,真的是太熟悉了。
看到报销页面的截图,感觉和请假管理有点像,但是好像还有很大的区别。一张请假单对应一个请假记录,但是一个报销单可以对应多笔报销。所以我们点开一个报销申请的折叠面板,可以看到有很多个报销子项。幸好MySQL有JSON类型,我们可以把这些报销子项存储在JSON数组里面。
一、熟悉报销表
报销模块对应的数据表是tb_reim
,这个数据表的结构不复杂。大家需要注意,差额就是实际报销的金额。假设某位员工报销6000元,但是他跟公司借款了4000元,那么差额就是2000元。也就是说,这位员工实际拿到手的报销款是2000元。如果另一位员工报销金额是1000元,但是借款金额是1500元,差额为-500元,那么该员工需要向公司返还500元。
二、编写持久层代码
在TbReimDao.xml
文件中,定义SQL语句。
<select id="searchReimByPage" parameterType="HashMap" resultType="HashMap">
SELECT r.id,
u.id,
u.`name`,
d.dept_name AS deptName,
r.content,
r.amount,
r.anleihen,
r.balance,
r.type_id AS typeId,
r.`status`,
DATE_FORMAT(r.create_time,'%Y-%m-%d') AS createTime,
IF(r.user_id = #{currentUserId},"true","false") AS mine
FROM tb_reim r
JOIN tb_user u ON r.user_id = u.id
JOIN tb_dept d ON d.id = u.dept_id
WHERE 1=1
<if test="deptId!=null">
AND u.dept_id = #{deptId}
</if>
<if test="typeId!=null">
AND r.type_id = #{typeId}
</if>
<if test="status!=null">
AND r.`status` = #{status}
</if>
<if test="userId!=null">
AND u.id = #{userId}
</if>
<if test="name!=null">
AND u.name LIKE '%${name}%'
</if>
<if test="startDate!=null & endDate!=null">
AND r.create_time BETWEEN #{startDate} AND #{endDate}
</if>
ORDER BY r.id DESC
LIMIT #{start}, #{length}
</select>
<select id="searchReimCount" parameterType="HashMap" resultType="long">
SELECT COUNT(*)
FROM tb_reim r
JOIN tb_user u ON r.user_id = u.id
JOIN tb_dept d ON d.id = u.dept_id
WHERE 1=1
<if test="deptId!=null">
AND u.dept_id = #{deptId}
</if>
<if test="typeId!=null">
AND r.type_id = #{typeId}
</if>
<if test="status!=null">
AND r.`status` = #{status}
</if>
<if test="userId!=null">
AND u.id = #{userId}
</if>
<if test="name!=null">
AND u.name LIKE '%${name}%'
</if>
<if test="startDate!=null & endDate!=null">
AND r.create_time BETWEEN #{startDate} AND #{endDate}
</if>
</select>
在TbReimDao.java
接口中,声明DAO方法。
public interface TbReimDao {
public ArrayList<HashMap> searchReimByPage(HashMap param);
public long searchReimCount(HashMap param);
}
三、编写业务层代码
创建ReimService.java
接口,声明抽象方法。
public interface ReimService {
public PageUtils searchReimByPage(HashMap param);
}
创建ReimServiceImpl.java
类,实现抽象方法。
@Service
@Slf4j
public class ReimServiceImpl implements ReimService {
@Autowired
private TbReimDao reimDao;
@Autowired
private ReimWorkflowTask reimWorkflowTask;
public PageUtils searchReimByPage(HashMap param) {
ArrayList<HashMap> list = reimDao.searchReimByPage(param);
long count = reimDao.searchReimCount(param);
int start = (Integer) param.get("start");
int length = (Integer) param.get("length");
PageUtils pageUtils = new PageUtils(list, count, start, length);
return pageUtils;
}
}
四、编写Web层代码
创建SearchReimByPageForm.java
类,用于封装Ajax提交的请求。
@Data
@Schema(description = "查询报销分页记录表单")
public class SearchReimByPageForm {
@Min(value = 1, message = "deptId不能小于1")
@Schema(description = "部门ID")
private Integer deptId;
@Min(value = 1, message = "typeId不能小于1")
@Schema(description = "类型ID")
private Byte typeId;
@Min(value = 1, message = "status不能小于1")
@Schema(description = "状态")
private Byte status;
@Pattern(regexp = "^[a-zA-Z0-9\\u4e00-\\u9fa5]{1,10}$", message = "name内容不正确")
@Schema(description = "姓名")
private String name;
@Pattern(regexp = "^((((1[6-9]|[2-9]\\d)\\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-0?2-(0?[1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$", message = "startDate内容不正确")
@Schema(description = "开始日期")
private String startDate;
@Pattern(regexp = "^((((1[6-9]|[2-9]\\d)\\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-0?2-(0?[1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$", message = "sendDate内容不正确")
@Schema(description = "截止日期")
private String endDate;
@NotNull(message = "page不能为空")
@Min(value = 1, message = "page不能小于1")
@Schema(description = "页数")
private Integer page;
@NotNull(message = "length不能为空")
@Range(min = 10, max = 50, message = "length必须在10~50之间")
@Schema(description = "每页记录数")
private Integer length;
}
创建ReimController.java
类,声明Web方法。你可以自己往tb_reim
表中添加几条记录,然后用Swagger测试Web方法。
@RestController
@RequestMapping("/reim")
@Tag(name = "ReimController", description = "报销模块Web接口")
public class ReimController {
@Autowired
private ReimService reimService;
@PostMapping("/searchReimByPage")
@Operation(summary = "查询报销分页记录")
@SaCheckLogin
public R searchReimByPage(@Valid @RequestBody SearchReimByPageForm form) {
int page = form.getPage();
int length = form.getLength();
int start = (page - 1) * length;
HashMap param = JSONUtil.parse(form).toBean(HashMap.class);
param.put("start", start);
param.put("currentUserId", StpUtil.getLoginIdAsInt());
if (!(StpUtil.hasPermission("REIM:SELECT") || StpUtil.hasPermission("ROOT"))) {
param.put("userId", StpUtil.getLoginIdAsInt());
}
PageUtils pageUtils = reimService.searchReimByPage(param);
return R.ok().put("page", pageUtils);
}
}