- Added configuration management page with table view and modal forms for adding/editing configurations. - Integrated Zustand for state management of configurations. - Implemented user management drawer for organizations with user addition/removal functionality. - Created user management page with CRUD operations for users. - Introduced admin store for user-related actions including user creation, deletion, and updates. - Developed reusable drawer component for UI consistency across user management. - Enhanced error handling and user feedback with toast notifications.
210 lines
6.3 KiB
TypeScript
210 lines
6.3 KiB
TypeScript
'use client';
|
||
import { useEffect, useState } from 'react';
|
||
import { useForm } from 'react-hook-form';
|
||
import { useOrgStore } from './store';
|
||
import { Button } from '@/components/ui/button';
|
||
import { Input } from '@/components/ui/input';
|
||
import {
|
||
Table,
|
||
TableBody,
|
||
TableCell,
|
||
TableHead,
|
||
TableHeader,
|
||
TableRow,
|
||
} from '@/components/ui/table';
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from '@/components/ui/dialog';
|
||
import {
|
||
Popover,
|
||
PopoverContent,
|
||
PopoverTrigger,
|
||
} from '@/components/ui/popover';
|
||
import { Plus, Pencil, Trash2, Users } from 'lucide-react';
|
||
import { LayoutMain } from '@/modules/layout';
|
||
import { UserDrawer } from './components/UserDrawer';
|
||
|
||
const TableList = () => {
|
||
const { list, setShowEdit, setFormData, deleteData, setOrgId } = useOrgStore();
|
||
const [userDrawerOpen, setUserDrawerOpen] = useState(false);
|
||
|
||
const handleOpenUserDrawer = (org: any) => {
|
||
setOrgId(org.id);
|
||
setUserDrawerOpen(true);
|
||
};
|
||
|
||
return (
|
||
<div className="rounded-md border">
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow>
|
||
<TableHead>名称</TableHead>
|
||
<TableHead>描述</TableHead>
|
||
<TableHead>创建时间</TableHead>
|
||
<TableHead>更新时间</TableHead>
|
||
<TableHead>操作</TableHead>
|
||
</TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
{list.map((org) => (
|
||
<TableRow key={org.id}>
|
||
<TableCell>{org.username}</TableCell>
|
||
<TableCell>{org.description || '-'}</TableCell>
|
||
<TableCell>{org.createdAt ? new Date(org.createdAt).toLocaleString() : '-'}</TableCell>
|
||
<TableCell>{org.updatedAt ? new Date(org.updatedAt).toLocaleString() : '-'}</TableCell>
|
||
<TableCell className="flex gap-2">
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={() => handleOpenUserDrawer(org)}>
|
||
<Users className="w-4 h-4 mr-1" />
|
||
用户管理
|
||
</Button>
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={() => {
|
||
setShowEdit(true);
|
||
setFormData(org);
|
||
}}>
|
||
<Pencil className="w-4 h-4 mr-1" />
|
||
编辑
|
||
</Button>
|
||
<Popover>
|
||
<PopoverTrigger asChild>
|
||
<Button
|
||
variant="destructive"
|
||
size="sm">
|
||
<Trash2 className="w-4 h-4 mr-1" />
|
||
删除
|
||
</Button>
|
||
</PopoverTrigger>
|
||
<PopoverContent className="w-48 p-2">
|
||
<div className="text-sm text-center mb-2">确认删除该组织?</div>
|
||
<div className="flex gap-2 justify-center">
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
deleteData(org.id);
|
||
}}>
|
||
确认
|
||
</Button>
|
||
<Button
|
||
variant="ghost"
|
||
size="sm"
|
||
onClick={(e) => e.stopPropagation()}>
|
||
取消
|
||
</Button>
|
||
</div>
|
||
</PopoverContent>
|
||
</Popover>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
<UserDrawer open={userDrawerOpen} onOpenChange={setUserDrawerOpen} />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
const FormModal = () => {
|
||
const { showEdit, setShowEdit, formData, setFormData, updateData } = useOrgStore();
|
||
const {
|
||
handleSubmit,
|
||
formState: { errors },
|
||
reset,
|
||
register,
|
||
} = useForm();
|
||
|
||
useEffect(() => {
|
||
if (!showEdit) return;
|
||
if (formData?.id) {
|
||
reset(formData);
|
||
} else {
|
||
reset({ username: '', description: '' });
|
||
}
|
||
}, [formData, showEdit, reset]);
|
||
|
||
const onSubmit = async (data: any) => {
|
||
const res = await updateData(data);
|
||
if (res.code === 200) {
|
||
setShowEdit(false);
|
||
setFormData({});
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Dialog open={showEdit} onOpenChange={(open) => {
|
||
setShowEdit(open);
|
||
if (!open) setFormData({});
|
||
}}>
|
||
<DialogContent>
|
||
<DialogHeader>
|
||
<DialogTitle>{formData?.id ? '编辑组织' : '添加组织'}</DialogTitle>
|
||
</DialogHeader>
|
||
<div className="p-4 ">
|
||
<form className="w-full flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
|
||
<div className="flex flex-col gap-2">
|
||
<label className="text-sm font-medium">名称</label>
|
||
<Input
|
||
{...register('username', { required: '请输入名称' })}
|
||
placeholder="请输入名称"
|
||
className={errors.username ? "border-red-500" : ""}
|
||
/>
|
||
{errors.username && <span className="text-xs text-red-500">{errors.username.message as string}</span>}
|
||
</div>
|
||
<div className="flex flex-col gap-2">
|
||
<label className="text-sm font-medium">描述</label>
|
||
<Input
|
||
{...register('description')}
|
||
placeholder="请输入描述"
|
||
/>
|
||
</div>
|
||
<div className="flex gap-2 justify-end">
|
||
<Button type="button" variant="outline" onClick={() => setShowEdit(false)}>
|
||
取消
|
||
</Button>
|
||
<Button type="submit">提交</Button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</DialogContent>
|
||
</Dialog>
|
||
);
|
||
};
|
||
|
||
export const List = () => {
|
||
const { getList, setShowEdit, setFormData } = useOrgStore();
|
||
|
||
useEffect(() => {
|
||
getList();
|
||
}, [getList]);
|
||
|
||
return (
|
||
<div className="p-4 w-full h-full overflow-auto">
|
||
<div className="flex mb-4">
|
||
<Button
|
||
onClick={() => {
|
||
setShowEdit(true);
|
||
setFormData({});
|
||
}}>
|
||
<Plus className="w-4 h-4 mr-1" />
|
||
添加
|
||
</Button>
|
||
</div>
|
||
<TableList />
|
||
<FormModal />
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default () => {
|
||
return <LayoutMain><List /></LayoutMain>;
|
||
}
|