修复登录缺陷和用户信息展示部分
This commit is contained in:
@@ -12,18 +12,16 @@ import {
|
||||
} from "lucide-react"
|
||||
import Image from "next/image"
|
||||
import Link from "next/link"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { usePathname, useRouter } from "next/navigation"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { getProfile, logout } from "@/actions/auth"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import type { User } from "@/models/user"
|
||||
|
||||
export default function Appbar() {
|
||||
const [currentUser] = useState({
|
||||
name: "张三",
|
||||
avatar: "/avatar.png",
|
||||
role: "管理员",
|
||||
})
|
||||
|
||||
const [currentUser, setCurrentUser] = useState<User>()
|
||||
const router = useRouter()
|
||||
const [showDropdown, setShowDropdown] = useState(false)
|
||||
const [showNotifications, setShowNotifications] = useState(false)
|
||||
const [notifications] = useState([
|
||||
@@ -116,6 +114,35 @@ export default function Appbar() {
|
||||
|
||||
const breadcrumbs = generateBreadcrumbs()
|
||||
const unreadCount = notifications.filter(n => !n.read).length
|
||||
const doLogout = async () => {
|
||||
const resp = await logout()
|
||||
if (resp.success) {
|
||||
router.replace("/")
|
||||
router.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchUserProfile() {
|
||||
try {
|
||||
const resp = await getProfile()
|
||||
console.log(resp, "resp")
|
||||
|
||||
if (resp.success) {
|
||||
setCurrentUser(resp.data)
|
||||
} else {
|
||||
console.error("获取用户信息失败:", resp.message)
|
||||
if (resp.status === 401) {
|
||||
router.replace("/login")
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取用户信息时出错:", error)
|
||||
}
|
||||
}
|
||||
|
||||
fetchUserProfile()
|
||||
}, [router])
|
||||
|
||||
return (
|
||||
<header className="bg-white h-16 border-b border-gray-200 flex items-center justify-between px-6">
|
||||
@@ -232,23 +259,45 @@ export default function Appbar() {
|
||||
aria-label="用户菜单"
|
||||
>
|
||||
<div className="h-8 w-8 rounded-full bg-blue-100 text-blue-800 flex items-center justify-center overflow-hidden border-2 border-white shadow-sm">
|
||||
<Image
|
||||
src={currentUser.avatar}
|
||||
alt="用户头像"
|
||||
width={32}
|
||||
height={32}
|
||||
onError={e => {
|
||||
const target = e.target as HTMLImageElement
|
||||
target.style.display = "none"
|
||||
target.parentElement!.innerHTML = currentUser.name.charAt(0)
|
||||
}}
|
||||
/>
|
||||
{currentUser ? (
|
||||
currentUser.avatar ? (
|
||||
<Image
|
||||
src={currentUser.avatar}
|
||||
alt="用户头像"
|
||||
width={32}
|
||||
height={32}
|
||||
className="h-full w-full object-cover"
|
||||
onError={e => {
|
||||
const target = e.target as HTMLImageElement
|
||||
target.style.display = "none"
|
||||
const parent = target.parentElement
|
||||
if (parent && currentUser?.name) {
|
||||
parent.textContent = currentUser.name
|
||||
.charAt(0)
|
||||
.toUpperCase()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
// 如果没有头像,直接显示用户名首字母
|
||||
<span className="text-sm font-semibold">
|
||||
{currentUser.name.charAt(0).toUpperCase()}
|
||||
</span>
|
||||
)
|
||||
) : (
|
||||
// 加载状态或用户信息为空时
|
||||
<UserIcon size={18} />
|
||||
)}
|
||||
</div>
|
||||
<div className="hidden md:block text-left">
|
||||
<p className="text-sm font-medium text-gray-800">
|
||||
{currentUser.name}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">{currentUser.role}</p>
|
||||
{currentUser && (
|
||||
<div>
|
||||
<p className="text-sm font-medium text-gray-800">
|
||||
{currentUser.name}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">{currentUser.username}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ChevronDownIcon />
|
||||
</Button>
|
||||
@@ -256,10 +305,15 @@ export default function Appbar() {
|
||||
{/* 用户下拉内容 */}
|
||||
{showDropdown && (
|
||||
<div className="absolute right-0 mt-2 w-56 bg-white rounded-lg shadow-lg py-2 z-20 border border-gray-200">
|
||||
<div className="px-4 py-2 border-b border-gray-100 md:hidden">
|
||||
<p className="font-medium text-gray-800">{currentUser.name}</p>
|
||||
<p className="text-xs text-gray-500">{currentUser.role}</p>
|
||||
</div>
|
||||
{currentUser && (
|
||||
<div className="px-4 py-2 border-b border-gray-100 md:hidden">
|
||||
<p className="font-medium text-gray-800">
|
||||
{currentUser.name}
|
||||
</p>
|
||||
|
||||
<p className="text-xs text-gray-500">{currentUser.name}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="py-1">
|
||||
<Link
|
||||
@@ -284,15 +338,15 @@ export default function Appbar() {
|
||||
<span className="pl-3">帮助中心</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-100 mt-1">
|
||||
<Link
|
||||
href="/login"
|
||||
className="flex items-center px-4 py-2 text-sm text-red-600 hover:bg-gray-100"
|
||||
<div className="border-t border-gray-100 pt-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={doLogout}
|
||||
className="flex items-center justify-start px-4 py-2 w-full text-sm text-red-600 hover:text-red-700 hover:bg-gray-100 font-normal"
|
||||
>
|
||||
<LogOutIcon size={18} />
|
||||
<span className="pl-3">退出登录</span>
|
||||
</Link>
|
||||
<LogOutIcon size={18} className="ml-2" />
|
||||
退出登录
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,6 @@ export default function BatchPage() {
|
||||
const table = useDataTable<Batch>((page, size) =>
|
||||
getPageBatch({ page, size }),
|
||||
)
|
||||
console.log(table, "table")
|
||||
|
||||
return (
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
|
||||
@@ -10,7 +10,6 @@ export default function BillingPage() {
|
||||
const table = useDataTable<Billing>((page, size) =>
|
||||
getPageBill({ page, size }),
|
||||
)
|
||||
console.log(table, "table")
|
||||
|
||||
return (
|
||||
<Suspense>
|
||||
@@ -24,7 +23,6 @@ export default function BillingPage() {
|
||||
accessorKey: "info",
|
||||
cell: ({ row }) => {
|
||||
const bill = row.original
|
||||
console.log(bill, "bill")
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
@@ -49,7 +49,6 @@ export default function ChannelPage() {
|
||||
header: "认证方式",
|
||||
cell: ({ row }) => {
|
||||
const channel = row.original
|
||||
console.log(channel, "channel")
|
||||
|
||||
const hasWhitelist =
|
||||
channel.whitelists && channel.whitelists.trim() !== ""
|
||||
|
||||
5
src/app/(root)/security/page.tsx
Normal file
5
src/app/(root)/security/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
"use client"
|
||||
|
||||
export default function SecurityPage() {
|
||||
return <div>管理员页面待完善~</div>
|
||||
}
|
||||
5
src/app/(root)/statistics/page.tsx
Normal file
5
src/app/(root)/statistics/page.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
"use client"
|
||||
|
||||
export default function StatisticsPage() {
|
||||
return <div>数据统计页面待完善~</div>
|
||||
}
|
||||
@@ -10,7 +10,6 @@ export default function TradePage() {
|
||||
const table = useDataTable<Trade>((page, size) =>
|
||||
getPageTrade({ page, size }),
|
||||
)
|
||||
console.log(table, "table")
|
||||
|
||||
return (
|
||||
<Suspense>
|
||||
|
||||
Reference in New Issue
Block a user