feat: 添加通知详情页面及通知列表点击跳转功能;优化分隔线样式

This commit is contained in:
2025-12-30 20:14:26 +07:00
parent 72e7c77003
commit cde6cd9bb5
6 changed files with 109 additions and 6 deletions

2
auto-imports.d.ts vendored
View File

@@ -156,8 +156,6 @@ declare global {
const useAsyncQueue: typeof import('@vueuse/core').useAsyncQueue const useAsyncQueue: typeof import('@vueuse/core').useAsyncQueue
const useAsyncState: typeof import('@vueuse/core').useAsyncState const useAsyncState: typeof import('@vueuse/core').useAsyncState
const useAttrs: typeof import('vue').useAttrs const useAttrs: typeof import('vue').useAttrs
const useAuth: typeof import('./src/composables/useAuth').useAuth
const useBack: typeof import('./src/composables/useBack').useBack
const useBase64: typeof import('@vueuse/core').useBase64 const useBase64: typeof import('@vueuse/core').useBase64
const useBattery: typeof import('@vueuse/core').useBattery const useBattery: typeof import('@vueuse/core').useBattery
const useBluetooth: typeof import('@vueuse/core').useBluetooth const useBluetooth: typeof import('@vueuse/core').useBluetooth

2
components.d.ts vendored
View File

@@ -50,6 +50,7 @@ declare module 'vue' {
IonSearchbar: typeof import('@ionic/vue')['IonSearchbar'] IonSearchbar: typeof import('@ionic/vue')['IonSearchbar']
IonSelect: typeof import('@ionic/vue')['IonSelect'] IonSelect: typeof import('@ionic/vue')['IonSelect']
IonSelectOption: typeof import('@ionic/vue')['IonSelectOption'] IonSelectOption: typeof import('@ionic/vue')['IonSelectOption']
IonSpinner: typeof import('@ionic/vue')['IonSpinner']
IonTabBar: typeof import('@ionic/vue')['IonTabBar'] IonTabBar: typeof import('@ionic/vue')['IonTabBar']
IonTabButton: typeof import('@ionic/vue')['IonTabButton'] IonTabButton: typeof import('@ionic/vue')['IonTabButton']
IonTabs: typeof import('@ionic/vue')['IonTabs'] IonTabs: typeof import('@ionic/vue')['IonTabs']
@@ -104,6 +105,7 @@ declare global {
const IonSearchbar: typeof import('@ionic/vue')['IonSearchbar'] const IonSearchbar: typeof import('@ionic/vue')['IonSearchbar']
const IonSelect: typeof import('@ionic/vue')['IonSelect'] const IonSelect: typeof import('@ionic/vue')['IonSelect']
const IonSelectOption: typeof import('@ionic/vue')['IonSelectOption'] const IonSelectOption: typeof import('@ionic/vue')['IonSelectOption']
const IonSpinner: typeof import('@ionic/vue')['IonSpinner']
const IonTabBar: typeof import('@ionic/vue')['IonTabBar'] const IonTabBar: typeof import('@ionic/vue')['IonTabBar']
const IonTabButton: typeof import('@ionic/vue')['IonTabButton'] const IonTabButton: typeof import('@ionic/vue')['IonTabButton']
const IonTabs: typeof import('@ionic/vue')['IonTabs'] const IonTabs: typeof import('@ionic/vue')['IonTabs']

View File

@@ -44,6 +44,11 @@ const routes: Array<RouteRecordRaw> = [
}, },
], ],
}, },
{
path: "/notify/:id",
props: true,
component: () => import("@/views/notify/detail.vue"),
},
{ {
path: "/onchain-address", path: "/onchain-address",
component: () => import("@/views/onchain-address/index.vue"), component: () => import("@/views/onchain-address/index.vue"),

View File

@@ -4,7 +4,7 @@ defineProps<{ text?: string }>();
<template> <template>
<div class="divider ion-margin-vertical" v-bind="$attrs"> <div class="divider ion-margin-vertical" v-bind="$attrs">
<span>{{ text }}</span> <span v-if="text">{{ text }}</span>
</div> </div>
</template> </template>
@@ -20,7 +20,7 @@ defineProps<{ text?: string }>();
.divider::after { .divider::after {
content: ""; content: "";
flex: 1; flex: 1;
border-bottom: 1px solid var(--ion-color-medium); border-bottom: 1px solid var(--ion-text-color-step-900);
} }
.divider span { .divider span {

View File

@@ -0,0 +1,87 @@
<script setup lang="ts">
import IcBaselineNotificationsNone from "~icons/ic/baseline-notifications-none";
import { mockClient } from "@/api";
const props = defineProps<{ id: string }>();
const router = useRouter();
const { data: allNotifications } = await mockClient("notify.list");
const notification = computed(() => {
return allNotifications.value.find(item => String(item.id) === props.id);
});
watch(notification, (val) => {
if (!val && allNotifications.value.length > 0) {
router.replace("/layout/notify");
}
}, { immediate: true });
function handleBack() {
router.back();
}
</script>
<template>
<IonPage>
<IonHeader class="ion-no-border">
<ion-toolbar class="ui-toolbar">
<ui-back-button slot="start" />
<ion-title>通知详情</ion-title>
</ion-toolbar>
</IonHeader>
<IonContent :fullscreen="true" class="ion-padding">
<div v-if="notification" class="notification-detail">
<!-- 图标和标题 -->
<div class="flex items-start gap-4 mb-2">
<div class="bg-[#f1f1f1] dark:bg-[#2d2d2d] p-2.5 rounded-full shrink-0">
<IcBaselineNotificationsNone class="text-2xl text-[#71cc51]" />
</div>
<div class="flex-1 min-w-0">
<div class="text-xl font-semibold wrap-break-word">
{{ notification.title }}
</div>
<ion-note class="text-xs">
{{ useDateFormat(notification.date, 'YYYY-MM-DD HH:mm:ss') }}
</ion-note>
</div>
</div>
<!-- 分割线 -->
<ui-divider />
<!-- 内容 -->
<div class="notification-content">
<p class="text-base leading-relaxed whitespace-pre-wrap wrap-break-word">
{{ notification.content }}
</p>
</div>
</div>
<!-- 加载状态 -->
<div v-else class="flex items-center justify-center h-full">
<ion-spinner name="crescent" />
</div>
</IonContent>
</IonPage>
</template>
<style scoped>
.notification-detail {
max-width: 800px;
margin: 0 auto;
}
.notification-content {
color: var(--ion-text-color);
font-size: 15px;
line-height: 1.8;
}
/* 深色模式适配 */
@media (prefers-color-scheme: dark) {
.notification-content {
color: var(--ion-color-step-600);
}
}
</style>

View File

@@ -4,7 +4,12 @@ import IconParkOutlineClearFormat from "~icons/icon-park-outline/clear-format";
import MaterialSymbolsAndroidContacts from "~icons/material-symbols/android-contacts"; import MaterialSymbolsAndroidContacts from "~icons/material-symbols/android-contacts";
import { mockClient } from "@/api"; import { mockClient } from "@/api";
const router = useRouter();
const { data } = mockClient("notify.list"); const { data } = mockClient("notify.list");
function handleItemClick(id: number) {
router.push(`/notify/${id}`);
}
</script> </script>
<template> <template>
@@ -24,8 +29,14 @@ const { data } = mockClient("notify.list");
<ion-searchbar placeholder="Search" /> <ion-searchbar placeholder="Search" />
<ion-list lines="none"> <ion-list lines="none">
<ion-item v-for="item in data" :key="item.id" class="py-3"> <ion-item
<div slot="start" class="bg-[#f1f1f1] p-2.5 rounded-full"> v-for="item in data"
:key="item.id"
class="py-3"
button
@click="handleItemClick(item.id)"
>
<div slot="start" class="bg-[#f1f1f1] dark:bg-[#2d2d2d] p-2.5 rounded-full">
<IcBaselineNotificationsNone class="text-2xl text-[#71cc51]" /> <IcBaselineNotificationsNone class="text-2xl text-[#71cc51]" />
</div> </div>
<div class="pl-3 w-full"> <div class="pl-3 w-full">