@@ -24,6 +24,11 @@ const routes = [
|
|||||||
component: () => import('@/views/finance/FinanceData.vue'),
|
component: () => import('@/views/finance/FinanceData.vue'),
|
||||||
meta: { title: '财务数据' }
|
meta: { title: '财务数据' }
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'finance/withdraw-fee',
|
||||||
|
component: () => import('@/views/finance/WithdrawFeeProfit.vue'),
|
||||||
|
meta: { title: '提现抽成利润' }
|
||||||
|
},
|
||||||
|
|
||||||
// ========== 考核管理 ==========
|
// ========== 考核管理 ==========
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<el-menu-item index="/finance/bankuai">板块配置</el-menu-item>
|
<el-menu-item index="/finance/bankuai">板块配置</el-menu-item>
|
||||||
<el-menu-item index="/finance/data">财务数据</el-menu-item>
|
<el-menu-item index="/finance/data">财务数据</el-menu-item>
|
||||||
|
<el-menu-item index="/finance/withdraw-fee">提现抽成利润</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
260
src/views/finance/WithdrawFeeProfit.vue
Normal file
260
src/views/finance/WithdrawFeeProfit.vue
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
<template>
|
||||||
|
<div class="withdraw-fee-profit">
|
||||||
|
<div v-if="!hasPermission" class="no-permission">
|
||||||
|
<div class="no-permission-icon">🔒</div>
|
||||||
|
<div class="no-permission-text">您无权访问此页面</div>
|
||||||
|
<div class="no-permission-desc">需要财务权限(caiwu)或提现设置权限(5500a/b/c)</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<el-alert
|
||||||
|
type="warning"
|
||||||
|
:closable="false"
|
||||||
|
show-icon
|
||||||
|
class="hint"
|
||||||
|
title="分账专用:仅统计「提现成功」的抽成利润 = 申请扣款额 − 实际到账额(手续费)。手动/自动一并计入。不含会员/押金/商家充值。旧财务「俱乐部利润」请勿用于分账。"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<el-card shadow="hover" class="filter-card">
|
||||||
|
<el-form :inline="true" @submit.prevent>
|
||||||
|
<el-form-item label="日期范围">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="daterange"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
start-placeholder="开始"
|
||||||
|
end-placeholder="结束"
|
||||||
|
:clearable="false"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="日期口径">
|
||||||
|
<el-select v-model="dateField" style="width: 140px">
|
||||||
|
<el-option label="成功落账日" value="update_time" />
|
||||||
|
<el-option label="申请日" value="create_time" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="身份">
|
||||||
|
<el-select v-model="leixing" clearable placeholder="全部身份" style="width: 140px">
|
||||||
|
<el-option label="打手佣金" :value="1" />
|
||||||
|
<el-option label="管事分红" :value="2" />
|
||||||
|
<el-option label="组长分红" :value="3" />
|
||||||
|
<el-option label="审核官分佣" :value="4" />
|
||||||
|
<el-option label="打手押金" :value="5" />
|
||||||
|
<el-option label="商家余额" :value="6" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="打款方式">
|
||||||
|
<el-select v-model="dakuanMode" clearable placeholder="全部" style="width: 120px">
|
||||||
|
<el-option label="手动" :value="1" />
|
||||||
|
<el-option label="自动" :value="2" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="汇总">
|
||||||
|
<el-radio-group v-model="groupBy">
|
||||||
|
<el-radio-button label="day">按天</el-radio-button>
|
||||||
|
<el-radio-button label="month">按月</el-radio-button>
|
||||||
|
<el-radio-button label="leixing">按身份</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" :loading="loading" @click="fetchData">查询</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-row :gutter="16" class="kpi-row" v-loading="loading">
|
||||||
|
<el-col :xs="24" :sm="8">
|
||||||
|
<div class="kpi-card profit">
|
||||||
|
<div class="kpi-label">抽成利润合计</div>
|
||||||
|
<div class="kpi-value">¥{{ summary.profit_total || '0.00' }}</div>
|
||||||
|
<div class="kpi-sub">{{ summary.leixing_label || '全部身份' }} · {{ summary.success_count || 0 }} 笔成功</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :sm="8">
|
||||||
|
<div class="kpi-card">
|
||||||
|
<div class="kpi-label">申请扣款合计</div>
|
||||||
|
<div class="kpi-value">¥{{ summary.apply_total || '0.00' }}</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :sm="8">
|
||||||
|
<div class="kpi-card">
|
||||||
|
<div class="kpi-label">实际到账合计</div>
|
||||||
|
<div class="kpi-value">¥{{ summary.payout_total || '0.00' }}</div>
|
||||||
|
<div class="kpi-sub">申请−到账={{ summary.apply_minus_payout || '0.00' }}(应≈抽成)</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="16" style="margin-bottom: 16px">
|
||||||
|
<el-col :xs="24" :md="12">
|
||||||
|
<el-card shadow="hover" header="按身份拆分">
|
||||||
|
<el-table :data="byLeixing" size="small" border>
|
||||||
|
<el-table-column prop="leixing_label" label="身份" />
|
||||||
|
<el-table-column prop="count" label="笔数" width="80" />
|
||||||
|
<el-table-column label="抽成利润" width="140">
|
||||||
|
<template #default="{ row }">¥{{ row.profit }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :xs="24" :md="12">
|
||||||
|
<el-card shadow="hover" header="按打款方式拆分">
|
||||||
|
<el-table :data="byMode" size="small" border>
|
||||||
|
<el-table-column prop="dakuan_mode_label" label="方式" />
|
||||||
|
<el-table-column prop="count" label="笔数" width="80" />
|
||||||
|
<el-table-column label="抽成利润" width="140">
|
||||||
|
<template #default="{ row }">¥{{ row.profit }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-card shadow="hover" :header="tableTitle">
|
||||||
|
<el-table :data="rows" v-loading="loading" border stripe>
|
||||||
|
<el-table-column v-if="groupBy !== 'leixing'" prop="period" :label="groupBy === 'month' ? '月份' : '日期'" min-width="120" />
|
||||||
|
<el-table-column v-if="groupBy === 'leixing'" prop="leixing_label" label="身份" min-width="120" />
|
||||||
|
<el-table-column prop="count" label="成功笔数" width="100" />
|
||||||
|
<el-table-column label="申请扣款" min-width="120">
|
||||||
|
<template #default="{ row }">¥{{ row.apply_amount }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="实际到账" min-width="120">
|
||||||
|
<template #default="{ row }">¥{{ row.payout_amount }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="抽成利润" min-width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span class="profit-text">¥{{ row.profit }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
const hasPermission = ref(true)
|
||||||
|
const loading = ref(false)
|
||||||
|
const summary = ref({})
|
||||||
|
const rows = ref([])
|
||||||
|
const byLeixing = ref([])
|
||||||
|
const byMode = ref([])
|
||||||
|
|
||||||
|
const today = new Date()
|
||||||
|
const pad = (n) => String(n).padStart(2, '0')
|
||||||
|
const fmt = (d) => `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`
|
||||||
|
const monthStart = new Date(today.getFullYear(), today.getMonth(), 1)
|
||||||
|
|
||||||
|
const dateRange = ref([fmt(monthStart), fmt(today)])
|
||||||
|
const dateField = ref('update_time')
|
||||||
|
const leixing = ref(null)
|
||||||
|
const dakuanMode = ref(null)
|
||||||
|
const groupBy = ref('day')
|
||||||
|
|
||||||
|
const tableTitle = computed(() => {
|
||||||
|
if (groupBy.value === 'month') return '按月汇总'
|
||||||
|
if (groupBy.value === 'leixing') return '按身份汇总'
|
||||||
|
return '按天汇总'
|
||||||
|
})
|
||||||
|
|
||||||
|
const fetchData = async () => {
|
||||||
|
if (!dateRange.value || dateRange.value.length !== 2) {
|
||||||
|
ElMessage.warning('请选择日期范围')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
phone: localStorage.getItem('username'),
|
||||||
|
date_from: dateRange.value[0],
|
||||||
|
date_to: dateRange.value[1],
|
||||||
|
date_field: dateField.value,
|
||||||
|
group_by: groupBy.value,
|
||||||
|
}
|
||||||
|
if (leixing.value) payload.leixing = leixing.value
|
||||||
|
if (dakuanMode.value) payload.dakuan_mode = dakuanMode.value
|
||||||
|
|
||||||
|
const res = await request.post('/houtai/txchouchengtj', payload)
|
||||||
|
if (res.code === 403) {
|
||||||
|
hasPermission.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (res.code !== 0) {
|
||||||
|
ElMessage.error(res.msg || '查询失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const data = res.data || {}
|
||||||
|
summary.value = data.summary || {}
|
||||||
|
rows.value = data.rows || []
|
||||||
|
byLeixing.value = data.by_leixing || []
|
||||||
|
byMode.value = data.by_dakuan_mode || []
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e?.response?.data?.msg || e?.message || '网络错误')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(fetchData)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.withdraw-fee-profit {
|
||||||
|
padding: 8px 4px;
|
||||||
|
}
|
||||||
|
.hint {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.filter-card {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.kpi-row {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.kpi-card {
|
||||||
|
background: rgba(0, 242, 255, 0.06);
|
||||||
|
border: 1px solid rgba(0, 242, 255, 0.2);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.kpi-card.profit {
|
||||||
|
border-color: rgba(103, 194, 58, 0.5);
|
||||||
|
background: rgba(103, 194, 58, 0.08);
|
||||||
|
}
|
||||||
|
.kpi-label {
|
||||||
|
color: rgba(255, 255, 255, 0.65);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.kpi-value {
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #00f2ff;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
.kpi-card.profit .kpi-value {
|
||||||
|
color: #67c23a;
|
||||||
|
}
|
||||||
|
.kpi-sub {
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255, 255, 255, 0.45);
|
||||||
|
}
|
||||||
|
.profit-text {
|
||||||
|
color: #67c23a;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.no-permission {
|
||||||
|
text-align: center;
|
||||||
|
padding: 80px 20px;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
|
.no-permission-icon {
|
||||||
|
font-size: 48px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user