新增:充值二维码

This commit is contained in:
lanxi 2026-03-09 15:02:12 +08:00
parent 50e451e892
commit fe1c6e8ad0
4 changed files with 106 additions and 6 deletions

2
.env
View File

@ -1,6 +1,6 @@
# API 基础地址,不设置时默认 https://api.xtrader.vip # API 基础地址,不设置时默认 https://api.xtrader.vip
# 连接测试服务器 192.168.3.21:8888 时复制本文件为 .env 或 .env.local 并取消下一行注释: # 连接测试服务器 192.168.3.21:8888 时复制本文件为 .env 或 .env.local 并取消下一行注释:
# VITE_API_BASE_URL=http://10.117.63.212:8888 VITE_API_BASE_URL=http://localhost:8888
# SSH 部署npm run deploy可选覆盖 # SSH 部署npm run deploy可选覆盖
# DEPLOY_HOST=38.246.250.238 # DEPLOY_HOST=38.246.250.238

View File

@ -158,7 +158,7 @@ function encodeFunctionCall(abiFragment: string, args: any[]): string {
data += addr.padStart(64, '0'); data += addr.padStart(64, '0');
// 数量参数补零到32字节 // 数量参数补零到32字节
let amount = BigInt(args[1]).toString(16); const amount = BigInt(args[1]).toString(16);
data += amount.padStart(64, '0'); data += amount.padStart(64, '0');
return data; return data;

51
src/api/wallet.ts Normal file
View File

@ -0,0 +1,51 @@
import { get } from './request'
export interface DepositAddressData {
address?: string
depositAddress?: string
tokenAddress?: string
walletAddress?: string
[key: string]: unknown
}
export interface DepositAddressResponse {
code: number
data?: DepositAddressData
msg?: string
}
export interface GetDepositAddressParams {
chain: string
tokenSymbol?: string
}
function pickAddress(d: DepositAddressData | undefined): string | undefined {
if (!d) return undefined
return (
(d.walletAddress as string | undefined) ??
(d.externalWalletAddress as string | undefined) ??
(d.depositAddress as string | undefined) ??
(d.tokenAddress as string | undefined) ??
(d.address as string | undefined)
)
}
export async function getDepositAddress(
params: GetDepositAddressParams,
config?: { headers?: Record<string, string> },
): Promise<{ ok: boolean; address?: string; raw?: DepositAddressResponse }> {
const paths = ['/pmset/getDepositAddress', '/wallet/getDepositAddress', '/pmset/getDepositAddressClient']
for (const p of paths) {
try {
const res = await get<DepositAddressResponse>(p, params as any, config)
const codeOk = res.code === 0 || res.code === 200
const addr = pickAddress(res.data)
if (codeOk && addr && typeof addr === 'string' && addr.length > 0) {
return { ok: true, address: addr, raw: res }
}
} catch {
}
}
return { ok: false }
}

View File

@ -147,6 +147,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch } from 'vue' import { ref, computed, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { getDepositAddress } from '@/api/wallet'
import { useUserStore } from '@/stores/user'
const { t } = useI18n() const { t } = useI18n()
const props = withDefaults( const props = withDefaults(
@ -158,7 +160,10 @@ const props = withDefaults(
) )
const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>() const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>()
const DEPOSIT_ADDRESS = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e' const userStore = useUserStore()
const depositAddress = ref('')
const loading = ref(false)
const loadError = ref('')
const step = ref<'method' | 'crypto' | 'exchange'>('method') const step = ref<'method' | 'crypto' | 'exchange'>('method')
const selectedNetwork = ref('ethereum') const selectedNetwork = ref('ethereum')
@ -174,12 +179,12 @@ const networks = [
] ]
const depositAddressShort = computed(() => { const depositAddressShort = computed(() => {
const a = DEPOSIT_ADDRESS const a = depositAddress.value
return a ? `${a.slice(0, 6)}...${a.slice(-4)}` : '' return a ? `${a.slice(0, 6)}...${a.slice(-4)}` : ''
}) })
const qrCodeUrl = computed(() => { const qrCodeUrl = computed(() => {
return `https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=${encodeURIComponent(DEPOSIT_ADDRESS)}` return `https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=${encodeURIComponent(depositAddress.value)}`
}) })
function close() { function close() {
@ -189,11 +194,13 @@ function close() {
function selectMethod(m: 'crypto' | 'exchange') { function selectMethod(m: 'crypto' | 'exchange') {
step.value = m step.value = m
if (m === 'exchange') exchangeConnected.value = false if (m === 'exchange') exchangeConnected.value = false
if (m === 'crypto') fetchAddress()
} }
async function copyAddress() { async function copyAddress() {
try { try {
await navigator.clipboard.writeText(DEPOSIT_ADDRESS) if (!depositAddress.value) return
await navigator.clipboard.writeText(depositAddress.value)
copied.value = true copied.value = true
setTimeout(() => { setTimeout(() => {
copied.value = false copied.value = false
@ -219,15 +226,57 @@ async function connectMetaMask() {
} }
} }
async function fetchAddress() {
loading.value = true
loadError.value = ''
try {
if (!userStore.user) {
await userStore.fetchUserInfo?.()
}
const u = userStore.user as Record<string, unknown> | null
const userAddr =
(u?.walletAddress as string | undefined) ||
(u?.externalWalletAddress as string | undefined)
if (userAddr && typeof userAddr === 'string' && userAddr.length > 0) {
depositAddress.value = userAddr
return
}
const headers = userStore.getAuthHeaders?.()
const resApi = await getDepositAddress(
{ chain: selectedNetwork.value, tokenSymbol: 'USDC' },
headers ? { headers } : undefined,
)
if (resApi.ok && resApi.address) {
depositAddress.value = resApi.address
return
}
depositAddress.value = ''
loadError.value = 'failed'
} catch {
loadError.value = 'failed'
} finally {
loading.value = false
}
}
watch( watch(
() => props.modelValue, () => props.modelValue,
(open) => { (open) => {
if (!open) { if (!open) {
step.value = 'method' step.value = 'method'
exchangeConnected.value = false exchangeConnected.value = false
depositAddress.value = ''
loadError.value = ''
loading.value = false
} else {
if (step.value === 'crypto') fetchAddress()
} }
}, },
) )
watch(selectedNetwork, () => {
if (step.value === 'crypto') fetchAddress()
})
</script> </script>
<style scoped> <style scoped>