1.优化充值跳转链接的问题

2.优化后台渠道管理页面的显示样式
This commit is contained in:
2026-05-30 14:37:46 +08:00
parent 15b9313c07
commit 1cdd597879
19 changed files with 1096 additions and 180 deletions

View File

@@ -9,7 +9,9 @@ export default {
admin_username: 'Agent username',
commission_rate: 'Commission rate',
calc_base_amount: 'Calculation base amount',
commission_amount: 'Commission amount',
commission_amount: 'Commission amount (gross)',
handling_fee: 'Handling fee amount',
net_commission_amount: 'Net commission',
status: 'Status',
'status 0': 'Pending',
'status 1': 'Paid',

View File

@@ -15,6 +15,19 @@ export default {
agent_mode_desc_affiliate_2: 'Formula: net loss after costs × affiliate share rate.',
agent_mode_desc_affiliate_3: 'Fields: supports fee deduction rate and carryover balance; turnover rate is cleared automatically.',
turnover_share_rate: 'turnover_share_rate',
settlement_handling_fee: 'settlement_handling_fee(%)',
settlement_handling_fee_tip: 'Percent of gross commission per agent per period; adjustable in manual settle',
settlement_handling_fee_percent: 'handling_fee(%)',
settlement_handling_fee_amount: 'handling_fee_amount',
manual_settle_settlement_base: 'settlement_base',
manual_settle_net_commission: 'net_commission',
manual_settle_col_base: 'Base',
manual_settle_col_share: 'Share',
manual_settle_col_gross: 'Gross',
manual_settle_col_commission_share: 'Share%',
manual_settle_col_net_short: 'Net',
manual_settle_col_fee: 'Fee',
manual_settle_col_net: 'Net',
affiliate_share_rate: 'affiliate_share_rate',
affiliate_fee_rate: 'affiliate_fee_rate',
affiliate_contract_no: 'affiliate_contract_no',
@@ -72,6 +85,19 @@ export default {
manual_settle_commission_amount: 'Commission amount',
manual_settle_submit: 'Settle',
manual_settle_remark: 'Remark',
manual_settle_calc_title: 'Settlement calculation',
manual_settle_calc_intro_turnover_1: 'For this period, sum settled bets: total bet and total payout; platform PnL = bet payout.',
manual_settle_calc_intro_turnover_2: 'Channel commission = settlement base (total bet) × turnover share rate; the table below splits it by agent tree.',
manual_settle_calc_intro_turnover_3: 'Commission applies only when platform-wide PnL is positive; otherwise channel commission is 0.',
manual_settle_calc_intro_affiliate_1: 'For this period, affiliate commission is based on net player loss and ladder rules in this channel.',
manual_settle_calc_intro_affiliate_2: 'Channel commission = base after costs × share rate; split in the table by agent hierarchy.',
manual_settle_calc_intro_affiliate_3: 'If net loss is not positive, commission may be 0 — use preview amounts.',
manual_settle_calc_tree_1: 'Expand/collapse the tree; each row is one agent share in this settlement.',
manual_settle_calc_tree_2: 'Settlement base = amount from parent; share % = cut from parent pool; commission = gross before fee.',
manual_settle_calc_tree_3: 'Commission share % = agent gross ÷ channel total commission × 100%.',
manual_settle_calc_handling_fee: 'Net = gross fee; fee uses channel rate {rate}% of gross, once per agent per period.',
manual_settle_col_net: 'Net',
manual_settle_split_scroll_tip: 'Swipe horizontally to view all columns',
share_config: 'Share config',
share_config_title: 'Channel admin share config',
share_config_tip: 'Only enabled rows participate in settlement split, and enabled share total must equal 100%.',

View File

@@ -9,7 +9,9 @@ export default {
admin_username: '代理账号',
commission_rate: '佣金比例',
calc_base_amount: '结算基数',
commission_amount: '佣金金额',
commission_amount: '佣金金额(费前)',
handling_fee: '手续费金额',
net_commission_amount: '实发佣金',
status: '状态',
'status 0': '待发放',
'status 1': '已发放',

View File

@@ -15,6 +15,20 @@ export default {
agent_mode_desc_affiliate_2: '计算方式:净客损扣除成本后 × 联营占成比例affiliate_share_rate。',
agent_mode_desc_affiliate_3: '字段说明:可配置联营成本扣除比例与负结转余额;切换到该模式会自动清空返水比例。',
turnover_share_rate: '返水分红比例',
settlement_handling_fee: '代理结算手续费(%)',
settlement_handling_fee_tip: '按该代理费前佣金的百分比扣除,每期每代理扣一次;手动结算时可单独调整',
settlement_handling_fee_percent: '手续费(%)',
settlement_handling_fee_amount: '手续费金额',
manual_settle_settlement_base: '结算基数',
manual_settle_net_commission: '实发佣金',
manual_settle_col_base: '基数',
manual_settle_col_share: '比例',
manual_settle_col_gross: '佣金',
manual_settle_col_commission_share: '占比',
manual_settle_col_net_short: '实发',
manual_settle_col_fee: '手续费',
manual_settle_col_net: '实发',
manual_settle_split_scroll_tip: '左右滑动查看全部分配列',
affiliate_share_rate: '联营占成比例',
affiliate_fee_rate: '联营成本扣除比例',
affiliate_contract_no: '联营契约编号',
@@ -72,6 +86,17 @@ export default {
manual_settle_commission_amount: '佣金金额',
manual_settle_submit: '结算',
manual_settle_remark: '备注',
manual_settle_calc_title: '结算计算说明',
manual_settle_calc_intro_turnover_1: '本期统计区间内,汇总该渠道已结算注单的总投注额与总派彩额,平台盈亏 = 总投注 总派彩。',
manual_settle_calc_intro_turnover_2: '渠道本期可分配佣金 = 结算基数(总投注额)× 返水分红比例;下方表格按代理树自上而下拆分该笔佣金。',
manual_settle_calc_intro_turnover_3: '仅当平台大盘盈利时参与分红;若大盘亏损或持平,本期渠道佣金为 0。',
manual_settle_calc_intro_affiliate_1: '本期统计区间内,按该渠道辖区净客损(平台盈亏)及联营规则计算可分配佣金。',
manual_settle_calc_intro_affiliate_2: '渠道本期可分配佣金 = 扣除联营成本后的结算基数 × 阶梯占成比例;下方表格按代理树拆分。',
manual_settle_calc_intro_affiliate_3: '净客损为负或持平时,本期可分配佣金可能为 0以实际预览金额为准。',
manual_settle_calc_tree_1: '分配树可点击展开/收起;每一行对应该代理在本期分到的金额。',
manual_settle_calc_tree_2: '结算基数 = 上级代理结算后分给本代理的金额;分配比例 = 从上级佣金中抽取的百分比;佣金金额 = 本代理实得(费前)。',
manual_settle_calc_tree_3: '佣金占比 = 该代理费前佣金 ÷ 渠道本期总佣金 × 100%,表示占全部可分配佣金的比例。',
manual_settle_calc_handling_fee: '实发佣金 = 佣金金额 手续费金额;手续费按渠道配置 {rate}%(费前佣金比例)扣除,每期每代理扣一次。',
share_config: '分配比例',
share_config_title: '渠道管理员分配比例',
share_config_tip: '仅启用项参与结算拆分且启用项占比总和必须等于100%。',

View File

@@ -109,6 +109,14 @@ const baTable = new baTableClass(
operator: 'RANGE',
formatter: formatAmount2,
},
{
label: t('agent.commissionRecord.handling_fee'),
prop: 'handling_fee',
align: 'center',
minWidth: 100,
operator: 'RANGE',
formatter: formatAmount2,
},
{
label: t('agent.commissionRecord.status'),
prop: 'status',

View File

@@ -42,7 +42,7 @@
<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="adminInfo.super && auth('batchSettlePending')" type="warning" @click="onBatchSettlePending">
<el-button v-if="auth('batchSettlePending')" type="warning" @click="onBatchSettlePending">
{{ t('channel.batch_settle_pending') }}
</el-button>
</div>
@@ -53,17 +53,26 @@
<PopupForm />
<el-dialog
class="ba-operate-dialog manual-settle-dialog"
class="manual-settle-dialog"
:close-on-click-modal="false"
:model-value="manualSettle.visible"
width="860px"
:width="manualSettleDialogWidth"
align-center
append-to-body
destroy-on-close
@close="closeManualSettleDialog"
@opened="dismissFloatingTooltips"
>
<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" class="manual-settle-form">
<el-form
:model="manualSettle.form"
:label-width="manualSettleFormLabelWidth"
:label-position="manualSettleFormLabelPosition"
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>
@@ -92,13 +101,97 @@
<el-input v-model="manualSettle.form.commission_amount" readonly />
</el-form-item>
<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>
</el-table-column>
<el-table-column prop="commission_amount" :label="t('channel.manual_settle_commission_amount')" min-width="110" />
</el-table>
<div class="manual-settle-split-block">
<div
class="manual-settle-split-table-scroll"
:class="{ 'is-mobile': manualSettleViewportMobile }"
>
<div
class="manual-settle-split-table-inner"
:class="{ 'is-mobile': manualSettleViewportMobile }"
:style="manualSettleSplitInnerStyle"
>
<el-table
:data="manualSettleSplitTree"
row-key="admin_id"
:tree-props="{ children: 'children' }"
default-expand-all
border
size="small"
:fit="!manualSettleViewportMobile"
class="manual-settle-split-table"
:class="{ 'is-mobile': manualSettleViewportMobile, 'w100': !manualSettleViewportMobile }"
:table-layout="manualSettleTableLayout"
>
<el-table-column
prop="admin_username"
:label="t('channel.admin__username')"
:min-width="manualSettleViewportMobile ? undefined : manualSettleSplitCol.adminWidth"
:width="manualSettleViewportMobile ? manualSettleSplitCol.adminWidth : undefined"
:show-overflow-tooltip="!manualSettleViewportMobile"
/>
<el-table-column
prop="settlement_base_amount"
:label="t('channel.manual_settle_col_base')"
:width="manualSettleSplitCol.baseWidth"
align="center"
:formatter="formatSplitAmountCell"
/>
<el-table-column
prop="share_rate"
:label="t('channel.manual_settle_col_share')"
:width="manualSettleSplitCol.shareWidth"
align="center"
>
<template #default="scope">{{ scope.row.share_rate }}%</template>
</el-table-column>
<el-table-column
prop="commission_amount"
:label="t('channel.manual_settle_col_gross')"
:width="manualSettleSplitCol.grossWidth"
align="center"
:formatter="formatSplitAmountCell"
/>
<el-table-column
prop="commission_share_percent"
:label="t('channel.manual_settle_col_commission_share')"
:width="manualSettleSplitCol.commissionShareWidth"
align="center"
>
<template #default="scope">{{ formatCommissionSharePercent(scope.row) }}</template>
</el-table-column>
<el-table-column
prop="handling_fee"
:label="t('channel.manual_settle_col_fee')"
:width="manualSettleSplitCol.feeWidth"
align="center"
:formatter="formatSplitAmountCell"
/>
<el-table-column
:label="t('channel.manual_settle_col_net')"
:width="manualSettleSplitCol.netWidth"
align="center"
>
<template #default="scope">{{ formatNetCommission(scope.row) }}</template>
</el-table-column>
</el-table>
</div>
<p v-if="manualSettleViewportMobile" class="manual-settle-split-scroll-tip">
{{ t('channel.manual_settle_split_scroll_tip') }}
</p>
</div>
<el-alert
class="manual-settle-calc-alert"
:title="t('channel.manual_settle_calc_title')"
type="info"
:closable="false"
show-icon
>
<ul class="manual-settle-calc-list">
<li v-for="(line, idx) in manualSettleCalcDescLines" :key="idx">{{ line }}</li>
</ul>
</el-alert>
</div>
</el-form-item>
<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" />
@@ -328,13 +421,12 @@
</template>
<script setup lang="ts">
import { onMounted, provide, reactive, ref, useTemplateRef } from 'vue'
import { computed, nextTick, onMounted, onUnmounted, provide, reactive, ref, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { ElMessage } from 'element-plus'
import PopupForm from './popupForm.vue'
import { baTableApi } from '/@/api/common'
import { auth } from '/@/utils/common'
import { useAdminInfo } from '/@/stores/adminInfo'
import { defaultOptButtons } from '/@/components/table'
import TableHeader from '/@/components/table/header/index.vue'
import Table from '/@/components/table/index.vue'
@@ -346,7 +438,76 @@ defineOptions({
})
const { t } = useI18n()
const adminInfo = useAdminInfo()
const MANUAL_SETTLE_MOBILE_BREAKPOINT = 768
const manualSettleViewportMobile = ref(typeof window !== 'undefined' ? window.innerWidth <= MANUAL_SETTLE_MOBILE_BREAKPOINT : false)
const manualSettleDialogWidth = computed(() => (manualSettleViewportMobile.value ? '96%' : '860px'))
const manualSettleFormLabelPosition = computed(() => (manualSettleViewportMobile.value ? 'top' : 'right'))
const manualSettleFormLabelWidth = computed(() => (manualSettleViewportMobile.value ? 'auto' : '140px'))
const manualSettleTableLayout = computed(() => 'fixed')
const manualSettleSplitCol = computed(() => {
if (manualSettleViewportMobile.value) {
return {
adminWidth: 120,
baseWidth: 72,
shareWidth: 58,
grossWidth: 72,
commissionShareWidth: 62,
feeWidth: 64,
netWidth: 72,
}
}
return {
adminWidth: 108,
baseWidth: 76,
shareWidth: 58,
grossWidth: 72,
commissionShareWidth: 62,
feeWidth: 64,
netWidth: 72,
}
})
const manualSettleSplitTableMinWidth = computed(() => {
const col = manualSettleSplitCol.value
return (
col.adminWidth +
col.baseWidth +
col.shareWidth +
col.grossWidth +
col.commissionShareWidth +
col.feeWidth +
col.netWidth +
32
)
})
const manualSettleSplitInnerStyle = computed(() => {
if (!manualSettleViewportMobile.value) {
return {}
}
return {
width: `${manualSettleSplitTableMinWidth.value}px`,
}
})
const syncManualSettleViewport = () => {
if (typeof window === 'undefined') {
return
}
manualSettleViewportMobile.value = window.innerWidth <= MANUAL_SETTLE_MOBILE_BREAKPOINT
}
const dismissFloatingTooltips = () => {
if (typeof document === 'undefined') {
return
}
document.querySelectorAll('.el-popper[role="tooltip"]').forEach((node) => node.remove())
const active = document.activeElement
if (active instanceof HTMLElement) {
active.blur()
}
}
const tableRef = useTemplateRef('tableRef')
let optButtons: OptButton[] = [
{
@@ -371,7 +532,7 @@ let optButtons: OptButton[] = [
type: 'warning',
icon: 'el-icon-Clock',
class: 'table-row-manual-settle',
disabledTip: false,
disabledTip: true,
display: () => auth('manualSettle'),
click: (row: TableRow) => {
void openManualSettleDialog(row)
@@ -385,6 +546,33 @@ const formatAmountInt = (_row: any, _column: any, cellValue: number | string | n
if (Number.isNaN(num)) return '-'
return `${num}`
}
const formatCommissionSharePercent = (row: { commission_amount?: string | number; commission_share_percent?: string | number }) => {
const preset = row.commission_share_percent
if (preset !== null && preset !== undefined && preset !== '') {
const n = Number(preset)
if (Number.isFinite(n)) {
return `${n.toFixed(2)}%`
}
}
const total = Number(manualSettle.form.commission_amount ?? 0)
const gross = Number(row.commission_amount ?? 0)
if (!Number.isFinite(total) || total <= 0 || !Number.isFinite(gross) || gross <= 0) {
return '0.00%'
}
return `${((gross / total) * 100).toFixed(2)}%`
}
const formatSplitAmountCell = (_row: anyObj, _column: any, cellValue: unknown) => {
if (cellValue === null || cellValue === undefined || cellValue === '') {
return '-'
}
const n = Number(cellValue)
if (!Number.isFinite(n)) {
return String(cellValue)
}
return n.toFixed(2)
}
const formatAmount2 = (_row: any, _column: any, cellValue: number | string | null) => {
if (cellValue === null || cellValue === undefined || cellValue === '') return '-'
const num = Number(cellValue)
@@ -434,7 +622,21 @@ const manualSettle = reactive({
commission_rate: '',
calc_base_amount: '',
commission_amount: '',
commission_split: [] as Array<{ admin_id: number; admin_username: string; share_rate: string; commission_amount: string }>,
agent_mode: 'turnover' as string,
settlement_handling_fee: '0.00',
commission_split: [] as Array<{
admin_id: number
admin_username: string
parent_admin_id?: number
level?: number
settlement_base_amount?: string
share_rate: string
commission_amount: string
commission_share_percent?: string
handling_fee_rate: number | string
handling_fee?: string
net_commission_amount?: string
}>,
remark: '',
},
})
@@ -496,18 +698,105 @@ const resetManualSettleForm = () => {
manualSettle.form.calc_base_amount = ''
manualSettle.form.commission_amount = ''
manualSettle.form.commission_split = []
manualSettle.form.agent_mode = 'turnover'
manualSettle.form.settlement_handling_fee = '0.00'
manualSettle.form.remark = ''
}
type ManualSettleSplitRow = {
admin_id: number
admin_username: string
parent_admin_id?: number
level?: number
settlement_base_amount?: string
share_rate: string
commission_amount: string
commission_share_percent?: string
handling_fee_rate: number | string
handling_fee?: string
net_commission_amount?: string
children?: ManualSettleSplitRow[]
}
const buildCommissionSplitTree = (flat: ManualSettleSplitRow[]): ManualSettleSplitRow[] => {
if (!flat.length) {
return []
}
const nodeMap = new Map<number, ManualSettleSplitRow>()
for (const row of flat) {
nodeMap.set(row.admin_id, { ...row, children: [] })
}
const roots: ManualSettleSplitRow[] = []
for (const row of flat) {
const node = nodeMap.get(row.admin_id)
if (!node) {
continue
}
const parentId = Number(row.parent_admin_id ?? 0)
if (parentId > 0 && nodeMap.has(parentId)) {
const parent = nodeMap.get(parentId)
if (parent) {
if (!parent.children) {
parent.children = []
}
parent.children.push(node)
}
continue
}
roots.push(node)
}
const pruneEmptyChildren = (nodes: ManualSettleSplitRow[]) => {
for (const node of nodes) {
if (node.children && node.children.length > 0) {
pruneEmptyChildren(node.children)
} else {
delete node.children
}
}
}
pruneEmptyChildren(roots)
return roots
}
const manualSettleSplitTree = computed(() => buildCommissionSplitTree(manualSettle.form.commission_split))
const manualSettleCalcDescLines = computed(() => {
const mode = manualSettle.form.agent_mode === 'affiliate' ? 'affiliate' : 'turnover'
const feeRate = manualSettle.form.settlement_handling_fee
const prefix =
mode === 'affiliate'
? [
t('channel.manual_settle_calc_intro_affiliate_1'),
t('channel.manual_settle_calc_intro_affiliate_2'),
t('channel.manual_settle_calc_intro_affiliate_3'),
]
: [
t('channel.manual_settle_calc_intro_turnover_1'),
t('channel.manual_settle_calc_intro_turnover_2'),
t('channel.manual_settle_calc_intro_turnover_3'),
]
return [
...prefix,
t('channel.manual_settle_calc_tree_1'),
t('channel.manual_settle_calc_tree_2'),
t('channel.manual_settle_calc_tree_3'),
t('channel.manual_settle_calc_handling_fee', { rate: feeRate }),
]
})
const closeManualSettleDialog = () => {
manualSettle.visible = false
resetManualSettleForm()
}
const openManualSettleDialog = async (row: TableRow) => {
dismissFloatingTooltips()
syncManualSettleViewport()
manualSettle.channelId = row.id
resetManualSettleForm()
manualSettle.visible = true
await nextTick()
dismissFloatingTooltips()
manualSettle.previewLoading = true
try {
const res = await createAxios(
@@ -532,7 +821,9 @@ const openManualSettleDialog = async (row: TableRow) => {
manualSettle.form.commission_rate = d.commission_rate ?? ''
manualSettle.form.calc_base_amount = d.calc_base_amount ?? ''
manualSettle.form.commission_amount = d.commission_amount ?? ''
manualSettle.form.commission_split = Array.isArray(d.commission_split) ? d.commission_split : []
manualSettle.form.agent_mode = d.agent_mode ?? 'turnover'
manualSettle.form.settlement_handling_fee = d.settlement_handling_fee ?? '0.00'
manualSettle.form.commission_split = normalizeManualSettleSplit(d.commission_split, d.settlement_handling_fee)
manualSettle.form.remark = `${t('channel.manual_settle')}-CH${row.id}`
} catch {
manualSettle.visible = false
@@ -541,6 +832,64 @@ const openManualSettleDialog = async (row: TableRow) => {
}
}
const calcHandlingFeeByPercent = (gross: number, ratePercent: number) => {
const g = Number.isFinite(gross) && gross > 0 ? gross : 0
let rate = Number.isFinite(ratePercent) ? ratePercent : 0
if (rate < 0) rate = 0
if (rate > 100) rate = 100
return Math.round(g * rate * 100) / 10000
}
const applyManualSettleRowAmounts = (row: {
commission_amount?: string | number
handling_fee_rate?: string | number
handling_fee?: string | number
net_commission_amount?: string
}) => {
const gross = Number(row.commission_amount ?? 0)
const rate = Number(row.handling_fee_rate ?? 0)
const feeAmount = calcHandlingFeeByPercent(gross, rate)
row.handling_fee = feeAmount.toFixed(2)
row.net_commission_amount = Math.max(0, (Number.isFinite(gross) ? gross : 0) - feeAmount).toFixed(2)
}
const normalizeManualSettleSplit = (rows: unknown, defaultFeeRate: unknown) => {
const feeDefault = Number(defaultFeeRate)
const baseRate = Number.isFinite(feeDefault) && feeDefault >= 0 ? Math.min(100, feeDefault) : 0
if (!Array.isArray(rows)) {
return []
}
return rows.map((row: anyObj) => {
let rate = Number(row.handling_fee_rate ?? row.handling_fee ?? baseRate)
if (!Number.isFinite(rate) || rate < 0) {
rate = baseRate
}
if (rate > 100) {
rate = 100
}
const normalized = {
...row,
handling_fee_rate: rate,
}
applyManualSettleRowAmounts(normalized)
return normalized
})
}
const formatNetCommission = (row: {
commission_amount?: string | number
handling_fee_rate?: string | number
net_commission_amount?: string
}) => {
if (row.net_commission_amount !== undefined && row.net_commission_amount !== '') {
return row.net_commission_amount
}
const gross = Number(row.commission_amount ?? 0)
const rate = Number(row.handling_fee_rate ?? 0)
const net = Math.max(0, (Number.isFinite(gross) ? gross : 0) - calcHandlingFeeByPercent(gross, rate))
return net.toFixed(2)
}
const submitManualSettle = async () => {
if (!manualSettle.channelId) return
manualSettle.loading = true
@@ -552,6 +901,10 @@ const submitManualSettle = async () => {
data: {
id: manualSettle.channelId,
remark: manualSettle.form.remark,
commission_split: manualSettle.form.commission_split.map((row) => ({
admin_id: row.admin_id,
handling_fee_rate: row.handling_fee_rate ?? 0,
})),
},
},
{ showSuccessMessage: true }
@@ -944,6 +1297,7 @@ const baTable = new baTableClass(
defaultItems: {
status: '1',
agent_mode: 'turnover',
settlement_handling_fee: 0,
settle_cycle: 'weekly',
settle_weekday: 1,
settle_monthday: 1,
@@ -976,6 +1330,8 @@ baTable.after.getData = () => {
provide('baTable', baTable)
onMounted(() => {
syncManualSettleViewport()
window.addEventListener('resize', syncManualSettleViewport)
baTable.table.ref = tableRef.value
baTable.mount()
baTable.getData()?.then(() => {
@@ -984,6 +1340,10 @@ onMounted(() => {
})
void loadSettleStats()
})
onUnmounted(() => {
window.removeEventListener('resize', syncManualSettleViewport)
})
</script>
<style scoped lang="scss">
@@ -1119,16 +1479,59 @@ onMounted(() => {
flex-wrap: wrap;
}
/* 手动结算弹窗:可滚动(勿使用 ba-operate-dialog 固定 58vh 高度) */
:deep(.manual-settle-dialog.el-dialog) {
display: flex !important;
flex-direction: column;
width: 92% !important;
max-width: 860px;
max-height: 92vh;
margin: 4vh auto !important;
padding-bottom: 0;
overflow: hidden;
}
:deep(.manual-settle-dialog .el-dialog__header) {
flex-shrink: 0;
padding: 12px 16px;
margin-right: 0;
}
:deep(.manual-settle-dialog .el-dialog__body) {
flex: 1 1 auto;
min-height: 0;
height: auto !important;
max-height: calc(92vh - 120px);
overflow-y: auto !important;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
overscroll-behavior: contain;
padding: 12px 16px 16px;
}
:deep(.manual-settle-dialog .el-dialog__footer) {
flex-shrink: 0;
position: static;
width: auto;
box-shadow: none;
border-top: 1px solid var(--el-border-color-lighter);
}
.manual-settle-dialog-body {
max-height: min(70vh, 680px);
overflow: auto;
padding-right: 2px;
min-height: 0;
overflow: visible;
}
:deep(.manual-settle-dialog-body .el-loading-mask) {
border-radius: 4px;
}
.manual-settle-form {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
column-gap: 16px;
min-width: 0;
max-width: 100%;
}
.manual-settle-form :deep(.el-form-item) {
@@ -1137,6 +1540,127 @@ onMounted(() => {
.manual-settle-form-item-full {
grid-column: 1 / -1;
min-width: 0;
}
.manual-settle-form-item-full :deep(.el-form-item__content) {
min-width: 0;
max-width: 100%;
}
.manual-settle-split-block {
width: 100%;
max-width: 100%;
min-width: 0;
overflow: hidden;
}
.manual-settle-split-table-scroll {
width: 100%;
max-width: 100%;
min-width: 0;
overflow: hidden;
}
.manual-settle-split-table-scroll.is-mobile {
overflow-x: scroll;
overflow-y: hidden;
overscroll-behavior-x: contain;
-webkit-overflow-scrolling: touch;
touch-action: pan-x;
border: 1px solid var(--el-border-color-lighter);
border-radius: 6px;
background: var(--el-fill-color-blank);
}
.manual-settle-split-table-inner.is-mobile {
display: inline-block;
max-width: none;
vertical-align: top;
}
.manual-settle-split-table-scroll.is-mobile :deep(.el-table) {
width: 100% !important;
}
.manual-settle-split-table-scroll.is-mobile :deep(.el-table__inner-wrapper) {
width: 100% !important;
}
.manual-settle-split-table-scroll.is-mobile :deep(.el-table__body-wrapper),
.manual-settle-split-table-scroll.is-mobile :deep(.el-table__header-wrapper) {
overflow: visible !important;
}
.manual-settle-split-table-scroll.is-mobile :deep(.el-scrollbar__wrap) {
overflow: visible !important;
}
.manual-settle-split-table-scroll.is-mobile :deep(.el-scrollbar__bar.is-horizontal) {
display: none !important;
}
.manual-settle-split-scroll-tip {
margin: 6px 0 0;
font-size: 11px;
line-height: 1.4;
color: var(--el-text-color-secondary);
text-align: center;
}
.manual-settle-split-table:not(.is-mobile) {
width: 100%;
}
.manual-settle-split-table :deep(.el-table__header th.el-table__cell),
.manual-settle-split-table :deep(.el-table__body td.el-table__cell) {
padding: 6px 4px;
}
.manual-settle-split-table :deep(.el-table__header .cell),
.manual-settle-split-table :deep(.el-table__body .cell) {
padding: 0 2px;
font-size: 12px;
line-height: 1.35;
word-break: break-all;
}
.manual-settle-split-table :deep(.el-table__header .cell) {
white-space: normal;
}
.manual-settle-split-table.is-mobile :deep(.el-table__header th.el-table__cell),
.manual-settle-split-table.is-mobile :deep(.el-table__body td.el-table__cell) {
padding: 5px 3px;
}
.manual-settle-split-table.is-mobile :deep(.el-table__header .cell),
.manual-settle-split-table.is-mobile :deep(.el-table__body .cell) {
font-size: 11px;
line-height: 1.3;
white-space: nowrap;
word-break: keep-all;
overflow-wrap: normal;
}
.manual-settle-split-table.is-mobile :deep(.el-table__body td:first-child .cell) {
white-space: nowrap;
word-break: keep-all;
}
.manual-settle-calc-alert {
margin-top: 12px;
}
.manual-settle-calc-list {
margin: 0;
padding-left: 18px;
line-height: 1.6;
font-size: 13px;
}
.manual-settle-calc-list li + li {
margin-top: 4px;
}
.manual-settle-footer {
@@ -1207,6 +1731,82 @@ onMounted(() => {
}
@media (max-width: 768px) {
:deep(.manual-settle-dialog.el-dialog) {
width: 96% !important;
max-width: none;
max-height: 94vh;
margin: 3vh auto !important;
}
:deep(.manual-settle-dialog .el-dialog__header) {
padding: 10px 12px;
}
:deep(.manual-settle-dialog .el-dialog__body) {
max-height: calc(94vh - 96px);
padding: 10px 10px 12px;
}
:deep(.manual-settle-dialog .el-dialog__footer) {
padding: 8px 10px 10px;
}
.manual-settle-form :deep(.el-form-item) {
margin-bottom: 10px;
}
.manual-settle-form :deep(.el-form-item__label) {
padding-bottom: 4px;
line-height: 1.4;
}
.manual-settle-form-item-full :deep(.el-form-item__content) {
width: 100%;
max-width: 100%;
min-width: 0;
}
.manual-settle-split-block {
max-width: 100%;
min-width: 0;
overflow: hidden;
margin: 0;
padding-bottom: 0;
}
.manual-settle-split-table-scroll.is-mobile {
max-width: 100%;
}
.manual-settle-calc-alert {
margin-top: 10px;
}
.manual-settle-calc-alert :deep(.el-alert__title) {
font-size: 13px;
line-height: 1.4;
}
.manual-settle-calc-alert :deep(.el-alert__content) {
max-height: none;
overflow: visible;
}
.manual-settle-calc-list {
font-size: 12px;
padding-left: 16px;
}
.manual-settle-footer {
flex-wrap: wrap;
justify-content: stretch;
}
.manual-settle-footer .el-button {
flex: 1;
margin: 0;
}
:deep(.channel-record-dialog.el-dialog) {
width: 96% !important;
max-height: 94vh;

View File

@@ -69,6 +69,14 @@
:input-attr="{ step: 0.01, precision: 2, min: 0, max: 100 }"
:placeholder="`${t('Please input field', { field: t('channel.turnover_share_rate') })} (例如 30.5)`"
/>
<FormItem
:label="t('channel.settlement_handling_fee')"
type="number"
v-model="baTable.form.items!.settlement_handling_fee"
prop="settlement_handling_fee"
:input-attr="{ step: 0.01, precision: 2, min: 0, max: 100 }"
:placeholder="t('channel.settlement_handling_fee_tip')"
/>
<FormItem
v-if="currentAgentMode === 'affiliate'"
:label="t('channel.affiliate_contract_no')"