feat: 更新环境配置,修改 API 地址和版本,添加充值页面,集成支付方式选择和表单验证
This commit is contained in:
@@ -1 +1 @@
|
|||||||
VITE_API_URL=http://192.168.1.7:9527
|
VITE_API_URL=http://192.168.1.2:9538
|
||||||
14
pnpm-lock.yaml
generated
14
pnpm-lock.yaml
generated
@@ -52,8 +52,8 @@ catalogs:
|
|||||||
specifier: 8.0.0
|
specifier: 8.0.0
|
||||||
version: 8.0.0
|
version: 8.0.0
|
||||||
'@capp/eden':
|
'@capp/eden':
|
||||||
specifier: http://192.168.1.2:9538/api/capp-eden-0.0.6.tgz
|
specifier: http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz
|
||||||
version: 0.0.6
|
version: 0.0.7
|
||||||
'@cloudflare/workers-types':
|
'@cloudflare/workers-types':
|
||||||
specifier: ^4.20260113.0
|
specifier: ^4.20260113.0
|
||||||
version: 4.20260116.0
|
version: 4.20260116.0
|
||||||
@@ -298,7 +298,7 @@ importers:
|
|||||||
version: 8.0.0(@capacitor/core@8.0.0)
|
version: 8.0.0(@capacitor/core@8.0.0)
|
||||||
'@capp/eden':
|
'@capp/eden':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: http://192.168.1.2:9538/api/capp-eden-0.0.6.tgz(@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)))
|
version: http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz(@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)))
|
||||||
'@elysiajs/eden':
|
'@elysiajs/eden':
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))
|
version: 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))
|
||||||
@@ -1182,9 +1182,9 @@ packages:
|
|||||||
'@capacitor/synapse@1.0.4':
|
'@capacitor/synapse@1.0.4':
|
||||||
resolution: {integrity: sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==}
|
resolution: {integrity: sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==}
|
||||||
|
|
||||||
'@capp/eden@http://192.168.1.2:9538/api/capp-eden-0.0.6.tgz':
|
'@capp/eden@http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz':
|
||||||
resolution: {tarball: http://192.168.1.2:9538/api/capp-eden-0.0.6.tgz}
|
resolution: {tarball: http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz}
|
||||||
version: 0.0.6
|
version: 0.0.7
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@elysiajs/eden': ^1.4.6
|
'@elysiajs/eden': ^1.4.6
|
||||||
|
|
||||||
@@ -6903,7 +6903,7 @@ snapshots:
|
|||||||
|
|
||||||
'@capacitor/synapse@1.0.4': {}
|
'@capacitor/synapse@1.0.4': {}
|
||||||
|
|
||||||
'@capp/eden@http://192.168.1.2:9538/api/capp-eden-0.0.6.tgz(@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)))':
|
'@capp/eden@http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz(@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@elysiajs/eden': 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))
|
'@elysiajs/eden': 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ catalog:
|
|||||||
'@capacitor/keyboard': 8.0.0
|
'@capacitor/keyboard': 8.0.0
|
||||||
'@capacitor/share': ^8.0.0
|
'@capacitor/share': ^8.0.0
|
||||||
'@capacitor/status-bar': 8.0.0
|
'@capacitor/status-bar': 8.0.0
|
||||||
'@capp/eden': http://192.168.1.2:9538/api/capp-eden-0.0.6.tgz
|
'@capp/eden': http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz
|
||||||
'@cloudflare/workers-types': ^4.20260113.0
|
'@cloudflare/workers-types': ^4.20260113.0
|
||||||
'@elysiajs/eden': ^1.4.6
|
'@elysiajs/eden': ^1.4.6
|
||||||
'@faker-js/faker': ^10.2.0
|
'@faker-js/faker': ^10.2.0
|
||||||
|
|||||||
@@ -99,6 +99,11 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: () => import("@/views/asset_details/index.vue"),
|
component: () => import("@/views/asset_details/index.vue"),
|
||||||
meta: { requiresAuth: true },
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/recharge",
|
||||||
|
component: () => import("@/views/recharge/index.vue"),
|
||||||
|
meta: { requiresAuth: true },
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
<script lang='ts' setup>
|
<script lang='ts' setup>
|
||||||
|
import type { Treaty } from "@elysiajs/eden";
|
||||||
|
import type { InfiniteScrollCustomEvent } from "@ionic/vue";
|
||||||
|
import type { TreatyQuery } from "@/api/types";
|
||||||
import {
|
import {
|
||||||
calendarOutline,
|
calendarOutline,
|
||||||
cardOutline,
|
cardOutline,
|
||||||
@@ -7,54 +10,35 @@ import {
|
|||||||
trendingUpOutline,
|
trendingUpOutline,
|
||||||
walletOutline,
|
walletOutline,
|
||||||
} from "ionicons/icons";
|
} from "ionicons/icons";
|
||||||
|
import { client, safeClient } from "@/api";
|
||||||
|
|
||||||
// 基金产品数据
|
type Product = Treaty.Data<typeof client.api.subscription.products.get>["data"][number];
|
||||||
const fundProducts = ref([
|
type ProductQuery = TreatyQuery<typeof client.api.subscription.products.get>;
|
||||||
{
|
|
||||||
id: 1,
|
const [query] = useResetRef<ProductQuery>({
|
||||||
name: "稳健增长基金",
|
offset: 0,
|
||||||
endTime: "2026-01-25 23:59",
|
limit: 10,
|
||||||
image: "https://picsum.photos/seed/fund1/200/200",
|
});
|
||||||
currentPrice: 1.258,
|
const data = ref<Product[]>([]);
|
||||||
expectedReturn: "15.8%",
|
const isFinished = ref(false);
|
||||||
period: "90天",
|
|
||||||
tag: "稳健",
|
async function fetchData() {
|
||||||
tagColor: "#1890ff",
|
const { data: responseData } = await safeClient(client.api.subscription.products.get({ query: { ...query.value } }));
|
||||||
},
|
data.value.push(...(responseData.value?.data || []));
|
||||||
{
|
isFinished.value = responseData.value?.pagination.hasNextPage === false;
|
||||||
id: 2,
|
}
|
||||||
name: "积极进取基金",
|
async function handleInfinite(event: InfiniteScrollCustomEvent) {
|
||||||
endTime: "2026-01-28 23:59",
|
if (isFinished.value) {
|
||||||
image: "https://picsum.photos/seed/fund2/200/200",
|
event.target.complete();
|
||||||
currentPrice: 1.482,
|
event.target.disabled = true;
|
||||||
expectedReturn: "22.5%",
|
return;
|
||||||
period: "180天",
|
}
|
||||||
tag: "积极",
|
query.value.offset! += query.value.limit!;
|
||||||
tagColor: "#c41e3a",
|
await fetchData();
|
||||||
},
|
setTimeout(() => {
|
||||||
{
|
event.target.complete();
|
||||||
id: 3,
|
}, 500);
|
||||||
name: "均衡配置基金",
|
}
|
||||||
endTime: "2026-02-01 23:59",
|
|
||||||
image: "https://picsum.photos/seed/fund3/200/200",
|
|
||||||
currentPrice: 1.356,
|
|
||||||
expectedReturn: "18.6%",
|
|
||||||
period: "120天",
|
|
||||||
tag: "均衡",
|
|
||||||
tagColor: "#52c41a",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: "价值投资基金",
|
|
||||||
endTime: "2026-02-05 23:59",
|
|
||||||
image: "https://picsum.photos/seed/fund4/200/200",
|
|
||||||
currentPrice: 1.189,
|
|
||||||
expectedReturn: "16.2%",
|
|
||||||
period: "90天",
|
|
||||||
tag: "价值",
|
|
||||||
tagColor: "#faad14",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
function handleProductClick(product: any) {
|
function handleProductClick(product: any) {
|
||||||
console.log("查看产品:", product.name);
|
console.log("查看产品:", product.name);
|
||||||
@@ -86,22 +70,22 @@ function handleSubscribe(product: any, event: Event) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-4">
|
<empty v-if="data.length === 0" message="暂无基金产品信息" />
|
||||||
|
<div v-else class="flex flex-col gap-4">
|
||||||
<div
|
<div
|
||||||
v-for="product in fundProducts"
|
v-for="product in data"
|
||||||
:key="product.id"
|
:key="product.id"
|
||||||
class="bg-white rounded-2xl overflow-hidden shadow-sm cursor-pointer transition-all active:translate-y-0.5 active:shadow-sm flex"
|
class="bg-white rounded-2xl overflow-hidden shadow-sm cursor-pointer transition-all active:translate-y-0.5 active:shadow-sm flex"
|
||||||
@click="handleProductClick(product)"
|
@click="handleProductClick(product)"
|
||||||
>
|
>
|
||||||
<!-- 左侧缩略图 -->
|
<!-- 左侧缩略图 -->
|
||||||
<div class="relative w-28 h-36 flex-shrink-0 overflow-hidden bg-gradient-to-br from-[#f5f5f5] to-[#e8e8e8]">
|
<div class="relative w-28 h-36 shrink-0 overflow-hidden bg-linear-to-br from-[#f5f5f5] to-[#e8e8e8]">
|
||||||
<img :src="product.image" :alt="product.name" class="w-full h-full object-cover">
|
<img :src="product.image" :alt="product.name" class="w-full h-full object-cover">
|
||||||
<div
|
<!-- <div
|
||||||
class="fund-tag absolute top-2 left-2 text-white px-2 py-0.5 rounded-lg text-xs font-semibold shadow-lg"
|
class="fund-tag absolute top-2 left-2 text-white px-2 py-0.5 rounded-lg text-xs font-semibold shadow-lg"
|
||||||
:style="{ background: product.tagColor }"
|
|
||||||
>
|
>
|
||||||
{{ product.tag }}
|
{{ product.tag }}
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧信息 -->
|
<!-- 右侧信息 -->
|
||||||
@@ -112,27 +96,27 @@ function handleSubscribe(product: any, event: Event) {
|
|||||||
</h4>
|
</h4>
|
||||||
<div class="flex items-center gap-1 text-xs text-[#999] mb-2">
|
<div class="flex items-center gap-1 text-xs text-[#999] mb-2">
|
||||||
<ion-icon :icon="timeOutline" class="text-sm" />
|
<ion-icon :icon="timeOutline" class="text-sm" />
|
||||||
<span>申购截止:{{ product.endTime }}</span>
|
<span>申购截止:{{ product.subscribeEndAt }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 产品信息 -->
|
<!-- 产品信息 -->
|
||||||
<div class="grid grid-cols-3 gap-2 mb-2">
|
<div class="grid grid-cols-3 gap-2 mb-2">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-xs text-[#999]">当前价格</span>
|
<span class="text-xs text-[#999]">当前价格</span>
|
||||||
<span class="text-lg font-bold text-[#c41e3a]">¥{{ product.currentPrice }}</span>
|
<span class="text-lg font-bold text-[#c41e3a]">¥{{ product.price }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-xs text-[#999]">到期收益</span>
|
<span class="text-xs text-[#999]">到期收益</span>
|
||||||
<span class="text-lg font-bold text-[#52c41a] flex items-center gap-0.5">
|
<span class="text-lg font-bold text-[#52c41a] flex items-center gap-0.5">
|
||||||
<ion-icon :icon="trendingUpOutline" class="text-xs" />
|
<ion-icon :icon="trendingUpOutline" class="text-xs" />
|
||||||
{{ product.expectedReturn }}
|
{{ product.maturityYield }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="text-xs text-[#999]">产品周期</span>
|
<span class="text-xs text-[#999]">产品周期</span>
|
||||||
<span class="text-lg font-bold text-[#1a1a1a] flex items-center gap-0.5">
|
<span class="text-lg font-bold text-[#1a1a1a] flex items-center gap-0.5">
|
||||||
<ion-icon :icon="calendarOutline" class="text-xs" />
|
<ion-icon :icon="calendarOutline" class="text-xs" />
|
||||||
{{ product.period }}
|
{{ product.cycleDays }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
562
src/views/recharge/index.vue
Normal file
562
src/views/recharge/index.vue
Normal file
@@ -0,0 +1,562 @@
|
|||||||
|
<script lang='ts' setup>
|
||||||
|
import { alertController, toastController } from "@ionic/vue";
|
||||||
|
import { cardOutline, checkmarkCircleOutline, logoAlipay, logoWechat, walletOutline } from "ionicons/icons";
|
||||||
|
|
||||||
|
const walletStore = useWalletStore();
|
||||||
|
const { balanceWallet } = storeToRefs(walletStore);
|
||||||
|
|
||||||
|
interface PaymentMethod {
|
||||||
|
id: number;
|
||||||
|
type: "alipay" | "unionpay" | "wechat";
|
||||||
|
name: string;
|
||||||
|
account: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 充值金额
|
||||||
|
const rechargeAmount = ref("");
|
||||||
|
const quickAmounts = [100, 500, 1000, 2000];
|
||||||
|
|
||||||
|
// 选中的支付方式类型
|
||||||
|
const selectedPaymentType = ref<"alipay" | "unionpay" | "wechat" | null>(null);
|
||||||
|
|
||||||
|
// 选中的支付账号
|
||||||
|
const selectedPaymentId = ref<number | null>(null);
|
||||||
|
|
||||||
|
// 模拟支付方式数据
|
||||||
|
const paymentMethods = ref<PaymentMethod[]>([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
type: "alipay",
|
||||||
|
name: "张三的支付宝",
|
||||||
|
account: "138****8000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
type: "alipay",
|
||||||
|
name: "李四的支付宝",
|
||||||
|
account: "159****6666",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
type: "unionpay",
|
||||||
|
name: "工商银行",
|
||||||
|
account: "6222 **** **** 1234",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
type: "unionpay",
|
||||||
|
name: "建设银行",
|
||||||
|
account: "6217 **** **** 5678",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
type: "wechat",
|
||||||
|
name: "张三的微信",
|
||||||
|
account: "wxid_abc123",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 根据选中的支付方式类型筛选账号
|
||||||
|
const filteredPaymentMethods = computed(() => {
|
||||||
|
if (!selectedPaymentType.value) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return paymentMethods.value.filter(
|
||||||
|
pm => pm.type === selectedPaymentType.value,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 支付方式选项
|
||||||
|
const paymentTypes = [
|
||||||
|
{ type: "alipay" as const, name: "支付宝", icon: logoAlipay, color: "#1677FF" },
|
||||||
|
{ type: "unionpay" as const, name: "银联", icon: cardOutline, color: "#E31937" },
|
||||||
|
{ type: "wechat" as const, name: "微信", icon: logoWechat, color: "#07C160" },
|
||||||
|
];
|
||||||
|
|
||||||
|
function selectQuickAmount(amount: number) {
|
||||||
|
rechargeAmount.value = amount.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPaymentType(type: "alipay" | "unionpay" | "wechat") {
|
||||||
|
if (selectedPaymentType.value === type) {
|
||||||
|
selectedPaymentType.value = null;
|
||||||
|
selectedPaymentId.value = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectedPaymentType.value = type;
|
||||||
|
selectedPaymentId.value = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPaymentMethod(id: number) {
|
||||||
|
selectedPaymentId.value = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function showToast(message: string, color: "success" | "danger" | "warning" = "success") {
|
||||||
|
const toast = await toastController.create({
|
||||||
|
message,
|
||||||
|
duration: 2000,
|
||||||
|
position: "top",
|
||||||
|
color,
|
||||||
|
});
|
||||||
|
await toast.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
const amount = Number.parseFloat(rechargeAmount.value);
|
||||||
|
|
||||||
|
if (!rechargeAmount.value || Number.isNaN(amount) || amount <= 0) {
|
||||||
|
await showToast("请输入有效的充值金额", "warning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount < 10) {
|
||||||
|
await showToast("充值金额不能低于10元", "warning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selectedPaymentType.value) {
|
||||||
|
await showToast("请选择支付方式", "warning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selectedPaymentId.value) {
|
||||||
|
await showToast("请选择支付账号", "warning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const alert = await alertController.create({
|
||||||
|
header: "确认充值",
|
||||||
|
message: `确认充值 ¥${amount.toFixed(2)} 吗?`,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: "取消",
|
||||||
|
role: "cancel",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "确认",
|
||||||
|
handler: async () => {
|
||||||
|
// TODO: 调用充值 API
|
||||||
|
await showToast("充值成功");
|
||||||
|
// 重置表单
|
||||||
|
rechargeAmount.value = "";
|
||||||
|
selectedPaymentType.value = null;
|
||||||
|
selectedPaymentId.value = null;
|
||||||
|
// 刷新余额
|
||||||
|
walletStore.syncBalanceWallet();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await alert.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
walletStore.syncBalanceWallet();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ion-page>
|
||||||
|
<ion-header class="ion-no-border">
|
||||||
|
<ion-toolbar class="ion-toolbar">
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<back-button />
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>充值</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content>
|
||||||
|
<!-- 账户余额卡片 -->
|
||||||
|
<div class="balance-card">
|
||||||
|
<div class="balance-label">
|
||||||
|
<ion-icon :icon="walletOutline" class="label-icon" />
|
||||||
|
<span>当前账户余额</span>
|
||||||
|
</div>
|
||||||
|
<div class="balance-amount">
|
||||||
|
¥{{ balanceWallet?.balance?.toFixed(2) || '0.00' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 充值金额输入 -->
|
||||||
|
<div class="section-card">
|
||||||
|
<div class="section-title">
|
||||||
|
充值金额
|
||||||
|
</div>
|
||||||
|
<div class="amount-input-wrapper">
|
||||||
|
<span class="currency-symbol">¥</span>
|
||||||
|
<input
|
||||||
|
v-model="rechargeAmount"
|
||||||
|
type="number"
|
||||||
|
inputmode="decimal"
|
||||||
|
placeholder="请输入充值金额"
|
||||||
|
class="amount-input"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 快速选择金额 -->
|
||||||
|
<div class="quick-amounts">
|
||||||
|
<div
|
||||||
|
v-for="amount in quickAmounts"
|
||||||
|
:key="amount"
|
||||||
|
class="quick-amount-btn"
|
||||||
|
:class="{ active: rechargeAmount === amount.toString() }"
|
||||||
|
@click="selectQuickAmount(amount)"
|
||||||
|
>
|
||||||
|
¥{{ amount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="amount-hint">
|
||||||
|
<ion-icon :icon="checkmarkCircleOutline" class="hint-icon" />
|
||||||
|
最低充值金额为 ¥10
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 支付方式选择 -->
|
||||||
|
<div class="section-card">
|
||||||
|
<div class="section-title">
|
||||||
|
支付方式
|
||||||
|
</div>
|
||||||
|
<div class="payment-types">
|
||||||
|
<div
|
||||||
|
v-for="pt in paymentTypes"
|
||||||
|
:key="pt.type"
|
||||||
|
class="payment-type-item"
|
||||||
|
:class="{ active: selectedPaymentType === pt.type }"
|
||||||
|
@click="selectPaymentType(pt.type)"
|
||||||
|
>
|
||||||
|
<ion-icon
|
||||||
|
:icon="pt.icon"
|
||||||
|
class="payment-type-icon"
|
||||||
|
:style="{ color: selectedPaymentType === pt.type ? pt.color : '#999' }"
|
||||||
|
/>
|
||||||
|
<div class="payment-type-name">
|
||||||
|
{{ pt.name }}
|
||||||
|
</div>
|
||||||
|
<div v-if="selectedPaymentType === pt.type" class="payment-type-check">
|
||||||
|
<ion-icon :icon="checkmarkCircleOutline" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 支付账号选择 -->
|
||||||
|
<div v-if="selectedPaymentType" class="section-card">
|
||||||
|
<div class="section-title">
|
||||||
|
选择账号
|
||||||
|
</div>
|
||||||
|
<div v-if="filteredPaymentMethods.length > 0" class="payment-accounts">
|
||||||
|
<div
|
||||||
|
v-for="pm in filteredPaymentMethods"
|
||||||
|
:key="pm.id"
|
||||||
|
class="payment-account-item"
|
||||||
|
:class="{ active: selectedPaymentId === pm.id }"
|
||||||
|
@click="selectPaymentMethod(pm.id)"
|
||||||
|
>
|
||||||
|
<div class="account-info">
|
||||||
|
<div class="account-name">
|
||||||
|
{{ pm.name }}
|
||||||
|
</div>
|
||||||
|
<div class="account-number">
|
||||||
|
{{ pm.account }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="selectedPaymentId === pm.id" class="account-check">
|
||||||
|
<ion-icon :icon="checkmarkCircleOutline" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="no-accounts">
|
||||||
|
暂无可用的{{ paymentTypes.find(pt => pt.type === selectedPaymentType)?.name }}账号
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 提交按钮 -->
|
||||||
|
<div class="submit-wrapper">
|
||||||
|
<ion-button
|
||||||
|
expand="block"
|
||||||
|
class="submit-btn"
|
||||||
|
@click="handleSubmit"
|
||||||
|
>
|
||||||
|
立即充值
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 温馨提示 -->
|
||||||
|
<div class="notice-card">
|
||||||
|
<div class="notice-title">
|
||||||
|
温馨提示
|
||||||
|
</div>
|
||||||
|
<div class="notice-content">
|
||||||
|
<p>1. 充值金额将实时到账,请确认充值信息无误</p>
|
||||||
|
<p>2. 如充值后未到账,请联系客服处理</p>
|
||||||
|
<p>3. 充值金额最低10元,单笔最高50000元</p>
|
||||||
|
<p>4. 充值成功后可在资产明细中查看记录</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='css' scoped>
|
||||||
|
.balance-card {
|
||||||
|
background: linear-gradient(135deg, #c41e3a 0%, #8b1a2e 100%);
|
||||||
|
padding: 24px 20px;
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-amount {
|
||||||
|
color: white;
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-card {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-input-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.currency-symbol {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-input {
|
||||||
|
flex: 1;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-input::placeholder {
|
||||||
|
color: #bbb;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-amounts {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-amount-btn {
|
||||||
|
padding: 12px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #666;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-amount-btn:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-amount-btn.active {
|
||||||
|
background: rgba(196, 30, 58, 0.1);
|
||||||
|
border-color: #c41e3a;
|
||||||
|
color: #c41e3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-hint {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-types {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-type-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px 12px;
|
||||||
|
background: #fafafa;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-type-item:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-type-item.active {
|
||||||
|
background: white;
|
||||||
|
border-color: #c41e3a;
|
||||||
|
box-shadow: 0 2px 12px rgba(196, 30, 58, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-type-icon {
|
||||||
|
font-size: 36px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-type-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-type-check {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
color: #c41e3a;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-accounts {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-account-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px;
|
||||||
|
background: #fafafa;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-account-item:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-account-item.active {
|
||||||
|
background: white;
|
||||||
|
border-color: #c41e3a;
|
||||||
|
box-shadow: 0 2px 12px rgba(196, 30, 58, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-name {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-number {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-check {
|
||||||
|
color: #c41e3a;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-accounts {
|
||||||
|
text-align: center;
|
||||||
|
padding: 32px 20px;
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-wrapper {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
--background: linear-gradient(135deg, #c41e3a 0%, #8b1a2e 100%);
|
||||||
|
--background-hover: linear-gradient(135deg, #a81830 0%, #751627 100%);
|
||||||
|
--border-radius: 12px;
|
||||||
|
--box-shadow: 0 4px 12px rgba(196, 30, 58, 0.3);
|
||||||
|
height: 48px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-card {
|
||||||
|
background: #fffbe6;
|
||||||
|
border-left: 4px solid #faad14;
|
||||||
|
padding: 16px;
|
||||||
|
margin: 0 20px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #d48806;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #8c7a3e;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-content p {
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user