完善接口和后台页面
This commit is contained in:
29
web/src/lang/backend/en/config/depositTier.ts
Normal file
29
web/src/lang/backend/en/config/depositTier.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export default {
|
||||
title: 'Deposit Tiers',
|
||||
desc: 'Configure the deposit tiers players can pick when creating a deposit order. In the third-party payment mode, only tier specs (name, amount, bonus, description) are maintained; receiving accounts are no longer stored here. Maintain both Chinese and English text for the title and description: the mobile API returns the language matching the request `lang` header, falling back to Chinese if English is blank. Changes take effect immediately.',
|
||||
btn_add: 'Add Tier',
|
||||
btn_save: 'Save',
|
||||
btn_remove: 'Delete',
|
||||
confirm_remove: 'Delete this deposit tier?',
|
||||
tier_id: 'Tier ID',
|
||||
auto_id: '(generated on save)',
|
||||
sort: 'Sort',
|
||||
status: 'Enabled',
|
||||
title_col: 'Title (ZH)',
|
||||
title_ph: 'e.g. 新手首充、VIP 高额充值',
|
||||
title_en_col: 'Title (EN)',
|
||||
title_en_ph: 'e.g. Starter Pack, VIP Recharge',
|
||||
amount: 'Amount',
|
||||
amount_ph: 'e.g. 100.00',
|
||||
bonus_amount: 'Bonus',
|
||||
bonus_ph: 'e.g. 20.00, use 0 if none',
|
||||
desc_col: 'Description (ZH)',
|
||||
desc_ph: 'Optional Chinese description, up to 255 chars',
|
||||
desc_en_col: 'Description (EN)',
|
||||
desc_en_ph: 'Optional English description, up to 255 chars',
|
||||
currency: '',
|
||||
operate: 'Action',
|
||||
err_title: 'Row {no}: Chinese title is required',
|
||||
err_amount: 'Row {no}: amount must be a number greater than 0',
|
||||
err_bonus: 'Row {no}: bonus must be a number no less than 0',
|
||||
}
|
||||
@@ -6,9 +6,7 @@ export default {
|
||||
user_id: 'User ID',
|
||||
channel_id: 'Channel ID',
|
||||
pick_numbers: 'Picks',
|
||||
unit_amount: 'Unit amount',
|
||||
pick_count: 'Pick count',
|
||||
total_amount: 'Total',
|
||||
total_amount: 'Total bet amount',
|
||||
streak_at_bet: 'Streak at bet',
|
||||
is_auto: 'Auto',
|
||||
'is_auto 0': 'Manual',
|
||||
|
||||
@@ -18,6 +18,6 @@ export default {
|
||||
bet_id: 'Bet ID',
|
||||
user_id: 'Player ID',
|
||||
pick_numbers: 'Pick numbers',
|
||||
unit_amount: 'Unit amount',
|
||||
total_amount: 'Total bet amount',
|
||||
streak_at_bet: 'Streak at bet',
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ export default {
|
||||
coin: 'Coin balance',
|
||||
coin_placeholder: 'decimal(18,4)',
|
||||
total_deposit_coin: 'Total deposit (coin)',
|
||||
total_valid_bet_coin: 'Total valid bet (coin)',
|
||||
total_withdraw_coin: 'Total withdraw (coin)',
|
||||
bet_flow_coin: 'Bet flow (coin)',
|
||||
risk_flags: 'Risk',
|
||||
risk_none: 'None',
|
||||
risk_no_login: 'No login',
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
user_id: 'User ID',
|
||||
channel_id: 'Channel ID',
|
||||
pick_numbers: 'Picks',
|
||||
unit_amount: 'Unit amount',
|
||||
pick_count: 'Pick count',
|
||||
total_amount: 'Total',
|
||||
total_amount: 'Total bet amount',
|
||||
streak_at_bet: 'Streak at bet',
|
||||
is_auto: 'Auto',
|
||||
'is_auto 0': 'Manual',
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
export default {
|
||||
'quick Search Fields': 'Order No./User ID/Pay channel',
|
||||
'quick Search Fields': 'Order No./User ID/Pay channel/Tier/Idempotency key',
|
||||
id: 'ID',
|
||||
order_no: 'Order No.',
|
||||
idempotency_key: 'Idempotency key',
|
||||
user_id: 'User ID',
|
||||
channel_id: 'Channel ID',
|
||||
amount: 'Amount',
|
||||
bonus_amount: 'Bonus',
|
||||
total_credit: 'Total credit',
|
||||
status: 'Status',
|
||||
'status 0': 'Pending',
|
||||
'status 1': 'Success',
|
||||
@@ -12,9 +15,12 @@ export default {
|
||||
'status 3': 'Canceled',
|
||||
pay_channel: 'Pay channel',
|
||||
pay_time: 'Pay time',
|
||||
deposit_tier_id: 'Deposit tier',
|
||||
remark: 'Remark',
|
||||
create_time: 'Created',
|
||||
update_time: 'Updated',
|
||||
user_username: 'Username',
|
||||
channel_name: 'Channel',
|
||||
detail_title: 'Deposit Order Detail',
|
||||
close_btn: 'Close',
|
||||
}
|
||||
|
||||
@@ -17,7 +17,20 @@ export default {
|
||||
remark: 'Remark',
|
||||
create_time: 'Created',
|
||||
update_time: 'Updated',
|
||||
user_username: 'Username',
|
||||
user_username: 'User',
|
||||
channel_name: 'Channel',
|
||||
review_admin_username: 'Reviewer',
|
||||
review_title: 'Withdraw review',
|
||||
review_reject_title: 'Reject withdraw',
|
||||
review_btn_approve: 'Approve',
|
||||
review_btn_reject: 'Reject',
|
||||
review_btn_back: 'Back',
|
||||
review_btn_confirm_reject: 'Confirm reject',
|
||||
review_reject_tip: 'Rejected withdrawals will refund the frozen amount back to the user wallet.',
|
||||
review_reject_placeholder: 'Enter reject reason (visible to the user on mobile history)',
|
||||
reject_reason_required: 'Please enter reject reason',
|
||||
already_reviewed: 'This order has already been reviewed',
|
||||
amount_invalid: 'Apply amount must be greater than 0',
|
||||
fee_invalid: 'Fee cannot be negative',
|
||||
fee_exceed_amount: 'Fee cannot exceed apply amount',
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ export default {
|
||||
coin: 'Coin balance',
|
||||
coin_placeholder: 'Amounts are displayed with 2 decimals',
|
||||
total_deposit_coin: 'Total deposit (coin)',
|
||||
total_valid_bet_coin: 'Total valid bet (coin)',
|
||||
total_withdraw_coin: 'Total withdraw (coin)',
|
||||
bet_flow_coin: 'Bet flow (coin)',
|
||||
risk_flags: 'Risk',
|
||||
risk_none: 'None',
|
||||
risk_no_login: 'No login',
|
||||
|
||||
29
web/src/lang/backend/zh-cn/config/depositTier.ts
Normal file
29
web/src/lang/backend/zh-cn/config/depositTier.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export default {
|
||||
title: '充值档位',
|
||||
desc: '配置玩家创建充值订单时可选的充值档位。第三方支付模式下仅需维护档位规格:名称、充值金额、赠送金额、描述等;不再保存收款账户信息。充值名称/描述需分别维护中英文两套:移动端接口会根据请求头 `lang` 返回对应语言,英文缺省时回退到中文。修改后立即生效。',
|
||||
btn_add: '新增档位',
|
||||
btn_save: '保存',
|
||||
btn_remove: '删除',
|
||||
confirm_remove: '确定删除该充值档位?',
|
||||
tier_id: '档位 ID',
|
||||
auto_id: '(保存时生成)',
|
||||
sort: '排序',
|
||||
status: '启用',
|
||||
title_col: '充值名称(中文)',
|
||||
title_ph: '例如:新手首充、VIP 高额充值',
|
||||
title_en_col: '充值名称(英文)',
|
||||
title_en_ph: 'e.g. Starter Pack, VIP Recharge',
|
||||
amount: '充值金额',
|
||||
amount_ph: '例如:100.00',
|
||||
bonus_amount: '赠送金额',
|
||||
bonus_ph: '例如:20.00,无赠送填 0',
|
||||
desc_col: '描述(中文)',
|
||||
desc_ph: '可选,展示给中文玩家的档位说明,最长 255 字',
|
||||
desc_en_col: '描述(英文)',
|
||||
desc_en_ph: 'Optional English description for EN players, up to 255 chars',
|
||||
currency: '币',
|
||||
operate: '操作',
|
||||
err_title: '第 {no} 行:中文充值名称不能为空',
|
||||
err_amount: '第 {no} 行:充值金额必须为大于 0 的数字',
|
||||
err_bonus: '第 {no} 行:赠送金额必须为不小于 0 的数字',
|
||||
}
|
||||
@@ -6,9 +6,7 @@ export default {
|
||||
user_id: '用户ID',
|
||||
channel_id: '渠道ID',
|
||||
pick_numbers: '选号',
|
||||
unit_amount: '单号金额',
|
||||
pick_count: '选号个数',
|
||||
total_amount: '总金额',
|
||||
total_amount: '压注总额',
|
||||
streak_at_bet: '下注时连胜',
|
||||
is_auto: '托管',
|
||||
'is_auto 0': '手动',
|
||||
|
||||
@@ -18,6 +18,6 @@ export default {
|
||||
bet_id: '注单ID',
|
||||
user_id: '玩家ID',
|
||||
pick_numbers: '压注号码',
|
||||
unit_amount: '单号金额',
|
||||
total_amount: '压注总额',
|
||||
streak_at_bet: '下注时连胜',
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ export default {
|
||||
coin: '游戏币余额',
|
||||
coin_placeholder: 'decimal(18,4),禁止业务用浮点存库',
|
||||
total_deposit_coin: '累计充值(币)',
|
||||
total_valid_bet_coin: '累计有效投注(币)',
|
||||
total_withdraw_coin: '累计提现(币)',
|
||||
bet_flow_coin: '打码量/流水(币)',
|
||||
risk_flags: '风控',
|
||||
risk_none: '无限制',
|
||||
risk_no_login: '禁止登录',
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
user_id: '用户ID',
|
||||
channel_id: '渠道ID',
|
||||
pick_numbers: '选号',
|
||||
unit_amount: '单号金额',
|
||||
pick_count: '选号个数',
|
||||
total_amount: '总金额',
|
||||
total_amount: '压注总额',
|
||||
streak_at_bet: '下注时连胜',
|
||||
is_auto: '托管',
|
||||
'is_auto 0': '手动',
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
export default {
|
||||
'quick Search Fields': '订单号/用户ID/支付通道',
|
||||
'quick Search Fields': '订单号/用户ID/支付通道/档位ID/幂等键',
|
||||
id: 'ID',
|
||||
order_no: '订单号',
|
||||
idempotency_key: '幂等键',
|
||||
user_id: '用户ID',
|
||||
user_username: '用户名',
|
||||
channel_id: '渠道ID',
|
||||
channel_name: '渠道',
|
||||
amount: '金额',
|
||||
bonus_amount: '赠送金额',
|
||||
total_credit: '实际到账',
|
||||
status: '状态',
|
||||
'status 0': '待处理',
|
||||
'status 0': '待支付',
|
||||
'status 1': '成功',
|
||||
'status 2': '失败',
|
||||
'status 3': '已取消',
|
||||
pay_channel: '支付通道',
|
||||
pay_time: '支付时间',
|
||||
deposit_tier_id: '充值档位',
|
||||
remark: '备注',
|
||||
create_time: '创建时间',
|
||||
update_time: '更新时间',
|
||||
detail_title: '充值订单详情',
|
||||
close_btn: '关闭',
|
||||
}
|
||||
|
||||
@@ -17,7 +17,20 @@ export default {
|
||||
remark: '备注',
|
||||
create_time: '创建时间',
|
||||
update_time: '更新时间',
|
||||
user_username: '用户名',
|
||||
user_username: '用户',
|
||||
channel_name: '渠道',
|
||||
review_admin_username: '审核人',
|
||||
review_title: '提现审核',
|
||||
review_reject_title: '提现拒绝',
|
||||
review_btn_approve: '通过',
|
||||
review_btn_reject: '拒绝',
|
||||
review_btn_back: '返回',
|
||||
review_btn_confirm_reject: '确认拒绝',
|
||||
review_reject_tip: '拒绝审核后,冻结的提现金额将原路退回用户钱包余额。',
|
||||
review_reject_placeholder: '请输入拒绝原因,玩家可在提现记录中看到该说明',
|
||||
reject_reason_required: '请输入拒绝原因',
|
||||
already_reviewed: '该订单已审核,无需重复操作',
|
||||
amount_invalid: '申请金额必须大于 0',
|
||||
fee_invalid: '手续费不能为负',
|
||||
fee_exceed_amount: '手续费不能大于申请金额',
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export default {
|
||||
export default {
|
||||
id: 'ID',
|
||||
username: '用户名',
|
||||
password: '密码',
|
||||
@@ -11,7 +11,8 @@
|
||||
coin: '余额',
|
||||
coin_placeholder: '金额展示统一两位小数',
|
||||
total_deposit_coin: '累计充值(币)',
|
||||
total_valid_bet_coin: '累计有效投注(币)',
|
||||
total_withdraw_coin: '累计提现(币)',
|
||||
bet_flow_coin: '打码量/流水(币)',
|
||||
risk_flags: '风控',
|
||||
risk_none: '无限制',
|
||||
risk_no_login: '禁止登录',
|
||||
|
||||
251
web/src/views/backend/config/depositTier/index.vue
Normal file
251
web/src/views/backend/config/depositTier/index.vue
Normal file
@@ -0,0 +1,251 @@
|
||||
<template>
|
||||
<div class="default-main ba-table-box deposit-tier-page">
|
||||
<el-alert type="info" :closable="false" show-icon>
|
||||
{{ t('config.depositTier.desc') }}
|
||||
</el-alert>
|
||||
|
||||
<div class="toolbar">
|
||||
<el-button type="primary" :disabled="loading" @click="onAdd">
|
||||
<Icon name="el-icon-Plus" />
|
||||
<span class="ml-6">{{ t('config.depositTier.btn_add') }}</span>
|
||||
</el-button>
|
||||
<el-button type="success" :loading="saving" :disabled="loading" @click="onSave">
|
||||
{{ t('config.depositTier.btn_save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" border stripe :data="items" row-key="_rowKey" max-height="720">
|
||||
<el-table-column prop="sort" :label="t('config.depositTier.sort')" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-input-number v-model="row.sort" :min="0" :max="9999" :controls="false" style="width: 100%" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('config.depositTier.status')" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-switch v-model="row.status" :active-value="1" :inactive-value="0" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('config.depositTier.title_col')" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.title" maxlength="64" :placeholder="t('config.depositTier.title_ph')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('config.depositTier.title_en_col')" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.title_en" maxlength="64" :placeholder="t('config.depositTier.title_en_ph')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('config.depositTier.amount')" min-width="140">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.amount" :placeholder="t('config.depositTier.amount_ph')">
|
||||
<template #suffix>
|
||||
<span class="currency">{{ t('config.depositTier.currency') }}</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('config.depositTier.bonus_amount')" min-width="140">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.bonus_amount" :placeholder="t('config.depositTier.bonus_ph')">
|
||||
<template #suffix>
|
||||
<span class="currency">{{ t('config.depositTier.currency') }}</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('config.depositTier.desc_col')" min-width="220">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.desc" maxlength="255" :autosize="{ minRows: 1, maxRows: 3 }" type="textarea" :placeholder="t('config.depositTier.desc_ph')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('config.depositTier.desc_en_col')" min-width="220">
|
||||
<template #default="{ row }">
|
||||
<el-input v-model="row.desc_en" maxlength="255" :autosize="{ minRows: 1, maxRows: 3 }" type="textarea" :placeholder="t('config.depositTier.desc_en_ph')" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('config.depositTier.tier_id')" width="140">
|
||||
<template #default="{ row }">
|
||||
<el-text class="tier-id" truncated>{{ row.id || t('config.depositTier.auto_id') }}</el-text>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('config.depositTier.operate')" width="90" align="center" fixed="right">
|
||||
<template #default="{ $index }">
|
||||
<el-button type="danger" link @click="onRemove($index)">
|
||||
{{ t('config.depositTier.btn_remove') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import createAxios from '/@/utils/axios'
|
||||
import { auth } from '/@/utils/common'
|
||||
|
||||
defineOptions({
|
||||
name: 'config/depositTier',
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
type Tier = {
|
||||
id: string
|
||||
title: string
|
||||
title_en: string
|
||||
amount: string
|
||||
bonus_amount: string
|
||||
desc: string
|
||||
desc_en: string
|
||||
sort: number
|
||||
status: number
|
||||
_rowKey?: string
|
||||
}
|
||||
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const items = ref<Tier[]>([])
|
||||
|
||||
function genRowKey(): string {
|
||||
return 'r_' + Math.random().toString(36).slice(2, 10)
|
||||
}
|
||||
|
||||
function emptyTier(): Tier {
|
||||
return {
|
||||
id: '',
|
||||
title: '',
|
||||
title_en: '',
|
||||
amount: '',
|
||||
bonus_amount: '0',
|
||||
desc: '',
|
||||
desc_en: '',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
_rowKey: genRowKey(),
|
||||
}
|
||||
}
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await createAxios({
|
||||
url: '/admin/config.DepositTier/index',
|
||||
method: 'get',
|
||||
})
|
||||
if (res.code === 1 && res.data) {
|
||||
const list = (res.data.items || []) as Tier[]
|
||||
items.value = (Array.isArray(list) ? list : []).map((it) => ({
|
||||
...emptyTier(),
|
||||
...it,
|
||||
_rowKey: genRowKey(),
|
||||
}))
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onAdd() {
|
||||
items.value.push(emptyTier())
|
||||
}
|
||||
|
||||
async function onRemove(idx: number) {
|
||||
try {
|
||||
await ElMessageBox.confirm(t('config.depositTier.confirm_remove'), t('Warning'), {
|
||||
type: 'warning',
|
||||
confirmButtonText: t('Delete'),
|
||||
cancelButtonText: t('Cancel'),
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
items.value.splice(idx, 1)
|
||||
}
|
||||
|
||||
async function onSave() {
|
||||
if (!auth('save')) {
|
||||
return
|
||||
}
|
||||
for (let i = 0; i < items.value.length; i++) {
|
||||
const row = items.value[i]
|
||||
if (!row.title || !row.title.trim()) {
|
||||
ElMessage.warning(t('config.depositTier.err_title', { no: i + 1 }))
|
||||
return
|
||||
}
|
||||
const amount = Number(row.amount)
|
||||
if (!row.amount || Number.isNaN(amount) || amount <= 0) {
|
||||
ElMessage.warning(t('config.depositTier.err_amount', { no: i + 1 }))
|
||||
return
|
||||
}
|
||||
const bonusRaw = row.bonus_amount === '' || row.bonus_amount === null || row.bonus_amount === undefined ? '0' : row.bonus_amount
|
||||
const bonus = Number(bonusRaw)
|
||||
if (Number.isNaN(bonus) || bonus < 0) {
|
||||
ElMessage.warning(t('config.depositTier.err_bonus', { no: i + 1 }))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
saving.value = true
|
||||
try {
|
||||
await createAxios({
|
||||
url: '/admin/config.DepositTier/save',
|
||||
method: 'post',
|
||||
data: {
|
||||
items: items.value.map((r) => ({
|
||||
id: r.id,
|
||||
title: r.title,
|
||||
title_en: r.title_en || '',
|
||||
amount: r.amount,
|
||||
bonus_amount: r.bonus_amount === '' || r.bonus_amount === null || r.bonus_amount === undefined ? '0' : r.bonus_amount,
|
||||
desc: r.desc || '',
|
||||
desc_en: r.desc_en || '',
|
||||
sort: r.sort,
|
||||
status: r.status,
|
||||
})),
|
||||
},
|
||||
showSuccessMessage: true,
|
||||
})
|
||||
await load()
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void load()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.deposit-tier-page {
|
||||
.toolbar {
|
||||
margin: 12px 0;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.currency {
|
||||
color: var(--el-text-color-placeholder);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tier-id {
|
||||
display: inline-block;
|
||||
max-width: 120px;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -48,7 +48,7 @@
|
||||
{{ formatPicks(scope.row.pick_numbers) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="unit_amount" :label="t('game.live.unit_amount')" width="120" />
|
||||
<el-table-column prop="total_amount" :label="t('game.live.total_amount')" width="120" />
|
||||
<el-table-column prop="streak_at_bet" :label="t('game.live.streak_at_bet')" width="90" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
@@ -142,15 +142,6 @@ const baTable = new baTableClass(
|
||||
operator: false,
|
||||
formatter: formatPickNumbers,
|
||||
},
|
||||
{
|
||||
label: t('order.betOrder.unit_amount'),
|
||||
prop: 'unit_amount',
|
||||
align: 'center',
|
||||
minWidth: 110,
|
||||
operator: 'RANGE',
|
||||
formatter: formatAmount,
|
||||
},
|
||||
{ label: t('order.betOrder.pick_count'), prop: 'pick_count', align: 'center', width: 90, operator: 'RANGE' },
|
||||
{
|
||||
label: t('order.betOrder.total_amount'),
|
||||
prop: 'total_amount',
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="default-main ba-table-box">
|
||||
<el-alert class="ba-table-alert" v-if="baTable.table.remark" :title="baTable.table.remark" type="info" show-icon />
|
||||
|
||||
<TableHeader
|
||||
:buttons="['refresh', 'add', 'edit', 'delete', 'comSearch', 'quickSearch', 'columnDisplay']"
|
||||
:buttons="['refresh', 'comSearch', 'quickSearch', 'columnDisplay']"
|
||||
:quick-search-placeholder="t('Quick search placeholder', { fields: t('order.depositOrder.quick Search Fields') })"
|
||||
></TableHeader>
|
||||
|
||||
@@ -29,7 +29,19 @@ defineOptions({
|
||||
|
||||
const { t } = useI18n()
|
||||
const tableRef = useTemplateRef('tableRef')
|
||||
const optButtons: OptButton[] = defaultOptButtons(['edit', 'delete'])
|
||||
const optButtons: OptButton[] = defaultOptButtons(['edit'])
|
||||
|
||||
function formatAmount(_row: anyObj, _column: any, cellValue: unknown) {
|
||||
if (cellValue === null || cellValue === undefined || cellValue === '') {
|
||||
return '-'
|
||||
}
|
||||
const s = String(cellValue).trim().replace(',', '.')
|
||||
const n = parseFloat(s)
|
||||
if (!Number.isFinite(n)) {
|
||||
return String(cellValue)
|
||||
}
|
||||
return n.toFixed(2)
|
||||
}
|
||||
|
||||
const baTable = new baTableClass(
|
||||
new baTableApi('/admin/order.DepositOrder/'),
|
||||
@@ -46,12 +58,11 @@ const baTable = new baTableClass(
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
},
|
||||
{ label: t('order.depositOrder.user_id'), prop: 'user_id', align: 'center', width: 90, operator: 'RANGE' },
|
||||
{
|
||||
label: t('order.depositOrder.user_username'),
|
||||
prop: 'user.username',
|
||||
align: 'center',
|
||||
minWidth: 110,
|
||||
minWidth: 120,
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
render: 'tags',
|
||||
@@ -65,7 +76,22 @@ const baTable = new baTableClass(
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
render: 'tags',
|
||||
},
|
||||
{ label: t('order.depositOrder.amount'), prop: 'amount', align: 'center', minWidth: 110, operator: 'RANGE' },
|
||||
{
|
||||
label: t('order.depositOrder.amount'),
|
||||
prop: 'amount',
|
||||
align: 'center',
|
||||
minWidth: 110,
|
||||
operator: 'RANGE',
|
||||
formatter: formatAmount,
|
||||
},
|
||||
{
|
||||
label: t('order.depositOrder.bonus_amount'),
|
||||
prop: 'bonus_amount',
|
||||
align: 'center',
|
||||
minWidth: 110,
|
||||
operator: 'RANGE',
|
||||
formatter: formatAmount,
|
||||
},
|
||||
{
|
||||
label: t('order.depositOrder.status'),
|
||||
prop: 'status',
|
||||
@@ -76,9 +102,9 @@ const baTable = new baTableClass(
|
||||
effect: 'dark',
|
||||
custom: {
|
||||
'0': 'info',
|
||||
'1': 'warning',
|
||||
'2': 'success',
|
||||
'3': 'danger',
|
||||
'1': 'success',
|
||||
'2': 'danger',
|
||||
'3': 'warning',
|
||||
},
|
||||
replaceValue: {
|
||||
'0': t('order.depositOrder.status 0'),
|
||||
@@ -91,10 +117,19 @@ const baTable = new baTableClass(
|
||||
label: t('order.depositOrder.pay_channel'),
|
||||
prop: 'pay_channel',
|
||||
align: 'center',
|
||||
minWidth: 110,
|
||||
minWidth: 130,
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
},
|
||||
{
|
||||
label: t('order.depositOrder.deposit_tier_id'),
|
||||
prop: 'deposit_tier_id',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: t('order.depositOrder.pay_time'),
|
||||
prop: 'pay_time',
|
||||
@@ -106,6 +141,16 @@ const baTable = new baTableClass(
|
||||
width: 170,
|
||||
timeFormat: 'yyyy-mm-dd hh:MM:ss',
|
||||
},
|
||||
{
|
||||
label: t('order.depositOrder.idempotency_key'),
|
||||
prop: 'idempotency_key',
|
||||
align: 'center',
|
||||
minWidth: 170,
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
showOverflowTooltip: true,
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: t('order.depositOrder.remark'),
|
||||
prop: 'remark',
|
||||
@@ -136,6 +181,7 @@ const baTable = new baTableClass(
|
||||
sortable: 'custom',
|
||||
width: 170,
|
||||
timeFormat: 'yyyy-mm-dd hh:MM:ss',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: t('Operate'),
|
||||
@@ -149,7 +195,7 @@ const baTable = new baTableClass(
|
||||
],
|
||||
},
|
||||
{
|
||||
defaultItems: { status: 0, amount: '0.0000' },
|
||||
defaultItems: { status: 0, amount: '0.0000', bonus_amount: '0.0000' },
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,48 +1,231 @@
|
||||
<template>
|
||||
<el-dialog class="ba-operate-dialog" :close-on-click-modal="false" :model-value="['Add', 'Edit'].includes(baTable.form.operate!)" @close="baTable.toggleForm">
|
||||
<template>
|
||||
<el-dialog
|
||||
class="ba-operate-dialog deposit-detail-dialog"
|
||||
:close-on-click-modal="false"
|
||||
:model-value="isOpen"
|
||||
width="640px"
|
||||
@close="onDialogClose"
|
||||
>
|
||||
<template #header>
|
||||
<div class="title" v-drag="['.ba-operate-dialog', '.el-dialog__header']" v-zoom="'.ba-operate-dialog'">{{ baTable.form.operate ? t(baTable.form.operate) : '' }}</div>
|
||||
<div class="title" v-drag="['.ba-operate-dialog', '.el-dialog__header']" v-zoom="'.ba-operate-dialog'">
|
||||
{{ t('order.depositOrder.detail_title') }}
|
||||
</div>
|
||||
</template>
|
||||
<el-scrollbar v-loading="baTable.form.loading" class="ba-table-form-scrollbar">
|
||||
<div class="ba-operate-form" :class="'ba-' + baTable.form.operate + '-form'" :style="config.layout.shrink ? '' : 'width: calc(100% - ' + baTable.form.labelWidth! / 2 + 'px)'">
|
||||
<el-form v-if="!baTable.form.loading" ref="formRef" @submit.prevent="" @keyup.enter="baTable.onSubmit(formRef)" :model="baTable.form.items" :label-position="config.layout.shrink ? 'top' : 'right'" :label-width="baTable.form.labelWidth + 'px'" :rules="rules">
|
||||
<FormItem :label="t('order.depositOrder.order_no')" type="string" v-model="baTable.form.items!.order_no" prop="order_no" />
|
||||
<FormItem :label="t('order.depositOrder.user_id')" type="number" v-model="baTable.form.items!.user_id" prop="user_id" :input-attr="{ min: 1, step: 1 }" />
|
||||
<FormItem :label="t('order.depositOrder.channel_id')" type="number" v-model="baTable.form.items!.channel_id" prop="channel_id" :input-attr="{ min: 1, step: 1 }" />
|
||||
<FormItem :label="t('order.depositOrder.amount')" type="number" v-model="baTable.form.items!.amount" prop="amount" :input-attr="{ step: 0.0001, precision: 4, min: 0 }" />
|
||||
<FormItem :label="t('order.depositOrder.status')" type="radio" v-model="baTable.form.items!.status" prop="status" :input-attr="{ content: { '0': t('order.depositOrder.status 0'), '1': t('order.depositOrder.status 1'), '2': t('order.depositOrder.status 2'), '3': t('order.depositOrder.status 3') } }" />
|
||||
<FormItem :label="t('order.depositOrder.pay_channel')" type="string" v-model="baTable.form.items!.pay_channel" prop="pay_channel" />
|
||||
<FormItem :label="t('order.depositOrder.pay_time')" type="datetime" v-model="baTable.form.items!.pay_time" prop="pay_time" />
|
||||
<FormItem :label="t('order.depositOrder.remark')" type="textarea" v-model="baTable.form.items!.remark" prop="remark" :input-attr="{ rows: 2 }" />
|
||||
|
||||
<el-scrollbar v-loading="loading" class="ba-table-form-scrollbar">
|
||||
<div
|
||||
class="ba-operate-form ba-edit-form"
|
||||
:style="config.layout.shrink ? '' : 'width: calc(100% - ' + (baTable.form.labelWidth ?? 120) / 2 + 'px)'"
|
||||
>
|
||||
<el-form
|
||||
v-if="!loading"
|
||||
:label-position="config.layout.shrink ? 'top' : 'right'"
|
||||
:label-width="(baTable.form.labelWidth ?? 120) + 'px'"
|
||||
@submit.prevent=""
|
||||
>
|
||||
<el-form-item :label="t('order.depositOrder.order_no')">
|
||||
<el-input :model-value="form.order_no" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.idempotency_key')">
|
||||
<el-input :model-value="form.idempotency_key || '-'" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.user_username')">
|
||||
<el-input :model-value="form.user_text" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.channel_name')">
|
||||
<el-input :model-value="form.channel_text" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.status')">
|
||||
<el-tag :type="statusTagType" effect="dark" size="small">{{ statusLabel }}</el-tag>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('order.depositOrder.amount')">
|
||||
<el-input :model-value="amountText" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.bonus_amount')">
|
||||
<el-input :model-value="bonusText" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.total_credit')">
|
||||
<el-input :model-value="totalCreditText" readonly />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('order.depositOrder.pay_channel')">
|
||||
<el-input :model-value="form.pay_channel || '-'" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.pay_time')">
|
||||
<el-input :model-value="form.pay_time_text" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.deposit_tier_id')">
|
||||
<el-input :model-value="form.deposit_tier_id || '-'" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.remark')">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="2" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.depositOrder.create_time')">
|
||||
<el-input :model-value="form.create_time_text" readonly />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<div :style="'width: calc(100% - ' + baTable.form.labelWidth! / 1.8 + 'px)'">
|
||||
<el-button @click="baTable.toggleForm()">{{ t('Cancel') }}</el-button>
|
||||
<el-button v-blur :loading="baTable.form.submitLoading" @click="baTable.onSubmit(formRef)" type="primary">{{ baTable.form.operateIds && baTable.form.operateIds.length > 1 ? t('Save and edit next item') : t('Save') }}</el-button>
|
||||
<div class="detail-footer">
|
||||
<el-button type="primary" v-blur @click="onDialogClose">{{ t('order.depositOrder.close_btn') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { FormItemRule } from 'element-plus'
|
||||
import { inject, reactive, useTemplateRef } from 'vue'
|
||||
import { computed, inject, reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import FormItem from '/@/components/formItem/index.vue'
|
||||
import { useConfig } from '/@/stores/config'
|
||||
import type baTableClass from '/@/utils/baTable'
|
||||
|
||||
const config = useConfig()
|
||||
const formRef = useTemplateRef('formRef')
|
||||
const baTable = inject('baTable') as baTableClass
|
||||
const { t } = useI18n()
|
||||
|
||||
const rules: Partial<Record<string, FormItemRule[]>> = reactive({
|
||||
order_no: [{ required: true, message: t('Please input field', { field: t('order.depositOrder.order_no') }) }],
|
||||
user_id: [{ required: true, message: t('Please input field', { field: t('order.depositOrder.user_id') }) }],
|
||||
const loading = ref(false)
|
||||
|
||||
const form = reactive({
|
||||
id: 0,
|
||||
order_no: '',
|
||||
idempotency_key: '',
|
||||
user_text: '-',
|
||||
channel_text: '-',
|
||||
pay_channel: '',
|
||||
pay_time_text: '-',
|
||||
deposit_tier_id: '',
|
||||
remark: '',
|
||||
create_time_text: '-',
|
||||
amount: 0,
|
||||
bonus_amount: 0,
|
||||
status: 0,
|
||||
})
|
||||
|
||||
const isOpen = computed(() => ['Edit'].includes(baTable.form.operate ?? ''))
|
||||
|
||||
watch(
|
||||
() => ({ visible: isOpen.value, loadingState: baTable.form.loading, items: baTable.form.items }),
|
||||
({ visible, loadingState }) => {
|
||||
if (!visible) return
|
||||
loading.value = loadingState === true
|
||||
if (loadingState) return
|
||||
hydrate()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
const hydrate = () => {
|
||||
const row = baTable.form.items as Record<string, unknown> | undefined
|
||||
if (!row || !row['id']) {
|
||||
return
|
||||
}
|
||||
form.id = Number(row['id'] ?? 0)
|
||||
form.order_no = String(row['order_no'] ?? '')
|
||||
form.idempotency_key = String(row['idempotency_key'] ?? '')
|
||||
form.pay_channel = String(row['pay_channel'] ?? '')
|
||||
form.deposit_tier_id = String(row['deposit_tier_id'] ?? '')
|
||||
form.remark = String(row['remark'] ?? '')
|
||||
form.amount = parseNumber(row['amount'])
|
||||
form.bonus_amount = parseNumber(row['bonus_amount'])
|
||||
form.status = Number(row['status'] ?? 0)
|
||||
form.create_time_text = formatTime(row['create_time'])
|
||||
form.pay_time_text = formatTime(row['pay_time'])
|
||||
form.user_text = resolveRelationText(row, 'user', row['user_id'])
|
||||
form.channel_text = resolveRelationText(row, 'channel', row['channel_id'])
|
||||
}
|
||||
|
||||
const statusLabel = computed(() => t('order.depositOrder.status ' + form.status))
|
||||
const statusTagType = computed(() => {
|
||||
switch (form.status) {
|
||||
case 1:
|
||||
return 'success'
|
||||
case 2:
|
||||
return 'danger'
|
||||
case 3:
|
||||
return 'warning'
|
||||
default:
|
||||
return 'info'
|
||||
}
|
||||
})
|
||||
|
||||
const amountText = computed(() => formatAmount(form.amount))
|
||||
const bonusText = computed(() => formatAmount(form.bonus_amount))
|
||||
const totalCreditText = computed(() => formatAmount(Number((form.amount + form.bonus_amount).toFixed(2))))
|
||||
|
||||
const onDialogClose = () => {
|
||||
baTable.toggleForm()
|
||||
}
|
||||
|
||||
function parseNumber(raw: unknown): number {
|
||||
if (raw === null || raw === undefined || raw === '') return 0
|
||||
const n = Number(raw)
|
||||
if (!Number.isFinite(n)) return 0
|
||||
return Number(n.toFixed(2))
|
||||
}
|
||||
|
||||
function formatAmount(value: number): string {
|
||||
if (!Number.isFinite(value)) return '0.00'
|
||||
return value.toFixed(2)
|
||||
}
|
||||
|
||||
function formatTime(raw: unknown): string {
|
||||
if (raw === null || raw === undefined || raw === '' || raw === 0) return '-'
|
||||
const sec = Number(raw)
|
||||
if (!Number.isFinite(sec) || sec <= 0) return '-'
|
||||
const d = new Date(sec * 1000)
|
||||
const pad = (n: number) => (n < 10 ? '0' + n : String(n))
|
||||
return (
|
||||
d.getFullYear() +
|
||||
'-' +
|
||||
pad(d.getMonth() + 1) +
|
||||
'-' +
|
||||
pad(d.getDate()) +
|
||||
' ' +
|
||||
pad(d.getHours()) +
|
||||
':' +
|
||||
pad(d.getMinutes()) +
|
||||
':' +
|
||||
pad(d.getSeconds())
|
||||
)
|
||||
}
|
||||
|
||||
function resolveRelationText(row: Record<string, unknown>, relationKey: string, fallbackId: unknown): string {
|
||||
const rel = row[relationKey]
|
||||
if (rel && typeof rel === 'object') {
|
||||
const r = rel as Record<string, unknown>
|
||||
const name = r['username'] ?? r['name']
|
||||
if (typeof name === 'string' && name !== '') {
|
||||
const id = fallbackId === null || fallbackId === undefined || fallbackId === '' ? '' : ' (ID: ' + String(fallbackId) + ')'
|
||||
return name + id
|
||||
}
|
||||
}
|
||||
if (fallbackId === null || fallbackId === undefined || fallbackId === '') {
|
||||
return '-'
|
||||
}
|
||||
return 'ID: ' + String(fallbackId)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
.deposit-detail-dialog {
|
||||
:deep(.el-dialog__body) {
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
:deep(.deposit-detail-dialog) {
|
||||
width: calc(100vw - 24px) !important;
|
||||
max-width: 100vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<el-alert class="ba-table-alert" v-if="baTable.table.remark" :title="baTable.table.remark" type="info" show-icon />
|
||||
|
||||
<TableHeader
|
||||
:buttons="['refresh', 'add', 'edit', 'delete', 'comSearch', 'quickSearch', 'columnDisplay']"
|
||||
:buttons="['refresh', 'comSearch', 'quickSearch', 'columnDisplay']"
|
||||
:quick-search-placeholder="t('Quick search placeholder', { fields: t('order.withdrawOrder.quick Search Fields') })"
|
||||
></TableHeader>
|
||||
|
||||
@@ -29,7 +29,7 @@ defineOptions({
|
||||
|
||||
const { t } = useI18n()
|
||||
const tableRef = useTemplateRef('tableRef')
|
||||
const optButtons: OptButton[] = defaultOptButtons(['edit', 'delete'])
|
||||
const optButtons: OptButton[] = defaultOptButtons(['edit'])
|
||||
|
||||
const baTable = new baTableClass(
|
||||
new baTableApi('/admin/order.WithdrawOrder/'),
|
||||
@@ -38,10 +38,33 @@ const baTable = new baTableClass(
|
||||
column: [
|
||||
{ type: 'selection', align: 'center', operator: false },
|
||||
{ label: t('order.withdrawOrder.id'), prop: 'id', align: 'center', width: 80, operator: 'RANGE', sortable: 'custom' },
|
||||
{ label: t('order.withdrawOrder.order_no'), prop: 'order_no', align: 'center', minWidth: 170, operator: 'LIKE', operatorPlaceholder: t('Fuzzy query') },
|
||||
{ label: t('order.withdrawOrder.user_id'), prop: 'user_id', align: 'center', width: 90, operator: 'RANGE' },
|
||||
{ label: t('order.withdrawOrder.user_username'), prop: 'user.username', align: 'center', minWidth: 110, operator: 'LIKE', operatorPlaceholder: t('Fuzzy query'), render: 'tags' },
|
||||
{ label: t('order.withdrawOrder.channel_name'), prop: 'channel.name', align: 'center', minWidth: 110, operator: 'LIKE', operatorPlaceholder: t('Fuzzy query'), render: 'tags' },
|
||||
{
|
||||
label: t('order.withdrawOrder.order_no'),
|
||||
prop: 'order_no',
|
||||
align: 'center',
|
||||
minWidth: 170,
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
},
|
||||
// { label: t('order.withdrawOrder.user_id'), prop: 'user_id', align: 'center', width: 90, operator: 'RANGE' },
|
||||
{
|
||||
label: t('order.withdrawOrder.user_username'),
|
||||
prop: 'user.username',
|
||||
align: 'center',
|
||||
minWidth: 120,
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
render: 'tags',
|
||||
},
|
||||
{
|
||||
label: t('order.withdrawOrder.channel_name'),
|
||||
prop: 'channel.name',
|
||||
align: 'center',
|
||||
minWidth: 110,
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
render: 'tags',
|
||||
},
|
||||
{ label: t('order.withdrawOrder.amount'), prop: 'amount', align: 'center', minWidth: 110, operator: 'RANGE' },
|
||||
{ label: t('order.withdrawOrder.fee'), prop: 'fee', align: 'center', minWidth: 110, operator: 'RANGE' },
|
||||
{ label: t('order.withdrawOrder.actual_amount'), prop: 'actual_amount', align: 'center', minWidth: 110, operator: 'RANGE' },
|
||||
@@ -59,13 +82,64 @@ const baTable = new baTableClass(
|
||||
'2': 'success',
|
||||
'3': 'danger',
|
||||
},
|
||||
replaceValue: { '0': t('order.withdrawOrder.status 0'), '1': t('order.withdrawOrder.status 1'), '2': t('order.withdrawOrder.status 2'), '3': t('order.withdrawOrder.status 3') },
|
||||
replaceValue: {
|
||||
'0': t('order.withdrawOrder.status 0'),
|
||||
'1': t('order.withdrawOrder.status 1'),
|
||||
'2': t('order.withdrawOrder.status 2'),
|
||||
'3': t('order.withdrawOrder.status 3'),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('order.withdrawOrder.review_admin_username'),
|
||||
prop: 'reviewAdmin.username',
|
||||
align: 'center',
|
||||
minWidth: 100,
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
render: 'tags',
|
||||
},
|
||||
{
|
||||
label: t('order.withdrawOrder.review_time'),
|
||||
prop: 'review_time',
|
||||
align: 'center',
|
||||
render: 'datetime',
|
||||
operator: 'RANGE',
|
||||
comSearchRender: 'datetime',
|
||||
sortable: 'custom',
|
||||
width: 170,
|
||||
timeFormat: 'yyyy-mm-dd hh:MM:ss',
|
||||
},
|
||||
{
|
||||
label: t('order.withdrawOrder.remark'),
|
||||
prop: 'remark',
|
||||
align: 'center',
|
||||
minWidth: 150,
|
||||
operator: 'LIKE',
|
||||
operatorPlaceholder: t('Fuzzy query'),
|
||||
showOverflowTooltip: true,
|
||||
},
|
||||
{
|
||||
label: t('order.withdrawOrder.create_time'),
|
||||
prop: 'create_time',
|
||||
align: 'center',
|
||||
render: 'datetime',
|
||||
operator: 'RANGE',
|
||||
comSearchRender: 'datetime',
|
||||
sortable: 'custom',
|
||||
width: 170,
|
||||
timeFormat: 'yyyy-mm-dd hh:MM:ss',
|
||||
},
|
||||
{
|
||||
label: t('order.withdrawOrder.update_time'),
|
||||
prop: 'update_time',
|
||||
align: 'center',
|
||||
render: 'datetime',
|
||||
operator: 'RANGE',
|
||||
comSearchRender: 'datetime',
|
||||
sortable: 'custom',
|
||||
width: 170,
|
||||
timeFormat: 'yyyy-mm-dd hh:MM:ss',
|
||||
},
|
||||
{ label: t('order.withdrawOrder.review_admin_username'), prop: 'reviewAdmin.username', align: 'center', minWidth: 100, operator: 'LIKE', operatorPlaceholder: t('Fuzzy query'), render: 'tags' },
|
||||
{ label: t('order.withdrawOrder.review_time'), prop: 'review_time', align: 'center', render: 'datetime', operator: 'RANGE', comSearchRender: 'datetime', sortable: 'custom', width: 170, timeFormat: 'yyyy-mm-dd hh:MM:ss' },
|
||||
{ label: t('order.withdrawOrder.remark'), prop: 'remark', align: 'center', minWidth: 150, operator: 'LIKE', operatorPlaceholder: t('Fuzzy query'), showOverflowTooltip: true },
|
||||
{ label: t('order.withdrawOrder.create_time'), prop: 'create_time', align: 'center', render: 'datetime', operator: 'RANGE', comSearchRender: 'datetime', sortable: 'custom', width: 170, timeFormat: 'yyyy-mm-dd hh:MM:ss' },
|
||||
{ label: t('order.withdrawOrder.update_time'), prop: 'update_time', align: 'center', render: 'datetime', operator: 'RANGE', comSearchRender: 'datetime', sortable: 'custom', width: 170, timeFormat: 'yyyy-mm-dd hh:MM:ss' },
|
||||
{ label: t('Operate'), align: 'center', width: 90, render: 'buttons', buttons: optButtons, operator: false, fixed: 'right' },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,50 +1,434 @@
|
||||
<template>
|
||||
<el-dialog class="ba-operate-dialog" :close-on-click-modal="false" :model-value="['Add', 'Edit'].includes(baTable.form.operate!)" @close="baTable.toggleForm">
|
||||
<el-dialog
|
||||
class="ba-operate-dialog withdraw-review-dialog"
|
||||
:close-on-click-modal="false"
|
||||
:model-value="isOpen"
|
||||
width="640px"
|
||||
@close="onDialogClose"
|
||||
>
|
||||
<template #header>
|
||||
<div class="title" v-drag="['.ba-operate-dialog', '.el-dialog__header']" v-zoom="'.ba-operate-dialog'">{{ baTable.form.operate ? t(baTable.form.operate) : '' }}</div>
|
||||
<div class="title" v-drag="['.ba-operate-dialog', '.el-dialog__header']" v-zoom="'.ba-operate-dialog'">
|
||||
{{ step === 'reject' ? t('order.withdrawOrder.review_reject_title') : t('order.withdrawOrder.review_title') }}
|
||||
</div>
|
||||
</template>
|
||||
<el-scrollbar v-loading="baTable.form.loading" class="ba-table-form-scrollbar">
|
||||
<div class="ba-operate-form" :class="'ba-' + baTable.form.operate + '-form'" :style="config.layout.shrink ? '' : 'width: calc(100% - ' + baTable.form.labelWidth! / 2 + 'px)'">
|
||||
<el-form v-if="!baTable.form.loading" ref="formRef" @submit.prevent="" @keyup.enter="baTable.onSubmit(formRef)" :model="baTable.form.items" :label-position="config.layout.shrink ? 'top' : 'right'" :label-width="baTable.form.labelWidth + 'px'" :rules="rules">
|
||||
<FormItem :label="t('order.withdrawOrder.order_no')" type="string" v-model="baTable.form.items!.order_no" prop="order_no" />
|
||||
<FormItem :label="t('order.withdrawOrder.user_id')" type="number" v-model="baTable.form.items!.user_id" prop="user_id" :input-attr="{ min: 1, step: 1 }" />
|
||||
<FormItem :label="t('order.withdrawOrder.channel_id')" type="number" v-model="baTable.form.items!.channel_id" prop="channel_id" :input-attr="{ min: 1, step: 1 }" />
|
||||
<FormItem :label="t('order.withdrawOrder.amount')" type="number" v-model="baTable.form.items!.amount" prop="amount" :input-attr="{ step: 0.0001, precision: 4, min: 0 }" />
|
||||
<FormItem :label="t('order.withdrawOrder.fee')" type="number" v-model="baTable.form.items!.fee" prop="fee" :input-attr="{ step: 0.0001, precision: 4, min: 0 }" />
|
||||
<FormItem :label="t('order.withdrawOrder.actual_amount')" type="number" v-model="baTable.form.items!.actual_amount" prop="actual_amount" :input-attr="{ step: 0.0001, precision: 4, min: 0 }" />
|
||||
<FormItem :label="t('order.withdrawOrder.status')" type="radio" v-model="baTable.form.items!.status" prop="status" :input-attr="{ content: { '0': t('order.withdrawOrder.status 0'), '1': t('order.withdrawOrder.status 1'), '2': t('order.withdrawOrder.status 2'), '3': t('order.withdrawOrder.status 3') } }" />
|
||||
<FormItem :label="t('order.withdrawOrder.review_admin_id')" type="number" v-model="baTable.form.items!.review_admin_id" prop="review_admin_id" :input-attr="{ min: 1, step: 1 }" />
|
||||
<FormItem :label="t('order.withdrawOrder.review_time')" type="datetime" v-model="baTable.form.items!.review_time" prop="review_time" />
|
||||
<FormItem :label="t('order.withdrawOrder.remark')" type="textarea" v-model="baTable.form.items!.remark" prop="remark" :input-attr="{ rows: 2 }" />
|
||||
|
||||
<el-scrollbar v-loading="loading" class="ba-table-form-scrollbar">
|
||||
<div class="ba-operate-form ba-edit-form" :style="config.layout.shrink ? '' : 'width: calc(100% - ' + (baTable.form.labelWidth ?? 120) / 2 + 'px)'">
|
||||
<!-- 第一页:关联信息 + 申请金额 / 手续费 -->
|
||||
<el-form
|
||||
v-if="!loading && step === 'review'"
|
||||
ref="reviewFormRef"
|
||||
:model="form"
|
||||
:rules="reviewRules"
|
||||
:label-position="config.layout.shrink ? 'top' : 'right'"
|
||||
:label-width="(baTable.form.labelWidth ?? 120) + 'px'"
|
||||
@submit.prevent=""
|
||||
>
|
||||
<el-form-item :label="t('order.withdrawOrder.order_no')">
|
||||
<el-input v-model="form.order_no" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.withdrawOrder.user_username')">
|
||||
<el-input :model-value="form.user_text" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.withdrawOrder.channel_name')">
|
||||
<el-input :model-value="form.channel_text" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.withdrawOrder.status')">
|
||||
<el-tag :type="statusTagType" effect="dark" size="small">{{ statusLabel }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.withdrawOrder.create_time')">
|
||||
<el-input :model-value="form.create_time_text" readonly />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('order.withdrawOrder.amount')" prop="amount">
|
||||
<el-input-number
|
||||
v-model="form.amount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
:controls="false"
|
||||
:disabled="!isPending"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.withdrawOrder.fee')" prop="fee">
|
||||
<el-input-number
|
||||
v-model="form.fee"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
:step="0.1"
|
||||
:controls="false"
|
||||
:disabled="!isPending"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.withdrawOrder.actual_amount')">
|
||||
<el-input :model-value="actualAmountText" readonly />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="!isPending" :label="t('order.withdrawOrder.review_admin_username')">
|
||||
<el-input :model-value="form.review_admin_text" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!isPending" :label="t('order.withdrawOrder.review_time')">
|
||||
<el-input :model-value="form.review_time_text" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!isPending" :label="t('order.withdrawOrder.remark')">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="2" readonly />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 第二页:拒绝 -> 必填备注 -->
|
||||
<el-form
|
||||
v-if="!loading && step === 'reject'"
|
||||
ref="rejectFormRef"
|
||||
:model="rejectForm"
|
||||
:rules="rejectRules"
|
||||
:label-position="config.layout.shrink ? 'top' : 'right'"
|
||||
:label-width="(baTable.form.labelWidth ?? 120) + 'px'"
|
||||
@submit.prevent=""
|
||||
>
|
||||
<el-alert
|
||||
class="review-reject-hint"
|
||||
type="warning"
|
||||
show-icon
|
||||
:closable="false"
|
||||
:title="t('order.withdrawOrder.review_reject_tip')"
|
||||
/>
|
||||
<el-form-item :label="t('order.withdrawOrder.order_no')">
|
||||
<el-input v-model="form.order_no" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.withdrawOrder.amount')">
|
||||
<el-input :model-value="amountText" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('order.withdrawOrder.remark')" prop="remark">
|
||||
<el-input
|
||||
v-model="rejectForm.remark"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
maxlength="255"
|
||||
show-word-limit
|
||||
:placeholder="t('order.withdrawOrder.review_reject_placeholder')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
|
||||
<template #footer>
|
||||
<div :style="'width: calc(100% - ' + baTable.form.labelWidth! / 1.8 + 'px)'">
|
||||
<el-button @click="baTable.toggleForm()">{{ t('Cancel') }}</el-button>
|
||||
<el-button v-blur :loading="baTable.form.submitLoading" @click="baTable.onSubmit(formRef)" type="primary">{{ baTable.form.operateIds && baTable.form.operateIds.length > 1 ? t('Save and edit next item') : t('Save') }}</el-button>
|
||||
<div class="review-footer">
|
||||
<template v-if="step === 'review'">
|
||||
<el-button @click="onDialogClose">{{ t('Cancel') }}</el-button>
|
||||
<template v-if="isPending">
|
||||
<el-button type="danger" :loading="submitting" @click="gotoReject">{{ t('order.withdrawOrder.review_btn_reject') }}</el-button>
|
||||
<el-button type="primary" v-blur :loading="submitting" @click="submitApprove">{{ t('order.withdrawOrder.review_btn_approve') }}</el-button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-button @click="backToReview">{{ t('order.withdrawOrder.review_btn_back') }}</el-button>
|
||||
<el-button type="danger" v-blur :loading="submitting" @click="submitReject">{{ t('order.withdrawOrder.review_btn_confirm_reject') }}</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { FormItemRule } from 'element-plus'
|
||||
import { inject, reactive, useTemplateRef } from 'vue'
|
||||
import type { FormInstance, FormItemRule } from 'element-plus'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { computed, inject, reactive, ref, useTemplateRef, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import FormItem from '/@/components/formItem/index.vue'
|
||||
import createAxios from '/@/utils/axios'
|
||||
import { useConfig } from '/@/stores/config'
|
||||
import type baTableClass from '/@/utils/baTable'
|
||||
|
||||
const config = useConfig()
|
||||
const formRef = useTemplateRef('formRef')
|
||||
const baTable = inject('baTable') as baTableClass
|
||||
const { t } = useI18n()
|
||||
|
||||
const rules: Partial<Record<string, FormItemRule[]>> = reactive({
|
||||
order_no: [{ required: true, message: t('Please input field', { field: t('order.withdrawOrder.order_no') }) }],
|
||||
user_id: [{ required: true, message: t('Please input field', { field: t('order.withdrawOrder.user_id') }) }],
|
||||
const reviewFormRef = useTemplateRef<FormInstance>('reviewFormRef')
|
||||
const rejectFormRef = useTemplateRef<FormInstance>('rejectFormRef')
|
||||
|
||||
type Step = 'review' | 'reject'
|
||||
const step = ref<Step>('review')
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
|
||||
const form = reactive({
|
||||
id: 0,
|
||||
order_no: '',
|
||||
user_text: '-',
|
||||
channel_text: '-',
|
||||
create_time_text: '',
|
||||
review_admin_text: '-',
|
||||
review_time_text: '-',
|
||||
amount: 0,
|
||||
fee: 0,
|
||||
status: 0,
|
||||
remark: '',
|
||||
})
|
||||
|
||||
const rejectForm = reactive({
|
||||
remark: '',
|
||||
})
|
||||
|
||||
const isOpen = computed(() => ['Edit'].includes(baTable.form.operate ?? ''))
|
||||
const isPending = computed(() => form.status === 0)
|
||||
|
||||
watch(
|
||||
isOpen,
|
||||
(visible) => {
|
||||
if (!visible) {
|
||||
return
|
||||
}
|
||||
step.value = 'review'
|
||||
rejectForm.remark = ''
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => ({ visible: isOpen.value, loadingState: baTable.form.loading, items: baTable.form.items }),
|
||||
({ visible, loadingState }) => {
|
||||
if (!visible) return
|
||||
loading.value = loadingState === true
|
||||
if (loadingState) return
|
||||
hydrate()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
const hydrate = () => {
|
||||
const row = baTable.form.items as Record<string, unknown> | undefined
|
||||
if (!row || !row['id']) {
|
||||
return
|
||||
}
|
||||
form.id = Number(row['id'] ?? 0)
|
||||
form.order_no = String(row['order_no'] ?? '')
|
||||
form.amount = parseNumber(row['amount'])
|
||||
form.fee = parseNumber(row['fee'])
|
||||
form.status = Number(row['status'] ?? 0)
|
||||
form.remark = String(row['remark'] ?? '')
|
||||
form.create_time_text = formatTime(row['create_time'])
|
||||
form.review_time_text = formatTime(row['review_time'])
|
||||
form.user_text = resolveRelationText(row, 'user', row['user_id'])
|
||||
form.channel_text = resolveRelationText(row, 'channel', row['channel_id'])
|
||||
form.review_admin_text = resolveRelationText(row, 'reviewAdmin', row['review_admin_id'])
|
||||
}
|
||||
|
||||
const statusLabel = computed(() => t('order.withdrawOrder.status ' + form.status))
|
||||
const statusTagType = computed(() => {
|
||||
switch (form.status) {
|
||||
case 1:
|
||||
return 'success'
|
||||
case 2:
|
||||
return 'danger'
|
||||
case 3:
|
||||
return 'success'
|
||||
default:
|
||||
return 'warning'
|
||||
}
|
||||
})
|
||||
|
||||
const amountText = computed(() => formatAmount(form.amount))
|
||||
const actualAmountText = computed(() => {
|
||||
const actual = Number((form.amount - form.fee).toFixed(2))
|
||||
return formatAmount(actual < 0 ? 0 : actual)
|
||||
})
|
||||
|
||||
const reviewRules: Record<string, FormItemRule[]> = {
|
||||
amount: [
|
||||
{
|
||||
required: true,
|
||||
validator: (_r, value, cb) => {
|
||||
if (value === null || value === undefined || Number(value) <= 0) {
|
||||
cb(new Error(t('order.withdrawOrder.amount_invalid')))
|
||||
return
|
||||
}
|
||||
cb()
|
||||
},
|
||||
},
|
||||
],
|
||||
fee: [
|
||||
{
|
||||
required: true,
|
||||
validator: (_r, value, cb) => {
|
||||
if (value === null || value === undefined || Number(value) < 0) {
|
||||
cb(new Error(t('order.withdrawOrder.fee_invalid')))
|
||||
return
|
||||
}
|
||||
if (Number(value) > Number(form.amount)) {
|
||||
cb(new Error(t('order.withdrawOrder.fee_exceed_amount')))
|
||||
return
|
||||
}
|
||||
cb()
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const rejectRules: Record<string, FormItemRule[]> = {
|
||||
remark: [
|
||||
{
|
||||
required: true,
|
||||
validator: (_r, value, cb) => {
|
||||
const text = typeof value === 'string' ? value.trim() : ''
|
||||
if (text === '') {
|
||||
cb(new Error(t('order.withdrawOrder.reject_reason_required')))
|
||||
return
|
||||
}
|
||||
cb()
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const onDialogClose = () => {
|
||||
if (submitting.value) {
|
||||
return
|
||||
}
|
||||
step.value = 'review'
|
||||
baTable.toggleForm()
|
||||
}
|
||||
|
||||
const gotoReject = async () => {
|
||||
step.value = 'reject'
|
||||
rejectForm.remark = ''
|
||||
}
|
||||
|
||||
const backToReview = () => {
|
||||
step.value = 'review'
|
||||
}
|
||||
|
||||
const submitApprove = async () => {
|
||||
if (!isPending.value) {
|
||||
ElMessage.warning(t('order.withdrawOrder.already_reviewed'))
|
||||
return
|
||||
}
|
||||
const formEl = reviewFormRef.value
|
||||
if (!formEl) return
|
||||
const valid = await formEl.validate().catch(() => false)
|
||||
if (!valid) return
|
||||
submitting.value = true
|
||||
try {
|
||||
await createAxios(
|
||||
{
|
||||
url: '/admin/order.WithdrawOrder/approve',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: form.id,
|
||||
amount: form.amount.toFixed(4),
|
||||
fee: form.fee.toFixed(4),
|
||||
},
|
||||
},
|
||||
{ showSuccessMessage: true }
|
||||
)
|
||||
baTable.onTableHeaderAction('refresh', {})
|
||||
baTable.toggleForm()
|
||||
} catch (_e) {
|
||||
// errors already surfaced by axios interceptor
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const submitReject = async () => {
|
||||
const formEl = rejectFormRef.value
|
||||
if (!formEl) return
|
||||
const valid = await formEl.validate().catch(() => false)
|
||||
if (!valid) return
|
||||
submitting.value = true
|
||||
try {
|
||||
await createAxios(
|
||||
{
|
||||
url: '/admin/order.WithdrawOrder/reject',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: form.id,
|
||||
remark: rejectForm.remark.trim(),
|
||||
},
|
||||
},
|
||||
{ showSuccessMessage: true }
|
||||
)
|
||||
baTable.onTableHeaderAction('refresh', {})
|
||||
baTable.toggleForm()
|
||||
} catch (_e) {
|
||||
// errors already surfaced by axios interceptor
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function parseNumber(raw: unknown): number {
|
||||
if (raw === null || raw === undefined || raw === '') return 0
|
||||
const n = Number(raw)
|
||||
if (!Number.isFinite(n)) return 0
|
||||
return Number(n.toFixed(2))
|
||||
}
|
||||
|
||||
function formatAmount(value: number): string {
|
||||
if (!Number.isFinite(value)) return '0.00'
|
||||
return value.toFixed(2)
|
||||
}
|
||||
|
||||
function formatTime(raw: unknown): string {
|
||||
if (raw === null || raw === undefined || raw === '' || raw === 0) return '-'
|
||||
const sec = Number(raw)
|
||||
if (!Number.isFinite(sec) || sec <= 0) return '-'
|
||||
const d = new Date(sec * 1000)
|
||||
const pad = (n: number) => (n < 10 ? '0' + n : String(n))
|
||||
return (
|
||||
d.getFullYear() +
|
||||
'-' +
|
||||
pad(d.getMonth() + 1) +
|
||||
'-' +
|
||||
pad(d.getDate()) +
|
||||
' ' +
|
||||
pad(d.getHours()) +
|
||||
':' +
|
||||
pad(d.getMinutes()) +
|
||||
':' +
|
||||
pad(d.getSeconds())
|
||||
)
|
||||
}
|
||||
|
||||
function resolveRelationText(row: Record<string, unknown>, relationKey: string, fallbackId: unknown): string {
|
||||
const rel = row[relationKey]
|
||||
if (rel && typeof rel === 'object') {
|
||||
const r = rel as Record<string, unknown>
|
||||
const name = r['username'] ?? r['name']
|
||||
if (typeof name === 'string' && name !== '') {
|
||||
const id = fallbackId === null || fallbackId === undefined || fallbackId === '' ? '' : ' (ID: ' + String(fallbackId) + ')'
|
||||
return name + id
|
||||
}
|
||||
}
|
||||
if (fallbackId === null || fallbackId === undefined || fallbackId === '') {
|
||||
return '-'
|
||||
}
|
||||
return 'ID: ' + String(fallbackId)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
<style scoped lang="scss">
|
||||
.withdraw-review-dialog {
|
||||
:deep(.el-dialog__body) {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.review-reject-hint {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.review-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
:deep(.withdraw-review-dialog) {
|
||||
width: calc(100vw - 24px) !important;
|
||||
max-width: 100vw;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="default-main ba-table-box">
|
||||
<el-alert class="ba-table-alert" v-if="baTable.table.remark" :title="baTable.table.remark" type="info" show-icon />
|
||||
|
||||
@@ -245,8 +245,17 @@ const baTable = new baTableClass(
|
||||
formatter: formatCoin,
|
||||
},
|
||||
{
|
||||
label: t('user.user.total_valid_bet_coin'),
|
||||
prop: 'total_valid_bet_coin',
|
||||
label: t('user.user.total_withdraw_coin'),
|
||||
prop: 'total_withdraw_coin',
|
||||
align: 'center',
|
||||
minWidth: 110,
|
||||
sortable: false,
|
||||
operator: 'RANGE',
|
||||
formatter: formatCoin,
|
||||
},
|
||||
{
|
||||
label: t('user.user.bet_flow_coin'),
|
||||
prop: 'bet_flow_coin',
|
||||
align: 'center',
|
||||
minWidth: 110,
|
||||
sortable: false,
|
||||
@@ -352,7 +361,8 @@ const baTable = new baTableClass(
|
||||
status: '1',
|
||||
coin: '0.00',
|
||||
total_deposit_coin: '0.00',
|
||||
total_valid_bet_coin: '0.00',
|
||||
total_withdraw_coin: '0.00',
|
||||
bet_flow_coin: '0.00',
|
||||
risk_flags: 0,
|
||||
current_streak: 0,
|
||||
last_bet_period_no: '',
|
||||
|
||||
Reference in New Issue
Block a user