feat(system): 实现用户审核功能

- 新增用户模型字段:auditStatus、auditRemark、auditTime
- 添加用户审核接口 auditUser,支持单条审核
- 用户列表页增加审核状态筛选项和对应列展示
- 列表行内仅待审核用户显示“审核”操作链接
- 工具栏添加批量审核按钮,实现批量审核功能
- 审核弹窗支持选择通过或拒绝及填写备注
- 审核提交支持单条和批量调用接口
- 保持代码类型检查无新增错误,符合项目字段命名规范
This commit is contained in:
2026-07-11 19:43:24 +08:00
parent dceb030712
commit bf259ea8ff
4 changed files with 172 additions and 7 deletions

View File

@@ -40,6 +40,18 @@
<a-select-option :value="2">普通用户</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="审核状态">
<a-select
v-model:value="searchWhere.auditStatus"
placeholder="全部"
allow-clear
style="width: 140px"
>
<a-select-option :value="0">待审核</a-select-option>
<a-select-option :value="1">通过</a-select-option>
<a-select-option :value="2">拒绝</a-select-option>
</a-select>
</a-form-item>
<a-form-item>
<a-button type="primary" @click="reload()">搜索</a-button>
<a-button style="margin-left: 8px" @click="resetSearch">重置</a-button>
@@ -84,6 +96,17 @@
:disabled="selection.length === 0"
>重置密码
</a-button>
<a-button
type="primary"
class="ele-btn-icon"
@click="openBatchAudit"
:disabled="selection.length === 0"
>
<template #icon>
<CheckCircleOutlined />
</template>
<span>批量审核</span>
</a-button>
<a-button
danger
type="primary"
@@ -142,6 +165,12 @@
<a-tag v-else-if="record.status === 1" color="red">冻结</a-tag>
<span v-else>-</span>
</template>
<template v-if="column.key === 'auditStatus'">
<a-tag v-if="record.auditStatus === 0" color="orange">待审核</a-tag>
<a-tag v-else-if="record.auditStatus === 1" color="green">通过</a-tag>
<a-tag v-else-if="record.auditStatus === 2" color="red">拒绝</a-tag>
<span v-else>-</span>
</template>
<template v-if="column.key === 'platform'">
<WechatOutlined v-if="record.platform === 'MP-WEIXIN'" />
<Html5Outlined v-if="record.platform === 'H5'" />
@@ -168,7 +197,9 @@
<template v-if="column.key === 'action'">
<div>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-divider type="vertical" v-if="record.auditStatus === 0" />
<a v-if="record.auditStatus === 0" @click.stop="openAudit(record)">审核</a>
<a-divider type="vertical" v-if="record.auditStatus === 0" />
<!-- <a @click="resetPsw(record)">重置</a>-->
<!-- <a-divider type="vertical" />-->
<a-popconfirm
@@ -194,6 +225,28 @@
<user-import v-model:visible="showImport" @done="reload" />
<!-- 用户详情 -->
<user-info v-model:visible="showInfo" :data="current" @done="reload" />
<!-- 审核弹窗 -->
<a-modal
v-model:visible="showAudit"
:title="auditTitle"
@ok="submitAudit"
>
<a-form :model="auditForm" layout="vertical">
<a-form-item label="审核结果">
<a-radio-group v-model:value="auditForm.status">
<a-radio :value="1">通过</a-radio>
<a-radio :value="2">拒绝</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="审核备注">
<a-textarea
v-model:value="auditForm.remark"
:rows="3"
placeholder="请输入审核备注(拒绝时建议填写)"
/>
</a-form-item>
</a-form>
</a-modal>
</a-page-header>
</template>
@@ -209,7 +262,8 @@
Html5Outlined,
ChromeOutlined,
WechatOutlined,
ExclamationCircleOutlined
ExclamationCircleOutlined,
CheckCircleOutlined
} from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro/es';
import type {
@@ -227,7 +281,8 @@
removeUsers,
updateUserPassword,
updateUser,
listUsers
listUsers,
auditUser
} from '@/api/system/user';
import type { User, UserParam } from '@/api/system/user/model';
import { toTreeData, uuid } from 'ele-admin-pro';
@@ -258,17 +313,31 @@
const showInfo = ref(false);
// 是否显示用户导入弹窗
const showImport = ref(false);
// 是否显示审核弹窗
const showAudit = ref(false);
// 是否批量审核
const batchAudit = ref(false);
// 审核弹窗标题
const auditTitle = ref('审核用户');
// 审核表单
const auditForm = reactive({
userId: undefined as number | undefined,
status: 1,
remark: ''
});
const searchText = ref('');
// 高级筛选条件
const searchWhere = reactive({
roleId: undefined,
platform: undefined,
isAdmin: undefined
isAdmin: undefined,
auditStatus: undefined
});
const resetSearch = () => {
searchWhere.roleId = undefined;
searchWhere.platform = undefined;
searchWhere.isAdmin = undefined;
searchWhere.auditStatus = undefined;
reload();
};
const userStore = useUserStore();
@@ -457,6 +526,13 @@
align: 'center',
width: 90
},
{
title: '审核状态',
dataIndex: 'auditStatus',
key: 'auditStatus',
align: 'center',
width: 100
},
{
title: '管理员',
key: 'isAdmin',
@@ -477,7 +553,7 @@
{
title: '操作',
key: 'action',
width: 120,
width: 160,
fixed: 'right',
align: 'center'
}
@@ -496,7 +572,8 @@
keywords: searchText.value,
roleId: searchWhere.roleId,
platform: searchWhere.platform,
isAdmin: searchWhere.isAdmin || undefined
isAdmin: searchWhere.isAdmin || undefined,
auditStatus: searchWhere.auditStatus || undefined
};
return pageUsers({ page, limit, ...params, ...orders });
};
@@ -604,6 +681,51 @@
});
};
/* 打开单条审核弹窗 */
const openAudit = (row: User) => {
batchAudit.value = false;
auditForm.userId = row.userId;
auditForm.status = 1;
auditForm.remark = '';
auditTitle.value = `审核用户 - ${row.nickname || row.username}`;
showAudit.value = true;
};
/* 打开批量审核弹窗 */
const openBatchAudit = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
batchAudit.value = true;
auditForm.userId = undefined;
auditForm.status = 1;
auditForm.remark = '';
auditTitle.value = `批量审核(已选 ${selection.value.length} 条)`;
showAudit.value = true;
};
/* 提交审核 */
const submitAudit = () => {
const hide = message.loading('提交中..', 0);
const doOne = (userId: number) =>
auditUser(userId, { status: auditForm.status, remark: auditForm.remark });
const tasks = batchAudit.value
? selection.value.map((d) => doOne(d.userId as number))
: [doOne(auditForm.userId as number)];
Promise.all(tasks)
.then(() => {
hide();
message.success('审核完成');
showAudit.value = false;
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 搜索处理 */
const handleSearch = () => {
reload();