上传限制

This commit is contained in:
zhx 2026-05-19 19:39:29 +08:00
parent 9d3880a8aa
commit 3a96357b2a
4 changed files with 97 additions and 12 deletions

View File

@ -125,6 +125,12 @@ export async function pageResidentWheelDrawRecords(params: Record<string, any>)
});
}
export async function retryResidentWheelDrawRecord(id: number | string) {
return requestClient.post<Record<string, any>>(`${WHEEL_BASE}/record/retry`, {
id,
});
}
export async function getResidentSmashGoldenEggConfig(sysOrigin: string) {
return requestClient.get<Record<string, any>>(`${SMASH_GOLDEN_EGG_BASE}/config`, {
params: { sysOrigin },

View File

@ -90,7 +90,7 @@ const showOnlyErrors = ref(false);
const submitting = ref(false);
const droppedFilePathMap = new WeakMap<File, string>();
const uploadQueue: UploadTask[] = [];
const MAX_UPLOAD_CONCURRENCY = 2;
const MAX_UPLOAD_CONCURRENCY = 1;
let activeUploadCount = 0;
const giftTabOptions = GIFT_CONFIG_TAB_OPTIONS.map((item) => ({

View File

@ -117,7 +117,7 @@ const showOnlyErrors = ref(false);
const submitting = ref(false);
const droppedFilePathMap = new WeakMap<File, string>();
const uploadQueue: UploadTask[] = [];
const MAX_UPLOAD_CONCURRENCY = 2;
const MAX_UPLOAD_CONCURRENCY = 1;
let activeUploadCount = 0;
const propsTypeOptions = PROPS_RESOURCE_CONFIG_TYPES.map((item) => ({

View File

@ -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 | number | string>(null);
const pickerCategory = ref('CLASSIC');
const pickerRewardIndex = ref(-1);
const pickerRewardRecord = ref<null | Record<string, any>>(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<string, any>) {
return categoryProbability(category) === PROBABILITY_TOTAL ? 'success' : 'error';
}
function probabilityPercent(value: any) {
return ((Number(value || 0) * 100) / PROBABILITY_TOTAL).toFixed(4);
}
function normalizeReward(item: Record<string, any> | undefined, index: number) {
const value = item || {};
const rewardType = normalizeRewardTypeValue(value.rewardType);
@ -243,6 +254,7 @@ function normalizeReward(item: Record<string, any> | 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<string, any> | 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<string, any>, item: Record<string, any>
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<string, any>) {
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<string, any>) {
void loadRecords();
}
async function retryRecord(record: Record<string, any>) {
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<string, any>) {
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 }"
>
<template #bodyCell="{ column, index, record }">
<template v-if="column.key === 'enabled'">
@ -980,12 +1022,35 @@ watch(activePageTab, (value) => {
style="width: 120px"
/>
<span class="sub-text">
{{
(Number(record.probability || 0) / 100).toFixed(2)
}}%
{{ probabilityPercent(record.probability) }}%
</span>
</Space>
</template>
<template v-else-if="column.key === 'limit'">
<Space direction="vertical" size="small">
<Space align="center">
<span class="sub-text">总量</span>
<InputNumber
v-model:value="record.totalLimit"
:min="0"
:precision="0"
placeholder="不限"
style="width: 110px"
/>
<span class="sub-text">已占 {{ Number(record.issuedCount || 0) }}</span>
</Space>
<Space align="center">
<span class="sub-text">单用户</span>
<InputNumber
v-model:value="record.userLimit"
:min="0"
:precision="0"
placeholder="不限"
style="width: 110px"
/>
</Space>
</Space>
</template>
<template v-else-if="column.key === 'actions'">
<Button danger type="link" @click="clearResource(record)">
清空
@ -1018,7 +1083,9 @@ watch(activePageTab, (value) => {
allow-clear
:options="[
{ label: '成功', value: 'SUCCESS' },
{ label: '失败', value: 'FAILED' },
{ label: '发奖失败', value: 'FAILED' },
{ label: '扣款失败', value: 'PAY_FAILED' },
{ label: '发奖中', value: 'GRANTING' },
{ label: '处理中', value: 'PENDING' },
]"
placeholder="状态"
@ -1041,7 +1108,7 @@ watch(activePageTab, (value) => {
total: recordPage.total,
}"
row-key="id"
:scroll="{ x: 1680 }"
:scroll="{ x: 1790 }"
@change="handleRecordTableChange"
>
<template #bodyCell="{ column, record }">
@ -1065,7 +1132,7 @@ watch(activePageTab, (value) => {
</div>
</template>
<template v-else-if="column.key === 'probability'">
{{ (Number(record.probability || 0) / 100).toFixed(2) }}%
{{ probabilityPercent(record.probability) }}%
</template>
<template v-else-if="column.key === 'status'">
<Tag :color="statusColor(record.status)">{{ record.status || '-' }}</Tag>
@ -1073,7 +1140,19 @@ watch(activePageTab, (value) => {
<template v-else-if="column.key === 'errorMessage'">
{{ record.errorMessage || '-' }}
</template>
</template>
<template v-else-if="column.key === 'actions'">
<Button
v-if="String(record.status || '').toUpperCase() === 'FAILED'"
:loading="retryingRecordId === record.id"
size="small"
type="link"
@click="retryRecord(record)"
>
补发
</Button>
<span v-else class="sub-text">-</span>
</template>
</template>
</Table>
</TabPane>
</Tabs>