灵仙游戏

This commit is contained in:
170-carry 2026-04-28 18:05:01 +08:00
parent 7aed3ce16d
commit c35af900cd
6 changed files with 188 additions and 4 deletions

View File

@ -91,6 +91,15 @@ export async function saveSpecifiedGiftWeeklyRankConfig(data: Record<string, any
return requestClient.post(`${SPECIFIED_GIFT_WEEKLY_RANK_BASE}/config/save`, data);
}
export async function getSpecifiedGiftWeeklyRankCurrentRank(
params: Record<string, any>,
) {
return requestClient.get<Record<string, any>>(
`${SPECIFIED_GIFT_WEEKLY_RANK_BASE}/current-rank`,
{ params },
);
}
export async function pageSpecifiedGiftWeeklyRankSnapshots(params: Record<string, any>) {
return requestClient.get<LegacyPageResult<Record<string, any>>>(
`${SPECIFIED_GIFT_WEEKLY_RANK_BASE}/snapshot/page`,

View File

@ -58,6 +58,10 @@ const profileOptions = [
{ label: '正式环境', value: 'PROD' },
{ label: '测试环境', value: 'TEST' },
];
const importShowcaseOptions = [
{ label: '默认上架', value: true as any },
{ label: '默认下架', value: false as any },
];
const contextQuery = reactive({ profile: 'PROD', sysOrigin: '' });
const providerForm = reactive(createProviderForm());
@ -77,6 +81,7 @@ const totalCatalog = ref(0);
const catalogList = ref<Array<Record<string, any>>>([]);
const selectedCatalogKeys = ref<Array<number>>([]);
const activeProfile = ref('PROD');
const importDefaultShowcase = ref(true as any);
const isCurrentProfileActive = computed(
() => activeProfile.value === contextQuery.profile,
@ -308,6 +313,7 @@ async function handleImportSelected() {
profile: contextQuery.profile,
sysOrigin: contextQuery.sysOrigin,
vendorGameIds: selectedCatalogKeys.value,
defaultShowcase: importDefaultShowcase.value,
});
selectedCatalogKeys.value = [];
message.success(
@ -452,6 +458,11 @@ async function handleImportSelected() {
<Button :loading="catalogFetching" @click="handleFetchCatalog">
重新获取目录
</Button>
<Select
v-model:value="importDefaultShowcase"
:options="importShowcaseOptions"
style="width: 120px"
/>
<Button
type="primary"
:loading="catalogImporting"

View File

@ -102,6 +102,10 @@ const showcaseOptions = [
{ label: '上架', value: 'true' as any },
{ label: '下架', value: 'false' as any },
];
const importShowcaseOptions = [
{ label: '默认上架', value: true as any },
{ label: '默认下架', value: false as any },
];
const clientOriginOptions = GAME_CLIENT_ORIGIN_OPTIONS.map((item) => ({
label: item.name,
value: item.value as any,
@ -158,6 +162,7 @@ const modalOpen = ref(false);
const gameList = ref<Array<Record<string, any>>>([]);
const catalogList = ref<Array<Record<string, any>>>([]);
const selectedCatalogKeys = ref<Array<number>>([]);
const importDefaultShowcase = ref(true as any);
const gameForm = reactive<Record<string, any>>(createGameForm());
const providerForm = reactive<Record<string, any>>(createProviderForm());
@ -439,6 +444,7 @@ async function handleImportSelected() {
const result = await importBaishunCatalog({
sysOrigin: contextQuery.sysOrigin,
vendorGameIds: selectedCatalogKeys.value,
defaultShowcase: importDefaultShowcase.value,
});
selectedCatalogKeys.value = [];
message.success(
@ -629,6 +635,11 @@ async function handleImportSelected() {
<Button :loading="catalogFetching" @click="handleFetchCatalog">
重新获取目录
</Button>
<Select
v-model:value="importDefaultShowcase"
:options="importShowcaseOptions"
style="width: 120px"
/>
<Button
type="primary"
:loading="catalogImporting"

View File

@ -40,6 +40,7 @@ function createProviderForm(sysOrigin = '') {
gameListUrl: defaultGameListUrl,
profile: 'PROD',
sysOrigin,
testRoomId: '',
testToken: '',
testUid: '',
};
@ -54,6 +55,10 @@ const profileOptions = [
{ label: '正式环境', value: 'PROD' },
{ label: '测试环境', value: 'TEST' },
];
const importShowcaseOptions = [
{ label: '默认上架', value: true as any },
{ label: '默认下架', value: false as any },
];
const contextQuery = reactive({ profile: 'PROD', sysOrigin: '' });
const providerForm = reactive(createProviderForm());
@ -73,6 +78,7 @@ const totalCatalog = ref(0);
const catalogList = ref<Array<Record<string, any>>>([]);
const selectedCatalogKeys = ref<Array<string>>([]);
const activeProfile = ref('PROD');
const importDefaultShowcase = ref(true as any);
const isCurrentProfileActive = computed(
() => activeProfile.value === contextQuery.profile,
@ -258,6 +264,7 @@ async function handleImportSelected() {
profile: contextQuery.profile,
sysOrigin: contextQuery.sysOrigin,
vendorGameIds: selectedCatalogKeys.value,
defaultShowcase: importDefaultShowcase.value,
});
selectedCatalogKeys.value = [];
message.success(
@ -315,6 +322,9 @@ async function handleImportSelected() {
type="password"
/>
</FormItem>
<FormItem label="RoomID">
<Input v-model:value="providerForm.testRoomId" placeholder="可选" />
</FormItem>
</div>
</CollapsePanel>
</Collapse>
@ -357,6 +367,11 @@ async function handleImportSelected() {
<Button :loading="catalogFetching" @click="handleFetchCatalog">
重新获取目录
</Button>
<Select
v-model:value="importDefaultShowcase"
:options="importShowcaseOptions"
style="width: 120px"
/>
<Button
type="primary"
:loading="catalogImporting"

View File

@ -6,6 +6,7 @@ import { useAccessStore } from '@vben/stores';
import { listGiftBySysOrigin } from '#/api/legacy/gift';
import {
getSpecifiedGiftWeeklyRankCurrentRank,
getSpecifiedGiftWeeklyRankConfig,
pageSpecifiedGiftWeeklyRankConfigs,
pageSpecifiedGiftWeeklyRankRewardRecords,
@ -103,6 +104,26 @@ const rewardLoading = ref(false);
const rewardTotal = ref(0);
const rewardList = ref<Array<Record<string, any>>>([]);
const rankLoading = ref(false);
const rankList = ref<Array<Record<string, any>>>([]);
const rankMeta = reactive<{
activityStatus: string;
configId: string;
cycleKey: string;
giftConfigs: Array<Record<string, any>>;
periodEndAt: string;
periodStartAt: string;
timezone: string;
}>({
activityStatus: '',
configId: '',
cycleKey: '',
giftConfigs: [],
periodEndAt: '',
periodStartAt: '',
timezone: 'Asia/Riyadh',
});
const form = reactive<Record<string, any>>(createEmptyForm());
const configQuery = reactive({
@ -125,6 +146,10 @@ const rewardQuery = reactive({
status: '',
});
const rankQuery = reactive({
limit: 20,
});
const rewardStatusOptions = [
{ label: '成功', value: 'SUCCESS' },
{ label: '失败', value: 'FAILED' },
@ -155,6 +180,13 @@ const snapshotColumns = [
{ dataIndex: 'period', key: 'period', title: '结算区间', width: 320 },
];
const rankColumns = [
{ dataIndex: 'rank', key: 'rank', title: '名次', width: 90 },
{ dataIndex: 'user', key: 'user', title: '用户', width: 280 },
{ dataIndex: 'countryName', key: 'countryName', title: '国家', width: 150 },
{ dataIndex: 'scoreGold', key: 'scoreGold', title: '当前金币积分', width: 160 },
];
const rewardColumns = [
{ dataIndex: 'cycleKey', key: 'cycleKey', title: '周期', width: 140 },
{ dataIndex: 'rank', key: 'rank', title: '名次', width: 90 },
@ -301,6 +333,39 @@ async function loadConfigDetail(id: number | string) {
}
}
async function loadCurrentRank() {
if (!selectedSysOrigin.value) {
rankList.value = [];
Object.assign(rankMeta, {
activityStatus: '',
configId: '',
cycleKey: '',
giftConfigs: [],
periodEndAt: '',
periodStartAt: '',
timezone: 'Asia/Riyadh',
});
return;
}
rankLoading.value = true;
try {
const result = await getSpecifiedGiftWeeklyRankCurrentRank({
limit: rankQuery.limit,
sysOrigin: selectedSysOrigin.value,
});
rankList.value = Array.isArray(result.records) ? result.records : [];
rankMeta.activityStatus = String(result.activityStatus || '');
rankMeta.configId = String(result.configId || '');
rankMeta.cycleKey = String(result.cycleKey || '');
rankMeta.giftConfigs = Array.isArray(result.giftConfigs) ? result.giftConfigs : [];
rankMeta.periodEndAt = String(result.periodEndAt || '');
rankMeta.periodStartAt = String(result.periodStartAt || '');
rankMeta.timezone = String(result.timezone || 'Asia/Riyadh');
} finally {
rankLoading.value = false;
}
}
async function loadSnapshots(reset = false) {
if (!selectedSysOrigin.value) {
snapshotList.value = [];
@ -346,7 +411,12 @@ async function loadRewardRecords(reset = false) {
}
async function reloadPageData() {
await Promise.all([loadConfigList(true), loadSnapshots(true), loadRewardRecords(true)]);
await Promise.all([
loadConfigList(true),
loadCurrentRank(),
loadSnapshots(true),
loadRewardRecords(true),
]);
}
function syncGiftSelection(slot: Record<string, any>, giftId: number | string | undefined) {
@ -660,6 +730,74 @@ watch(
</div>
</Card>
<Card :bordered="false" class="mt-16" title="当前排行榜">
<Space class="toolbar" wrap>
<Tag :color="statusColor(rankMeta.activityStatus)">
{{ configStatusTextMap[rankMeta.activityStatus] || rankMeta.activityStatus || '未配置' }}
</Tag>
<Tag color="processing">{{ rankMeta.cycleKey || '-' }}</Tag>
<Tag>{{ rankMeta.timezone || '-' }}</Tag>
<span class="sub-text">
{{ rankMeta.periodStartAt || '-' }} ~ {{ rankMeta.periodEndAt || '-' }}
</span>
<div class="tag-stack">
<Tag
v-for="item in rankMeta.giftConfigs"
:key="`${rankMeta.configId}-${item.giftId}`"
color="gold"
>
{{ item.giftName || item.giftId }}
</Tag>
</div>
<Select
v-model:value="rankQuery.limit"
:options="[
{ label: 'Top 20', value: 20 },
{ label: 'Top 50', value: 50 },
{ label: 'Top 100', value: 100 },
]"
style="width: 120px"
@change="loadCurrentRank"
/>
<Button :loading="rankLoading" type="primary" @click="loadCurrentRank">
刷新排行
</Button>
</Space>
<Table
:columns="rankColumns"
:data-source="rankList"
:loading="rankLoading"
:pagination="false"
row-key="userId"
:scroll="{ x: 680 }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'user'">
<div class="user-cell">
<Image
v-if="record.userAvatar"
:preview="false"
:src="record.userAvatar"
class="avatar"
/>
<div v-else class="avatar placeholder">U</div>
<div class="user-meta">
<div>{{ record.userNickname || '-' }}</div>
<div class="sub-text">
{{ record.account || record.userId }}
<span v-if="record.countryCode"> · {{ record.countryCode }}</span>
</div>
</div>
</div>
</template>
<template v-else-if="column.key === 'countryName'">
{{ record.countryName || record.countryCode || '-' }}
</template>
</template>
</Table>
</Card>
<Card :bordered="false" class="mt-16" title="上周快照">
<Space class="toolbar" wrap>
<Select

View File

@ -274,7 +274,7 @@ INSERT INTO sys_menu (
SELECT
1700000256,
(SELECT id FROM sys_menu WHERE alias = 'ResidentActivityManager' LIMIT 1),
'指定礼物周榜',
'周星',
'resident-activity/week-star/index',
2,
'form',
@ -299,7 +299,7 @@ SET
LIMIT 1
) AS resident_menu
),
menu_name = '指定礼物周榜',
menu_name = '周星',
path = 'resident-activity/week-star/index',
menu_type = 2,
icon = 'form',
@ -482,7 +482,7 @@ SET menu_name = CONVERT(0xE98280E8AFB7E6B4BBE58AA8E58897E8A1A8 USING utf8mb4)
WHERE alias = 'ResidentInviteList';
UPDATE sys_menu
SET menu_name = CONVERT(0xE68C87E5AE9AE7A4BCE789A9E591A8E6A69C USING utf8mb4)
SET menu_name = CONVERT(0xE591A8E6989F USING utf8mb4)
WHERE alias = 'ResidentSpecifiedGiftWeeklyRank';
UPDATE sys_menu