持续模拟

This commit is contained in:
zhx 2026-05-25 21:19:16 +08:00
parent bdd3a99bba
commit 42c88e6282
2 changed files with 258 additions and 2 deletions

View File

@ -6,3 +6,22 @@ export async function simulateRegionBroadcast(data: Record<string, any>) {
data,
);
}
export async function getRegionBroadcastWorkerStatus() {
return requestClient.get<Record<string, any>>(
'/go/operate/region-broadcast/worker/status',
);
}
export async function startRegionBroadcastWorker(data: Record<string, any>) {
return requestClient.post<Record<string, any>>(
'/go/operate/region-broadcast/worker/start',
data,
);
}
export async function stopRegionBroadcastWorker() {
return requestClient.post<Record<string, any>>(
'/go/operate/region-broadcast/worker/stop',
);
}

View File

@ -4,7 +4,13 @@ import { computed, reactive, ref, watch } from 'vue';
import { Page } from '@vben/common-ui';
import { useAccessStore } from '@vben/stores';
import { simulateRegionBroadcast } from '#/api/legacy/region-broadcast';
import {
getRegionBroadcastWorkerStatus,
simulateRegionBroadcast,
startRegionBroadcastWorker,
stopRegionBroadcastWorker,
} from '#/api/legacy/region-broadcast';
import { regionConfigTable } from '#/api/legacy/system';
import { getAllowedSysOrigins } from '#/views/system/shared';
import SystemRegionSelect from './components/system-region-select.vue';
@ -12,9 +18,13 @@ import SystemRegionSelect from './components/system-region-select.vue';
import {
Button,
Card,
Checkbox,
Form,
FormItem,
Input,
InputNumber,
Descriptions,
DescriptionsItem,
Select,
Space,
TextArea,
@ -58,7 +68,24 @@ const form = reactive<Record<string, any>>({
});
const sending = ref(false);
const workerLoading = ref(false);
const resultText = ref('');
const regionLoading = ref(false);
const regionOptions = ref<Array<Record<string, any>>>([]);
const workerStatus = ref<Record<string, any>>({});
const workerForm = reactive<Record<string, any>>({
betAmounts: '100,200,500,1000',
enableGameWin: true,
enableLuckyGift: true,
gameWinAmounts: '1000,2000,5000,10000',
giftCandyOptions: '100,200,500',
giftQuantityOptions: '1,5,10',
luckyGiftWinAmounts: '1000,2000,5000,10000',
maxDelaySeconds: 20,
minDelaySeconds: 0,
multiples: '10,20,50,100',
regionCodes: [] as string[],
});
const isLuckyGift = computed(() => form.kind === 'LUCKY_GIFT');
@ -74,12 +101,36 @@ watch(
watch(
() => form.sysOrigin,
() => {
(value) => {
form.regionId = '';
form.regionCode = '';
workerForm.regionCodes = [];
if (value) {
void loadRegions();
void refreshWorkerStatus();
}
},
);
async function loadRegions() {
if (!form.sysOrigin) {
regionOptions.value = [];
return;
}
regionLoading.value = true;
try {
const list = await regionConfigTable({ sysOrigin: form.sysOrigin });
regionOptions.value = (list || [])
.map((item) => ({
label: item.regionName || item.regionCode || item.code || String(item.id),
value: item.regionCode || item.code || '',
}))
.filter((item) => item.value);
} finally {
regionLoading.value = false;
}
}
function handleRegionChange(_value: any, item: Record<string, any> | null) {
form.regionCode = item?.regionCode || item?.code || '';
}
@ -143,6 +194,80 @@ async function handleSend() {
sending.value = false;
}
}
function parseIntList(value: any) {
return String(value || '')
.split(/[,\s]+/)
.map((item) => Number(item.trim()))
.filter((item) => Number.isFinite(item) && item > 0)
.map((item) => Math.trunc(item));
}
function parseFloatList(value: any) {
return String(value || '')
.split(/[,\s]+/)
.map((item) => Number(item.trim()))
.filter((item) => Number.isFinite(item) && item > 0);
}
function buildWorkerPayload() {
return {
betAmounts: parseIntList(workerForm.betAmounts),
enableGameWin: Boolean(workerForm.enableGameWin),
enableLuckyGift: Boolean(workerForm.enableLuckyGift),
gameWinAmounts: parseIntList(workerForm.gameWinAmounts),
giftCandyOptions: parseIntList(workerForm.giftCandyOptions),
giftQuantityOptions: parseIntList(workerForm.giftQuantityOptions),
luckyGiftWinAmounts: parseIntList(workerForm.luckyGiftWinAmounts),
maxDelaySeconds: Number(workerForm.maxDelaySeconds || 0),
minDelaySeconds: Number(workerForm.minDelaySeconds || 0),
multiples: parseFloatList(workerForm.multiples),
regionCodes: workerForm.regionCodes || [],
sysOrigin: form.sysOrigin,
};
}
async function refreshWorkerStatus() {
workerLoading.value = true;
try {
workerStatus.value = (await getRegionBroadcastWorkerStatus()) || {};
} finally {
workerLoading.value = false;
}
}
async function handleStartWorker() {
const payload = buildWorkerPayload();
if (!payload.sysOrigin) {
message.warning('请选择系统来源');
return;
}
if (!payload.regionCodes.length) {
message.warning('请至少选择一个区域');
return;
}
if (!payload.enableGameWin && !payload.enableLuckyGift) {
message.warning('请至少开启一种飘屏');
return;
}
workerLoading.value = true;
try {
workerStatus.value = (await startRegionBroadcastWorker(payload)) || {};
message.success('持续模拟已启动');
} finally {
workerLoading.value = false;
}
}
async function handleStopWorker() {
workerLoading.value = true;
try {
workerStatus.value = (await stopRegionBroadcastWorker()) || {};
message.success('持续模拟已停止');
} finally {
workerLoading.value = false;
}
}
</script>
<template>
@ -231,6 +356,114 @@ async function handleSend() {
placeholder="发送成功后显示服务端返回内容"
/>
</Card>
<Card class="result-card" title="持续模拟">
<Form layout="vertical">
<div class="form-grid">
<FormItem label="区域" required>
<Select
v-model:value="workerForm.regionCodes"
:loading="regionLoading"
:options="regionOptions"
mode="multiple"
placeholder="可多选"
/>
</FormItem>
<FormItem label="随机间隔">
<Space>
<InputNumber
v-model:value="workerForm.minDelaySeconds"
:min="0"
:precision="0"
addon-after="秒"
/>
<InputNumber
v-model:value="workerForm.maxDelaySeconds"
:min="0"
:precision="0"
addon-after="秒"
/>
</Space>
</FormItem>
<FormItem label="飘屏开关">
<Space>
<Checkbox v-model:checked="workerForm.enableLuckyGift">
幸运礼物
</Checkbox>
<Checkbox v-model:checked="workerForm.enableGameWin">
游戏盈利
</Checkbox>
</Space>
</FormItem>
<FormItem label="中奖倍数">
<Input v-model:value="workerForm.multiples" placeholder="10,20,50" />
</FormItem>
<FormItem label="游戏中奖金额">
<Input
v-model:value="workerForm.gameWinAmounts"
placeholder="1000,2000,5000"
/>
</FormItem>
<FormItem label="幸运礼物中奖金额">
<Input
v-model:value="workerForm.luckyGiftWinAmounts"
placeholder="1000,2000,5000"
/>
</FormItem>
<FormItem label="投注金额">
<Input v-model:value="workerForm.betAmounts" placeholder="100,200,500" />
</FormItem>
<FormItem label="礼物单价">
<Input
v-model:value="workerForm.giftCandyOptions"
placeholder="100,200,500"
/>
</FormItem>
<FormItem label="礼物数量">
<Input
v-model:value="workerForm.giftQuantityOptions"
placeholder="1,5,10"
/>
</FormItem>
</div>
<Space>
<Button :loading="workerLoading" type="primary" @click="handleStartWorker">
启动持续模拟
</Button>
<Button :loading="workerLoading" danger @click="handleStopWorker">
停止
</Button>
<Button :loading="workerLoading" @click="refreshWorkerStatus">
刷新状态
</Button>
</Space>
</Form>
<Descriptions bordered class="summary" size="small">
<DescriptionsItem label="状态">
{{ workerStatus.running ? '运行中' : '已停止' }}
</DescriptionsItem>
<DescriptionsItem label="下次间隔">
{{ workerStatus.nextDelaySec ?? 0 }}
</DescriptionsItem>
<DescriptionsItem label="总发送">
{{ workerStatus.totalCount ?? 0 }}
</DescriptionsItem>
<DescriptionsItem label="幸运礼物">
{{ workerStatus.luckyGiftCount ?? 0 }}
</DescriptionsItem>
<DescriptionsItem label="游戏盈利">
{{ workerStatus.gameWinCount ?? 0 }}
</DescriptionsItem>
<DescriptionsItem label="最后执行">
{{ workerStatus.lastRunAt || '-' }}
</DescriptionsItem>
<DescriptionsItem label="最后错误">
{{ workerStatus.lastError || '-' }}
</DescriptionsItem>
</Descriptions>
</Card>
</Page>
</template>
@ -244,4 +477,8 @@ async function handleSend() {
.result-card {
margin-top: 16px;
}
.summary {
margin-top: 16px;
}
</style>