feat: 完善小组绩效与有效端统计并修复审查问题
This commit is contained in:
@@ -9,9 +9,14 @@
|
||||
<el-alert v-else-if="summaryError" class="mt-3" type="error" :closable="false" :title="summaryError" />
|
||||
<el-alert v-else-if="summary?.available === false" class="mt-3" type="warning" :closable="false" title="工作台所需业务数据尚未接入。" />
|
||||
</el-card>
|
||||
<my-goal-card />
|
||||
<div class="overview-period">
|
||||
<el-radio-group v-model="overviewPeriod" @change="overviewPeriod !== 'custom' && loadSummary()"><el-radio-button v-for="option in periods" :key="option.value" :value="option.value">{{ option.label }}</el-radio-button><el-radio-button value="custom">自定义</el-radio-button></el-radio-group>
|
||||
<template v-if="overviewPeriod === 'custom'"><el-date-picker v-model="overviewDates" type="daterange" value-format="YYYY-MM-DD" start-placeholder="开始日期" end-placeholder="结束日期" :clearable="false" /><el-button type="primary" @click="loadSummary">搜索</el-button></template>
|
||||
</div>
|
||||
<div v-loading="summaryLoading" class="business-kpis">
|
||||
<el-card v-for="card in cards" :key="card.key" shadow="never">
|
||||
<div class="business-muted">{{ card.label }}</div>
|
||||
<el-tooltip :content="card.key === 'effectivePromote' ? `渠道注册后 ${summary?.settings?.days ?? 30} 天内充值满 ¥${summary?.settings?.amount ?? 3000},按达标日期统计。` : card.event ? '按所选区间内的状态变更事件统计,与上一等长周期比较。' : '所选时间区间内的数据,与上一等长周期比较。'"><div class="business-muted">{{ card.label }}</div></el-tooltip>
|
||||
<div class="business-value">{{ metricValue(card) }}</div>
|
||||
<el-text :type="rateType(summary?.[card.key]?.changeRate)" size="small">{{ metricCompare(card.key) }}</el-text>
|
||||
</el-card>
|
||||
@@ -38,7 +43,9 @@
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getWorkbenchSummary, getWorkbenchRanks } from '@/api/workbench'
|
||||
import { getWorkbenchRanks } from '@/api/workbench'
|
||||
import { getDashboardOverview } from '@/api/performance'
|
||||
import MyGoalCard from '@/view/sw/components/MyGoalCard.vue'
|
||||
import { listAlertRecords } from '@/api/alert'
|
||||
import { channelCount, channelMoney } from '@/view/sw/channel-display'
|
||||
import CompactRankingTable from '@/view/sw/components/CompactRankingTable.vue'
|
||||
@@ -46,9 +53,10 @@ import CompactRankingTable from '@/view/sw/components/CompactRankingTable.vue'
|
||||
const router = useRouter(), carousel = ref()
|
||||
const platforms = { lx: '龙翔', hw: '汇玩', yq: '游趣' }
|
||||
const sources = ref(Object.keys(platforms)), summary = ref(null), summaryLoading = ref(false), summaryError = ref('')
|
||||
const overviewPeriod = ref('today'), overviewDates = ref([])
|
||||
const alerts = reactive({ rows: [], total: null, loading: false, error: '', version: 0 })
|
||||
const periods = [{ label: '今日', value: 'today' }, { label: '昨日', value: 'yesterday' }, { label: '近7天', value: 'last7' }, { label: '近30天', value: 'last30' }]
|
||||
const cards = [{ key: 'todayRegister', label: '今日渠道玩家注册' }, { key: 'todayActive', label: '今日渠道活跃玩家' }, { key: 'todayPay', label: '今日充值金额', money: true }, { key: 'monthPay', label: '本月充值金额', money: true }, { key: 'activePromote', label: '活跃渠道数' }, { key: 'newPromote', label: '新增渠道数' }]
|
||||
const cards = [{ key: 'todayRegister', label: '玩家注册' }, { key: 'todayActive', label: '活跃玩家' }, { key: 'todayPay', label: '充值金额', money: true }, { key: 'effectivePromote', label: '有效端' }, { key: 'activePromote', label: '活跃渠道数' }, { key: 'newPromote', label: '新增渠道数' }, { key: 'lockedPromote', label: '锁定渠道', event: true }, { key: 'terminatedPromote', label: '解除合作渠道', event: true }]
|
||||
const panels = reactive([
|
||||
{ key: 'register', endpoint: 'registerTop', title: '渠道注册 TOP10', period: 'today' },
|
||||
{ key: 'payHigh', endpoint: 'payRank', title: '渠道充值 TOP10', period: 'today', order: 'desc' },
|
||||
@@ -57,21 +65,22 @@ const panels = reactive([
|
||||
].map(panel => ({ ...panel, rows: [], loading: false, error: '', version: 0 })))
|
||||
let summaryVersion = 0
|
||||
const count = value => value == null ? '未获取' : channelCount(String(value).split('.')[0])
|
||||
const metricValue = card => { const value = summary.value?.[card.key]?.value; if (value == null) return !sources.value.length ? '—' : summary.value?.available === false ? '未接入' : '未获取'; return card.money ? channelMoney(value) : count(value) }
|
||||
const metricValue = card => { const value = summary.value?.[card.key]?.value; if (card.event && summary.value && value == null) return '未接入'; if (value == null) return !sources.value.length ? '—' : summary.value?.available === false ? '未接入' : '未获取'; return card.money ? channelMoney(value) : count(value) }
|
||||
const rateType = rate => rate == null || Number(rate) === 0 ? 'info' : Number(rate) > 0 ? 'success' : 'danger'
|
||||
const metricCompare = key => {
|
||||
const card = summary.value?.[key]
|
||||
if (card?.value == null) return '—'
|
||||
if (card?.value == null) return card?.compareLabel === '事件数据未接入' ? card.compareLabel : '—'
|
||||
if (card.changeRate == null) return `${card.compareLabel}:无可比数据`
|
||||
return `${card.compareLabel} ${Number(card.changeRate) > 0 ? '+' : ''}${card.changeRate}%`
|
||||
}
|
||||
const rankValue = (panel, value) => panel.key === 'register' ? count(value) : panel.key === 'unlogin' ? `${count(value)} 天` : channelMoney(value)
|
||||
const rankingRows = panel => panel.rows.map(row => ({ rowKey: `${row.sourceDb}:${row.promoteId}`, rank: row.rank, objectName: row.promoteName, sourceDbLabel: row.sourceDbLabel, metricValue: row.value }))
|
||||
const loadSummary = async () => {
|
||||
if (overviewPeriod.value === 'custom' && (!overviewDates.value?.[0] || !overviewDates.value?.[1] || overviewDates.value[0] > overviewDates.value[1])) { ElMessage.warning('请选择正确的起止日期'); return }
|
||||
const current = ++summaryVersion; summary.value = null; summaryError.value = ''
|
||||
if (!sources.value.length) { summaryLoading.value = false; return }
|
||||
summaryLoading.value = true
|
||||
try { const res = await getWorkbenchSummary({ sourceDbList: sources.value.join(',') }); if (current !== summaryVersion) return; if (res.code === 0) summary.value = res.data; else summaryError.value = res.msg || '商务指标读取失败' }
|
||||
try { const res = await getDashboardOverview({ sourceDbList: sources.value.join(','), period: overviewPeriod.value, begin: overviewDates.value?.[0], end: overviewDates.value?.[1] }); if (current !== summaryVersion) return; if (res.code === 0) summary.value = { ...res.data, ...res.data.cards }; else summaryError.value = res.msg || '商务指标读取失败' }
|
||||
catch { if (current === summaryVersion) summaryError.value = '商务指标读取失败,请重试' } finally { if (current === summaryVersion) summaryLoading.value = false }
|
||||
}
|
||||
const loadRank = async panel => {
|
||||
@@ -100,6 +109,7 @@ onMounted(refresh)
|
||||
|
||||
<style scoped>
|
||||
.business-dashboard { display: flex; flex-direction: column; gap: 12px; }
|
||||
.overview-period { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; margin-top: 8px; }
|
||||
.business-toolbar, .business-rank-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
||||
.business-platform-filter { display: flex; align-items: center; gap: 12px; }
|
||||
.business-platform-filter .el-select { width: 240px; }
|
||||
|
||||
Reference in New Issue
Block a user