flnxi-Wu/app/admin/_components/users/UserEditModal.tsx
2026-05-25 15:13:49 +08:00

225 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

'use client'
import type { Department, User } from '../types'
import { useThemeStyles, cn } from '@/lib/ui-styles'
import { formatDateTime } from '../../_utils/formatters'
import Modal from '@/components/ui/Modal'
interface UserEditModalProps {
isOpen: boolean
user: User | null
departments: Department[]
editingUsername: string
selectedDepartment: string
managerNames: string[]
showTransferButton: boolean
canChangeProtectedFields: boolean
onChangeUsername: (value: string) => void
onChangeDepartment: (value: string) => void
onClose: () => void
onSave: () => void
onToggleRole: () => void
onToggleActive: () => void
onToggleDownload: () => void
onDelete: () => void
onOpenTransferModal: () => void
hasDepartments: boolean
}
export default function UserEditModal({
isOpen,
user,
departments,
editingUsername,
selectedDepartment,
managerNames,
showTransferButton,
canChangeProtectedFields,
onChangeUsername,
onChangeDepartment,
onClose,
onSave,
onToggleRole,
onToggleActive,
onToggleDownload,
onDelete,
onOpenTransferModal,
hasDepartments,
}: UserEditModalProps) {
const styles = useThemeStyles()
if (!isOpen || !user) return null
return (
<Modal
isOpen={isOpen}
onClose={onClose}
title="编辑用户"
size="large"
containerClassName="max-h-[90vh]"
bodyClassName="overflow-y-auto max-h-[calc(90vh-180px)]"
footer={
<div className="flex justify-end gap-3">
<button
type="button"
onClick={onClose}
className={cn(
styles.buttonStyles.secondary,
'bg-white dark:bg-slate-800 border-slate-300 dark:border-slate-600 text-slate-700 dark:text-slate-200'
)}
>
取消
</button>
<button
type="button"
onClick={onSave}
className={cn(
styles.buttonStyles.primary,
'bg-indigo-600 hover:bg-indigo-700 text-white'
)}
>
保存
</button>
</div>
}
>
<div className="space-y-5">
<div>
<p className="text-sm text-slate-500 dark:text-slate-400 mb-4 break-all">{user.email}</p>
</div>
<section className="grid gap-4 md:grid-cols-3">
<div>
<p className="text-sm text-slate-500 dark:text-slate-400">注册时间</p>
<p className="text-sm font-medium text-slate-900 dark:text-white">
{formatDateTime(user.createdAt)}
</p>
</div>
<div className="md:col-span-2">
<p className="text-sm text-slate-500 dark:text-slate-400">直属上级</p>
<p className="text-sm font-medium text-slate-900 dark:text-white">
{managerNames.length ? managerNames.join('、') : '暂无'}
</p>
</div>
</section>
<section className="space-y-2">
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300">用户名</label>
<input
type="text"
value={editingUsername}
onChange={(e) => onChangeUsername(e.target.value)}
className={styles.inputStyles.base}
placeholder="请输入用户名"
/>
</section>
<section className="space-y-2">
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300">选择部门</label>
<select
value={selectedDepartment}
onChange={(e) => onChangeDepartment(e.target.value)}
disabled={!canChangeProtectedFields}
className={cn(styles.inputStyles.base, 'pr-10')}
>
<option value="">-- 未分配部门 --</option>
{departments.map((dept) => (
<option key={dept.id} value={dept.name}>
{dept.name}
</option>
))}
</select>
<p className="text-xs text-slate-500 dark:text-slate-400">
{canChangeProtectedFields
? '更改部门后将自动为其匹配该部门的管理员作为直属上级。'
: '只有最高权限账号可以调整用户部门。'}
</p>
</section>
{canChangeProtectedFields && (
<section className="space-y-3">
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300">角色与高危操作</label>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<button
type="button"
onClick={onToggleRole}
className={cn(
styles.buttonStyles.secondary,
'w-full justify-center h-12',
'bg-white dark:bg-slate-800 border-slate-300 dark:border-slate-600 text-slate-900 dark:text-slate-200',
user.role === 'ADMIN' && '!bg-purple-600 !text-white hover:!bg-purple-700',
)}
>
{user.role === 'ADMIN' ? '管理员' : '设为管理员'}
</button>
<button
type="button"
onClick={onDelete}
className={cn(
styles.buttonStyles.danger,
'w-full justify-center h-12',
)}
>
删除用户
</button>
</div>
</section>
)}
{canChangeProtectedFields && (
<section className="grid grid-cols-1 md:grid-cols-2 gap-3">
<button
type="button"
onClick={onToggleActive}
className={cn(
styles.buttonStyles.secondary,
'bg-white dark:bg-slate-800 border-slate-300 dark:border-slate-600 text-slate-900 dark:text-slate-200', // 显式添加文字颜色,确保在浅色模式下清晰可见
user.isActive
? 'bg-rose-100 dark:bg-rose-900/30 text-rose-800 dark:text-rose-300 hover:bg-rose-200 dark:hover:bg-rose-900/50' // 使用更深的文字颜色
: 'bg-emerald-100 dark:bg-emerald-900/30 text-emerald-800 dark:text-emerald-300 hover:bg-emerald-200 dark:hover:bg-emerald-900/50', // 使用更深的文字颜色
)}
>
{user.isActive ? '禁用用户' : '激活用户'}
</button>
<button
type="button"
onClick={onToggleDownload}
className={cn(
styles.buttonStyles.secondary,
'bg-white dark:bg-slate-800 border-slate-300 dark:border-slate-600 text-slate-900 dark:text-slate-200', // 显式添加文字颜色,确保在浅色模式下清晰可见
user.canDownload
? 'bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-300 hover:bg-amber-200 dark:hover:bg-amber-900/50' // 使用更深的文字颜色
: 'bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-300 hover:bg-blue-200 dark:hover:bg-blue-900/50', // 使用更深的文字颜色
)}
>
{user.canDownload ? '禁止下载' : '允许下载'}
</button>
</section>
)}
{showTransferButton && (
<section className="space-y-2 border-t border-slate-200 dark:border-slate-700 pt-4">
<button
type="button"
onClick={onOpenTransferModal}
className={cn(
styles.buttonStyles.primary,
'w-full justify-center',
// 统一UI样式已包含颜色,不需要额外添加
)}
>
转移最高权限
</button>
<p className="text-xs text-slate-500 dark:text-slate-400">仅当前最高权限持有者可执行此操作。</p>
</section>
)}
{!hasDepartments && (
<div className="text-sm text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg p-3">
⚠️ 暂无部门,请先在系统设置中添加部门。
</div>
)}
</div>
</Modal>
)
}