Skip to content

Commit

Permalink
Merge pull request #94 from MarleneJiang/issue-54-新增文章列表
Browse files Browse the repository at this point in the history
Issue 54 新增文章列表
  • Loading branch information
MarleneJiang authored Jan 27, 2023
2 parents 6d92f2c + 0e5c4ba commit b53c6a8
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 127 deletions.
Binary file modified backend/.tmp/data.db
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
},
"x-generation-date": "2023-01-27T04:58:57.064Z"
"x-generation-date": "2023-01-27T08:40:22.000Z"
},
"x-strapi-config": {
"path": "/documentation",
Expand Down
18 changes: 10 additions & 8 deletions frontend/components/Articles/Item.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
<script setup lang="ts">
const props = defineProps({
uname: String,
name: String,
duration: String,
title: String,
desc: String,
summary: String,
tags: {
type: Array,
default: () => [],
default: (): string[] => [],
},
topicHeat: {
type: Array,
default: (): number[] => [0, 0, 0],
},
postID: String,
cover: String,
})
const enteredtopicHeat: (string | number)[] = props.topicHeat.map((item) => {
const value = item as number
Expand All @@ -22,10 +23,10 @@ const enteredtopicHeat: (string | number)[] = props.topicHeat.map((item) => {

<template>
<li class="focus:text-slate-500 flex justify-between items-center py-4 transition-all bg-white hover:bg-gray-50 b-b b-grey all-cursor-pointer">
<NuxtLink class="flex-auto pl-5 truncate" :to="`/${uname}`" style="flex: 1">
<NuxtLink class="flex-auto pl-5 truncate" :to="`/${name}`" style="flex: 1">
<div class="flex items-center all-px-4 pr-4" style="font-size: 13px;">
<span class="border-r-1 pl-0">{{ uname }}</span>
<span class="text-gray-500 border-r-1">{{ duration }}</span>
<span class="border-r-1 pl-0">{{ name }}</span>
<span class="text-gray-500 border-r-1">{{ duration }}</span>
<div class="flex">
<div v-for="(tag, index) in tags" :key="index" class="al-px-0 px-0 text-gray-500 items-center flex">
<span class="px-0 text-gray-500">{{ tag }}</span>
Expand All @@ -38,7 +39,7 @@ const enteredtopicHeat: (string | number)[] = props.topicHeat.map((item) => {
{{ title }}
</div>
<div class="truncate pt-4 text-slate-500" style="font-size: 13px;">
{{ desc }}
{{ summary }}
</div>
</div>
<div class="flex all-flex all-items-center all-text-slate-700" style="font-size: 13px;">
Expand All @@ -58,7 +59,8 @@ const enteredtopicHeat: (string | number)[] = props.topicHeat.map((item) => {
</NuxtLink>
<div class="px-4">
<nuxt-img
src="/og-image.png"
:src="cover"
:alt="summary"
width="120"
height="80"
loading="lazy"
Expand Down
26 changes: 18 additions & 8 deletions frontend/components/Articles/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<script setup lang="ts">
watchEffect(() => {
// TODO: 请求数据
})
const route = useRoute()
let pagenum = 0
const isLoading = useState('isLoading', () => false)
const artlistData = useArtlist(await useFetchPostData())
Expand All @@ -10,13 +8,24 @@ const addArtListItem = () => {
const timer = setTimeout(async () => {
if (useScrollBottom()) {
pagenum++
const newArtlistData = await useFetchPostData()
artlistData.value = newArtlistData
const type = route.path.replace('/', '')
const sort = route.query?.sort as string | undefined
const newArtlistData = await useFetchPostData(type, sort, pagenum)
artlistData.value.push(...newArtlistData)
}
clearTimeout(timer)
}, 1000)
}
}
watchEffect(() => {
const type = route.path.replace('/', '')
const sort = route.query?.sort as string | undefined
isLoading.value = true
useFetchPostData(type, sort).then((data) => {
artlistData.value = data
isLoading.value = false
})
}, { flush: 'post' })
onMounted(() => {
const EmployeeWindow = window as any
EmployeeWindow.addEventListener('scroll', addArtListItem)
Expand All @@ -33,10 +42,11 @@ onUnmounted(() => {
<ArticlesLink />
<UnoSelect />
</div>
<ul v-if="!isLoading && artlistData">
<ul v-if="!isLoading">
<ArticlesItem
v-for="items in artlistData" :key="items.uname" :uname="items.uname" :duration="items.duration"
:title="items.title" :desc="items.desc" :tags="items.tags" :topic-heat="items.topicHeat"
v-for="items in artlistData" :key="items.id" :name="items.name" :duration="items.duration"
:title="items.title" :summary="items.summary" :tags="items.tagIds" :topic-heat="items.topicHeat"
:cover="items.cover"
/>
</ul>
<ArticlesSkeleton v-else />
Expand Down
152 changes: 48 additions & 104 deletions frontend/composables/useFetchPostData.ts
Original file line number Diff line number Diff line change
@@ -1,114 +1,58 @@
import type { IPanel } from '~~/types/IPanel'
const postData: IPanel[] = []
import type { Ref } from 'vue'
import type { IArticleItem, IPanel } from '~~/types/IPanel'
function fixPoint(num: number) {
return num.toFixed(0)
}
function formatTime(createdAt: string) {
const created = new Date(createdAt)
const now = new Date()
const duration = (now.getTime() - created.getTime()) / 1000 / 60
let ans = '刚刚'
// 年月日时分秒
if (duration < 60) // 一小时内
ans = `${fixPoint(duration)}分钟前`
else if (duration < 60 * 24) // 一天内
ans = `${fixPoint(duration / 60)}小时前`
else if (duration < 60 * 24 * 30) // 一个月内
ans = `${fixPoint(duration / 60 / 24)}天前`
else if (duration < 60 * 24 * 30 * 365) // 一年内
ans = `${fixPoint(duration / 60 / 24 / 30)}月前`
else // 超过一年
ans = `${fixPoint(duration / 60 / 24 / 30 / 365)}年前`
return ans
}
function formatArtlist(artlistData: Ref<IArticleItem[]>): IPanel[] {
return artlistData.value.map((item: IArticleItem) => {
const tagIds: string[] = []
item.tagIds.data.forEach((sub) => {
tagIds.push(sub.tag)
})
return {
id: item.id,
title: item.title,
topicHeat: [item.viewed, item.liked, item.commented],
summary: item.summary,
cover: item.cover,
duration: formatTime(item.createdAt),
tagIds,
name: item.authorId.name,
}
})
}
export const useArtlist = (data: IPanel[]) => useState('artlist', () => [...data] as IPanel[])
export const useArtlistPath = (path?: string | undefined) => useState('artlistPath', () => {
if (path === undefined)
return ''
return path
})
// TODO: 请求数据
export default async (/* mode = 'recommend' | 'latest' | 'heat' , pagenum = 1, */): Promise<IPanel[]> => {
export default async (type?: string, sort?: string, pagenum = 1): Promise<IPanel[]> => {
// 接口
// const fetchData = await useFetch()
const value = [
{
uname: 'OrzR3',
duration: '2月',
tags: ['后端', 'Go', '前端'],
title: 'Go 语言中的 Gin 框架',
desc: 'Go 语言中的 gin 框架简易上手指南,初始化安装,加载静态资源和页面,以及表单提交Go 语言中的 gin 框架简易上手指南,初始化安装,加载静态资源和页面,以及表单提交',
topicHeat: [3182, 22, 6],
},
{
uname: 'xj1',
duration: '2月',
tags: ['Vue.js', 'arco design', 'koa'],
title: '帮朋友搭建后台管理系统',
desc: '对,还是那位朋友,一位接近40的澳洲老哥,找我帮忙搞一个管理后台,他刚找到编程',
topicHeat: [15000, 276, 45],
},
{
uname: 'sx1',
duration: '8天',
tags: ['前端', '后端'],
title: '如何打造一个优雅的git工作流',
desc: '在开发中,不论是一个团队一起开发一个项目,还是自己独立开发一个项目。都少不了',
topicHeat: [2022, 26, 6],
},
{
uname: 'OrzR31',
duration: '2月',
tags: ['后端', 'Go', '前端'],
title: 'Go 语言中的 Gin 框架',
desc: 'Go 语言中的 gin 框架简易上手指南,初始化安装,加载静态资源和页面,以及表单提交Go 语言中的 gin 框架简易上手指南,初始化安装,加载静态资源和页面,以及表单提交',
topicHeat: [3182, 22, 6],
},
{
uname: 'xj2',
duration: '2月',
tags: ['Vue.js', 'arco design', 'koa'],
title: '帮朋友搭建后台管理系统',
desc: '对,还是那位朋友,一位接近40的澳洲老哥,找我帮忙搞一个管理后台,他刚找到编程',
topicHeat: [15000, 276, 45],
},
{
uname: 'sx2',
duration: '8天',
tags: ['前端', '后端'],
title: '如何打造一个优雅的git工作流',
desc: '在开发中,不论是一个团队一起开发一个项目,还是自己独立开发一个项目。都少不了',
topicHeat: [2022, 26, 6],
},
{
uname: 'OrzR32',
duration: '2月',
tags: ['后端', 'Go', '前端'],
title: 'Go 语言中的 Gin 框架',
desc: 'Go 语言中的 gin 框架简易上手指南,初始化安装,加载静态资源和页面,以及表单提交Go 语言中的 gin 框架简易上手指南,初始化安装,加载静态资源和页面,以及表单提交',
topicHeat: [3182, 22, 6],
},
{
uname: 'xj',
duration: '2月',
tags: ['Vue.js', 'arco design', 'koa'],
title: '帮朋友搭建后台管理系统',
desc: '对,还是那位朋友,一位接近40的澳洲老哥,找我帮忙搞一个管理后台,他刚找到编程',
topicHeat: [15000, 276, 45],
},
{
uname: 'sx',
duration: '8天',
tags: ['前端', '后端'],
title: '如何打造一个优雅的git工作流',
desc: '在开发中,不论是一个团队一起开发一个项目,还是自己独立开发一个项目。都少不了',
topicHeat: [2022, 26, 6],
},
{
uname: 'OrzR3',
duration: '2月',
tags: ['后端', 'Go', '前端'],
title: 'Go 语言中的 Gin 框架',
desc: 'Go 语言中的 gin 框架简易上手指南,初始化安装,加载静态资源和页面,以及表单提交Go 语言中的 gin 框架简易上手指南,初始化安装,加载静态资源和页面,以及表单提交',
topicHeat: [3182, 22, 6],
},
{
uname: 'xj',
duration: '2月',
tags: ['Vue.js', 'arco design', 'koa'],
title: '帮朋友搭建后台管理系统',
desc: '对,还是那位朋友,一位接近40的澳洲老哥,找我帮忙搞一个管理后台,他刚找到编程',
topicHeat: [15000, 276, 45],
},
{
uname: 'sx',
duration: '8天',
tags: ['前端', '后端'],
title: '如何打造一个优雅的git工作流',
desc: '在开发中,不论是一个团队一起开发一个项目,还是自己独立开发一个项目。都少不了',
topicHeat: [2022, 26, 6],
},
]
if (type === undefined)
type = ''
if (sort === undefined)
sort = 'recommended'
const { data } = await useFetch(`/api/articles/list?sort=${sort}&type=${type}&pageNum=${pagenum}`)
// 数据内容
postData.push(...value)
return postData
return formatArtlist(data)
}
33 changes: 27 additions & 6 deletions frontend/types/IPanel.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
interface IAuthor {
name: string
}

interface ITagItem {
tag: string
}

interface IArticleItem {
id: string
title: string
viewed: number
liked: number
commented: number
summary: string
cover: string
createdAt: string
authorId: IAuthor
tagIds: { data: ITagItem[] }
}
interface IPanel {
uname: string
duration: string
tags?: string[]
id: string
title: string
desc: string
topicHeat: number[]
imgUrl?: string
summary: string
cover: string
duration: string
tagIds: string[]
name: string
}

export {
IArticleItem,
IPanel,
}

1 comment on commit b53c6a8

@vercel
Copy link

@vercel vercel bot commented on b53c6a8 Jan 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.