diff --git a/app/app/(admin)/admin/ana/page.tsx b/app/app/(admin)/admin/ana/page.tsx index 1d5835598..f4def8561 100644 --- a/app/app/(admin)/admin/ana/page.tsx +++ b/app/app/(admin)/admin/ana/page.tsx @@ -1,17 +1,17 @@ import UsageByModel from "./usage-by-model-chart"; import UserByMap from "./user-by-map"; -import { getSession } from "@/lib/auth"; -import { isName, ADMIN_LIST } from "@/lib/auth_list"; -import { redirect } from "next/navigation"; +// import { getSession } from "@/lib/auth"; +// import { isName, ADMIN_LIST } from "@/lib/auth_list"; +// import { redirect } from "next/navigation"; import { Flex } from "antd"; export default async function AdminPage() { - const session = await getSession(); - const name = session?.user?.email || session?.user?.name; - if (!(name && ADMIN_LIST.includes(name))) { - // Replace '/dashboard' with the desired redirect path - redirect("/"); - } + // const session = await getSession(); + // const name = session?.user?.email || session?.user?.name; + // if (!(name && ADMIN_LIST.includes(name))) { + // // Replace '/dashboard' with the desired redirect path + // redirect("/"); + // } return ( <> diff --git a/app/app/(admin)/admin/layout.tsx b/app/app/(admin)/admin/layout.tsx index c60375cf8..a760b9960 100644 --- a/app/app/(admin)/admin/layout.tsx +++ b/app/app/(admin)/admin/layout.tsx @@ -1,6 +1,9 @@ "use client"; -import React, { ReactNode, useState } from "react"; +import { useSession } from "next-auth/react"; +import { redirect } from "next/navigation"; +import { ADMIN_LIST } from "@/lib/auth_list"; +import React, { ReactNode, useEffect, useState } from "react"; import { MenuFoldOutlined, MenuUnfoldOutlined, @@ -15,12 +18,23 @@ const { Header, Sider, Content } = Layout; function MainLayout({ children }: { children: ReactNode }) { // const [theme, setTheme] = useState('dark'); - + const { data, status } = useSession(); + const name = data?.user?.email || data?.user?.name; + // console.log('name', name, data, status) const [collapsed, setCollapsed] = useState(false); const { token: { colorBgContainer, borderRadiusLG, colorBgLayout }, } = theme.useToken(); + // 客户端才执行 + useEffect(() => { + // 用户已登录,且没设置密码 + // if (status === "loading") return; + if (status === "authenticated" && !(name && ADMIN_LIST.includes(name))) { + redirect("/"); + } + // 状态变化时,重新判断 + }, [name, status]); return ( + + + + + ); +} diff --git a/app/app/(admin)/components/sidebar.tsx b/app/app/(admin)/components/sidebar.tsx index 89c98108a..0287214ba 100644 --- a/app/app/(admin)/components/sidebar.tsx +++ b/app/app/(admin)/components/sidebar.tsx @@ -68,33 +68,15 @@ const SideBar: React.FC = () => { setCurrent(e.key); router.push(e.key); }; - useEffect(() => { - // 如果按钮和路径不相等,那其实应该跳转到按钮的网址 - if (current != pathname) { - router.push(current); - } - }, [current, pathname, router]); // useEffect(() => { - // const handleStart = () => setLoading(true) - // const handleComplete = () => setLoading(false); - // router.events.on('routeChangeStart', handleStart); - // router.events.on('routeChangeComplete', handleStop); - // router.events.on('routeChangeError', handleStop); - // - // return () => { - // router. - // } - // - // }, [router]); + // // 如果按钮和路径不相等,那其实应该跳转到按钮的网址 + // if (current != pathname) { + // router.push(current); + // } + // }, [current, pathname, router]); return ( <> - {/**/}

