feat: 添加新闻组件,整合动态新闻数据并优化RWA组件展示
This commit is contained in:
10
components.d.ts
vendored
10
components.d.ts
vendored
@@ -25,6 +25,11 @@ declare module 'vue' {
|
|||||||
IonBadge: typeof import('@ionic/vue')['IonBadge']
|
IonBadge: typeof import('@ionic/vue')['IonBadge']
|
||||||
IonButton: typeof import('@ionic/vue')['IonButton']
|
IonButton: typeof import('@ionic/vue')['IonButton']
|
||||||
IonButtons: typeof import('@ionic/vue')['IonButtons']
|
IonButtons: typeof import('@ionic/vue')['IonButtons']
|
||||||
|
IonCard: typeof import('@ionic/vue')['IonCard']
|
||||||
|
IonCardContent: typeof import('@ionic/vue')['IonCardContent']
|
||||||
|
IonCardHeader: typeof import('@ionic/vue')['IonCardHeader']
|
||||||
|
IonCardSubtitle: typeof import('@ionic/vue')['IonCardSubtitle']
|
||||||
|
IonCardTitle: typeof import('@ionic/vue')['IonCardTitle']
|
||||||
IonChip: typeof import('@ionic/vue')['IonChip']
|
IonChip: typeof import('@ionic/vue')['IonChip']
|
||||||
IonCol: typeof import('@ionic/vue')['IonCol']
|
IonCol: typeof import('@ionic/vue')['IonCol']
|
||||||
IonContent: typeof import('@ionic/vue')['IonContent']
|
IonContent: typeof import('@ionic/vue')['IonContent']
|
||||||
@@ -91,6 +96,11 @@ declare global {
|
|||||||
const IonBadge: typeof import('@ionic/vue')['IonBadge']
|
const IonBadge: typeof import('@ionic/vue')['IonBadge']
|
||||||
const IonButton: typeof import('@ionic/vue')['IonButton']
|
const IonButton: typeof import('@ionic/vue')['IonButton']
|
||||||
const IonButtons: typeof import('@ionic/vue')['IonButtons']
|
const IonButtons: typeof import('@ionic/vue')['IonButtons']
|
||||||
|
const IonCard: typeof import('@ionic/vue')['IonCard']
|
||||||
|
const IonCardContent: typeof import('@ionic/vue')['IonCardContent']
|
||||||
|
const IonCardHeader: typeof import('@ionic/vue')['IonCardHeader']
|
||||||
|
const IonCardSubtitle: typeof import('@ionic/vue')['IonCardSubtitle']
|
||||||
|
const IonCardTitle: typeof import('@ionic/vue')['IonCardTitle']
|
||||||
const IonChip: typeof import('@ionic/vue')['IonChip']
|
const IonChip: typeof import('@ionic/vue')['IonChip']
|
||||||
const IonCol: typeof import('@ionic/vue')['IonCol']
|
const IonCol: typeof import('@ionic/vue')['IonCol']
|
||||||
const IonContent: typeof import('@ionic/vue')['IonContent']
|
const IonContent: typeof import('@ionic/vue')['IonContent']
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
import "./notify";
|
import "./notify";
|
||||||
import "./income";
|
import "./income";
|
||||||
|
import "./news";
|
||||||
|
|||||||
43
src/mocks/data/news.ts
Normal file
43
src/mocks/data/news.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { useMocks } from "../index";
|
||||||
|
|
||||||
|
export interface NewsItem {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
time: string;
|
||||||
|
thumbnail: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mockNews: NewsItem[] = [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
title: "比特币突破45000美元大关,创下近期新高",
|
||||||
|
description: "在市场乐观情绪推动下,比特币价格今日突破45000美元,较上周上涨8.5%,投资者信心持续回升。",
|
||||||
|
time: "2024-12-28 10:30:00",
|
||||||
|
thumbnail: "https://images.unsplash.com/photo-1518546305927-5a555bb7020d?w=400",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
title: "美联储维持利率不变,加密货币市场迎来利好",
|
||||||
|
description: "美联储宣布维持基准利率在5.25%-5.5%区间,市场普遍认为这将有利于加密货币市场的稳定发展。",
|
||||||
|
time: "2024-12-28 09:15:00",
|
||||||
|
thumbnail: "https://images.unsplash.com/photo-1621761191319-c6fb62004040?w=400",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
title: "以太坊2.0质押量突破3200万ETH",
|
||||||
|
description: "以太坊网络质押总量持续增长,目前已超过3200万枚ETH,占总供应量的26.7%,显示出投资者对网络的长期信心。",
|
||||||
|
time: "2024-12-28 08:45:00",
|
||||||
|
thumbnail: "https://images.unsplash.com/photo-1639762681485-074b7f938ba0?w=400",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "4",
|
||||||
|
title: "香港推出加密货币交易所监管新规",
|
||||||
|
description: "香港证监会发布最新监管指引,要求所有在港运营的加密货币交易平台必须在规定期限内申请牌照。",
|
||||||
|
time: "2024-12-27 18:20:00",
|
||||||
|
thumbnail: "https://images.unsplash.com/photo-1611974789855-9c2a0a7236a3?w=400",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 注册mock数据
|
||||||
|
useMocks().register("news", () => mockNews);
|
||||||
74
src/views/riwa/components/news.vue
Normal file
74
src/views/riwa/components/news.vue
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<script lang='ts' setup>
|
||||||
|
import type { NewsItem } from "@/mocks/data/news";
|
||||||
|
import { mockClient } 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" });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="mt-5">
|
||||||
|
<div class="text-md font-semibold mb-4">
|
||||||
|
动态新闻
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 新闻列表 -->
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div
|
||||||
|
v-for="item in data"
|
||||||
|
:key="item.id"
|
||||||
|
class="flex gap-3 p-3 rounded-lg bg-(--ion-color-light) transition-colors cursor-pointer"
|
||||||
|
>
|
||||||
|
<!-- 缩略图 -->
|
||||||
|
<div class="shrink-0">
|
||||||
|
<img
|
||||||
|
:src="item.thumbnail"
|
||||||
|
:alt="item.title"
|
||||||
|
class="w-20 h-20 rounded-lg object-cover"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 内容 -->
|
||||||
|
<div class="flex-1 min-w-0 flex flex-col justify-between">
|
||||||
|
<!-- 标题 -->
|
||||||
|
<div class="text-md font-medium line-clamp-1">
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 描述 -->
|
||||||
|
<p class="text-xs line-clamp-2 mt-1">
|
||||||
|
{{ item.description }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- 时间 -->
|
||||||
|
<div class="text-xs mt-1">
|
||||||
|
{{ formatTime(item.time) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='css' scoped>
|
||||||
|
</style>
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
<script lang='ts' setup>
|
<script lang='ts' setup>
|
||||||
|
import { cartOutline } from "ionicons/icons";
|
||||||
|
import CryptocurrencyColorNuls from "~icons/cryptocurrency-color/nuls";
|
||||||
import { client, safeClient } from "@/api";
|
import { client, safeClient } from "@/api";
|
||||||
|
|
||||||
const { data } = safeClient(client.api.rwa.subscription.available_editions.get({
|
const { data } = safeClient(client.api.rwa.subscription.available_editions.get({
|
||||||
@@ -10,8 +12,52 @@ const { data } = safeClient(client.api.rwa.subscription.available_editions.get({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
{{ data }}
|
<div class="text-md font-semibold">
|
||||||
|
RWA产品
|
||||||
|
</div>
|
||||||
|
<div v-for="item in data?.data" :key="item.id" class="card">
|
||||||
|
<div class="flex justify-between items-center mb-2 h-10">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<CryptocurrencyColorNuls class="text-2xl inline-block mr-2" />
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="text-md font-medium">
|
||||||
|
{{ item.product.name }}/{{ item.product.code }}
|
||||||
|
</div>
|
||||||
|
<ui-tag size="small" type="secondary">
|
||||||
|
{{ item.product.category?.name }}
|
||||||
|
</ui-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ion-button size="small">
|
||||||
|
<ion-icon slot="start" :icon="cartOutline" />
|
||||||
|
<span>购 入</span>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-sm font-semibold mb-2 text-text-300">
|
||||||
|
阶段:{{ item.editionName }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-2xl font-bold mb-2">
|
||||||
|
{{ formatAmountWithSplit(item.totalSupply) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='css' scoped></style>
|
<style lang='css' scoped>
|
||||||
|
.card {
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 12px;
|
||||||
|
box-shadow: 0 0 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
ion-button {
|
||||||
|
--padding-start: 12px;
|
||||||
|
--padding-end: 12px;
|
||||||
|
--padding-top: 8px;
|
||||||
|
--padding-bottom: 8px;
|
||||||
|
--border-radius: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import IconParkOutlineApplicationMenu from "~icons/icon-park-outline/application-menu";
|
import IconParkOutlineApplicationMenu from "~icons/icon-park-outline/application-menu";
|
||||||
|
import News from "./components/news.vue";
|
||||||
import Rwa from "./components/rwa.vue";
|
import Rwa from "./components/rwa.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -16,8 +17,9 @@ import Rwa from "./components/rwa.vue";
|
|||||||
<ion-title>首页</ion-title>
|
<ion-title>首页</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content :fullscreen="true">
|
<ion-content :fullscreen="true" class="ion-padding">
|
||||||
<Rwa />
|
<Rwa />
|
||||||
|
<News />
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ion-page>
|
</ion-page>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user