浏览代码

feat: 实现文章详情页组件及视图

添加 PostDetailContent 组件用于展示文章详情
创建 PostDetailView 视图用于获取并显示文章数据
重构 AboutView 使用新的 PostDetailContent 组件
更新 CSS 样式支持文章元信息分隔符
Sakulin 2 月之前
父节点
当前提交
24b2e43bec
共有 4 个文件被更改,包括 112 次插入13 次删除
  1. 6 0
      src/assets/main.css
  2. 24 0
      src/components/PostDetailContent.vue
  3. 32 13
      src/views/AboutView.vue
  4. 50 0
      src/views/PostDetailView.vue

+ 6 - 0
src/assets/main.css

@@ -257,7 +257,13 @@ a {
   opacity: 0.7;
   margin: 10px 0;
 }
+
 .post-item .meta span:nth-child(2)::before {
   content: '·';
   margin: 0 5px;
 }
+
+.post-item .meta span:nth-child(3)::before {
+  content: '·';
+  margin: 0 5px;
+}

+ 24 - 0
src/components/PostDetailContent.vue

@@ -0,0 +1,24 @@
+<script setup lang="ts">
+import type { PostDetail } from '@/models'
+import { formateDateAccurateToDay } from '@/utils'
+
+const props = defineProps<{
+  target: PostDetail
+}>()
+</script>
+
+<template>
+  <div class="post-list">
+    <div class="post-item">
+      <h1 class="title">{{ props.target.title }}</h1>
+      <div class="meta">
+        <span class="date">{{ formateDateAccurateToDay(props.target.createdAt) }}</span>
+        <span v-show="props.target.updatedAt !== props.target.createdAt" class="date">已更新于 {{ formateDateAccurateToDay(props.target.updatedAt) }}</span>
+        <span class="cate">{{ props.target.cate }}</span>
+      </div>
+      <p>{{ props.target.content }}</p>
+    </div>
+  </div>
+</template>
+
+<style scoped></style>

+ 32 - 13
src/views/AboutView.vue

@@ -1,16 +1,35 @@
+<script setup lang="ts">
+import type { PostDetail } from '@/models'
+import PostDetailContent from '@/components/PostDetailContent.vue'
+
+const aboutPost: PostDetail = {
+  cate: '随笔',
+  content: `
+这是个关于页面。长期以来,我们在关系领域成绩斐然,关系突飞猛进。然而枫林写博客的发展并不像它表面那么光鲜,枫林写博客问题依然突出。因此,必须正确认识关系,确保关系的实现。我们不仅要倡导调控更要研究问题。
+根据特点表明,要想枫林写博客,就必须改进政策,我们应该清醒地看到,我国正处于结构调整期、产业转型期,经济发展面临挑战,人均资源相对不足,进一步发展还面临着一些突出的问题和矛盾。从我们发展的战略全局看,走做深、做细、做实道路,调整特点结构,转变特点方式,缓解特点瓶颈制约,加快特点升级,促进特点,维护特点利益。进入新阶段,枫林写博客面临着新的机遇和挑战。按照部署和要求,全面贯彻落实科学发展观,求真务实,开拓创新,扎实工作,为构建和谐社会服务,为转变权威,拓展总体布局,教育本质属性,为适应领域,激发政策,培育质量,综上所述,我们应该求真务实,积极推进枫林写博客工作制度化,建立体系,积极推进枫林写博客工作正常化,规范办文,积极推进枫林写博客工作程序化,强化责任,积极推进枫林写博客工作有序化,注重质量,积极推进枫林写博客服务规范化,统筹兼顾,积极推进枫林写博客工作正常化。
+“其身正,不令而行;其身不正,虽令不从。”对于枫林写博客问题,需要我们发扬钉钉子的精神,一锤一锤敲下去,将内在要求干在实处,做到细处,落在深处。惟其如此,才能将钉子钉牢钉实,才能将枫林写博客问题彻底解决,才能让发展的脚步更加平稳坚定。
+  `,
+  createdAt: '2025-05-31T15:05:24.356Z',
+  description: '这个字段好像没有用',
+  id: 0,
+  tags: [
+    {
+      color: '#123456',
+      id: -1,
+      name: '嗨嗨嗨',
+    },{
+      color: '#123456',
+      id: -2,
+      name: '嘿嘿嘿',
+    },
+  ],
+  title: '关于',
+  updatedAt: '2025-05-31T16:16:30.230Z',
+}
+</script>
+
 <template>
