From 80adc0e928910749cbc647d2bbd88dd4ad0aeac7 Mon Sep 17 00:00:00 2001 From: Mars <3361409208a@gmail.com> Date: Wed, 3 Jun 2026 13:49:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=E7=AE=A1=E7=90=86=E7=AB=AF?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E5=88=86=E9=A1=B5=E3=80=81=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=8F=B0=E5=9B=BE=E8=A1=A8=E4=B8=8E=E8=B5=9B=E4=BA=8B=E5=AF=BC?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 玩家/代理/赛事/注单/审计列表分页,默认每页 10 条,无页面滚动条布局 - ECharts 控制台概览、注单管理中文化与列宽优化 - zhibo 赛事字段迁移与导入,玩家编辑可改所属代理 - 管理端 API 分页与 dashboard 统计接口 Co-authored-by: Cursor --- apps/admin/package.json | 2 + apps/admin/src/App.vue | 272 ++++++++ apps/admin/src/components/RobotVerify.vue | 121 ++++ .../src/components/dashboard/EChartPanel.vue | 44 ++ .../src/components/dashboard/echarts-setup.ts | 22 + apps/admin/src/layouts/ManageLayout.vue | 277 ++++++-- apps/admin/src/utils/bet-labels.ts | 60 ++ apps/admin/src/utils/dashboard-charts.ts | 290 +++++++++ apps/admin/src/utils/format-amount.ts | 43 ++ apps/admin/src/views/Agents.vue | 489 ++++++++++++-- apps/admin/src/views/Audit.vue | 97 ++- apps/admin/src/views/Bets.vue | 325 +++++++++- apps/admin/src/views/Cashback.vue | 64 +- apps/admin/src/views/Dashboard.vue | 332 +++++++++- apps/admin/src/views/Login.vue | 232 ++++++- apps/admin/src/views/Matches.vue | 489 +++++++++++++- apps/admin/src/views/Settlement.vue | 114 +++- apps/admin/src/views/Users.vue | 595 +++++++++++++++++- apps/admin/src/views/agent-form.ts | 96 +++ apps/admin/src/views/agent/Bets.vue | 112 +++- apps/admin/src/views/agent/Dashboard.vue | 93 ++- apps/admin/src/views/agent/Players.vue | 118 +++- apps/admin/src/views/agent/SubAgents.vue | 70 ++- apps/admin/src/views/bet-form.ts | 40 ++ apps/admin/src/views/dashboard-types.ts | 71 +++ apps/admin/src/views/match-form.ts | 78 +++ apps/admin/src/views/user-form.ts | 120 ++++ .../migration.sql | 21 + apps/api/prisma/schema.prisma | 58 +- .../admin/admin-dashboard.service.ts | 209 ++++++ .../applications/admin/admin.controller.ts | 438 +++++++++++-- .../src/applications/admin/admin.module.ts | 2 + .../agent/agent-portal.controller.ts | 14 +- apps/api/src/domains/agent/agents.service.ts | 300 ++++++++- apps/api/src/domains/betting/bets.service.ts | 156 ++++- .../src/domains/catalog/matches.service.ts | 402 +++++++++++- .../src/domains/catalog/zhibo-match.mapper.ts | 64 ++ .../src/domains/catalog/zhibo-match.types.ts | 67 ++ apps/api/src/domains/identity/users.module.ts | 2 + .../api/src/domains/identity/users.service.ts | 233 ++++++- .../domains/operations/audit/audit.service.ts | 2 +- .../src/assets/images/足球赛事下注背景框.png | Bin 0 -> 161266 bytes .../components/outright/OutrightBetModal.vue | 390 +++++++++--- apps/player/src/router/index.js | 2 + pnpm-lock.yaml | 37 ++ 45 files changed, 6564 insertions(+), 499 deletions(-) create mode 100644 apps/admin/src/components/RobotVerify.vue create mode 100644 apps/admin/src/components/dashboard/EChartPanel.vue create mode 100644 apps/admin/src/components/dashboard/echarts-setup.ts create mode 100644 apps/admin/src/utils/bet-labels.ts create mode 100644 apps/admin/src/utils/dashboard-charts.ts create mode 100644 apps/admin/src/utils/format-amount.ts create mode 100644 apps/admin/src/views/agent-form.ts create mode 100644 apps/admin/src/views/bet-form.ts create mode 100644 apps/admin/src/views/dashboard-types.ts create mode 100644 apps/admin/src/views/match-form.ts create mode 100644 apps/admin/src/views/user-form.ts create mode 100644 apps/api/prisma/migrations/20260603102323_zhibo_match_fields/migration.sql create mode 100644 apps/api/src/applications/admin/admin-dashboard.service.ts create mode 100644 apps/api/src/domains/catalog/zhibo-match.mapper.ts create mode 100644 apps/api/src/domains/catalog/zhibo-match.types.ts create mode 100644 apps/player/src/assets/images/足球赛事下注背景框.png create mode 100644 apps/player/src/router/index.js diff --git a/apps/admin/package.json b/apps/admin/package.json index 686b7ba..c3c31ea 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -11,8 +11,10 @@ }, "dependencies": { "axios": "^1.7.9", + "echarts": "^6.1.0", "element-plus": "^2.9.3", "vue": "^3.5.13", + "vue-echarts": "^8.0.1", "vue-router": "^4.5.0" }, "devDependencies": { diff --git a/apps/admin/src/App.vue b/apps/admin/src/App.vue index e571fd1..a49b14e 100644 --- a/apps/admin/src/App.vue +++ b/apps/admin/src/App.vue @@ -2,3 +2,275 @@ import { RouterView } from 'vue-router'; + + diff --git a/apps/admin/src/components/RobotVerify.vue b/apps/admin/src/components/RobotVerify.vue new file mode 100644 index 0000000..bed4aff --- /dev/null +++ b/apps/admin/src/components/RobotVerify.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/apps/admin/src/components/dashboard/EChartPanel.vue b/apps/admin/src/components/dashboard/EChartPanel.vue new file mode 100644 index 0000000..e441a47 --- /dev/null +++ b/apps/admin/src/components/dashboard/EChartPanel.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/apps/admin/src/components/dashboard/echarts-setup.ts b/apps/admin/src/components/dashboard/echarts-setup.ts new file mode 100644 index 0000000..9d5f806 --- /dev/null +++ b/apps/admin/src/components/dashboard/echarts-setup.ts @@ -0,0 +1,22 @@ +import { use } from 'echarts/core'; +import { BarChart, LineChart, PieChart } from 'echarts/charts'; +import { + GridComponent, + TooltipComponent, + LegendComponent, + TitleComponent, + GraphicComponent, +} from 'echarts/components'; +import { CanvasRenderer } from 'echarts/renderers'; + +use([ + CanvasRenderer, + BarChart, + LineChart, + PieChart, + GridComponent, + TooltipComponent, + LegendComponent, + TitleComponent, + GraphicComponent, +]); diff --git a/apps/admin/src/layouts/ManageLayout.vue b/apps/admin/src/layouts/ManageLayout.vue index 4f88fb2..33e4ea0 100644 --- a/apps/admin/src/layouts/ManageLayout.vue +++ b/apps/admin/src/layouts/ManageLayout.vue @@ -8,24 +8,32 @@ const router = useRouter(); const auth = useAuthStore(); const adminMenus = [ - { path: '/', label: '控制台' }, - { path: '/users', label: '玩家管理' }, - { path: '/agents', label: '代理管理' }, - { path: '/matches', label: '赛事管理' }, - { path: '/bets', label: '注单管理' }, - { path: '/cashback', label: '返水管理' }, - { path: '/audit', label: '操作日志' }, + { path: '/', label: '控制台' }, + { path: '/users', label: '玩家管理' }, + { path: '/agents', label: '代理管理' }, + { path: '/matches', label: '赛事管理' }, + { path: '/bets', label: '注单管理' }, + { path: '/cashback', label: '返水管理' }, + { path: '/audit', label: '操作日志' }, ]; const agentMenus = [ - { path: '/', label: '概览' }, - { path: '/my-players', label: '直属玩家' }, - { path: '/sub-agents', label: '下级代理' }, - { path: '/my-bets', label: '注单查询' }, + { path: '/', label: '概览' }, + { path: '/my-players', label: '直属玩家' }, + { path: '/sub-agents', label: '下级代理' }, + { path: '/my-bets', label: '注单查询' }, ]; const menus = computed(() => (auth.isAdmin.value ? adminMenus : agentMenus)); +const currentLabel = computed(() => + menus.value.find(m => m.path === route.path)?.label ?? '' +); + +const userInitial = computed(() => + (auth.user?.username ?? '').charAt(0).toUpperCase() +); + function logout() { auth.logout(); router.push('/login'); @@ -33,33 +41,224 @@ function logout() { + + diff --git a/apps/admin/src/utils/bet-labels.ts b/apps/admin/src/utils/bet-labels.ts new file mode 100644 index 0000000..7ea2f23 --- /dev/null +++ b/apps/admin/src/utils/bet-labels.ts @@ -0,0 +1,60 @@ +export type BetTagType = '' | 'info' | 'success' | 'warning' | 'danger'; + +const STATUS_LABELS: Record = { + PENDING: '待结算', + WON: '已赢', + LOST: '已输', + VOID: '作废', + REFUNDED: '已退款', +}; + +const STATUS_TAG: Record = { + PENDING: 'warning', + WON: 'success', + LOST: 'danger', + VOID: 'info', + REFUNDED: 'info', +}; + +const TYPE_LABELS: Record = { + SINGLE: '单关', + PARLAY: '串关', +}; + +export function betStatusLabel(status: string) { + return STATUS_LABELS[status] ?? status; +} + +export function betStatusTagType(status: string): BetTagType { + return STATUS_TAG[status] ?? 'info'; +} + +export function betTypeLabel(betType: string) { + return TYPE_LABELS[betType] ?? betType; +} + +const SETTLEMENT_LABELS: Record = { + PENDING: '待结算', + SETTLED: '已结算', + VOID: '已作废', +}; + +export function betSettlementLabel(v: string | null | undefined) { + if (!v) return '—'; + return SETTLEMENT_LABELS[v] ?? v; +} + +export const BET_STATUS_OPTIONS = [ + { value: '', label: '全部' }, + { value: 'PENDING', label: '待结算' }, + { value: 'WON', label: '已赢' }, + { value: 'LOST', label: '已输' }, + { value: 'VOID', label: '作废' }, + { value: 'REFUNDED', label: '已退款' }, +]; + +export const BET_TYPE_OPTIONS = [ + { value: '', label: '全部' }, + { value: 'SINGLE', label: '单关' }, + { value: 'PARLAY', label: '串关' }, +]; diff --git a/apps/admin/src/utils/dashboard-charts.ts b/apps/admin/src/utils/dashboard-charts.ts new file mode 100644 index 0000000..a00a29e --- /dev/null +++ b/apps/admin/src/utils/dashboard-charts.ts @@ -0,0 +1,290 @@ +import type { EChartsOption } from 'echarts'; +import { formatAmount, formatAmountFull } from './format-amount'; + +const tooltipBase = { + backgroundColor: '#141414', + borderColor: '#2a2a2a', + textStyle: { color: '#e0e0e0', fontSize: 12 }, +}; + +const axisLabel = { color: '#888', fontSize: 11 }; +const splitLine = { lineStyle: { color: '#252525' } }; + +export type ChartSeries = { name: string; color: string; values: number[] }; +export type PieSegment = { label: string; value: number; color: string }; + +export function buildBarChartOption( + labels: string[], + series: ChartSeries[], + opts?: { amountAxis?: boolean }, +): EChartsOption { + const amountAxis = opts?.amountAxis !== false; + return { + backgroundColor: 'transparent', + color: series.map((s) => s.color), + tooltip: { + ...tooltipBase, + trigger: 'axis', + axisPointer: { type: 'shadow' }, + valueFormatter: (v) => + amountAxis ? formatAmountFull(Number(v)) : fmtCount(Number(v)), + }, + legend: { + bottom: 0, + itemWidth: 10, + itemHeight: 10, + textStyle: { color: '#999', fontSize: 11 }, + }, + grid: { left: 52, right: 12, top: 20, bottom: 48 }, + xAxis: { + type: 'category', + data: labels, + axisLabel, + axisLine: { lineStyle: { color: '#333' } }, + axisTick: { show: false }, + }, + yAxis: { + type: 'value', + axisLabel: { + ...axisLabel, + formatter: (v: number) => (amountAxis ? formatAmount(v) : fmtCount(v)), + }, + splitLine, + }, + series: series.map((s) => ({ + name: s.name, + type: 'bar', + data: s.values, + itemStyle: { color: s.color, borderRadius: [4, 4, 0, 0] }, + barMaxWidth: 22, + emphasis: { focus: 'series' }, + })), + }; +} + +export function buildMultiLineChartOption( + labels: string[], + series: ChartSeries[], +): EChartsOption { + return { + backgroundColor: 'transparent', + color: series.map((s) => s.color), + tooltip: { + ...tooltipBase, + trigger: 'axis', + valueFormatter: (v) => formatAmountFull(Number(v)), + }, + legend: { + bottom: 0, + itemWidth: 10, + itemHeight: 10, + textStyle: { color: '#999', fontSize: 11 }, + }, + grid: { left: 52, right: 12, top: 20, bottom: 48 }, + xAxis: { + type: 'category', + data: labels, + boundaryGap: false, + axisLabel, + axisLine: { lineStyle: { color: '#333' } }, + }, + yAxis: { + type: 'value', + axisLabel: { ...axisLabel, formatter: (v: number) => formatAmount(v) }, + splitLine, + }, + series: series.map((s) => ({ + name: s.name, + type: 'line', + smooth: true, + symbol: 'circle', + symbolSize: 6, + data: s.values, + itemStyle: { color: s.color }, + lineStyle: { color: s.color, width: 2 }, + areaStyle: { color: s.color, opacity: 0.12 }, + })), + }; +} + +export function buildPieChartOption( + title: string, + segments: PieSegment[], +): EChartsOption { + const data = segments.map((s) => ({ + name: s.label, + value: s.value, + itemStyle: { color: s.color }, + })); + + return { + backgroundColor: 'transparent', + tooltip: { + ...tooltipBase, + trigger: 'item', + formatter: '{b}:{c}({d}%)', + }, + legend: { + orient: 'vertical', + right: 4, + top: 'middle', + itemWidth: 8, + itemHeight: 8, + textStyle: { color: '#999', fontSize: 11 }, + }, + series: [ + { + name: title, + type: 'pie', + radius: ['42%', '68%'], + center: ['36%', '50%'], + avoidLabelOverlap: true, + itemStyle: { borderRadius: 4, borderColor: '#111', borderWidth: 2 }, + label: { + show: segments.length > 0, + color: '#bbb', + fontSize: 11, + formatter: '{b}\n{d}%', + }, + labelLine: { lineStyle: { color: '#444' } }, + emphasis: { + label: { fontSize: 12, fontWeight: 'bold' }, + scaleSize: 6, + }, + data: data.length ? data : [{ name: '暂无数据', value: 1, itemStyle: { color: '#333' } }], + }, + ], + }; +} + +function fmtCount(v: number) { + return v.toLocaleString('zh-CN', { maximumFractionDigits: 0 }); +} + +/** 7 日金额折线 + 注单柱(双 Y 轴),一图看清趋势 */ +export function buildCombinedTrendOption( + labels: string[], + amountSeries: ChartSeries[], + betCounts: number[], +): EChartsOption { + return { + backgroundColor: 'transparent', + color: [...amountSeries.map((s) => s.color), '#fb923c'], + tooltip: { + ...tooltipBase, + trigger: 'axis', + formatter(params) { + const items = Array.isArray(params) ? params : [params]; + return items + .map((p) => { + const v = Number(p.value ?? 0); + const isCount = p.seriesName === '注单笔数'; + const val = isCount ? `${fmtCount(v)} 笔` : formatAmountFull(v); + return `${p.marker ?? ''}${p.seriesName}:${val}`; + }) + .join('
'); + }, + }, + legend: { + top: 0, + itemWidth: 10, + itemHeight: 10, + textStyle: { color: '#999', fontSize: 11 }, + }, + grid: { left: 56, right: 48, top: 36, bottom: 28 }, + xAxis: { + type: 'category', + data: labels, + boundaryGap: true, + axisLabel, + axisLine: { lineStyle: { color: '#333' } }, + }, + yAxis: [ + { + type: 'value', + name: '金额', + nameTextStyle: { color: '#666', fontSize: 10 }, + axisLabel: { ...axisLabel, formatter: (v: number) => formatAmount(v) }, + splitLine, + }, + { + type: 'value', + name: '笔数', + nameTextStyle: { color: '#666', fontSize: 10 }, + axisLabel: { ...axisLabel, formatter: (v: number) => fmtCount(v) }, + splitLine: { show: false }, + }, + ], + series: [ + ...amountSeries.map((s) => ({ + name: s.name, + type: 'line' as const, + yAxisIndex: 0, + smooth: true, + symbol: 'circle', + symbolSize: 5, + data: s.values, + itemStyle: { color: s.color }, + lineStyle: { color: s.color, width: 2 }, + })), + { + name: '注单笔数', + type: 'bar', + yAxisIndex: 1, + data: betCounts, + barMaxWidth: 14, + itemStyle: { color: 'rgba(251, 146, 60, 0.45)', borderRadius: [3, 3, 0, 0] }, + }, + ], + }; +} + +/** 三个饼图并排,占一张图 */ +export function buildTriplePieOption( + blocks: { title: string; segments: PieSegment[] }[], +): EChartsOption { + const slots = [ + { center: ['18%', '58%'] as [string, string], titleLeft: '14%' }, + { center: ['50%', '58%'] as [string, string], titleLeft: '46%' }, + { center: ['82%', '58%'] as [string, string], titleLeft: '78%' }, + ]; + + return { + backgroundColor: 'transparent', + tooltip: { + ...tooltipBase, + trigger: 'item', + formatter: '{b}:{c}({d}%)', + }, + graphic: blocks.map((b, i) => ({ + type: 'text' as const, + left: slots[i]?.titleLeft ?? '50%', + top: '6%', + style: { + text: b.title, + fill: '#aaa', + fontSize: 12, + fontWeight: 600, + textAlign: 'center', + }, + })), + series: blocks.map((b, i) => { + const data = b.segments.map((s) => ({ + name: s.label, + value: s.value, + itemStyle: { color: s.color }, + })); + return { + name: b.title, + type: 'pie' as const, + radius: ['32%', '48%'], + center: slots[i]?.center ?? ['50%', '55%'], + label: { show: false }, + labelLine: { show: false }, + data: data.length + ? data + : [{ name: '暂无', value: 1, itemStyle: { color: '#333' } }], + }; + }), + }; +} diff --git a/apps/admin/src/utils/format-amount.ts b/apps/admin/src/utils/format-amount.ts new file mode 100644 index 0000000..3dfe808 --- /dev/null +++ b/apps/admin/src/utils/format-amount.ts @@ -0,0 +1,43 @@ +/** 完整数字(悬停提示、详情对照) */ +export function formatAmountFull(value: string | number | null | undefined): string { + const n = Number(value); + if (!Number.isFinite(n)) return '—'; + return n.toLocaleString('zh-CN', { maximumFractionDigits: 4 }); +} + +function unitPart(abs: number, divisor: number, maxDecimals: number): string { + return (abs / divisor).toLocaleString('zh-CN', { + minimumFractionDigits: 0, + maximumFractionDigits: maxDecimals, + }); +} + +/** + * 金额展示:≥1万用「万」,≥1亿用「亿」,避免表格撑破布局 + */ +export function formatAmount( + value: string | number | null | undefined, + maxDecimals = 2, +): string { + const n = Number(value); + if (!Number.isFinite(n)) return '—'; + + const sign = n < 0 ? '-' : ''; + const abs = Math.abs(n); + + if (abs >= 1e8) { + return `${sign}${unitPart(abs, 1e8, maxDecimals)}亿`; + } + if (abs >= 1e4) { + return `${sign}${unitPart(abs, 1e4, maxDecimals)}万`; + } + + return n.toLocaleString('zh-CN', { + minimumFractionDigits: 0, + maximumFractionDigits: maxDecimals, + }); +} + +export function shouldCompactAmount(value: string | number | null | undefined): boolean { + return Math.abs(Number(value) || 0) >= 1e4; +} diff --git a/apps/admin/src/views/Agents.vue b/apps/admin/src/views/Agents.vue index 9131df1..aa488b0 100644 --- a/apps/admin/src/views/Agents.vue +++ b/apps/admin/src/views/Agents.vue @@ -2,51 +2,468 @@ import { ref, onMounted } from 'vue'; import api from '../api'; import { ElMessage } from 'element-plus'; +import { + emptyAgentCreateForm, + emptyAgentEditForm, + editFormFromAgentDetail, + buildCreateAgentPayload, + type AgentRow, + type AgentDetail, + type AgentCreateForm, + type AgentEditForm, +} from './agent-form'; +import { + formatAmount, + formatAmountFull, + shouldCompactAmount as shouldCompact, +} from '../utils/format-amount'; -const agents = ref([]); -const form = ref({ username: '', password: 'Agent@123', creditLimit: 50000 }); +const agents = ref([]); +const total = ref(0); +const page = ref(1); +const pageSize = ref(10); +const keyword = ref(''); + +function creditLine(row: AgentRow) { + return `${formatAmount(row.creditLimit)} / ${formatAmount(row.usedCredit)} / ${formatAmount(row.availableCredit)}`; +} + +function creditLineFull(row: AgentRow) { + return `${formatAmountFull(row.creditLimit)} / ${formatAmountFull(row.usedCredit)} / ${formatAmountFull(row.availableCredit)}`; +} + +const createVisible = ref(false); +const editVisible = ref(false); +const detailVisible = ref(false); +const creditVisible = ref(false); +const createLoading = ref(false); +const editLoading = ref(false); +const creditLoading = ref(false); + +const createForm = ref(emptyAgentCreateForm()); +const editForm = ref(emptyAgentEditForm()); +const detail = ref(null); +const editingId = ref(''); + +const creditForm = ref({ amount: 10000, remark: '' }); onMounted(load); async function load() { - const { data } = await api.get('/admin/agents'); - agents.value = data.data; -} - -async function create() { - await api.post('/admin/agents', form.value); - ElMessage.success('创建成功'); - load(); -} - -async function adjustCredit(agent: { userId: string }, amount: number) { - await api.post(`/admin/agents/${agent.userId}/credit`, { - amount, - requestId: `credit-${Date.now()}`, + const { data } = await api.get('/admin/agents', { + params: { + page: page.value, + pageSize: pageSize.value, + keyword: keyword.value.trim() || undefined, + }, }); - ElMessage.success('额度已调整'); + agents.value = data.data.items as AgentRow[]; + total.value = data.data.total; +} + +function onPageChange(p: number) { + page.value = p; load(); } + +function onSizeChange(size: number) { + pageSize.value = size; + page.value = 1; + load(); +} + +function openCreate() { + createForm.value = emptyAgentCreateForm(); + createVisible.value = true; +} + +async function openDetail(userId: string) { + const { data } = await api.get(`/admin/agents/${userId}`); + detail.value = data.data as AgentDetail; + detailVisible.value = true; +} + +async function openEdit(userId: string) { + const { data } = await api.get(`/admin/agents/${userId}`); + const d = data.data as AgentDetail; + editingId.value = userId; + editForm.value = editFormFromAgentDetail(d); + editVisible.value = true; +} + +function openCredit(row: AgentRow) { + editingId.value = row.userId; + creditForm.value = { amount: 10000, remark: '' }; + creditVisible.value = true; +} + +async function submitCreate() { + let payload: ReturnType; + try { + payload = buildCreateAgentPayload(createForm.value); + } catch (e) { + ElMessage.warning(e instanceof Error ? e.message : '请检查表单'); + return; + } + createLoading.value = true; + try { + await api.post('/admin/agents', payload); + ElMessage.success('一级代理已创建'); + createVisible.value = false; + load(); + } catch (e: unknown) { + const err = e as { response?: { data?: { error?: string } } }; + ElMessage.error(err.response?.data?.error ?? '创建失败'); + } finally { + createLoading.value = false; + } +} + +async function submitEdit() { + editLoading.value = true; + try { + await api.put(`/admin/agents/${editingId.value}`, { + status: editForm.value.status, + phone: editForm.value.phone.trim() || undefined, + email: editForm.value.email.trim() || undefined, + cashbackRate: editForm.value.cashbackRate, + }); + ElMessage.success('已保存'); + editVisible.value = false; + load(); + } catch (e: unknown) { + const err = e as { response?: { data?: { error?: string } } }; + ElMessage.error(err.response?.data?.error ?? '保存失败'); + } finally { + editLoading.value = false; + } +} + +async function submitCredit() { + if (creditForm.value.amount === 0) { + ElMessage.warning('调整金额不能为 0'); + return; + } + creditLoading.value = true; + try { + await api.post(`/admin/agents/${editingId.value}/credit`, { + amount: creditForm.value.amount, + requestId: `credit-${editingId.value}-${Date.now()}`, + remark: creditForm.value.remark || undefined, + }); + ElMessage.success('授信已调整'); + creditVisible.value = false; + load(); + } catch (e: unknown) { + const err = e as { response?: { data?: { error?: string } } }; + ElMessage.error(err.response?.data?.error ?? '调整失败'); + } finally { + creditLoading.value = false; + } +} + +function formatTime(v: string) { + if (!v) return '—'; + return new Date(v).toLocaleString('zh-CN'); +} + +function statusTagType(s: string) { + return s === 'ACTIVE' ? 'success' : 'warning'; +} + +function statusLabel(s: string) { + return s === 'ACTIVE' ? '正常' : s === 'SUSPENDED' ? '停用' : s; +} + +function creditTypeLabel(t: string) { + if (t === 'CREDIT_INCREASE') return '增加'; + if (t === 'CREDIT_DECREASE') return '减少'; + return t; +} + + diff --git a/apps/admin/src/views/Audit.vue b/apps/admin/src/views/Audit.vue index f738b7c..7995773 100644 --- a/apps/admin/src/views/Audit.vue +++ b/apps/admin/src/views/Audit.vue @@ -3,21 +3,94 @@ import { ref, onMounted } from 'vue'; import api from '../api'; const logs = ref([]); +const total = ref(0); +const page = ref(1); +const pageSize = ref(10); +const filterModule = ref(''); -onMounted(async () => { - const { data } = await api.get('/admin/audit-logs'); +onMounted(load); + +async function load() { + const { data } = await api.get('/admin/audit-logs', { + params: { + page: page.value, + pageSize: pageSize.value, + module: filterModule.value || undefined, + }, + }); logs.value = data.data.items; -}); + total.value = data.data.total; +} + +function onPageChange(p: number) { + page.value = p; + load(); +} + +function onSizeChange(size: number) { + pageSize.value = size; + page.value = 1; + load(); +} + + diff --git a/apps/admin/src/views/Bets.vue b/apps/admin/src/views/Bets.vue index 6997ac8..8fbcaa6 100644 --- a/apps/admin/src/views/Bets.vue +++ b/apps/admin/src/views/Bets.vue @@ -1,24 +1,319 @@ + + diff --git a/apps/admin/src/views/Cashback.vue b/apps/admin/src/views/Cashback.vue index 1a8f5e3..07a5ce2 100644 --- a/apps/admin/src/views/Cashback.vue +++ b/apps/admin/src/views/Cashback.vue @@ -21,19 +21,63 @@ async function confirm() { if (!preview.value?.batch) return; await api.post(`/admin/cashbacks/${(preview.value.batch as { id: string }).id}/confirm`); ElMessage.success('返水已发放'); + preview.value = null; } + + diff --git a/apps/admin/src/views/Dashboard.vue b/apps/admin/src/views/Dashboard.vue index 481ff89..ad82e27 100644 --- a/apps/admin/src/views/Dashboard.vue +++ b/apps/admin/src/views/Dashboard.vue @@ -1,21 +1,329 @@ + + diff --git a/apps/admin/src/views/Login.vue b/apps/admin/src/views/Login.vue index 0ca10b4..70a761e 100644 --- a/apps/admin/src/views/Login.vue +++ b/apps/admin/src/views/Login.vue @@ -4,6 +4,8 @@ import { useRoute, useRouter } from 'vue-router'; import api from '../api'; import { ElMessage } from 'element-plus'; import { useAuthStore, type StaffUser } from '../stores/auth'; +import RobotVerify from '../components/RobotVerify.vue'; +import bgImage from '../assets/images/bg.png'; const router = useRouter(); const route = useRoute(); @@ -11,17 +13,37 @@ const auth = useAuthStore(); const form = ref({ username: '', password: '' }); const loading = ref(false); +const captchaRef = ref | null>(null); + +async function quickLogin(username: string, password: string) { + loading.value = true; + try { + const { data } = await api.post('/manage/auth/login', { username, password }); + const payload = data.data as { token: string; user: StaffUser }; + auth.setSession(payload.token, payload.user); + router.push((route.query.redirect as string) || '/'); + } catch { + ElMessage.error('快速登录失败'); + } finally { + loading.value = false; + } +} async function login() { + if (!captchaRef.value?.validate()) { + ElMessage.error('验证码错误,请重试'); + captchaRef.value?.refresh(); + return; + } loading.value = true; try { const { data } = await api.post('/manage/auth/login', form.value); const payload = data.data as { token: string; user: StaffUser }; auth.setSession(payload.token, payload.user); - const redirect = (route.query.redirect as string) || '/'; - router.push(redirect); + router.push((route.query.redirect as string) || '/'); } catch { ElMessage.error('登录失败,请检查账号与密码'); + captchaRef.value?.refresh(); } finally { loading.value = false; } @@ -29,28 +51,188 @@ async function login() { + + diff --git a/apps/admin/src/views/Matches.vue b/apps/admin/src/views/Matches.vue index fd74902..0fa408d 100644 --- a/apps/admin/src/views/Matches.vue +++ b/apps/admin/src/views/Matches.vue @@ -1,31 +1,185 @@ + + diff --git a/apps/admin/src/views/Settlement.vue b/apps/admin/src/views/Settlement.vue index 43092c3..f9fdb77 100644 --- a/apps/admin/src/views/Settlement.vue +++ b/apps/admin/src/views/Settlement.vue @@ -1,5 +1,5 @@ + + diff --git a/apps/admin/src/views/Users.vue b/apps/admin/src/views/Users.vue index fde65bb..1fc3707 100644 --- a/apps/admin/src/views/Users.vue +++ b/apps/admin/src/views/Users.vue @@ -1,38 +1,585 @@ + + + + diff --git a/apps/admin/src/views/agent-form.ts b/apps/admin/src/views/agent-form.ts new file mode 100644 index 0000000..0c82b7a --- /dev/null +++ b/apps/admin/src/views/agent-form.ts @@ -0,0 +1,96 @@ +export interface AgentCreateForm { + username: string; + password: string; + confirmPassword: string; + creditLimit: number; + cashbackRate: number; + phone: string; + email: string; +} + +export interface AgentEditForm { + status: string; + phone: string; + email: string; + cashbackRate: number; +} + +export interface AgentRow { + userId: string; + username: string; + userStatus: string; + level: number; + status: string; + creditLimit: string; + usedCredit: string; + availableCredit: string; + directPlayerCount: number; + cashbackRate: string; + phone: string | null; + email: string | null; + locale: string; + createdAt: string; +} + +export interface AgentDetail extends AgentRow { + parentAgentId: string | null; + parentUsername: string | null; + directPlayerLiability: string; + childAgentExposure: string; + lastLoginAt: string | null; + updatedAt: string; + recentCreditTransactions: { + id: string; + transactionType: string; + amount: string; + creditBefore: string; + creditAfter: string; + remark: string | null; + createdAt: string; + }[]; +} + +export function emptyAgentCreateForm(): AgentCreateForm { + return { + username: '', + password: 'Agent@123', + confirmPassword: 'Agent@123', + creditLimit: 50000, + cashbackRate: 0, + phone: '', + email: '', + }; +} + +export function emptyAgentEditForm(): AgentEditForm { + return { + status: 'ACTIVE', + phone: '', + email: '', + cashbackRate: 0, + }; +} + +export function editFormFromAgentDetail(d: AgentDetail): AgentEditForm { + return { + status: d.status, + phone: d.phone ?? '', + email: d.email ?? '', + cashbackRate: Number(d.cashbackRate), + }; +} + +export function buildCreateAgentPayload(form: AgentCreateForm) { + if (!form.username.trim()) throw new Error('请填写用户名'); + if (form.password.length < 8) throw new Error('密码至少 8 位'); + if (form.password !== form.confirmPassword) throw new Error('两次密码不一致'); + if (form.creditLimit < 0) throw new Error('授信额度不能为负'); + return { + username: form.username.trim(), + password: form.password, + creditLimit: form.creditLimit, + cashbackRate: form.cashbackRate, + phone: form.phone.trim() || undefined, + email: form.email.trim() || undefined, + }; +} diff --git a/apps/admin/src/views/agent/Bets.vue b/apps/admin/src/views/agent/Bets.vue index a39e110..8c5e580 100644 --- a/apps/admin/src/views/agent/Bets.vue +++ b/apps/admin/src/views/agent/Bets.vue @@ -1,25 +1,105 @@ + + diff --git a/apps/admin/src/views/agent/Dashboard.vue b/apps/admin/src/views/agent/Dashboard.vue index 0e5415a..ddc10ef 100644 --- a/apps/admin/src/views/agent/Dashboard.vue +++ b/apps/admin/src/views/agent/Dashboard.vue @@ -1,6 +1,7 @@ + + diff --git a/apps/admin/src/views/agent/Players.vue b/apps/admin/src/views/agent/Players.vue index 351d1b7..b873d80 100644 --- a/apps/admin/src/views/agent/Players.vue +++ b/apps/admin/src/views/agent/Players.vue @@ -2,6 +2,7 @@ import { ref, onMounted } from 'vue'; import api from '../../api'; import { ElMessage } from 'element-plus'; +import { formatAmount, formatAmountFull } from '../../utils/format-amount'; const players = ref([]); const form = ref({ username: '', password: 'Player@123' }); @@ -41,28 +42,97 @@ async function withdraw(playerId: string, amount: number) { + + diff --git a/apps/admin/src/views/agent/SubAgents.vue b/apps/admin/src/views/agent/SubAgents.vue index f326f79..14f408c 100644 --- a/apps/admin/src/views/agent/SubAgents.vue +++ b/apps/admin/src/views/agent/SubAgents.vue @@ -2,6 +2,7 @@ import { ref, onMounted } from 'vue'; import api from '../../api'; import { ElMessage } from 'element-plus'; +import { formatAmount, formatAmountFull } from '../../utils/format-amount'; const agents = ref([]); const form = ref({ username: '', password: 'Agent@123', creditLimit: 10000 }); @@ -21,19 +22,58 @@ async function create() { + + diff --git a/apps/admin/src/views/bet-form.ts b/apps/admin/src/views/bet-form.ts new file mode 100644 index 0000000..5f4faa7 --- /dev/null +++ b/apps/admin/src/views/bet-form.ts @@ -0,0 +1,40 @@ +export interface BetListRow { + id: string; + betNo: string; + userId: string; + username: string; + parentUsername: string | null; + agentId: string | null; + betType: string; + stake: string; + totalOdds: string | null; + potentialReturn: string | null; + actualReturn: string; + status: string; + settlementStatus: string | null; + currency: string; + placedAt: string; + settledAt: string | null; + selectionCount: number; +} + +export interface BetSelectionDetail { + id: string; + matchId: string | null; + marketType: string; + period: string | null; + selectionName: string; + handicapLine: string | null; + totalLine: string | null; + odds: string; + resultStatus: string | null; + effectiveOdds: string | null; + sortOrder: number; +} + +export interface BetDetail extends BetListRow { + requestId: string; + createdAt: string; + updatedAt: string; + selections: BetSelectionDetail[]; +} diff --git a/apps/admin/src/views/dashboard-types.ts b/apps/admin/src/views/dashboard-types.ts new file mode 100644 index 0000000..89dd6a7 --- /dev/null +++ b/apps/admin/src/views/dashboard-types.ts @@ -0,0 +1,71 @@ +export interface DashboardTrendDay { + date: string; + label: string; + betCount: number; + stake: string; + payout: string; + ggr: string; +} + +export interface AdminDashboard { + generatedAt: string; + trend7d: DashboardTrendDay[]; + today: { + betCount: number; + stake: string; + payout: string; + ggr: string; + newPlayers: number; + }; + yesterday: { + betCount: number; + stake: string; + payout: string; + ggr: string; + }; + users: { + playersTotal: number; + playersActive: number; + playersSuspended: number; + playersDirect: number; + agentsTotal: number; + agentsActive: number; + }; + wallets: { + totalAvailable: string; + totalFrozen: string; + playerWalletCount: number; + }; + agents: { + totalCreditLimit: string; + totalUsedCredit: string; + totalAvailableCredit: string; + }; + matches: { + total: number; + draft: number; + published: number; + closed: number; + cancelled: number; + pendingSettlement: number; + settled: number; + }; + bets: { + pendingTotal: number; + todayByStatus: Record; + }; + recentBets: { + betNo: string; + username: string; + stake: string; + status: string; + placedAt: string; + }[]; + recentPlayers: { + id: string; + username: string; + status: string; + parentUsername: string | null; + createdAt: string; + }[]; +} diff --git a/apps/admin/src/views/match-form.ts b/apps/admin/src/views/match-form.ts new file mode 100644 index 0000000..705e01b --- /dev/null +++ b/apps/admin/src/views/match-form.ts @@ -0,0 +1,78 @@ +/** 后台手动新增赛事(投注平台最小字段) */ + +export interface MatchCreateForm { + leagueEn: string; + leagueZh: string; + startTime: string; + homeTeamZh: string; + homeTeamEn: string; + awayTeamZh: string; + awayTeamEn: string; + isHot: boolean; +} + +export function emptyMatchForm(): MatchCreateForm { + return { + leagueEn: 'FIFA World Cup 2026', + leagueZh: '2026 世界杯', + startTime: '', + homeTeamZh: '', + homeTeamEn: '', + awayTeamZh: '', + awayTeamEn: '', + isHot: false, + }; +} + +export type AdminMatchDetail = { + id: string; + status: string; + isOutright: boolean; + isHot: boolean; + startTime: string; + leagueEn: string; + leagueZh: string; + homeTeamEn: string; + homeTeamZh: string; + awayTeamEn: string; + awayTeamZh: string; + matchName: string; +}; + +export function formFromDetail(d: AdminMatchDetail): MatchCreateForm { + return { + leagueEn: d.leagueEn, + leagueZh: d.leagueZh, + startTime: d.startTime, + homeTeamZh: d.homeTeamZh, + homeTeamEn: d.homeTeamEn, + awayTeamZh: d.awayTeamZh, + awayTeamEn: d.awayTeamEn, + isHot: d.isHot, + }; +} + +export function buildPlatformPayload(form: MatchCreateForm) { + if (!form.startTime.trim()) { + throw new Error('请填写开赛时间'); + } + const homeOk = form.homeTeamZh.trim() || form.homeTeamEn.trim(); + const awayOk = form.awayTeamZh.trim() || form.awayTeamEn.trim(); + if (!homeOk || !awayOk) { + throw new Error('请填写主客队名称(中文或英文至少一项)'); + } + if (!form.leagueZh.trim() && !form.leagueEn.trim()) { + throw new Error('请填写联赛名称'); + } + + return { + leagueEn: form.leagueEn.trim(), + leagueZh: form.leagueZh.trim(), + homeTeamEn: form.homeTeamEn.trim(), + homeTeamZh: form.homeTeamZh.trim(), + awayTeamEn: form.awayTeamEn.trim(), + awayTeamZh: form.awayTeamZh.trim(), + startTime: form.startTime.trim(), + isHot: form.isHot, + }; +} diff --git a/apps/admin/src/views/user-form.ts b/apps/admin/src/views/user-form.ts new file mode 100644 index 0000000..f7aca63 --- /dev/null +++ b/apps/admin/src/views/user-form.ts @@ -0,0 +1,120 @@ +export interface PlayerCreateForm { + username: string; + password: string; + confirmPassword: string; + parentId: string; + phone: string; + email: string; + initialDeposit: number; + remark: string; +} + +export interface PlayerEditForm { + id: string; + username: string; + status: string; + parentId: string; + parentUsername: string | null; + availableBalance: string; + frozenBalance: string; + betCount: number; + totalStake: string; + totalReturn: string; + createdAt: string; + lastLoginAt: string | null; + loginFailCount: number; + phone: string; + email: string; +} + +export interface PlayerRow { + id: string; + username: string; + status: string; + locale: string; + parentId: string | null; + parentUsername: string | null; + phone: string | null; + email: string | null; + availableBalance: string; + frozenBalance: string; + lastLoginAt: string | null; + betCount: number; + totalStake: string; + totalReturn: string; + createdAt: string; +} + +export interface PlayerDetail extends PlayerRow { + loginFailCount: number; + lockedUntil: string | null; + updatedAt: string; +} + +export function emptyPlayerCreateForm(): PlayerCreateForm { + return { + username: '', + password: 'Player@123', + confirmPassword: 'Player@123', + parentId: '', + phone: '', + email: '', + initialDeposit: 0, + remark: '', + }; +} + +export function emptyPlayerEditForm(): PlayerEditForm { + return { + id: '', + username: '', + status: 'ACTIVE', + parentId: '', + parentUsername: null, + availableBalance: '0', + frozenBalance: '0', + betCount: 0, + totalStake: '0', + totalReturn: '0', + createdAt: '', + lastLoginAt: null, + loginFailCount: 0, + phone: '', + email: '', + }; +} + +export function editFormFromDetail(d: PlayerDetail): PlayerEditForm { + return { + id: d.id, + username: d.username, + status: d.status, + parentId: d.parentId ?? '', + parentUsername: d.parentUsername, + availableBalance: d.availableBalance, + frozenBalance: d.frozenBalance, + betCount: d.betCount, + totalStake: d.totalStake, + totalReturn: d.totalReturn, + createdAt: d.createdAt, + lastLoginAt: d.lastLoginAt, + loginFailCount: d.loginFailCount, + phone: d.phone ?? '', + email: d.email ?? '', + }; +} + +export function buildCreatePlayerPayload(form: PlayerCreateForm) { + if (!form.username.trim()) throw new Error('请填写用户名'); + if (form.password.length < 8) throw new Error('密码至少 8 位'); + if (form.password !== form.confirmPassword) throw new Error('两次密码不一致'); + return { + username: form.username.trim(), + password: form.password, + parentId: form.parentId || undefined, + phone: form.phone.trim() || undefined, + email: form.email.trim() || undefined, + initialDeposit: form.initialDeposit > 0 ? form.initialDeposit : undefined, + remark: form.remark.trim() || undefined, + }; +} diff --git a/apps/api/prisma/migrations/20260603102323_zhibo_match_fields/migration.sql b/apps/api/prisma/migrations/20260603102323_zhibo_match_fields/migration.sql new file mode 100644 index 0000000..5008730 --- /dev/null +++ b/apps/api/prisma/migrations/20260603102323_zhibo_match_fields/migration.sql @@ -0,0 +1,21 @@ +-- AlterTable +ALTER TABLE "teams" ADD COLUMN IF NOT EXISTS "external_id" INTEGER, +ADD COLUMN IF NOT EXISTS "logo_url" VARCHAR(500); + +-- AlterTable +ALTER TABLE "matches" ADD COLUMN IF NOT EXISTS "official_match_no" INTEGER, +ADD COLUMN IF NOT EXISTS "stage" VARCHAR(32), +ADD COLUMN IF NOT EXISTS "group_name" VARCHAR(8), +ADD COLUMN IF NOT EXISTS "live_match_id" BIGINT, +ADD COLUMN IF NOT EXISTS "addition_match_id" BIGINT, +ADD COLUMN IF NOT EXISTS "channel_id" VARCHAR(64), +ADD COLUMN IF NOT EXISTS "match_name" VARCHAR(200), +ADD COLUMN IF NOT EXISTS "venue_json" JSONB, +ADD COLUMN IF NOT EXISTS "kickoff_json" JSONB, +ADD COLUMN IF NOT EXISTS "external_status" VARCHAR(32); + +-- CreateIndex +CREATE UNIQUE INDEX IF NOT EXISTS "teams_external_id_key" ON "teams"("external_id"); + +-- CreateIndex +CREATE UNIQUE INDEX IF NOT EXISTS "matches_live_match_id_key" ON "matches"("live_match_id"); diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index 427333f..bab2d2d 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -227,12 +227,14 @@ model League { } model Team { - id BigInt @id @default(autoincrement()) - sportType String @default("FOOTBALL") @map("sport_type") @db.VarChar(20) - code String @unique @db.VarChar(64) - createdAt DateTime @default(now()) @map("created_at") - updatedAt DateTime @updatedAt @map("updated_at") - deletedAt DateTime? @map("deleted_at") + id BigInt @id @default(autoincrement()) + sportType String @default("FOOTBALL") @map("sport_type") @db.VarChar(20) + code String @unique @db.VarChar(64) + externalId Int? @unique @map("external_id") + logoUrl String? @map("logo_url") @db.VarChar(500) + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + deletedAt DateTime? @map("deleted_at") homeMatches Match[] @relation("HomeTeam") awayMatches Match[] @relation("AwayTeam") @@ -256,23 +258,33 @@ model EntityTranslation { } model Match { - id BigInt @id @default(autoincrement()) - sportType String @default("FOOTBALL") @map("sport_type") @db.VarChar(20) - leagueId BigInt @map("league_id") - homeTeamId BigInt @map("home_team_id") - awayTeamId BigInt @map("away_team_id") - startTime DateTime @map("start_time") - status String @default("DRAFT") @db.VarChar(32) - isHot Boolean @default(false) @map("is_hot") - displayOrder Int @default(0) @map("display_order") - publishTime DateTime? @map("publish_time") - closeTime DateTime? @map("close_time") - isOutright Boolean @default(false) @map("is_outright") - createdBy BigInt? @map("created_by") - updatedBy BigInt? @map("updated_by") - createdAt DateTime @default(now()) @map("created_at") - updatedAt DateTime @updatedAt @map("updated_at") - deletedAt DateTime? @map("deleted_at") + id BigInt @id @default(autoincrement()) + sportType String @default("FOOTBALL") @map("sport_type") @db.VarChar(20) + leagueId BigInt @map("league_id") + homeTeamId BigInt @map("home_team_id") + awayTeamId BigInt @map("away_team_id") + startTime DateTime @map("start_time") + status String @default("DRAFT") @db.VarChar(32) + isHot Boolean @default(false) @map("is_hot") + displayOrder Int @default(0) @map("display_order") + publishTime DateTime? @map("publish_time") + closeTime DateTime? @map("close_time") + isOutright Boolean @default(false) @map("is_outright") + officialMatchNo Int? @map("official_match_no") + stage String? @db.VarChar(32) + groupName String? @map("group_name") @db.VarChar(8) + liveMatchId BigInt? @unique @map("live_match_id") + additionMatchId BigInt? @map("addition_match_id") + channelId String? @map("channel_id") @db.VarChar(64) + matchName String? @map("match_name") @db.VarChar(200) + venueJson Json? @map("venue_json") + kickoffJson Json? @map("kickoff_json") + externalStatus String? @map("external_status") @db.VarChar(32) + createdBy BigInt? @map("created_by") + updatedBy BigInt? @map("updated_by") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + deletedAt DateTime? @map("deleted_at") league League @relation(fields: [leagueId], references: [id]) homeTeam Team @relation("HomeTeam", fields: [homeTeamId], references: [id]) diff --git a/apps/api/src/applications/admin/admin-dashboard.service.ts b/apps/api/src/applications/admin/admin-dashboard.service.ts new file mode 100644 index 0000000..2da678d --- /dev/null +++ b/apps/api/src/applications/admin/admin-dashboard.service.ts @@ -0,0 +1,209 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../shared/prisma/prisma.service'; +import { Decimal } from '@prisma/client/runtime/library'; + +function dec(v: Decimal | null | undefined) { + return v?.toString() ?? '0'; +} + +function sub(a: Decimal | null | undefined, b: Decimal | null | undefined) { + return new Decimal(a ?? 0).sub(b ?? 0).toString(); +} + +@Injectable() +export class AdminDashboardService { + constructor(private prisma: PrismaService) {} + + async getOverview() { + const today = new Date(); + today.setHours(0, 0, 0, 0); + + const trend7d = await Promise.all( + Array.from({ length: 7 }, (_, i) => { + const dayStart = new Date(today); + dayStart.setDate(dayStart.getDate() - (6 - i)); + const dayEnd = new Date(dayStart); + dayEnd.setDate(dayEnd.getDate() + 1); + return this.prisma.bet + .aggregate({ + where: { placedAt: { gte: dayStart, lt: dayEnd } }, + _sum: { stake: true, actualReturn: true }, + _count: true, + }) + .then((agg) => ({ + date: dayStart.toISOString().slice(0, 10), + label: `${dayStart.getMonth() + 1}/${dayStart.getDate()}`, + betCount: agg._count, + stake: dec(agg._sum.stake), + payout: dec(agg._sum.actualReturn), + ggr: sub(agg._sum.stake, agg._sum.actualReturn), + })); + }), + ); + + const playerWhere = { userType: 'PLAYER', deletedAt: null }; + + const [ + todayBets, + yesterdayBets, + pendingBets, + betStatusToday, + matchGroups, + matchTotal, + playerTotal, + playerActive, + playerSuspended, + playerDirect, + newPlayersToday, + agentProfiles, + agentsActive, + walletAgg, + recentBets, + recentPlayers, + ] = await Promise.all([ + this.prisma.bet.aggregate({ + where: { placedAt: { gte: today } }, + _sum: { stake: true, actualReturn: true }, + _count: true, + }), + this.prisma.bet.aggregate({ + where: { + placedAt: { + gte: new Date(today.getTime() - 86400000), + lt: today, + }, + }, + _sum: { stake: true, actualReturn: true }, + _count: true, + }), + this.prisma.bet.count({ where: { status: 'PENDING' } }), + this.prisma.bet.groupBy({ + by: ['status'], + where: { placedAt: { gte: today } }, + _count: { _all: true }, + _sum: { stake: true }, + }), + this.prisma.match.groupBy({ + by: ['status'], + where: { deletedAt: null }, + _count: { _all: true }, + }), + this.prisma.match.count({ where: { deletedAt: null } }), + this.prisma.user.count({ where: playerWhere }), + this.prisma.user.count({ where: { ...playerWhere, status: 'ACTIVE' } }), + this.prisma.user.count({ where: { ...playerWhere, status: 'SUSPENDED' } }), + this.prisma.user.count({ + where: { ...playerWhere, parentId: null }, + }), + this.prisma.user.count({ + where: { ...playerWhere, createdAt: { gte: today } }, + }), + this.prisma.agentProfile.aggregate({ + _sum: { creditLimit: true, usedCredit: true }, + _count: { _all: true }, + }), + this.prisma.agentProfile.count({ where: { status: 'ACTIVE' } }), + this.prisma.wallet.aggregate({ + where: { user: playerWhere }, + _sum: { availableBalance: true, frozenBalance: true }, + _count: { _all: true }, + }), + this.prisma.bet.findMany({ + take: 8, + orderBy: { placedAt: 'desc' }, + include: { user: { select: { username: true } } }, + }), + this.prisma.user.findMany({ + where: playerWhere, + take: 6, + orderBy: { createdAt: 'desc' }, + select: { + id: true, + username: true, + status: true, + createdAt: true, + parent: { select: { username: true } }, + }, + }), + ]); + + const matchByStatus: Record = {}; + for (const g of matchGroups) { + matchByStatus[g.status] = g._count._all; + } + + const todayBetByStatus: Record = {}; + for (const g of betStatusToday) { + todayBetByStatus[g.status] = { + count: g._count._all, + stake: dec(g._sum.stake), + }; + } + + const creditLimit = agentProfiles._sum.creditLimit ?? new Decimal(0); + const usedCredit = agentProfiles._sum.usedCredit ?? new Decimal(0); + + return { + generatedAt: new Date().toISOString(), + trend7d, + today: { + betCount: todayBets._count, + stake: dec(todayBets._sum.stake), + payout: dec(todayBets._sum.actualReturn), + ggr: sub(todayBets._sum.stake, todayBets._sum.actualReturn), + newPlayers: newPlayersToday, + }, + yesterday: { + betCount: yesterdayBets._count, + stake: dec(yesterdayBets._sum.stake), + payout: dec(yesterdayBets._sum.actualReturn), + ggr: sub(yesterdayBets._sum.stake, yesterdayBets._sum.actualReturn), + }, + users: { + playersTotal: playerTotal, + playersActive: playerActive, + playersSuspended: playerSuspended, + playersDirect: playerDirect, + agentsTotal: agentProfiles._count._all, + agentsActive, + }, + wallets: { + totalAvailable: dec(walletAgg._sum.availableBalance), + totalFrozen: dec(walletAgg._sum.frozenBalance), + playerWalletCount: walletAgg._count._all, + }, + agents: { + totalCreditLimit: dec(creditLimit), + totalUsedCredit: dec(usedCredit), + totalAvailableCredit: creditLimit.sub(usedCredit).toString(), + }, + matches: { + total: matchTotal, + draft: matchByStatus.DRAFT ?? 0, + published: matchByStatus.PUBLISHED ?? 0, + closed: matchByStatus.CLOSED ?? 0, + cancelled: matchByStatus.CANCELLED ?? 0, + pendingSettlement: matchByStatus.PENDING_SETTLEMENT ?? 0, + settled: matchByStatus.SETTLED ?? 0, + }, + bets: { + pendingTotal: pendingBets, + todayByStatus: todayBetByStatus, + }, + recentBets: recentBets.map((b) => ({ + betNo: b.betNo, + username: b.user.username, + stake: dec(b.stake), + status: b.status, + placedAt: b.placedAt, + })), + recentPlayers: recentPlayers.map((p) => ({ + id: p.id.toString(), + username: p.username, + status: p.status, + parentUsername: p.parent?.username ?? null, + createdAt: p.createdAt, + })), + }; + } +} diff --git a/apps/api/src/applications/admin/admin.controller.ts b/apps/api/src/applications/admin/admin.controller.ts index 5422c15..d21275a 100644 --- a/apps/api/src/applications/admin/admin.controller.ts +++ b/apps/api/src/applications/admin/admin.controller.ts @@ -1,5 +1,7 @@ import { + BadRequestException, Controller, + Delete, Get, Post, Put, @@ -24,7 +26,18 @@ import { I18nService } from '../../domains/operations/i18n/i18n.service'; import { AuditService } from '../../domains/operations/audit/audit.service'; import { BetsService } from '../../domains/betting/bets.service'; import { PrismaService } from '../../shared/prisma/prisma.service'; -import { IsString, IsNumber, IsOptional, IsArray, IsBoolean, MinLength } from 'class-validator'; +import { AdminDashboardService } from './admin-dashboard.service'; +import { + IsString, + IsNumber, + IsOptional, + IsArray, + IsBoolean, + MinLength, + IsIn, + Min, +} from 'class-validator'; +import type { ZhiboMatchExport, ZhiboMatchesBundleExport } from '../../domains/catalog/zhibo-match.types'; class CreateUserDto { @IsString() @@ -43,6 +56,116 @@ class CreateUserDto { creditLimit?: number; } +class CreatePlayerAdminDto { + @IsString() + username!: string; + + @IsString() + @MinLength(8) + password!: string; + + @IsOptional() + @IsString() + parentId?: string; + + @IsOptional() + @IsString() + locale?: string; + + @IsOptional() + @IsString() + phone?: string; + + @IsOptional() + @IsString() + email?: string; + + @IsOptional() + @IsNumber() + @Min(0) + initialDeposit?: number; + + @IsOptional() + @IsString() + remark?: string; +} + +class UpdatePlayerAdminDto { + @IsOptional() + @IsIn(['ACTIVE', 'SUSPENDED']) + status?: string; + + @IsOptional() + @IsString() + locale?: string; + + @IsOptional() + @IsString() + phone?: string; + + @IsOptional() + @IsString() + email?: string; + + /** 传空字符串表示改为平台直属(无代理) */ + @IsOptional() + @IsString() + parentId?: string; +} + +class CreateAgentAdminDto { + @IsString() + username!: string; + + @IsString() + @MinLength(8) + password!: string; + + @IsNumber() + @Min(0) + creditLimit!: number; + + @IsOptional() + @IsString() + locale?: string; + + @IsOptional() + @IsString() + phone?: string; + + @IsOptional() + @IsString() + email?: string; + + @IsOptional() + @IsNumber() + @Min(0) + cashbackRate?: number; +} + +class UpdateAgentAdminDto { + @IsOptional() + @IsIn(['ACTIVE', 'SUSPENDED']) + status?: string; + + @IsOptional() + @IsString() + locale?: string; + + @IsOptional() + @IsString() + phone?: string; + + @IsOptional() + @IsString() + email?: string; + + @IsOptional() + @IsNumber() + @Min(0) + cashbackRate?: number; +} + class DepositDto { @IsNumber() amount!: number; @@ -55,15 +178,24 @@ class DepositDto { remark?: string; } -class CreateMatchDto { +class CreatePlatformMatchDto { @IsString() - leagueId!: string; + leagueEn!: string; @IsString() - homeTeamId!: string; + leagueZh!: string; @IsString() - awayTeamId!: string; + homeTeamEn!: string; + + @IsString() + homeTeamZh!: string; + + @IsString() + awayTeamEn!: string; + + @IsString() + awayTeamZh!: string; @IsString() startTime!: string; @@ -71,6 +203,15 @@ class CreateMatchDto { @IsOptional() @IsBoolean() isHot?: boolean; + + @IsOptional() + @IsNumber() + displayOrder?: number; +} + +function isZhiboBundlePayload(body: unknown): body is ZhiboMatchesBundleExport { + if (!body || typeof body !== 'object') return false; + return Array.isArray((body as ZhiboMatchesBundleExport).matches); } class ScoreDto { @@ -123,44 +264,73 @@ export class AdminController { private audit: AuditService, private bets: BetsService, private prisma: PrismaService, + private readonly dashboardService: AdminDashboardService, ) {} @Get('dashboard') - async dashboard() { - const today = new Date(); - today.setHours(0, 0, 0, 0); - - const [todayBets, pendingMatches, totalPlayers] = await Promise.all([ - this.prisma.bet.aggregate({ - where: { placedAt: { gte: today } }, - _sum: { stake: true, actualReturn: true }, - _count: true, - }), - this.prisma.match.count({ where: { status: 'PENDING_SETTLEMENT' } }), - this.prisma.user.count({ where: { userType: 'PLAYER' } }), - ]); - - return jsonResponse({ - todayBetCount: todayBets._count, - todayStake: todayBets._sum.stake, - todayPayout: todayBets._sum.actualReturn, - pendingSettlement: pendingMatches, - totalPlayers, - }); + async getDashboard() { + const overview = await this.dashboardService.getOverview(); + return jsonResponse(overview); } @Get('users') - async listUsers(@Query('page') page?: string) { - const result = await this.users.listPlayers(page ? parseInt(page) : 1); + async listUsers( + @Query('page') page?: string, + @Query('pageSize') pageSize?: string, + @Query('keyword') keyword?: string, + @Query('parentId') parentId?: string, + @Query('status') status?: string, + ) { + const result = await this.users.listPlayers( + page ? parseInt(page, 10) : 1, + pageSize ? parseInt(pageSize, 10) : 10, + { + keyword, + parentId: parentId ? BigInt(parentId) : undefined, + status, + }, + ); return jsonResponse(result); } + @Get('users/:id') + async getUserDetail(@Param('id') id: string) { + const detail = await this.users.getPlayerAdminDetail(BigInt(id)); + return jsonResponse(detail); + } + + @Put('users/:id') + async updateUser( + @CurrentUser('id') operatorId: bigint, + @Param('id') id: string, + @Body() dto: UpdatePlayerAdminDto, + ) { + const detail = await this.users.updatePlayerAdmin(BigInt(id), dto); + await this.audit.log({ + operatorId, + operatorType: 'ADMIN', + action: 'UPDATE_PLAYER', + module: 'USERS', + targetId: id, + }); + return jsonResponse(detail); + } + @Post('users') - async createPlayer(@CurrentUser('id') operatorId: bigint, @Body() dto: CreateUserDto) { + async createPlayer( + @CurrentUser('id') operatorId: bigint, + @Body() dto: CreatePlayerAdminDto, + ) { const user = await this.agents.createPlayer(operatorId, { username: dto.username, password: dto.password, - parentId: dto.parentId ? BigInt(dto.parentId) : operatorId, + parentId: dto.parentId ? BigInt(dto.parentId) : undefined, + locale: dto.locale, + phone: dto.phone, + email: dto.email, + initialDeposit: dto.initialDeposit, + depositRemark: dto.remark, + depositRequestId: `create-player-${dto.username}-${Date.now()}`, }); await this.audit.log({ operatorId, @@ -169,24 +339,73 @@ export class AdminController { module: 'USERS', targetId: user.id.toString(), }); - return jsonResponse(user); + const detail = await this.users.getPlayerAdminDetail(user.id); + return jsonResponse(detail); + } + + @Get('agents/options') + async listAgentOptions() { + const agents = await this.prisma.user.findMany({ + where: { userType: 'AGENT', deletedAt: null, agentLevel: 1 }, + select: { id: true, username: true }, + orderBy: { username: 'asc' }, + }); + return jsonResponse( + agents.map((a) => ({ id: a.id.toString(), username: a.username })), + ); } @Get('agents') - async listAgents() { - const agents = await this.prisma.agentProfile.findMany({ - include: { user: true }, + async listAgents( + @Query('page') page?: string, + @Query('pageSize') pageSize?: string, + @Query('keyword') keyword?: string, + ) { + const result = await this.agents.listAgentsAdmin({ + page: page ? parseInt(page, 10) : 1, + pageSize: pageSize ? parseInt(pageSize, 10) : 10, + keyword, }); - return jsonResponse(agents); + return jsonResponse(result); + } + + @Get('agents/:id') + async getAgentDetail(@Param('id') id: string) { + const detail = await this.agents.getAgentAdminDetail(BigInt(id)); + return jsonResponse(detail); + } + + @Put('agents/:id') + async updateAgent( + @CurrentUser('id') operatorId: bigint, + @Param('id') id: string, + @Body() dto: UpdateAgentAdminDto, + ) { + const detail = await this.agents.updateAgentAdmin(BigInt(id), dto); + await this.audit.log({ + operatorId, + operatorType: 'ADMIN', + action: 'UPDATE_AGENT', + module: 'AGENTS', + targetId: id, + }); + return jsonResponse(detail); } @Post('agents') - async createAgent(@CurrentUser('id') operatorId: bigint, @Body() dto: CreateUserDto) { + async createAgent( + @CurrentUser('id') operatorId: bigint, + @Body() dto: CreateAgentAdminDto, + ) { const user = await this.agents.createAgent(operatorId, { username: dto.username, password: dto.password, level: 1, creditLimit: dto.creditLimit, + locale: dto.locale, + phone: dto.phone, + email: dto.email, + cashbackRate: dto.cashbackRate, }); await this.audit.log({ operatorId, @@ -195,7 +414,8 @@ export class AdminController { module: 'AGENTS', targetId: user.id.toString(), }); - return jsonResponse(user); + const detail = await this.agents.getAgentAdminDetail(user.id); + return jsonResponse(detail); } @Post('agents/:id/credit') @@ -257,27 +477,100 @@ export class AdminController { } @Get('matches') - async listMatches() { - const matches = await this.prisma.match.findMany({ - include: { markets: { include: { selections: true } } }, - orderBy: { startTime: 'desc' }, + async listMatches( + @Query('page') page?: string, + @Query('pageSize') pageSize?: string, + @Query('status') status?: string, + @Query('keyword') keyword?: string, + ) { + const p = Math.max(1, page ? parseInt(page, 10) : 1); + const size = Math.min(Math.max(1, pageSize ? parseInt(pageSize, 10) : 10), 100); + const skip = (p - 1) * size; + const where: { deletedAt: null; status?: string; OR?: object[] } = { deletedAt: null }; + if (status) where.status = status; + const kw = keyword?.trim(); + if (kw) { + where.OR = [ + { matchName: { contains: kw, mode: 'insensitive' } }, + { homeTeam: { code: { contains: kw, mode: 'insensitive' } } }, + { awayTeam: { code: { contains: kw, mode: 'insensitive' } } }, + ]; + } + const [items, total] = await Promise.all([ + this.prisma.match.findMany({ + where, + include: { + homeTeam: true, + awayTeam: true, + }, + orderBy: [{ displayOrder: 'asc' }, { startTime: 'desc' }], + skip, + take: size, + }), + this.prisma.match.count({ where }), + ]); + return jsonResponse({ items, total, page: p, pageSize: size }); + } + + @Get('matches/:id') + async getMatch(@Param('id') id: string) { + const match = await this.matches.getAdminMatchDetail(BigInt(id)); + return jsonResponse(match); + } + + @Put('matches/:id') + async updateMatch( + @CurrentUser('id') operatorId: bigint, + @Param('id') id: string, + @Body() dto: CreatePlatformMatchDto, + ) { + const match = await this.matches.updatePlatformMatch(BigInt(id), { + leagueEn: dto.leagueEn, + leagueZh: dto.leagueZh, + homeTeamEn: dto.homeTeamEn, + homeTeamZh: dto.homeTeamZh, + awayTeamEn: dto.awayTeamEn, + awayTeamZh: dto.awayTeamZh, + startTime: new Date(dto.startTime), + isHot: dto.isHot, + displayOrder: dto.displayOrder, + updatedBy: operatorId, }); - return jsonResponse(matches); + return jsonResponse(match); + } + + @Delete('matches/:id') + async deleteMatch(@Param('id') id: string) { + await this.matches.deleteMatch(BigInt(id)); + return jsonResponse({ deleted: true }); } @Post('matches') - async createMatch(@CurrentUser('id') operatorId: bigint, @Body() dto: CreateMatchDto) { - const match = await this.matches.createMatch({ - leagueId: BigInt(dto.leagueId), - homeTeamId: BigInt(dto.homeTeamId), - awayTeamId: BigInt(dto.awayTeamId), + async createMatch(@CurrentUser('id') operatorId: bigint, @Body() dto: CreatePlatformMatchDto) { + const match = await this.matches.createPlatformMatch({ + leagueEn: dto.leagueEn, + leagueZh: dto.leagueZh, + homeTeamEn: dto.homeTeamEn, + homeTeamZh: dto.homeTeamZh, + awayTeamEn: dto.awayTeamEn, + awayTeamZh: dto.awayTeamZh, startTime: new Date(dto.startTime), isHot: dto.isHot, + displayOrder: dto.displayOrder, createdBy: operatorId, }); return jsonResponse(match); } + @Post('matches/import') + async importMatches(@CurrentUser('id') operatorId: bigint, @Body() dto: ZhiboMatchesBundleExport) { + if (!isZhiboBundlePayload(dto)) { + throw new BadRequestException('Invalid import payload: matches[] required'); + } + const result = await this.matches.importZhiboMatchesBundle(dto, operatorId); + return jsonResponse(result); + } + @Post('matches/:id/publish') async publishMatch(@Param('id') id: string) { const match = await this.matches.publishMatch(BigInt(id)); @@ -343,20 +636,31 @@ export class AdminController { } @Get('bets') - async listBets(@Query('status') status?: string, @Query('page') page?: string) { - const skip = ((page ? parseInt(page) : 1) - 1) * 20; - const where = status ? { status } : {}; - const [items, total] = await Promise.all([ - this.prisma.bet.findMany({ - where, - include: { selections: true, user: true }, - orderBy: { placedAt: 'desc' }, - skip, - take: 20, - }), - this.prisma.bet.count({ where }), - ]); - return jsonResponse({ items, total }); + async listBets( + @Query('page') page?: string, + @Query('pageSize') pageSize?: string, + @Query('keyword') keyword?: string, + @Query('status') status?: string, + @Query('betType') betType?: string, + @Query('placedFrom') placedFrom?: string, + @Query('placedTo') placedTo?: string, + ) { + const result = await this.bets.listBetsAdmin({ + page: page ? parseInt(page, 10) : 1, + pageSize: pageSize ? parseInt(pageSize, 10) : 10, + keyword, + status: status || undefined, + betType: betType || undefined, + placedFrom, + placedTo, + }); + return jsonResponse(result); + } + + @Get('bets/:id') + async getBet(@Param('id') id: string) { + const detail = await this.bets.getBetAdminDetail(BigInt(id)); + return jsonResponse(detail); } @Post('cashbacks/preview') @@ -393,8 +697,16 @@ export class AdminController { } @Get('audit-logs') - async auditLogs(@Query('page') page?: string, @Query('module') module?: string) { - const result = await this.audit.list(page ? parseInt(page) : 1, 50, module); + async auditLogs( + @Query('page') page?: string, + @Query('pageSize') pageSize?: string, + @Query('module') module?: string, + ) { + const result = await this.audit.list( + page ? parseInt(page, 10) : 1, + pageSize ? parseInt(pageSize, 10) : 10, + module || undefined, + ); return jsonResponse(result); } } diff --git a/apps/api/src/applications/admin/admin.module.ts b/apps/api/src/applications/admin/admin.module.ts index 844eac5..7277e1c 100644 --- a/apps/api/src/applications/admin/admin.module.ts +++ b/apps/api/src/applications/admin/admin.module.ts @@ -1,5 +1,6 @@ import { Module } from '@nestjs/common'; import { AdminController } from './admin.controller'; +import { AdminDashboardService } from './admin-dashboard.service'; import { UsersModule } from '../../domains/identity/users.module'; import { AgentsModule } from '../../domains/agent/agents.module'; import { WalletModule } from '../../domains/ledger/wallet.module'; @@ -25,5 +26,6 @@ import { BetsModule } from '../../domains/betting/bets.module'; BetsModule, ], controllers: [AdminController], + providers: [AdminDashboardService], }) export class AdminModule {} diff --git a/apps/api/src/applications/agent/agent-portal.controller.ts b/apps/api/src/applications/agent/agent-portal.controller.ts index fcb4622..83da514 100644 --- a/apps/api/src/applications/agent/agent-portal.controller.ts +++ b/apps/api/src/applications/agent/agent-portal.controller.ts @@ -147,8 +147,14 @@ export class AgentPortalController { } @Get('bets') - async listBets(@CurrentUser('id') agentId: bigint, @Query('page') page?: string) { - const skip = ((page ? parseInt(page) : 1) - 1) * 20; + async listBets( + @CurrentUser('id') agentId: bigint, + @Query('page') page?: string, + @Query('pageSize') pageSize?: string, + ) { + const p = Math.max(1, page ? parseInt(page, 10) : 1); + const size = Math.min(Math.max(1, pageSize ? parseInt(pageSize, 10) : 10), 100); + const skip = (p - 1) * size; const descendants = await this.prisma.agentClosure.findMany({ where: { ancestorId: agentId }, }); @@ -160,11 +166,11 @@ export class AgentPortalController { include: { selections: true, user: true }, orderBy: { placedAt: 'desc' }, skip, - take: 20, + take: size, }), this.prisma.bet.count({ where: { agentId: { in: agentIds } } }), ]); - return jsonResponse({ items, total }); + return jsonResponse({ items, total, page: p, pageSize: size }); } @Get('reports/summary') diff --git a/apps/api/src/domains/agent/agents.service.ts b/apps/api/src/domains/agent/agents.service.ts index 52f9dc6..f5c3505 100644 --- a/apps/api/src/domains/agent/agents.service.ts +++ b/apps/api/src/domains/agent/agents.service.ts @@ -1,4 +1,10 @@ -import { Injectable, BadRequestException, ForbiddenException } from '@nestjs/common'; +import { + Injectable, + BadRequestException, + ForbiddenException, + NotFoundException, +} from '@nestjs/common'; +import { Prisma } from '@prisma/client'; import { PrismaService } from '../../shared/prisma/prisma.service'; import { WalletService } from '../ledger/wallet.service'; import { AuthService } from '../identity/auth.service'; @@ -147,6 +153,211 @@ export class AgentsService { return { success: true }; } + async listAgentsAdmin(params?: { + page?: number; + pageSize?: number; + keyword?: string; + }) { + const page = Math.max(1, params?.page ?? 1); + const pageSize = Math.min(Math.max(1, params?.pageSize ?? 10), 100); + const skip = (page - 1) * pageSize; + + const where: Prisma.AgentProfileWhereInput = {}; + const kw = params?.keyword?.trim(); + if (kw) { + where.user = { username: { contains: kw, mode: 'insensitive' } }; + } + + const [profiles, total] = await Promise.all([ + this.prisma.agentProfile.findMany({ + where, + include: { + user: { include: { preferences: true } }, + }, + orderBy: { createdAt: 'desc' }, + skip, + take: pageSize, + }), + this.prisma.agentProfile.count({ where }), + ]); + + const agentIds = profiles.map((p) => p.userId); + const playerCounts = + agentIds.length > 0 + ? await this.prisma.user.groupBy({ + by: ['parentId'], + where: { + userType: 'PLAYER', + parentId: { in: agentIds }, + deletedAt: null, + }, + _count: { _all: true }, + }) + : []; + + const countMap = new Map( + playerCounts.map((g) => [g.parentId?.toString(), g._count._all]), + ); + + const items = profiles.map((p) => { + const available = new Decimal(p.creditLimit).sub(p.usedCredit); + return { + id: p.id.toString(), + userId: p.userId.toString(), + username: p.user.username, + userStatus: p.user.status, + level: p.level, + status: p.status, + parentAgentId: p.parentAgentId?.toString() ?? null, + creditLimit: p.creditLimit.toString(), + usedCredit: p.usedCredit.toString(), + availableCredit: available.toString(), + directPlayerLiability: p.directPlayerLiability.toString(), + childAgentExposure: p.childAgentExposure.toString(), + cashbackRate: p.cashbackRate.toString(), + directPlayerCount: countMap.get(p.userId.toString()) ?? 0, + phone: p.user.preferences?.phone ?? null, + email: p.user.preferences?.email ?? null, + locale: p.user.locale, + createdAt: p.createdAt, + updatedAt: p.updatedAt, + }; + }); + + return { items, total, page, pageSize }; + } + + async getAgentAdminDetail(agentId: bigint) { + const profile = await this.prisma.agentProfile.findUnique({ + where: { userId: agentId }, + include: { user: { include: { preferences: true, auth: true } } }, + }); + if (!profile) throw new NotFoundException('代理不存在'); + + const [directPlayerCount, recentCredits] = await Promise.all([ + this.prisma.user.count({ + where: { parentId: agentId, userType: 'PLAYER', deletedAt: null }, + }), + this.prisma.agentCreditTransaction.findMany({ + where: { agentId }, + orderBy: { createdAt: 'desc' }, + take: 10, + }), + ]); + + const available = new Decimal(profile.creditLimit).sub(profile.usedCredit); + let parentUsername: string | null = null; + if (profile.parentAgentId) { + const parent = await this.prisma.user.findUnique({ + where: { id: profile.parentAgentId }, + select: { username: true }, + }); + parentUsername = parent?.username ?? null; + } + + return { + id: profile.id.toString(), + userId: profile.userId.toString(), + username: profile.user.username, + userStatus: profile.user.status, + level: profile.level, + status: profile.status, + parentAgentId: profile.parentAgentId?.toString() ?? null, + parentUsername, + creditLimit: profile.creditLimit.toString(), + usedCredit: profile.usedCredit.toString(), + availableCredit: available.toString(), + directPlayerLiability: profile.directPlayerLiability.toString(), + childAgentExposure: profile.childAgentExposure.toString(), + cashbackRate: profile.cashbackRate.toString(), + directPlayerCount, + phone: profile.user.preferences?.phone ?? null, + email: profile.user.preferences?.email ?? null, + locale: profile.user.locale, + lastLoginAt: profile.user.auth?.lastLoginAt ?? null, + createdAt: profile.createdAt, + updatedAt: profile.updatedAt, + recentCreditTransactions: recentCredits.map((t) => ({ + id: t.id.toString(), + transactionType: t.transactionType, + amount: t.amount.toString(), + creditBefore: t.creditBefore.toString(), + creditAfter: t.creditAfter.toString(), + remark: t.remark, + createdAt: t.createdAt, + })), + }; + } + + async updateAgentAdmin( + agentId: bigint, + data: { + status?: string; + locale?: string; + phone?: string; + email?: string; + cashbackRate?: number; + }, + ) { + const profile = await this.prisma.agentProfile.findUnique({ + where: { userId: agentId }, + include: { user: true }, + }); + if (!profile) throw new NotFoundException('代理不存在'); + + if (data.status && !['ACTIVE', 'SUSPENDED'].includes(data.status)) { + throw new BadRequestException('无效状态'); + } + + if (data.status) { + await this.prisma.$transaction([ + this.prisma.user.update({ + where: { id: agentId }, + data: { status: data.status }, + }), + this.prisma.agentProfile.update({ + where: { userId: agentId }, + data: { status: data.status }, + }), + ]); + } + + if (data.locale) { + await this.prisma.user.update({ + where: { id: agentId }, + data: { locale: data.locale }, + }); + } + + if (data.cashbackRate !== undefined) { + await this.prisma.agentProfile.update({ + where: { userId: agentId }, + data: { cashbackRate: data.cashbackRate }, + }); + } + + if (data.phone !== undefined || data.email !== undefined || data.locale) { + const phone = data.phone !== undefined ? data.phone?.trim() || null : undefined; + const email = data.email !== undefined ? data.email?.trim() || null : undefined; + await this.prisma.userPreference.upsert({ + where: { userId: agentId }, + create: { + userId: agentId, + locale: data.locale ?? profile.user.locale, + phone: phone ?? null, + email: email ?? null, + }, + update: { + ...(data.locale ? { locale: data.locale } : {}), + ...(phone !== undefined ? { phone } : {}), + ...(email !== undefined ? { email } : {}), + }, + }); + } + + return this.getAgentAdminDetail(agentId); + } + async createAgent( operatorId: bigint, data: { @@ -155,6 +366,10 @@ export class AgentsService { level: number; parentAgentId?: bigint; creditLimit?: number; + locale?: string; + phone?: string; + email?: string; + cashbackRate?: number; }, ) { if (data.level === 2 && !data.parentAgentId) { @@ -164,12 +379,14 @@ export class AgentsService { const hash = await this.auth.hashPassword(data.password); return this.prisma.$transaction(async (tx) => { + const locale = data.locale ?? 'zh-CN'; const user = await tx.user.create({ data: { username: data.username, userType: 'AGENT', parentId: data.parentAgentId, agentLevel: data.level, + locale, }, }); @@ -177,12 +394,22 @@ export class AgentsService { data: { userId: user.id, passwordHash: hash }, }); + await tx.userPreference.create({ + data: { + userId: user.id, + locale, + phone: data.phone?.trim() || null, + email: data.email?.trim() || null, + }, + }); + await tx.agentProfile.create({ data: { userId: user.id, level: data.level, parentAgentId: data.parentAgentId, creditLimit: data.creditLimit ?? 0, + cashbackRate: data.cashbackRate ?? 0, }, }); @@ -215,38 +442,81 @@ export class AgentsService { async createPlayer( operatorId: bigint, - data: { username: string; password: string; parentId: bigint }, + data: { + username: string; + password: string; + parentId?: bigint; + locale?: string; + phone?: string; + email?: string; + initialDeposit?: number; + depositRemark?: string; + depositRequestId?: string; + }, ) { - const hash = await this.auth.hashPassword(data.password); + let parentId: bigint | null = null; + if (data.parentId != null) { + const parent = await this.prisma.user.findUnique({ where: { id: data.parentId } }); + if (!parent || parent.userType !== 'AGENT') { + throw new BadRequestException('上级必须为代理账号'); + } + parentId = data.parentId; + } - return this.prisma.$transaction(async (tx) => { - const user = await tx.user.create({ + const hash = await this.auth.hashPassword(data.password); + const locale = data.locale ?? 'zh-CN'; + + const user = await this.prisma.$transaction(async (tx) => { + const created = await tx.user.create({ data: { username: data.username, userType: 'PLAYER', - parentId: data.parentId, + parentId, + locale, }, }); await tx.userAuth.create({ - data: { userId: user.id, passwordHash: hash }, + data: { userId: created.id, passwordHash: hash }, }); await tx.wallet.create({ - data: { userId: user.id }, + data: { userId: created.id }, }); await tx.userPreference.create({ - data: { userId: user.id }, + data: { + userId: created.id, + locale, + phone: data.phone?.trim() || null, + email: data.email?.trim() || null, + }, }); - const parent = await tx.user.findUnique({ where: { id: data.parentId } }); - if (parent?.userType === 'AGENT') { - await this.recalculateUsedCredit(data.parentId); - } - - return user; + return created; }); + + if (parentId) { + await this.recalculateUsedCredit(parentId); + } + + const initial = data.initialDeposit ?? 0; + if (initial > 0) { + const requestId = + data.depositRequestId ?? `admin-create-${user.id}-${Date.now()}`; + await this.wallet.deposit( + user.id, + initial, + operatorId, + data.depositRemark ?? '开户初始余额', + requestId, + ); + if (parentId) { + await this.recalculateUsedCredit(parentId); + } + } + + return user; } async getDirectPlayers(agentId: bigint) { diff --git a/apps/api/src/domains/betting/bets.service.ts b/apps/api/src/domains/betting/bets.service.ts index d8df885..5b572f7 100644 --- a/apps/api/src/domains/betting/bets.service.ts +++ b/apps/api/src/domains/betting/bets.service.ts @@ -1,4 +1,5 @@ -import { Injectable, BadRequestException, ConflictException } from '@nestjs/common'; +import { Injectable, BadRequestException, ConflictException, NotFoundException } from '@nestjs/common'; +import { Prisma } from '@prisma/client'; import { PrismaService } from '../../shared/prisma/prisma.service'; import { WalletService } from '../ledger/wallet.service'; import { Decimal } from '@prisma/client/runtime/library'; @@ -208,4 +209,157 @@ export class BetsService { include: { selections: true }, }); } + + private dec(v: Decimal | null | undefined) { + return v?.toString() ?? '0'; + } + + private formatBetListRow( + b: { + id: bigint; + betNo: string; + userId: bigint; + agentId: bigint | null; + betType: string; + stake: Decimal; + totalOdds: Decimal | null; + potentialReturn: Decimal | null; + actualReturn: Decimal; + status: string; + settlementStatus: string | null; + currency: string; + placedAt: Date; + settledAt: Date | null; + user: { id: bigint; username: string; parent: { username: string } | null }; + _count: { selections: number }; + }, + ) { + return { + id: b.id.toString(), + betNo: b.betNo, + userId: b.userId.toString(), + username: b.user.username, + parentUsername: b.user.parent?.username ?? null, + agentId: b.agentId?.toString() ?? null, + betType: b.betType, + stake: this.dec(b.stake), + totalOdds: b.totalOdds ? this.dec(b.totalOdds) : null, + potentialReturn: b.potentialReturn ? this.dec(b.potentialReturn) : null, + actualReturn: this.dec(b.actualReturn), + status: b.status, + settlementStatus: b.settlementStatus, + currency: b.currency, + placedAt: b.placedAt, + settledAt: b.settledAt, + selectionCount: b._count.selections, + }; + } + + async listBetsAdmin(params: { + page?: number; + pageSize?: number; + keyword?: string; + status?: string; + betType?: string; + placedFrom?: string; + placedTo?: string; + }) { + const page = Math.max(1, params.page ?? 1); + const pageSize = Math.min(Math.max(1, params.pageSize ?? 10), 100); + const skip = (page - 1) * pageSize; + + const where: Prisma.BetWhereInput = {}; + + if (params.status) where.status = params.status; + if (params.betType) where.betType = params.betType; + + if (params.placedFrom || params.placedTo) { + where.placedAt = {}; + if (params.placedFrom) { + const from = new Date(params.placedFrom); + from.setHours(0, 0, 0, 0); + where.placedAt.gte = from; + } + if (params.placedTo) { + const to = new Date(params.placedTo); + to.setHours(23, 59, 59, 999); + where.placedAt.lte = to; + } + } + + const kw = params.keyword?.trim(); + if (kw) { + where.OR = [ + { betNo: { contains: kw, mode: 'insensitive' } }, + { user: { username: { contains: kw, mode: 'insensitive' } } }, + ]; + } + + const [items, total] = await Promise.all([ + this.prisma.bet.findMany({ + where, + include: { + user: { + select: { + id: true, + username: true, + parent: { select: { username: true } }, + }, + }, + _count: { select: { selections: true } }, + }, + orderBy: { placedAt: 'desc' }, + skip, + take: pageSize, + }), + this.prisma.bet.count({ where }), + ]); + + return { + items: items.map((b) => this.formatBetListRow(b)), + total, + page, + pageSize, + }; + } + + async getBetAdminDetail(betId: bigint) { + const bet = await this.prisma.bet.findUnique({ + where: { id: betId }, + include: { + user: { + select: { + id: true, + username: true, + parent: { select: { username: true } }, + }, + }, + selections: { orderBy: { sortOrder: 'asc' } }, + }, + }); + if (!bet) throw new NotFoundException('注单不存在'); + + return { + ...this.formatBetListRow({ + ...bet, + _count: { selections: bet.selections.length }, + }), + requestId: bet.requestId, + createdAt: bet.createdAt, + updatedAt: bet.updatedAt, + selections: bet.selections.map((s) => ({ + id: s.id.toString(), + matchId: s.matchId?.toString() ?? null, + marketType: s.marketType, + period: s.period, + selectionName: s.selectionNameSnapshot, + handicapLine: s.handicapLine ? this.dec(s.handicapLine) : null, + totalLine: s.totalLine ? this.dec(s.totalLine) : null, + odds: this.dec(s.odds), + resultStatus: s.resultStatus, + effectiveOdds: s.effectiveOdds ? this.dec(s.effectiveOdds) : null, + sortOrder: s.sortOrder, + })), + }; + } } diff --git a/apps/api/src/domains/catalog/matches.service.ts b/apps/api/src/domains/catalog/matches.service.ts index 7ca1c00..b3cfa40 100644 --- a/apps/api/src/domains/catalog/matches.service.ts +++ b/apps/api/src/domains/catalog/matches.service.ts @@ -1,6 +1,18 @@ import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; +import { Prisma } from '@prisma/client'; import { PrismaService } from '../../shared/prisma/prisma.service'; +import type { ZhiboLeagueExport, ZhiboMatchExport, ZhiboMatchesBundleExport, ZhiboTeamExport } from './zhibo-match.types'; +import { + leagueCodeFromExport, + resolveInternalStatus, + resolveIsHot, + resolveStartTime, + teamCodeFromExport, + toKickoffJson, + toVenueJson, + translationsFromZhiboNames, +} from './zhibo-match.mapper'; @Injectable() export class MatchesService { @@ -44,8 +56,24 @@ export class MatchesService { awayTeamId: bigint; startTime: Date; isHot?: boolean; + displayOrder?: number; createdBy?: bigint; + status?: string; + publishTime?: Date; + zhibo?: Partial<{ + officialMatchNo: number; + stage: string; + groupName: string; + liveMatchId?: bigint; + additionMatchId: bigint | null; + channelId: string | null; + matchName: string; + venueJson: Prisma.InputJsonValue; + kickoffJson: Prisma.InputJsonValue; + externalStatus: string; + }>; }) { + const status = data.status ?? 'DRAFT'; return this.prisma.match.create({ data: { leagueId: data.leagueId, @@ -53,12 +81,384 @@ export class MatchesService { awayTeamId: data.awayTeamId, startTime: data.startTime, isHot: data.isHot ?? false, + displayOrder: data.displayOrder ?? 0, createdBy: data.createdBy, - status: 'DRAFT', + status, + publishTime: data.publishTime ?? (status === 'PUBLISHED' ? new Date() : undefined), + officialMatchNo: data.zhibo?.officialMatchNo, + stage: data.zhibo?.stage, + groupName: data.zhibo?.groupName, + liveMatchId: data.zhibo?.liveMatchId, + additionMatchId: data.zhibo?.additionMatchId ?? undefined, + channelId: data.zhibo?.channelId ?? undefined, + matchName: data.zhibo?.matchName, + venueJson: data.zhibo?.venueJson, + kickoffJson: data.zhibo?.kickoffJson, + externalStatus: data.zhibo?.externalStatus, }, }); } + private async upsertEntityTranslations( + entityType: 'LEAGUE' | 'TEAM', + entityId: bigint, + translations: Record, + ) { + for (const [locale, value] of Object.entries(translations)) { + await this.prisma.entityTranslation.upsert({ + where: { + entityType_entityId_locale_fieldName: { + entityType, + entityId, + locale, + fieldName: 'name', + }, + }, + create: { entityType, entityId, locale, fieldName: 'name', value }, + update: { value }, + }); + } + } + + async upsertLeagueFromZhiboExport(league: ZhiboLeagueExport) { + const code = leagueCodeFromExport(league); + const record = await this.prisma.league.upsert({ + where: { code }, + create: { code, sportType: league.type || 'FOOTBALL' }, + update: { sportType: league.type || 'FOOTBALL' }, + }); + await this.upsertEntityTranslations('LEAGUE', record.id, { + 'zh-CN': league.zh, + 'en-US': league.en, + }); + return record; + } + + async upsertTeamFromZhiboExport(team: ZhiboTeamExport) { + const code = teamCodeFromExport(team); + const translations = translationsFromZhiboNames(team.names, team.name); + + let record = + team.id != null + ? await this.prisma.team.findFirst({ where: { externalId: team.id } }) + : await this.prisma.team.findUnique({ where: { code } }); + + if (!record) { + record = await this.prisma.team.create({ + data: { + code, + externalId: team.id ?? undefined, + logoUrl: team.image || undefined, + }, + }); + } else { + record = await this.prisma.team.update({ + where: { id: record.id }, + data: { + logoUrl: team.image || record.logoUrl, + externalId: team.id ?? record.externalId, + }, + }); + } + + await this.upsertEntityTranslations('TEAM', record.id, translations); + return record; + } + + private async findExistingZhiboMatch( + leagueId: bigint, + homeTeamId: bigint, + awayTeamId: bigint, + item: ZhiboMatchExport, + ) { + if (item.liveMatchId != null) { + return this.prisma.match.findUnique({ + where: { liveMatchId: BigInt(item.liveMatchId) }, + }); + } + if (item.officialMatchNo != null) { + return this.prisma.match.findFirst({ + where: { + leagueId, + homeTeamId, + awayTeamId, + officialMatchNo: item.officialMatchNo, + }, + }); + } + return null; + } + + async createPlatformMatch(data: { + leagueEn: string; + leagueZh: string; + homeTeamZh: string; + homeTeamEn: string; + awayTeamZh: string; + awayTeamEn: string; + startTime: Date; + isHot?: boolean; + displayOrder?: number; + createdBy?: bigint; + }) { + const homeEn = data.homeTeamEn.trim(); + const homeZh = data.homeTeamZh.trim(); + const awayEn = data.awayTeamEn.trim(); + const awayZh = data.awayTeamZh.trim(); + if ((!homeEn && !homeZh) || (!awayEn && !awayZh)) { + throw new BadRequestException('请填写主客队中英文名至少各一项'); + } + + const league = await this.upsertLeagueFromZhiboExport({ + type: 'FOOTBALL', + en: data.leagueEn.trim(), + zh: data.leagueZh.trim(), + }); + const [homeTeam, awayTeam] = await Promise.all([ + this.upsertTeamFromZhiboExport({ + id: null, + name: homeEn || homeZh, + names: { zh: homeZh || null, en: homeEn || null, zhTw: '', vi: null, km: null, ms: null }, + image: '', + }), + this.upsertTeamFromZhiboExport({ + id: null, + name: awayEn || awayZh, + names: { zh: awayZh || null, en: awayEn || null, zhTw: '', vi: null, km: null, ms: null }, + image: '', + }), + ]); + + return this.createMatch({ + leagueId: league.id, + homeTeamId: homeTeam.id, + awayTeamId: awayTeam.id, + startTime: data.startTime, + isHot: data.isHot ?? false, + displayOrder: data.displayOrder ?? 0, + createdBy: data.createdBy, + status: 'DRAFT', + zhibo: { + matchName: `${homeEn || homeZh} - ${awayEn || awayZh}`, + }, + }); + } + + private async requireAdminMatch(matchId: bigint) { + const match = await this.prisma.match.findFirst({ + where: { id: matchId, deletedAt: null }, + include: { homeTeam: true, awayTeam: true }, + }); + if (!match) throw new NotFoundException('赛事不存在'); + return match; + } + + async getAdminMatchDetail(matchId: bigint) { + const match = await this.requireAdminMatch(matchId); + const [leagueEn, leagueZh, homeEn, homeZh, awayEn, awayZh] = await Promise.all([ + this.getTranslation('LEAGUE', match.leagueId, 'en-US'), + this.getTranslation('LEAGUE', match.leagueId, 'zh-CN'), + this.getTranslation('TEAM', match.homeTeamId, 'en-US'), + this.getTranslation('TEAM', match.homeTeamId, 'zh-CN'), + this.getTranslation('TEAM', match.awayTeamId, 'en-US'), + this.getTranslation('TEAM', match.awayTeamId, 'zh-CN'), + ]); + return { + id: match.id.toString(), + status: match.status, + isOutright: match.isOutright, + isHot: match.isHot, + startTime: match.startTime.toISOString(), + leagueEn, + leagueZh, + homeTeamEn: homeEn, + homeTeamZh: homeZh, + awayTeamEn: awayEn, + awayTeamZh: awayZh, + matchName: match.matchName ?? '', + }; + } + + async updatePlatformMatch( + matchId: bigint, + data: { + leagueEn: string; + leagueZh: string; + homeTeamZh: string; + homeTeamEn: string; + awayTeamZh: string; + awayTeamEn: string; + startTime: Date; + isHot?: boolean; + displayOrder?: number; + updatedBy?: bigint; + }, + ) { + const match = await this.requireAdminMatch(matchId); + if (match.isOutright) { + throw new BadRequestException('冠军盘请通过盘口管理维护'); + } + if (!['DRAFT', 'PUBLISHED'].includes(match.status)) { + throw new BadRequestException('当前状态不可编辑'); + } + + const matchName = `${data.homeTeamEn.trim() || data.homeTeamZh.trim()} - ${data.awayTeamEn.trim() || data.awayTeamZh.trim()}`; + + await Promise.all([ + this.upsertEntityTranslations('LEAGUE', match.leagueId, { + 'zh-CN': data.leagueZh.trim(), + 'en-US': data.leagueEn.trim(), + }), + this.upsertEntityTranslations('TEAM', match.homeTeamId, { + 'zh-CN': data.homeTeamZh.trim(), + 'en-US': data.homeTeamEn.trim(), + }), + this.upsertEntityTranslations('TEAM', match.awayTeamId, { + 'zh-CN': data.awayTeamZh.trim(), + 'en-US': data.awayTeamEn.trim(), + }), + ]); + + return this.prisma.match.update({ + where: { id: matchId }, + data: { + startTime: data.startTime, + isHot: data.isHot ?? match.isHot, + displayOrder: data.displayOrder ?? match.displayOrder, + matchName, + updatedBy: data.updatedBy, + }, + }); + } + + async deleteMatch(matchId: bigint) { + const match = await this.requireAdminMatch(matchId); + if (match.isOutright) { + throw new BadRequestException('冠军盘不可删除'); + } + if (match.status !== 'DRAFT') { + throw new BadRequestException('仅草稿状态可删除'); + } + const betCount = await this.prisma.betSelection.count({ where: { matchId } }); + if (betCount > 0) { + throw new BadRequestException('该赛事已有注单关联,无法删除'); + } + return this.prisma.match.update({ + where: { id: matchId }, + data: { deletedAt: new Date() }, + }); + } + + async createMatchFromZhiboExport( + item: ZhiboMatchExport, + createdBy?: bigint, + opts?: { asDraft?: boolean }, + ) { + const league = await this.upsertLeagueFromZhiboExport(item.league); + const [homeTeam, awayTeam] = await Promise.all([ + this.upsertTeamFromZhiboExport(item.homeTeam), + this.upsertTeamFromZhiboExport(item.awayTeam), + ]); + + const status = opts?.asDraft ? 'DRAFT' : resolveInternalStatus(item); + const startTime = resolveStartTime(item.kickoff); + const liveMatchId = + item.liveMatchId != null ? BigInt(item.liveMatchId) : undefined; + const payload = { + leagueId: league.id, + homeTeamId: homeTeam.id, + awayTeamId: awayTeam.id, + startTime, + isHot: resolveIsHot(item), + displayOrder: item.sortOrder, + createdBy, + status, + publishTime: status === 'PUBLISHED' ? new Date() : undefined, + zhibo: { + officialMatchNo: item.officialMatchNo, + stage: item.stage, + groupName: item.groupName, + liveMatchId, + additionMatchId: item.additionMatchId != null ? BigInt(item.additionMatchId) : null, + channelId: item.channelId, + matchName: item.matchName, + venueJson: toVenueJson(item.venue), + kickoffJson: toKickoffJson(item.kickoff), + externalStatus: item.status.state, + }, + }; + + const existing = await this.findExistingZhiboMatch( + league.id, + homeTeam.id, + awayTeam.id, + item, + ); + if (existing) { + return this.prisma.match.update({ + where: { id: existing.id }, + data: { + leagueId: payload.leagueId, + homeTeamId: payload.homeTeamId, + awayTeamId: payload.awayTeamId, + startTime: payload.startTime, + isHot: payload.isHot, + displayOrder: payload.displayOrder, + status: payload.status, + publishTime: existing.publishTime ?? payload.publishTime, + officialMatchNo: payload.zhibo.officialMatchNo, + stage: payload.zhibo.stage, + groupName: payload.zhibo.groupName, + liveMatchId: payload.zhibo.liveMatchId ?? undefined, + additionMatchId: payload.zhibo.additionMatchId ?? undefined, + channelId: payload.zhibo.channelId ?? undefined, + matchName: payload.zhibo.matchName, + venueJson: payload.zhibo.venueJson, + kickoffJson: payload.zhibo.kickoffJson, + externalStatus: payload.zhibo.externalStatus, + updatedBy: createdBy, + }, + }); + } + + return this.createMatch(payload); + } + + async importZhiboMatchesBundle(bundle: ZhiboMatchesBundleExport, createdBy?: bigint) { + if (!bundle.matches?.length) { + throw new BadRequestException('matches array is required'); + } + + const results: Array<{ liveMatchId: string; id: string; status: string; skipped?: boolean; reason?: string }> = []; + + for (const item of bundle.matches) { + try { + const match = await this.createMatchFromZhiboExport(item, createdBy, { asDraft: true }); + results.push({ + liveMatchId: item.liveMatchId != null ? String(item.liveMatchId) : '', + id: match.id.toString(), + status: match.status, + }); + } catch (err) { + const message = err instanceof Error ? err.message : 'import failed'; + results.push({ + liveMatchId: item.liveMatchId != null ? String(item.liveMatchId) : '', + id: '', + status: 'error', + reason: message, + }); + } + } + + return { + total: bundle.matches.length, + imported: results.filter((r) => !r.skipped && r.status !== 'error').length, + skipped: results.filter((r) => r.skipped).length, + failed: results.filter((r) => r.status === 'error').length, + results, + }; + } + async publishMatch(matchId: bigint) { return this.prisma.match.update({ where: { id: matchId }, diff --git a/apps/api/src/domains/catalog/zhibo-match.mapper.ts b/apps/api/src/domains/catalog/zhibo-match.mapper.ts new file mode 100644 index 0000000..85858b0 --- /dev/null +++ b/apps/api/src/domains/catalog/zhibo-match.mapper.ts @@ -0,0 +1,64 @@ +import { Prisma } from '@prisma/client'; +import type { ZhiboLeagueExport, ZhiboMatchExport, ZhiboTeamExport } from './zhibo-match.types'; + +const LOCALE_MAP: Record = { + zh: 'zh-CN', + en: 'en-US', + ms: 'ms-MY', +}; + +export function slugTeamCode(name: string): string { + return name + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') + .replace(/[^a-zA-Z0-9]+/g, '_') + .replace(/^_|_$/g, '') + .toUpperCase() + .slice(0, 48) || 'TEAM'; +} + +export function teamCodeFromExport(team: ZhiboTeamExport): string { + if (team.id != null) return `ZIBO_${team.id}`; + return `NAME_${slugTeamCode(team.name)}`; +} + +export function leagueCodeFromExport(league: ZhiboLeagueExport): string { + if (league.en.includes('World Cup 2026')) return 'WC2026'; + return slugTeamCode(league.en).slice(0, 32); +} + +export function translationsFromZhiboNames( + names: ZhiboTeamExport['names'], + fallbackEn: string, +): Record { + const out: Record = {}; + for (const [key, locale] of Object.entries(LOCALE_MAP)) { + const v = names[key as keyof typeof names]; + if (typeof v === 'string' && v.trim()) out[locale] = v.trim(); + } + if (!out['en-US'] && fallbackEn) out['en-US'] = fallbackEn; + if (!out['zh-CN'] && names.zh) out['zh-CN'] = names.zh; + return out; +} + +export function resolveStartTime(kickoff: ZhiboMatchExport['kickoff']): Date { + if (kickoff.utcIso) return new Date(kickoff.utcIso); + return new Date(kickoff.utcTimeStart * 1000); +} + +export function resolveInternalStatus(item: ZhiboMatchExport): string { + if (!item.isPublished || item.status.state === 'off') return 'DRAFT'; + return 'PUBLISHED'; +} + +export function resolveIsHot(item: ZhiboMatchExport): boolean { + return (item.status.isHot ?? 0) > 0; +} + +export function toKickoffJson(kickoff: ZhiboMatchExport['kickoff']): Prisma.InputJsonValue { + return kickoff as unknown as Prisma.InputJsonValue; +} + +export function toVenueJson(venue: ZhiboMatchExport['venue']): Prisma.InputJsonValue { + return venue as unknown as Prisma.InputJsonValue; +} diff --git a/apps/api/src/domains/catalog/zhibo-match.types.ts b/apps/api/src/domains/catalog/zhibo-match.types.ts new file mode 100644 index 0000000..54efd70 --- /dev/null +++ b/apps/api/src/domains/catalog/zhibo-match.types.ts @@ -0,0 +1,67 @@ +/** zhibo 导出(world_cup_match_ext + live_matches)对齐结构 */ + +export interface ZhiboLocalizedNames { + zh?: string | null; + en?: string | null; + zhTw?: string | null; + vi?: string | null; + km?: string | null; + ms?: string | null; +} + +export interface ZhiboLeagueExport { + type: string; + en: string; + zh: string; +} + +export interface ZhiboKickoffExport { + utcTimeStart: number; + utcTimeStop: number; + utcIso: string; + chinaTime: string; + venueTime: string; + venueTimezone: string; +} + +export interface ZhiboTeamExport { + id: number | null; + name: string; + names: ZhiboLocalizedNames; + image: string; +} + +export interface ZhiboMatchExport { + officialMatchNo: number; + stage: string; + groupName: string; + liveMatchId: number | null; + additionMatchId: number | null; + channelId: string | null; + matchName: string; + league: ZhiboLeagueExport; + kickoff: ZhiboKickoffExport; + homeTeam: ZhiboTeamExport; + awayTeam: ZhiboTeamExport; + score: { home: number | string | null; away: number | string | null }; + status: { + state: string; + nowPlaying: number; + isLive: number; + isHot: number; + }; + venue: { + names: ZhiboLocalizedNames; + city: ZhiboLocalizedNames; + }; + sortOrder: number; + isPublished: boolean; +} + +export interface ZhiboMatchesBundleExport { + exportedAt?: string; + source?: Record; + count?: number; + groups?: string[]; + matches: ZhiboMatchExport[]; +} diff --git a/apps/api/src/domains/identity/users.module.ts b/apps/api/src/domains/identity/users.module.ts index 8fa904f..6004921 100644 --- a/apps/api/src/domains/identity/users.module.ts +++ b/apps/api/src/domains/identity/users.module.ts @@ -1,7 +1,9 @@ import { Module } from '@nestjs/common'; import { UsersService } from './users.service'; +import { AgentsModule } from '../agent/agents.module'; @Module({ + imports: [AgentsModule], providers: [UsersService], exports: [UsersService], }) diff --git a/apps/api/src/domains/identity/users.service.ts b/apps/api/src/domains/identity/users.service.ts index e340c11..21c71f2 100644 --- a/apps/api/src/domains/identity/users.service.ts +++ b/apps/api/src/domains/identity/users.service.ts @@ -1,9 +1,77 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from '../../shared/prisma/prisma.service'; +import { AgentsService } from '../agent/agents.service'; + +export type PlayerListFilters = { + keyword?: string; + parentId?: bigint; + status?: string; +}; @Injectable() export class UsersService { - constructor(private prisma: PrismaService) {} + constructor( + private prisma: PrismaService, + private agents: AgentsService, + ) {} + + private formatPlayerRow( + u: { + id: bigint; + username: string; + status: string; + locale: string; + parentId: bigint | null; + createdAt: Date; + updatedAt: Date; + wallet?: { availableBalance: { toString(): string }; frozenBalance: { toString(): string } } | null; + preferences?: { phone: string | null; email: string | null } | null; + parent?: { username: string } | null; + auth?: { lastLoginAt: Date | null } | null; + }, + bet?: { count: number; totalStake: string; totalReturn: string }, + ) { + return { + id: u.id.toString(), + username: u.username, + status: u.status, + locale: u.locale, + parentId: u.parentId?.toString() ?? null, + parentUsername: u.parent?.username ?? null, + phone: u.preferences?.phone ?? null, + email: u.preferences?.email ?? null, + availableBalance: u.wallet?.availableBalance?.toString() ?? '0', + frozenBalance: u.wallet?.frozenBalance?.toString() ?? '0', + lastLoginAt: u.auth?.lastLoginAt ?? null, + betCount: bet?.count ?? 0, + totalStake: bet?.totalStake ?? '0', + totalReturn: bet?.totalReturn ?? '0', + createdAt: u.createdAt, + updatedAt: u.updatedAt, + }; + } + + private async loadBetStatsMap(userIds: bigint[]) { + if (userIds.length === 0) return new Map(); + + const groups = await this.prisma.bet.groupBy({ + by: ['userId'], + where: { userId: { in: userIds } }, + _count: { _all: true }, + _sum: { stake: true, actualReturn: true }, + }); + + return new Map( + groups.map((g) => [ + g.userId.toString(), + { + count: g._count._all, + totalStake: g._sum.stake?.toString() ?? '0', + totalReturn: g._sum.actualReturn?.toString() ?? '0', + }, + ]), + ); + } async findById(id: bigint) { return this.prisma.user.findUnique({ @@ -36,19 +104,170 @@ export class UsersService { return { locale }; } - async listPlayers(page = 1, pageSize = 20, parentId?: bigint) { - const where = { userType: 'PLAYER', ...(parentId ? { parentId } : {}) }; + async listPlayers( + page = 1, + pageSize = 10, + filters: PlayerListFilters = {}, + ) { + const where: { + userType: string; + deletedAt: null; + parentId?: bigint; + status?: string; + OR?: { username?: { contains: string; mode: 'insensitive' } }[]; + } = { + userType: 'PLAYER', + deletedAt: null, + }; + if (filters.parentId) where.parentId = filters.parentId; + if (filters.status) where.status = filters.status; + if (filters.keyword?.trim()) { + const kw = filters.keyword.trim(); + where.OR = [{ username: { contains: kw, mode: 'insensitive' } }]; + } + const skip = (page - 1) * pageSize; - const [items, total] = await Promise.all([ + const [rows, total] = await Promise.all([ this.prisma.user.findMany({ where, - include: { wallet: true }, + include: { + wallet: true, + preferences: true, + parent: { select: { id: true, username: true } }, + auth: { select: { lastLoginAt: true } }, + }, skip, take: pageSize, orderBy: { createdAt: 'desc' }, }), this.prisma.user.count({ where }), ]); - return { items, total, page, pageSize }; + + const betMap = await this.loadBetStatsMap(rows.map((r) => r.id)); + return { + items: rows.map((u) => this.formatPlayerRow(u, betMap.get(u.id.toString()))), + total, + page, + pageSize, + }; + } + + async getPlayerAdminDetail(playerId: bigint) { + const user = await this.prisma.user.findFirst({ + where: { id: playerId, userType: 'PLAYER', deletedAt: null }, + include: { + wallet: true, + preferences: true, + parent: { select: { id: true, username: true, agentLevel: true } }, + auth: { select: { lastLoginAt: true, loginFailCount: true, lockedUntil: true } }, + }, + }); + if (!user) throw new NotFoundException('玩家不存在'); + + const [betCount, betStake] = await Promise.all([ + this.prisma.bet.count({ where: { userId: playerId } }), + this.prisma.bet.aggregate({ + where: { userId: playerId }, + _sum: { stake: true, actualReturn: true }, + }), + ]); + + return { + ...this.formatPlayerRow(user), + lastLoginAt: user.auth?.lastLoginAt ?? null, + loginFailCount: user.auth?.loginFailCount ?? 0, + lockedUntil: user.auth?.lockedUntil ?? null, + betCount, + totalStake: betStake._sum.stake?.toString() ?? '0', + totalReturn: betStake._sum.actualReturn?.toString() ?? '0', + }; + } + + async updatePlayerAdmin( + playerId: bigint, + data: { + status?: string; + locale?: string; + phone?: string; + email?: string; + parentId?: string | null; + }, + ) { + const user = await this.prisma.user.findFirst({ + where: { id: playerId, userType: 'PLAYER', deletedAt: null }, + }); + if (!user) throw new NotFoundException('玩家不存在'); + + if (data.status && !['ACTIVE', 'SUSPENDED'].includes(data.status)) { + throw new BadRequestException('无效状态'); + } + + if (data.status) { + await this.prisma.user.update({ + where: { id: playerId }, + data: { status: data.status }, + }); + } + + if (data.parentId !== undefined) { + const newParentId = + data.parentId === null || data.parentId === '' + ? null + : BigInt(data.parentId); + + if (newParentId !== null) { + const parent = await this.prisma.user.findUnique({ + where: { id: newParentId }, + }); + if (!parent || parent.userType !== 'AGENT') { + throw new BadRequestException('上级必须为代理账号'); + } + } + + const oldParentId = user.parentId; + const changed = + (oldParentId?.toString() ?? null) !== (newParentId?.toString() ?? null); + + if (changed) { + await this.prisma.user.update({ + where: { id: playerId }, + data: { parentId: newParentId }, + }); + if (oldParentId) { + await this.agents.recalculateUsedCredit(oldParentId); + } + if (newParentId) { + await this.agents.recalculateUsedCredit(newParentId); + } + } + } + + if (data.locale) { + await this.prisma.user.update({ + where: { id: playerId }, + data: { locale: data.locale }, + }); + } + + if (data.phone !== undefined || data.email !== undefined || data.locale) { + const phone = data.phone !== undefined ? data.phone?.trim() || null : undefined; + const email = data.email !== undefined ? data.email?.trim() || null : undefined; + await this.prisma.userPreference.upsert({ + where: { userId: playerId }, + create: { + userId: playerId, + locale: data.locale ?? user.locale, + phone: phone ?? null, + email: email ?? null, + }, + update: { + ...(data.locale ? { locale: data.locale } : {}), + ...(phone !== undefined ? { phone } : {}), + ...(email !== undefined ? { email } : {}), + }, + }); + } + + return this.getPlayerAdminDetail(playerId); } } diff --git a/apps/api/src/domains/operations/audit/audit.service.ts b/apps/api/src/domains/operations/audit/audit.service.ts index f6081c7..4f0eda1 100644 --- a/apps/api/src/domains/operations/audit/audit.service.ts +++ b/apps/api/src/domains/operations/audit/audit.service.ts @@ -31,7 +31,7 @@ export class AuditService { }); } - async list(page = 1, pageSize = 50, module?: string) { + async list(page = 1, pageSize = 10, module?: string) { const skip = (page - 1) * pageSize; const where = module ? { module } : {}; const [items, total] = await Promise.all([ diff --git a/apps/player/src/assets/images/足球赛事下注背景框.png b/apps/player/src/assets/images/足球赛事下注背景框.png new file mode 100644 index 0000000000000000000000000000000000000000..a7de43b22e4553e7c7fe18e60c47532bf03bb8f4 GIT binary patch literal 161266 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

X7%d-q%s;a}mAnAItEN|+0j6QdnBV%p!>0PJX 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 + props.pick ? teamFlagUrl(props.pick.teamCode, props.pick.teamName) : null, +); + const balanceText = computed(() => formatMoney(balance.value, locale.value)); +const oddsNum = computed(() => { + if (!props.pick) return 0; + const n = parseFloat(props.pick.odds); + return Number.isFinite(n) ? n : 0; +}); + +const estReturn = computed(() => { + const s = Number(stake.value); + if (!s || s <= 0 || !oddsNum.value) return 0; + return s * oddsNum.value; +}); + +const estReturnText = computed(() => formatMoney(estReturn.value, locale.value)); + watch( () => props.open, async (v) => { @@ -56,8 +75,20 @@ function genRequestId() { return `${Date.now()}-${Math.random().toString(36).slice(2)}`; } +function setStake(amount: number) { + stake.value = Math.max(0.01, Math.round(amount * 100) / 100); +} + +function setMaxStake() { + if (balance.value > 0) setStake(balance.value); +} + async function submit() { if (!props.pick || stake.value <= 0) return; + if (stake.value > balance.value) { + error.value = t('bet.outright_insufficient'); + return; + } loading.value = true; error.value = ''; try { @@ -88,13 +119,26 @@ function formatOdds(odds: string) {