超管后台 - 删除管理员
This commit is contained in:
@@ -26,6 +26,8 @@ Route::group('', function () {
|
||||
Route::post('update', 'app\\superadmin\\controller\\Administrator@updateAdmin');
|
||||
// 添加管理员
|
||||
Route::post('add', 'app\\superadmin\\controller\\Administrator@addAdmin');
|
||||
// 删除管理员
|
||||
Route::post('delete', 'app\\superadmin\\controller\\Administrator@deleteAdmin');
|
||||
});
|
||||
|
||||
// 系统信息相关路由
|
||||
|
||||
@@ -264,4 +264,65 @@ class Administrator extends Controller
|
||||
'data' => null
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除管理员
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function deleteAdmin()
|
||||
{
|
||||
if (!$this->request->isPost()) {
|
||||
return json(['code' => 405, 'msg' => '请求方法不允许']);
|
||||
}
|
||||
|
||||
// 获取当前登录的管理员信息
|
||||
$currentAdmin = $this->request->adminInfo;
|
||||
|
||||
// 获取请求参数
|
||||
$id = $this->request->post('id/d');
|
||||
|
||||
// 参数验证
|
||||
if (empty($id)) {
|
||||
return json(['code' => 400, 'msg' => '参数不完整']);
|
||||
}
|
||||
|
||||
// 不能删除自己的账号
|
||||
if ($currentAdmin->id == $id) {
|
||||
return json(['code' => 403, 'msg' => '不能删除自己的账号']);
|
||||
}
|
||||
|
||||
// 只有超级管理员(ID为1)可以删除管理员
|
||||
if ($currentAdmin->id != 1) {
|
||||
return json(['code' => 403, 'msg' => '您没有权限删除管理员']);
|
||||
}
|
||||
|
||||
// 不能删除超级管理员账号
|
||||
if ($id == 1) {
|
||||
return json(['code' => 403, 'msg' => '不能删除超级管理员账号']);
|
||||
}
|
||||
|
||||
// 查询管理员
|
||||
$admin = AdminModel::where('id', $id)->where('deleteTime', 0)->find();
|
||||
if (!$admin) {
|
||||
return json(['code' => 404, 'msg' => '管理员不存在']);
|
||||
}
|
||||
|
||||
// 执行软删除
|
||||
$admin->deleteTime = time();
|
||||
$result = $admin->save();
|
||||
|
||||
if ($result) {
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '删除成功',
|
||||
'data' => null
|
||||
]);
|
||||
} else {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '删除失败',
|
||||
'data' => null
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,17 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
|
||||
import { Search, MoreHorizontal, Edit, Trash, UserPlus, Loader2 } from "lucide-react"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { useToast } from "@/components/ui/use-toast"
|
||||
import { getAdministrators, Administrator } from "@/lib/admin-api"
|
||||
import { getAdministrators, deleteAdministrator, Administrator } from "@/lib/admin-api"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog"
|
||||
|
||||
// 保留原始示例数据,作为加载失败时的备用数据
|
||||
const adminsData = [
|
||||
@@ -54,11 +64,16 @@ const adminsData = [
|
||||
export default function AdminsPage() {
|
||||
const [searchTerm, setSearchTerm] = useState("")
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [isDeleting, setIsDeleting] = useState(false)
|
||||
const [administrators, setAdministrators] = useState<Administrator[]>([])
|
||||
const [totalCount, setTotalCount] = useState(0)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [pageSize] = useState(10)
|
||||
const { toast } = useToast()
|
||||
|
||||
// 删除对话框状态
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)
|
||||
const [adminToDelete, setAdminToDelete] = useState<Administrator | null>(null)
|
||||
|
||||
// 加载管理员列表
|
||||
useEffect(() => {
|
||||
@@ -122,6 +137,50 @@ export default function AdminsPage() {
|
||||
const isSuperAdmin = (id: number) => {
|
||||
return id === 1
|
||||
}
|
||||
|
||||
// 打开删除确认对话框
|
||||
const openDeleteDialog = (admin: Administrator) => {
|
||||
setAdminToDelete(admin)
|
||||
setDeleteDialogOpen(true)
|
||||
}
|
||||
|
||||
// 确认删除管理员
|
||||
const confirmDelete = async () => {
|
||||
if (!adminToDelete) return
|
||||
|
||||
setIsDeleting(true)
|
||||
try {
|
||||
const response = await deleteAdministrator(adminToDelete.id)
|
||||
|
||||
if (response.code === 200) {
|
||||
toast({
|
||||
title: "删除成功",
|
||||
description: `管理员 ${adminToDelete.name} 已成功删除`,
|
||||
variant: "success",
|
||||
})
|
||||
|
||||
// 重新获取管理员列表
|
||||
fetchAdministrators()
|
||||
} else {
|
||||
toast({
|
||||
title: "删除失败",
|
||||
description: response.msg || "请稍后重试",
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("删除管理员出错:", error)
|
||||
toast({
|
||||
title: "删除失败",
|
||||
description: "请检查网络连接后重试",
|
||||
variant: "destructive",
|
||||
})
|
||||
} finally {
|
||||
setIsDeleting(false)
|
||||
setDeleteDialogOpen(false)
|
||||
setAdminToDelete(null)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -205,7 +264,10 @@ export default function AdminsPage() {
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
{!isSuperAdmin(admin.id) && (
|
||||
<DropdownMenuItem className="text-destructive">
|
||||
<DropdownMenuItem
|
||||
className="text-destructive"
|
||||
onClick={() => openDeleteDialog(admin)}
|
||||
>
|
||||
<Trash className="mr-2 h-4 w-4" /> 删除管理员
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
@@ -248,6 +310,35 @@ export default function AdminsPage() {
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 删除确认对话框 */}
|
||||
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>确认删除管理员</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
您确定要删除管理员 "{adminToDelete?.name}" 吗?此操作无法撤销。
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel disabled={isDeleting}>取消</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={confirmDelete}
|
||||
disabled={isDeleting}
|
||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
{isDeleting ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
删除中...
|
||||
</>
|
||||
) : (
|
||||
"确认删除"
|
||||
)}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,12 @@ const AlertDialog = AlertDialogPrimitive.Root
|
||||
|
||||
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
|
||||
|
||||
const AlertDialogPortal = AlertDialogPrimitive.Portal
|
||||
const AlertDialogPortal = ({
|
||||
...props
|
||||
}: AlertDialogPrimitive.AlertDialogPortalProps) => (
|
||||
<AlertDialogPrimitive.Portal {...props} />
|
||||
)
|
||||
AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName
|
||||
|
||||
const AlertDialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
||||
@@ -18,7 +23,7 @@ const AlertDialogOverlay = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -36,7 +41,7 @@ const AlertDialogContent = React.forwardRef<
|
||||
<AlertDialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -128,8 +133,6 @@ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
||||
|
||||
export {
|
||||
AlertDialog,
|
||||
AlertDialogPortal,
|
||||
AlertDialogOverlay,
|
||||
AlertDialogTrigger,
|
||||
AlertDialogContent,
|
||||
AlertDialogHeader,
|
||||
|
||||
@@ -121,4 +121,13 @@ export async function addAdministrator(
|
||||
}
|
||||
): Promise<ApiResponse<null>> {
|
||||
return apiRequest('/administrator/add', 'POST', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除管理员
|
||||
* @param id 管理员ID
|
||||
* @returns 删除结果
|
||||
*/
|
||||
export async function deleteAdministrator(id: number | string): Promise<ApiResponse<null>> {
|
||||
return apiRequest('/administrator/delete', 'POST', { id });
|
||||
}
|
||||
Reference in New Issue
Block a user