diff --git a/src/views/TrafficOpsView/TrafficOpsView.vue b/src/views/TrafficOpsView/TrafficOpsView.vue index ac146b5..c931a06 100644 --- a/src/views/TrafficOpsView/TrafficOpsView.vue +++ b/src/views/TrafficOpsView/TrafficOpsView.vue @@ -69,7 +69,78 @@ -
采购入池占位
+
+
+ 尚未建立资源池,首次录入采购后自动创建 +
+
+
+ 资源池总量 + {{ bytesToGbText(pool.totalBytes) }} + {{ pool.totalBytes ?? 0 }} bytes +
+
+ 可用流量 + {{ bytesToGbText(pool.availableBytes) }} + {{ pool.availableBytes ?? 0 }} bytes +
+
+ 池状态 + {{ pool.status === 'active' ? '有效' : (pool.status || '—') }} + {{ pool.status || '—' }} +
+
+ +
+ +
+ +
+
+ + + + + 录入采购 + +
+
+ +
+ +
+ + +
+
账务流水占位
@@ -151,6 +222,77 @@ + + +
+ + +
+ + +
+
+ + +
+ +
{{ purchaseFormError }}
+
+ +
@@ -337,8 +479,143 @@ async function disablePackage(row) { } } +const pool = ref(null) +const poolMissing = ref(false) +const purchaseList = ref([]) +const purchaseTotal = ref(0) +const purchasePageNum = ref(1) +const purchasePageSize = ref(10) +const purchaseProvider = ref('') +const purchaseStatus = ref('') +const purchaseModalVisible = ref(false) +const purchaseFormError = ref('') +const purchaseForm = reactive({ + batchNo: '', + provider: '', + totalGb: 1, + unitCost: 0, + totalCost: 0, + expiresAt: '', + remark: '' +}) + +const purchaseStatusOptions = [ + { label: '全部状态', value: '' }, + { label: '有效', value: 'active' }, + { label: '失效', value: 'inactive' } +] +const purchaseColumns = [ + { colKey: 'batchNo', title: '批次号', width: '12%' }, + { colKey: 'provider', title: '供应商', width: '10%' }, + { colKey: 'totalText', title: '总量', width: '10%' }, + { colKey: 'costText', title: '成本', width: '10%' }, + { colKey: 'expiresAt', title: '到期', width: '14%' }, + { colKey: 'statusName', title: '状态', width: '8%' }, + { colKey: 'remark', title: '备注', width: '14%', ellipsis: true }, + { colKey: 'createdAt', title: '创建时间', width: '16%' } +] + +async function loadPool() { + poolMissing.value = false + try { + pool.value = await request.get(urls.ADMIN_TRAFFIC_POOL) + } catch (e) { + if (e.status === 404 || /资源不存在|not found/i.test(e.message || '')) { + pool.value = null + poolMissing.value = true + return + } + ui.toast(e.message || '加载资源池失败') + } +} + +async function loadPurchases() { + try { + const params = { pageNum: purchasePageNum.value, pageSize: purchasePageSize.value } + if (purchaseProvider.value) params.provider = purchaseProvider.value + if (purchaseStatus.value) params.status = purchaseStatus.value + const page = await request.get(urls.ADMIN_TRAFFIC_PURCHASES, { params }) + purchaseTotal.value = page?.total || 0 + purchaseList.value = (page?.records || []).map((p) => ({ + id: String(p.id), + batchNo: p.batchNo || '—', + provider: p.provider || '—', + totalText: bytesToGbText(p.totalBytes), + costText: `¥${Number(p.totalCost || 0).toFixed(2)}`, + expiresAt: fmtTime(p.expiresAt), + statusName: p.status === 'active' ? '有效' : (p.status || '—'), + remark: p.remark || '', + createdAt: fmtTime(p.createdAt), + raw: p + })) + } catch (e) { + ui.toast(e.message || '加载采购列表失败') + } +} + +async function loadPurchasesTab() { + await Promise.all([loadPool(), loadPurchases()]) +} + +function reloadPurchases() { + purchasePageNum.value = 1 + loadPurchases() +} + +function openPurchaseAdd() { + Object.assign(purchaseForm, { + batchNo: '', + provider: '', + totalGb: 1, + unitCost: 0, + totalCost: 0, + expiresAt: '', + remark: '' + }) + purchaseFormError.value = '' + purchaseModalVisible.value = true +} + +async function submitPurchase() { + purchaseFormError.value = '' + if (!purchaseForm.batchNo.trim() || !purchaseForm.provider.trim()) { + purchaseFormError.value = '请填写批次号和供应商' + return + } + if (!(Number(purchaseForm.totalGb) > 0)) { + purchaseFormError.value = '采购总量必须大于 0 GB' + return + } + const payload = { + batchNo: purchaseForm.batchNo.trim(), + provider: purchaseForm.provider.trim(), + totalBytes: Math.round(Number(purchaseForm.totalGb) * GB_BYTES), + unitCost: Number(purchaseForm.unitCost || 0), + totalCost: Number(purchaseForm.totalCost || 0), + remark: purchaseForm.remark || '' + } + if (purchaseForm.expiresAt) { + const expires = new Date(purchaseForm.expiresAt) + if (Number.isNaN(expires.getTime())) { + purchaseFormError.value = '到期时间格式无效' + return + } + payload.expiresAt = expires.toISOString() + } + try { + await request.post(urls.ADMIN_TRAFFIC_PURCHASES, payload) + ui.toast('采购已录入') + purchaseModalVisible.value = false + await loadPurchasesTab() + } catch (e) { + purchaseFormError.value = e.message || '录入失败' + } +} + + watch(tab, (v) => { if (v === 'packages') loadPackages() + if (v === 'purchases') loadPurchasesTab() }) onMounted(() => { @@ -347,12 +624,37 @@ onMounted(() => {