feat: 添加 SubscribeRwa 组件,优化 RWA 申购功能并更新相关类型定义
This commit is contained in:
2
auto-imports.d.ts
vendored
2
auto-imports.d.ts
vendored
@@ -270,6 +270,7 @@ declare global {
|
|||||||
const useStorage: typeof import('@vueuse/core').useStorage
|
const useStorage: typeof import('@vueuse/core').useStorage
|
||||||
const useStorageAsync: typeof import('@vueuse/core').useStorageAsync
|
const useStorageAsync: typeof import('@vueuse/core').useStorageAsync
|
||||||
const useStyleTag: typeof import('@vueuse/core').useStyleTag
|
const useStyleTag: typeof import('@vueuse/core').useStyleTag
|
||||||
|
const useSubscribeModal: typeof import('./src/composables/useSubscribeModal').useSubscribeModal
|
||||||
const useSupported: typeof import('@vueuse/core').useSupported
|
const useSupported: typeof import('@vueuse/core').useSupported
|
||||||
const useSwipe: typeof import('@vueuse/core').useSwipe
|
const useSwipe: typeof import('@vueuse/core').useSwipe
|
||||||
const useTemplateRef: typeof import('vue').useTemplateRef
|
const useTemplateRef: typeof import('vue').useTemplateRef
|
||||||
@@ -611,6 +612,7 @@ declare module 'vue' {
|
|||||||
readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']>
|
readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']>
|
||||||
readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']>
|
readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']>
|
||||||
readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']>
|
readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']>
|
||||||
|
readonly useSubscribeModal: UnwrapRef<typeof import('./src/composables/useSubscribeModal')['useSubscribeModal']>
|
||||||
readonly useSupported: UnwrapRef<typeof import('@vueuse/core')['useSupported']>
|
readonly useSupported: UnwrapRef<typeof import('@vueuse/core')['useSupported']>
|
||||||
readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']>
|
readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']>
|
||||||
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
|
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
|
||||||
|
|||||||
4
components.d.ts
vendored
4
components.d.ts
vendored
@@ -35,6 +35,7 @@ declare module 'vue' {
|
|||||||
IonIcon: typeof import('@ionic/vue')['IonIcon']
|
IonIcon: typeof import('@ionic/vue')['IonIcon']
|
||||||
IonInfiniteScroll: typeof import('@ionic/vue')['IonInfiniteScroll']
|
IonInfiniteScroll: typeof import('@ionic/vue')['IonInfiniteScroll']
|
||||||
IonInfiniteScrollContent: typeof import('@ionic/vue')['IonInfiniteScrollContent']
|
IonInfiniteScrollContent: typeof import('@ionic/vue')['IonInfiniteScrollContent']
|
||||||
|
IonInput: typeof import('@ionic/vue')['IonInput']
|
||||||
IonInputOtp: typeof import('@ionic/vue')['IonInputOtp']
|
IonInputOtp: typeof import('@ionic/vue')['IonInputOtp']
|
||||||
IonItem: typeof import('@ionic/vue')['IonItem']
|
IonItem: typeof import('@ionic/vue')['IonItem']
|
||||||
IonLabel: typeof import('@ionic/vue')['IonLabel']
|
IonLabel: typeof import('@ionic/vue')['IonLabel']
|
||||||
@@ -61,6 +62,7 @@ declare module 'vue' {
|
|||||||
QrScanner: typeof import('./src/components/qr-scanner/index.vue')['default']
|
QrScanner: typeof import('./src/components/qr-scanner/index.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
SubscribeRwa: typeof import('./src/components/subscribe-rwa/index.vue')['default']
|
||||||
UiAvatar: typeof import('./src/components/ui/avatar/index.vue')['default']
|
UiAvatar: typeof import('./src/components/ui/avatar/index.vue')['default']
|
||||||
UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default']
|
UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default']
|
||||||
UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default']
|
UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default']
|
||||||
@@ -99,6 +101,7 @@ declare global {
|
|||||||
const IonIcon: typeof import('@ionic/vue')['IonIcon']
|
const IonIcon: typeof import('@ionic/vue')['IonIcon']
|
||||||
const IonInfiniteScroll: typeof import('@ionic/vue')['IonInfiniteScroll']
|
const IonInfiniteScroll: typeof import('@ionic/vue')['IonInfiniteScroll']
|
||||||
const IonInfiniteScrollContent: typeof import('@ionic/vue')['IonInfiniteScrollContent']
|
const IonInfiniteScrollContent: typeof import('@ionic/vue')['IonInfiniteScrollContent']
|
||||||
|
const IonInput: typeof import('@ionic/vue')['IonInput']
|
||||||
const IonInputOtp: typeof import('@ionic/vue')['IonInputOtp']
|
const IonInputOtp: typeof import('@ionic/vue')['IonInputOtp']
|
||||||
const IonItem: typeof import('@ionic/vue')['IonItem']
|
const IonItem: typeof import('@ionic/vue')['IonItem']
|
||||||
const IonLabel: typeof import('@ionic/vue')['IonLabel']
|
const IonLabel: typeof import('@ionic/vue')['IonLabel']
|
||||||
@@ -125,6 +128,7 @@ declare global {
|
|||||||
const QrScanner: typeof import('./src/components/qr-scanner/index.vue')['default']
|
const QrScanner: typeof import('./src/components/qr-scanner/index.vue')['default']
|
||||||
const RouterLink: typeof import('vue-router')['RouterLink']
|
const RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
const RouterView: typeof import('vue-router')['RouterView']
|
const RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
const SubscribeRwa: typeof import('./src/components/subscribe-rwa/index.vue')['default']
|
||||||
const UiAvatar: typeof import('./src/components/ui/avatar/index.vue')['default']
|
const UiAvatar: typeof import('./src/components/ui/avatar/index.vue')['default']
|
||||||
const UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default']
|
const UiCollapse: typeof import('./src/components/ui/collapse/index.vue')['default']
|
||||||
const UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default']
|
const UiDatetime: typeof import('./src/components/ui/datetime/index.vue')['default']
|
||||||
|
|||||||
45
src/components/subscribe-rwa/index.vue
Normal file
45
src/components/subscribe-rwa/index.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<script lang='ts' setup>
|
||||||
|
const props = defineProps<{
|
||||||
|
unitPrice: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const walletStore = useWalletStore();
|
||||||
|
const { balances } = storeToRefs(walletStore);
|
||||||
|
const currentUSDTBalance = computed(() => balances.value[0].available);
|
||||||
|
const maxSubscribeNumber = computed(() => {
|
||||||
|
return Math.floor(Number(currentUSDTBalance.value) / props.unitPrice);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ion-content class="ion-padding" :scroll-y="false">
|
||||||
|
<div class="space-y-5 mt-3">
|
||||||
|
<div>申购RWA</div>
|
||||||
|
|
||||||
|
<ion-input :placeholder="`最大可申购数量: ${maxSubscribeNumber}`" type="number" :max="maxSubscribeNumber" />
|
||||||
|
|
||||||
|
<div class="mt-4 text-sm color-(--ion-text-color-secondary)">
|
||||||
|
单价: ${{ unitPrice }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 text-sm color-(--ion-text-color-secondary)">
|
||||||
|
可用余额: ${{ Number(currentUSDTBalance) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ion-button expand="block" class="mt-6 ui-button" color="primary">
|
||||||
|
确认申购
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
</ion-content>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@reference "tailwindcss";
|
||||||
|
|
||||||
|
ion-input {
|
||||||
|
@apply rounded-lg;
|
||||||
|
--padding-start: 16px;
|
||||||
|
--padding-end: 16px;
|
||||||
|
border: 1px solid var(--ion-color-light-shade);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -47,26 +47,34 @@ const { data } = safeClient(client.api.rwa.subscription.available_editions({ edi
|
|||||||
</ion-col>
|
</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
|
<ion-col>
|
||||||
|
<div class="label">
|
||||||
|
单价
|
||||||
|
</div>
|
||||||
|
<div>${{ formatAmount(data?.unitPrice) }}</div>
|
||||||
|
</ion-col>
|
||||||
<ion-col>
|
<ion-col>
|
||||||
<div class="label">
|
<div class="label">
|
||||||
总发行量
|
总发行量
|
||||||
</div>
|
</div>
|
||||||
<div>{{ Number(data?.totalSupply) }}份</div>
|
<div>{{ Number(data?.totalSupply) }}份</div>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
<ion-row>
|
||||||
<ion-col>
|
<ion-col>
|
||||||
<div class="label">
|
<div class="label">
|
||||||
每人限量
|
每人限量
|
||||||
</div>
|
</div>
|
||||||
<div>{{ Number(data?.perUserLimit) }}份</div>
|
<div>{{ Number(data?.perUserLimit) }}份</div>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
</ion-row>
|
|
||||||
<ion-row>
|
|
||||||
<ion-col>
|
<ion-col>
|
||||||
<div class="label">
|
<div class="label">
|
||||||
发行时间
|
发行时间
|
||||||
</div>
|
</div>
|
||||||
<div>{{ useDateFormat(data?.launchDate || '', 'YYYY/MM/DD') }}</div>
|
<div>{{ useDateFormat(data?.launchDate || '', 'YYYY/MM/DD') }}</div>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
<ion-row>
|
||||||
<ion-col>
|
<ion-col>
|
||||||
<div class="label">
|
<div class="label">
|
||||||
认购截止时间
|
认购截止时间
|
||||||
@@ -90,12 +98,13 @@ const { data } = safeClient(client.api.rwa.subscription.available_editions({ edi
|
|||||||
<ion-footer>
|
<ion-footer>
|
||||||
<ion-toolbar class="ion-padding-horizontal ui-toolbar">
|
<ion-toolbar class="ion-padding-horizontal ui-toolbar">
|
||||||
<div class="flex justify-center my-2 gap-5">
|
<div class="flex justify-center my-2 gap-5">
|
||||||
<ion-button shape="round" expand="block" color="success">
|
<ion-button id="open-modal" shape="round" expand="block" color="success">
|
||||||
申购
|
申购
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ion-button shape="round" expand="block" color="danger">
|
|
||||||
赎回
|
<ion-modal trigger="open-modal" :initial-breakpoint="0.4" :breakpoints="[0, 0.4]">
|
||||||
</ion-button>
|
<subscribe-rwa :unit-price="Number(data?.unitPrice || 0)" />
|
||||||
|
</ion-modal>
|
||||||
</div>
|
</div>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-footer>
|
</ion-footer>
|
||||||
|
|||||||
@@ -1,11 +1,36 @@
|
|||||||
<script lang='ts' setup>
|
<script lang='ts' setup>
|
||||||
|
import type { Animation } from "@ionic/vue";
|
||||||
|
import { createAnimation } from "@ionic/vue";
|
||||||
import { cartOutline } from "ionicons/icons";
|
import { cartOutline } from "ionicons/icons";
|
||||||
|
|
||||||
const model = defineModel<"sale" | "buy" | null>();
|
const model = defineModel<"sale" | "buy" | null>();
|
||||||
|
|
||||||
|
const operationInst = useTemplateRef<HTMLDivElement>("operationInst");
|
||||||
|
const targetIsVisible = useElementVisibility(operationInst);
|
||||||
|
const animation = ref<Animation | null>(null);
|
||||||
|
|
||||||
|
watch(targetIsVisible, (visible) => {
|
||||||
|
if (visible) {
|
||||||
|
animation.value?.easing("ease-in")
|
||||||
|
.fromTo("opacity", "0", "1")
|
||||||
|
.play();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
animation.value?.easing("ease-out")
|
||||||
|
.fromTo("opacity", "1", "0")
|
||||||
|
.play();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
animation.value = createAnimation()
|
||||||
|
.addElement(operationInst.value!)
|
||||||
|
.duration(500);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="model === null" class="operation-container">
|
<div v-if="model === null" ref="operationInst" class="operation-container">
|
||||||
<div class="wrapper" />
|
<div class="wrapper" />
|
||||||
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
|
|||||||
@@ -3,18 +3,17 @@ import { cartOutline } from "ionicons/icons";
|
|||||||
import OperationWrapper from "./components/operation-wrapper.vue";
|
import OperationWrapper from "./components/operation-wrapper.vue";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const current = ref<"sale" | "buy" | null>(null);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<IonPage>
|
<IonPage>
|
||||||
<IonHeader>
|
<IonHeader class="ion-no-border">
|
||||||
<IonToolbar>
|
<ion-toolbar class="ui-toolbar">
|
||||||
<IonTitle>{{ t('tabs.trade') }}</IonTitle>
|
<IonTitle>{{ t('tabs.trade') }}</IonTitle>
|
||||||
</IonToolbar>
|
</ion-toolbar>
|
||||||
</IonHeader>
|
</IonHeader>
|
||||||
<IonContent :fullscreen="true">
|
<IonContent :fullscreen="true">
|
||||||
<OperationWrapper v-model="current" />
|
<!-- <OperationWrapper v-model="current" /> -->
|
||||||
</IonContent>
|
</IonContent>
|
||||||
</IonPage>
|
</IonPage>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user