feat(catalog): 玩家端隐藏已结算赛事与冠军盘联赛
- listPublished/listUpcomingPublished 排除 SETTLED 及冠军盘已结算联赛 - outright.listForPlayer 仅返回 PUBLISHED - 首页 todayMatches 过滤 SETTLED;管理端已结算冠军盘隐藏下架按钮 - 补充 matches/outright 单测
This commit is contained in:
@@ -49,7 +49,7 @@ defineEmits<{
|
|||||||
{{ row.labels.publish }}
|
{{ row.labels.publish }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-else
|
v-else-if="!row.isOutrightSettled"
|
||||||
size="small"
|
size="small"
|
||||||
type="warning"
|
type="warning"
|
||||||
:loading="row.isPublishing"
|
:loading="row.isPublishing"
|
||||||
|
|||||||
@@ -198,7 +198,8 @@ export class PlayerController {
|
|||||||
const hotMatches = (allMatches as Array<{ isHot?: boolean; status?: string }>).filter(
|
const hotMatches = (allMatches as Array<{ isHot?: boolean; status?: string }>).filter(
|
||||||
(m) => m.isHot && m.status !== 'SETTLED',
|
(m) => m.isHot && m.status !== 'SETTLED',
|
||||||
);
|
);
|
||||||
const todayMatches = (allMatches as Array<{ startTime: string }>).filter((m) => {
|
const todayMatches = (allMatches as Array<{ startTime: string; status?: string }>).filter((m) => {
|
||||||
|
if (m.status === 'SETTLED') return false;
|
||||||
const kickoff = new Date(m.startTime);
|
const kickoff = new Date(m.startTime);
|
||||||
return !Number.isNaN(kickoff.getTime()) && isInLocalTodayMatchWindow(kickoff, now, timeZone);
|
return !Number.isNaN(kickoff.getTime()) && isInLocalTodayMatchWindow(kickoff, now, timeZone);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -267,6 +267,15 @@ describe('MatchesService listUpcomingPublished', () => {
|
|||||||
sportType: 'FOOTBALL',
|
sportType: 'FOOTBALL',
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
startTime: { gte: now, lte: end },
|
startTime: { gte: now, lte: end },
|
||||||
|
league: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
NOT: {
|
||||||
|
matches: {
|
||||||
|
some: { isOutright: true, status: 'SETTLED', deletedAt: null },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
orderBy: [{ startTime: 'asc' }, { displayOrder: 'asc' }],
|
orderBy: [{ startTime: 'asc' }, { displayOrder: 'asc' }],
|
||||||
take: 50,
|
take: 50,
|
||||||
@@ -302,6 +311,52 @@ describe('MatchesService listUpcomingPublished', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('MatchesService listPublished', () => {
|
||||||
|
let prisma: {
|
||||||
|
match: { findMany: jest.Mock };
|
||||||
|
entityTranslation: { findMany: jest.Mock };
|
||||||
|
};
|
||||||
|
let service: MatchesService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
prisma = {
|
||||||
|
match: { findMany: jest.fn().mockResolvedValue([]) },
|
||||||
|
entityTranslation: {
|
||||||
|
findMany: jest.fn().mockResolvedValue([]),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
service = new MatchesService(
|
||||||
|
prisma as never,
|
||||||
|
{ syncWithLeaguePublished: jest.fn() } as never,
|
||||||
|
{ betStatsForMatches: jest.fn().mockResolvedValue(new Map()) } as never,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('excludes settled fixtures and leagues with settled outright', async () => {
|
||||||
|
await service.listPublished('zh-CN', undefined, { includeMarkets: false });
|
||||||
|
|
||||||
|
expect(prisma.match.findMany).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
where: {
|
||||||
|
status: { in: ['PUBLISHED', 'CLOSED', 'PENDING_SETTLEMENT'] },
|
||||||
|
isOutright: false,
|
||||||
|
sportType: 'FOOTBALL',
|
||||||
|
deletedAt: null,
|
||||||
|
league: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
NOT: {
|
||||||
|
matches: {
|
||||||
|
some: { isOutright: true, status: 'SETTLED', deletedAt: null },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('MatchesService listAdminLeagueMatches', () => {
|
describe('MatchesService listAdminLeagueMatches', () => {
|
||||||
const leagueId = BigInt(1);
|
const leagueId = BigInt(1);
|
||||||
|
|
||||||
|
|||||||
@@ -1554,11 +1554,19 @@ export class MatchesService {
|
|||||||
|
|
||||||
const matches = await this.prisma.match.findMany({
|
const matches = await this.prisma.match.findMany({
|
||||||
where: {
|
where: {
|
||||||
status: { in: ['PUBLISHED', 'CLOSED', 'PENDING_SETTLEMENT', 'SETTLED'] },
|
status: { in: ['PUBLISHED', 'CLOSED', 'PENDING_SETTLEMENT'] },
|
||||||
isOutright: false,
|
isOutright: false,
|
||||||
sportType: 'FOOTBALL',
|
sportType: 'FOOTBALL',
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
league: { isActive: true, deletedAt: null },
|
league: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
NOT: {
|
||||||
|
matches: {
|
||||||
|
some: { isOutright: true, status: 'SETTLED', deletedAt: null },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
...(leagueId ? { leagueId } : {}),
|
...(leagueId ? { leagueId } : {}),
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
@@ -1602,7 +1610,15 @@ export class MatchesService {
|
|||||||
sportType: 'FOOTBALL',
|
sportType: 'FOOTBALL',
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
startTime: { gte: now, lte: end },
|
startTime: { gte: now, lte: end },
|
||||||
league: { isActive: true, deletedAt: null },
|
league: {
|
||||||
|
isActive: true,
|
||||||
|
deletedAt: null,
|
||||||
|
NOT: {
|
||||||
|
matches: {
|
||||||
|
some: { isOutright: true, status: 'SETTLED', deletedAt: null },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
league: true,
|
league: true,
|
||||||
|
|||||||
33
apps/api/src/domains/catalog/outright.service.spec.ts
Normal file
33
apps/api/src/domains/catalog/outright.service.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
jest.mock('./wc2026-outright.sync', () => ({
|
||||||
|
syncWc2026OutrightMarket: jest.fn().mockResolvedValue(undefined),
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { OutrightService } from './outright.service';
|
||||||
|
|
||||||
|
describe('OutrightService listForPlayer', () => {
|
||||||
|
let prisma: { match: { findMany: jest.Mock } };
|
||||||
|
let service: OutrightService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
prisma = {
|
||||||
|
match: { findMany: jest.fn().mockResolvedValue([]) },
|
||||||
|
};
|
||||||
|
service = new OutrightService(prisma as never, {} as never);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns only published outright markets for player browse', async () => {
|
||||||
|
await service.listForPlayer('zh-CN');
|
||||||
|
|
||||||
|
expect(prisma.match.findMany).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
where: expect.objectContaining({
|
||||||
|
status: 'PUBLISHED',
|
||||||
|
isOutright: true,
|
||||||
|
sportType: 'FOOTBALL',
|
||||||
|
deletedAt: null,
|
||||||
|
league: { isActive: true, deletedAt: null },
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -701,7 +701,7 @@ export class OutrightService {
|
|||||||
|
|
||||||
const matches = await this.prisma.match.findMany({
|
const matches = await this.prisma.match.findMany({
|
||||||
where: {
|
where: {
|
||||||
status: { in: ['PUBLISHED', 'SETTLED'] },
|
status: 'PUBLISHED',
|
||||||
isOutright: true,
|
isOutright: true,
|
||||||
sportType: 'FOOTBALL',
|
sportType: 'FOOTBALL',
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
|
|||||||
Reference in New Issue
Block a user