mirror of
https://github.com/LiuYuYang01/ThriveX-Blog.git
synced 2026-06-04 03:39:28 +08:00
完成文章归纳基本布局
This commit is contained in:
146
src/app/data/page.tsx
Normal file
146
src/app/data/page.tsx
Normal file
@@ -0,0 +1,146 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import { getArticleListAPI } from '@/api/article'
|
||||
import { Article } from "@/types/app/article"
|
||||
import Swiper from "@/components/Swiper";
|
||||
import Starry from "@/components/Starry";
|
||||
import { Accordion, AccordionItem } from "@nextui-org/react";
|
||||
import archiving from '@/assets/svg/other/archiving.svg'
|
||||
|
||||
interface MonthData {
|
||||
total: number;
|
||||
list: Article[];
|
||||
wordCount: number;
|
||||
}
|
||||
|
||||
interface YearData {
|
||||
year: number;
|
||||
total: number;
|
||||
month: Record<number, MonthData>;
|
||||
wordCount: number;
|
||||
}
|
||||
|
||||
const Title = ({ data }: { data: YearData }) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="text-xl font-sans inline-block textMarkSty">{data.year} 年</div>
|
||||
<div>总共发布了:{data.total} 篇文章</div>
|
||||
<div>总字数约:{(data.wordCount / 1000).toFixed(2)}K</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const [list, setList] = useState<YearData[]>([])
|
||||
const getArticleList = async () => {
|
||||
const { data } = await getArticleListAPI()
|
||||
const result = groupByYearAndMonth(data);
|
||||
// 从早到晚排序
|
||||
result.sort((a, b) => b.year - a.year)
|
||||
setList(result)
|
||||
}
|
||||
|
||||
// 将文章进行分组
|
||||
function groupByYearAndMonth(data: Article[]): YearData[] {
|
||||
const groupedData: Record<number, YearData> = {};
|
||||
|
||||
data.forEach(item => {
|
||||
const date = new Date(+item.createTime!);
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth() + 1;
|
||||
const wordCount = item.content ? item.content.length : 0;
|
||||
|
||||
if (!groupedData[year]) {
|
||||
groupedData[year] = { year, total: 0, month: {}, wordCount: 0 };
|
||||
}
|
||||
|
||||
if (!groupedData[year].month[month]) {
|
||||
groupedData[year].month[month] = { total: 0, list: [], wordCount: 0 };
|
||||
}
|
||||
|
||||
groupedData[year].month[month].list.push(item);
|
||||
groupedData[year].month[month].total++;
|
||||
groupedData[year].total++;
|
||||
groupedData[year].wordCount += wordCount;
|
||||
});
|
||||
|
||||
return Object.values(groupedData);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getArticleList()
|
||||
}, [])
|
||||
|
||||
const defaultContent =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.";
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<title>数据统计</title>
|
||||
<meta name="description" content="数据统计" />
|
||||
|
||||
<Swiper isRipple={false}>
|
||||
{/* 星空背景组件 */}
|
||||
<Starry />
|
||||
|
||||
<div className="absolute top-[45%] left-[50%] transform -translate-x-1/2 flex flex-col items-center">
|
||||
<div className="text-white text-[20px] xs:text-[25px] sm:text-[30px] whitespace-nowrap custom_text_shadow">数据统计</div>
|
||||
</div>
|
||||
</Swiper>
|
||||
|
||||
<div className="w-[1200px] mt-10 mx-auto bg-white p-10 rounded-xl border">
|
||||
<h3 className="flex items-center text-2xl mb-3"><img src={archiving.src} alt="归档" className="w-9 mr-3"/> 文章归纳</h3>
|
||||
|
||||
<Accordion
|
||||
className="[&>hr]:bg-[#eee] !px-0"
|
||||
motionProps={{
|
||||
variants: {
|
||||
enter: {
|
||||
y: 0,
|
||||
opacity: 1,
|
||||
height: "auto",
|
||||
transition: {
|
||||
height: {
|
||||
type: "spring",
|
||||
stiffness: 500,
|
||||
damping: 30,
|
||||
duration: 1,
|
||||
},
|
||||
opacity: {
|
||||
easings: "ease",
|
||||
duration: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
exit: {
|
||||
y: -10,
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
transition: {
|
||||
height: {
|
||||
easings: "ease",
|
||||
duration: 0.25,
|
||||
},
|
||||
opacity: {
|
||||
easings: "ease",
|
||||
duration: 0.3,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{
|
||||
list.map((item, index) => (
|
||||
<AccordionItem key={index} aria-label={item.year + '年'} title={<Title data={item} />}>
|
||||
{defaultContent}
|
||||
</AccordionItem>
|
||||
))
|
||||
}
|
||||
</Accordion>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
1
src/assets/svg/other/archiving.svg
Normal file
1
src/assets/svg/other/archiving.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1729842746325" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7408" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M270.4 104.8c-33.4 0-60.4 27-60.4 60.4v30.2c0 16.7 13.5 30.2 30.2 30.2h543.5c16.7 0 30.2-13.5 30.2-30.2v-30.2c0-33.4-27-60.4-60.4-60.4H270.4z m-60.3 150.9c-33.4 0-60.4 27-60.4 60.4v30.2c0 8 3.2 15.7 8.8 21.4 5.7 5.7 13.3 8.8 21.4 8.8h664.3c8 0 15.7-3.2 21.3-8.8 5.7-5.7 8.8-13.3 8.8-21.4v-30.2c0-33.4-27-60.4-60.4-60.4H210.1z m0 0" fill="#FFAA44" p-id="7409"></path><path d="M512 527.5c55.2 0 103.4-37.4 117.1-90.9 4.1-16.2 17.2-29.9 33.9-29.9h211.4c33.3 0 60.4 27 60.4 60.4V769c0 32-12.7 62.8-35.4 85.4-22.7 22.7-53.4 35.4-85.4 35.4H210.1c-32 0-62.8-12.7-85.4-35.4-22.7-22.6-35.4-53.3-35.4-85.4V467.1c0-33.3 27-60.4 60.4-60.4H361c16.7 0 29.8 13.7 33.9 29.9 13.7 53.5 61.9 90.9 117.1 90.9z m0 0" fill="#FF7744" p-id="7410"></path><path d="M345.9 708.7c0-12 4.8-23.5 13.3-32s20-13.3 32-13.3h241.6c25 0 45.3 20.3 45.3 45.3S657.8 754 632.8 754H391.2c-25-0.1-45.3-20.3-45.3-45.3z m0 0" fill="#FFFFFF" p-id="7411"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -33,6 +33,21 @@ body {
|
||||
animation: 5s linear infinite miniShape;
|
||||
}
|
||||
|
||||
// 文本标记样式
|
||||
.textMarkSty {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 50%;
|
||||
height: 10px;
|
||||
background-color: #539dfd80;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes miniShape {
|
||||
|
||||
0%,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// const url = "http://localhost:9003/api"
|
||||
const url = "https://api.liuyuyang.net/api"
|
||||
const url = "http://localhost:9003/api"
|
||||
// const url = "https://api.liuyuyang.net/api"
|
||||
|
||||
export default async <T>(method: string, api: string, data?: any, caching = true) => {
|
||||
const res = await fetch(`${url}${api}`, {
|
||||
@@ -16,4 +16,43 @@ export default async <T>(method: string, api: string, data?: any, caching = true
|
||||
})
|
||||
|
||||
return res.json() as Promise<ResponseData<T>>;
|
||||
}
|
||||
}
|
||||
|
||||
// [
|
||||
// {
|
||||
// year: 2024,
|
||||
// total: 3, // 结果是每个月份的total
|
||||
// month: [
|
||||
// {
|
||||
// 1: {
|
||||
// total: 2, // 文章的数量
|
||||
// list: [文章数据1, 文章数据2]
|
||||
// },
|
||||
// 2: {
|
||||
// total: 1,
|
||||
// list: [文章数据1]
|
||||
// },
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// year: 2023,
|
||||
// total: 2, // 结果是每个月份的total
|
||||
// month: [
|
||||
// {
|
||||
// 1: {
|
||||
// total: 1, // 文章的数量
|
||||
// list: [文章数据1]
|
||||
// },
|
||||
// 2: {
|
||||
// total: 0,
|
||||
// list: []
|
||||
// },
|
||||
// 3: {
|
||||
// total: 1,
|
||||
// list: [文章数据1]
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
Reference in New Issue
Block a user