This commit is contained in:
wangjiming
2026-08-03 09:34:08 +08:00
parent b975de02da
commit 15c4223f2c
43 changed files with 4498 additions and 234 deletions

View File

@@ -1,12 +1,36 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { getUsers } from '@/api/modules/system'
import type { SystemUser } from '@/types'
import { computed, onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
deleteUser,
getUsers,
resetUserPassword,
updateUserAccess,
} from '@/api/modules/system'
import type { PermissionCode, SystemUser, UserStatus } from '@/types'
import { statusLabel, statusTagType } from '@/utils/status'
const loading = ref(false)
const users = ref<SystemUser[]>([])
// 权限码 -> 中文名(与路由模块一一对应)
const PERMISSION_LABELS: Record<PermissionCode, string> = {
dashboard: '服务看板',
'fine-tune': '模型训练',
'model-eval': '模型评测',
'model-inference': '模型推理',
'model-manage': '模型管理',
dataset: '数据集管理',
'data-process': '数据处理',
'data-convert': '数据转换',
compute: '计算资源',
hardware: '硬件监控',
logs: '日志中心',
'user-settings': '用户与权限',
}
const ALL_PERMISSIONS = Object.keys(PERMISSION_LABELS) as PermissionCode[]
async function loadUsers() {
loading.value = true
try {
@@ -17,6 +41,109 @@ async function loadUsers() {
}
onMounted(loadUsers)
// 当前登录用户,用于禁止操作自身(避免误锁自己)
const currentUsername = ref<string>('')
try {
currentUsername.value = JSON.parse(localStorage.getItem('currentUser') || '{}').username || ''
} catch {
currentUsername.value = ''
}
function isSelf(row: SystemUser) {
return row.username === currentUsername.value
}
// ---------- 启停 ----------
async function toggleStatus(row: SystemUser, next: boolean) {
const nextStatus: UserStatus = next ? 'active' : 'disabled'
const prev = row.status
row.status = nextStatus
try {
await updateUserAccess(row.id, { status: nextStatus })
ElMessage.success(`${row.display_name}${next ? '启用' : '停用'}`)
await loadUsers()
} catch {
row.status = prev
ElMessage.error('状态更新失败')
}
}
// ---------- 重置密码 ----------
const pwdDialog = reactive({ visible: false, id: '', name: '', password: '', saving: false })
function openResetPwd(row: SystemUser) {
pwdDialog.id = row.id
pwdDialog.name = row.display_name
pwdDialog.password = 'Platform@123'
pwdDialog.visible = true
}
async function confirmResetPwd() {
if (!pwdDialog.password.trim()) {
ElMessage.warning('请输入新密码')
return
}
pwdDialog.saving = true
try {
await resetUserPassword(pwdDialog.id, pwdDialog.password.trim())
ElMessage.success(`已重置 ${pwdDialog.name} 的密码`)
pwdDialog.visible = false
} catch {
ElMessage.error('重置密码失败')
} finally {
pwdDialog.saving = false
}
}
// ---------- 页面权限 ----------
const permDialog = reactive({
visible: false,
id: '',
name: '',
checked: [] as PermissionCode[],
saving: false,
})
function openPerms(row: SystemUser) {
permDialog.id = row.id
permDialog.name = row.display_name
permDialog.checked = [...(row.permissions || [])]
permDialog.visible = true
}
async function confirmPerms() {
permDialog.saving = true
try {
await updateUserAccess(permDialog.id, { permissions: permDialog.checked })
ElMessage.success(`已更新 ${permDialog.name} 的页面权限`)
permDialog.visible = false
await loadUsers()
} catch {
ElMessage.error('权限更新失败')
} finally {
permDialog.saving = false
}
}
const permColumns = computed(() => ALL_PERMISSIONS)
// ---------- 删除 ----------
async function removeUser(row: SystemUser) {
try {
await ElMessageBox.confirm(
`确定删除用户 “${row.display_name}${row.username})” 吗?该操作不可恢复。`,
'删除用户',
{ type: 'warning', confirmButtonText: '删除', cancelButtonText: '取消' },
)
} catch {
return
}
try {
await deleteUser(row.id)
ElMessage.success(`已删除 ${row.display_name}`)
await loadUsers()
} catch (err: any) {
const msg = err?.response?.data?.message || '删除失败'
ElMessage.error(msg)
}
}
</script>
<template>
@@ -24,25 +151,93 @@ onMounted(loadUsers)
<header class="page-header">
<div>
<h1>用户设置</h1>
<p>管理平台账号角色状态页面权限</p>
<p>管理平台账号角色状态登录密码与页面权限</p>
</div>
<el-button type="primary" @click="$router.push('/user-settings/create')">创建用户</el-button>
</header>
<el-table :data="users">
<el-table :data="users" border>
<el-table-column prop="username" label="账号" min-width="140" />
<el-table-column prop="display_name" label="显示名称" min-width="160" />
<el-table-column prop="role" label="角色" width="120" />
<el-table-column label="状态" width="120">
<el-table-column label="状态" width="130">
<template #default="{ row }">
<el-tag :type="statusTagType(row.status)" size="small">{{ statusLabel(row.status) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="权限" width="120">
<template #default="{ row }">{{ row.permissions?.length || 0 }}</template>
<el-table-column label="页面权限" min-width="160">
<template #default="{ row }">
<el-tag
v-for="p in (row.permissions || []).slice(0, 3)"
:key="p"
size="small"
type="info"
class="perm-tag"
>{{ PERMISSION_LABELS[p] || p }}</el-tag>
<span v-if="(row.permissions || []).length > 3" class="perm-more">
+{{ (row.permissions || []).length - 3 }}
</span>
<span v-if="!(row.permissions || []).length" class="perm-more"></span>
</template>
</el-table-column>
<el-table-column prop="create_time" label="创建时间" min-width="180" />
<el-table-column label="操作" width="260" fixed="right">
<template #default="{ row }">
<el-switch
:model-value="row.status === 'active'"
:disabled="row.protected || isSelf(row)"
@change="(v: any) => toggleStatus(row, v)"
inline-prompt
active-text="启用"
inactive-text="停用"
/>
<el-button
link
type="primary"
:disabled="row.protected"
@click="openResetPwd(row)"
>重置密码</el-button>
<el-button
link
type="primary"
@click="openPerms(row)"
>页面权限</el-button>
<el-button
link
type="danger"
:disabled="row.protected || isSelf(row)"
@click="removeUser(row)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 重置密码 -->
<el-dialog v-model="pwdDialog.visible" title="重置密码" width="420px">
<p class="dlg-tip"> <b>{{ pwdDialog.name }}</b> 设置新密码</p>
<el-input v-model="pwdDialog.password" placeholder="请输入新密码" show-password />
<template #footer>
<el-button @click="pwdDialog.visible = false">取消</el-button>
<el-button type="primary" :loading="pwdDialog.saving" @click="confirmResetPwd">确定重置</el-button>
</template>
</el-dialog>
<!-- 页面权限 -->
<el-dialog v-model="permDialog.visible" title="页面权限" width="540px">
<p class="dlg-tip"> <b>{{ permDialog.name }}</b> 分配可访问的页面模块</p>
<el-checkbox-group v-model="permDialog.checked" class="perm-group">
<el-checkbox
v-for="code in permColumns"
:key="code"
:value="code"
:label="PERMISSION_LABELS[code]"
/>
</el-checkbox-group>
<template #footer>
<el-button @click="permDialog.visible = false">取消</el-button>
<el-button type="primary" :loading="permDialog.saving" @click="confirmPerms">保存</el-button>
</template>
</el-dialog>
</section>
</template>
@@ -67,4 +262,25 @@ onMounted(loadUsers)
margin: 8px 0 0;
color: #64748b;
}
.perm-tag {
margin-right: 4px;
margin-bottom: 2px;
}
.perm-more {
color: #94a3b8;
font-size: 12px;
}
.dlg-tip {
margin: 0 0 12px;
color: #475569;
}
.perm-group {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px 12px;
}
</style>