Browse Source

feat(account): recharge SIM cards via package order and payment APIs

main
xiaosi 3 weeks ago
parent
commit
c8d78828ef
  1. 84
      src/views/AccountView/AccountView.vue

84
src/views/AccountView/AccountView.vue

@ -136,7 +136,9 @@
<template #usage="{ row }">{{ row.lastSyncAt ? `${Number(row.usedGb || 0).toFixed(1)} / ${row.planGb || 0} GB` : '暂无运营商同步数据' }}</template> <template #usage="{ row }">{{ row.lastSyncAt ? `${Number(row.usedGb || 0).toFixed(1)} / ${row.planGb || 0} GB` : '暂无运营商同步数据' }}</template>
<template #status="{ row }"><span class="carrier-status" :class="simStatus(row).cls"><i></i>{{ simStatus(row).name }}</span></template> <template #status="{ row }"><span class="carrier-status" :class="simStatus(row).cls"><i></i>{{ simStatus(row).name }}</span></template>
<template #lastSyncAt="{ row }">{{ fmtTime(row.lastSyncAt) }}</template> <template #lastSyncAt="{ row }">{{ fmtTime(row.lastSyncAt) }}</template>
<template #actions><span>运营商通道未接入</span></template>
<template #actions="{ row }">
<t-button variant="text" theme="primary" @click="openSimRecharge(row)">充值</t-button>
</template>
</t-table> </t-table>
<div class="table-footer" v-if="simTotal"><t-pagination v-model:current="simPageNum" :total="simTotal" :page-size="10" @current-change="loadSim" /></div> <div class="table-footer" v-if="simTotal"><t-pagination v-model:current="simPageNum" :total="simTotal" :page-size="10" @current-change="loadSim" /></div>
<div class="account-subsection-title"><h3>通信卡充值记录</h3><span> {{ simRechargeTotal }} </span></div> <div class="account-subsection-title"><h3>通信卡充值记录</h3><span> {{ simRechargeTotal }} </span></div>
@ -144,7 +146,7 @@
<template #simCardId="{ row }">{{ cardLabel(row.simCardId) }}</template> <template #simCardId="{ row }">{{ cardLabel(row.simCardId) }}</template>
<template #amountGb="{ row }"><strong>{{ row.amountGb }} GB</strong></template> <template #amountGb="{ row }"><strong>{{ row.amountGb }} GB</strong></template>
<template #totalPrice="{ row }"><strong>{{ money(row.totalPrice) }}</strong></template> <template #totalPrice="{ row }"><strong>{{ money(row.totalPrice) }}</strong></template>
<template #payStatus="{ row }"><em>{{ payStatusName(row.payStatus) }}</em></template>
<template #payStatus="{ row }"><em>{{ payStatusName(row.payStatus || row.paymentStatus) }}</em></template>
<template #rechargeStatus="{ row }"><em :class="{ processing: row.rechargeStatus === 'pending' }">{{ rechargeStatusName(row.rechargeStatus) }}</em></template> <template #rechargeStatus="{ row }"><em :class="{ processing: row.rechargeStatus === 'pending' }">{{ rechargeStatusName(row.rechargeStatus) }}</em></template>
<template #createdAt="{ row }">{{ fmtTime(row.createdAt) }}</template> <template #createdAt="{ row }">{{ fmtTime(row.createdAt) }}</template>
</t-table> </t-table>
@ -227,6 +229,35 @@
<t-button theme="primary" @click="changePassword">确认修改</t-button> <t-button theme="primary" @click="changePassword">确认修改</t-button>
</template> </template>
</t-dialog> </t-dialog>
<t-dialog
v-model:visible="simRechargeOpen"
header="通信卡充值"
width="480px"
destroy-on-close
dialog-class-name="recharge-modal"
placement="center"
>
<p>ICCID{{ simRechargeCard?.iccid || '--' }}</p>
<label>
<span>选择套餐</span>
<t-radio-group v-model="selectedSimPackageId" :disabled="!simPackages.length || simRecharging">
<t-radio v-for="pkg in simPackages" :key="pkg.id" :value="pkg.id">
{{ pkg.name }} · {{ pkg.amountGb }}GB · {{ moneyFromFen(pkg.saleFeeFen) }}
<small v-if="pkg.validityMonths"> / {{ pkg.validityMonths }}个月</small>
</t-radio>
</t-radio-group>
<small v-if="!simPackages.length">暂无可用通信卡套餐</small>
</label>
<template #footer>
<t-button variant="outline" @click="simRechargeOpen = false">取消</t-button>
<t-button
theme="primary"
:loading="simRecharging"
:disabled="!selectedSimPackageId || !simPackages.length"
@click="submitSimRecharge"
>创建并支付</t-button>
</template>
</t-dialog>
</section> </section>
</template> </template>
@ -262,6 +293,11 @@ const orders = ref([]); const orderTotal = ref(0); const orderPages = ref(1); co
const usage = ref([]); const usageTotal = ref(0); const usagePages = ref(1); const usagePageNum = ref(1) const usage = ref([]); const usageTotal = ref(0); const usagePages = ref(1); const usagePageNum = ref(1)
const simCards = ref([]); const simTotal = ref(0); const simPages = ref(1); const simPageNum = ref(1) const simCards = ref([]); const simTotal = ref(0); const simPages = ref(1); const simPageNum = ref(1)
const simRechargeLogs = ref([]); const simRechargeTotal = ref(0); const simRechargePages = ref(1); const simRechargePageNum = ref(1) const simRechargeLogs = ref([]); const simRechargeTotal = ref(0); const simRechargePages = ref(1); const simRechargePageNum = ref(1)
const simPackages = ref([])
const simRechargeOpen = ref(false)
const simRechargeCard = ref(null)
const selectedSimPackageId = ref(0)
const simRecharging = ref(false)
const editOpen = ref(false); const saving = ref(false); const editForm = ref({ name: '', email: '' }) const editOpen = ref(false); const saving = ref(false); const editForm = ref({ name: '', email: '' })
const orderColumns = [ const orderColumns = [
@ -397,6 +433,14 @@ async function loadTrafficPackages() {
trafficPackages.value = [] trafficPackages.value = []
} }
} }
async function loadSimPackages() {
try {
const list = await request.get(urls.SIM_PACKAGES)
simPackages.value = Array.isArray(list) ? list : []
} catch {
simPackages.value = []
}
}
async function load() { async function load() {
const results = await Promise.allSettled([ const results = await Promise.allSettled([
loadProfile(), loadProfile(),
@ -406,7 +450,8 @@ async function load() {
loadSim(), loadSim(),
loadDeviceCount(), loadDeviceCount(),
loadAccountExtensions(), loadAccountExtensions(),
loadTrafficPackages()
loadTrafficPackages(),
loadSimPackages()
]) ])
if (results.some((result) => result.status === 'rejected')) ui.toast('部分账户数据加载失败') if (results.some((result) => result.status === 'rejected')) ui.toast('部分账户数据加载失败')
} }
@ -461,6 +506,39 @@ async function cancelTrafficOrder(id) {
ui.toast(error.message || '取消失败') ui.toast(error.message || '取消失败')
} }
} }
function openSimRecharge(card) {
simRechargeCard.value = card
selectedSimPackageId.value = simPackages.value[0]?.id || 0
simRechargeOpen.value = true
}
async function submitSimRecharge() {
if (!simRechargeCard.value?.id) return
if (!selectedSimPackageId.value) {
ui.toast('请选择套餐')
return
}
simRecharging.value = true
let orderCreated = false
try {
const order = await request.post(
urls.SIM_CARD_RECHARGE_ORDERS(simRechargeCard.value.id),
{ packageId: Number(selectedSimPackageId.value) }
)
orderCreated = true
const payment = await createPayment('sim_recharge_order', order.id)
ui.toast(describePayment(payment))
simRechargeOpen.value = false
await loadSim()
} catch (error) {
ui.toast(error.message || '充值下单失败')
if (orderCreated) {
simRechargeOpen.value = false
await loadSim()
}
} finally {
simRecharging.value = false
}
}
async function saveProfile() { saving.value = true; try { const updated = await request.put(urls.ACCOUNT_PROFILE, editForm.value); profile.value = updated; userStore.user = { ...(userStore.user || {}), ...updated }; localStorage.setItem('user', JSON.stringify(userStore.user)); editOpen.value = false; ui.toast('账户资料已保存') } catch (error) { ui.toast(error.message || '保存账户资料失败') } finally { saving.value = false } } async function saveProfile() { saving.value = true; try { const updated = await request.put(urls.ACCOUNT_PROFILE, editForm.value); profile.value = updated; userStore.user = { ...(userStore.user || {}), ...updated }; localStorage.setItem('user', JSON.stringify(userStore.user)); editOpen.value = false; ui.toast('账户资料已保存') } catch (error) { ui.toast(error.message || '保存账户资料失败') } finally { saving.value = false } }
onMounted(load) onMounted(load)
</script> </script>

Loading…
Cancel
Save