146 lines
5.3 KiB
Vue
146 lines
5.3 KiB
Vue
<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>
|