Compare commits

...

7 Commits
master ... dev

Author SHA1 Message Date
expdsn e1bf501c13 save 2025-02-18 18:36:06 +08:00
expdsn 35d61ebd6c 更改 2025-02-18 17:39:04 +08:00
expdsn d757d6712f Merge remote-tracking branch 'origin/markdown' into dev
# Conflicts:
#	app/admin/(default)/dashboard/article/detail/AddOrEdit.tsx
2025-02-18 17:38:54 +08:00
expdsn 0c08e7d230 更改 2025-02-18 17:09:28 +08:00
expdsn 18c4efc908 save 2025-02-18 11:32:41 +08:00
expdsn f273be61d4 clear 2025-02-17 18:17:12 +08:00
expdsn 2603adc802 save 2025-02-17 10:30:40 +08:00
44 changed files with 1163 additions and 194 deletions

149
.idea/workspace.xml Normal file
View File

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="84ab346f-c07b-447e-ab86-93b94f723f79" name="更改" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="PackageJsonUpdateNotifier">
<dismissed value="$PROJECT_DIR$/package.json" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 3
}</component>
<component name="ProjectId" id="2tCjKDO1RAqqDDpGgzpShWM9BvI" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"git-widget-placeholder": "markdown",
"ignore.virus.scanning.warn.message": "true",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "pnpm",
"npm.dev.executor": "Run",
"settings.editor.selected.configurable": "preferences.language.and.region",
"ts.external.directory.path": "C:\\Users\\expdsn\\WebstormProjects\\ai-bot\\node_modules\\typescript\\lib",
"vue.rearranger.settings.migration": "true"
}
}]]></component>
<component name="RunManager">
<configuration name="dev" type="js.build_tools.npm" temporary="true" nameIsGenerated="true">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="dev" />
</scripts>
<node-interpreter value="project" />
<package-manager value="yarn" />
<envs />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="npm.dev" />
</list>
</recent_temporary>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-js-predefined-d6986cc7102b-76f8388c3a79-JavaScript-WS-243.24978.60" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="默认任务">
<changelist id="84ab346f-c07b-447e-ab86-93b94f723f79" name="更改" comment="" />
<created>1739862885367</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1739862885367</updated>
<workItem from="1739862887270" duration="2556000" />
<workItem from="1739866039210" duration="2420000" />
<workItem from="1739868501347" duration="114000" />
<workItem from="1739868625193" duration="55000" />
<workItem from="1739868789923" duration="1235000" />
</task>
<task id="LOCAL-00001" summary="更改">
<option name="closed" value="true" />
<created>1739869769283</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1739869769283</updated>
</task>
<task id="LOCAL-00002" summary="1">
<option name="closed" value="true" />
<created>1739870022777</created>
<option name="number" value="00002" />
<option name="presentableId" value="LOCAL-00002" />
<option name="project" value="LOCAL" />
<updated>1739870022777</updated>
</task>
<option name="localTasksCounter" value="3" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="RECENT_FILTERS">
<map>
<entry key="Branch">
<value>
<list>
<RecentGroup>
<option name="FILTER_VALUES">
<option value="origin/dev" />
</option>
</RecentGroup>
</list>
</value>
</entry>
</map>
</option>
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State>
<option name="FILTERS">
<map>
<entry key="branch">
<value>
<list>
<option value="origin/dev" />
</list>
</value>
</entry>
</map>
</option>
</State>
</value>
</entry>
</map>
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="完成了网站的广告和详请展示" />
<MESSAGE value="更改" />
<MESSAGE value="1" />
<option name="LAST_COMMIT_MESSAGE" value="1" />
</component>
</project>

View File

