Springboot3+Vue3实现提交审核业务功能

1.什么叫提交审核业务场景?

1.请假申请审核: 学生提交请假信息,管理员(教师)进行审核.

2.博客论坛,发布心得等等:用户发布帖子(或者其他信息) 管理员进行审核

3.作业模块: 学生提交作业,教师审核(打分)

4.房屋租赁系统: 房东发布一个房源,管理员进行审核

5.商家入驻,心理咨询师,家教系统,教师入驻,提价信息,管理员审核.

6.发布商品: 商家发布商品,管理员审核.

场景特征: 首先得有个功能模块,需要某个角色来提交数据(新增数据),需要另一个觉得去进行"审核"的操作

(审核只是广义上的,并不是说一定叫审核,它根据具体业务叫法可以不一样)

提交者只能看到自己相关的数据(这个不是必须的 根据业务来)

2. 以请假为例

1
2
3
4
5
6
7
8
9
10
CREATE TABLE `apply` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` int DEFAULT NULL COMMENT '用户ID',
`title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '请假标题',
`content` text COLLATE utf8mb4_unicode_ci COMMENT '请假说明',
`time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '提交时间',
`status` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '审核状态',
`reason` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '审核说明',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户请假表';

复用之前的notice模块的时候一定要细心一点 不然要改很久…

改完后直接新增:

image-20250308112340042.png

image-20250308113858909.png

首先需要在apply的实体类中增加一个username来接受查询出来的这个值

我直接放xml

1
2
3
4
5
6
7
<select id="selectAll" resultType="com.yjy.entity.Apply">
select apply.*,user.name as username from `apply` left join user on apply.user_id = user.id
<where>
<if test="title!=null and title != ''">and title like concat('%',#{title},'%')</if>
</where>
order by apply.id desc
</select>

只能看到自己的怎么写?之前的角色权限控制文章有讲过

1
2
3
4
5
6
7
8
9
10
public PageInfo<Apply> selectPage(Integer pageNum, Integer pageSize,Apply apply) {
Account currentUser = TokenUtils.getCurrentUser();
if("USER".equals(currentUser.getRole())){
apply.setUserId(currentUser.getId());
}
//开启分页查询
PageHelper.startPage(pageNum,pageSize);
List<Apply> applys = applyMapper.selectAll(apply);
return PageInfo.of(applys);
}
1
2
3
4
5
6
7
8
9
10
<select id="selectAll" resultType="com.yjy.entity.Apply">
select apply.*,user.name as username from `apply` left join user on apply.user_id = user.id
<where>
<if test="title!=null and title != ''">and title like concat('%',#{title},'%')</if>
<if test="userId!=null">and user_id = #{userId}</if>
</where>
order by apply.id desc
</select>

# 加多一行这个: <if test="userId!=null">and user_id = #{userId}</if>

给按钮增加条件: :disabled="scope.row.status !== '待审核'"

1
2
3
4
5
6
<el-table-column label="操作" width="100">
<template #default="scope">
<el-button :disabled="scope.row.status !== '待审核'" type="primary" icon="Edit" circle @click="handleEdit(scope.row)"></el-button>
<el-button :disabled="scope.row.status !== '待审核'" type="danger" icon="Delete" circle @click="del(scope.row.id)"></el-button>
</template>
</el-table-column>

接下来做审核

管理员视角

3.核心总结

1.提交审核业务必须要有角色_id 和 status两个字段

2.在提交的接口里面需要绑定号角色id以及初始化状态(待审核)

1
2
3
4
5
6
7
8
9
public void add(Apply apply) {
Account currentUser = TokenUtils.getCurrentUser();
//获取当前的用户
apply.setUserId(currentUser.getId());
apply.setTime(DateUtil.now());
apply.setStatus("待审核");
applyMapper.insert(apply);
}

3.提交的用户只能看到自己的

4.管理员审核的细节,它需要去更新这个状态

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
<el-dialog v-model="data.formVisible" title="请假信息" width="40%" destroy-on-close>
<el-form ref="formRef" :model="data.form" :rules="data.rules" label-width="80px" style="padding: 20px 30px 10px 0">


<el-form-item prop="title" label="请假标题" v-if="data.user.role === 'USER'">
<el-input v-model="data.form.title" autocomplete="off" placeholder="请输入请假标题"/>
</el-form-item>

<el-form-item prop="content" label="请假说明" v-if="data.user.role === 'USER'">
<el-input type="textarea" :rows="3" v-model="data.form.content" autocomplete="off" placeholder="请输入请假说明"/>
</el-form-item>

<el-form-item prop="status" label="审核状态" v-if="data.user.role === 'ADMIN'">
<el-radio-group v-model="data.form.status">
<el-radio-button label="待审核" value="待审核" />
<el-radio-button label="审核通过" value="审核通过" />
<el-radio-button label="审核拒绝" value="审核拒绝" />
</el-radio-group>
</el-form-item>

<el-form-item prop="reason" label="审核说明" v-if="data.user.role === 'ADMIN' && data.form.status === '审核拒绝'">
<el-input v-model="data.form.reason" autocomplete="off" placeholder="请输入拒绝说明"/>
</el-form-item>

</el-form>

5.提交角色的操作按钮和审核角色的操作按钮可以通过状态字段进行控制

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
<el-table :data="data.tableData" style="width: 100%" :header-cell-style="{fontWeight: 'bold',color: '#333',backgroundColor: '#c902f6'}">

<el-table-column prop="title" label="请假标题"/>
<el-table-column prop="content" label="请假说明"/>
<!-- <template v-slot="scope">-->
<!-- <span v-if="data.user.role === 'ADMIN'">{{ scope.row.content }}</span>-->
<!-- <span v-if="data.user.role === 'USER'">您暂无权限查看</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column prop="username" label="请假人"/>
<el-table-column prop="time" label="提交时间" />
<el-table-column prop="status" label="审核状态">
<template v-slot="scope">
<el-tag type="warning" v-if="scope.row.status === '待审核'">{{scope.row.status}}</el-tag>
<el-tag type="success" v-if="scope.row.status === '审核通过'">{{scope.row.status}}</el-tag>
<el-tag type="danger" v-if="scope.row.status === '审核拒绝'">{{scope.row.status}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="reason" label="审核说明" />
<el-table-column label="操作" width="100" v-if="data.user.role === 'USER'">
<template #default="scope">
<el-button :disabled="scope.row.status !== '待审核'" type="primary" icon="Edit" circle @click="handleEdit(scope.row)"></el-button>
<el-button :disabled="scope.row.status !== '待审核'" type="danger" icon="Delete" circle @click="del(scope.row.id)"></el-button>
</template>
</el-table-column>

<el-table-column label="操作" width="100" v-else>
<template #default="scope">
<el-button :disabled="scope.row.status !== '待审核'" type="primary" @click="handleEdit(scope.row)">审核</el-button>
</template>
</el-table-column>
</el-table>

修复遗留BUG

修复bug: Introduction.vue 中wangeditor中代码部分:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘destroy’)
at Introduction.vue:183:10

组件销毁时,editorRef.value 未正确初始化或已被提前销毁。以下是分步解决方案:

1. 修复 resetForm 中的销毁逻辑

resetForm 中,当对话框关闭时,如果编辑器未初始化(如新增时未打开过编辑器),直接调用 destroy() 会报错。修改如下

1
2
3
4
5
6
7
8
9
const resetForm = () => {
data.form = {}; // 清空表单数据
// 确保编辑器存在后再销毁
if (editorRef.value) {
editorRef.value.destroy();
editorRef.value = undefined; // 重置引用
}
data.formVisible = false;
};

2. 确保 onBeforeUnmount 安全销毁

在组件卸载时,可能重复调用 destroy()修改钩子函数

1
2
3
4
5
6
onBeforeUnmount(() => {
if (editorRef.value) {
editorRef.value.destroy();
editorRef.value = undefined; // 避免残留引用
}
});

3. 优化 handleCreated 初始化逻辑

确保每次打开对话框时,编辑器实例被正确创建:

1
2
3
4
5
6
7
const handleCreated = (editor) => {
editorRef.value = editor;
// 如果表单有旧内容,初始化编辑器内容
if (data.form.content) {
editorRef.value.setHtml(data.form.content);
}
};

4. 关键代码对比

修改前(错误)

1
2
3
4
5
6
7
// resetForm 函数
if (editorRef.value) {
editorRef.value.destroy(); // 可能重复销毁
}

// onBeforeUnmount 钩子
editor.destroy(); // 未检查是否已销毁

修改后(修复)

1
2
3
4
5
6
7
8
9
10
11
// resetForm 函数
if (editorRef.value) {
editorRef.value.destroy();
editorRef.value = undefined; // 重置引用,避免重复操作
}

// onBeforeUnmount 钩子
if (editorRef.value) {
editorRef.value.destroy();
editorRef.value = undefined;
}

5. 验证修复

  1. 操作流程
    • 打开“攻略管理”页面。
    • 点击“新增”打开对话框,不上传图片直接关闭。
    • 再次打开“请假申请”模块,观察控制台是否还有错误。
  2. 预期结果
    • destroy() 仅在编辑器存在时调用。
    • editorRef.value 在销毁后被重置为 undefined,避免重复操作。