feat: 添加法币充值页面,更新相关路由和组件,优化钱包卡片以支持充值功能

This commit is contained in:
2025-12-14 00:52:28 +07:00
parent 2c4df90b31
commit f78dfa87ed
9 changed files with 123 additions and 14 deletions

2
auto-imports.d.ts vendored
View File

@@ -307,7 +307,7 @@ declare global {
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
// @ts-ignore
export type { PageInstance, InputInstance } from './src/utils/ionic-helper'
export type { PageInstance, InputInstance, ModalInstance } from './src/utils/ionic-helper'
import('./src/utils/ionic-helper')
}

6
components.d.ts vendored
View File

@@ -38,6 +38,8 @@ declare module 'vue' {
IonPage: typeof import('@ionic/vue')['IonPage']
IonRouterOutlet: typeof import('@ionic/vue')['IonRouterOutlet']
IonSearchbar: typeof import('@ionic/vue')['IonSearchbar']
IonSelect: typeof import('@ionic/vue')['IonSelect']
IonSelectOption: typeof import('@ionic/vue')['IonSelectOption']
IonTabBar: typeof import('@ionic/vue')['IonTabBar']
IonTabButton: typeof import('@ionic/vue')['IonTabButton']
IonTabs: typeof import('@ionic/vue')['IonTabs']
@@ -50,6 +52,7 @@ declare module 'vue' {
UiDivider: typeof import('./src/components/ui/divider/index.vue')['default']
UiInput: typeof import('./src/components/ui/input/index.vue')['default']
UiInputLabel: typeof import('./src/components/ui/input-label/index.vue')['default']
UiSelectLabel: typeof import('./src/components/ui/select-label/index.vue')['default']
}
}
@@ -81,6 +84,8 @@ declare global {
const IonPage: typeof import('@ionic/vue')['IonPage']
const IonRouterOutlet: typeof import('@ionic/vue')['IonRouterOutlet']
const IonSearchbar: typeof import('@ionic/vue')['IonSearchbar']
const IonSelect: typeof import('@ionic/vue')['IonSelect']
const IonSelectOption: typeof import('@ionic/vue')['IonSelectOption']
const IonTabBar: typeof import('@ionic/vue')['IonTabBar']
const IonTabButton: typeof import('@ionic/vue')['IonTabButton']
const IonTabs: typeof import('@ionic/vue')['IonTabs']
@@ -93,4 +98,5 @@ declare global {
const UiDivider: typeof import('./src/components/ui/divider/index.vue')['default']
const UiInput: typeof import('./src/components/ui/input/index.vue')['default']
const UiInputLabel: typeof import('./src/components/ui/input-label/index.vue')['default']
const UiSelectLabel: typeof import('./src/components/ui/select-label/index.vue')['default']
}

9
src/api/enum.ts Normal file
View File

@@ -0,0 +1,9 @@
export enum PaymentChannelEnum {
FIAT = "fiat",
CRYPTO = "crypto",
}
export enum AssetCodeEnum {
USDT = "USDT",
OPTS = "OPTS",
}

10
src/api/types.ts Normal file
View File

@@ -0,0 +1,10 @@
import type { Treaty } from "@elysiajs/eden";
import type { client } from ".";
import type { AssetCodeEnum, PaymentChannelEnum } from "./enum";
export type DepositFiatBody = Parameters<typeof client.api.asset.deposit.fiat.post>[0] & {
paymentChannel: PaymentChannelEnum;
assetCode: AssetCodeEnum;
};
export type DepositFiatData = Treaty.Data<typeof client.api.asset.deposit.fiat.post>;

View File

@@ -40,6 +40,10 @@ const routes: Array<RouteRecordRaw> = [
path: "/onchain-address",
component: () => import("@/views/onchain-address/index.vue"),
},
{
path: "/deposit/fiat",
component: () => import("@/views/deposit/fiat.vue"),
},
];
const router = createRouter({

View File

@@ -1,2 +1,3 @@
export type PageInstance = InstanceType<typeof import("@ionic/vue").IonPage>;
export type InputInstance = InstanceType<typeof import("@ionic/vue").IonInput>;
export type ModalInstance = InstanceType<typeof import("@ionic/vue").IonModal>;

View File

@@ -0,0 +1,71 @@
<script lang='ts' setup>
import type { DepositFiatBody } from "@/api/types";
import { AssetCodeEnum, PaymentChannelEnum } from "@/api/enum";
const form = ref<DepositFiatBody>({
amount: "",
assetCode: AssetCodeEnum.USDT,
paymentChannel: PaymentChannelEnum.FIAT,
});
const inputInstance = useTemplateRef<InputInstance>("inputInstance");
function markTouched() {
inputInstance.value?.$el.classList.add("ion-touched");
}
function validate(value: string) {
inputInstance.value?.$el.classList.remove("ion-valid");
inputInstance.value?.$el.classList.remove("ion-invalid");
if (value === "") {
return false;
}
const isEmailValid = emailPattern.test(form.value.amount);
isEmailValid ? inputInstance.value?.$el.classList.add("ion-valid") : inputInstance.value?.$el.classList.add("ion-invalid");
return isEmailValid;
}
</script>
<template>
<ion-page>
<IonHeader>
<ion-toolbar class="ui-toolbar">
<ion-buttons slot="start">
<ion-back-button />
</ion-buttons>
<ion-title>Fiat Recharge</ion-title>
</ion-toolbar>
</IonHeader>
<IonContent :fullscreen="true" class="ion-padding">
<div class="flex flex-col gap-10px">
<ui-input-label
label="Recharge bank card account"
model-value="74321329321312"
type="number"
readonly
disabled
/>
<ion-select v-model="form.assetCode" label="Select Currency" placeholder="Select One" label-placement="floating">
<ion-select-option v-for="item in AssetCodeEnum" :key="item" :value="item">
{{ item }}
</ion-select-option>
</ion-select>
<ui-input-label
ref="inputInstance"
v-model="form.amount"
label="Amount"
placeholder="Enter the amount"
type="number"
error-text="Please enter a valid amount."
@ion-input="validate($event.target.value as string)"
@ion-blur="markTouched"
/>
</div>
</IonContent>
</ion-page>
</template>
<style lang='css' scoped></style>

View File

@@ -1,6 +1,14 @@
<script lang='ts' setup>
import IcBaselineDataUsage from "~icons/ic/baseline-data-usage";
import IcBaselineDownloading from "~icons/ic/baseline-downloading";
const emit = defineEmits<{
(e: "close"): void;
}>();
const router = useRouter();
async function handleFiatRecharge() {
emit("close");
router.push("/deposit/fiat");
}
</script>
<template>
@@ -16,7 +24,7 @@ import IcBaselineDownloading from "~icons/ic/baseline-downloading";
<i-ic-round-arrow-forward-ios class="ml-auto color-text-400" />
</div>
<div class="flex items-center gap-10px">
<div class="flex items-center gap-10px" @click="handleFiatRecharge">
<i-ic-baseline-data-saver-off class="text-2xl" />
<ion-label class="flex-1">
<h2>Fiat currency</h2>
@@ -29,8 +37,4 @@ import IcBaselineDownloading from "~icons/ic/baseline-downloading";
</div>
</template>
<style lang='css' scoped>
.list {
--background: transparent;
}
</style>
<style lang='css' scoped></style>

View File

@@ -1,17 +1,17 @@
<script lang='ts' setup>
import { modalController } from "@ionic/vue";
import { client } from "@/api";
import RechargeChannel from "./recharge-channel.vue";
const { t } = useI18n();
const { data } = await client.api.asset.balances.get();
const rechargeInstance = ref<ModalInstance>();
function onCloseModal() {
rechargeInstance.value?.$el.dismiss(null, "confirm");
}
</script>
<template>
<ion-modal class="recharge-channel-modal" trigger="open-modal" :initial-breakpoint="1" :breakpoints="[0]">
<RechargeChannel />
</ion-modal>
<div class="mt-20px">
<div class="grid grid-cols-2 gap-20px p-20px bg-[var(--ion-card-background)] rounded-t-6px">
<div v-for="item in data" :key="item.assetCode" class="flex flex-col gap-4px">
@@ -36,6 +36,10 @@ const { data } = await client.api.asset.balances.get();
</ion-buttons>
</div>
</div>
<ion-modal ref="rechargeInstance" class="recharge-channel-modal" trigger="open-modal" :initial-breakpoint="1" :breakpoints="[0, 1]">
<RechargeChannel @close="onCloseModal" />
</ion-modal>
</template>
<style scoped>