feat: 更新新闻相关功能,整合 API 数据获取,优化新闻列表展示和详情页面
This commit is contained in:
@@ -34,7 +34,7 @@
|
|||||||
"@elysiajs/eden": "^1.4.5",
|
"@elysiajs/eden": "^1.4.5",
|
||||||
"@ionic/vue": "^8.7.11",
|
"@ionic/vue": "^8.7.11",
|
||||||
"@ionic/vue-router": "^8.7.11",
|
"@ionic/vue-router": "^8.7.11",
|
||||||
"@riwa/api-types": "http://192.168.1.7:9527/api/riwa-eden-0.0.102.tgz",
|
"@riwa/api-types": "http://192.168.1.7:9527/api/riwa-eden-0.0.109.tgz",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"@vee-validate/yup": "^4.15.1",
|
"@vee-validate/yup": "^4.15.1",
|
||||||
"@vueuse/core": "^14.1.0",
|
"@vueuse/core": "^14.1.0",
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
"ionicons": "^8.0.13",
|
"ionicons": "^8.0.13",
|
||||||
"lightweight-charts": "^5.1.0",
|
"lightweight-charts": "^5.1.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"markdown-it": "^14.1.0",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"tailwindcss": "^4.1.18",
|
"tailwindcss": "^4.1.18",
|
||||||
|
|||||||
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@@ -57,8 +57,8 @@ importers:
|
|||||||
specifier: ^8.7.11
|
specifier: ^8.7.11
|
||||||
version: 8.7.11(@stencil/core@4.39.0)(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
|
version: 8.7.11(@stencil/core@4.39.0)(vue-router@4.6.3(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))
|
||||||
'@riwa/api-types':
|
'@riwa/api-types':
|
||||||
specifier: http://192.168.1.7:9527/api/riwa-eden-0.0.102.tgz
|
specifier: http://192.168.1.7:9527/api/riwa-eden-0.0.109.tgz
|
||||||
version: '@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.102.tgz(@elysiajs/eden@1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))'
|
version: '@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.109.tgz(@elysiajs/eden@1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))'
|
||||||
'@tailwindcss/vite':
|
'@tailwindcss/vite':
|
||||||
specifier: ^4.1.18
|
specifier: ^4.1.18
|
||||||
version: 4.1.18(vite@7.2.7(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
|
version: 4.1.18(vite@7.2.7(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(yaml@2.8.2))
|
||||||
@@ -89,6 +89,9 @@ importers:
|
|||||||
lodash-es:
|
lodash-es:
|
||||||
specifier: ^4.17.21
|
specifier: ^4.17.21
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
|
markdown-it:
|
||||||
|
specifier: ^14.1.0
|
||||||
|
version: 14.1.0
|
||||||
pinia:
|
pinia:
|
||||||
specifier: ^3.0.4
|
specifier: ^3.0.4
|
||||||
version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))
|
||||||
@@ -2772,9 +2775,9 @@ packages:
|
|||||||
'@remirror/core-constants@3.0.0':
|
'@remirror/core-constants@3.0.0':
|
||||||
resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==}
|
resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==}
|
||||||
|
|
||||||
'@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.102.tgz':
|
'@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.109.tgz':
|
||||||
resolution: {tarball: http://192.168.1.7:9527/api/riwa-eden-0.0.102.tgz}
|
resolution: {tarball: http://192.168.1.7:9527/api/riwa-eden-0.0.109.tgz}
|
||||||
version: 0.0.102
|
version: 0.0.109
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@elysiajs/eden': ^1.4.5
|
'@elysiajs/eden': ^1.4.5
|
||||||
|
|
||||||
@@ -12099,7 +12102,7 @@ snapshots:
|
|||||||
|
|
||||||
'@remirror/core-constants@3.0.0': {}
|
'@remirror/core-constants@3.0.0': {}
|
||||||
|
|
||||||
'@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.102.tgz(@elysiajs/eden@1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))':
|
'@riwa/eden@http://192.168.1.7:9527/api/riwa-eden-0.0.109.tgz(@elysiajs/eden@1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@elysiajs/eden': 1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3))
|
'@elysiajs/eden': 1.4.5(elysia@1.4.18(@sinclair/typebox@0.34.41)(exact-mirror@0.2.5(@sinclair/typebox@0.34.41))(file-type@21.1.1)(openapi-types@12.1.3)(typescript@5.9.3))
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,10 @@ export type NotificationData = Treaty.Data<typeof client.api.notifications.get>[
|
|||||||
|
|
||||||
export type NotificationBody = TreatyQuery<typeof client.api.notifications.get>;
|
export type NotificationBody = TreatyQuery<typeof client.api.notifications.get>;
|
||||||
|
|
||||||
|
export type NewBody = TreatyQuery<typeof client.api.news.get>;
|
||||||
|
|
||||||
|
export type NewData = Treaty.Data<typeof client.api.news.get>["data"][number];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用版本信息
|
* 应用版本信息
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -392,6 +392,13 @@
|
|||||||
"fileSizeError": "File {name} exceeds {max}MB limit",
|
"fileSizeError": "File {name} exceeds {max}MB limit",
|
||||||
"uploadError": "File {name} upload failed"
|
"uploadError": "File {name} upload failed"
|
||||||
},
|
},
|
||||||
|
"news": {
|
||||||
|
"detail": "News Detail",
|
||||||
|
"summary": "Summary",
|
||||||
|
"views": "views",
|
||||||
|
"attachments": "Attachments",
|
||||||
|
"loadError": "Failed to load, please try again later"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Log in",
|
"title": "Log in",
|
||||||
|
|||||||
@@ -398,6 +398,13 @@
|
|||||||
"fileSizeError": "文件 {name} 超过 {max}MB 限制",
|
"fileSizeError": "文件 {name} 超过 {max}MB 限制",
|
||||||
"uploadError": "文件 {name} 上传失败"
|
"uploadError": "文件 {name} 上传失败"
|
||||||
},
|
},
|
||||||
|
"news": {
|
||||||
|
"detail": "新闻详情",
|
||||||
|
"summary": "摘要",
|
||||||
|
"views": "次查看",
|
||||||
|
"attachments": "附件",
|
||||||
|
"loadError": "加载失败,请稍后重试"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"login": {
|
"login": {
|
||||||
"title": "登录",
|
"title": "登录",
|
||||||
|
|||||||
@@ -225,6 +225,11 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: () => import("@/views/market/orders.vue"),
|
component: () => import("@/views/market/orders.vue"),
|
||||||
meta: { requiresAuth: true },
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/new/:id",
|
||||||
|
props: true,
|
||||||
|
component: () => import("@/views/new/id.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/global-menu",
|
path: "/global-menu",
|
||||||
component: () => import("@/views/global-menu/index.vue"),
|
component: () => import("@/views/global-menu/index.vue"),
|
||||||
|
|||||||
187
src/views/new/id.vue
Normal file
187
src/views/new/id.vue
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<script lang='ts' setup>
|
||||||
|
import { downloadOutline, eyeOutline, timeOutline } from "ionicons/icons";
|
||||||
|
import markdownit from "markdown-it";
|
||||||
|
import { client, safeClient } from "@/api";
|
||||||
|
|
||||||
|
const props = defineProps<{ id: string }>();
|
||||||
|
|
||||||
|
const md = markdownit();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const { data, error } = await safeClient(client.api.news({ id: props.id }).get());
|
||||||
|
|
||||||
|
function formatViewCount(count: number): string {
|
||||||
|
if (count >= 10000) {
|
||||||
|
return `${(count / 10000).toFixed(1)}w`;
|
||||||
|
}
|
||||||
|
if (count >= 1000) {
|
||||||
|
return `${(count / 1000).toFixed(1)}k`;
|
||||||
|
}
|
||||||
|
return String(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDownloadAttachment(url: string, filename: string) {
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = url;
|
||||||
|
link.download = filename;
|
||||||
|
link.target = "_blank";
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<IonPage>
|
||||||
|
<IonHeader class="ion-no-border">
|
||||||
|
<ion-toolbar class="ion-toolbar">
|
||||||
|
<ui-back-button slot="start" />
|
||||||
|
<ion-title>{{ t('news.detail') }}</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</IonHeader>
|
||||||
|
|
||||||
|
<IonContent :fullscreen="true" class="ion-padding">
|
||||||
|
<!-- 加载状态 -->
|
||||||
|
<div v-if="!data && !error" class="flex items-center justify-center h-full">
|
||||||
|
<ion-spinner name="crescent" color="primary" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 错误状态 -->
|
||||||
|
<div v-else-if="error" class="flex flex-col items-center justify-center h-full gap-4">
|
||||||
|
<Icon icon="mdi:alert-circle-outline" class="text-5xl text-(--ion-color-danger)" />
|
||||||
|
<ion-text color="medium">
|
||||||
|
{{ t('news.loadError') }}
|
||||||
|
</ion-text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 新闻内容 -->
|
||||||
|
<div v-else-if="data" class="max-w-800px mx-auto pb-8">
|
||||||
|
<!-- 标题 -->
|
||||||
|
<div class="text-2xl sm:text-xl font-bold leading-tight text-(--ion-text-color) mb-4 wrap-break-word">
|
||||||
|
{{ data.title }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 元信息 -->
|
||||||
|
<div class="flex items-center gap-4 sm:gap-3 flex-wrap mb-4">
|
||||||
|
<div class="flex items-center gap-1.5 text-xs text-(--ion-color-medium)">
|
||||||
|
<ion-icon :icon="timeOutline" class="text-base" />
|
||||||
|
<span>{{ useDateFormat(data.publishedAt || data.createdAt, 'YYYY-MM-DD HH:mm') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1.5 text-xs text-(--ion-color-medium)">
|
||||||
|
<ion-icon :icon="eyeOutline" class="text-base" />
|
||||||
|
<span>{{ formatViewCount(data.viewCount || 0) }} {{ t('news.views') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ui-divider class="my-4" />
|
||||||
|
|
||||||
|
<!-- 摘要 -->
|
||||||
|
<div v-if="data.summary" class="border-2 border-dashed border-text-900 rounded-xl p-4 ">
|
||||||
|
<div class="text-sm font-semibold text-(--ion-color-primary) mb-2">
|
||||||
|
{{ t('news.summary') }}
|
||||||
|
</div>
|
||||||
|
<p class="text-base leading-relaxed text-(--ion-color-step-600) m-0">
|
||||||
|
{{ data.summary }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 缩略图 -->
|
||||||
|
<div v-if="data.thumbnailId" class="my-6 rounded-xl overflow-hidden shadow-sm dark:shadow-md">
|
||||||
|
<img :src="data.thumbnailId" :alt="data.title" class="w-full h-auto block">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 正文内容 -->
|
||||||
|
<div class="news-content text-base leading-relaxed text-(--ion-text-color) my-6">
|
||||||
|
<div v-html="md.render(data.content)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 附件列表 -->
|
||||||
|
<div v-if="data.attachments && data.attachments.length > 0" class="mt-8 pt-6 border-t border-(--ion-color-light)">
|
||||||
|
<div class="flex items-center gap-2 text-base font-semibold text-(--ion-text-color) mb-4">
|
||||||
|
<Icon icon="mdi:paperclip" class="text-lg" />
|
||||||
|
<span>{{ t('news.attachments') }} ({{ data.attachments.length }})</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-3">
|
||||||
|
<div
|
||||||
|
v-for="(attachment, index) in data.attachments"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-center justify-between p-3 px-4 bg-(--ion-color-light) dark:bg-(--ion-color-step-100) rounded-lg cursor-pointer transition-all hover:bg-(--ion-color-light-shade) dark:hover:bg-(--ion-color-step-150) hover:translate-x-1 active:scale-98"
|
||||||
|
@click="handleDownloadAttachment(attachment.url, attachment.name)"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3 flex-1 min-w-0">
|
||||||
|
<Icon icon="mdi:file-document-outline" class="text-2xl text-(--ion-color-primary) shrink-0" />
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<div class="text-sm font-medium text-(--ion-text-color) truncate">
|
||||||
|
{{ attachment.name }}
|
||||||
|
</div>
|
||||||
|
<div v-if="attachment.size" class="text-xs text-(--ion-color-medium) mt-0.5">
|
||||||
|
{{ (attachment.size / 1024).toFixed(2) }} KB
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ion-button fill="clear" size="small">
|
||||||
|
<ion-icon slot="icon-only" :icon="downloadOutline" />
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</IonContent>
|
||||||
|
</IonPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@reference "tailwindcss";
|
||||||
|
|
||||||
|
/* 正文内容富文本样式 */
|
||||||
|
.news-content :deep(p) {
|
||||||
|
@apply my-4 whitespace-pre-wrap wrap-break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(img) {
|
||||||
|
@apply max-w-full h-auto rounded-lg my-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(h1),
|
||||||
|
.news-content :deep(h2),
|
||||||
|
.news-content :deep(h3) {
|
||||||
|
@apply font-semibold my-6 mb-4 leading-tight;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(h1) {
|
||||||
|
@apply text-xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(h2) {
|
||||||
|
@apply text-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(h3) {
|
||||||
|
@apply text-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(ul),
|
||||||
|
.news-content :deep(ol) {
|
||||||
|
@apply pl-6 my-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(li) {
|
||||||
|
@apply my-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(blockquote) {
|
||||||
|
@apply border-l-3 border-(--ion-color-medium) pl-4 my-4 text-(--ion-color-medium) italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(code) {
|
||||||
|
@apply bg-(--ion-color-light) px-1.5 py-0.5 rounded text-sm font-mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(pre) {
|
||||||
|
@apply bg-(--ion-color-light) p-4 rounded-lg overflow-x-auto my-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-content :deep(pre code) {
|
||||||
|
@apply bg-transparent p-0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,34 +1,17 @@
|
|||||||
<script lang='ts' setup>
|
<script lang='ts' setup>
|
||||||
import type { NewsItem } from "@/mocks/data/news";
|
import type { NewData } from "@/api/types";
|
||||||
import { mockClient } from "@/api";
|
import { client, safeClient } from "@/api";
|
||||||
|
|
||||||
// TODO: 后续从API获取新闻数据
|
|
||||||
const { data } = mockClient<NewsItem[]>("news");
|
|
||||||
|
|
||||||
function formatTime(time: string) {
|
|
||||||
const date = new Date(time);
|
|
||||||
const now = new Date();
|
|
||||||
const diff = now.getTime() - date.getTime();
|
|
||||||
const hours = Math.floor(diff / (1000 * 60 * 60));
|
|
||||||
|
|
||||||
if (hours < 1) {
|
|
||||||
const minutes = Math.floor(diff / (1000 * 60));
|
|
||||||
return `${minutes}分钟前`;
|
|
||||||
}
|
|
||||||
if (hours < 24) {
|
|
||||||
return `${hours}小时前`;
|
|
||||||
}
|
|
||||||
const days = Math.floor(hours / 24);
|
|
||||||
if (days < 7) {
|
|
||||||
return `${days}天前`;
|
|
||||||
}
|
|
||||||
return date.toLocaleDateString("zh-CN", { month: "2-digit", day: "2-digit" });
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { data } = await safeClient(() => client.api.news.get({
|
||||||
|
query: {
|
||||||
|
limit: 10,
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
function openNewsDetail(item: NewsItem) {
|
function openNewsDetail(item: NewData) {
|
||||||
router.push(`/news/${item.id}`);
|
router.push(`/new/${item.id}`);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -38,37 +21,30 @@ function openNewsDetail(item: NewsItem) {
|
|||||||
动态新闻
|
动态新闻
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 新闻列表 -->
|
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div
|
<div
|
||||||
v-for="item in data"
|
v-for="item in data?.data"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
class="flex gap-3 p-3 rounded-lg bg-(--ion-color-faint) transition-colors cursor-pointer"
|
class="flex gap-3 p-3 rounded-lg bg-(--ion-color-faint) transition-colors cursor-pointer"
|
||||||
|
@click="openNewsDetail(item)"
|
||||||
>
|
>
|
||||||
<!-- 缩略图 -->
|
|
||||||
<div class="shrink-0">
|
<div class="shrink-0">
|
||||||
<img
|
<img
|
||||||
:src="item.thumbnail"
|
:src="item.thumbnailId!"
|
||||||
:alt="item.title"
|
:alt="item.title"
|
||||||
class="w-20 h-20 rounded-lg object-cover"
|
class="w-20 h-20 rounded-lg object-cover"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 内容 -->
|
|
||||||
<div class="flex-1 min-w-0 flex flex-col justify-between">
|
<div class="flex-1 min-w-0 flex flex-col justify-between">
|
||||||
<!-- 标题 -->
|
|
||||||
<div class="text-md font-medium line-clamp-1">
|
<div class="text-md font-medium line-clamp-1">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 描述 -->
|
|
||||||
<p class="text-xs line-clamp-2 mt-1">
|
<p class="text-xs line-clamp-2 mt-1">
|
||||||
{{ item.description }}
|
{{ item.summary }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- 时间 -->
|
|
||||||
<div class="text-xs mt-1">
|
<div class="text-xs mt-1">
|
||||||
{{ formatTime(item.time) }}
|
{{ useDateFormat(item.createdAt, 'YY/MM/DD') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user