From 3a96357b2a2be79bc36e7303792d9f7f230ad2ae Mon Sep 17 00:00:00 2001 From: zhx Date: Tue, 19 May 2026 19:39:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/src/api/legacy/resident-activity.ts | 6 ++ .../operate/components/gift-batch-drawer.vue | 2 +- .../components/resource-batch-drawer.vue | 2 +- .../views/resident-activity/wheel-config.vue | 99 +++++++++++++++++-- 4 files changed, 97 insertions(+), 12 deletions(-) diff --git a/apps/src/api/legacy/resident-activity.ts b/apps/src/api/legacy/resident-activity.ts index 049d3b3..9c7d301 100644 --- a/apps/src/api/legacy/resident-activity.ts +++ b/apps/src/api/legacy/resident-activity.ts @@ -125,6 +125,12 @@ export async function pageResidentWheelDrawRecords(params: Record) }); } +export async function retryResidentWheelDrawRecord(id: number | string) { + return requestClient.post>(`${WHEEL_BASE}/record/retry`, { + id, + }); +} + export async function getResidentSmashGoldenEggConfig(sysOrigin: string) { return requestClient.get>(`${SMASH_GOLDEN_EGG_BASE}/config`, { params: { sysOrigin }, diff --git a/apps/src/views/operate/components/gift-batch-drawer.vue b/apps/src/views/operate/components/gift-batch-drawer.vue index 6fcc623..fe46f9e 100644 --- a/apps/src/views/operate/components/gift-batch-drawer.vue +++ b/apps/src/views/operate/components/gift-batch-drawer.vue @@ -90,7 +90,7 @@ const showOnlyErrors = ref(false); const submitting = ref(false); const droppedFilePathMap = new WeakMap(); const uploadQueue: UploadTask[] = []; -const MAX_UPLOAD_CONCURRENCY = 2; +const MAX_UPLOAD_CONCURRENCY = 1; let activeUploadCount = 0; const giftTabOptions = GIFT_CONFIG_TAB_OPTIONS.map((item) => ({ diff --git a/apps/src/views/props/components/resource-batch-drawer.vue b/apps/src/views/props/components/resource-batch-drawer.vue index e44d9fe..17c095a 100644 --- a/apps/src/views/props/components/resource-batch-drawer.vue +++ b/apps/src/views/props/components/resource-batch-drawer.vue @@ -117,7 +117,7 @@ const showOnlyErrors = ref(false); const submitting = ref(false); const droppedFilePathMap = new WeakMap(); const uploadQueue: UploadTask[] = []; -const MAX_UPLOAD_CONCURRENCY = 2; +const MAX_UPLOAD_CONCURRENCY = 1; let activeUploadCount = 0; const propsTypeOptions = PROPS_RESOURCE_CONFIG_TYPES.map((item) => ({ diff --git a/apps/src/views/resident-activity/wheel-config.vue b/apps/src/views/resident-activity/wheel-config.vue index 822dafa..5194c7d 100644 --- a/apps/src/views/resident-activity/wheel-config.vue +++ b/apps/src/views/resident-activity/wheel-config.vue @@ -23,6 +23,7 @@ import { import { getResidentWheelConfig, pageResidentWheelDrawRecords, + retryResidentWheelDrawRecord, saveResidentWheelCategoryConfig, } from '#/api/legacy/resident-activity'; import PropsSourceSelectDrawer from '#/views/operate/components/props-source-select-drawer.vue'; @@ -30,7 +31,7 @@ import { getAllowedSysOrigins } from '#/views/system/shared'; defineOptions({ name: 'ResidentWheelConfigPage' }); -const PROBABILITY_TOTAL = 10_000; +const PROBABILITY_TOTAL = 1_000_000; const WHEEL_CATEGORIES = [ { category: 'CLASSIC', @@ -95,6 +96,7 @@ function createReward(type = 'RESOURCE', sort = 1) { enabled: true, goldAmount: type === 'GOLD' ? 100 : 0, id: 0, + issuedCount: 0, probability: 0, rewardType: type, resourceId: null as null | number | string, @@ -103,6 +105,8 @@ function createReward(type = 'RESOURCE', sort = 1) { resourceUrl: '', rowKey: createRowKey(sort), sort, + totalLimit: 0, + userLimit: 0, }; } @@ -146,6 +150,7 @@ const loading = ref(false); const savingCategory = ref(''); const recordLoading = ref(false); const resourcePickerOpen = ref(false); +const retryingRecordId = ref(null); const pickerCategory = ref('CLASSIC'); const pickerRewardIndex = ref(-1); const pickerRewardRecord = ref>(null); @@ -169,8 +174,9 @@ const rewardColumns = [ { dataIndex: 'enabled', key: 'enabled', title: '启用', width: 80 }, { dataIndex: 'sort', key: 'sort', title: '位置', width: 90 }, { dataIndex: 'rewardType', key: 'rewardType', title: '类型', width: 130 }, - { dataIndex: 'reward', key: 'reward', title: '奖励', width: 620 }, + { dataIndex: 'reward', key: 'reward', title: '奖励', width: 560 }, { dataIndex: 'probability', key: 'probability', title: '概率', width: 180 }, + { dataIndex: 'limit', key: 'limit', title: '止损线', width: 280 }, { dataIndex: 'actions', key: 'actions', title: '操作', width: 90 }, ]; @@ -185,6 +191,7 @@ const recordColumns = [ { dataIndex: 'status', key: 'status', title: '状态', width: 110 }, { dataIndex: 'createTime', key: 'createTime', title: '时间', width: 180 }, { dataIndex: 'errorMessage', key: 'errorMessage', title: '失败原因', width: 260 }, + { dataIndex: 'actions', key: 'actions', title: '操作', width: 110 }, ]; const statusMeta = computed(() => { @@ -222,6 +229,10 @@ function categoryProbabilityColor(category: Record) { return categoryProbability(category) === PROBABILITY_TOTAL ? 'success' : 'error'; } +function probabilityPercent(value: any) { + return ((Number(value || 0) * 100) / PROBABILITY_TOTAL).toFixed(4); +} + function normalizeReward(item: Record | undefined, index: number) { const value = item || {}; const rewardType = normalizeRewardTypeValue(value.rewardType); @@ -243,6 +254,7 @@ function normalizeReward(item: Record | undefined, index: number) { enabled: value.enabled !== false, goldAmount: Number(value.goldAmount || 0), id: Number(value.id || 0), + issuedCount: Number(value.issuedCount || 0), probability: Number(value.probability || 0), rewardType, resourceId: resourceId || null, @@ -251,6 +263,8 @@ function normalizeReward(item: Record | undefined, index: number) { resourceUrl: String(value.resourceUrl || ''), rowKey: createRowKey(value.id || index + 1), sort: Number(value.sort || index + 1), + totalLimit: Number(value.totalLimit || 0), + userLimit: Number(value.userLimit || 0), }; } @@ -586,6 +600,14 @@ function validateReward(category: Record, item: Record message.warning(`${label} 概率不能小于 0`); return false; } + if (Number(item.totalLimit || 0) < 0) { + message.warning(`${label} 总量上限不能小于 0`); + return false; + } + if (Number(item.userLimit || 0) < 0) { + message.warning(`${label} 单用户上限不能小于 0`); + return false; + } if ( category.enabled !== false && item.enabled !== false && @@ -669,6 +691,8 @@ function categoryPayload(category: Record) { resourceType: rewardType === 'RESOURCE' ? String(item.resourceType || '') : '', resourceUrl: rewardType === 'RESOURCE' ? String(item.resourceUrl || '') : '', sort: Number(item.sort || 0), + totalLimit: Number(item.totalLimit || 0), + userLimit: Number(item.userLimit || 0), }; }), }; @@ -715,6 +739,21 @@ function handleRecordTableChange(pagination: Record) { void loadRecords(); } +async function retryRecord(record: Record) { + const id = record?.id; + if (!id) { + return; + } + retryingRecordId.value = id; + try { + await retryResidentWheelDrawRecord(id); + message.success('补发成功'); + await loadRecords(); + } finally { + retryingRecordId.value = null; + } +} + function rewardRecordName(record: Record) { if (record.resourceName) { return record.resourceName; @@ -740,6 +779,9 @@ function statusColor(status: string) { case 'FAILED': { return 'error'; } + case 'PAY_FAILED': { + return 'warning'; + } case 'SUCCESS': { return 'success'; } @@ -875,7 +917,7 @@ watch(activePageTab, (value) => { :loading="loading" :pagination="false" row-key="rowKey" - :scroll="{ x: 1180 }" + :scroll="{ x: 1460 }" >