171 lines
5.5 KiB
Vue
171 lines
5.5 KiB
Vue
<template>
|
|
<el-card>
|
|
<div class="toolbar">
|
|
<div class="spacer" />
|
|
<el-button type="success" @click="openDialog()">
|
|
<el-icon><Plus /></el-icon> 新增用户
|
|
</el-button>
|
|
</div>
|
|
|
|
<el-table :data="rows" v-loading="loading">
|
|
<el-table-column prop="id" label="ID" width="70" />
|
|
<el-table-column prop="username" label="用户名" width="140" />
|
|
<el-table-column prop="realName" label="姓名" width="120" />
|
|
<el-table-column prop="roleLabel" label="角色" width="100">
|
|
<template #default="{ row }">
|
|
<el-tag :type="row.role === 'ADMIN' ? 'danger' : row.role === 'TEACHER' ? 'warning' : 'info'">
|
|
{{ row.roleLabel }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="email" label="邮箱" min-width="180" />
|
|
<el-table-column prop="phone" label="电话" width="140" />
|
|
<el-table-column label="状态" width="90" align="center">
|
|
<template #default="{ row }">
|
|
<el-tag :type="row.enabled ? 'success' : 'info'">{{ row.enabled ? '启用' : '禁用' }}</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" width="170" fixed="right">
|
|
<template #default="{ row }">
|
|
<el-button size="small" @click="openDialog(row)">编辑</el-button>
|
|
<el-button size="small" type="danger" @click="remove(row)">删除</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<el-dialog v-model="dialogVisible" :title="form.id ? '编辑用户' : '新增用户'" width="480px">
|
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="90px">
|
|
<el-form-item label="用户名" prop="username">
|
|
<el-input v-model="form.username" :disabled="Boolean(form.id)" />
|
|
</el-form-item>
|
|
<el-form-item v-if="!form.id" label="初始密码" prop="password">
|
|
<el-input v-model="form.password" type="password" show-password />
|
|
</el-form-item>
|
|
<el-form-item v-else label="重置密码">
|
|
<el-input v-model="form.password" type="password" show-password placeholder="留空则不修改" />
|
|
</el-form-item>
|
|
<el-form-item label="姓名" prop="realName">
|
|
<el-input v-model="form.realName" />
|
|
</el-form-item>
|
|
<el-form-item label="角色" prop="role">
|
|
<el-select v-model="form.role">
|
|
<el-option label="管理员" value="ADMIN" />
|
|
<el-option label="教师" value="TEACHER" />
|
|
<el-option label="学生" value="STUDENT" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="邮箱">
|
|
<el-input v-model="form.email" />
|
|
</el-form-item>
|
|
<el-form-item label="电话">
|
|
<el-input v-model="form.phone" />
|
|
</el-form-item>
|
|
<el-form-item v-if="form.id" label="启用">
|
|
<el-switch v-model="form.enabled" />
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<el-button @click="dialogVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="submit">保存</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</el-card>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { onMounted, reactive, ref } from 'vue'
|
|
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
|
import { userApi } from '@/api'
|
|
import type { Role, UserVO } from '@/types'
|
|
|
|
interface UserForm {
|
|
id?: number
|
|
username?: string
|
|
password?: string
|
|
realName?: string
|
|
role?: Role
|
|
email?: string
|
|
phone?: string
|
|
enabled?: boolean
|
|
}
|
|
|
|
const loading = ref(false)
|
|
const rows = ref<UserVO[]>([])
|
|
const dialogVisible = ref(false)
|
|
const formRef = ref<FormInstance>()
|
|
const form = reactive<UserForm>({ role: 'STUDENT', enabled: true })
|
|
|
|
/** 表单校验规则 */
|
|
const rules: FormRules = {
|
|
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
|
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
|
realName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
|
role: [{ required: true, message: '请选择角色', trigger: 'change' }]
|
|
}
|
|
|
|
/**
|
|
* 加载用户列表。
|
|
*/
|
|
async function load(): Promise<void> {
|
|
loading.value = true
|
|
try {
|
|
rows.value = await userApi.list()
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 打开新增/编辑对话框。
|
|
*
|
|
* @param row 行数据
|
|
*/
|
|
function openDialog(row?: UserVO): void {
|
|
Object.keys(form).forEach((key) => delete (form as Record<string, unknown>)[key])
|
|
if (row) {
|
|
Object.assign(form, row, { password: '' })
|
|
} else {
|
|
Object.assign(form, { role: 'STUDENT', enabled: true })
|
|
}
|
|
dialogVisible.value = true
|
|
}
|
|
|
|
/**
|
|
* 保存用户。
|
|
*/
|
|
async function submit(): Promise<void> {
|
|
const valid = await formRef.value?.validate().catch(() => false)
|
|
if (!valid) {
|
|
return
|
|
}
|
|
if (form.id) {
|
|
const payload: Record<string, unknown> = { ...form }
|
|
delete payload.username
|
|
if (!payload.password) {
|
|
delete payload.password
|
|
}
|
|
await userApi.update(form.id, payload)
|
|
ElMessage.success('修改成功')
|
|
} else {
|
|
await userApi.create(form as Record<string, unknown>)
|
|
ElMessage.success('新增成功')
|
|
}
|
|
dialogVisible.value = false
|
|
await load()
|
|
}
|
|
|
|
/**
|
|
* 删除用户。
|
|
*
|
|
* @param row 行数据
|
|
*/
|
|
async function remove(row: UserVO): Promise<void> {
|
|
await ElMessageBox.confirm(`确认删除用户「${row.realName}」吗?`, '提示', { type: 'warning' })
|
|
await userApi.remove(row.id)
|
|
ElMessage.success('删除成功')
|
|
await load()
|
|
}
|
|
|
|
onMounted(load)
|
|
</script>
|