1.修改电话号码格式为60前缀,马来西亚格式
2.优化渠道可以查看分红方式,可以查看游玩详情
This commit is contained in:
@@ -83,6 +83,33 @@ export default {
|
||||
settle_stats_enabled: 'Enabled channels',
|
||||
settle_stats_pending_dividend: 'Channels pending dividend',
|
||||
settle_stats_pending_amount: 'Pending dividend amount',
|
||||
settle_stats_paid_dividend: 'Paid dividend amount',
|
||||
direct_bet_amount: 'Direct bet amount',
|
||||
view_settlement_bet: 'View settlement bets',
|
||||
dividend_record_dialog_title: 'Paid dividend records',
|
||||
direct_bet_record_dialog_title: 'Direct player bet records',
|
||||
settlement_bet_record_dialog_title: 'Dividend-scope bet records',
|
||||
bet_record_period_no: 'Period No.',
|
||||
bet_record_user_username: 'Player',
|
||||
bet_record_total_amount: 'Bet amount',
|
||||
bet_record_win_amount: 'Win amount',
|
||||
bet_record_channel_name: 'Channel',
|
||||
bet_record_pick_numbers: 'Picks',
|
||||
bet_record_result_number: 'Winning number',
|
||||
bet_record_win_hit: 'Win status',
|
||||
bet_record_win_hit_won: 'Won',
|
||||
bet_record_win_hit_lost: 'Lost',
|
||||
bet_record_win_hit_pending: 'Pending',
|
||||
bet_record_pick_filter_placeholder: 'Number',
|
||||
bet_record_summary_count: 'Total records',
|
||||
bet_record_summary_bet: 'Total bet',
|
||||
bet_record_summary_win: 'Total win',
|
||||
dividend_settlement_no: 'Settlement No.',
|
||||
dividend_channel_name: 'Channel',
|
||||
dividend_admin_username: 'Agent',
|
||||
dividend_commission_amount: 'Dividend amount',
|
||||
dividend_settled_at: 'Paid at',
|
||||
dividend_period_range: 'Settlement period',
|
||||
settle_filter_all: 'All',
|
||||
settle_filter_with_balance: 'With dividend balance',
|
||||
settle_filter_no_balance: 'No dividend balance',
|
||||
|
||||
@@ -83,6 +83,33 @@ export default {
|
||||
settle_stats_enabled: '启用渠道',
|
||||
settle_stats_pending_dividend: '待分红渠道',
|
||||
settle_stats_pending_amount: '待分红总额',
|
||||
settle_stats_paid_dividend: '已分红金额',
|
||||
direct_bet_amount: '直属投注额',
|
||||
view_settlement_bet: '查看总投注金额',
|
||||
dividend_record_dialog_title: '已分红记录',
|
||||
direct_bet_record_dialog_title: '直属玩家下注记录',
|
||||
settlement_bet_record_dialog_title: '分红口径下注记录',
|
||||
bet_record_period_no: '游戏期号',
|
||||
bet_record_user_username: '玩家名',
|
||||
bet_record_total_amount: '投注金额',
|
||||
bet_record_win_amount: '玩家中奖金额',
|
||||
bet_record_channel_name: '渠道',
|
||||
bet_record_pick_numbers: '选号',
|
||||
bet_record_result_number: '中奖号码',
|
||||
bet_record_win_hit: '中奖状态',
|
||||
bet_record_win_hit_won: '已中奖',
|
||||
bet_record_win_hit_lost: '未中奖',
|
||||
bet_record_win_hit_pending: '待开奖',
|
||||
bet_record_pick_filter_placeholder: '号码',
|
||||
bet_record_summary_count: '总笔数',
|
||||
bet_record_summary_bet: '总投注额',
|
||||
bet_record_summary_win: '总中奖额',
|
||||
dividend_settlement_no: '结算单号',
|
||||
dividend_channel_name: '渠道',
|
||||
dividend_admin_username: '代理账号',
|
||||
dividend_commission_amount: '分红金额',
|
||||
dividend_settled_at: '发放时间',
|
||||
dividend_period_range: '结算周期',
|
||||
settle_filter_all: '全部',
|
||||
settle_filter_with_balance: '有分红余额',
|
||||
settle_filter_no_balance: '无分红余额',
|
||||
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
'The correct area is not clicked, please try again!': 'The correct area is not clicked, please try again!',
|
||||
'Verification is successful!': 'Verification is successful!',
|
||||
'Please click': 'Please click',
|
||||
'Please enter the correct mobile number': 'Please enter the correct mobile number',
|
||||
'Please enter the correct mobile number': 'Please enter a valid Malaysia mobile number starting with 60',
|
||||
'Please enter the correct account': 'The account requires 3 to 15 characters and contains a-z A-Z 0-9 _',
|
||||
'Please enter the correct password': 'The password requires 6 to 32 characters and cannot contains & < > " \'',
|
||||
'Please enter the correct name': 'Please enter the correct name',
|
||||
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
'The correct area is not clicked, please try again!': '未点中正确区域,请重试!',
|
||||
'Verification is successful!': '验证成功!',
|
||||
'Please click': '请依次点击',
|
||||
'Please enter the correct mobile number': '请输入正确的手机号',
|
||||
'Please enter the correct mobile number': '请输入正确的马来西亚手机号(60开头)',
|
||||
'Please enter the correct account': '要求3到15位,字母开头且只含字母、数字、下划线',
|
||||
'Please enter the correct password': '密码要求6到32位,不能包含 & < > " \'',
|
||||
'Please enter the correct name': '请输入正确的名称',
|
||||
|
||||
@@ -2,6 +2,11 @@ import type { RuleType } from 'async-validator'
|
||||
import type { FormItemRule } from 'element-plus'
|
||||
import { i18n } from '../lang'
|
||||
|
||||
/**
|
||||
* 马来西亚手机号(60 国际前缀,不含 +)
|
||||
*/
|
||||
export const malaysiaMobilePattern = /^60(1[0-9])\d{7,9}$/
|
||||
|
||||
/**
|
||||
* 手机号码验证
|
||||
*/
|
||||
@@ -10,7 +15,7 @@ export function validatorMobile(rule: any, mobile: string | number, callback: Fu
|
||||
if (!mobile) {
|
||||
return callback()
|
||||
}
|
||||
if (!/^(1[3-9])\d{9}$/.test(mobile.toString())) {
|
||||
if (!malaysiaMobilePattern.test(mobile.toString())) {
|
||||
return callback(new Error(i18n.global.t('validate.Please enter the correct mobile number')))
|
||||
}
|
||||
return callback()
|
||||
|
||||
@@ -24,6 +24,15 @@
|
||||
<div class="label">{{ t('channel.settle_stats_pending_amount') }}</div>
|
||||
<div class="value">{{ settleStats.carryover_positive_total }}</div>
|
||||
</el-card>
|
||||
<el-card
|
||||
shadow="never"
|
||||
class="channel-stat-card"
|
||||
:class="{ 'channel-stat-card-clickable': auth('viewDividendRecords') }"
|
||||
@click="onPaidDividendCardClick"
|
||||
>
|
||||
<div class="label">{{ t('channel.settle_stats_paid_dividend') }}</div>
|
||||
<div class="value">{{ settleStats.paid_dividend_total }}</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="channel-action-row">
|
||||
<el-radio-group v-model="settleFilterMode" size="small" @change="onSettleFilterChange">
|
||||
@@ -106,11 +115,220 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
class="channel-record-dialog"
|
||||
:close-on-click-modal="false"
|
||||
:model-value="dividendDialog.visible"
|
||||
width="92%"
|
||||
@close="closeDividendDialog"
|
||||
>
|
||||
<template #header>
|
||||
<div class="title">{{ t('channel.dividend_record_dialog_title') }}</div>
|
||||
</template>
|
||||
<div v-loading="dividendDialog.loading" class="channel-record-dialog__body">
|
||||
<div class="channel-record-table-wrap">
|
||||
<el-table :data="dividendDialog.list" border size="small" class="channel-record-table">
|
||||
<el-table-column prop="settlement_no" :label="t('channel.dividend_settlement_no')" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="channel_name" :label="t('channel.dividend_channel_name')" min-width="100" />
|
||||
<el-table-column prop="admin_username" :label="t('channel.dividend_admin_username')" min-width="100" />
|
||||
<el-table-column prop="commission_amount" :label="t('channel.dividend_commission_amount')" min-width="100" align="right" />
|
||||
<el-table-column :label="t('channel.dividend_period_range')" min-width="180">
|
||||
<template #default="scope">
|
||||
{{ scope.row.period_start_at || '-' }} ~ {{ scope.row.period_end_at || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="settled_at" :label="t('channel.dividend_settled_at')" min-width="150" />
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="channel-record-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
layout="total, prev, pager, next"
|
||||
:total="dividendDialog.total"
|
||||
:page-size="dividendDialog.limit"
|
||||
:current-page="dividendDialog.page"
|
||||
@current-change="onDividendPageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
class="channel-record-dialog channel-bet-record-dialog"
|
||||
:close-on-click-modal="false"
|
||||
:model-value="betRecordDialog.visible"
|
||||
width="92%"
|
||||
@close="closeBetRecordDialog"
|
||||
>
|
||||
<template #header>
|
||||
<div class="title">{{ betRecordDialog.title }}</div>
|
||||
</template>
|
||||
<div v-loading="betRecordDialog.loading" class="channel-record-dialog__body">
|
||||
<div class="channel-bet-summary">
|
||||
<el-card shadow="never" class="channel-bet-summary-card channel-stat-card">
|
||||
<div class="label">{{ t('channel.bet_record_summary_count') }}</div>
|
||||
<div class="value">{{ betRecordDialog.summary.record_count }}</div>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="channel-bet-summary-card channel-stat-card">
|
||||
<div class="label">{{ t('channel.bet_record_summary_bet') }}</div>
|
||||
<div class="value">{{ betRecordDialog.summary.total_bet_amount }}</div>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="channel-bet-summary-card channel-stat-card">
|
||||
<div class="label">{{ t('channel.bet_record_summary_win') }}</div>
|
||||
<div class="value">{{ betRecordDialog.summary.total_win_amount }}</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<el-form :inline="true" size="small" class="channel-bet-filter" @submit.prevent="onBetRecordSearch">
|
||||
<el-form-item :label="t('channel.bet_record_period_no')">
|
||||
<el-input
|
||||
v-model="betRecordDialog.filters.period_no"
|
||||
clearable
|
||||
:placeholder="t('Fuzzy query')"
|
||||
class="channel-bet-filter-input"
|
||||
@keyup.enter="onBetRecordSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('channel.bet_record_user_username')">
|
||||
<el-input
|
||||
v-model="betRecordDialog.filters.user_keyword"
|
||||
clearable
|
||||
:placeholder="t('Fuzzy query')"
|
||||
class="channel-bet-filter-input"
|
||||
@keyup.enter="onBetRecordSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('channel.bet_record_result_number')">
|
||||
<el-input
|
||||
v-model="betRecordDialog.filters.result_number"
|
||||
clearable
|
||||
class="channel-bet-filter-input--short"
|
||||
@keyup.enter="onBetRecordSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('channel.bet_record_pick_numbers')">
|
||||
<el-input
|
||||
v-model="betRecordDialog.filters.pick_number"
|
||||
clearable
|
||||
:placeholder="t('channel.bet_record_pick_filter_placeholder')"
|
||||
class="channel-bet-filter-input--short"
|
||||
@keyup.enter="onBetRecordSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('channel.bet_record_win_hit')">
|
||||
<el-select
|
||||
v-model="betRecordDialog.filters.win_hit"
|
||||
clearable
|
||||
:placeholder="t('Please select field', { field: t('channel.bet_record_win_hit') })"
|
||||
class="channel-bet-filter-select"
|
||||
>
|
||||
<el-option :label="t('channel.bet_record_win_hit_won')" value="won" />
|
||||
<el-option :label="t('channel.bet_record_win_hit_lost')" value="lost" />
|
||||
<el-option :label="t('channel.bet_record_win_hit_pending')" value="pending" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onBetRecordSearch">{{ t('Search') }}</el-button>
|
||||
<el-button @click="onBetRecordReset">{{ t('Reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="channel-record-table-wrap">
|
||||
<el-table
|
||||
:data="betRecordDialog.list"
|
||||
border
|
||||
size="small"
|
||||
class="channel-bet-record-table channel-record-table"
|
||||
>
|
||||
<el-table-column
|
||||
prop="period_no"
|
||||
:label="t('channel.bet_record_period_no')"
|
||||
min-width="120"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="user_username"
|
||||
:label="t('channel.bet_record_user_username')"
|
||||
min-width="120"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="channel_name"
|
||||
:label="t('channel.bet_record_channel_name')"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="pick_numbers"
|
||||
:label="t('channel.bet_record_pick_numbers')"
|
||||
min-width="120"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="result_number"
|
||||
:label="t('channel.bet_record_result_number')"
|
||||
min-width="90"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
:label="t('channel.bet_record_win_hit')"
|
||||
min-width="90"
|
||||
align="center"
|
||||
header-align="center"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
v-if="scope.row.win_hit"
|
||||
:type="betRecordWinHitTagType(scope.row.win_hit)"
|
||||
effect="dark"
|
||||
size="small"
|
||||
>
|
||||
{{ formatBetRecordWinHit(scope.row.win_hit) }}
|
||||
</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="total_amount"
|
||||
:label="t('channel.bet_record_total_amount')"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="win_amount"
|
||||
:label="t('channel.bet_record_win_amount')"
|
||||
min-width="100"
|
||||
align="center"
|
||||
header-align="center"
|
||||
/>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="channel-record-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
layout="total, prev, pager, next"
|
||||
:total="betRecordDialog.total"
|
||||
:page-size="betRecordDialog.limit"
|
||||
:current-page="betRecordDialog.page"
|
||||
@current-change="onBetRecordPageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, provide, reactive, ref, useTemplateRef } from 'vue'
|
||||
import { onMounted, provide, reactive, ref, useTemplateRef } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import PopupForm from './popupForm.vue'
|
||||
@@ -131,6 +349,20 @@ const { t } = useI18n()
|
||||
const adminInfo = useAdminInfo()
|
||||
const tableRef = useTemplateRef('tableRef')
|
||||
let optButtons: OptButton[] = [
|
||||
{
|
||||
render: 'tipButton',
|
||||
name: 'viewSettlementBet',
|
||||
title: 'channel.view_settlement_bet',
|
||||
text: '',
|
||||
type: 'info',
|
||||
icon: 'fa fa-list-alt',
|
||||
class: 'table-row-view-settlement-bet',
|
||||
disabledTip: false,
|
||||
display: () => auth('viewSettlementBetRecords'),
|
||||
click: (row: TableRow) => {
|
||||
void openBetRecordDialog('settlement', row)
|
||||
},
|
||||
},
|
||||
{
|
||||
render: 'tipButton',
|
||||
name: 'manualSettle',
|
||||
@@ -140,7 +372,7 @@ let optButtons: OptButton[] = [
|
||||
icon: 'el-icon-Clock',
|
||||
class: 'table-row-manual-settle',
|
||||
disabledTip: false,
|
||||
display: () => adminInfo.super && auth('manualSettle'),
|
||||
display: () => auth('manualSettle'),
|
||||
click: (row: TableRow) => {
|
||||
void openManualSettleDialog(row)
|
||||
},
|
||||
@@ -153,6 +385,30 @@ const formatAmountInt = (_row: any, _column: any, cellValue: number | string | n
|
||||
if (Number.isNaN(num)) return '-'
|
||||
return `${num}`
|
||||
}
|
||||
const formatAmount2 = (_row: any, _column: any, cellValue: number | string | null) => {
|
||||
if (cellValue === null || cellValue === undefined || cellValue === '') return '-'
|
||||
const num = Number(cellValue)
|
||||
if (Number.isNaN(num)) return '-'
|
||||
return num.toFixed(2)
|
||||
}
|
||||
const formatBetRecordWinHit = (code: unknown) => {
|
||||
const key = code === null || code === undefined ? '' : String(code)
|
||||
if (!key) return '-'
|
||||
const i18nKey = `channel.bet_record_win_hit_${key}`
|
||||
const text = t(i18nKey)
|
||||
return text !== i18nKey ? text : key
|
||||
}
|
||||
|
||||
const betRecordWinHitTagType = (code: unknown): 'success' | 'info' | 'warning' | 'danger' => {
|
||||
const key = code === null || code === undefined ? '' : String(code)
|
||||
const map: Record<string, 'success' | 'info' | 'warning' | 'danger'> = {
|
||||
won: 'success',
|
||||
lost: 'info',
|
||||
pending: 'warning',
|
||||
}
|
||||
return map[key] ?? 'info'
|
||||
}
|
||||
|
||||
const formatSettleDay = (row: anyObj) => {
|
||||
if (row.settle_cycle === 'weekly') {
|
||||
return t(`channel.weekday ${row.settle_weekday ?? 1}`)
|
||||
@@ -191,6 +447,42 @@ const settleStats = reactive({
|
||||
carryover_positive_count: 0,
|
||||
carryover_total: '0.00',
|
||||
carryover_positive_total: '0.00',
|
||||
paid_dividend_total: '0.00',
|
||||
})
|
||||
|
||||
const dividendDialog = reactive({
|
||||
visible: false,
|
||||
loading: false,
|
||||
page: 1,
|
||||
limit: 20,
|
||||
total: 0,
|
||||
list: [] as anyObj[],
|
||||
})
|
||||
|
||||
const createBetRecordFilters = () => ({
|
||||
period_no: '',
|
||||
user_keyword: '',
|
||||
result_number: '',
|
||||
pick_number: '',
|
||||
win_hit: '' as '' | 'won' | 'lost' | 'pending',
|
||||
})
|
||||
|
||||
const betRecordDialog = reactive({
|
||||
visible: false,
|
||||
loading: false,
|
||||
mode: '' as '' | 'direct' | 'settlement',
|
||||
channelId: 0,
|
||||
title: '',
|
||||
page: 1,
|
||||
limit: 20,
|
||||
total: 0,
|
||||
list: [] as anyObj[],
|
||||
filters: createBetRecordFilters(),
|
||||
summary: {
|
||||
record_count: 0,
|
||||
total_bet_amount: '0.00',
|
||||
total_win_amount: '0.00',
|
||||
},
|
||||
})
|
||||
|
||||
const resetManualSettleForm = () => {
|
||||
@@ -298,6 +590,156 @@ const loadSettleStats = async () => {
|
||||
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')
|
||||
settleStats.paid_dividend_total = String(res.data.paid_dividend_total ?? '0.00')
|
||||
}
|
||||
|
||||
const loadDividendRecords = async () => {
|
||||
dividendDialog.loading = true
|
||||
try {
|
||||
const res = await createAxios({
|
||||
url: '/admin/channel/dividendRecordList',
|
||||
method: 'get',
|
||||
params: { page: dividendDialog.page, limit: dividendDialog.limit },
|
||||
})
|
||||
if (res.code !== 1 || !res.data) {
|
||||
return
|
||||
}
|
||||
dividendDialog.list = Array.isArray(res.data.list) ? res.data.list : []
|
||||
dividendDialog.total = Number(res.data.total ?? 0)
|
||||
} finally {
|
||||
dividendDialog.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const onPaidDividendCardClick = () => {
|
||||
if (!auth('viewDividendRecords')) {
|
||||
return
|
||||
}
|
||||
dividendDialog.page = 1
|
||||
dividendDialog.visible = true
|
||||
void loadDividendRecords()
|
||||
}
|
||||
|
||||
const closeDividendDialog = () => {
|
||||
dividendDialog.visible = false
|
||||
dividendDialog.list = []
|
||||
dividendDialog.total = 0
|
||||
dividendDialog.page = 1
|
||||
}
|
||||
|
||||
const onDividendPageChange = (page: number) => {
|
||||
dividendDialog.page = page
|
||||
void loadDividendRecords()
|
||||
}
|
||||
|
||||
const resetBetRecordDialog = () => {
|
||||
betRecordDialog.mode = ''
|
||||
betRecordDialog.channelId = 0
|
||||
betRecordDialog.title = ''
|
||||
betRecordDialog.page = 1
|
||||
betRecordDialog.total = 0
|
||||
betRecordDialog.list = []
|
||||
betRecordDialog.summary = {
|
||||
record_count: 0,
|
||||
total_bet_amount: '0.00',
|
||||
total_win_amount: '0.00',
|
||||
}
|
||||
Object.assign(betRecordDialog.filters, createBetRecordFilters())
|
||||
}
|
||||
|
||||
const buildBetRecordFilterParams = () => {
|
||||
const f = betRecordDialog.filters
|
||||
const params: Record<string, string> = {}
|
||||
if (f.period_no.trim()) {
|
||||
params.period_no = f.period_no.trim()
|
||||
}
|
||||
if (f.user_keyword.trim()) {
|
||||
params.user_keyword = f.user_keyword.trim()
|
||||
}
|
||||
if (f.result_number.trim()) {
|
||||
params.result_number = f.result_number.trim()
|
||||
}
|
||||
if (f.pick_number.trim()) {
|
||||
params.pick_number = f.pick_number.trim()
|
||||
}
|
||||
if (f.win_hit) {
|
||||
params.win_hit = f.win_hit
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
const loadBetRecords = async () => {
|
||||
if (!betRecordDialog.channelId || !betRecordDialog.mode) {
|
||||
return
|
||||
}
|
||||
const url =
|
||||
betRecordDialog.mode === 'direct' ? '/admin/channel/directBetRecordList' : '/admin/channel/settlementBetRecordList'
|
||||
betRecordDialog.loading = true
|
||||
try {
|
||||
const res = await createAxios({
|
||||
url,
|
||||
method: 'get',
|
||||
params: {
|
||||
channel_id: betRecordDialog.channelId,
|
||||
page: betRecordDialog.page,
|
||||
limit: betRecordDialog.limit,
|
||||
...buildBetRecordFilterParams(),
|
||||
},
|
||||
})
|
||||
if (res.code !== 1 || !res.data) {
|
||||
return
|
||||
}
|
||||
betRecordDialog.list = Array.isArray(res.data.list) ? res.data.list : []
|
||||
betRecordDialog.total = Number(res.data.total ?? 0)
|
||||
const summary = res.data.summary
|
||||
if (summary && typeof summary === 'object') {
|
||||
betRecordDialog.summary.record_count = Number(summary.record_count ?? 0)
|
||||
betRecordDialog.summary.total_bet_amount = String(summary.total_bet_amount ?? '0.00')
|
||||
betRecordDialog.summary.total_win_amount = String(summary.total_win_amount ?? '0.00')
|
||||
}
|
||||
} finally {
|
||||
betRecordDialog.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const openBetRecordDialog = (mode: 'direct' | 'settlement', row: TableRow) => {
|
||||
const permission = mode === 'direct' ? 'viewDirectBetRecords' : 'viewSettlementBetRecords'
|
||||
if (!auth(permission)) {
|
||||
return
|
||||
}
|
||||
resetBetRecordDialog()
|
||||
betRecordDialog.mode = mode
|
||||
betRecordDialog.channelId = Number(row.id ?? 0)
|
||||
betRecordDialog.title =
|
||||
mode === 'direct'
|
||||
? `${t('channel.direct_bet_record_dialog_title')} - ${row.name ?? row.id}`
|
||||
: `${t('channel.settlement_bet_record_dialog_title')} - ${row.name ?? row.id}`
|
||||
betRecordDialog.visible = true
|
||||
void loadBetRecords()
|
||||
}
|
||||
|
||||
const closeBetRecordDialog = () => {
|
||||
betRecordDialog.visible = false
|
||||
resetBetRecordDialog()
|
||||
}
|
||||
|
||||
const onBetRecordPageChange = (page: number) => {
|
||||
betRecordDialog.page = page
|
||||
void loadBetRecords()
|
||||
}
|
||||
|
||||
const onBetRecordSearch = () => {
|
||||
betRecordDialog.page = 1
|
||||
void loadBetRecords()
|
||||
}
|
||||
|
||||
const onBetRecordReset = () => {
|
||||
Object.assign(betRecordDialog.filters, createBetRecordFilters())
|
||||
onBetRecordSearch()
|
||||
}
|
||||
|
||||
const openDirectBetDialog = (row: TableRow) => {
|
||||
void openBetRecordDialog('direct', row)
|
||||
}
|
||||
|
||||
const baTable = new baTableClass(
|
||||
@@ -420,6 +862,22 @@ const baTable = new baTableClass(
|
||||
sortable: false,
|
||||
operator: 'RANGE',
|
||||
},
|
||||
{
|
||||
label: t('channel.direct_bet_amount'),
|
||||
prop: 'direct_bet_amount',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
sortable: false,
|
||||
operator: false,
|
||||
render: 'tag',
|
||||
formatter: formatAmount2,
|
||||
customRenderAttr: {
|
||||
tag: ({ row }: { row: TableRow }) => ({
|
||||
class: auth('viewDirectBetRecords') ? 'channel-direct-bet-tag' : '',
|
||||
onClick: auth('viewDirectBetRecords') ? () => openDirectBetDialog(row) : undefined,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('channel.profit_amount'),
|
||||
prop: 'profit_amount',
|
||||
@@ -478,7 +936,7 @@ const baTable = new baTableClass(
|
||||
width: 160,
|
||||
timeFormat: 'yyyy-mm-dd hh:MM:ss',
|
||||
},
|
||||
{ label: t('Operate'), align: 'center', width: 120, render: 'buttons', buttons: optButtons, operator: false, fixed: 'right' },
|
||||
{ label: t('Operate'), align: 'center', width: 160, render: 'buttons', buttons: optButtons, operator: false, fixed: 'right' },
|
||||
],
|
||||
dblClickNotEditColumn: [undefined, 'status'],
|
||||
},
|
||||
@@ -556,11 +1014,91 @@ onMounted(() => {
|
||||
|
||||
.channel-stats-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.channel-stat-card-clickable {
|
||||
cursor: pointer;
|
||||
transition: box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.channel-stat-card-clickable:hover {
|
||||
box-shadow: 0 0 0 1px var(--el-color-primary-light-5);
|
||||
}
|
||||
|
||||
.channel-stat-card-clickable .value {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
:deep(.channel-direct-bet-tag) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.channel-bet-filter {
|
||||
margin-bottom: 12px;
|
||||
padding: 10px 12px 2px;
|
||||
background: var(--el-fill-color-lighter);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.channel-bet-filter :deep(.el-form-item) {
|
||||
margin-bottom: 8px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.channel-bet-filter-input {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.channel-bet-filter-input--short {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.channel-bet-filter-select {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.channel-bet-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.channel-bet-summary-card {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.channel-bet-summary-card .label {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.channel-bet-summary-card .value {
|
||||
margin-top: 6px;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.channel-bet-record-table :deep(.el-table__cell) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.channel-bet-record-table :deep(.cell) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.channel-record-pagination {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.channel-stat-card .label {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
@@ -607,6 +1145,57 @@ onMounted(() => {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 渠道记录弹窗:可滚动、适配移动端(勿使用 ba-operate-dialog 固定高度) */
|
||||
:deep(.channel-record-dialog.el-dialog) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 92vh;
|
||||
margin: 4vh auto !important;
|
||||
padding-bottom: 0;
|
||||
overflow: hidden;
|
||||
width: 92% !important;
|
||||
max-width: 1080px;
|
||||
}
|
||||
|
||||
:deep(.channel-record-dialog.channel-bet-record-dialog.el-dialog) {
|
||||
max-width: 1080px;
|
||||
}
|
||||
|
||||
:deep(.channel-record-dialog .el-dialog__header) {
|
||||
flex-shrink: 0;
|
||||
padding: 12px 16px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
:deep(.channel-record-dialog .el-dialog__body) {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
height: auto !important;
|
||||
max-height: calc(92vh - 56px);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 12px 14px 16px;
|
||||
}
|
||||
|
||||
.channel-record-dialog__body {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.channel-record-table-wrap {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.channel-record-table {
|
||||
min-width: 640px;
|
||||
}
|
||||
|
||||
.channel-bet-record-table {
|
||||
min-width: 880px;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.channel-stats-cards {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
@@ -616,4 +1205,80 @@ onMounted(() => {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
:deep(.channel-record-dialog.el-dialog) {
|
||||
width: 96% !important;
|
||||
max-height: 94vh;
|
||||
margin: 3vh auto !important;
|
||||
}
|
||||
|
||||
:deep(.channel-record-dialog .el-dialog__body) {
|
||||
max-height: calc(94vh - 52px);
|
||||
padding: 10px 10px 14px;
|
||||
}
|
||||
|
||||
.channel-bet-summary {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.channel-bet-summary-card :deep(.el-card__body) {
|
||||
padding: 8px 4px;
|
||||
}
|
||||
|
||||
.channel-bet-summary-card .label {
|
||||
font-size: 10px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.channel-bet-summary-card .value {
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.channel-bet-filter {
|
||||
padding: 8px 10px 0;
|
||||
}
|
||||
|
||||
.channel-bet-filter :deep(.el-form-item) {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.channel-bet-filter :deep(.el-form-item__label) {
|
||||
width: 72px !important;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
.channel-bet-filter :deep(.el-form-item__content) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.channel-bet-filter-input,
|
||||
.channel-bet-filter-input--short,
|
||||
.channel-bet-filter-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.channel-bet-filter :deep(.el-form-item:last-child .el-form-item__content) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.channel-record-pagination {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.channel-record-pagination :deep(.el-pagination) {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
row-gap: 6px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user