@ -2,7 +2,7 @@ import { getArticle } from "@/app/_lib/data/article"
import MarkdownView from "@/app/_ui/MarkdownView"
import { faArrowRight } from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { MdEditor } from "md-editor-rt"
import Image from "next/image"
import Link from "next/link"
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
@ -14,8 +14,8 @@ export default async function Page({ params }: { params: Promise<{ id: string }>
<div className="w-full h-full ">
<div className="flex gap-x-5">
<div className="p-4 rounded-lg">
<img src={article?.cover} className=" rounded-lg shadow object-cover w-[200px] h-[200px]">
</img>
<Image src={article?.cover} width={200} height={200} className=" rounded-lg shadow object-cover w-[200px] h-[200px]" alt="">
</Image>
</div>
<div className="flex flex-col gap-y-3 py-5">
<h1 className="text-2xl">{article.title}</h1>

View File

@ -1,5 +1,6 @@
import SiderNav from "../_ui/SiderNav";
import { getLinkTypeList } from "../_lib/data/linkType";
import HeaderNav from "../_ui/HeaderNav";
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>
<HeaderNav></HeaderNav>
{children}
</div>

View File

@ -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">
<SiderNav linkList={linkTypeList} />
<div className="w-full">
<main className="flex-1 relative flex flex-col p-5 gap-y-4">
{/* <HeaderNav></HeaderNav> */}
<Search></Search>
{/* <PosterBox posterList={[]} /> */}
<LinkListBox linkList={linkList} linkTypeList={linkTypeList} showHot showRecent></LinkListBox>
</main>
<Footer></Footer>

View File

@ -0,0 +1,10 @@
export default function ResultBox() {
return <div className="h-[40vh] w-full px-4">
<div className="font-bold">:</div>
<div className="pl-2 border-l-blue-400 border-0 border-l-2 my-2"></div>
<div className="w-full grid grid-rows-6">
</div>
</div>
}

View File

@ -0,0 +1,9 @@
import Search from "@/app/_ui/Search";
import ResultBox from "./ResultBox";
export default function Page() {
return <div>
<Search></Search>
<ResultBox />
</div>
}

View File

@ -0,0 +1,18 @@
"use server"
import { ArticleType } from "../data/article"
import { Link } from "../data/link"
export type SiteSearchType = {
articles: ArticleType[];
articleCount: number;
links: Link[];
linkCount: number;
}
export async function doSearch(wd: string) {
return {
}
}

View File

@ -2,4 +2,3 @@ import { atom } from 'jotai';
// 定义一个简单的原子
export const linkTypeAtom = atom('');

View File

@ -1,7 +1,6 @@
"use server";
import { getCollection } from "../mongodb";
import { ReactNode } from "react";
export type Link = {
name: string;

View File

@ -1,5 +1,6 @@
"use server";
import { ObjectId } from "mongodb";
import { getCollection } from "../mongodb";
export type SearchTypeItem = {
@ -37,7 +38,7 @@ export async function getSearchTypeList({ page = 1, pageSize = 9999 }: {
const list = await cursor.toArray();
// 计算总数量
const total = (await collection.find<SearchTypeItem>({}).toArray()).length
const total = await collection.countDocuments()
return {
total,
list
@ -69,3 +70,11 @@ export async function getSearchWayList({ page = 1, pageSize = 9999 }: {
list
}
}
export async function deleteSearchWay(id: string) {
const collection = await getCollection('search-type')
collection.deleteOne({
_id: new ObjectId(id)
})
}

View File

@ -1,5 +1,5 @@
// lib/mongodb.ts
import { MongoClient, Db } from 'mongodb';
import { MongoClient } from 'mongodb';
const uri = process.env.MONGODB_URI;

View File

@ -1,4 +1,3 @@
import { message } from "antd"
/**
*
@ -13,7 +12,7 @@ export async function mRequest<T>(
data?: any,
responseType: 'json' | 'text' | 'blob' = 'json'
): Promise<T> {
let options: RequestInit = {
const options: RequestInit = {
method: method,
headers: {
'Content-Type': 'application/json'

View File

@ -23,7 +23,7 @@ export async function decrypt(session: string | undefined = '') {
algorithms: ['HS256'],
})
return payload
} catch (error) {
} catch {
console.log('Failed to verify session')
}
}

View File

@ -1,20 +0,0 @@
const OSS = require('ali-oss');
// 创建OSS实例
const client = new OSS({
accessKeyId: 'LTAI5tNzopZHJFa2Q9vqr1u5',
accessKeySecret: 'qPu7fyft0KJ1l6SGqbS71IW0vDbRlr'
// 先不指定region和bucket以便后续查询
});
// 列出所有Bucket
client.listBuckets().then((result) => {
console.log('所有的Bucket:', result.buckets);
// 打印每个Bucket的信息
result.buckets.forEach((bucket) => {
console.log('Bucket名称:', bucket.name);
console.log('Bucket所在区域:', bucket.location);
});
}).catch((error) => {
console.error('列出Bucket失败:', error);
});

View File

@ -1,52 +0,0 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { LinkTypeItem } from "../_lib/types";
import { faPenClip, faThumbsUp } from "@fortawesome/free-solid-svg-icons";
const defaultLinkList = [
{
label: 'AI应用集',
icon: <FontAwesomeIcon icon={faThumbsUp} className="fa-fw text-blue-500" />,
href: '/ai-apps',
id: 1,
},
{
label: 'AI写作工具',
icon: <FontAwesomeIcon icon={faPenClip} className="fa-fw text-blue-500" />,
id: 2,
},
{
label: 'AI写作工具',
icon: <FontAwesomeIcon icon={faPenClip} className="fa-fw text-blue-500" />,
id: 3,
},
{
label: 'AI写作工具',
icon: <FontAwesomeIcon icon={faPenClip} className="fa-fw text-blue-500" />,
id: 4,
},
{
label: 'AI写作工具',
icon: <FontAwesomeIcon icon={faPenClip} className="fa-fw text-blue-500" />,
id: 5,
},
{
label: 'AI写作工具',
icon: <FontAwesomeIcon icon={faPenClip} className="fa-fw text-blue-500" />,
id: 6,
},
{
label: 'AI写作工具',
icon: <FontAwesomeIcon icon={faPenClip} className="fa-fw text-blue-500" />,
id: 7,
},
{
label: 'AI写作工具',
icon: <FontAwesomeIcon icon={faPenClip} className="fa-fw text-blue-500" />,
id: 8,
},
{
label: 'AI写作工具',
icon: <FontAwesomeIcon icon={faPenClip} className="fa-fw text-blue-500" />,
id: 9,
}
] as LinkTypeItem[];

View File

@ -1,11 +1,12 @@
import Link from "next/link";
export default function HeaderNav() {
return (
<header className="w-full gap-x-2 flex py-4 px-5 text-[14px]">
<div>AI应用集</div>
<div>AI应用集</div>
<div>AI应用集</div>
<div>AI应用集</div>
<div>AI应用集</div>
<header className="w-full gap-x-2 flex py-4 px-5 text-[14px]">
<Link href={"/"}>AI合集</Link>
<Link href={"/news"}>AI新闻</Link>
<Link href={"/article"}>AI文章</Link>
</header>
);
}

View File

@ -24,7 +24,7 @@ export default function ImageUpload(props: {
if (url) {
props.onChange?.(url)
}
} catch (e) {
} catch {
setLoading(false)
}

View File

@ -4,7 +4,7 @@ import { LinkType } from "../_lib/data/linkType";
import { Link as _Link } from "../_lib/data/link";
import { useEffect, useMemo } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faClock, faFire, faTimeline, faTimesCircle, faTimesRectangle, faVolumeTimes } from "@fortawesome/free-solid-svg-icons";
import { faClock, faFire } from "@fortawesome/free-solid-svg-icons";
import { useAtom } from "jotai";
import { linkTypeAtom } from "../_lib/atom";
import Image from "next/image";
@ -12,16 +12,16 @@ import Image from "next/image";
const LinkBlock = ({ val }: { val: _Link }) => {
return <Link className="flex gap-x-2 bg-white rounded-lg py-4 pl-2 cursor-pointer duration-150 hover:-translate-y-1 shadow-sm"
href={val.articleId ? `/article/${val.articleId}` : val.link || ''} target="_blank">
<img src={val.logoLink} className="w-[40px] h-[40px]"></img>
<div className="flex-1 w-0 flex flex-col justify-between">
<Image alt="image" src={val.logoLink} className="w-[40px] h-[40px]" width={40} height={40}></Image>
<div className="flex-2 w-0 flex flex-col justify-between">
<span className=" font-bold text-ellipsis overflow-hidden whitespace-nowrap">{val.name}</span>
<span className=" text-ellipsis overflow-hidden whitespace-nowrap text-[#666] text-xs" title={val.description}>{val.description}</span>
<span className=" text-ellipsis overflow-hidden whitespace-nowrap text-[#665] text-xs" title={val.description}>{val.description}</span>
</div>
</Link>
}
export default function LinkListBox({ linkTypeList, linkList, showHot, showRecent }: { linkTypeList: LinkType[]; linkList: _Link[]; showHot: boolean; showRecent: boolean }) {
const hotList = useMemo(() => linkList.filter((val, index) => val.isHot && index < 12), [])
const recentList = useMemo(() => linkList.map(val => val).sort((a, b) => b.addTime - a.addTime).filter((_, idx) => idx < 12), [])
const hotList = useMemo(() => linkList.filter((val, index) => val.isHot && index < 12), [linkList])
const recentList = useMemo(() => linkList.map(val => val).sort((a, b) => b.addTime - a.addTime).filter((_, idx) => idx < 12), [linkList])
const [currentId] = useAtom(linkTypeAtom)
useEffect(() => {
console.log(currentId);
@ -38,9 +38,9 @@ export default function LinkListBox({ linkTypeList, linkList, showHot, showRecen
return <div className="flex w-full flex-col gap-y-4">
{
showHot && <div className="flex flex-col gap-y-2" >
<div className="flex items-center text-[#555555] gap-x-2 text-xl">
<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>
<div className="flex items-center text-[#555555] gap-x-2 text-xl">
<FontAwesomeIcon icon={faFire} className="text-red-500 "></FontAwesomeIcon>
<span className="text-white bg-red-500/90 rounded-2xl px-3 py-1 text-[14px] font-bold"></span>
</div>
<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" >
<div className="flex items-center text-[#555555] gap-x-2 text-xl">
<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 className=" grid grid-cols-3 lg:grid-cols-6 gap-4 ">
@ -72,7 +72,7 @@ export default function LinkListBox({ linkTypeList, linkList, showHot, showRecen
linkTypeList.map(item => (
<div className="flex flex-col gap-y-2" key={item._id} id={item._id}>
<div className="flex items-center text-[#555555] gap-x-2 text-xl">
<img src={item.icon as string} className="w-[30px] h-[30px] object-cover"></img>
<Image src={item.icon as string} className="w-[30px] h-[30px] object-cover" width={30} height={30} alt=""></Image>
<span>{item.label}</span>
</div>

View File

@ -1,5 +1,5 @@
"use client";
import { MdPreview, MdCatalog } from 'md-editor-rt';
import { MdPreview} from 'md-editor-rt';
export default function MarkdownView({ value = '' }: { value?: string }) {
return (

View File

@ -1,4 +1,6 @@
export default function PosterBox({ posterList }: { posterList: string[] }) {
console.log('posterList', posterList);
return (
<div className="w-full min-h-[140px] bg-white shadow-md rounded-lg p-2">
<div className="w-full grid grid-cols-5 gap-x-2">

View File

@ -6,17 +6,29 @@ import clsx from "clsx";
import { useEffect, useMemo, useState } from "react";
import Logo from "./Logo";
import { useRequest } from "ahooks";
import { mRequest } from "../_lib/request";
import { SearchTypeItem, SearchWayItemType } from "../_lib/data/search";
import { getSearchTypeList, getSearchWayList, SearchWayItemType } from "../_lib/data/search";
import { doSearch } from "../_lib/utils";
import { log } from "node:console";
const defaultSearchEngine: SearchWayItemType = {
_id: 'default',
label: '站内',
value: '/search?wd=%s',
fullName: '站内',
}
export default function Search() {
const { data: searchWayList = [] } = useRequest(() => mRequest<{ list: SearchWayItemType[] }>('GET', '/api/search?page=1&pageSize=999').then(res => res.list))
const { data: searchTypeList = [] } = useRequest(() => mRequest<{ list: SearchTypeItem[] }>('GET', '/api/searchType?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(() => 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 [activeSearchKey, setActiveSearchKey] = useState<string | null>(null)
const [inputStr, setInputStr] = useState('')
@ -47,27 +59,30 @@ export default function Search() {
if (filterSeachList.length > 0) {
setActiveSearchKey(filterSeachList[0]._id)
}
}, [selectKey])
}, [filterSeachList, selectKey])
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]">
<Logo></Logo>
</div>
<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]">
{
searchTypeList.map(item => (
searchTypeList.map((item, idx) => (
<div key={item._id}
onClick={() => {
setSelectKey(item._id)
}}
className={clsx(item._id === selectKey ?
className={clsx(item._id === selectKey || (idx === 0 && selectKey === 'default') ?
"text-[#333]" : "text-[#999] cursor-pointer")}>
{item.name}
</div>
))
}
</div>
<div className="w-full relative">
<input
@ -83,10 +98,11 @@ export default function Search() {
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>
</div>
<div className="w-full flex justify-center gap-x-4 ">
{
filterSeachList.map(item => (
<div key={item._id} onClick={() => {

View File

@ -1,16 +1,17 @@
"use client";
import Link from "next/link";
import { LinkTypeItem } from "../_lib/types";
import Logo from "./Logo";
import clsx from "clsx";
import { usePathname } from "next/navigation";
import { usePathname, useRouter } from "next/navigation";
import { useAtom } from "jotai";
import { linkTypeAtom } from "../_lib/atom";
import { LinkType } from "../_lib/data/linkType";
import Image from "next/image";
export default function SiderNav({ linkList }: { linkList: LinkType[] }) {
const pathname = usePathname()
const router = useRouter()
const [, setSelectType] = useAtom(linkTypeAtom)
return (
<div className="w-[220px] flex flex-col gap-y-2 fixed left-0 top-0 h-[100vh] bg-[#F9F9F9]">
<div className="bg-white shadow-sm">
@ -31,10 +32,14 @@ export default function SiderNav({ linkList }: { linkList: LinkType[] }) {
</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}
onClick={() => {
if (pathname !== '/') {
router.replace('/')
}
setSelectType(item._id)
}}
>
<img src={item.icon as string} className="w-[20px] h-[20px] object-cover"></img>
<Image src={item.icon as string} className="w-[20px] h-[20px] object-cover" alt="" width={20} height={20} ></Image>
<span>{item.label}</span>
</div>

View File

@ -25,7 +25,7 @@ import { useState } from "react"
export default function LinkTable(props: { id: string }) {
const [loading, setLoading] = useState(false)
const [loading] = useState(false)
const { data: LinkTypeList } = useRequest(async () => mRequest<{
list: LinkType[]
}>('GET', '/api/linkType'))
@ -83,7 +83,7 @@ export default function LinkTable(props: { id: string }) {
title: "图标",
dataIndex: "logoLink",
render: (_, row) => (
<Image width={80} src={row.logoLink}></Image>
<Image width={80} src={row.logoLink} alt=""></Image>
)
},
{

View File

@ -20,7 +20,7 @@ export default function Page() {
},
{
title: '操作',
render: (_, row) => (
render: () => (
<Space>
<Button type="primary"></Button>
<Button type="primary"></Button>

View File

@ -5,17 +5,18 @@ import ImageUpload from '@/app/_ui/ImageUpload';
import { faArrowLeft, faRibbon } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { BackTop, Button, Card, Col, DatePicker, Form, Grid, Input, InputNumber, message, Row, Select, Space, Upload } from 'antd';
import dynamic from 'next/dynamic';
import { useParams, useRouter } from 'next/navigation'
import { useState } from 'react';
// const MDEditor = dynamic(() => import('@uiw/react-md-editor'), { ssr: false });
import { MdEditor } from 'md-editor-rt';
import 'md-editor-rt/lib/style.css';
import '@ant-design/v5-patch-for-react-19';
import { mRequest } from '@/app/_lib/request';
import dayjs from 'dayjs';
import {Editor} from "@bytemd/react";
import gfm from '@bytemd/plugin-gfm'
const plugins = [
gfm(),
// Add more plugins here
]
export default function AddOrEdit({ editData }: { editData?: ArticleType | null }) {
const router = useRouter()
console.log(editData);
@ -148,7 +149,9 @@ export default function AddOrEdit({ editData }: { editData?: ArticleType | null
}
]}>
{/* <MDEditor className='my-markdown ' /> */}
<MdEditor />
<Editor
plugins={plugins} value={''}
/>
</Form.Item>
<Form.Item className="flex justify-end">

View File

@ -41,7 +41,7 @@ export default function Page() {
dataIndex: "content",
render: (_, item) => (
<>
<Image src={item.content} width={70} ></Image>
<Image src={item.content} width={70} alt="" ></Image>
</>
)
},

View File

@ -1,31 +1,16 @@
"use client";
import { Button, Card, Drawer, Form, Image, Input, InputNumber, message, Modal, Popconfirm, Space, Table } from "antd";
import { useRef, useState } from "react";
import { Button, Card, Drawer, Form, Image, Input, InputNumber, message, Popconfirm, Space, Table } from "antd";
import { useState } from "react";
import { useAntdTable } from "ahooks";
import { mRequest } from "@/app/_lib/request";
import { LinkTypeItem } from "@/app/_lib/types";
import LinkTable from "./LinkTable";
import ImageUpload from "@/app/_ui/ImageUpload";
import { useForm } from "antd/es/form/Form";
import { LinkType } from "@/app/_lib/data/linkType";
import { getLinkTypeList, LinkType } from "@/app/_lib/data/linkType";
import '@ant-design/v5-patch-for-react-19';
export default function Page() {
const { tableProps, refresh } = useAntdTable(
async ({ current, pageSize }) => {
return mRequest<{
total: number;
data: LinkTypeItem[]
}>(
"GET",
`/api/linkType?page=${current}&pageSize=${pageSize}`
).then((res: any) => {
return {
total: res?.total || 0,
list: res?.list || [],
}
})
},
async ({ current, pageSize }) => getLinkTypeList({ page: current, pageSize }),
)
const [selectedType, setSelectedType] = useState<undefined | null | LinkType>(
@ -69,7 +54,7 @@ export default function Page() {
dataIndex: "icon",
render: (_, item) => (
<>
<Image src={item.icon} width={70} ></Image>
<Image src={item.icon} width={70} alt=""></Image>
</>
)
},
@ -187,7 +172,7 @@ export default function Page() {
</Form.Item>
</Form>
</Drawer>
{/* <Drawer
forceRender
title={'添加图标'}

View File

@ -1,7 +1,7 @@
import { SearchWayItemType } from "@/app/_lib/data/search";
import { mRequest } from "@/app/_lib/request";
import { useRequest } from "ahooks";
import { Checkbox, Space } from "antd";
import { Checkbox } from "antd";
import { useMemo } from "react";
export default function SearchSelect({ value, onChange }: { value?: string[]; onChange?: (e: any) => void }) {

View File

@ -1,5 +1,5 @@
"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 { useAntdTable } from "ahooks";
import { Button, Card, Drawer, Form, Input, InputNumber, message, Popconfirm, Space, Table } from "antd";
@ -63,8 +63,12 @@ export default function Page() {
okText="确定"
cancelText="取消"
onConfirm={() => {
mRequest('DELETE', `/api/search/${row._id}`).then(res => {
// mRequest('DELETE', `/api/search/${row._id}`).then(res => {
// refresh()
// })
deleteSearchWay(row._id).then(() => {
refresh()
message.success('删除成功')
})
}}
>
@ -128,7 +132,7 @@ export default function Page() {
okText="确定"
cancelText="取消"
onConfirm={() => {
mRequest('DELETE', `/api/searchType/${row._id}`).then(res => {
mRequest('DELETE', `/api/searchType/${row._id}`).then(() => {
refreshTypeList()
message.success('删除成功')
})
@ -243,6 +247,7 @@ export default function Page() {
await mRequest("POST", "/api/searchType", {
...res,
})
}
refreshTypeList()
setSelectedType(undefined)

View File

@ -19,7 +19,7 @@ export async function DELETE(req: NextRequest, { params }: { params: Promise<{ i
_id: new ObjectId(slug)
})
return Response.json({ message: '删除成功' })
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -15,7 +15,7 @@ export async function POST(request: NextRequest) {
const collection = await getCollection('article');
const data = await collection.insertOne(body);
return Response.json(data)
} catch (e) {
} catch {
return Response.error()
}
}
@ -25,7 +25,7 @@ export async function PUT(request: NextRequest) {
const collection = await getCollection('article');
const data = await collection.updateOne({ _id: body._id }, { $set: body });
return Response.json(data)
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -1,4 +1,4 @@
import { getCollection, getDb } from "@/app/_lib/mongodb";
import { getCollection } from "@/app/_lib/mongodb";
import { ObjectId } from "mongodb";
import { NextRequest } from "next/server";
import { verifySession } from "@/app/_lib/dal";
@ -26,7 +26,7 @@ export async function GET(req: NextRequest) {
total,
list: data,
})
} catch (e) {
} catch {
return Response.error()
}
}
@ -46,7 +46,7 @@ export async function DELETE(req: NextRequest, { params }: { params: Promise<{ i
_id: new ObjectId(slug)
})
return Response.json({ message: '删除成功' })
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -1,9 +1,6 @@
import { verifySession } from "@/app/_lib/dal";
import { Link } from "@/app/_lib/data/link";
import { User } from "@/app/_lib/data/user";
import { getCollection, getDb } from "@/app/_lib/mongodb";
import { message } from "antd";
import bcrypt from 'bcrypt';
import { getCollection } from "@/app/_lib/mongodb";
import { ObjectId } from "mongodb";
import { NextRequest } from "next/server";
@ -29,7 +26,7 @@ export async function GET(req: NextRequest) {
total,
list: data,
})
} catch (e) {
} catch {
return Response.error()
}
}
@ -48,7 +45,7 @@ export async function POST(req: NextRequest) {
const collection = await getCollection('link')
await collection.insertOne(link)
return Response.json({ message: '成功' })
} catch (e) {
} catch {
return Response.error()
}
}
@ -67,7 +64,7 @@ export async function PUT(req: NextRequest) {
const collection = await getCollection('link')
await collection.replaceOne({ _id: new ObjectId(link._id) }, { ...link, _id: new ObjectId(link._id) })
return Response.json({ message: '成功' })
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -1,5 +1,5 @@
import { verifySession } from "@/app/_lib/dal";
import { getCollection, getDb } from "@/app/_lib/mongodb";
import { getCollection} from "@/app/_lib/mongodb";
import { ObjectId } from "mongodb";
import { NextRequest } from "next/server";
import { getLinkList } from "@/app/_lib/data/link";
@ -19,7 +19,7 @@ export async function GET(req: NextRequest) {
const res = await getLinkList({ page, pageSize })
return Response.json(res)
} catch (e) {
} catch {
return Response.error()
}
}
@ -40,7 +40,7 @@ export async function DELETE(req: NextRequest, { params }: { params: Promise<{ i
_id: new ObjectId(slug)
})
return Response.json({ message: '删除成功' })
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -1,6 +1,6 @@
import { verifySession } from "@/app/_lib/dal";
import { getLinkTypeList, LinkType } from "@/app/_lib/data/linkType";
import { getCollection, getDb } from "@/app/_lib/mongodb";
import { getCollection } from "@/app/_lib/mongodb";
import { ObjectId } from "mongodb";
import { NextRequest } from "next/server";
@ -11,7 +11,7 @@ export async function GET(req: NextRequest) {
const pageSize = parseInt(req.nextUrl.searchParams.get('pageSize') || '10') || 10;
const res = await getLinkTypeList({ page, pageSize })
return Response.json(res)
} catch (e) {
} catch {
return Response.error()
}
}
@ -29,7 +29,7 @@ export async function POST(req: NextRequest) {
const collection = await getCollection('link-type')
await collection.insertOne(link)
return Response.json({ message: '成功' })
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -1,9 +1,9 @@
import { getCollection, getDb } from "@/app/_lib/mongodb";
import { getCollection } from "@/app/_lib/mongodb";
import { ObjectId } from "mongodb";
import { NextRequest } from "next/server";
import { verifySession } from "@/app/_lib/dal";
import { getLinkList, Link } from "@/app/_lib/data/link";
import { getLinkList } from "@/app/_lib/data/link";
export async function GET(req: NextRequest) {
try {
@ -13,7 +13,7 @@ export async function GET(req: NextRequest) {
const res = await getLinkList({ page, pageSize, typeId })
return Response.json(res)
} catch (e) {
} catch {
return Response.error()
}
}
@ -34,7 +34,7 @@ export async function DELETE(req: NextRequest, { params }: { params: Promise<{ i
_id: new ObjectId(slug)
})
return Response.json({ message: '删除成功' })
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -1,7 +1,7 @@
import { verifySession } from "@/app/_lib/dal";
import { Link } from "@/app/_lib/data/link";
import { getSearchWayList } from "@/app/_lib/data/search";
import { getCollection, getDb } from "@/app/_lib/mongodb";
import { getCollection } from "@/app/_lib/mongodb";
import { ObjectId } from "mongodb";
import { NextRequest } from "next/server";
@ -14,7 +14,7 @@ export async function GET(req: NextRequest) {
const res = await getSearchWayList({ page, pageSize })
return Response.json(res)
} catch (e) {
} catch {
return Response.error()
}
}
@ -33,7 +33,7 @@ export async function POST(req: NextRequest) {
const collection = await getCollection('search')
await collection.insertOne(link)
return Response.json({ message: '成功' })
} catch (e) {
} catch {
return Response.error()
}
}
@ -56,7 +56,7 @@ export async function PUT(req: NextRequest) {
return Response.json({ message: '成功' })
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -1,4 +1,4 @@
import { getCollection, getDb } from "@/app/_lib/mongodb";
import { getCollection } from "@/app/_lib/mongodb";
import { ObjectId } from "mongodb";
import { NextRequest } from "next/server";
import { verifySession } from "@/app/_lib/dal";
@ -6,7 +6,7 @@ import { verifySession } from "@/app/_lib/dal";
export async function DELETE(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
const session = await verifySession()
// Check if the user is authenticated
if (!session) {
// User is not authenticated
@ -19,7 +19,7 @@ export async function DELETE(req: NextRequest, { params }: { params: Promise<{ i
_id: new ObjectId(slug)
})
return Response.json({ message: '删除成功' })
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -13,7 +13,7 @@ export async function GET(req: NextRequest) {
const res = await getSearchTypeList({ page, pageSize })
return Response.json(res)
} catch (e) {
} catch {
return Response.error()
}
}
@ -31,7 +31,7 @@ export async function POST(req: NextRequest) {
const res = collection.insertOne(item)
return Response.json(res)
} catch (e) {
} catch {
return Response.error()
}
}
@ -50,7 +50,7 @@ export async function PUT(req: NextRequest) {
const item = await req.json() as SearchTypeItem
const res = await collection.replaceOne({ _id: new ObjectId(item._id) }, { ...item, _id: new ObjectId(item._id) })
return Response.json(res)
} catch (e) {
} catch {
return Response.error()
}
}

View File

@ -1,5 +1,5 @@
@import "tailwindcss";
@import 'bytemd/dist/index.css';
:root {
--background: #f9f9f9;
--foreground: #171717;

View File

@ -13,7 +13,7 @@ const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
{
rules: {
"@typescript-eslint/no-explicit-any": "",
"@typescript-eslint/no-explicit-any": "off", // 禁用对显式 any 类型的检查
},
},
];

View File

@ -14,6 +14,17 @@ const nextConfig: NextConfig = {
]
},
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'aihlp.com.cn',
port: '',
pathname: '/**',
search: '',
},
],
},
};
export default nextConfig;

View File

@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"dev": "next dev --turbopack",
"build": "next build",
"pro-build": "node --max-old-space-size=1024 node_modules/next/dist/bin/next build",
"start": "next start",
@ -12,6 +12,8 @@
"dependencies": {
"@ant-design/icons": "^5.5.2",
"@ant-design/nextjs-registry": "^1.0.2",
"@bytemd/plugin-gfm": "^1.22.0",
"@bytemd/react": "^1.22.0",
"@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^0.2.2",
@ -21,9 +23,9 @@
"ali-oss": "^6.22.0",
"antd": "^5.23.2",
"bcrypt": "^5.1.1",
"bytemd": "^1.22.0",
"clsx": "^2.1.1",
"dayjs": "^1.11.13",
"icons": "link:@awesome.me/kit-KIT_CODE/icons",
"jose": "^5.9.6",
"jotai": "^2.11.1",
"md-editor-rt": "^5.2.2",
@ -49,5 +51,11 @@
"postcss": "^8.5.1",
"tailwindcss": "^4.0.4",
"typescript": "^5"
},
"pnpm": {
"onlyBuiltDependencies": [
"bcrypt",
"sharp"
]
}
}

File diff suppressed because it is too large Load Diff