feat: 充值订单审计与重新申请,优化赛事展示和余额刷新
- 新增 deposit_order_audit_logs 表,记录提交/审批/拒绝/撤销/重提全链路 - 管理端充值单页增加审计历史;玩家端充值历史支持时间线与重新申请 - 已拒绝订单可原单号重提;撤销入账使用 PLAYER_DEPOSIT_REVERSAL 并加强幂等 - 结算后清除热门标记,允许归档已结算赛事,完善今日赛事时区窗口 - 足球页今日/早盘独立折叠;资料与余额在进入钱包/个人页及下注后自动刷新 - 补充投注玩法、结算返水规则文档;新增 smoke/settlement CLI 脚本 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import { useAuthStore } from '../stores/auth';
|
||||
import { formatMoney, parseAmount } from '../utils/localeDisplay';
|
||||
import BetSuccessOverlay from './BetSuccessOverlay.vue';
|
||||
import api from '../api';
|
||||
import { usePlayerProfile } from '../composables/usePlayerProfile';
|
||||
|
||||
const props = defineProps<{ modelValue: boolean }>();
|
||||
const emit = defineEmits<{ 'update:modelValue': [boolean] }>();
|
||||
@@ -19,6 +20,7 @@ const emit = defineEmits<{ 'update:modelValue': [boolean] }>();
|
||||
const { t, locale } = useI18n();
|
||||
const slip = useBetSlipStore();
|
||||
const auth = useAuthStore();
|
||||
const { refreshProfile } = usePlayerProfile();
|
||||
const show = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (v) => emit('update:modelValue', v),
|
||||
@@ -261,7 +263,7 @@ async function placeBet() {
|
||||
}
|
||||
success.value = t('bet.place_success');
|
||||
showSuccess.value = true;
|
||||
await loadBalance();
|
||||
await Promise.all([loadBalance(), refreshProfile()]);
|
||||
setTimeout(() => {
|
||||
if (showSuccess.value) onSuccessDone();
|
||||
}, 2200);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { formatMoney } from '../utils/localeDisplay';
|
||||
import { usePlayerProfile } from '../composables/usePlayerProfile';
|
||||
|
||||
const { locale, t } = useI18n();
|
||||
const { profileRaw } = usePlayerProfile();
|
||||
const { profileRaw, refreshProfile } = usePlayerProfile();
|
||||
const router = useRouter();
|
||||
const open = ref(false);
|
||||
const root = ref<HTMLElement | null>(null);
|
||||
@@ -38,7 +38,9 @@ const total = computed(() =>
|
||||
);
|
||||
|
||||
function toggle() {
|
||||
open.value = !open.value;
|
||||
const next = !open.value;
|
||||
open.value = next;
|
||||
if (next) void refreshProfile();
|
||||
}
|
||||
|
||||
function close() {
|
||||
|
||||
@@ -64,6 +64,8 @@ const openCount = computed(() => props.matches.filter(m => m.matchPhase === 'ope
|
||||
:src="leagueLogoUrl || saishiImg"
|
||||
alt=""
|
||||
class="league-saishi"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -91,6 +91,8 @@ const liveScoreText = computed(() => {
|
||||
class="team-flag"
|
||||
:class="{ 'flag-logo': homeIsLogo }"
|
||||
alt=""
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -108,6 +110,8 @@ const liveScoreText = computed(() => {
|
||||
class="team-flag"
|
||||
:class="{ 'flag-logo': awayIsLogo }"
|
||||
alt=""
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import api from '../../api';
|
||||
import { usePlayerProfile } from '../../composables/usePlayerProfile';
|
||||
import { formatMoney, parseAmount } from '../../utils/localeDisplay';
|
||||
import { teamFlagUrl } from '../../utils/teamFlag';
|
||||
import BetSuccessOverlay from '../BetSuccessOverlay.vue';
|
||||
@@ -23,6 +24,7 @@ const props = defineProps<{
|
||||
const emit = defineEmits<{ close: [] }>();
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const { refreshProfile } = usePlayerProfile();
|
||||
|
||||
const step = ref<'form' | 'success'>('form');
|
||||
const stake = ref(1);
|
||||
@@ -105,6 +107,7 @@ async function submit() {
|
||||
balance.value = successBalance.value;
|
||||
step.value = 'success';
|
||||
showSuccess.value = true;
|
||||
void refreshProfile();
|
||||
} catch (e: unknown) {
|
||||
error.value =
|
||||
(e as { response?: { data?: { error?: string } } })?.response?.data?.error ||
|
||||
|
||||
Reference in New Issue
Block a user