save
This commit is contained in:
parent
f532a992e1
commit
2603adc802
|
@ -1,5 +1,6 @@
|
||||||
import SiderNav from "../_ui/SiderNav";
|
import SiderNav from "../_ui/SiderNav";
|
||||||
import { getLinkTypeList } from "../_lib/data/linkType";
|
import { getLinkTypeList } from "../_lib/data/linkType";
|
||||||
|
import HeaderNav from "../_ui/HeaderNav";
|
||||||
|
|
||||||
export default async function Layout({ children }: Readonly<{ children: React.ReactNode }>) {
|
export default async function Layout({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||||
|
|
||||||
|
@ -16,6 +17,8 @@ export default async function Layout({ children }: Readonly<{ children: React.Re
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<HeaderNav></HeaderNav>
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,8 @@ export default async function Page() {
|
||||||
<div className="flex min-h-full w-full font-[family-name:var(--font-geist-sans)] relative">
|
<div className="flex min-h-full w-full font-[family-name:var(--font-geist-sans)] relative">
|
||||||
<SiderNav linkList={linkTypeList} />
|
<SiderNav linkList={linkTypeList} />
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
|
|
||||||
<main className="flex-1 relative flex flex-col p-5 gap-y-4">
|
<main className="flex-1 relative flex flex-col p-5 gap-y-4">
|
||||||
|
|
||||||
{/* <HeaderNav></HeaderNav> */}
|
|
||||||
<Search></Search>
|
<Search></Search>
|
||||||
{/* <PosterBox posterList={[]} /> */}
|
|
||||||
<LinkListBox linkList={linkList} linkTypeList={linkTypeList} showHot showRecent></LinkListBox>
|
<LinkListBox linkList={linkList} linkTypeList={linkTypeList} showHot showRecent></LinkListBox>
|
||||||
</main>
|
</main>
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export default function Page() {
|
||||||
|
return <div>
|
||||||
|
home
|
||||||
|
</div>
|
||||||
|
}
|
|
@ -2,4 +2,3 @@ import { atom } from 'jotai';
|
||||||
|
|
||||||
// 定义一个简单的原子
|
// 定义一个简单的原子
|
||||||
export const linkTypeAtom = atom('');
|
export const linkTypeAtom = atom('');
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
|
import { ObjectId } from "mongodb";
|
||||||
|
import { verifySession } from "../dal";
|
||||||
import { getCollection } from "../mongodb";
|
import { getCollection } from "../mongodb";
|
||||||
|
|
||||||
export type SearchTypeItem = {
|
export type SearchTypeItem = {
|
||||||
|
@ -37,7 +39,7 @@ export async function getSearchTypeList({ page = 1, pageSize = 9999 }: {
|
||||||
const list = await cursor.toArray();
|
const list = await cursor.toArray();
|
||||||
|
|
||||||
// 计算总数量
|
// 计算总数量
|
||||||
const total = (await collection.find<SearchTypeItem>({}).toArray()).length
|
const total = await collection.countDocuments()
|
||||||
return {
|
return {
|
||||||
total,
|
total,
|
||||||
list
|
list
|
||||||
|
@ -69,3 +71,11 @@ export async function getSearchWayList({ page = 1, pageSize = 9999 }: {
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export async function deleteSearchWay(id: string) {
|
||||||
|
|
||||||
|
const collection = await getCollection('search-type')
|
||||||
|
collection.deleteOne({
|
||||||
|
_id: new ObjectId(id)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export default function HeaderNav() {
|
export default function HeaderNav() {
|
||||||
return (
|
return (
|
||||||
<header className="w-full gap-x-2 flex py-4 px-5 text-[14px]">
|
<header className="w-full gap-x-2 flex py-4 px-5 text-[14px]">
|
||||||
<div>AI应用集</div>
|
<Link href={"/"}>AI合集</Link>
|
||||||
<div>AI应用集</div>
|
<Link href={"/news"}>AI新闻</Link>
|
||||||
<div>AI应用集</div>
|
<Link href={"/article"}>AI文章</Link>
|
||||||
<div>AI应用集</div>
|
|
||||||
<div>AI应用集</div>
|
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -38,9 +38,9 @@ export default function LinkListBox({ linkTypeList, linkList, showHot, showRecen
|
||||||
return <div className="flex w-full flex-col gap-y-4">
|
return <div className="flex w-full flex-col gap-y-4">
|
||||||
{
|
{
|
||||||
showHot && <div className="flex flex-col gap-y-2" >
|
showHot && <div className="flex flex-col gap-y-2" >
|
||||||
<div className="flex items-center text-[#555555] gap-x-2 text-xl">
|
<div className="flex items-center text-[#555555] gap-x-2 text-xl">
|
||||||
<FontAwesomeIcon icon={faFire} className="text-red-500"></FontAwesomeIcon>
|
<FontAwesomeIcon icon={faFire} className="text-red-500 "></FontAwesomeIcon>
|
||||||
<span className="text-white bg-red-500/90 rounded-2xl px-3 text-[14px] font-bold">热门网站</span>
|
<span className="text-white bg-red-500/90 rounded-2xl px-3 py-1 text-[14px] font-bold">热门网站</span>
|
||||||
</div>
|
</div>
|
||||||
<div className=" grid grid-cols-3 lg:grid-cols-6 gap-4 ">
|
<div className=" grid grid-cols-3 lg:grid-cols-6 gap-4 ">
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ export default function LinkListBox({ linkTypeList, linkList, showHot, showRecen
|
||||||
showRecent && <div className="flex flex-col gap-y-2" >
|
showRecent && <div className="flex flex-col gap-y-2" >
|
||||||
<div className="flex items-center text-[#555555] gap-x-2 text-xl">
|
<div className="flex items-center text-[#555555] gap-x-2 text-xl">
|
||||||
<FontAwesomeIcon icon={faClock} className="text-blue-500"></FontAwesomeIcon>
|
<FontAwesomeIcon icon={faClock} className="text-blue-500"></FontAwesomeIcon>
|
||||||
<span className="text-white bg-blue-500/90 rounded-2xl px-3 text-[14px] font-bold">最新收录</span>
|
<span className="text-white bg-blue-500/90 rounded-2xl px-3 py-1 text-[14px] font-bold">最新收录</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className=" grid grid-cols-3 lg:grid-cols-6 gap-4 ">
|
<div className=" grid grid-cols-3 lg:grid-cols-6 gap-4 ">
|
||||||
|
|
|
@ -7,16 +7,30 @@ import { useEffect, useMemo, useState } from "react";
|
||||||
import Logo from "./Logo";
|
import Logo from "./Logo";
|
||||||
import { useRequest } from "ahooks";
|
import { useRequest } from "ahooks";
|
||||||
import { mRequest } from "../_lib/request";
|
import { mRequest } from "../_lib/request";
|
||||||
import { SearchTypeItem, SearchWayItemType } from "../_lib/data/search";
|
import { getSearchTypeList, getSearchWayList, SearchTypeItem, SearchWayItemType } from "../_lib/data/search";
|
||||||
import { doSearch } from "../_lib/utils";
|
import { doSearch } from "../_lib/utils";
|
||||||
import { log } from "node:console";
|
import { log } from "node:console";
|
||||||
|
|
||||||
|
|
||||||
|
const defaultSearchEngine: SearchWayItemType = {
|
||||||
|
_id: 'default',
|
||||||
|
label: '站内',
|
||||||
|
value: '/search?wd=%s',
|
||||||
|
fullName: '站内',
|
||||||
|
}
|
||||||
|
|
||||||
export default function Search() {
|
export default function Search() {
|
||||||
|
|
||||||
const { data: searchWayList = [] } = useRequest(() => mRequest<{ list: SearchWayItemType[] }>('GET', '/api/search?page=1&pageSize=999').then(res => res.list))
|
const { data: searchWayList = [] } = useRequest(() => getSearchWayList({ page: 1, pageSize: 9999 }).then(res => [defaultSearchEngine, ...res.list]))
|
||||||
const { data: searchTypeList = [] } = useRequest(() => mRequest<{ list: SearchTypeItem[] }>('GET', '/api/searchType?page=1&pageSize=999').then(res => res.list))
|
const { data: searchTypeList = [] } = useRequest(() => getSearchTypeList({ page: 1, pageSize: 9999 }).then(res => res.list.map((val, idx) => {
|
||||||
|
if (idx === 0) {
|
||||||
|
return {
|
||||||
|
...val,
|
||||||
|
includes: ['default', ...val.includes]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
})))
|
||||||
const [selectKey, setSelectKey] = useState<string | null>(null)
|
const [selectKey, setSelectKey] = useState<string | null>(null)
|
||||||
const [activeSearchKey, setActiveSearchKey] = useState<string | null>(null)
|
const [activeSearchKey, setActiveSearchKey] = useState<string | null>(null)
|
||||||
const [inputStr, setInputStr] = useState('')
|
const [inputStr, setInputStr] = useState('')
|
||||||
|
@ -49,25 +63,28 @@ export default function Search() {
|
||||||
}
|
}
|
||||||
}, [selectKey])
|
}, [selectKey])
|
||||||
return (
|
return (
|
||||||
<div className="w-full flex justify-center flex-col items-center py-10 h-[500px]">
|
<div className="w-full flex justify-center flex-col items-center py-10 h-[300px]">
|
||||||
|
|
||||||
<div className="w-[200px]">
|
<div className="w-[200px]">
|
||||||
<Logo></Logo>
|
<Logo></Logo>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full lg:w-[800px] flex flex-col gap-y-2">
|
<div className="w-full lg:w-[800px] flex flex-col gap-y-2">
|
||||||
<div className="flex w-full justify-center gap-x-5 text-[#666666]">
|
<div className="flex w-full justify-center gap-x-5 text-[#666666]">
|
||||||
|
|
||||||
{
|
{
|
||||||
searchTypeList.map(item => (
|
searchTypeList.map((item, idx) => (
|
||||||
<div key={item._id}
|
<div key={item._id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectKey(item._id)
|
setSelectKey(item._id)
|
||||||
}}
|
}}
|
||||||
className={clsx(item._id === selectKey ?
|
className={clsx(item._id === selectKey || (idx === 0 && selectKey === 'default') ?
|
||||||
"text-[#333]" : "text-[#999] cursor-pointer")}>
|
"text-[#333]" : "text-[#999] cursor-pointer")}>
|
||||||
{item.name}
|
{item.name}
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full relative">
|
<div className="w-full relative">
|
||||||
<input
|
<input
|
||||||
|
@ -83,10 +100,11 @@ export default function Search() {
|
||||||
setInputStr(e.target.value)
|
setInputStr(e.target.value)
|
||||||
|
|
||||||
}}
|
}}
|
||||||
placeholder={`${activeSearch?.label}搜索`} className="w-full bg-[#C4C2C6] px-4 h-[50px] rounded-3xl outline-none" />
|
placeholder={`${activeSearch?.label || ' '}搜索`} className="w-full bg-[#C4C2C6] px-4 h-[50px] rounded-3xl outline-none" />
|
||||||
<FontAwesomeIcon className="text-white absolute top-1/2 -translate-y-1/2 right-6 text-xl" icon={faSearch}></FontAwesomeIcon>
|
<FontAwesomeIcon className="text-white absolute top-1/2 -translate-y-1/2 right-6 text-xl" icon={faSearch}></FontAwesomeIcon>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex justify-center gap-x-4 ">
|
<div className="w-full flex justify-center gap-x-4 ">
|
||||||
|
|
||||||
{
|
{
|
||||||
filterSeachList.map(item => (
|
filterSeachList.map(item => (
|
||||||
<div key={item._id} onClick={() => {
|
<div key={item._id} onClick={() => {
|
||||||
|
|
|
@ -3,13 +3,14 @@ import Link from "next/link";
|
||||||
import { LinkTypeItem } from "../_lib/types";
|
import { LinkTypeItem } from "../_lib/types";
|
||||||
import Logo from "./Logo";
|
import Logo from "./Logo";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname, useRouter } from "next/navigation";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
import { linkTypeAtom } from "../_lib/atom";
|
import { linkTypeAtom } from "../_lib/atom";
|
||||||
import { LinkType } from "../_lib/data/linkType";
|
import { LinkType } from "../_lib/data/linkType";
|
||||||
|
|
||||||
export default function SiderNav({ linkList }: { linkList: LinkType[] }) {
|
export default function SiderNav({ linkList }: { linkList: LinkType[] }) {
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
|
const router = useRouter()
|
||||||
const [, setSelectType] = useAtom(linkTypeAtom)
|
const [, setSelectType] = useAtom(linkTypeAtom)
|
||||||
return (
|
return (
|
||||||
<div className="w-[220px] flex flex-col gap-y-2 fixed left-0 top-0 h-[100vh] bg-[#F9F9F9]">
|
<div className="w-[220px] flex flex-col gap-y-2 fixed left-0 top-0 h-[100vh] bg-[#F9F9F9]">
|
||||||
|
@ -31,6 +32,10 @@ export default function SiderNav({ linkList }: { linkList: LinkType[] }) {
|
||||||
</Link> :
|
</Link> :
|
||||||
<div className="cursor-pointer py-3 flex gap-x-2 items-center hover:bg-[#E0E0E0] rounded pl-3 text-[#515C6B] hover:text-[#5961F9] text-[14px]" key={item._id}
|
<div className="cursor-pointer py-3 flex gap-x-2 items-center hover:bg-[#E0E0E0] rounded pl-3 text-[#515C6B] hover:text-[#5961F9] text-[14px]" key={item._id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
||||||
|
if (pathname !== '/') {
|
||||||
|
router.replace('/')
|
||||||
|
}
|
||||||
setSelectType(item._id)
|
setSelectType(item._id)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"use client";
|
"use client";
|
||||||
import { SearchTypeItem, SearchWayItemType } from "@/app/_lib/data/search";
|
import { deleteSearchWay, SearchTypeItem, SearchWayItemType } from "@/app/_lib/data/search";
|
||||||
import { mRequest } from "@/app/_lib/request";
|
import { mRequest } from "@/app/_lib/request";
|
||||||
import { useAntdTable } from "ahooks";
|
import { useAntdTable } from "ahooks";
|
||||||
import { Button, Card, Drawer, Form, Input, InputNumber, message, Popconfirm, Space, Table } from "antd";
|
import { Button, Card, Drawer, Form, Input, InputNumber, message, Popconfirm, Space, Table } from "antd";
|
||||||
|
@ -63,8 +63,12 @@ export default function Page() {
|
||||||
okText="确定"
|
okText="确定"
|
||||||
cancelText="取消"
|
cancelText="取消"
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
mRequest('DELETE', `/api/search/${row._id}`).then(res => {
|
// mRequest('DELETE', `/api/search/${row._id}`).then(res => {
|
||||||
|
// refresh()
|
||||||
|
// })
|
||||||
|
deleteSearchWay(row._id).then(res => {
|
||||||
refresh()
|
refresh()
|
||||||
|
message.success('删除成功')
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -243,6 +247,7 @@ export default function Page() {
|
||||||
await mRequest("POST", "/api/searchType", {
|
await mRequest("POST", "/api/searchType", {
|
||||||
...res,
|
...res,
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
refreshTypeList()
|
refreshTypeList()
|
||||||
setSelectedType(undefined)
|
setSelectedType(undefined)
|
||||||
|
|
Loading…
Reference in New Issue