Files
kra-new/web/src/view/sw/ChannelActivationList.vue
T

110 lines
7.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div>
<div class="kra-search-box">
<el-form :model="query" :inline="true" @submit.prevent="search">
<el-form-item label="所属平台"><el-select v-model="query.platformNames" multiple collapse-tags clearable placeholder="选择平台" style="width: 210px"><el-option v-for="(label, value) in platforms" :key="value" :label="label" :value="value" /></el-select></el-form-item>
<el-form-item label="渠道账号"><el-input v-model="query.promoteAccount" clearable placeholder="渠道账号" /></el-form-item>
<el-form-item label="绑定商务"><el-input v-model="query.busierAccount" clearable placeholder="绑定商务" /></el-form-item>
<el-form-item><el-button icon="refresh" @click="reset">重置</el-button><el-button type="primary" icon="search" native-type="submit">查询</el-button></el-form-item>
</el-form>
</div>
<div class="kra-table-box">
<el-alert v-if="!available" class="mb-4" type="warning" :closable="false" title="OA 渠道激活数据源尚未接入或暂不可用。" />
<el-table v-loading="loading" :data="rows" row-key="id">
<el-table-column prop="platformTitle" label="所属平台" min-width="100" />
<el-table-column prop="promoteAccount" label="渠道名称" min-width="140" show-overflow-tooltip />
<el-table-column prop="busierAccount" label="绑定商务" min-width="130" show-overflow-tooltip />
<el-table-column label="绑定日期" min-width="120"><template #default="{ row }">{{ date(row.bindAt) }}</template></el-table-column>
<el-table-column label="解绑时间" min-width="120"><template #default="{ row }">{{ date(row.unbindAt) }}</template></el-table-column>
<el-table-column label="累计流水金额" min-width="160"><template #default="{ row }">{{ currency(row.accumAmount) }}</template></el-table-column>
<el-table-column label="状态" width="110"><template #default="{ row }"><el-tag effect="plain" :type="statusTone(row.status)">{{ row.statusText || row.status || '—' }}</el-tag></template></el-table-column>
<el-table-column label="操作" width="120" fixed="right"><template #default="{ row }"><el-button v-if="row.status !== 'rejected' && row.statusText !== '已驳回'" link type="primary" @click="openFlow(row)">流水明细</el-button><span v-else>—</span></template></el-table-column>
</el-table>
<div class="kra-pagination"><el-pagination v-model:current-page="query.pageNum" v-model:page-size="query.pageSize" :total="total" :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next, jumper" @size-change="search" @current-change="load" /></div>
</div>
<el-dialog v-model="dialog" title="流水明细" width="min(640px, 95vw)" append-to-body destroy-on-close @closed="clearDetail">
<div v-loading="flowLoading">
<el-descriptions :column="1">
<el-descriptions-item label="所属平台">{{ selected?.platformTitle || '—' }}</el-descriptions-item>
<el-descriptions-item label="渠道名称">{{ selected?.promoteAccount || '—' }}</el-descriptions-item>
<el-descriptions-item label="绑定期间">{{ period }}</el-descriptions-item>
</el-descriptions>
<el-alert v-if="flowError" type="warning" :title="flowError" :closable="false" />
<template v-else-if="detail">
<el-alert class="mb-4" type="info" title="仅统计绑定期间产生的流水。" :closable="false" />
<el-table :data="detail.list" max-height="320">
<el-table-column prop="platformTitle" label="所属平台" min-width="100" />
<el-table-column prop="gameName" label="游戏名称" min-width="160" show-overflow-tooltip />
<el-table-column label="累计金额" min-width="150" align="right"><template #default="{ row }">{{ currency(row.totalAmount) }}</template></el-table-column>
</el-table>
<p class="mt-4 text-right">绑定期间累计流水:<strong>{{ currency(detail.totalAmount) }}</strong></p>
</template>
</div>
<template #footer><el-button @click="dialog = false">关闭</el-button></template>
</el-dialog>
</div>
</template>
<script setup>
import { computed, onMounted, reactive, ref } from 'vue'
import { listChannelActivations, getActivationSpend } from '@/api/activation'
defineOptions({ name: 'SwChannelActivationList' })
const platforms = { lx: '龙翔', hw: '汇玩', yq: '游趣' }
const query = reactive({ pageNum: 1, pageSize: 10, platformNames: Object.keys(platforms), promoteAccount: '', busierAccount: '' })
const rows = ref([])
const total = ref(0)
const available = ref(true)
const loading = ref(false)
const dialog = ref(false)
const flowLoading = ref(false)
const flowError = ref('')
const selected = ref(null)
const detail = ref(null)
let listVersion = 0
let detailVersion = 0
const date = value => value ? value.slice(0, 10) : '—'
// 金额按字符串分组,保留超出 JavaScript 精确整数范围的金额。
const currency = value => {
const text = String(value ?? '0').trim()
if (!/^-?\d+(\.\d+)?$/.test(text)) return '—'
const [whole, fraction = ''] = text.split('.')
return `¥${whole.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}.${fraction.padEnd(2, '0').slice(0, 2)}`
}
const statusTone = status => ({ pending: 'info', in_progress: 'warning', reached: 'success', rejected: 'danger', unbound: 'info' })[status] || 'info'
const period = computed(() => {
const start = detail.value?.bindAt || selected.value?.bindAt
const end = detail.value?.endAt || selected.value?.endAt
if (!start) return '—'
return end ? `${date(start)} 至 ${date(end)}` : `${date(start)} 起`
})
const load = async () => {
const version = ++listVersion
if (!query.platformNames.length) { rows.value = []; total.value = 0; available.value = true; loading.value = false; return }
loading.value = true
try {
const res = await listChannelActivations({ ...query, platformNames: query.platformNames.join(','), promoteAccount: query.promoteAccount.trim(), busierAccount: query.busierAccount.trim() })
if (version !== listVersion) return
if (res.code === 0) { rows.value = res.data.rows; total.value = res.data.total; available.value = res.data.available !== false }
else { rows.value = []; total.value = 0 }
} catch { if (version === listVersion) { rows.value = []; total.value = 0 } } finally { if (version === listVersion) loading.value = false }
}
const search = () => { query.pageNum = 1; return load() }
const reset = () => { Object.assign(query, { platformNames: Object.keys(platforms), promoteAccount: '', busierAccount: '' }); return search() }
const clearDetail = () => { ++detailVersion; detail.value = null; selected.value = null; flowError.value = ''; flowLoading.value = false }
const openFlow = async row => {
clearDetail()
const version = ++detailVersion
selected.value = row
dialog.value = true
flowLoading.value = true
try {
const res = await getActivationSpend(row.id)
if (version !== detailVersion) return
if (res.code === 0) detail.value = res.data
else flowError.value = res.msg || '流水明细读取失败'
} catch { if (version === detailVersion) flowError.value = '流水明细读取失败,请重试' } finally { if (version === detailVersion) flowLoading.value = false }
}
onMounted(load)
</script>