mirror of https://github.com/halo-dev/halo
refactor: convert post publish dates to human-readable format (#7526)
#### What type of PR is this? /area ui /kind improvement /milestone 2.21.x #### What this PR does / why we need it: <img width="1202" alt="image" src="https://github.com/user-attachments/assets/cac050d2-b984-4b48-afe0-e18db220ec19" /> #### Does this PR introduce a user-facing change? ```release-note 将 Console 端文章列表的发布时间改为语义化时间 ```pull/7527/head
parent
224d78079d
commit
3fa6532d9b
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import PostContributorList from "@/components/user/PostContributorList.vue";
|
import PostContributorList from "@/components/user/PostContributorList.vue";
|
||||||
import { formatDatetime } from "@/utils/date";
|
import { formatDatetime, relativeTimeTo } from "@/utils/date";
|
||||||
import { usePermission } from "@/utils/permission";
|
import { usePermission } from "@/utils/permission";
|
||||||
import type { ListedSinglePage, SinglePage } from "@halo-dev/api-client";
|
import type { ListedSinglePage, SinglePage } from "@halo-dev/api-client";
|
||||||
import { consoleApiClient, coreApiClient } from "@halo-dev/api-client";
|
import { consoleApiClient, coreApiClient } from "@halo-dev/api-client";
|
||||||
|
@ -356,12 +356,11 @@ watch(
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</VEntityField>
|
</VEntityField>
|
||||||
<VEntityField>
|
<VEntityField
|
||||||
<template #description>
|
v-if="singlePage.page.spec.publishTime"
|
||||||
<span class="truncate text-xs tabular-nums text-gray-500">
|
v-tooltip="formatDatetime(singlePage.page.spec.publishTime)"
|
||||||
{{ formatDatetime(singlePage.page.spec.publishTime) }}
|
:description="relativeTimeTo(singlePage.page.spec.publishTime)"
|
||||||
</span>
|
>
|
||||||
</template>
|
|
||||||
</VEntityField>
|
</VEntityField>
|
||||||
</template>
|
</template>
|
||||||
<template
|
<template
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import PostContributorList from "@/components/user/PostContributorList.vue";
|
import PostContributorList from "@/components/user/PostContributorList.vue";
|
||||||
import { singlePageLabels } from "@/constants/labels";
|
import { singlePageLabels } from "@/constants/labels";
|
||||||
import { formatDatetime } from "@/utils/date";
|
import { formatDatetime, relativeTimeTo } from "@/utils/date";
|
||||||
import { usePermission } from "@/utils/permission";
|
import { usePermission } from "@/utils/permission";
|
||||||
import type { ListedSinglePage, SinglePage } from "@halo-dev/api-client";
|
import type { ListedSinglePage, SinglePage } from "@halo-dev/api-client";
|
||||||
import { coreApiClient } from "@halo-dev/api-client";
|
import { coreApiClient } from "@halo-dev/api-client";
|
||||||
|
@ -224,12 +224,11 @@ const handleDelete = async () => {
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</VEntityField>
|
</VEntityField>
|
||||||
<VEntityField>
|
<VEntityField
|
||||||
<template #description>
|
v-if="singlePage.page.spec.publishTime"
|
||||||
<span class="truncate text-xs tabular-nums text-gray-500">
|
v-tooltip="formatDatetime(singlePage.page.spec.publishTime)"
|
||||||
{{ formatDatetime(singlePage.page.spec.publishTime) }}
|
:description="relativeTimeTo(singlePage.page.spec.publishTime)"
|
||||||
</span>
|
>
|
||||||
</template>
|
|
||||||
</VEntityField>
|
</VEntityField>
|
||||||
</template>
|
</template>
|
||||||
<template
|
<template
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import PostContributorList from "@/components/user/PostContributorList.vue";
|
import PostContributorList from "@/components/user/PostContributorList.vue";
|
||||||
import { formatDatetime } from "@/utils/date";
|
import { formatDatetime, relativeTimeTo } from "@/utils/date";
|
||||||
import { usePermission } from "@/utils/permission";
|
import { usePermission } from "@/utils/permission";
|
||||||
import type { ListedPost, Post } from "@halo-dev/api-client";
|
import type { ListedPost, Post } from "@halo-dev/api-client";
|
||||||
import { consoleApiClient, coreApiClient } from "@halo-dev/api-client";
|
import { consoleApiClient, coreApiClient } from "@halo-dev/api-client";
|
||||||
|
@ -390,12 +390,11 @@ watch(
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</VEntityField>
|
</VEntityField>
|
||||||
<VEntityField>
|
<VEntityField
|
||||||
<template #description>
|
v-if="post.post.spec.publishTime"
|
||||||
<span class="truncate text-xs tabular-nums text-gray-500">
|
v-tooltip="formatDatetime(post.post.spec.publishTime)"
|
||||||
{{ formatDatetime(post.post.spec.publishTime) }}
|
:description="relativeTimeTo(post.post.spec.publishTime)"
|
||||||
</span>
|
>
|
||||||
</template>
|
|
||||||
</VEntityField>
|
</VEntityField>
|
||||||
</template>
|
</template>
|
||||||
<template
|
<template
|
||||||
|
|
|
@ -205,6 +205,7 @@ const { startFields, endFields } = useEntityFieldItemExtensionPoint<ListedPost>(
|
||||||
priority: 50,
|
priority: 50,
|
||||||
position: "end",
|
position: "end",
|
||||||
component: markRaw(PublishTimeField),
|
component: markRaw(PublishTimeField),
|
||||||
|
hidden: !props.post.post.spec.publishTime,
|
||||||
props: {
|
props: {
|
||||||
post: props.post,
|
post: props.post,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { postLabels } from "@/constants/labels";
|
import { postLabels } from "@/constants/labels";
|
||||||
import { formatDatetime } from "@/utils/date";
|
import { formatDatetime, relativeTimeTo } from "@/utils/date";
|
||||||
import type { ListedPost } from "@halo-dev/api-client";
|
import type { ListedPost } from "@halo-dev/api-client";
|
||||||
import { IconTimerLine, VEntityField } from "@halo-dev/components";
|
import { IconTimerLine, VEntityField } from "@halo-dev/components";
|
||||||
|
|
||||||
|
@ -16,8 +16,11 @@ withDefaults(
|
||||||
<VEntityField>
|
<VEntityField>
|
||||||
<template #description>
|
<template #description>
|
||||||
<div class="inline-flex items-center space-x-2">
|
<div class="inline-flex items-center space-x-2">
|
||||||
<span class="entity-field-description">
|
<span
|
||||||
{{ formatDatetime(post.post.spec.publishTime) }}
|
v-tooltip="formatDatetime(post.post.spec.publishTime)"
|
||||||
|
class="entity-field-description"
|
||||||
|
>
|
||||||
|
{{ relativeTimeTo(post.post.spec.publishTime) }}
|
||||||
</span>
|
</span>
|
||||||
<IconTimerLine
|
<IconTimerLine
|
||||||
v-if="
|
v-if="
|
||||||
|
|
|
@ -1,28 +1,18 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { postLabels } from "@/constants/labels";
|
import { postLabels } from "@/constants/labels";
|
||||||
import { formatDatetime } from "@/utils/date";
|
|
||||||
import WidgetCard from "@console/modules/dashboard/components/WidgetCard.vue";
|
import WidgetCard from "@console/modules/dashboard/components/WidgetCard.vue";
|
||||||
import type { ListedPost } from "@halo-dev/api-client";
|
import type { ListedPost } from "@halo-dev/api-client";
|
||||||
import { consoleApiClient } from "@halo-dev/api-client";
|
import { consoleApiClient } from "@halo-dev/api-client";
|
||||||
import {
|
import { VEntityContainer } from "@halo-dev/components";
|
||||||
IconExternalLinkLine,
|
|
||||||
VEntity,
|
|
||||||
VEntityContainer,
|
|
||||||
VEntityField,
|
|
||||||
VSpace,
|
|
||||||
} from "@halo-dev/components";
|
|
||||||
import { useQuery } from "@tanstack/vue-query";
|
import { useQuery } from "@tanstack/vue-query";
|
||||||
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
|
import { OverlayScrollbarsComponent } from "overlayscrollbars-vue";
|
||||||
|
import PostListItem from "./components/PostListItem.vue";
|
||||||
|
|
||||||
const { data } = useQuery<ListedPost[]>({
|
const { data } = useQuery<ListedPost[]>({
|
||||||
queryKey: ["widget-recent-posts"],
|
queryKey: ["widget-recent-posts"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await consoleApiClient.content.post.listPosts({
|
const { data } = await consoleApiClient.content.post.listPosts({
|
||||||
labelSelector: [
|
labelSelector: [`${postLabels.DELETED}=false`],
|
||||||
`${postLabels.DELETED}=false`,
|
|
||||||
`${postLabels.PUBLISHED}=true`,
|
|
||||||
],
|
|
||||||
sort: ["spec.publishTime,desc"],
|
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 10,
|
size: 10,
|
||||||
});
|
});
|
||||||
|
@ -42,61 +32,11 @@ const { data } = useQuery<ListedPost[]>({
|
||||||
defer
|
defer
|
||||||
>
|
>
|
||||||
<VEntityContainer>
|
<VEntityContainer>
|
||||||
<VEntity v-for="post in data" :key="post.post.metadata.name">
|
<PostListItem
|
||||||
<template #start>
|
v-for="post in data"
|
||||||
<VEntityField
|
:key="post.post.metadata.name"
|
||||||
:title="post.post.spec.title"
|
:post="post"
|
||||||
:route="{
|
/>
|
||||||
name: 'PostEditor',
|
|
||||||
query: { name: post.post.metadata.name },
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<template #description>
|
|
||||||
<VSpace>
|
|
||||||
<span class="text-xs text-gray-500">
|
|
||||||
{{
|
|
||||||
$t(
|
|
||||||
"core.dashboard.widgets.presets.recent_published.visits",
|
|
||||||
{ visits: post.stats.visit || 0 }
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</span>
|
|
||||||
<span class="text-xs text-gray-500">
|
|
||||||
{{
|
|
||||||
$t(
|
|
||||||
"core.dashboard.widgets.presets.recent_published.comments",
|
|
||||||
{ comments: post.stats.totalComment || 0 }
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</span>
|
|
||||||
<span class="truncate text-xs tabular-nums text-gray-500">
|
|
||||||
{{
|
|
||||||
$t(
|
|
||||||
"core.dashboard.widgets.presets.recent_published.publishTime",
|
|
||||||
{
|
|
||||||
publishTime: formatDatetime(
|
|
||||||
post.post.spec.publishTime
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</span>
|
|
||||||
</VSpace>
|
|
||||||
</template>
|
|
||||||
<template #extra>
|
|
||||||
<a
|
|
||||||
v-if="post.post.status?.permalink"
|
|
||||||
target="_blank"
|
|
||||||
:href="post.post.status?.permalink"
|
|
||||||
:title="post.post.status?.permalink"
|
|
||||||
class="hidden text-gray-600 transition-all hover:text-gray-900 group-hover:inline-block"
|
|
||||||
>
|
|
||||||
<IconExternalLinkLine class="h-3.5 w-3.5" />
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
</template>
|
|
||||||
</VEntity>
|
|
||||||
</VEntityContainer>
|
</VEntityContainer>
|
||||||
</OverlayScrollbarsComponent>
|
</OverlayScrollbarsComponent>
|
||||||
</WidgetCard>
|
</WidgetCard>
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { postLabels } from "@/constants/labels";
|
||||||
|
import { formatDatetime, relativeTimeTo } from "@/utils/date";
|
||||||
|
import type { ListedPost } from "@halo-dev/api-client";
|
||||||
|
import {
|
||||||
|
IconExternalLinkLine,
|
||||||
|
VEntity,
|
||||||
|
VEntityField,
|
||||||
|
VSpace,
|
||||||
|
VTag,
|
||||||
|
} from "@halo-dev/components";
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
post: ListedPost;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const isPublished = computed(() => {
|
||||||
|
return props.post.post.metadata.labels?.[postLabels.PUBLISHED] === "true";
|
||||||
|
});
|
||||||
|
|
||||||
|
const previewUrl = computed(() => {
|
||||||
|
const { status, metadata } = props.post.post;
|
||||||
|
if (isPublished.value) {
|
||||||
|
return status?.permalink;
|
||||||
|
}
|
||||||
|
return `/preview/posts/${metadata.name}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const datetime = computed(() => {
|
||||||
|
return (
|
||||||
|
props.post.post.spec.publishTime ||
|
||||||
|
props.post.post.metadata.creationTimestamp
|
||||||
|
);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VEntity>
|
||||||
|
<template #start>
|
||||||
|
<VEntityField
|
||||||
|
:title="post.post.spec.title"
|
||||||
|
:route="{
|
||||||
|
name: 'PostEditor',
|
||||||
|
query: { name: post.post.metadata.name },
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template v-if="isPublished" #description>
|
||||||
|
<VSpace>
|
||||||
|
<span class="text-xs text-gray-500">
|
||||||
|
{{
|
||||||
|
$t("core.dashboard.widgets.presets.recent_published.visits", {
|
||||||
|
visits: post.stats.visit || 0,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<span class="text-xs text-gray-500">
|
||||||
|
{{
|
||||||
|
$t("core.dashboard.widgets.presets.recent_published.comments", {
|
||||||
|
comments: post.stats.totalComment || 0,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</VSpace>
|
||||||
|
</template>
|
||||||
|
<template #extra>
|
||||||
|
<VSpace>
|
||||||
|
<VTag v-if="!isPublished">
|
||||||
|
{{ $t("core.post.filters.status.items.draft") }}
|
||||||
|
</VTag>
|
||||||
|
<a
|
||||||
|
v-if="previewUrl"
|
||||||
|
target="_blank"
|
||||||
|
:href="previewUrl"
|
||||||
|
:title="previewUrl"
|
||||||
|
class="hidden text-gray-600 transition-all hover:text-gray-900 group-hover:inline-block"
|
||||||
|
>
|
||||||
|
<IconExternalLinkLine class="h-3.5 w-3.5" />
|
||||||
|
</a>
|
||||||
|
</VSpace>
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
|
</template>
|
||||||
|
<template #end>
|
||||||
|
<VEntityField
|
||||||
|
v-tooltip="formatDatetime(datetime)"
|
||||||
|
:description="relativeTimeTo(datetime)"
|
||||||
|
></VEntityField>
|
||||||
|
</template>
|
||||||
|
</VEntity>
|
||||||
|
</template>
|
|
@ -66,7 +66,6 @@ core:
|
||||||
title: Recent Posts
|
title: Recent Posts
|
||||||
visits: "{visits} Visits"
|
visits: "{visits} Visits"
|
||||||
comments: "{comments} Comments"
|
comments: "{comments} Comments"
|
||||||
publishTime: Publish Time {publishTime}
|
|
||||||
notification:
|
notification:
|
||||||
title: Notifications
|
title: Notifications
|
||||||
empty:
|
empty:
|
||||||
|
|
|
@ -64,7 +64,6 @@ core:
|
||||||
title: 最近文章
|
title: 最近文章
|
||||||
visits: 访问量 {visits}
|
visits: 访问量 {visits}
|
||||||
comments: 评论 {comments}
|
comments: 评论 {comments}
|
||||||
publishTime: 发布日期 {publishTime}
|
|
||||||
notification:
|
notification:
|
||||||
title: 通知
|
title: 通知
|
||||||
empty:
|
empty:
|
||||||
|
|
|
@ -64,7 +64,6 @@ core:
|
||||||
title: 最近文章
|
title: 最近文章
|
||||||
visits: 訪問量 {visits}
|
visits: 訪問量 {visits}
|
||||||
comments: 留言 {comments}
|
comments: 留言 {comments}
|
||||||
publishTime: 發佈日期 {publishTime}
|
|
||||||
notification:
|
notification:
|
||||||
title: 通知
|
title: 通知
|
||||||
empty:
|
empty:
|
||||||
|
|
|
@ -3,7 +3,7 @@ import StatusDotField from "@/components/entity-fields/StatusDotField.vue";
|
||||||
import HasPermission from "@/components/permission/HasPermission.vue";
|
import HasPermission from "@/components/permission/HasPermission.vue";
|
||||||
import PostContributorList from "@/components/user/PostContributorList.vue";
|
import PostContributorList from "@/components/user/PostContributorList.vue";
|
||||||
import { postLabels } from "@/constants/labels";
|
import { postLabels } from "@/constants/labels";
|
||||||
import { formatDatetime } from "@/utils/date";
|
import { formatDatetime, relativeTimeTo } from "@/utils/date";
|
||||||
import PostTag from "@console/modules/contents/posts/tags/components/PostTag.vue";
|
import PostTag from "@console/modules/contents/posts/tags/components/PostTag.vue";
|
||||||
import type { ListedPost } from "@halo-dev/api-client";
|
import type { ListedPost } from "@halo-dev/api-client";
|
||||||
import { ucApiClient } from "@halo-dev/api-client";
|
import { ucApiClient } from "@halo-dev/api-client";
|
||||||
|
@ -238,8 +238,11 @@ function handleDelete() {
|
||||||
<VEntityField v-if="post.post.spec.publishTime">
|
<VEntityField v-if="post.post.spec.publishTime">
|
||||||
<template #description>
|
<template #description>
|
||||||
<div class="inline-flex items-center space-x-2">
|
<div class="inline-flex items-center space-x-2">
|
||||||
<span class="entity-field-description">
|
<span
|
||||||
{{ formatDatetime(post.post.spec.publishTime) }}
|
v-tooltip="formatDatetime(post.post.spec.publishTime)"
|
||||||
|
class="entity-field-description"
|
||||||
|
>
|
||||||
|
{{ relativeTimeTo(post.post.spec.publishTime) }}
|
||||||
</span>
|
</span>
|
||||||
<IconTimerLine
|
<IconTimerLine
|
||||||
v-if="
|
v-if="
|
||||||
|
|
Loading…
Reference in New Issue