Files
olons_server/web/src/mobile/views/FinanceRecordsView.vue
T

121 lines
4.3 KiB
Vue

<template>
<section class="m-page m-page--white m-finance-records">
<PageHeader title="记录" />
<div class="m-finance-tabs" role="tablist">
<button
v-for="item in tabs"
:key="item.value"
:class="{ active: tab === item.value }"
@click="changeTab(item.value)"
>
{{ item.label }}
</button>
</div>
<AsyncState
:loading="loading"
:error="error"
:empty="!visibleRecords.length"
empty-text="暂无相关记录"
@retry="load"
>
<div class="m-finance-list">
<button v-for="item in visibleRecords" :key="`${item.type}-${item.id}`" type="button">
<span class="m-finance-icon" :class="`is-${item.type}`">
<img
:src="item.type === 'recharge' ? mobileAssets.rechargeRecord : mobileAssets.withdrawalRecord"
alt=""
/>
</span>
<span class="m-finance-main">
<b>{{ item.no }}</b>
<time>{{ dateTime(item.created_at) }}</time>
</span>
<span class="m-finance-result">
<b>{{ item.type === 'recharge' ? '+' : '-' }}{{ plainMoney(item.amount) }}</b>
<em :class="item.success ? 'is-success' : 'is-failed'">{{ item.status_text }}</em>
</span>
</button>
</div>
</AsyncState>
</section>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import PageHeader from '../components/PageHeader.vue';
import AsyncState from '../components/AsyncState.vue';
import { dateTime, errorText, request } from '../api';
import { mobileAssets } from '../assets';
type RecordType = 'all' | 'recharge' | 'withdrawal';
const route = useRoute();
const router = useRouter();
const tabs: { label: string; value: RecordType }[] = [
{ label: '全部', value: 'all' },
{ label: '储入记录', value: 'recharge' },
{ label: '取出记录', value: 'withdrawal' },
];
const requestedTab = String(route.query.tab || 'all');
const tab = ref<RecordType>(
requestedTab === 'recharge' || requestedTab === 'withdrawal' ? requestedTab : 'all'
);
const loading = ref(true);
const error = ref('');
const records = ref<any[]>([]);
const visibleRecords = computed(() =>
tab.value === 'all' ? records.value : records.value.filter((item) => item.type === tab.value)
);
const successful = new Set(['succeeded', 'completed', 'paid']);
const plainMoney = (value: number) => (Number(value || 0) / 100).toFixed(2);
function normalize(item: any, type: 'recharge' | 'withdrawal') {
const success = successful.has(item.status);
return {
id: item.id,
type,
no: item.recharge_no || item.withdrawal_no || `SW${item.id}`,
amount: item.request_amount || item.amount || 0,
created_at: item.created_at,
status_text:
item.status_text || `${type === 'recharge' ? '储入' : '取出'}${success ? '成功' : '失败'}`,
success,
};
}
async function load() {
loading.value = true;
error.value = '';
try {
const [rechargeResult, withdrawalResult] = await Promise.allSettled([
request<any>({
url: '/v1/recharge-orders',
params: { page: 1, page_size: 50, status: 'all' },
}),
request<any>({
url: '/v1/withdrawal-orders',
params: { page: 1, page_size: 50, status: 'all' },
}),
]);
if (rechargeResult.status === 'rejected' && withdrawalResult.status === 'rejected') {
throw withdrawalResult.reason;
}
const recharge = rechargeResult.status === 'fulfilled' ? rechargeResult.value.items || [] : [];
const withdrawals =
withdrawalResult.status === 'fulfilled' ? withdrawalResult.value.items || [] : [];
records.value = [
...recharge.map((item: any) => normalize(item, 'recharge')),
...withdrawals.map((item: any) => normalize(item, 'withdrawal')),
].sort((a, b) => String(b.created_at).localeCompare(String(a.created_at)));
} catch (err) {
error.value = errorText(err);
} finally {
loading.value = false;
}
}
async function changeTab(value: RecordType) {
tab.value = value;
await router.replace({ query: value === 'all' ? {} : { tab: value } });
}
onMounted(load);
</script>