1.修改电话号码格式为60前缀,马来西亚格式

2.优化渠道可以查看分红方式,可以查看游玩详情
This commit is contained in:
2026-05-30 11:09:54 +08:00
parent 28d0100d5a
commit e65c3474bd
37 changed files with 1772 additions and 113 deletions

View File

@@ -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',

View File

@@ -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: '无分红余额',

View File

@@ -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',

View File

@@ -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': '请输入正确的名称',

View File

@@ -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()

View File

@@ -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>