; + +function UsersTable({ users }: UserInterface) { + // const data = {} + // console.log('[data]', users) + const [searchText, setSearchText] = useState(""); + const [searchedColumn, setSearchedColumn] = useState(""); + const searchInput = useRef(null); + const handleSearch = ( + selectedKeys: string[], + confirm: FilterDropdownProps["confirm"], + dataIndex: DataIndex, + ) => { + confirm(); + setSearchText(selectedKeys[0]); + setSearchedColumn(dataIndex); + }; + + const handleReset = (clearFilters: () => void) => { + clearFilters(); + setSearchText(""); + }; + + const getColumnSearchProps = ( + dataIndex: DataIndex, + ): TableColumnType => ({ + filterDropdown: ({ + setSelectedKeys, + selectedKeys, + confirm, + clearFilters, + close, + }) => ( +
e.stopPropagation()}> + + setSelectedKeys(e.target.value ? [e.target.value] : []) + } + onPressEnter={() => + handleSearch(selectedKeys as string[], confirm, dataIndex) + } + style={{ marginBottom: 8, display: "block" }} + /> + + + + + + +
+ ), + filterIcon: (filtered: boolean) => ( + + ), + onFilter: (value, record: User) => { + let result = record?.[dataIndex]; + if (result) { + return result + .toString() + .toLowerCase() + .includes((value as string).toLowerCase()); + } + return false; + }, + onFilterDropdownOpenChange: (visible) => { + if (visible) { + setTimeout(() => searchInput.current?.select(), 100); + } + }, + render: (text) => + searchedColumn === dataIndex ? ( + + ) : ( + text + ), + }); + + const columns: TableColumnsType = [ + { title: "Name", dataIndex: "name", ...getColumnSearchProps("name") }, + { + title: "UserName", + dataIndex: "username", + ...getColumnSearchProps("username"), + }, + { title: "Email", dataIndex: "email", ...getColumnSearchProps("email") }, + { + title: "createdAt", + dataIndex: "createdAt", + render: (value) => getCurrentTime(value), + sorter: (a, b) => { + if (a.createdAt < b.createdAt) return 1; + return -1; + }, + }, + { + title: "updatedAt", + dataIndex: "updatedAt", + render: (value) => getCurrentTime(value), + }, + ]; + + return ; +} + +export default UsersTable; diff --git a/app/utils/custom.ts b/app/utils/custom.ts index a6636f7d3..43aba914c 100644 --- a/app/utils/custom.ts +++ b/app/utils/custom.ts @@ -1,5 +1,7 @@ -export function getCurrentTime(): string { - const now = new Date(); +export function getCurrentTime(now?: Date): string { + if (!now) { + const now = new Date(); + } const formatter = new Intl.DateTimeFormat("zh-CN", { timeZone: "Asia/Shanghai", // 设置为中国标准时间 year: "numeric", diff --git a/lib/auth_list.ts b/lib/auth_list.ts index c28ea6df2..5dfd2a68b 100644 --- a/lib/auth_list.ts +++ b/lib/auth_list.ts @@ -1,6 +1,6 @@ export const DENY_LIST: string[] = [ - "suibian", "某某", "张三", "李四", "啊实打实", "官方回复电话", "笑死", "观化听风" + "suibian", "某某", "张三", "李四", "啊实打实", "官方回复电话", "笑死", "观化听风", "null", "undefined", ] export const ADMIN_LIST: string[] = [ "司金辉", "sijinhui", "sijinhui@qq.com", diff --git a/package.json b/package.json index 4c97b71b8..91d625e44 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@vercel/speed-insights": "^1.0.9", "antd": "^5.15.1", "bcryptjs": "^2.4.3", + "cron": "^3.1.6", "echarts": "^5.4.3", "emoji-picker-react": "^4.7.10", "fuse.js": "^7.0.0", @@ -39,6 +40,7 @@ "nodemailer": "^6.9.13", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-highlight-words": "^0.20.0", "react-markdown": "^9.0.1", "react-router-dom": "^6.21.3", "rehype-highlight": "^7.0.0", @@ -60,6 +62,7 @@ "@types/node": "^20.11.10", "@types/react": "^18.2.48", "@types/react-dom": "^18.2.7", + "@types/react-highlight-words": "^0.16.7", "@types/react-katex": "^3.0.0", "@types/spark-md5": "^3.0.4", "autoprefixer": "^10.4.17", @@ -74,7 +77,7 @@ "postcss": "^8.4.33", "prettier": "^3.2.4", "prettier-plugin-tailwindcss": "^0.5.11", - "prisma": "^5.9.0", + "prisma": "^5.11.0", "tailwindcss": "^3.4.1", "tailwindcss-animate": "^1.0.7", "typescript": "^5.3.3",