From c8b6c313575bb84a0b3bc2a69b5745528ddfc098 Mon Sep 17 00:00:00 2001 From: sijinhui Date: Tue, 26 Mar 2024 21:18:43 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app/(admin)/admin/users/page.tsx | 4 +++ app/app/(admin)/components/sidebar.tsx | 12 +++---- .../(admin)/components/user-table-search.tsx | 31 +++++++++++++++++++ 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 app/app/(admin)/components/user-table-search.tsx diff --git a/app/app/(admin)/admin/users/page.tsx b/app/app/(admin)/admin/users/page.tsx index 2e94d5805..999964fe6 100644 --- a/app/app/(admin)/admin/users/page.tsx +++ b/app/app/(admin)/admin/users/page.tsx @@ -2,6 +2,7 @@ import { Flex } from "antd"; import prisma from "@/lib/prisma"; import { User } from "@prisma/client"; import UsersTable from "../../components/users-table"; +import UserTableSearchInput from "../../components/user-table-search"; async function getData() { return await prisma.user.findMany({ @@ -18,6 +19,9 @@ export default async function UsersPage() { return ( <> +
+ +
diff --git a/app/app/(admin)/components/sidebar.tsx b/app/app/(admin)/components/sidebar.tsx index b3081cb2a..ec0883048 100644 --- a/app/app/(admin)/components/sidebar.tsx +++ b/app/app/(admin)/components/sidebar.tsx @@ -63,12 +63,12 @@ const SideBar: React.FC = () => { setCurrent(e.key); router.push(e.key); }; - useEffect(() => { - // 如果按钮和路径不相等,那其实应该跳转到按钮的网址 - if (current != pathname) { - router.push(current); - } - }, [current, pathname, router]); + // useEffect(() => { + // // 如果按钮和路径不相等,那其实应该跳转到按钮的网址 + // if (current != pathname) { + // router.push(current); + // } + // }, [current, pathname, router]); return ( <> diff --git a/app/app/(admin)/components/user-table-search.tsx b/app/app/(admin)/components/user-table-search.tsx new file mode 100644 index 000000000..1e24e7200 --- /dev/null +++ b/app/app/(admin)/components/user-table-search.tsx @@ -0,0 +1,31 @@ +"use client"; + +import React from "react"; +import { AudioOutlined } from "@ant-design/icons"; +import { Input, Space } from "antd"; +import type { SearchProps } from "antd/es/input/Search"; + +const { Search } = Input; + +const suffix = ( + +); + +const onSearch: SearchProps["onSearch"] = (value, _e, info) => + console.log(info?.source, value); + +const UserTableSearchInput: React.FC = () => ( + +); + +export default UserTableSearchInput; From 45fa760db1e06a8e2e20309bae82d5f5557131be Mon Sep 17 00:00:00 2001 From: sijinhui Date: Tue, 26 Mar 2024 23:23:03 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E8=A1=A8=E5=88=9D=E6=AD=A5=E6=88=90=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/admin/users/[...path]/route.ts | 23 ++ app/api/admin/users/route.ts | 58 +++ app/app/(admin)/admin/users/page.tsx | 24 +- app/app/(admin)/components/sidebar.tsx | 4 +- .../(admin)/components/user-table-search.tsx | 31 -- app/app/(admin)/components/users-table.tsx | 340 +++++++++++------- app/styles/globals.scss | 28 +- 7 files changed, 325 insertions(+), 183 deletions(-) create mode 100644 app/api/admin/users/[...path]/route.ts create mode 100644 app/api/admin/users/route.ts delete mode 100644 app/app/(admin)/components/user-table-search.tsx diff --git a/app/api/admin/users/[...path]/route.ts b/app/api/admin/users/[...path]/route.ts new file mode 100644 index 000000000..eafb0b642 --- /dev/null +++ b/app/api/admin/users/[...path]/route.ts @@ -0,0 +1,23 @@ +import { NextRequest, NextResponse } from "next/server"; +import prisma from "@/lib/prisma"; + +async function handle( + req: NextRequest, + { params }: { params: { path: string[] } }, +) { + // 判断网址和请求方法 + // const method = req.method; + // // const url = req.url; + // const { pathname } = new URL(req.url); + // + // console.log('123', method, pathname,) + // const result = await prisma.user.findMany({ + // orderBy: { + // createdAt: "desc", + // }, + // }); + return NextResponse.json({ error: "暂未开发" }, { status: 400 }); +} + +export const GET = handle; +export const POST = handle; diff --git a/app/api/admin/users/route.ts b/app/api/admin/users/route.ts new file mode 100644 index 000000000..42999d237 --- /dev/null +++ b/app/api/admin/users/route.ts @@ -0,0 +1,58 @@ +import { NextRequest, NextResponse } from "next/server"; +import prisma from "@/lib/prisma"; + +async function handle( + req: NextRequest, + { params }: { params: { path: string[] } }, +) { + // 判断网址和请求方法 + const method = req.method; + // const url = req.url; + const { pathname, searchParams } = new URL(req.url); + const searchText = searchParams.get("search"); + // console.log(req) + + if (method === "GET") { + // 是否有查询 + const result = searchText + ? await prisma.user.findMany({ + orderBy: { + createdAt: "desc", + }, + where: { + OR: [ + { + name: { + contains: searchText, + mode: "insensitive", // 不区分大小写 + }, + }, + { + username: { + contains: searchText, + mode: "insensitive", // 不区分大小写 + }, + }, + { + email: { + contains: searchText, + mode: "insensitive", // 不区分大小写 + }, + }, + ], + }, + }) + : await prisma.user.findMany({ + orderBy: { + createdAt: "desc", + }, + }); + const count = result.length; + return NextResponse.json({ count: count, results: result }); + } + + return NextResponse.json({ error: "当前方法不支持" }, { status: 400 }); +} + +export const GET = handle; +export const POST = handle; diff --git a/app/app/(admin)/admin/users/page.tsx b/app/app/(admin)/admin/users/page.tsx index 999964fe6..6884d7c67 100644 --- a/app/app/(admin)/admin/users/page.tsx +++ b/app/app/(admin)/admin/users/page.tsx @@ -1,28 +1,24 @@ import { Flex } from "antd"; import prisma from "@/lib/prisma"; import { User } from "@prisma/client"; -import UsersTable from "../../components/users-table"; -import UserTableSearchInput from "../../components/user-table-search"; +import UsersTablePart from "../../components/users-table"; -async function getData() { - return await prisma.user.findMany({ - orderBy: { - createdAt: "desc", - }, - }); -} +// async function getData() { +// return await prisma.user.findMany({ +// orderBy: { +// createdAt: "desc", +// }, +// }); +// } export default async function UsersPage() { - const users: User[] = await getData(); + // const users: User[] = await getData(); // console.log("data", data); return ( <> -
- -
- +
); diff --git a/app/app/(admin)/components/sidebar.tsx b/app/app/(admin)/components/sidebar.tsx index ec0883048..3c037335e 100644 --- a/app/app/(admin)/components/sidebar.tsx +++ b/app/app/(admin)/components/sidebar.tsx @@ -50,7 +50,7 @@ const items: MenuItem[] = [ const SideBar: React.FC = () => { const [theme, setTheme] = useState("dark"); - const [current, setCurrent] = useState("/admin/ana"); + const [current, setCurrent] = useState(""); const router = useRouter(); const [loading, setLoading] = useState(false); const pathname = usePathname(); @@ -78,7 +78,7 @@ const SideBar: React.FC = () => { theme={theme} onClick={onClick} // style={{ width: 256 }} - defaultOpenKeys={["dashboard"]} + // defaultOpenKeys={["dashboard"]} selectedKeys={[current]} mode="inline" items={items} diff --git a/app/app/(admin)/components/user-table-search.tsx b/app/app/(admin)/components/user-table-search.tsx deleted file mode 100644 index 1e24e7200..000000000 --- a/app/app/(admin)/components/user-table-search.tsx +++ /dev/null @@ -1,31 +0,0 @@ -"use client"; - -import React from "react"; -import { AudioOutlined } from "@ant-design/icons"; -import { Input, Space } from "antd"; -import type { SearchProps } from "antd/es/input/Search"; - -const { Search } = Input; - -const suffix = ( - -); - -const onSearch: SearchProps["onSearch"] = (value, _e, info) => - console.log(info?.source, value); - -const UserTableSearchInput: React.FC = () => ( - -); - -export default UserTableSearchInput; diff --git a/app/app/(admin)/components/users-table.tsx b/app/app/(admin)/components/users-table.tsx index 6662f5c4e..31185b25a 100644 --- a/app/app/(admin)/components/users-table.tsx +++ b/app/app/(admin)/components/users-table.tsx @@ -1,6 +1,12 @@ "use client"; -import React, { useRef, useState } from "react"; +import React, { + Dispatch, + SetStateAction, + useEffect, + useRef, + useState, +} from "react"; import { User } from "@prisma/client"; import { Space, Table, Tag, Input, Button } from "antd"; import { SearchOutlined } from "@ant-design/icons"; @@ -9,145 +15,194 @@ import type { GetRef, TableColumnsType, TableColumnType } from "antd"; import Highlighter from "react-highlight-words"; // 后期考虑删除该依赖 +import type { SearchProps } from "antd/es/input/Search"; + +const { Search } = Input; + import { getCurrentTime } from "@/app/utils/custom"; interface UserInterface { users: User[]; + setUsers: Dispatch>; + loading: Boolean; + setLoading: Dispatch>; } +interface SearchTextProps { + searchText: string; + setSearchText: Dispatch>; +} + type DataIndex = keyof User; type InputRef = GetRef; -function UsersTable({ users }: UserInterface) { - // const data = {} - // console.log('[data]', users) +function UserTableSearchInput({ users, setUsers, setLoading }: UserInterface) { 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 onSearch: SearchProps["onSearch"] = (value, _e, info) => { + setSearchText(value); }; - const handleReset = (clearFilters: () => void) => { - clearFilters(); - setSearchText(""); - }; + useEffect(() => { + setLoading(true); + const fetchUsers = async () => { + try { + const url = new URL("/api/admin/users/", "http://localhost:3000"); + url.searchParams.append("search", searchText); + console.log(url, "url"); + const response = await fetch(url); + if (response.ok) { + const data = await response.json(); + setUsers(data["results"]); + setLoading(false); + } + } catch (e) { + setLoading(false); + console.log("fetch user error: ", e); + } + }; - 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) { - // @ts-ignore - setTimeout(() => searchInput.current?.select(), 100); - } - }, - render: (text) => - searchedColumn === dataIndex ? ( - // @ts-ignore - - ) : ( - text - ), - }); + fetchUsers(); + console.log(users, "users1"); + }, [searchText]); + + return ( + + ); +} + +function UsersTable({ users, setUsers, loading }: UserInterface) { + // 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) { + // // @ts-ignore + // setTimeout(() => searchInput.current?.select(), 100); + // } + // }, + // render: (text) => + // searchedColumn === dataIndex ? ( + // // @ts-ignore + // + // ) : ( + // text + // ), + // }); const columns: TableColumnsType = [ - { title: "Name", dataIndex: "name", ...getColumnSearchProps("name") }, + { title: "Name", dataIndex: "name" }, { title: "UserName", dataIndex: "username", - ...getColumnSearchProps("username"), }, - { title: "Email", dataIndex: "email", ...getColumnSearchProps("email") }, + { title: "Email", dataIndex: "email" }, { title: "createdAt", dataIndex: "createdAt", - render: (value) => getCurrentTime(value), + render: (value) => getCurrentTime(new Date(value)), sorter: (a, b) => { if (a.createdAt < b.createdAt) return 1; return -1; @@ -156,11 +211,52 @@ function UsersTable({ users }: UserInterface) { { title: "updatedAt", dataIndex: "updatedAt", - render: (value) => getCurrentTime(value), + render: (value) => getCurrentTime(new Date(value)), + }, + { + title: "Action", + dataIndex: "", + key: "id", + render: () => ( + + 编辑 + 删除 + + ), }, ]; + console.log(users, "users2"); - return ; + return ( +
+ ); } -export default UsersTable; +function UsersTablePart() { + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(false); + + return ( + <> + + + + ); +} + +export default UsersTablePart; diff --git a/app/styles/globals.scss b/app/styles/globals.scss index c9dc0b8d5..539df3acb 100644 --- a/app/styles/globals.scss +++ b/app/styles/globals.scss @@ -219,20 +219,20 @@ input[type="range"]::-ms-thumb:hover { @include thumbHover(); } -input[type="number"], -input[type="text"], -input[type="password"] { - appearance: none; - border-radius: 10px; - border: var(--border-in-light); - min-height: 36px; - box-sizing: border-box; - background: var(--white); - color: var(--black); - padding: 0 10px; - max-width: 50%; - font-family: inherit; -} +//input[type="number"], +//input[type="text"], +//input[type="password"] { +// appearance: none; +// border-radius: 10px; +// border: var(--border-in-light); +// min-height: 36px; +// box-sizing: border-box; +// background: var(--white); +// color: var(--black); +// padding: 0 10px; +// max-width: 50%; +// font-family: inherit; +//} div.math { overflow-x: auto;