优化当前彩金池-安全线
This commit is contained in:
@@ -26,7 +26,26 @@
|
|||||||
"realtime": "Live",
|
"realtime": "Live",
|
||||||
"profitCalcHint": "Sum of (win amount including BIGWIN minus 100 ticket cost) per round; refreshes every 2s while open.",
|
"profitCalcHint": "Sum of (win amount including BIGWIN minus 100 ticket cost) per round; refreshes every 2s while open.",
|
||||||
"tierRuleTitle": "Tier Rule",
|
"tierRuleTitle": "Tier Rule",
|
||||||
"tierRuleContent": "When player profit in this pool is below safety line, use player T*_weight; when above or equal, use pool T*_weight (kill)."
|
"tierRuleContent": "When player profit in this pool is below safety line, use player T*_weight; when above or equal, use pool T*_weight (kill).",
|
||||||
|
"killScoreWeights": "Kill weights (type=1 read-only)",
|
||||||
|
"killWeightNote": "(Kill weights from pool config type=1; edit in list.)",
|
||||||
|
"btnResetProfit": "Reset Player Total Profit",
|
||||||
|
"btnSaveSafetyLine": "Save Safety Line",
|
||||||
|
"ruleSafetyLineRequired": "Please enter safety line",
|
||||||
|
"msgGetPoolFailed": "Failed to get lottery pool",
|
||||||
|
"msgSaveSuccess": "Saved",
|
||||||
|
"msgResetProfitSuccess": "Player total profit reset to 0",
|
||||||
|
"msgResetFailed": "Reset failed",
|
||||||
|
"ruleNameRequired": "Name is required",
|
||||||
|
"rulePoolTypeRequired": "Please select pool type",
|
||||||
|
"ruleT1Required": "T1 weight is required",
|
||||||
|
"ruleT2Required": "T2 weight is required",
|
||||||
|
"ruleT3Required": "T3 weight is required",
|
||||||
|
"ruleT4Required": "T4 weight is required",
|
||||||
|
"ruleT5Required": "T5 weight is required",
|
||||||
|
"msgWeightsMust100": "Total pool weights must equal 100%",
|
||||||
|
"msgAddSuccess": "Added",
|
||||||
|
"msgUpdateSuccess": "Updated"
|
||||||
},
|
},
|
||||||
"toolbar": {
|
"toolbar": {
|
||||||
"viewCurrentPool": "View Current Pool"
|
"viewCurrentPool": "View Current Pool"
|
||||||
|
|||||||
@@ -26,7 +26,26 @@
|
|||||||
"realtime": "实时",
|
"realtime": "实时",
|
||||||
"profitCalcHint": "计算方式:每局按“当前中奖金额(含超级大奖 BIGWIN)减去抽奖券费用 100”累加,弹窗打开期间每 2 秒自动刷新",
|
"profitCalcHint": "计算方式:每局按“当前中奖金额(含超级大奖 BIGWIN)减去抽奖券费用 100”累加,弹窗打开期间每 2 秒自动刷新",
|
||||||
"tierRuleTitle": "抽奖档位规则",
|
"tierRuleTitle": "抽奖档位规则",
|
||||||
"tierRuleContent": "当玩家在当前彩金池的累计盈利 低于安全线 时,按 玩家 的 T*_weight 权重抽取档位;当累计盈利 高于或等于安全线 时,按 当前彩金池 的 T*_weight 权重抽取档位(杀分)。"
|
"tierRuleContent": "当玩家在当前彩金池的累计盈利 低于安全线 时,按 玩家 的 T*_weight 权重抽取档位;当累计盈利 高于或等于安全线 时,按 当前彩金池 的 T*_weight 权重抽取档位(杀分)。",
|
||||||
|
"killScoreWeights": "杀分权重(type=1 只读)",
|
||||||
|
"killWeightNote": "(杀分权重来自奖池配置 type=1,请在列表中编辑对应记录)",
|
||||||
|
"btnResetProfit": "重置玩家累计盈利",
|
||||||
|
"btnSaveSafetyLine": "保存安全线",
|
||||||
|
"ruleSafetyLineRequired": "请输入安全线",
|
||||||
|
"msgGetPoolFailed": "获取彩金池失败",
|
||||||
|
"msgSaveSuccess": "保存成功",
|
||||||
|
"msgResetProfitSuccess": "玩家累计盈利已重置为 0",
|
||||||
|
"msgResetFailed": "重置失败",
|
||||||
|
"ruleNameRequired": "名称必需填写",
|
||||||
|
"rulePoolTypeRequired": "请选择奖池类型",
|
||||||
|
"ruleT1Required": "T1池权重必需填写",
|
||||||
|
"ruleT2Required": "T2池权重必需填写",
|
||||||
|
"ruleT3Required": "T3池权重必需填写",
|
||||||
|
"ruleT4Required": "T4池权重必需填写",
|
||||||
|
"ruleT5Required": "T5池权重必需填写",
|
||||||
|
"msgWeightsMust100": "五个池权重总和必须为100%",
|
||||||
|
"msgAddSuccess": "新增成功",
|
||||||
|
"msgUpdateSuccess": "修改成功"
|
||||||
},
|
},
|
||||||
"toolbar": {
|
"toolbar": {
|
||||||
"viewCurrentPool": "查看当前彩金池"
|
"viewCurrentPool": "查看当前彩金池"
|
||||||
|
|||||||
@@ -42,38 +42,28 @@
|
|||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('page.form.t1Weight')" prop="t1_weight">
|
<el-form-item :label="$t('page.form.killScoreWeights')">
|
||||||
<el-slider v-model="formData.t1_weight" :min="0" :max="100" :step="1" show-input />
|
<div class="text-gray-500 text-sm">
|
||||||
</el-form-item>
|
T1: {{ pool.t1_weight }}% / T2: {{ pool.t2_weight }}% / T3: {{ pool.t3_weight }}% / T4: {{ pool.t4_weight }}% / T5: {{ pool.t5_weight }}%
|
||||||
<el-form-item :label="$t('page.form.t2Weight')" prop="t2_weight">
|
</div>
|
||||||
<el-slider v-model="formData.t2_weight" :min="0" :max="100" :step="1" show-input />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t('page.form.t3Weight')" prop="t3_weight">
|
|
||||||
<el-slider v-model="formData.t3_weight" :min="0" :max="100" :step="1" show-input />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t('page.form.t4Weight')" prop="t4_weight">
|
|
||||||
<el-slider v-model="formData.t4_weight" :min="0" :max="100" :step="1" show-input />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t('page.form.t5Weight')" prop="t5_weight">
|
|
||||||
<el-slider v-model="formData.t5_weight" :min="0" :max="100" :step="1" show-input />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<div class="text-gray-500 text-sm">
|
<div class="text-gray-500 text-sm">
|
||||||
{{ $t('page.form.weightsSumHint') }}<span :class="weightsSum !== 100 ? 'text-red-500' : ''">{{
|
{{ $t('page.form.weightsSumHint') }}<span :class="weightsSum !== 100 ? 'text-red-500' : ''">{{
|
||||||
weightsSum
|
weightsSum
|
||||||
}}</span
|
}}</span
|
||||||
>{{ $t('page.form.weightsSumUnitCurrent') }}
|
>{{ $t('page.form.weightsSumUnitCurrent') }} {{ $t('page.form.killWeightNote') }}
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="handleClose">关闭</el-button>
|
<el-button @click="handleClose">{{ $t('form.close') }}</el-button>
|
||||||
<el-button :loading="resetting" :disabled="!pool" @click="handleResetProfit">
|
<el-button :loading="resetting" :disabled="!pool" @click="handleResetProfit">
|
||||||
重置玩家累计盈利
|
{{ $t('page.form.btnResetProfit') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" :loading="saving" :disabled="!pool" @click="handleSubmit">
|
<el-button type="primary" :loading="saving" :disabled="!pool" @click="handleSubmit">
|
||||||
保存权重与安全线
|
{{ $t('page.form.btnSaveSafetyLine') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@@ -83,6 +73,9 @@
|
|||||||
import api from '../../../api/lottery_pool_config/index'
|
import api from '../../../api/lottery_pool_config/index'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
interface PoolData {
|
interface PoolData {
|
||||||
id: number
|
id: number
|
||||||
@@ -111,31 +104,18 @@
|
|||||||
const formRef = ref<FormInstance>()
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
safety_line: 0,
|
safety_line: 0
|
||||||
t1_weight: 0,
|
|
||||||
t2_weight: 0,
|
|
||||||
t3_weight: 0,
|
|
||||||
t4_weight: 0,
|
|
||||||
t5_weight: 0
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const rules: FormRules = {
|
const rules = computed<FormRules>(() => ({
|
||||||
safety_line: [{ required: true, message: '请输入安全线', trigger: 'blur' }],
|
safety_line: [{ required: true, message: t('page.form.ruleSafetyLineRequired'), trigger: 'blur' }]
|
||||||
t1_weight: [{ required: true, message: '请输入T1权重', trigger: 'blur' }],
|
}))
|
||||||
t2_weight: [{ required: true, message: '请输入T2权重', trigger: 'blur' }],
|
|
||||||
t3_weight: [{ required: true, message: '请输入T3权重', trigger: 'blur' }],
|
|
||||||
t4_weight: [{ required: true, message: '请输入T4权重', trigger: 'blur' }],
|
|
||||||
t5_weight: [{ required: true, message: '请输入T5权重', trigger: 'blur' }]
|
|
||||||
}
|
|
||||||
|
|
||||||
const weightsSum = computed(
|
const weightsSum = computed(() => {
|
||||||
() =>
|
const p = pool.value
|
||||||
formData.t1_weight +
|
if (!p) return 0
|
||||||
formData.t2_weight +
|
return (p.t1_weight ?? 0) + (p.t2_weight ?? 0) + (p.t3_weight ?? 0) + (p.t4_weight ?? 0) + (p.t5_weight ?? 0)
|
||||||
formData.t3_weight +
|
})
|
||||||
formData.t4_weight +
|
|
||||||
formData.t5_weight
|
|
||||||
)
|
|
||||||
|
|
||||||
const displayProfitAmount = computed(() => {
|
const displayProfitAmount = computed(() => {
|
||||||
const v = pool.value?.profit_amount
|
const v = pool.value?.profit_amount
|
||||||
@@ -163,14 +143,9 @@
|
|||||||
if (data && typeof data === 'object') {
|
if (data && typeof data === 'object') {
|
||||||
pool.value = data
|
pool.value = data
|
||||||
formData.safety_line = data.safety_line ?? 0
|
formData.safety_line = data.safety_line ?? 0
|
||||||
formData.t1_weight = data.t1_weight ?? 0
|
|
||||||
formData.t2_weight = data.t2_weight ?? 0
|
|
||||||
formData.t3_weight = data.t3_weight ?? 0
|
|
||||||
formData.t4_weight = data.t4_weight ?? 0
|
|
||||||
formData.t5_weight = data.t5_weight ?? 0
|
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
ElMessage.error(e?.message ?? '获取彩金池失败')
|
ElMessage.error(e?.message ?? t('page.form.msgGetPoolFailed'))
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
@@ -200,23 +175,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
if (!formRef.value || !pool.value) return
|
if (!pool.value) return
|
||||||
if (weightsSum.value !== 100) {
|
|
||||||
ElMessage.warning('T1~T5 权重合计须为 100%')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
await formRef.value.validate()
|
await formRef.value?.validate?.()
|
||||||
saving.value = true
|
saving.value = true
|
||||||
await api.updateCurrentPool({
|
await api.updateCurrentPool({
|
||||||
safety_line: formData.safety_line,
|
safety_line: formData.safety_line
|
||||||
t1_weight: formData.t1_weight,
|
|
||||||
t2_weight: formData.t2_weight,
|
|
||||||
t3_weight: formData.t3_weight,
|
|
||||||
t4_weight: formData.t4_weight,
|
|
||||||
t5_weight: formData.t5_weight
|
|
||||||
})
|
})
|
||||||
ElMessage.success('保存成功')
|
ElMessage.success(t('page.form.msgSaveSuccess'))
|
||||||
await loadPool()
|
await loadPool()
|
||||||
emit('success')
|
emit('success')
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@@ -231,11 +197,11 @@
|
|||||||
try {
|
try {
|
||||||
resetting.value = true
|
resetting.value = true
|
||||||
await api.resetProfitAmount()
|
await api.resetProfitAmount()
|
||||||
ElMessage.success('玩家累计盈利已重置为 0')
|
ElMessage.success(t('page.form.msgResetProfitSuccess'))
|
||||||
await loadPool()
|
await loadPool()
|
||||||
emit('success')
|
emit('success')
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
ElMessage.error(e?.message ?? '重置失败')
|
ElMessage.error(e?.message ?? t('page.form.msgResetFailed'))
|
||||||
} finally {
|
} finally {
|
||||||
resetting.value = false
|
resetting.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,9 @@
|
|||||||
import api from '../../../api/lottery_pool_config/index'
|
import api from '../../../api/lottery_pool_config/index'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
modelValue: boolean
|
modelValue: boolean
|
||||||
@@ -122,15 +125,15 @@
|
|||||||
/**
|
/**
|
||||||
* 表单验证规则
|
* 表单验证规则
|
||||||
*/
|
*/
|
||||||
const rules = reactive<FormRules>({
|
const rules = computed<FormRules>(() => ({
|
||||||
name: [{ required: true, message: '名称必需填写', trigger: 'blur' }],
|
name: [{ required: true, message: t('page.form.ruleNameRequired'), trigger: 'blur' }],
|
||||||
type: [{ required: true, message: '请选择奖池类型', trigger: 'change' }],
|
type: [{ required: true, message: t('page.form.rulePoolTypeRequired'), trigger: 'change' }],
|
||||||
t1_weight: [{ required: true, message: 'T1池权重必需填写', trigger: 'blur' }],
|
t1_weight: [{ required: true, message: t('page.form.ruleT1Required'), trigger: 'blur' }],
|
||||||
t2_weight: [{ required: true, message: 'T2池权重必需填写', trigger: 'blur' }],
|
t2_weight: [{ required: true, message: t('page.form.ruleT2Required'), trigger: 'blur' }],
|
||||||
t3_weight: [{ required: true, message: 'T3池权重必需填写', trigger: 'blur' }],
|
t3_weight: [{ required: true, message: t('page.form.ruleT3Required'), trigger: 'blur' }],
|
||||||
t4_weight: [{ required: true, message: 'T4池权重必需填写', trigger: 'blur' }],
|
t4_weight: [{ required: true, message: t('page.form.ruleT4Required'), trigger: 'blur' }],
|
||||||
t5_weight: [{ required: true, message: 'T5池权重必需填写', trigger: 'blur' }]
|
t5_weight: [{ required: true, message: t('page.form.ruleT5Required'), trigger: 'blur' }]
|
||||||
})
|
}))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始数据(权重为数字便于输入与校验)
|
* 初始数据(权重为数字便于输入与校验)
|
||||||
@@ -221,15 +224,15 @@
|
|||||||
try {
|
try {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
if (Math.abs(weightsSum.value - 100) > 0.01) {
|
if (Math.abs(weightsSum.value - 100) > 0.01) {
|
||||||
ElMessage.warning('五个池权重总和必须为100%')
|
ElMessage.warning(t('page.form.msgWeightsMust100'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (props.dialogType === 'add') {
|
if (props.dialogType === 'add') {
|
||||||
await api.save(formData)
|
await api.save(formData)
|
||||||
ElMessage.success('新增成功')
|
ElMessage.success(t('page.form.msgAddSuccess'))
|
||||||
} else {
|
} else {
|
||||||
await api.update(formData)
|
await api.update(formData)
|
||||||
ElMessage.success('修改成功')
|
ElMessage.success(t('page.form.msgUpdateSuccess'))
|
||||||
}
|
}
|
||||||
emit('success')
|
emit('success')
|
||||||
handleClose()
|
handleClose()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace app\api\controller;
|
|||||||
use support\Log;
|
use support\Log;
|
||||||
use support\Request;
|
use support\Request;
|
||||||
use support\Response;
|
use support\Response;
|
||||||
|
use support\think\Db;
|
||||||
use app\api\logic\GameLogic;
|
use app\api\logic\GameLogic;
|
||||||
use app\api\logic\PlayStartLogic;
|
use app\api\logic\PlayStartLogic;
|
||||||
use app\api\util\ReturnCode;
|
use app\api\util\ReturnCode;
|
||||||
@@ -162,6 +163,11 @@ class GameController extends BaseController
|
|||||||
return $this->success([], $msg);
|
return $this->success([], $msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$lockName = 'play_start_' . $userId;
|
||||||
|
$lockResult = Db::query('SELECT GET_LOCK(?, 30) as l', [$lockName]);
|
||||||
|
if (empty($lockResult) || (int) ($lockResult[0]['l'] ?? 0) !== 1) {
|
||||||
|
return $this->fail('请求过于频繁,请稍后再试', ReturnCode::BUSINESS_ERROR);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
$logic = new PlayStartLogic();
|
$logic = new PlayStartLogic();
|
||||||
$data = $logic->run($userId, (int)$direction);
|
$data = $logic->run($userId, (int)$direction);
|
||||||
@@ -245,6 +251,8 @@ class GameController extends BaseController
|
|||||||
$msg = '没有原因';
|
$msg = '没有原因';
|
||||||
}
|
}
|
||||||
return $this->fail('服务超时,' . $msg);
|
return $this->fail('服务超时,' . $msg);
|
||||||
|
} finally {
|
||||||
|
Db::execute('SELECT RELEASE_LOCK(?)', [$lockName]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,27 +70,31 @@ class PlayStartLogic
|
|||||||
|
|
||||||
$lotteryService = LotteryService::getOrCreate($playerId);
|
$lotteryService = LotteryService::getOrCreate($playerId);
|
||||||
$ticketType = LotteryService::drawTicketType($paid, $free);
|
$ticketType = LotteryService::drawTicketType($paid, $free);
|
||||||
$config = $ticketType === self::LOTTERY_TYPE_PAID
|
$configType0 = DiceLotteryPoolConfig::where('type', 0)->find();
|
||||||
? ($lotteryService->getConfigType0Id() ? DiceLotteryPoolConfig::find($lotteryService->getConfigType0Id()) : null)
|
$configType1 = DiceLotteryPoolConfig::where('type', 1)->find();
|
||||||
: ($lotteryService->getConfigType1Id() ? DiceLotteryPoolConfig::find($lotteryService->getConfigType1Id()) : null);
|
if (!$configType0) {
|
||||||
// 未找到付费/免费对应配置时,统一回退到 type=0 的彩金池
|
throw new ApiException('奖池配置不存在(需 type=0)');
|
||||||
if (!$config) {
|
|
||||||
$config = DiceLotteryPoolConfig::where('type', 0)->find();
|
|
||||||
}
|
|
||||||
if (!$config) {
|
|
||||||
throw new ApiException('奖池配置不存在');
|
|
||||||
}
|
}
|
||||||
|
// 杀分时使用 type=1 配置的权重;未杀分时付费用 type=0、免费用 type=1(无 type=1 时回退 type=0)
|
||||||
|
$configForWeights = $ticketType === self::LOTTERY_TYPE_PAID
|
||||||
|
? $configType0
|
||||||
|
: ($configType1 ?? $configType0);
|
||||||
|
|
||||||
// 计算当前玩家在该彩金池中的累计盈利金额:当前中奖金额(含 BIGWIN)减去抽奖券费用 100
|
// 玩家累计盈利:仅统计 lottery_config_id=type=0 的成功对局(中奖金额-100*局数)
|
||||||
$playerQuery = DicePlayRecord::where('player_id', $playerId)
|
$playerQuery = DicePlayRecord::where('player_id', $playerId)
|
||||||
->where('lottery_config_id', $config->id)
|
->where('lottery_config_id', $configType0->id)
|
||||||
->where('status', self::RECORD_STATUS_SUCCESS);
|
->where('status', self::RECORD_STATUS_SUCCESS);
|
||||||
$playerWinSum = (float) $playerQuery->sum('win_coin');
|
$playerWinSum = (float) $playerQuery->sum('win_coin');
|
||||||
$playerPlayCount = (int) $playerQuery->count();
|
$playerPlayCount = (int) $playerQuery->count();
|
||||||
$playerProfitTotal = $playerWinSum - 100.0 * $playerPlayCount;
|
$playerProfitTotal = $playerWinSum - 100.0 * $playerPlayCount;
|
||||||
$safetyLine = (int) ($config->safety_line ?? 0);
|
$safetyLine = (int) ($configType0->safety_line ?? 0);
|
||||||
// 玩家累计盈利金额达到或超过安全线时,按奖池 T*_weight 杀分;否则按玩家 T*_weight 抽档位
|
// 玩家累计盈利>=安全线时杀分:用 type=1 的 T*_weight,并记录 lottery_config_id=type=1 的 id;否则用玩家权重,记录对应配置 id
|
||||||
$usePoolWeights = $playerProfitTotal >= $safetyLine;
|
$usePoolWeights = $playerProfitTotal >= $safetyLine && $configType1 !== null;
|
||||||
|
if ($usePoolWeights) {
|
||||||
|
$config = $configType1;
|
||||||
|
} else {
|
||||||
|
$config = $configForWeights;
|
||||||
|
}
|
||||||
|
|
||||||
// 按档位 T1-T5 抽取后,从 DiceReward 表按当前方向取该档位数据,再按 weight 抽取一条得到 grid_number
|
// 按档位 T1-T5 抽取后,从 DiceReward 表按当前方向取该档位数据,再按 weight 抽取一条得到 grid_number
|
||||||
$rewardInstance = DiceReward::getCachedInstance();
|
$rewardInstance = DiceReward::getCachedInstance();
|
||||||
@@ -177,6 +181,7 @@ class PlayStartLogic
|
|||||||
|
|
||||||
$record = null;
|
$record = null;
|
||||||
$configId = (int) $config->id;
|
$configId = (int) $config->id;
|
||||||
|
$type0ConfigId = (int) $configType0->id;
|
||||||
$rewardId = ($isWin === 1 && $superWinCoin > 0) ? 0 : $targetIndex; // 中豹子不记录原奖励配置 id
|
$rewardId = ($isWin === 1 && $superWinCoin > 0) ? 0 : $targetIndex; // 中豹子不记录原奖励配置 id
|
||||||
$configName = (string) ($config->name ?? '');
|
$configName = (string) ($config->name ?? '');
|
||||||
$adminId = ($player->admin_id ?? null) ? (int) $player->admin_id : null;
|
$adminId = ($player->admin_id ?? null) ? (int) $player->admin_id : null;
|
||||||
@@ -185,6 +190,7 @@ class PlayStartLogic
|
|||||||
$playerId,
|
$playerId,
|
||||||
$adminId,
|
$adminId,
|
||||||
$configId,
|
$configId,
|
||||||
|
$type0ConfigId,
|
||||||
$rewardId,
|
$rewardId,
|
||||||
$configName,
|
$configName,
|
||||||
$ticketType,
|
$ticketType,
|
||||||
@@ -250,20 +256,17 @@ class PlayStartLogic
|
|||||||
|
|
||||||
$p->save();
|
$p->save();
|
||||||
|
|
||||||
// 玩家累计盈利底层仍使用 profit_amount 字段存储:每局按“当前中奖金额(含 BIGWIN) - 抽奖券费用 100”累加
|
// 玩家累计盈利累加在 type=0 彩金池上:每局按“当前中奖金额(含 BIGWIN) - 抽奖券费用 100”
|
||||||
// 需确保表有 profit_amount 字段(见 db/dice_lottery_config_add_profit_amount.sql)
|
|
||||||
$perPlayProfit = $winCoin - 100.0;
|
$perPlayProfit = $winCoin - 100.0;
|
||||||
$addProfit = $perPlayProfit;
|
$addProfit = $perPlayProfit;
|
||||||
try {
|
try {
|
||||||
DiceLotteryPoolConfig::where('id', $configId)->update([
|
DiceLotteryPoolConfig::where('id', $type0ConfigId)->update([
|
||||||
'profit_amount' => Db::raw('IFNULL(profit_amount,0) + ' . (float) $addProfit),
|
'profit_amount' => Db::raw('IFNULL(profit_amount,0) + ' . (float) $addProfit),
|
||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
Log::warning('彩金池盈利累加失败,请确认表 dice_lottery_config 已存在 profit_amount 字段并执行 db/dice_lottery_config_add_profit_amount.sql', [
|
Log::warning('彩金池盈利累加失败', [
|
||||||
'config_id' => $configId,
|
'config_id' => $type0ConfigId,
|
||||||
'add_profit' => $addProfit,
|
'add_profit' => $addProfit,
|
||||||
'real_ev' => $realEv,
|
|
||||||
'bigwin_ev' => $bigWinRealEv,
|
|
||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,83 +31,49 @@ class DiceLotteryPoolConfigLogic extends BaseLogic
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前彩金池:从 Redis 读取实例,profit_amount 每次从 DB 实时读取(表示玩家在该池子的累计盈利)
|
* 获取当前彩金池(type=0)+ 杀分权重为 type=1 的只读展示
|
||||||
|
* profit_amount 每次从 DB 实时读取;t1_weight~t5_weight 来自 type=1(杀分权重,不可在弹窗内修改)
|
||||||
*
|
*
|
||||||
* @return array{id:int,name:string,safety_line:int,t1_weight:int,t2_weight:int,t3_weight:int,t4_weight:int,t5_weight:int,profit_amount:float}
|
* @return array{id:int,name:string,safety_line:int,t1_weight:int,...,t5_weight:int,profit_amount:float}
|
||||||
*/
|
*/
|
||||||
public function getCurrentPool(): array
|
public function getCurrentPool(): array
|
||||||
{
|
{
|
||||||
$cached = Cache::get(self::REDIS_KEY_CURRENT_POOL);
|
$configType0 = DiceLotteryPoolConfig::where('type', 0)->find();
|
||||||
if ($cached && is_string($cached)) {
|
if (!$configType0) {
|
||||||
$data = json_decode($cached, true);
|
|
||||||
if (is_array($data)) {
|
|
||||||
$config = DiceLotteryPoolConfig::find($data['id'] ?? 0);
|
|
||||||
$profit = 0.0;
|
|
||||||
if ($config) {
|
|
||||||
$profit = isset($config->profit_amount) ? (float) $config->profit_amount : (isset($config->ev) ? (float) $config->ev : 0.0);
|
|
||||||
} else {
|
|
||||||
$profit = (float) ($data['profit_amount'] ?? 0);
|
|
||||||
}
|
|
||||||
$data['profit_amount'] = $profit;
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$config = DiceLotteryPoolConfig::where('type', 0)->find();
|
|
||||||
if (!$config) {
|
|
||||||
throw new ApiException('未找到 type=0 的奖池配置,请先创建');
|
throw new ApiException('未找到 type=0 的奖池配置,请先创建');
|
||||||
}
|
}
|
||||||
$row = $config->toArray();
|
$configType1 = DiceLotteryPoolConfig::where('type', 1)->find();
|
||||||
$profitAmount = isset($row['profit_amount']) ? (float) $row['profit_amount'] : (isset($row['ev']) ? (float) $row['ev'] : 0.0);
|
$row0 = $configType0->toArray();
|
||||||
|
$profitAmount = isset($row0['profit_amount']) ? (float) $row0['profit_amount'] : (isset($row0['ev']) ? (float) $row0['ev'] : 0.0);
|
||||||
$pool = [
|
$pool = [
|
||||||
'id' => (int) $row['id'],
|
'id' => (int) $row0['id'],
|
||||||
'name' => (string) ($row['name'] ?? ''),
|
'name' => (string) ($row0['name'] ?? ''),
|
||||||
'safety_line' => (int) ($row['safety_line'] ?? 0),
|
'safety_line' => (int) ($row0['safety_line'] ?? 0),
|
||||||
't1_weight' => (int) ($row['t1_weight'] ?? 0),
|
|
||||||
't2_weight' => (int) ($row['t2_weight'] ?? 0),
|
|
||||||
't3_weight' => (int) ($row['t3_weight'] ?? 0),
|
|
||||||
't4_weight' => (int) ($row['t4_weight'] ?? 0),
|
|
||||||
't5_weight' => (int) ($row['t5_weight'] ?? 0),
|
|
||||||
'profit_amount' => $profitAmount,
|
'profit_amount' => $profitAmount,
|
||||||
];
|
];
|
||||||
Cache::set(self::REDIS_KEY_CURRENT_POOL, json_encode($pool), self::EXPIRE);
|
$row1 = $configType1 ? $configType1->toArray() : [];
|
||||||
|
$pool['t1_weight'] = (int) ($row1['t1_weight'] ?? 0);
|
||||||
|
$pool['t2_weight'] = (int) ($row1['t2_weight'] ?? 0);
|
||||||
|
$pool['t3_weight'] = (int) ($row1['t3_weight'] ?? 0);
|
||||||
|
$pool['t4_weight'] = (int) ($row1['t4_weight'] ?? 0);
|
||||||
|
$pool['t5_weight'] = (int) ($row1['t5_weight'] ?? 0);
|
||||||
return $pool;
|
return $pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新当前彩金池:仅允许修改 safety_line、t1_weight~t5_weight,不修改 profit_amount
|
* 更新当前彩金池:仅允许修改 type=0 的 safety_line(杀分权重来自 type=1,不可在此接口修改)
|
||||||
* 同时更新 Redis 与 DB 中 type=0 的记录
|
|
||||||
*
|
*
|
||||||
* @param array{safety_line?:int,t1_weight?:int,t2_weight?:int,t3_weight?:int,t4_weight?:int,t5_weight?:int} $data
|
* @param array{safety_line?:int} $data
|
||||||
*/
|
*/
|
||||||
public function updateCurrentPool(array $data): void
|
public function updateCurrentPool(array $data): void
|
||||||
{
|
{
|
||||||
$pool = $this->getCurrentPool();
|
$pool = $this->getCurrentPool();
|
||||||
$id = (int) $pool['id'];
|
$id = (int) $pool['id'];
|
||||||
$config = DiceLotteryPoolConfig::find($id);
|
if (!array_key_exists('safety_line', $data)) {
|
||||||
if (!$config) {
|
|
||||||
throw new ApiException('奖池配置不存在');
|
|
||||||
}
|
|
||||||
$allow = ['safety_line', 't1_weight', 't2_weight', 't3_weight', 't4_weight', 't5_weight'];
|
|
||||||
$update = [];
|
|
||||||
foreach ($allow as $k) {
|
|
||||||
if (array_key_exists($k, $data)) {
|
|
||||||
if ($k === 'safety_line') {
|
|
||||||
$update[$k] = (int) $data[$k];
|
|
||||||
} else {
|
|
||||||
$update[$k] = max(0, min(100, (int) $data[$k]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (empty($update)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DiceLotteryPoolConfig::where('id', $id)->update($update);
|
$safetyLine = (int) $data['safety_line'];
|
||||||
$pool = array_merge($pool, $update);
|
DiceLotteryPoolConfig::where('id', $id)->update(['safety_line' => $safetyLine]);
|
||||||
$refreshed = DiceLotteryPoolConfig::find($id);
|
|
||||||
$pool['profit_amount'] = $refreshed && (isset($refreshed->profit_amount) || isset($refreshed->ev))
|
|
||||||
? (float) ($refreshed->profit_amount ?? $refreshed->ev)
|
|
||||||
: (float) ($pool['profit_amount'] ?? 0);
|
|
||||||
Cache::set(self::REDIS_KEY_CURRENT_POOL, json_encode($pool), self::EXPIRE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user