模拟飘屏
This commit is contained in:
parent
6e516e95f2
commit
bdd3a99bba
8
apps/src/api/legacy/region-broadcast.ts
Normal file
8
apps/src/api/legacy/region-broadcast.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export async function simulateRegionBroadcast(data: Record<string, any>) {
|
||||
return requestClient.post<Record<string, any>>(
|
||||
'/go/operate/region-broadcast/simulate',
|
||||
data,
|
||||
);
|
||||
}
|
||||
@ -65,6 +65,12 @@ const routes: RouteRecordRaw[] = [
|
||||
component: () => import('#/views/operate/tools-other.vue'),
|
||||
meta: { title: '小工具' },
|
||||
},
|
||||
{
|
||||
name: 'OperateRegionBroadcast',
|
||||
path: 'region-broadcast',
|
||||
component: () => import('#/views/operate/region-broadcast.vue'),
|
||||
meta: { title: '区域飘屏' },
|
||||
},
|
||||
{
|
||||
name: 'OperateAbnormalLog',
|
||||
path: 'abnormal/log',
|
||||
|
||||
@ -226,6 +226,21 @@ function formatMoney(value?: number | string) {
|
||||
return `$${amount.toFixed(2)}`;
|
||||
}
|
||||
|
||||
function shouldShowAgentSalary(record: Record<string, any>) {
|
||||
if (record.agentMember !== undefined && record.agentMember !== null) {
|
||||
return record.agentMember === true;
|
||||
}
|
||||
return (
|
||||
!!record.userId &&
|
||||
!!record.teamOwnId &&
|
||||
String(record.userId) === String(record.teamOwnId)
|
||||
);
|
||||
}
|
||||
|
||||
function formatAgentMoney(record: Record<string, any>, key: string) {
|
||||
return shouldShowAgentSalary(record) ? formatMoney(record[key]) : '-';
|
||||
}
|
||||
|
||||
function formatInteger(value?: number | string) {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
return '-';
|
||||
@ -493,7 +508,7 @@ void loadCountries();
|
||||
{{ formatMoney(record.expectedMemberSalary) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'expectedAgentSalary'">
|
||||
{{ formatMoney(record.expectedAgentSalary) }}
|
||||
{{ formatAgentMoney(record, 'expectedAgentSalary') }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'payableMemberSalary'">
|
||||
<span
|
||||
@ -506,7 +521,7 @@ void loadCountries();
|
||||
<span
|
||||
:class="{ 'payable-salary-negative': Number(record.payableAgentSalary || 0) < 0 }"
|
||||
>
|
||||
{{ formatMoney(record.payableAgentSalary) }}
|
||||
{{ formatAgentMoney(record, 'payableAgentSalary') }}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'payableSalary'">
|
||||
@ -529,9 +544,9 @@ void loadCountries();
|
||||
</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'agentIssuedSalary'">
|
||||
<span>{{ formatMoney(record.agentIssuedSalary) }}</span>
|
||||
<span>{{ formatAgentMoney(record, 'agentIssuedSalary') }}</span>
|
||||
<span
|
||||
v-if="Number(record.agentOverIssuedSalary || 0) > 0"
|
||||
v-if="shouldShowAgentSalary(record) && Number(record.agentOverIssuedSalary || 0) > 0"
|
||||
class="over-issued-salary"
|
||||
>
|
||||
({{ formatMoney(record.agentOverIssuedSalary) }})
|
||||
|
||||
247
apps/src/views/operate/region-broadcast.vue
Normal file
247
apps/src/views/operate/region-broadcast.vue
Normal file
@ -0,0 +1,247 @@
|
||||
<script lang="ts" setup>
|
||||
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 { getAllowedSysOrigins } from '#/views/system/shared';
|
||||
|
||||
import SystemRegionSelect from './components/system-region-select.vue';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
Select,
|
||||
Space,
|
||||
TextArea,
|
||||
message,
|
||||
} from 'antdv-next';
|
||||
|
||||
defineOptions({ name: 'OperateRegionBroadcast' });
|
||||
|
||||
const accessStore = useAccessStore();
|
||||
const sysOriginOptions = computed(() => {
|
||||
const options = getAllowedSysOrigins(accessStore.accessCodes || []);
|
||||
return (options.length > 0 ? options : getAllowedSysOrigins([])).map((item) => ({
|
||||
label: item.label,
|
||||
value: item.value,
|
||||
}));
|
||||
});
|
||||
|
||||
const kindOptions = [
|
||||
{ label: '幸运礼物中奖飘屏', value: 'LUCKY_GIFT' },
|
||||
{ label: '游戏盈利飘屏', value: 'GAME_WIN' },
|
||||
];
|
||||
|
||||
const form = reactive<Record<string, any>>({
|
||||
acceptUserId: '',
|
||||
betAmount: '100',
|
||||
gameId: 'admin-sim-game',
|
||||
gameRoundId: '',
|
||||
gameUrl: '',
|
||||
giftCandy: '100',
|
||||
giftId: '',
|
||||
giftQuantity: '1',
|
||||
kind: 'LUCKY_GIFT',
|
||||
multiple: '10',
|
||||
providerOrderId: '',
|
||||
regionCode: '',
|
||||
regionId: '',
|
||||
roomId: '',
|
||||
senderUserId: '',
|
||||
sysOrigin: '',
|
||||
winAmount: '1000',
|
||||
});
|
||||
|
||||
const sending = ref(false);
|
||||
const resultText = ref('');
|
||||
|
||||
const isLuckyGift = computed(() => form.kind === 'LUCKY_GIFT');
|
||||
|
||||
watch(
|
||||
sysOriginOptions,
|
||||
(options) => {
|
||||
if (!form.sysOrigin && options.length > 0) {
|
||||
form.sysOrigin = String(options[0]?.value || '');
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
() => form.sysOrigin,
|
||||
() => {
|
||||
form.regionId = '';
|
||||
form.regionCode = '';
|
||||
},
|
||||
);
|
||||
|
||||
function handleRegionChange(_value: any, item: Record<string, any> | null) {
|
||||
form.regionCode = item?.regionCode || item?.code || '';
|
||||
}
|
||||
|
||||
function normalizePayload() {
|
||||
return {
|
||||
acceptUserId: String(form.acceptUserId || '').trim(),
|
||||
betAmount: String(form.betAmount || '').trim(),
|
||||
gameId: String(form.gameId || '').trim(),
|
||||
gameRoundId: String(form.gameRoundId || '').trim(),
|
||||
gameUrl: String(form.gameUrl || '').trim(),
|
||||
giftCandy: String(form.giftCandy || '').trim(),
|
||||
giftId: String(form.giftId || '').trim(),
|
||||
giftQuantity: String(form.giftQuantity || '').trim(),
|
||||
kind: form.kind,
|
||||
multiple: String(form.multiple || '').trim(),
|
||||
providerOrderId: String(form.providerOrderId || '').trim(),
|
||||
regionCode: String(form.regionCode || '').trim(),
|
||||
roomId: String(form.roomId || '').trim(),
|
||||
senderUserId: String(form.senderUserId || '').trim(),
|
||||
sysOrigin: String(form.sysOrigin || '').trim(),
|
||||
winAmount: String(form.winAmount || '').trim(),
|
||||
};
|
||||
}
|
||||
|
||||
function validatePayload(payload: Record<string, any>) {
|
||||
if (!payload.sysOrigin) {
|
||||
return '请选择系统来源';
|
||||
}
|
||||
if (!payload.regionCode) {
|
||||
return '请选择区域';
|
||||
}
|
||||
if (!payload.senderUserId) {
|
||||
return '请输入发送用户ID';
|
||||
}
|
||||
if (!payload.roomId) {
|
||||
return '请输入房间ID';
|
||||
}
|
||||
if (!payload.multiple || Number(payload.multiple) < 10) {
|
||||
return '中奖倍数必须大于等于10';
|
||||
}
|
||||
if (!payload.winAmount || Number(payload.winAmount) <= 0) {
|
||||
return '中奖金额必须大于0';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
async function handleSend() {
|
||||
const payload = normalizePayload();
|
||||
const error = validatePayload(payload);
|
||||
if (error) {
|
||||
message.warning(error);
|
||||
return;
|
||||
}
|
||||
sending.value = true;
|
||||
try {
|
||||
const result = await simulateRegionBroadcast(payload);
|
||||
resultText.value = JSON.stringify(result || {}, null, 2);
|
||||
message.success('区域飘屏已发送');
|
||||
} finally {
|
||||
sending.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page title="区域飘屏">
|
||||
<Card>
|
||||
<Form layout="vertical">
|
||||
<div class="form-grid">
|
||||
<FormItem label="系统来源" required>
|
||||
<Select
|
||||
v-model:value="form.sysOrigin"
|
||||
:options="sysOriginOptions"
|
||||
placeholder="请选择系统来源"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="区域" required>
|
||||
<SystemRegionSelect
|
||||
v-model:value="form.regionId"
|
||||
:sys-origin="form.sysOrigin"
|
||||
placeholder="请选择区域"
|
||||
@change="handleRegionChange"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="飘屏类型" required>
|
||||
<Select v-model:value="form.kind" :options="kindOptions" />
|
||||
</FormItem>
|
||||
<FormItem label="发送用户ID" required>
|
||||
<Input v-model:value="form.senderUserId" placeholder="用户长ID" />
|
||||
</FormItem>
|
||||
<FormItem label="房间ID" required>
|
||||
<Input v-model:value="form.roomId" placeholder="房间ID" />
|
||||
</FormItem>
|
||||
<FormItem label="中奖倍数" required>
|
||||
<Input v-model:value="form.multiple" placeholder="10" />
|
||||
</FormItem>
|
||||
<FormItem label="中奖金额" required>
|
||||
<Input v-model:value="form.winAmount" placeholder="金币数量" />
|
||||
</FormItem>
|
||||
|
||||
<template v-if="isLuckyGift">
|
||||
<FormItem label="收礼用户ID">
|
||||
<Input v-model:value="form.acceptUserId" placeholder="可选" />
|
||||
</FormItem>
|
||||
<FormItem label="礼物ID">
|
||||
<Input v-model:value="form.giftId" placeholder="可选" />
|
||||
</FormItem>
|
||||
<FormItem label="礼物单价">
|
||||
<Input v-model:value="form.giftCandy" />
|
||||
</FormItem>
|
||||
<FormItem label="礼物数量">
|
||||
<Input v-model:value="form.giftQuantity" />
|
||||
</FormItem>
|
||||
<FormItem label="业务单号">
|
||||
<Input v-model:value="form.providerOrderId" placeholder="可选" />
|
||||
</FormItem>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<FormItem label="游戏ID">
|
||||
<Input v-model:value="form.gameId" />
|
||||
</FormItem>
|
||||
<FormItem label="游戏局号">
|
||||
<Input v-model:value="form.gameRoundId" placeholder="可选" />
|
||||
</FormItem>
|
||||
<FormItem label="投注金额">
|
||||
<Input v-model:value="form.betAmount" />
|
||||
</FormItem>
|
||||
<FormItem label="游戏封面">
|
||||
<Input v-model:value="form.gameUrl" placeholder="可选" />
|
||||
</FormItem>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<Space>
|
||||
<Button :loading="sending" type="primary" @click="handleSend">
|
||||
发送模拟飘屏
|
||||
</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</Card>
|
||||
|
||||
<Card class="result-card" title="发送结果">
|
||||
<TextArea
|
||||
v-model:value="resultText"
|
||||
:auto-size="{ minRows: 8, maxRows: 16 }"
|
||||
readonly
|
||||
placeholder="发送成功后显示服务端返回内容"
|
||||
/>
|
||||
</Card>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 12px 16px;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
75
scripts/sql/sync_region_broadcast_menu.sql
Normal file
75
scripts/sql/sync_region_broadcast_menu.sql
Normal file
@ -0,0 +1,75 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
SET @operate_manager_id := (
|
||||
SELECT id
|
||||
FROM sys_menu
|
||||
WHERE alias = 'OperateManager'
|
||||
LIMIT 1
|
||||
);
|
||||
|
||||
INSERT INTO sys_menu (
|
||||
id,
|
||||
parent_id,
|
||||
menu_name,
|
||||
path,
|
||||
menu_type,
|
||||
icon,
|
||||
create_user,
|
||||
update_user,
|
||||
sort,
|
||||
status,
|
||||
router,
|
||||
alias
|
||||
)
|
||||
SELECT
|
||||
menu_id.next_id,
|
||||
@operate_manager_id,
|
||||
'区域飘屏',
|
||||
'operate/region-broadcast',
|
||||
2,
|
||||
'lucide:radio-tower',
|
||||
'0',
|
||||
'0',
|
||||
18,
|
||||
0,
|
||||
'region-broadcast',
|
||||
'OperateRegionBroadcast'
|
||||
FROM (
|
||||
SELECT COALESCE(MAX(id), 1700000000) + 1 AS next_id
|
||||
FROM sys_menu
|
||||
) AS menu_id
|
||||
WHERE @operate_manager_id IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sys_menu WHERE alias = 'OperateRegionBroadcast'
|
||||
);
|
||||
|
||||
UPDATE sys_menu
|
||||
SET
|
||||
parent_id = @operate_manager_id,
|
||||
menu_name = '区域飘屏',
|
||||
path = 'operate/region-broadcast',
|
||||
menu_type = 2,
|
||||
icon = 'lucide:radio-tower',
|
||||
update_user = '0',
|
||||
sort = 18,
|
||||
status = 0,
|
||||
router = 'region-broadcast'
|
||||
WHERE alias = 'OperateRegionBroadcast'
|
||||
AND @operate_manager_id IS NOT NULL;
|
||||
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT DISTINCT
|
||||
role_menu.role_id,
|
||||
target_menu.id
|
||||
FROM sys_role_menu AS role_menu
|
||||
JOIN sys_menu AS source_menu
|
||||
ON source_menu.id = role_menu.menu_id
|
||||
AND source_menu.alias = 'OperateManager'
|
||||
JOIN sys_menu AS target_menu
|
||||
ON target_menu.alias = 'OperateRegionBroadcast'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sys_role_menu AS existing_role_menu
|
||||
WHERE existing_role_menu.role_id = role_menu.role_id
|
||||
AND existing_role_menu.menu_id = target_menu.id
|
||||
);
|
||||
Loading…
x
Reference in New Issue
Block a user