diff --git a/apps/player/src/components/FloatingMailbox.vue b/apps/player/src/components/FloatingMailbox.vue index f5d0b6c..3fcb4aa 100644 --- a/apps/player/src/components/FloatingMailbox.vue +++ b/apps/player/src/components/FloatingMailbox.vue @@ -320,21 +320,22 @@ onMounted(() => { width: 56px; height: 56px; border-radius: 50%; - background: var(--primary); - color: #fff; - border: none; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + background: #0A3558; + color: rgba(255, 255, 255, 0.92); + border: 1px solid rgba(255, 255, 255, 0.2); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); display: flex; align-items: center; justify-content: center; cursor: pointer; - transition: transform 0.2s, background 0.2s; + transition: transform 0.2s, background 0.2s, border-color 0.2s; position: relative; } .fab-btn:hover { transform: scale(1.05); - background: var(--primary-light); + background: #0F4068; + border-color: rgba(255, 255, 255, 0.28); } .fab-active { @@ -356,7 +357,7 @@ onMounted(() => { font-weight: 700; padding: 2px 6px; border-radius: 10px; - border: 2px solid var(--bg-card); + border: 2px solid #0A3558; line-height: 1; } @@ -383,8 +384,9 @@ onMounted(() => { justify-content: space-between; padding: 0 12px; border-bottom: 1px solid var(--border); - background: rgba(255, 255, 255, 0.02); + background: #001A33; height: 48px; + flex-shrink: 0; } .popup-title { @@ -440,10 +442,13 @@ onMounted(() => { } .popup-body { - height: calc(100% - 48px); + flex: 1; + min-height: 0; position: relative; - background: var(--bg-body); + background: #0A2540; overflow-y: auto; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; } .panel-content { diff --git a/apps/player/src/components/MessageListPanel.vue b/apps/player/src/components/MessageListPanel.vue index c84cf4d..5bb97ba 100644 --- a/apps/player/src/components/MessageListPanel.vue +++ b/apps/player/src/components/MessageListPanel.vue @@ -1,6 +1,5 @@ + + + + + + + + + {{ t('common.load_failed') }} + + {{ t('common.retry') }} + + + + + + {{ detail.betNo }} + {{ statusLabel(detail.status) }} + + + {{ t('bet.stake') }} + {{ formatMoney(detail.stake, locale) }} + + + {{ t('bet.potential_payout') }} + {{ detail.potentialReturn ? formatMoney(detail.potentialReturn, locale) : '-' }} + + + {{ t('bet.placed_at') }} + {{ detail.placedAt ? new Date(detail.placedAt).toLocaleString() : '-' }} + + + + + + {{ t('bet.selections') }} + + {{ leg.matchTitle || t('bet.match') }} + + {{ leg.marketLabel || '' }} + {{ translateSel(leg.selectionName || '') }} + @{{ leg.odds }} + ({{ t('history.ft') }}: {{ leg.score.ft }}) + + + + + + {{ t('common.not_found') }} + + + + diff --git a/apps/player/src/components/desktop/DesktopCashbackDetailModal.vue b/apps/player/src/components/desktop/DesktopCashbackDetailModal.vue new file mode 100644 index 0000000..d93711c --- /dev/null +++ b/apps/player/src/components/desktop/DesktopCashbackDetailModal.vue @@ -0,0 +1,147 @@ + + + + + + + {{ formatMoney(record.amount, locale) }} + {{ record.batchNo }} + + + + + {{ t('cashback.period') }} + {{ formatPeriod(record.periodStart, record.periodEnd) }} + + + {{ t('cashback.effective_stake') }} + {{ formatMoneyCompact(record.effectiveStake, locale) }} + + + {{ t('cashback.rate') }} + {{ formatRate(record.rate) }} + + + {{ t('wallet.time') }} + {{ formatTime(record.confirmedAt ?? record.createdAt) }} + + + + + {{ t('common.not_found') }} + + + + diff --git a/apps/player/src/components/desktop/DesktopDetailModalShell.vue b/apps/player/src/components/desktop/DesktopDetailModalShell.vue new file mode 100644 index 0000000..f9b87dd --- /dev/null +++ b/apps/player/src/components/desktop/DesktopDetailModalShell.vue @@ -0,0 +1,141 @@ + + + + + + + + + {{ title }} + + × + + + + + + + + + + + + diff --git a/apps/player/src/components/desktop/DesktopRechargeDetailModal.vue b/apps/player/src/components/desktop/DesktopRechargeDetailModal.vue new file mode 100644 index 0000000..ea82d91 --- /dev/null +++ b/apps/player/src/components/desktop/DesktopRechargeDetailModal.vue @@ -0,0 +1,392 @@ + + + + + + + {{ detail.orderNo }} + {{ statusLabel(detail.status) }} + + + {{ t('wallet.amount') }} + {{ formatMoney(detail.amount, locale) }} + + + {{ t('recharge.credited') }} + {{ formatMoney(detail.approvedAmount, locale) }} + + + {{ t('recharge.method') }} + {{ methodLabel(detail) }} + + + {{ t('recharge.apply_time') }} + {{ new Date(detail.createdAt).toLocaleString() }} + + + {{ t('recharge.review_time') }} + {{ new Date(detail.reviewedAt).toLocaleString() }} + + + + {{ orderNoteLine(detail) }} + + + {{ t('recharge.reapply') }} + + + + + {{ t('recharge.audit_title') }} + + + + + + + + + {{ auditActionLabel(entry.log.action) }} + {{ formatAuditTime(entry.log.createdAt) }} + + {{ entry.actor }} + + {{ t('recharge.audit_credited') }} {{ formatMoney(entry.log.approvedAmount, locale) }} + + + {{ t('recharge.reject_reason') }} + {{ entry.remark.text }} + + + {{ auditNoteDisplayText(entry.remark) }} + + + + + + + + {{ t('common.not_found') }} + + + + diff --git a/apps/player/src/components/desktop/DesktopTxDetailModal.vue b/apps/player/src/components/desktop/DesktopTxDetailModal.vue new file mode 100644 index 0000000..4027fad --- /dev/null +++ b/apps/player/src/components/desktop/DesktopTxDetailModal.vue @@ -0,0 +1,292 @@ + + + + + + + + + + {{ t('common.load_failed') }} + + {{ t('common.retry') }} + + + + + + + {{ formatMoney(detail.amount, locale) }} + + {{ txLabel(detail) }} + + + + + {{ t('wallet.note') }} + {{ txSummaryLabel(detail, t) || '-' }} + + + {{ t('wallet.balance_before') }} + {{ formatMoney(detail.balanceBefore, locale) }} + + + {{ t('wallet.balance_after') }} + {{ formatMoney(detail.balanceAfter, locale) }} + + + {{ t('wallet.detail_frozen_before') }} + {{ formatMoney(detail.frozenBefore, locale) }} + + + {{ t('wallet.detail_frozen_after') }} + {{ formatMoney(detail.frozenAfter, locale) }} + + + {{ t('wallet.time') }} + {{ new Date(detail.createdAt).toLocaleString() }} + + + {{ t('wallet.transaction_id') }} + {{ detail.transactionId }} + + + + + + {{ t('wallet.detail_bet_link') }} · {{ betNo }} + + + {{ t('wallet.detail_cashback_link') }} · {{ cashbackBatchNo }} + + + + + {{ t('common.not_found') }} + + + + diff --git a/apps/player/src/styles/desktop/records.css b/apps/player/src/styles/desktop/records.css index 82e84a0..1005d23 100644 --- a/apps/player/src/styles/desktop/records.css +++ b/apps/player/src/styles/desktop/records.css @@ -19,8 +19,11 @@ gap: 20px 32px; flex-wrap: wrap; flex-shrink: 0; - padding-bottom: 14px; - border-bottom: 1px solid var(--border); + padding: 14px 18px; + background: var(--desktop-surface-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + box-shadow: var(--shadow); } .desktop-records-header-main { @@ -155,9 +158,10 @@ flex-direction: column; flex: 1; min-height: 0; - background: rgba(10, 37, 64, 0.94); + background: var(--desktop-surface-solid); border: 1px solid var(--border); - border-radius: 10px; + border-radius: var(--radius); + box-shadow: var(--shadow); overflow: hidden; } @@ -182,7 +186,7 @@ font-size: 11px; font-weight: 800; color: var(--text-muted); - background: #0A2540; + background: var(--desktop-surface-header); text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 1px solid var(--border); @@ -240,8 +244,8 @@ .desktop-records-pagination { flex-shrink: 0; padding: 12px 16px; - border-top: 1px solid rgba(255, 255, 255, 0.06); - background: rgba(0, 26, 51, 0.5); + border-top: 1px solid var(--border); + background: var(--desktop-surface-header); } .desktop-records-loading, diff --git a/apps/player/src/styles/desktop/tokens.css b/apps/player/src/styles/desktop/tokens.css index ac4fff0..b2d1ffe 100644 --- a/apps/player/src/styles/desktop/tokens.css +++ b/apps/player/src/styles/desktop/tokens.css @@ -1,3 +1,11 @@ +/* Teleport 弹窗挂在 body 下,须用 :root 暴露实心色 */ +:root { + --desktop-surface-solid: #0A2540; + --desktop-surface-elevated: #0A3558; + --desktop-surface-header: #001A33; + --desktop-border: rgba(255, 255, 255, 0.1); +} + .desktop-shell { /* Color Palette overrides */ --primary: rgba(255, 255, 255, 0.92); @@ -36,6 +44,9 @@ --desktop-border: rgba(255, 255, 255, 0.1); --desktop-sidebar-bg: rgba(10, 37, 64, 0.95); --desktop-sidebar-panel-bg: linear-gradient(rgba(0, 26, 51, 0.88), rgba(0, 26, 51, 0.88)); + --desktop-surface-solid: #0A2540; + --desktop-surface-elevated: #0A3558; + --desktop-surface-header: #001A33; /* Reset typography inside desktop */ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; diff --git a/apps/player/src/utils/depositOrderLookup.ts b/apps/player/src/utils/depositOrderLookup.ts new file mode 100644 index 0000000..0b1d1d6 --- /dev/null +++ b/apps/player/src/utils/depositOrderLookup.ts @@ -0,0 +1,63 @@ +import api from '../api'; + +export type DepositAuditLog = { + id: string; + action: string; + actorType: string; + statusBefore: string | null; + statusAfter: string; + amount: string | null; + approvedAmount: string | null; + remark: string | null; + createdAt: string; +}; + +export type PlayerDepositOrder = { + id: string; + orderNo: string; + paymentMethodId?: string; + methodType: string; + amount: string; + status: string; + approvedAmount: string | null; + rejectReason: string | null; + remark: string | null; + createdAt: string; + reviewedAt: string | null; + paymentMethodName: string | null; + bankName?: string | null; + auditLogs?: DepositAuditLog[]; +}; + +export async function fetchDepositOrderAuditLogs(orderId: string): Promise { + try { + const { data } = await api.get(`/player/deposit-orders/${orderId}/audit-logs`); + const items = data.data?.items ?? data.data ?? []; + return Array.isArray(items) ? (items as DepositAuditLog[]) : []; + } catch { + return []; + } +} + +export async function enrichDepositOrder(order: PlayerDepositOrder): Promise { + if (order.auditLogs?.length) return order; + const auditLogs = await fetchDepositOrderAuditLogs(order.id); + return auditLogs.length ? { ...order, auditLogs } : order; +} + +export async function findDepositOrderById(orderId: string): Promise { + let page = 1; + const pageSize = 20; + + while (true) { + const { data } = await api.get('/player/deposit-orders', { params: { page, pageSize } }); + const result = data.data ?? { items: [], total: 0, pageSize }; + const items = (result.items ?? []) as PlayerDepositOrder[]; + const found = items.find((order) => order.id === orderId); + if (found) return enrichDepositOrder(found); + + const total = result.total ?? 0; + if (!items.length || page * pageSize >= total) return null; + page += 1; + } +} diff --git a/apps/player/src/views/BetDetailView.vue b/apps/player/src/views/BetDetailView.vue index 436662d..6cab81c 100644 --- a/apps/player/src/views/BetDetailView.vue +++ b/apps/player/src/views/BetDetailView.vue @@ -1,9 +1,23 @@ + diff --git a/apps/player/src/views/MobileInboxHubView.vue b/apps/player/src/views/MobileInboxHubView.vue index 97753fd..bc99e57 100644 --- a/apps/player/src/views/MobileInboxHubView.vue +++ b/apps/player/src/views/MobileInboxHubView.vue @@ -159,7 +159,11 @@ onActivated(() => { - + router.push(`/messages/${id}`)" + /> +import { onMounted } from 'vue'; +import { useRoute, useRouter } from 'vue-router'; import { useViewport } from '../composables/useViewport'; import MobileRechargeDetailView from './MobileRechargeDetailView.vue'; import DesktopRechargeDetailView from './desktop/DesktopRechargeDetailView.vue'; +const route = useRoute(); +const router = useRouter(); const { isDesktop } = useViewport(); + +onMounted(() => { + if (!isDesktop.value) return; + const id = route.params.id; + if (id) { + void router.replace({ + path: '/wallet/recharge/history', + query: { orderId: String(id) }, + }); + } +}); diff --git a/apps/player/src/views/WalletTransactionDetailView.vue b/apps/player/src/views/WalletTransactionDetailView.vue index d2616df..4233a6f 100644 --- a/apps/player/src/views/WalletTransactionDetailView.vue +++ b/apps/player/src/views/WalletTransactionDetailView.vue @@ -1,9 +1,26 @@ + diff --git a/apps/player/src/views/desktop/DesktopCashbackRecordsView.vue b/apps/player/src/views/desktop/DesktopCashbackRecordsView.vue index 7e79a7c..bec6d41 100644 --- a/apps/player/src/views/desktop/DesktopCashbackRecordsView.vue +++ b/apps/player/src/views/desktop/DesktopCashbackRecordsView.vue @@ -1,22 +1,50 @@ @@ -113,7 +147,12 @@ onActivated(loadData); - + {{ formatPeriod(row.periodStart, row.periodEnd) }} {{ formatMoneyCompact(row.effectiveStake, locale) }} {{ formatRate(row.rate) }} @@ -140,6 +179,8 @@ onActivated(loadData); /> + + diff --git a/apps/player/src/views/desktop/DesktopMyBetsView.vue b/apps/player/src/views/desktop/DesktopMyBetsView.vue index 67a7c8a..a3a2188 100644 --- a/apps/player/src/views/desktop/DesktopMyBetsView.vue +++ b/apps/player/src/views/desktop/DesktopMyBetsView.vue @@ -1,18 +1,42 @@ @@ -94,7 +116,7 @@ onActivated(() => loadPage(1)); v-for="tx in items" :key="tx.transactionId" class="hover-row clickable-row" - @click="router.push(`/wallet/transactions/${tx.transactionId}`)" + @click="openDetail(tx.transactionId)" > {{ txLabel(tx) }} {{ txSummaryLabel(tx, t) || '-' }} @@ -118,6 +140,11 @@ onActivated(() => loadPage(1)); + + @@ -146,10 +173,10 @@ onActivated(() => loadPage(1)); flex-direction: column; flex: 0 1 auto; min-height: 0; - background: var(--bg-card); - backdrop-filter: blur(12px); - border: 1px solid rgba(255, 255, 255, 0.08); + background: var(--desktop-surface-solid); + border: 1px solid var(--border); border-radius: 8px; + box-shadow: var(--shadow); overflow: hidden; } .table-wrap { flex: 1; overflow-x: auto; overflow-y: auto; } @@ -163,7 +190,7 @@ onActivated(() => loadPage(1)); font-size: 11px; font-weight: 700; color: var(--text-muted); - background: #0A2540; + background: var(--desktop-surface-header); text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 1px solid var(--desktop-border); diff --git a/apps/player/src/views/desktop/DesktopWalletTransactionDetailView.vue b/apps/player/src/views/desktop/DesktopWalletTransactionDetailView.vue index 1dcaab4..d170d05 100644 --- a/apps/player/src/views/desktop/DesktopWalletTransactionDetailView.vue +++ b/apps/player/src/views/desktop/DesktopWalletTransactionDetailView.vue @@ -109,11 +109,11 @@ function txLabel(tx: TxDetail): string { {{ formatMoney(detail.balanceAfter, locale) }} - {{ t('wallet.frozen_before') || '冻结前' }} + {{ t('wallet.detail_frozen_before') }} {{ formatMoney(detail.frozenBefore, locale) }} - {{ t('wallet.frozen_after') || '冻结后' }} + {{ t('wallet.detail_frozen_after') }} {{ formatMoney(detail.frozenAfter, locale) }} diff --git a/apps/player/src/views/desktop/DesktopWalletView.vue b/apps/player/src/views/desktop/DesktopWalletView.vue index cd1ee4a..2fd60fe 100644 --- a/apps/player/src/views/desktop/DesktopWalletView.vue +++ b/apps/player/src/views/desktop/DesktopWalletView.vue @@ -1,17 +1,25 @@
{{ t('common.load_failed') }}
{{ entry.actor }}
+ {{ t('recharge.audit_credited') }} {{ formatMoney(entry.log.approvedAmount, locale) }} +
+ {{ auditNoteDisplayText(entry.remark) }} +