feat(i18n): 管理端与玩家端三语支持(中/英/马来语)

- 管理后台 adminT 文案库、结算与代理端页面、表单校验
- 玩家端 vue-i18n 补全首页/公告/串关与 ms 文案
- Element Plus ms 语言包与共享 locale 工具
This commit is contained in:
2026-06-03 15:05:36 +08:00
parent 80adc0e928
commit cbfa18d1d3
63 changed files with 3081 additions and 1038 deletions

View File

@@ -3,14 +3,16 @@ import { ref } from 'vue';
import { useRoute } from 'vue-router';
import api from '../api';
import { ElMessage } from 'element-plus';
import { useAdminLocale } from '../composables/useAdminLocale';
const { t } = useAdminLocale();
const route = useRoute();
const score = ref({ htHome: 0, htAway: 0, ftHome: 0, ftAway: 0 });
const preview = ref<Record<string, unknown> | null>(null);
async function recordScore() {
await api.post(`/admin/matches/${route.params.id}/settlement/score`, score.value);
ElMessage.success('比分已录入');
ElMessage.success(t('msg.score_recorded'));
}
async function previewSettlement() {
@@ -21,21 +23,21 @@ async function previewSettlement() {
async function confirm() {
if (!preview.value?.batch) return;
await api.post(`/admin/settlement/${(preview.value.batch as { id: string }).id}/confirm`);
ElMessage.success('结算已确认');
ElMessage.success(t('msg.settlement_confirmed'));
preview.value = null;
}
</script>
<template>
<div class="page-header">
<h2 class="page-title">赛事结算</h2>
<h2 class="page-title">{{ t('page.settlement.title') }}</h2>
<span class="page-id"># {{ route.params.id }}</span>
</div>
<el-card class="tool-card" shadow="never">
<div class="score-section">
<div class="score-block">
<div class="score-title">半场比分</div>
<div class="score-title">{{ t('settlement.ht_score') }}</div>
<div class="score-inputs">
<el-input-number v-model="score.htHome" :min="0" controls-position="right" style="width: 100px" />
<span class="score-sep"></span>
@@ -43,7 +45,7 @@ async function confirm() {
</div>
</div>
<div class="score-block">
<div class="score-title">全场比分</div>
<div class="score-title">{{ t('settlement.ft_score') }}</div>
<div class="score-inputs">
<el-input-number v-model="score.ftHome" :min="0" controls-position="right" style="width: 100px" />
<span class="score-sep"></span>
@@ -52,34 +54,34 @@ async function confirm() {
</div>
</div>
<div class="action-row">
<el-button @click="recordScore">录入比分</el-button>
<el-button type="primary" @click="previewSettlement">生成结算预览</el-button>
<el-button @click="recordScore">{{ t('settlement.record_score') }}</el-button>
<el-button type="primary" @click="previewSettlement">{{ t('settlement.preview_btn') }}</el-button>
</div>
</el-card>
<el-card v-if="preview" class="preview-card" shadow="never">
<div class="preview-title">结算预览</div>
<div class="preview-title">{{ t('settlement.preview_title') }}</div>
<el-row :gutter="20">
<el-col :span="8">
<div class="pstat">
<div class="pstat-value">{{ preview.singleBetCount }}</div>
<div class="pstat-label">单关注单数</div>
<div class="pstat-label">{{ t('settlement.single_count') }}</div>
</div>
</el-col>
<el-col :span="8">
<div class="pstat">
<div class="pstat-value pstat-green">{{ preview.totalPayout }}</div>
<div class="pstat-label">预计派彩</div>
<div class="pstat-label">{{ t('settlement.est_payout') }}</div>
</div>
</el-col>
<el-col :span="8">
<div class="pstat">
<div class="pstat-value pstat-orange">{{ preview.totalRefund }}</div>
<div class="pstat-label">退款金额</div>
<div class="pstat-label">{{ t('settlement.refund_amount') }}</div>
</div>
</el-col>
</el-row>
<el-button type="success" @click="confirm" style="margin-top: 24px">确认结算</el-button>
<el-button type="success" @click="confirm" style="margin-top: 24px">{{ t('settlement.confirm_btn') }}</el-button>
</el-card>
</template>