全部开发者教程

企业级在线办公系统

这一章我们要完成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 &amp; 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 &amp; 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);
    }
}