feat(admin, i18n): enhance reports, draws, config, and player workflows

This commit is contained in:
2026-06-08 17:41:55 +08:00
parent af982bb9f7
commit 7e65c53732
55 changed files with 1986 additions and 804 deletions

View File

@@ -15,9 +15,9 @@
"risk-cap": "Payout caps"
},
"rulesPlaysTitle": "Play rules",
"rulesOddsTitle": "Odds & rebate",
"rulesOddsDescription": "Odds matrix and rebate rates on one page, sharing the same odds version line.",
"rulesOddsDescriptionShort": "Pick a play on the left, edit odds and rebate on the right, then save and publish.",
"rulesOddsTitle": "Odds & base rebate",
"rulesOddsDescription": "Odds matrix and base rebate are maintained on one page, sharing the same odds version line.",
"rulesOddsDescriptionShort": "Pick a play on the left, edit odds and base rebate on the right. Agent/player rebate is added on top of this base, then save and publish.",
"riskCapTitle": "Risk cap rules"
},
"hub": {
@@ -25,8 +25,8 @@
"description": "Jump to play rules, odds & rebate, jackpot, and risk cap by domain. The sidebar provides direct links; this page is an overview.",
"playsTitle": "Play rules",
"playsDesc": "Play switches, limits, and rule copy",
"oddsTitle": "Odds & rebate",
"oddsDesc": "Odds matrix and rebate rates in one version stream",
"oddsTitle": "Odds & base rebate",
"oddsDesc": "Odds matrix and base rebate in one version stream",
"jackpotTitle": "Jackpot",
"jackpotDesc": "Pool parameters and ledger records",
"riskCapTitle": "Risk cap rules",
@@ -351,6 +351,20 @@
"readOnlyDraftHint": "Current version is read-only. Create a draft first.",
"batchEnabledCount": "{{enabledCount}}/{{total}} enabled",
"noPlayTypes": "No play types",
"filters": {
"sectionTitle": "Filter plays",
"sectionDescription": "Narrow the list first, then use batch switches or row-level edits.",
"keyword": "Search plays",
"keywordPlaceholder": "Filter by play code, display name, or category",
"category": "Category",
"status": "Status",
"allCategories": "All categories",
"allStatuses": "All statuses",
"uncategorized": "Uncategorized",
"reset": "Clear filters",
"empty": "No matching play types",
"groupCount": "{{count}} plays"
},
"actions": {
"enable": "Enable",
"disable": "Disable",
@@ -362,6 +376,13 @@
"en": "English",
"ne": "Nepali"
},
"categories": {
"standard": "Standard",
"attribute": "Attribute",
"position": "Position",
"box": "Box",
"jackpot": "Jackpot"
},
"table": {
"playCode": "Play code",
"category": "Category",
@@ -413,7 +434,7 @@
},
"currentSelection": "Selection: {{category}} / {{play}}",
"playSelectPlaceholder": "Select play type",
"readOnlyBanner": "This version is read-only. Create a draft to edit odds and rebate.",
"readOnlyBanner": "This version is read-only. Create a draft to edit odds and base rebate.",
"table": {
"prizeScope": "Prize scope",
"multiplier": "Odds multiplier"
@@ -452,11 +473,11 @@
"loadingDetails": "Loading details…",
"multiplier": "Multiplier x{{value}} · {{currency}}",
"missingScopeRow": "Missing {{scope}} row. Check seed or version data.",
"rebateRate": "Rebate rate (%)",
"rebateRateHint": "Writes rebate_rate to all prize scopes under this play type.",
"rebateRate": "Base rebate rate (%)",
"rebateRateHint": "This is the platform base rebate. It writes rebate_rate to all prize scopes under this play type; agent/player rebate is added on top of it.",
"placeholders": {
"multiplier": "Enter odds multiplier",
"rebateRate": "Enter rebate rate"
"rebateRate": "Enter base rebate rate"
},
"publishFailed": "Publish failed",
"createDraftSuccess": "Created draft v{{version}}",
@@ -481,33 +502,33 @@
}
},
"rebate": {
"sectionHint": "Rebate rates are stored in the odds version; select or create an odds draft in the section above first.",
"sectionHint": "This section configures the base rebate, which is stored in the odds version; select or create an odds draft in the section above first.",
"lazyLoadHint": "Scroll down to the rebate section to load",
"embeddedVersionHint": "Rebate shares the odds version line—switch versions in the Odds section above.",
"embeddedVersionHint": "Base rebate shares the odds version line—switch versions in the Odds section above.",
"sheetDescription": "Rebate is stored in the odds draft version and shares the same version set as odds.",
"publishLabel": "Publish",
"publishSuccess": "Published odds version with rebate",
"publishFailed": "Publish failed",
"publishDialog": {
"title": "Publish rebate/odds version?",
"description": "After publish, rebate calculation applies to new tickets.",
"title": "Publish base rebate/odds version?",
"description": "After publish, the base rebate applies to new tickets. Agent/player extra rebate is still added on top.",
"confirm": "Confirm publish"
},
"createDraftSuccess": "Created draft v{{version}}",
"createDraftFailed": "Failed to create draft",
"deleteFailed": "Delete failed",
"editingVersion": "Editing version v{{version}} · {{status}}",
"readOnlyHint": "Create a draft before editing rebate.",
"dimensionRatesMixedHint": "Rebate rates within the same dimension (2D/3D/4D) are not identical: the three percentage inputs show the first play (alphabetically) that has the primary prize scope; use the table as the source of truth. Bulk inputs will overwrite all plays in that dimension to one rate.",
"readOnlyHint": "Create a draft before editing base rebate.",
"dimensionRatesMixedHint": "Base rebate within the same dimension (2D/3D/4D) is not identical: the three percentage inputs show the first play (alphabetically) that has the primary prize scope; use the table as the source of truth. Bulk inputs will overwrite all plays in that dimension to one rate.",
"fields": {
"d2": "2D rebate rate (%)",
"d3": "3D rebate rate (%)",
"d4": "4D rebate rate (%)"
"d2": "2D base rebate rate (%)",
"d3": "3D base rebate rate (%)",
"d4": "4D base rebate rate (%)"
},
"placeholders": {
"d2": "Enter 2D rebate",
"d3": "Enter 3D rebate",
"d4": "Enter 4D rebate"
"d2": "Enter 2D base rebate",
"d3": "Enter 3D base rebate",
"d4": "Enter 4D base rebate"
},
"winEnjoy": {
"label": "Deduct rebate on winning payouts",
@@ -527,6 +548,8 @@
"validation": {
"requireAtLeastOne": "At least one cap row is required",
"defaultGreaterThanZero": "Default cap amount must be greater than 0",
"defaultCannotBindDraw": "Default cap cannot be bound to a specific draw",
"specialGreaterThanZero": "Special cap amount must be greater than 0: {{number}}",
"numberMustBe4Digits": "Number must be 4 digits: {{number}}",
"enterValidCapAmount": "Enter a valid cap amount"
},
@@ -547,14 +570,37 @@
"defaultCap": {
"title": "Default cap",
"description": "Numbers without a special cap use this default cap template.",
"fieldLabel": "Cap amount (minor unit)"
"fieldLabel": "Cap amount (major unit)"
},
"specialCaps": {
"title": "Special caps"
"title": "Special caps",
"description": "No draw selected means a global number cap. Selecting a draw makes it a draw-specific cap."
},
"scope": {
"global": "Global number",
"drawId": "Draw ID: {{id}}"
},
"groups": {
"globalTitle": "Global number caps",
"globalDescription": "Long-running caps that are not tied to a specific draw. Use these for normal number-level selling limits.",
"globalEmpty": "No global number caps yet.",
"drawTitle": "Draw-specific caps",
"drawDescription": "Only applies to the selected draw. Use these for temporary tightening or relaxing of a number cap.",
"drawEmpty": "No draw-specific caps yet.",
"count": "{{count}} rows"
},
"summary": {
"defaultCap": "Default cap",
"defaultHint": "Any number without a special rule falls back to this value.",
"globalCaps": "Global number caps",
"globalHint": "Long-running rules that do not change with a single draw.",
"drawCaps": "Draw-specific caps",
"drawHint": "Temporary rules that only apply to selected draws."
},
"loadingDetails": "Loading details…",
"noDetailRows": "No detail rows.",
"table": {
"scope": "Scope",
"number": "Number",
"capAmount": "Cap amount",
"used": "Used",