feat(用户管理): 新增账户审核功能并完善用户管理模块

添加用户审核页面及接口,实现账户审批操作
完善用户管理模块的编辑、删除功能
优化用户状态显示和表单验证逻辑
This commit is contained in:
liangbin 2026-01-27 18:00:27 +08:00
parent 6cbac2d533
commit 0767228b64
5 changed files with 322 additions and 52 deletions

View File

@ -134,3 +134,13 @@ export function deptTreeSelect() {
method: 'get' method: 'get'
}) })
} }
// 账户审批操作
export function FetchUserReview(params) {
return request({
url: '/system/user/audit/' + params.userId,
method: 'put',
data: params
})
}

View File

@ -319,6 +319,19 @@ export const constantRoutes = [
}, },
], ],
}, },
{
path: "",
component: Layout,
redirect: "/index",
children: [
{
path: "/logistics/UserReview",
component: () => import("@/views/Logistics/UserReview/index.vue"),
name: "UserReview",
meta: { title: "账户审核", icon: "table" },
},
],
},
{ {
path: "", path: "",
component: Layout, component: Layout,

View File

@ -1,17 +1,17 @@
<!-- 后勤模块-账户管理-账户新增/编辑/查看弹窗详情 --> <!-- 后勤模块-账户管理-账户新增/编辑/查看弹窗详情 -->
<template> <template>
<el-dialog title="新建账户" v-model="props.show" @close="handleClose" width="600px"> <el-dialog :title="userId ? '编辑账户' : '新建账户'" v-model="props.show" @close="handleClose" width="600px">
<div class="Cneter-box"> <div class="Cneter-box">
<el-form :model="formData" label-width="120px" class="user-form" label-position="top"> <el-form :model="formData" label-width="120px" class="user-form" label-position="top">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="账户名"> <el-form-item label="账户名">
<el-input v-model="formData.account" placeholder="如: NJGD_ZH" /> <el-input v-model="formData.userName" placeholder="如: NJGD_ZH" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="姓名"> <el-form-item label="姓名">
<el-input v-model="formData.realName" placeholder="请输入姓名" /> <el-input v-model="formData.nickName" placeholder="请输入姓名" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -23,7 +23,7 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="联系电话"> <el-form-item label="联系电话">
<el-input v-model="formData.phone" placeholder="请输入手机号" /> <el-input v-model="formData.phonenumber" placeholder="请输入手机号" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -36,16 +36,15 @@
<el-form-item label="所属单位"> <el-form-item label="所属单位">
<div class="TreeBox"> <div class="TreeBox">
<el-tree :data="unitTreeData" :props="treeProps" show-line highlight-current default-expand-all <el-tree :data="unitTreeData" :props="treeProps" show-line highlight-current default-expand-all
@current-change="handleUnitChange" class="unit-tree" /> @current-change="handleUnitChange" :expand-on-click-node="false" class="unit-tree" />
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="角色"> <el-form-item label="角色">
<el-select v-model="formData.role" placeholder="请选择角色"> <el-select v-model="formData.roleId" placeholder="请选择角色" @change="handleRoleChange">
<el-option label="项目经理" value="projectManager" /> <el-option v-for="item in roleList" :key="item.roleId" :label="item.roleName"
<el-option label="审核人" value="auditor" /> :value="item.roleId" />
<el-option label="物业管理员" value="propertyManager" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -64,8 +63,16 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { getUser, deptTreeSelect, addUser } from '@/api/system/user.js'
import { listRole } from '@/api/system/role.js'
import { ElMessage } from 'element-plus'
import { ref, onBeforeMount } from 'vue'
const props = defineProps({ const props = defineProps({
userId: {
type: Number || String,
default: ''
},
show: { show: {
type: Boolean, type: Boolean,
default: false default: false
@ -78,44 +85,77 @@ const props = defineProps({
// //
const formData = ref({ const formData = ref({
account: '', userName: '', //
realName: '', nickName: '', //
password: '', password: '', //
phone: '', phonenumber: '', //
email: '', email: '', //
role: '', roleId: '', //
roleName: '', //
deptName: '', //
deptId: '', // ID
expiry: '永久有效' expiry: '永久有效'
}) })
//
const roleList = ref([])
// //
const unitTreeData = ref([ const unitTreeData = ref([])
{
label: '江苏省电力公司',
children: [
{
label: '南京市供电公司',
children: [
{
label: '城东片区',
children: [
{ label: 'A办公楼' }
]
}
]
}
]
}
])
// //
const treeProps = { const treeProps = {
children: 'children', children: 'children',
label: 'label' label: 'label'
} }
onBeforeMount(() => {
getRoleList()
getUnitTree()
})
//
const getRoleList = async () => {
let res = await listRole()
if (res.code === 200) {
roleList.value = res.rows
}
}
//
const getUnitTree = async () => {
let res = await deptTreeSelect()
if (res.code === 200) {
console.log("单位树:", res.data)
unitTreeData.value = res.data
}
}
//
const getUserDetail = async () => {
let res = await getUser({
account: formData.value.account
})
if (res.code === 200) {
formData.value = res.data
}
}
//
const handleRoleChange = (roleId) => {
console.log('Selected roleId:', roleId)
let role = roleList.value.find(item => item.roleId === roleId)
if (role) {
formData.value.roleName = role.roleName
}
}
// //
const handleUnitChange = (data) => { const handleUnitChange = (data) => {
console.log('Selected unit:', data) console.log('Selected unit:', data)
formData.value.deptName = data.label
formData.value.deptId = data.id
console.log('Selected unit:', data)
} }
// //
@ -123,9 +163,44 @@ const handleClose = () => {
props.CloseDialog() props.CloseDialog()
} }
//
const handleSubmit = () => { const handleSubmit = () => {
console.log('提交数据:', formData.value)
//
if (!formData.value.roleId) {
ElMessage.warning('请选择角色')
return
}
if (!formData.value.deptId) {
ElMessage.warning('请选择所属单位')
return
}
if (!formData.value.userName) {
ElMessage.warning('请输入账户名')
return
}
if (!formData.value.nickName) {
ElMessage.warning('请输入姓名')
return
}
if (!formData.value.phonenumber) {
ElMessage.warning('请输入联系电话')
return
}
addUser(formData.value).then(res => {
if (res.code === 200) {
ElMessage.success('添加成功')
props.CloseDialog()
} else {
ElMessage.error(res.msg || '添加失败')
}
})
// //
props.CloseDialog() // props.CloseDialog()
} }
</script> </script>

View File

@ -83,7 +83,7 @@
<el-table :data="accountList" border height="350px"> <el-table :data="accountList" border height="350px">
<el-table-column prop="userName" label="账户名" /> <el-table-column prop="userName" label="账户名" />
<el-table-column prop="nickName" label="姓名" /> <el-table-column prop="nickName" label="姓名" />
<el-table-column prop="deptName" label="所属单位" > <el-table-column prop="deptName" label="所属单位">
<template #default="{ row }"> <template #default="{ row }">
{{ row.dept.deptName || '-' }} {{ row.dept.deptName || '-' }}
</template> </template>
@ -92,42 +92,43 @@
<el-table-column prop="remark" label="角色" /> <el-table-column prop="remark" label="角色" />
<el-table-column prop="status" label="状态"> <el-table-column prop="status" label="状态">
<template #default="{ row }"> <template #default="{ row }">
<el-tag :type="getStatusTagType(row.status)">{{ row.status }}</el-tag> <el-tag :type="getStatusTagType(row.status)">{{ statusMap[row.status] }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作"> <el-table-column label="操作">
<template #default="{ row }"> <template #default="{ row }">
<el-button type="text" icon="Edit">编辑</el-button> <el-button type="text" icon="Edit" @click="handleEditUser(row)">编辑</el-button>
<el-button type="text" icon="Delete">删除</el-button> <el-button type="text" icon="Delete" @click="handleDeleteUser(row)">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="PageBox"> <div class="PageBox">
<el-pagination :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :total="pageInfo.total" <el-pagination :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize"
layout="total, prev, pager, next" @current-change="handleCurrentChange" /> :total="pageInfo.total" layout="total, prev, pager, next"
@current-change="handleCurrentChange" />
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
<!-- 账户新增/编辑/查看弹窗 --> <!-- 账户新增/编辑/查看弹窗 -->
<UserDialog v-if="dialogShow" :show="dialogShow" :CloseDialog="handleCancel" /> <UserDialog v-if="dialogShow" :show="dialogShow" :userId="userId" :CloseDialog="handleCancel" />
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, getCurrentInstance, reactive, toRefs, nextTick } from 'vue' import { ref, onMounted, getCurrentInstance, reactive, toRefs, nextTick } from 'vue'
import { listDept } from '@/api/treeRatingManagement' import { listDept } from '@/api/treeRatingManagement'
import { listUser } from '@/api/system/user.js' import { listUser, delUser } from '@/api/system/user.js'
import UserDialog from "./UserDialog.vue"; import UserDialog from "./UserDialog.vue";
import { ElMessage, ElMessageBox } from 'element-plus'
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
// //
const statusMap = { const statusMap = {
'0': '待审核', '0': '已生效',
'1': '已通过', '1': '已停用',
'2': '已驳回', '2': '待审核',
'3': '已禁用',
} }
const dialogShow = ref(false); // const dialogShow = ref(false); //
@ -139,6 +140,9 @@ const pageInfo = reactive({
pageNum: 1, pageNum: 1,
}) })
// ID
const userId = ref('')
// //
const loading = ref(false) const loading = ref(false)
@ -279,27 +283,59 @@ const handleTreeChange = (data) => {
parentId: data.originalData.parentId || '-', parentId: data.originalData.parentId || '-',
createTime: data.originalData.createTime || '-' createTime: data.originalData.createTime || '-'
} }
console.log(data,'获取当前节点', JDformData.value) console.log(data, '获取当前节点', JDformData.value)
// //
getUserList() getUserList()
} }
// //
const getStatusTagType = (status) => { const getStatusTagType = (status) => {
if (status === '已生效') return 'success' if (status === '0') return 'success'
if (status === '待审核') return 'warning' if (status === '1') return 'info'
if (status === '已禁用') return 'danger' if (status === '2') return 'primary'
return 'info' return 'info'
} }
// //
const handleAddUserClick = () => { const handleAddUserClick = () => {
dialogShow.value = true; dialogShow.value = true;
userId.value = ''
} }
// //
const handleCancel = () => { const handleCancel = () => {
dialogShow.value = false; dialogShow.value = false;
userId.value = ''
getUserList()
}
//
const handleEditUser = (user) => {
dialogShow.value = true;
userId.value = user.userId
}
//
const handleDeleteUser = async (user) => {
//
const confirm = await ElMessageBox.confirm('确定删除账户 ' + user.userName + ' 吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
if (!confirm) return
try {
const response = await delUser(user.userId)
if (response.code === 200) {
ElMessage.success('删除成功')
getUserList()
} else {
ElMessage.error(response.msg || '删除失败')
}
} catch (error) {
console.error('删除账户失败:', error)
ElMessage.error('删除账户失败')
}
} }
</script> </script>
@ -345,6 +381,7 @@ const handleCancel = () => {
.account-card { .account-card {
position: relative; position: relative;
} }
.PageBox { .PageBox {
padding: 20px; padding: 20px;
margin-top: 20px; margin-top: 20px;

View File

@ -0,0 +1,135 @@
<!-- 后勤模块-账户审核-列表 -->
<template>
<div class="MainBox">
<div class="FormBox card-box">
<el-form :model="formData" inline ref="formRef">
<el-form-item label="用户名" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="时间范围" prop="timeRange">
<el-date-picker v-model="formData.timeRange" type="daterange" value-format="yyyy-MM-dd"
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item>
</el-form>
<div class="ButtonBox">
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button type="primary" @click="handleSearch">重置</el-button>
</div>
</div>
<div class="card-box">
<div class="TableBox">
<el-table :data="tableData" v-loading="loading">
<el-table-column prop="userName" label="账户名" />
<el-table-column prop="nickName" label="姓名" />
<el-table-column prop="deptName" label="所属单位">
<template #default="{ row }">
{{ row.dept.deptName || '-' }}
</template>
</el-table-column>
<el-table-column prop="phonenumber" label="联系电话" />
<el-table-column prop="remark" label="角色" />
<el-table-column prop="status" label="状态" />
<el-table-column prop="operation" label="操作" width="100">
<template #default="scope">
<div class="FlexBox">
<el-button type="text" size="mini" @click="handleApprove(scope.row)">审批</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="PageBox">
<el-pagination layout="total, prev, pager, next" :total="pageInfo.total"
:page-size.sync="pageInfo.pageSize" :current-page.sync="pageInfo.pageNum"
@current-change="handleCurrentChange" />
</div>
</div>
</div>
</template>
<script setup>
import dayjs from "dayjs";
import { ref, onBeforeMount } from "vue";
import { listUser } from "@/api/system/user";
//
const formData = ref({
username: "",
timeRange: [],
});
//
const loading = ref(false);
//
const pageInfo = ref({
pageNum: 1,
pageSize: 10,
total: 0,
});
//
const tableData = ref([]);
onBeforeMount(() => {
getinit();
});
//
const getinit = async () => {
let query = {
username: formData.value.username,
startTime: formData.value.timeRange[0] ? dayjs(formData.value.timeRange[0]).format('YYYY-MM-DD') : '',
endTime: formData.value.timeRange[1] ? dayjs(formData.value.timeRange[1]).format('YYYY-MM-DD') : '',
pageNum: pageInfo.value.pageNum,
pageSize: pageInfo.value.pageSize,
};
loading.value = true;
let res = await listUser(query);
loading.value = false;
if (res.code === 200) {
tableData.value = res.rows;
pageInfo.value.total = res.total;
}
};
</script>
<style scoped lang="scss">
.MainBox {
padding: 20px;
height: 100%;
background: #F9FAFB;
}
.FlexBox {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 10px;
}
.card-box {
background: #fff;
padding: 16px;
border-radius: 4px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.FormBox {
display: flex;
}
.TableBox {
height: 400px;
}
.PageBox {
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 20px;
}
</style>