Scert/frontend/src/views/UserManagement/UserManagement.vue

146 lines
5.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import HelpTip from "../components/HelpTip/HelpTip.vue";
import { useUserManagement } from "./UserManagement.js";
import ChangePassword from "../components/ChangePassword/ChangePassword.vue";
import UserTable from "./UserTable.vue";
import UserGroupEditor from "./UserGroupEditor.vue";
const {
canManage,
showGroups,
groupedUsers,
availableGroups,
visible,
users,
loading,
saving,
error,
notice,
showForm,
form,
formError,
formTitle,
isEditing,
roleLabels,
statusLabels,
isPrimaryAccount,
openCreate,
openEdit,
closeForm,
saveUser,
toggleStatus,
deleteUser,
loadUsers,
} = useUserManagement();
</script>
<template>
<section v-if="visible" class="user-management panel">
<div class="user-management-heading">
<div>
<p class="eyebrow">权限与账号</p>
<h2>用户管理</h2>
<HelpTip>
管理登录账号、角色和使用状态。密码只在服务端保存摘要。
</HelpTip>
</div>
<div class="user-management-actions">
<ChangePassword />
<button class="secondary-button" type="button" :disabled="loading" @click="loadUsers">
{{ loading ? "读取中……" : "刷新列表" }}
</button>
<button v-if="canManage" class="primary-button" type="button" @click="openCreate">添加用户</button>
</div>
</div>
<p v-if="error" class="user-message error-message">{{ error }}</p>
<p v-if="notice" class="user-message notice-message">{{ notice }}</p>
<div v-if="loading && users.length === 0" class="user-empty">正在读取用户列表……</div>
<div v-else-if="showGroups" class="user-groups">
<template v-for="group in groupedUsers" :key="group.name">
<section v-if="group.isDefault" class="user-group default-group" aria-label="默认分组">
<h3 class="user-group-heading">默认分组 <span>{{ group.users.length }} 人</span></h3>
<UserTable
:users="group.users"
:can-manage="canManage"
:role-labels="roleLabels"
:status-labels="statusLabels"
@edit="openEdit"
@toggle="toggleStatus"
@delete="deleteUser"
/>
</section>
<details v-else class="user-group">
<summary class="user-group-heading">{{ group.name }} <span>{{ group.users.length }} 人</span></summary>
<UserTable
:users="group.users"
:can-manage="canManage"
:role-labels="roleLabels"
:status-labels="statusLabels"
@edit="openEdit"
@toggle="toggleStatus"
@delete="deleteUser"
/>
</details>
</template>
</div>
<UserTable v-else :users="users" :role-labels="roleLabels" :status-labels="statusLabels" />
<div v-if="showForm && canManage" class="modal-backdrop" @click.self="closeForm">
<section class="modal-card user-modal" role="dialog" aria-modal="true" :aria-label="formTitle">
<div class="modal-heading">
<div>
<p class="eyebrow">账号配置</p>
<h2>{{ formTitle }}</h2>
</div>
<button class="close-button" type="button" aria-label="关闭" @click="closeForm">×</button>
</div>
<form @submit.prevent="saveUser">
<div class="form-grid">
<label class="field">
<span>用户名</span>
<input v-model="form.username" type="text" autocomplete="off" placeholder="3 到 64 个字符" />
</label>
<label class="field">
<span>绑定邮箱 <small>可选</small></span>
<input v-model="form.email" type="email" autocomplete="off" placeholder="用于邮箱登录" />
</label>
</div>
<label class="field">
<span>密码 <small>{{ isEditing ? "留空表示不修改,8 到 12 个字符" : "8 到 12 个字符" }}</small></span>
<input v-model="form.password" type="password" autocomplete="new-password" placeholder="请输入密码" />
</label>
<div class="form-grid">
<label class="field">
<span>角色</span>
<select v-model="form.role">
<option value="user">普通用户</option>
<option value="admin">管理员</option>
<option v-if="isEditing && form.role === 'super_admin'" value="super_admin" disabled>超级管理员</option>
</select>
</label>
<label class="field">
<span>状态</span>
<select v-model="form.status">
<option value="active">正常</option>
<option value="disabled">已禁用</option>
</select>
</label>
</div>
<UserGroupEditor v-model="form.groups" :role="form.role" :available-groups="availableGroups" />
<p v-if="formError" class="form-error">{{ formError }}</p>
<div class="modal-actions">
<button class="secondary-button" type="button" :disabled="saving" @click="closeForm">取消</button>
<button class="primary-button" type="submit" :disabled="saving">{{ saving ? "保存中……" : "保存用户" }}</button>
</div>
</form>
</section>
</div>
</section>
</template>
<style scoped>
@import "./UserManagement.css";
</style>