1.优化后端管理员提现方式
2.优化后端
This commit is contained in:
@@ -6,17 +6,55 @@
|
||||
:buttons="['refresh', 'add', 'edit', 'delete', 'comSearch', 'quickSearch', 'columnDisplay']"
|
||||
:quick-search-placeholder="t('Quick search placeholder', { fields: t('channel.quick Search Fields') })"
|
||||
></TableHeader>
|
||||
<div class="channel-top-actions">
|
||||
<div class="channel-stats-cards">
|
||||
<el-card shadow="never" class="channel-stat-card">
|
||||
<div class="label">{{ t('channel.settle_stats_channel_total') }}</div>
|
||||
<div class="value">{{ settleStats.channel_total }}</div>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="channel-stat-card">
|
||||
<div class="label">{{ t('channel.settle_stats_enabled') }}</div>
|
||||
<div class="value">{{ settleStats.enabled_count }}</div>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="channel-stat-card">
|
||||
<div class="label">{{ t('channel.settle_stats_pending_dividend') }}</div>
|
||||
<div class="value">{{ settleStats.carryover_positive_count }}</div>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="channel-stat-card">
|
||||
<div class="label">{{ t('channel.settle_stats_pending_amount') }}</div>
|
||||
<div class="value">{{ settleStats.carryover_positive_total }}</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="channel-action-row">
|
||||
<el-radio-group v-model="settleFilterMode" size="small" @change="onSettleFilterChange">
|
||||
<el-radio-button label="all">{{ t('channel.settle_filter_all') }}</el-radio-button>
|
||||
<el-radio-button label="with_balance">{{ t('channel.settle_filter_with_balance') }}</el-radio-button>
|
||||
<el-radio-button label="no_balance">{{ t('channel.settle_filter_no_balance') }}</el-radio-button>
|
||||
<el-radio-button label="enabled">{{ t('channel.settle_filter_enabled') }}</el-radio-button>
|
||||
<el-radio-button label="disabled">{{ t('channel.settle_filter_disabled') }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-button v-if="auth('batchSettlePending')" type="warning" @click="onBatchSettlePending">
|
||||
{{ t('channel.batch_settle_pending') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table ref="tableRef"></Table>
|
||||
|
||||
<PopupForm />
|
||||
|
||||
<el-dialog class="ba-operate-dialog" :close-on-click-modal="false" :model-value="manualSettle.visible" @close="closeManualSettleDialog">
|
||||
<el-dialog
|
||||
class="ba-operate-dialog manual-settle-dialog"
|
||||
:close-on-click-modal="false"
|
||||
:model-value="manualSettle.visible"
|
||||
width="860px"
|
||||
@close="closeManualSettleDialog"
|
||||
>
|
||||
<template #header>
|
||||
<div class="title">{{ t('channel.manual_settle') }}</div>
|
||||
</template>
|
||||
<div v-loading="manualSettle.previewLoading" class="manual-settle-dialog-body">
|
||||
<el-form :model="manualSettle.form" label-width="140px">
|
||||
<el-form :model="manualSettle.form" label-width="140px" class="manual-settle-form">
|
||||
<el-form-item :label="t('channel.manual_settle_settlement_no')">
|
||||
<el-input v-model="manualSettle.form.settlement_no" readonly />
|
||||
</el-form-item>
|
||||
@@ -44,8 +82,8 @@
|
||||
<el-form-item :label="t('channel.manual_settle_commission_amount')">
|
||||
<el-input v-model="manualSettle.form.commission_amount" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('channel.share_config')">
|
||||
<el-table :data="manualSettle.form.commission_split" border size="small" class="w100">
|
||||
<el-form-item :label="t('channel.share_config')" class="manual-settle-form-item-full">
|
||||
<el-table :data="manualSettle.form.commission_split" border size="small" class="w100" max-height="220">
|
||||
<el-table-column prop="admin_username" :label="t('channel.admin__username')" min-width="100" />
|
||||
<el-table-column prop="share_rate" :label="t('channel.share_rate_percent')" min-width="90">
|
||||
<template #default="scope">{{ scope.row.share_rate }}%</template>
|
||||
@@ -53,16 +91,18 @@
|
||||
<el-table-column prop="commission_amount" :label="t('channel.manual_settle_commission_amount')" min-width="110" />
|
||||
</el-table>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('channel.manual_settle_remark')">
|
||||
<el-form-item :label="t('channel.manual_settle_remark')" class="manual-settle-form-item-full">
|
||||
<el-input v-model="manualSettle.form.remark" type="textarea" :rows="2" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="closeManualSettleDialog">{{ t('Cancel') }}</el-button>
|
||||
<el-button type="primary" :disabled="manualSettle.previewLoading" :loading="manualSettle.loading" @click="submitManualSettle">
|
||||
{{ t('Save') }}
|
||||
</el-button>
|
||||
<div class="manual-settle-footer">
|
||||
<el-button @click="closeManualSettleDialog">{{ t('Cancel') }}</el-button>
|
||||
<el-button type="primary" :disabled="manualSettle.previewLoading" :loading="manualSettle.loading" @click="submitManualSettle">
|
||||
{{ t('Save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
@@ -115,7 +155,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, provide, reactive, useTemplateRef } from 'vue'
|
||||
import { computed, onMounted, provide, reactive, ref, useTemplateRef } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import PopupForm from './popupForm.vue'
|
||||
@@ -207,6 +247,15 @@ const shareDialog = reactive({
|
||||
channelId: 0,
|
||||
list: [] as Array<{ admin_id: number; username: string; role_group_name: string; role_level: number; status: number; share_rate: number | null }>,
|
||||
})
|
||||
const settleFilterMode = ref<'all' | 'with_balance' | 'no_balance' | 'enabled' | 'disabled'>('all')
|
||||
const settleStats = reactive({
|
||||
channel_total: 0,
|
||||
enabled_count: 0,
|
||||
disabled_count: 0,
|
||||
carryover_positive_count: 0,
|
||||
carryover_total: '0.00',
|
||||
carryover_positive_total: '0.00',
|
||||
})
|
||||
|
||||
const shareEnabledTotal = computed(() => {
|
||||
let sum = 0
|
||||
@@ -370,6 +419,35 @@ const submitManualSettle = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const onBatchSettlePending = async () => {
|
||||
await createAxios(
|
||||
{
|
||||
url: '/admin/channel/batchSettlePending',
|
||||
method: 'post',
|
||||
},
|
||||
{ showSuccessMessage: true }
|
||||
)
|
||||
await loadSettleStats()
|
||||
baTable.onTableHeaderAction('refresh', { event: 'batch-settle' })
|
||||
}
|
||||
|
||||
const onSettleFilterChange = () => {
|
||||
baTable.getData()
|
||||
}
|
||||
|
||||
const loadSettleStats = async () => {
|
||||
const res = await createAxios({ url: '/admin/channel/settleStats', method: 'get' })
|
||||
if (res.code !== 1 || !res.data) {
|
||||
return
|
||||
}
|
||||
settleStats.channel_total = Number(res.data.channel_total ?? 0)
|
||||
settleStats.enabled_count = Number(res.data.enabled_count ?? 0)
|
||||
settleStats.disabled_count = Number(res.data.disabled_count ?? 0)
|
||||
settleStats.carryover_positive_count = Number(res.data.carryover_positive_count ?? 0)
|
||||
settleStats.carryover_total = String(res.data.carryover_total ?? '0.00')
|
||||
settleStats.carryover_positive_total = String(res.data.carryover_positive_total ?? '0.00')
|
||||
}
|
||||
|
||||
const baTable = new baTableClass(
|
||||
new baTableApi('/admin/channel/'),
|
||||
{
|
||||
@@ -564,6 +642,27 @@ const baTable = new baTableClass(
|
||||
}
|
||||
)
|
||||
|
||||
baTable.before.getData = () => {
|
||||
const filter = baTable.table.filter || {}
|
||||
const searchRaw = filter.search
|
||||
const search = Array.isArray(searchRaw) ? searchRaw.filter((item: any) => item && item.field !== 'carryover_balance' && item.field !== 'status') : []
|
||||
if (settleFilterMode.value === 'with_balance') {
|
||||
search.push({ field: 'carryover_balance', operator: 'gt', val: 0 })
|
||||
} else if (settleFilterMode.value === 'no_balance') {
|
||||
search.push({ field: 'carryover_balance', operator: 'elt', val: 0 })
|
||||
} else if (settleFilterMode.value === 'enabled') {
|
||||
search.push({ field: 'status', operator: 'eq', val: 1 })
|
||||
} else if (settleFilterMode.value === 'disabled') {
|
||||
search.push({ field: 'status', operator: 'eq', val: 0 })
|
||||
}
|
||||
filter.search = search
|
||||
baTable.table.filter = filter
|
||||
}
|
||||
|
||||
baTable.after.getData = () => {
|
||||
void loadSettleStats()
|
||||
}
|
||||
|
||||
provide('baTable', baTable)
|
||||
|
||||
onMounted(() => {
|
||||
@@ -573,6 +672,7 @@ onMounted(() => {
|
||||
baTable.initSort()
|
||||
baTable.dragSort()
|
||||
})
|
||||
void loadSettleStats()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -597,4 +697,71 @@ onMounted(() => {
|
||||
.share-group-empty {
|
||||
color: var(--el-text-color-placeholder);
|
||||
}
|
||||
|
||||
.channel-top-actions {
|
||||
margin: 8px 0 12px;
|
||||
}
|
||||
|
||||
.channel-stats-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.channel-stat-card .label {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.channel-stat-card .value {
|
||||
margin-top: 6px;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.channel-action-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.manual-settle-dialog-body {
|
||||
max-height: min(70vh, 680px);
|
||||
overflow: auto;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.manual-settle-form {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
column-gap: 16px;
|
||||
}
|
||||
|
||||
.manual-settle-form :deep(.el-form-item) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.manual-settle-form-item-full {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.manual-settle-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.channel-stats-cards {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.manual-settle-form {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -210,6 +210,7 @@ type TreeNode = {
|
||||
const adminScopeTree = ref<TreeNode[]>([])
|
||||
const adminIdToChannelId = ref<Record<string, number>>({})
|
||||
const adminIdToInviteCode = ref<Record<string, string>>({})
|
||||
const currentAdminId = ref('')
|
||||
|
||||
const treeProps = {
|
||||
value: 'value',
|
||||
@@ -309,6 +310,8 @@ const loadAdminScopeTree = async () => {
|
||||
method: 'get',
|
||||
})
|
||||
const list = (res.data?.list ?? []) as TreeNode[]
|
||||
const currentIdRaw = res.data?.current_admin_id
|
||||
currentAdminId.value = currentIdRaw === undefined || currentIdRaw === null ? '' : String(currentIdRaw)
|
||||
adminScopeTree.value = list
|
||||
|
||||
const { mapCh, mapInv } = buildAdminMapsFromTree(list)
|
||||
@@ -316,6 +319,14 @@ const loadAdminScopeTree = async () => {
|
||||
adminIdToInviteCode.value = mapInv
|
||||
|
||||
await nextTick()
|
||||
if (
|
||||
baTable.form.operate === 'Add' &&
|
||||
baTable.form.items &&
|
||||
(baTable.form.items.admin_id === undefined || baTable.form.items.admin_id === null || baTable.form.items.admin_id === '') &&
|
||||
currentAdminId.value !== ''
|
||||
) {
|
||||
baTable.form.items.admin_id = currentAdminId.value
|
||||
}
|
||||
const aid = baTable.form.items?.admin_id
|
||||
if (aid !== undefined && aid !== null && aid !== '') {
|
||||
onAdminTreeChange(aid as string | number)
|
||||
@@ -398,6 +409,14 @@ watch(
|
||||
(op) => {
|
||||
if (op === 'Add') {
|
||||
syncRiskFromFlags(0)
|
||||
if (
|
||||
baTable.form.items &&
|
||||
(baTable.form.items.admin_id === undefined || baTable.form.items.admin_id === null || baTable.form.items.admin_id === '') &&
|
||||
currentAdminId.value !== ''
|
||||
) {
|
||||
baTable.form.items.admin_id = currentAdminId.value
|
||||
onAdminTreeChange(currentAdminId.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user