[游戏管理]用户管理-优化钱包操作
This commit is contained in:
@@ -20,7 +20,7 @@ class User extends Backend
|
|||||||
*/
|
*/
|
||||||
protected ?object $model = null;
|
protected ?object $model = null;
|
||||||
|
|
||||||
protected array|string $preExcludeFields = ['id', 'uuid', 'create_time', 'update_time', 'invite_code'];
|
protected array|string $preExcludeFields = ['id', 'uuid', 'create_time', 'update_time', 'invite_code', 'coin', 'total_deposit_coin', 'total_valid_bet_coin'];
|
||||||
|
|
||||||
protected array $withJoinTable = ['channel', 'admin'];
|
protected array $withJoinTable = ['channel', 'admin'];
|
||||||
|
|
||||||
@@ -200,6 +200,159 @@ class User extends Backend
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台钱包加减点(不允许在用户编辑表单直接改余额)
|
||||||
|
*/
|
||||||
|
public function walletAdjust(WebmanRequest $request): Response
|
||||||
|
{
|
||||||
|
$response = $this->initializeBackend($request);
|
||||||
|
if ($response !== null) {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
if ($request->method() !== 'POST') {
|
||||||
|
return $this->error(__('Parameter error'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$userIdRaw = $request->post('user_id');
|
||||||
|
$userId = is_numeric(strval($userIdRaw)) ? intval(strval($userIdRaw)) : 0;
|
||||||
|
if ($userId <= 0) {
|
||||||
|
return $this->error(__('Parameter error'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$opRaw = $request->post('op');
|
||||||
|
$op = is_string($opRaw) ? trim($opRaw) : '';
|
||||||
|
if (!in_array($op, ['credit', 'deduct'], true)) {
|
||||||
|
return $this->error('操作类型不正确');
|
||||||
|
}
|
||||||
|
|
||||||
|
$amountRaw = $request->post('amount');
|
||||||
|
$amountText = is_string($amountRaw) || is_numeric($amountRaw) ? trim(strval($amountRaw)) : '';
|
||||||
|
if ($amountText === '' || !is_numeric($amountText)) {
|
||||||
|
return $this->error('金额格式不正确');
|
||||||
|
}
|
||||||
|
if (bccomp($amountText, '0', 4) <= 0) {
|
||||||
|
return $this->error('金额必须大于0');
|
||||||
|
}
|
||||||
|
|
||||||
|
$remarkRaw = $request->post('remark');
|
||||||
|
$remark = is_string($remarkRaw) ? trim($remarkRaw) : '';
|
||||||
|
$adminName = is_string($this->auth->username ?? null) ? $this->auth->username : ('#' . strval($this->auth->id));
|
||||||
|
$amountForRemark = self::formatAmountForDisplay($amountText);
|
||||||
|
if ($remark === '') {
|
||||||
|
$actionText = $op === 'credit' ? '加点' : '扣点';
|
||||||
|
$remark = '后台管理员(' . $adminName . ')' . $actionText . $amountForRemark . '(值)';
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->model->where('id', $userId)->find();
|
||||||
|
if (!$user) {
|
||||||
|
return $this->error(__('Record not found'));
|
||||||
|
}
|
||||||
|
$dataLimitAdminIds = $this->getDataLimitAdminIds();
|
||||||
|
if ($dataLimitAdminIds && !in_array($user[$this->dataLimitField], $dataLimitAdminIds)) {
|
||||||
|
return $this->error(__('You have no permission'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$channelIdRaw = $user['channel_id'] ?? null;
|
||||||
|
$channelId = is_numeric(strval($channelIdRaw)) ? intval(strval($channelIdRaw)) : null;
|
||||||
|
$before = strval($user['coin'] ?? '0');
|
||||||
|
$delta = self::normalizeAmountScale($amountText, 4);
|
||||||
|
if ($op === 'credit') {
|
||||||
|
$after = bcadd($before, $delta, 4);
|
||||||
|
$bizType = 'admin_credit';
|
||||||
|
$direction = 1;
|
||||||
|
} else {
|
||||||
|
if (bccomp($before, $delta, 4) < 0) {
|
||||||
|
return $this->error('余额不足,扣点失败');
|
||||||
|
}
|
||||||
|
$after = bcsub($before, $delta, 4);
|
||||||
|
$bizType = 'admin_deduct';
|
||||||
|
$direction = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = time();
|
||||||
|
$idem = 'admin_adjust_' . $userId . '_' . $this->auth->id . '_' . $now . '_' . random_int(1000, 9999);
|
||||||
|
Db::startTrans();
|
||||||
|
try {
|
||||||
|
Db::name('user')->where('id', $userId)->update([
|
||||||
|
'coin' => $after,
|
||||||
|
'update_time' => $now,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Db::name('user_wallet_record')->insert([
|
||||||
|
'user_id' => $userId,
|
||||||
|
'channel_id' => $channelId,
|
||||||
|
'biz_type' => $bizType,
|
||||||
|
'direction' => $direction,
|
||||||
|
'amount' => $delta,
|
||||||
|
'balance_before' => $before,
|
||||||
|
'balance_after' => $after,
|
||||||
|
'ref_type' => 'admin_user_wallet_adjust',
|
||||||
|
'ref_id' => null,
|
||||||
|
'idempotency_key' => $idem,
|
||||||
|
'operator_admin_id' => intval(strval($this->auth->id)),
|
||||||
|
'remark' => substr($remark, 0, 500),
|
||||||
|
'create_time' => $now,
|
||||||
|
]);
|
||||||
|
Db::commit();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
Db::rollback();
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->success('钱包调整成功', [
|
||||||
|
'user_id' => $userId,
|
||||||
|
'coin_before' => self::formatAmountForDisplay($before),
|
||||||
|
'coin_after' => self::formatAmountForDisplay($after),
|
||||||
|
'amount' => self::formatAmountForDisplay($delta),
|
||||||
|
'op' => $op,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function normalizeAmountScale(string $amount, int $scale): string
|
||||||
|
{
|
||||||
|
$raw = trim(str_replace(',', '.', $amount));
|
||||||
|
if ($raw === '') {
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
$negative = false;
|
||||||
|
if (str_starts_with($raw, '-')) {
|
||||||
|
$negative = true;
|
||||||
|
$raw = ltrim(substr($raw, 1));
|
||||||
|
}
|
||||||
|
if (!str_contains($raw, '.')) {
|
||||||
|
$v = ltrim($raw, '0');
|
||||||
|
$v = $v === '' ? '0' : $v;
|
||||||
|
return $negative ? ('-' . $v) : $v;
|
||||||
|
}
|
||||||
|
[$intPart, $fracPart] = explode('.', $raw, 2);
|
||||||
|
$intPart = ltrim($intPart, '0');
|
||||||
|
$intPart = $intPart === '' ? '0' : $intPart;
|
||||||
|
$fracPart = preg_replace('/\D+/', '', $fracPart) ?? '';
|
||||||
|
if (strlen($fracPart) > $scale) {
|
||||||
|
$fracPart = substr($fracPart, 0, $scale);
|
||||||
|
} else {
|
||||||
|
$fracPart = str_pad($fracPart, $scale, '0');
|
||||||
|
}
|
||||||
|
$v = $intPart . '.' . $fracPart;
|
||||||
|
return $negative ? ('-' . $v) : $v;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function formatAmountForDisplay(string $amount): string
|
||||||
|
{
|
||||||
|
$normalized = self::normalizeAmountScale($amount, 4);
|
||||||
|
$negative = false;
|
||||||
|
if (str_starts_with($normalized, '-')) {
|
||||||
|
$negative = true;
|
||||||
|
$normalized = substr($normalized, 1);
|
||||||
|
}
|
||||||
|
$parts = explode('.', $normalized, 2);
|
||||||
|
$intPart = $parts[0] ?? '0';
|
||||||
|
$fracPart = $parts[1] ?? '0000';
|
||||||
|
$displayFrac = substr($fracPart, 0, 2);
|
||||||
|
$v = $intPart . '.' . str_pad($displayFrac, 2, '0');
|
||||||
|
return $negative ? ('-' . $v) : $v;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色组 → 管理员树(仅当前账号可管理的角色组及其下管理员;用于游戏用户归属)
|
* 角色组 → 管理员树(仅当前账号可管理的角色组及其下管理员;用于游戏用户归属)
|
||||||
* 同一管理员若属于多个组,只挂在 id 最小的所属组下,避免树中重复 value
|
* 同一管理员若属于多个组,只挂在 id 最小的所属组下,避免树中重复 value
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default {
|
|||||||
head_image: 'Avatar',
|
head_image: 'Avatar',
|
||||||
remark: 'Remark',
|
remark: 'Remark',
|
||||||
coin: 'Coin balance',
|
coin: 'Coin balance',
|
||||||
coin_placeholder: 'decimal(18,4)',
|
coin_placeholder: 'Amounts are displayed with 2 decimals',
|
||||||
total_deposit_coin: 'Total deposit (coin)',
|
total_deposit_coin: 'Total deposit (coin)',
|
||||||
total_valid_bet_coin: 'Total valid bet (coin)',
|
total_valid_bet_coin: 'Total valid bet (coin)',
|
||||||
risk_flags: 'Risk',
|
risk_flags: 'Risk',
|
||||||
@@ -42,4 +42,12 @@ export default {
|
|||||||
section_risk: 'Risk control',
|
section_risk: 'Risk control',
|
||||||
section_streak: 'Streak (fallback)',
|
section_streak: 'Streak (fallback)',
|
||||||
section_other: 'Other',
|
section_other: 'Other',
|
||||||
|
wallet_adjust_title: 'Wallet adjustment',
|
||||||
|
wallet_adjust_op: 'Operation',
|
||||||
|
wallet_adjust_credit: 'Credit',
|
||||||
|
wallet_adjust_deduct: 'Deduct',
|
||||||
|
wallet_adjust_amount: 'Amount',
|
||||||
|
wallet_adjust_amount_invalid: 'Please enter an amount greater than 0',
|
||||||
|
wallet_adjust_operator_admin: 'operator admin',
|
||||||
|
wallet_adjust_default_remark: 'Backend admin ({admin}) {action} {amount} (value)',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
head_image: '头像',
|
head_image: '头像',
|
||||||
remark: '备注',
|
remark: '备注',
|
||||||
coin: '余额',
|
coin: '余额',
|
||||||
coin_placeholder: 'decimal(18,4),禁止业务用浮点存库',
|
coin_placeholder: '金额展示统一两位小数',
|
||||||
total_deposit_coin: '累计充值(币)',
|
total_deposit_coin: '累计充值(币)',
|
||||||
total_valid_bet_coin: '累计有效投注(币)',
|
total_valid_bet_coin: '累计有效投注(币)',
|
||||||
risk_flags: '风控',
|
risk_flags: '风控',
|
||||||
@@ -42,4 +42,12 @@
|
|||||||
section_risk: '风控',
|
section_risk: '风控',
|
||||||
section_streak: '连胜(兜底)',
|
section_streak: '连胜(兜底)',
|
||||||
section_other: '其他',
|
section_other: '其他',
|
||||||
|
wallet_adjust_title: '钱包加减点',
|
||||||
|
wallet_adjust_op: '操作类型',
|
||||||
|
wallet_adjust_credit: '加点',
|
||||||
|
wallet_adjust_deduct: '扣点',
|
||||||
|
wallet_adjust_amount: '操作金额',
|
||||||
|
wallet_adjust_amount_invalid: '请输入大于0的金额',
|
||||||
|
wallet_adjust_operator_admin: '操作管理员',
|
||||||
|
wallet_adjust_default_remark: '后台管理员({admin}){action}{amount}(值)',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,24 +10,71 @@
|
|||||||
<Table ref="tableRef"></Table>
|
<Table ref="tableRef"></Table>
|
||||||
|
|
||||||
<PopupForm />
|
<PopupForm />
|
||||||
|
|
||||||
|
<el-dialog v-model="walletDialogVisible" class="ba-operate-dialog wallet-adjust-dialog" :close-on-click-modal="false" width="520px">
|
||||||
|
<template #header>
|
||||||
|
<div class="title">{{ t('user.user.wallet_adjust_title') }}</div>
|
||||||
|
</template>
|
||||||
|
<el-scrollbar class="ba-table-form-scrollbar">
|
||||||
|
<div class="ba-operate-form wallet-adjust-form">
|
||||||
|
<el-form :label-position="config.layout.shrink ? 'top' : 'right'" :label-width="config.layout.shrink ? '' : '110px'">
|
||||||
|
<el-form-item :label="t('user.user.username')">
|
||||||
|
<el-input :model-value="walletForm.username" readonly />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('user.user.coin')">
|
||||||
|
<el-tag type="primary">{{ walletForm.current_coin }}</el-tag>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('user.user.wallet_adjust_op')">
|
||||||
|
<el-radio-group v-model="walletForm.op" class="wallet-adjust-op-group" @change="syncWalletRemark">
|
||||||
|
<el-radio label="credit">{{ t('user.user.wallet_adjust_credit') }}</el-radio>
|
||||||
|
<el-radio label="deduct">{{ t('user.user.wallet_adjust_deduct') }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('user.user.wallet_adjust_amount')">
|
||||||
|
<el-input-number
|
||||||
|
class="wallet-adjust-amount-input"
|
||||||
|
v-model="walletForm.amount"
|
||||||
|
:min="0.01"
|
||||||
|
:step="0.01"
|
||||||
|
:precision="2"
|
||||||
|
@change="syncWalletRemark"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="t('user.user.remark')">
|
||||||
|
<el-input v-model="walletForm.remark" type="textarea" :rows="3" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
<template #footer>
|
||||||
|
<div class="wallet-adjust-dialog-footer">
|
||||||
|
<el-button @click="walletDialogVisible = false">{{ t('Cancel') }}</el-button>
|
||||||
|
<el-button type="primary" :loading="walletSubmitting" @click="submitWalletAdjust">{{ t('Save') }}</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, provide, useTemplateRef } from 'vue'
|
import { onMounted, provide, reactive, ref, useTemplateRef } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
import PopupForm from './popupForm.vue'
|
import PopupForm from './popupForm.vue'
|
||||||
import { baTableApi } from '/@/api/common'
|
import { baTableApi } from '/@/api/common'
|
||||||
import { defaultOptButtons } from '/@/components/table'
|
import { defaultOptButtons } from '/@/components/table'
|
||||||
import TableHeader from '/@/components/table/header/index.vue'
|
import TableHeader from '/@/components/table/header/index.vue'
|
||||||
import Table from '/@/components/table/index.vue'
|
import Table from '/@/components/table/index.vue'
|
||||||
import baTableClass from '/@/utils/baTable'
|
import baTableClass from '/@/utils/baTable'
|
||||||
|
import createAxios from '/@/utils/axios'
|
||||||
|
import { useConfig } from '/@/stores/config'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'user/user',
|
name: 'user/user',
|
||||||
})
|
})
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
const config = useConfig()
|
||||||
const tableRef = useTemplateRef('tableRef')
|
const tableRef = useTemplateRef('tableRef')
|
||||||
const optButtons: OptButton[] = defaultOptButtons(['edit', 'delete'])
|
const optButtons: OptButton[] = defaultOptButtons(['edit', 'delete'])
|
||||||
|
|
||||||
@@ -40,7 +87,7 @@ function formatCoin(_row: anyObj, _column: any, cellValue: unknown) {
|
|||||||
if (!Number.isFinite(n)) {
|
if (!Number.isFinite(n)) {
|
||||||
return String(cellValue)
|
return String(cellValue)
|
||||||
}
|
}
|
||||||
return n.toFixed(4)
|
return n.toFixed(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 杩斿洖澶氭爣绛炬枃妗堟暟缁勶紝渚?render: tags 浣跨敤 */
|
/** 杩斿洖澶氭爣绛炬枃妗堟暟缁勶紝渚?render: tags 浣跨敤 */
|
||||||
@@ -55,6 +102,73 @@ function formatRiskFlags(row: anyObj, _column: any, cellValue: unknown) {
|
|||||||
return parts
|
return parts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildDisplayAmount(v: unknown): string {
|
||||||
|
if (v === null || v === undefined || v === '') return '0.00'
|
||||||
|
const n = parseFloat(String(v).trim().replace(',', '.'))
|
||||||
|
if (!Number.isFinite(n)) return '0.00'
|
||||||
|
return n.toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
const walletDialogVisible = ref(false)
|
||||||
|
const walletSubmitting = ref(false)
|
||||||
|
const walletForm = reactive({
|
||||||
|
user_id: 0,
|
||||||
|
username: '',
|
||||||
|
current_coin: '0.00',
|
||||||
|
op: 'credit',
|
||||||
|
amount: 100,
|
||||||
|
remark: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
function syncWalletRemark() {
|
||||||
|
const action = walletForm.op === 'credit' ? t('user.user.wallet_adjust_credit') : t('user.user.wallet_adjust_deduct')
|
||||||
|
walletForm.remark = t('user.user.wallet_adjust_default_remark', {
|
||||||
|
admin: t('user.user.wallet_adjust_operator_admin'),
|
||||||
|
action,
|
||||||
|
amount: Number(walletForm.amount || 0).toFixed(2),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function openWalletDialog(row: anyObj) {
|
||||||
|
walletForm.user_id = Number(row.id || 0)
|
||||||
|
walletForm.username = String(row.username ?? '-')
|
||||||
|
walletForm.current_coin = buildDisplayAmount(row.coin)
|
||||||
|
walletForm.op = 'credit'
|
||||||
|
walletForm.amount = 100
|
||||||
|
syncWalletRemark()
|
||||||
|
walletDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function submitWalletAdjust() {
|
||||||
|
if (!walletForm.user_id) return
|
||||||
|
if (!(walletForm.amount > 0)) {
|
||||||
|
ElMessage.error(t('user.user.wallet_adjust_amount_invalid'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
walletSubmitting.value = true
|
||||||
|
try {
|
||||||
|
const res = await createAxios({
|
||||||
|
url: '/admin/user.User/walletAdjust',
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
user_id: walletForm.user_id,
|
||||||
|
op: walletForm.op,
|
||||||
|
amount: Number(walletForm.amount).toFixed(2),
|
||||||
|
remark: walletForm.remark,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (res.code === 1) {
|
||||||
|
ElMessage.success(res.msg || t('Success'))
|
||||||
|
walletDialogVisible.value = false
|
||||||
|
await baTable.getData()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg || t('Unknown error'))
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
walletSubmitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const baTable = new baTableClass(
|
const baTable = new baTableClass(
|
||||||
new baTableApi('/admin/user.User/'),
|
new baTableApi('/admin/user.User/'),
|
||||||
{
|
{
|
||||||
@@ -105,7 +219,22 @@ const baTable = new baTableClass(
|
|||||||
showOverflowTooltip: true,
|
showOverflowTooltip: true,
|
||||||
operator: 'LIKE',
|
operator: 'LIKE',
|
||||||
},
|
},
|
||||||
{ label: t('user.user.coin'), prop: 'coin', align: 'center', sortable: false, operator: 'RANGE', formatter: formatCoin },
|
{
|
||||||
|
label: t('user.user.coin'),
|
||||||
|
prop: 'coin',
|
||||||
|
align: 'center',
|
||||||
|
minWidth: 100,
|
||||||
|
sortable: false,
|
||||||
|
operator: 'RANGE',
|
||||||
|
render: 'tag',
|
||||||
|
formatter: formatCoin,
|
||||||
|
customRenderAttr: {
|
||||||
|
tag: ({ row }) => ({
|
||||||
|
class: 'wallet-balance-tag',
|
||||||
|
onClick: () => openWalletDialog(row),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: t('user.user.total_deposit_coin'),
|
label: t('user.user.total_deposit_coin'),
|
||||||
prop: 'total_deposit_coin',
|
prop: 'total_deposit_coin',
|
||||||
@@ -221,9 +350,9 @@ const baTable = new baTableClass(
|
|||||||
{
|
{
|
||||||
defaultItems: {
|
defaultItems: {
|
||||||
status: '1',
|
status: '1',
|
||||||
coin: '0.0000',
|
coin: '0.00',
|
||||||
total_deposit_coin: '0.0000',
|
total_deposit_coin: '0.00',
|
||||||
total_valid_bet_coin: '0.0000',
|
total_valid_bet_coin: '0.00',
|
||||||
risk_flags: 0,
|
risk_flags: 0,
|
||||||
current_streak: 0,
|
current_streak: 0,
|
||||||
last_bet_period_no: '',
|
last_bet_period_no: '',
|
||||||
@@ -246,6 +375,54 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss">
|
||||||
|
.wallet-balance-tag {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-adjust-form :deep(.el-form-item) {
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-adjust-op-group {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-adjust-amount-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-adjust-amount-input :deep(.el-input__wrapper) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-adjust-dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.wallet-adjust-dialog :deep(.el-dialog) {
|
||||||
|
width: calc(100vw - 16px) !important;
|
||||||
|
margin-top: 4vh !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-adjust-op-group {
|
||||||
|
gap: 8px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-adjust-dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wallet-adjust-dialog-footer .el-button {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -99,30 +99,6 @@
|
|||||||
:placeholder="t('user.user.register_invite_code_auto_placeholder')"
|
:placeholder="t('user.user.register_invite_code_auto_placeholder')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<el-divider content-position="left">{{ t('user.user.section_finance') }}</el-divider>
|
|
||||||
<FormItem
|
|
||||||
:label="t('user.user.coin')"
|
|
||||||
type="number"
|
|
||||||
v-model="baTable.form.items!.coin"
|
|
||||||
prop="coin"
|
|
||||||
:input-attr="{ step: 0.0001, min: 0, precision: 4 }"
|
|
||||||
:placeholder="t('user.user.coin_placeholder')"
|
|
||||||
/>
|
|
||||||
<FormItem
|
|
||||||
:label="t('user.user.total_deposit_coin')"
|
|
||||||
type="number"
|
|
||||||
v-model="baTable.form.items!.total_deposit_coin"
|
|
||||||
prop="total_deposit_coin"
|
|
||||||
:input-attr="{ step: 0.0001, min: 0, precision: 4 }"
|
|
||||||
/>
|
|
||||||
<FormItem
|
|
||||||
:label="t('user.user.total_valid_bet_coin')"
|
|
||||||
type="number"
|
|
||||||
v-model="baTable.form.items!.total_valid_bet_coin"
|
|
||||||
prop="total_valid_bet_coin"
|
|
||||||
:input-attr="{ step: 0.0001, min: 0, precision: 4 }"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<el-divider content-position="left">{{ t('user.user.section_risk') }}</el-divider>
|
<el-divider content-position="left">{{ t('user.user.section_risk') }}</el-divider>
|
||||||
<el-form-item :label="t('user.user.risk_flags')">
|
<el-form-item :label="t('user.user.risk_flags')">
|
||||||
<div class="risk-flag-row">
|
<div class="risk-flag-row">
|
||||||
@@ -455,27 +431,10 @@ const validatorGameUserPassword = (rule: any, val: string, callback: (error?: Er
|
|||||||
return callback()
|
return callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
const decimalRule = (fieldTitle: string): FormItemRule => ({
|
|
||||||
trigger: 'blur',
|
|
||||||
validator: (_rule, val, callback) => {
|
|
||||||
if (val === null || val === undefined || val === '') {
|
|
||||||
return callback()
|
|
||||||
}
|
|
||||||
const n = typeof val === 'number' ? val : parseFloat(String(val).trim().replace(',', '.'))
|
|
||||||
if (!Number.isFinite(n) || n < 0) {
|
|
||||||
return callback(new Error(t('Please enter the correct field', { field: fieldTitle })))
|
|
||||||
}
|
|
||||||
return callback()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const rules: Partial<Record<string, FormItemRule[]>> = reactive({
|
const rules: Partial<Record<string, FormItemRule[]>> = reactive({
|
||||||
username: [buildValidatorData({ name: 'required', title: t('user.user.username') })],
|
username: [buildValidatorData({ name: 'required', title: t('user.user.username') })],
|
||||||
password: [{ validator: validatorGameUserPassword, trigger: 'blur' }],
|
password: [{ validator: validatorGameUserPassword, trigger: 'blur' }],
|
||||||
phone: [buildValidatorData({ name: 'required', title: t('user.user.phone') })],
|
phone: [buildValidatorData({ name: 'required', title: t('user.user.phone') })],
|
||||||
coin: [decimalRule(t('user.user.coin'))],
|
|
||||||
total_deposit_coin: [decimalRule(t('user.user.total_deposit_coin'))],
|
|
||||||
total_valid_bet_coin: [decimalRule(t('user.user.total_valid_bet_coin'))],
|
|
||||||
admin_id: [buildValidatorData({ name: 'required', title: t('user.user.admin_affiliation') })],
|
admin_id: [buildValidatorData({ name: 'required', title: t('user.user.admin_affiliation') })],
|
||||||
create_time: [buildValidatorData({ name: 'date', title: t('user.user.create_time') })],
|
create_time: [buildValidatorData({ name: 'date', title: t('user.user.create_time') })],
|
||||||
update_time: [buildValidatorData({ name: 'date', title: t('user.user.update_time') })],
|
update_time: [buildValidatorData({ name: 'date', title: t('user.user.update_time') })],
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ function formatAmount(_row: anyObj, _column: any, cellValue: unknown) {
|
|||||||
if (!Number.isFinite(n)) {
|
if (!Number.isFinite(n)) {
|
||||||
return String(cellValue)
|
return String(cellValue)
|
||||||
}
|
}
|
||||||
return n.toFixed(4)
|
return n.toFixed(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
const bizReplace = {
|
const bizReplace = {
|
||||||
|
|||||||
Reference in New Issue
Block a user