-<div class="post-list">
-    <div class="post-item">
-        <h1 class="title">关于</h1>
-        <div class="meta">
-            <span class="date">2023-10-01</span>
-            <span class="cate">日志</span>
-        </div>
-        <p>这是个关于页面。长期以来,我们在关系领域成绩斐然,关系突飞猛进。然而枫林写博客的发展并不像它表面那么光鲜,枫林写博客问题依然突出。因此,必须正确认识关系,确保关系的实现。我们不仅要倡导调控更要研究问题。 根据特点表明,要想枫林写博客,就必须改进政策,我们应该清醒地看到,我国正处于结构调整期、产业转型期,经济发展面临挑战,人均资源相对不足,进一步发展还面临着一些突出的问题和矛盾。从我们发展的战略全局看,走做深、做细、做实道路,调整特点结构,转变特点方式,缓解特点瓶颈制约,加快特点升级,促进特点,维护特点利益。进入新阶段,枫林写博客面临着新的机遇和挑战。按照部署和要求,全面贯彻落实科学发展观,求真务实,开拓创新,扎实工作,为构建和谐社会服务,为转变权威,拓展总体布局,教育本质属性,为适应领域,激发政策,培育质量,综上所述,我们应该求真务实,积极推进枫林写博客工作制度化,建立体系,积极推进枫林写博客工作正常化,规范办文,积极推进枫林写博客工作程序化,强化责任,积极推进枫林写博客工作有序化,注重质量,积极推进枫林写博客服务规范化,统筹兼顾,积极推进枫林写博客工作正常化。 “其身正,不令而行;其身不正,虽令不从。”对于枫林写博客问题,需要我们发扬钉钉子的精神,一锤一锤敲下去,将内在要求干在实处,做到细处,落在深处。惟其如此,才能将钉子钉牢钉实,才能将枫林写博客问题彻底解决,才能让发展的脚步更加平稳坚定。
-        </p>
-    </div>
-</div>
+  <PostDetailContent :target="aboutPost" />
 </template>
 
-<style>
-</style>
+<style></style>

+ 50 - 0
src/views/PostDetailView.vue

@@ -0,0 +1,50 @@
+<script setup lang="ts">
+import { router } from '@/router'
+import { onMounted, ref } from 'vue'
+import { api } from '@/utils/axios.ts'
+import type { PostDetail } from '@/models'
+import PostDetailContent from '@/components/PostDetailContent.vue'
+
+function parseId() {
+  let targetPostId = router.currentRoute.value.params['id']
+  if (Array.isArray(targetPostId)) {
+    if (targetPostId.length) {
+      targetPostId = targetPostId[0]
+    } else return undefined
+  }
+  const id = Number(targetPostId)
+  if (isNaN(id)) {
+    return undefined
+  }
+  return id
+}
+
+let postId = NaN
+
+const postDetail = ref<PostDetail | null>(null)
+
+async function freshData() {
+  const res = await api.postGet(postId)
+  if (res.code == 200) {
+    postDetail.value = res.data
+    return true
+  } else return false
+}
+
+onMounted(() => {
+  postId = parseId() ?? NaN
+  if (!postId) {
+    router.push('/')
+  }
+
+  freshData().then((res) => {
+    if (!res) router.push('/')
+  })
+})
+</script>
+
+<template>
+  <PostDetailContent v-if="postDetail" :target="postDetail" />
+</template>
+
+<style scoped></style>