优化每日推送和积分转化逻辑

This commit is contained in:
2026-07-24 11:12:29 +08:00
parent b2b4fd4fbc
commit 4bad91b8a3
29 changed files with 661 additions and 102 deletions

View File

@@ -92,9 +92,11 @@ const fieldOptions = computed(() => [
{ value: 'date', label: t('mall.dailyPush.date') },
{ value: 'username', label: t('mall.dailyPush.username') },
{ value: 'yesterday_win_loss_net', label: t('mall.dailyPush.yesterday_win_loss_net') },
{ value: 'converted_points', label: t('mall.dailyPush.converted_points') },
{ value: 'yesterday_total_deposit', label: t('mall.dailyPush.yesterday_total_deposit') },
{ value: 'lifetime_total_deposit', label: t('mall.dailyPush.lifetime_total_deposit') },
{ value: 'lifetime_total_withdraw', label: t('mall.dailyPush.lifetime_total_withdraw') },
{ value: 'lifetime_win_loss_net', label: t('mall.dailyPush.lifetime_win_loss_net') },
{ value: 'create_time', label: t('mall.dailyPush.create_time') },
])

View File

@@ -81,6 +81,14 @@ const baTable = new baTableClass(
operator: 'RANGE',
sortable: 'custom',
},
{
label: t('mall.dailyPush.converted_points'),
prop: 'converted_points',
align: 'center',
operator: 'RANGE',
sortable: 'custom',
width: 100,
},
{
label: t('mall.dailyPush.yesterday_total_deposit'),
prop: 'yesterday_total_deposit',
@@ -103,6 +111,14 @@ const baTable = new baTableClass(
operator: 'RANGE',
sortable: 'custom',
},
{
label: t('mall.dailyPush.lifetime_win_loss_net'),
prop: 'lifetime_win_loss_net',
align: 'center',
minWidth: 95,
operator: 'RANGE',
sortable: 'custom',
},
{
label: t('mall.dailyPush.create_time'),
prop: 'create_time',

View File

@@ -14,6 +14,11 @@
@submit.prevent=""
@keyup.enter="onSubmit()"
>
<el-divider content-position="left">{{ t('mall.playxConfig.section_daily_source') }}</el-divider>
<el-form-item :label="t('mall.playxConfig.daily_points_enabled')" prop="daily_points_enabled">
<el-switch v-model="form.daily_points_enabled" />
<div class="form-tip">{{ t('mall.playxConfig.daily_points_enabled_tip') }}</div>
</el-form-item>
<el-form-item :label="t('mall.playxConfig.return_ratio')" prop="return_ratio">
<el-input-number
v-model="form.return_ratio"
@@ -23,9 +28,57 @@
:precision="2"
controls-position="right"
class="w100"
:disabled="!form.daily_points_enabled"
/>
<div class="form-tip">{{ t('mall.playxConfig.return_ratio_tip') }}</div>
</el-form-item>
<el-divider content-position="left">{{ t('mall.playxConfig.section_lifetime_source') }}</el-divider>
<el-form-item :label="t('mall.playxConfig.lifetime_points_enabled')" prop="lifetime_points_enabled">
<el-switch v-model="form.lifetime_points_enabled" />
<div class="form-tip">{{ t('mall.playxConfig.lifetime_points_enabled_tip') }}</div>
</el-form-item>
<el-form-item :label="t('mall.playxConfig.lifetime_points_ratio')" prop="lifetime_points_ratio">
<el-input-number
v-model="form.lifetime_points_ratio"
:min="0"
:max="100"
:step="0.01"
:precision="2"
controls-position="right"
class="w100"
:disabled="!form.lifetime_points_enabled"
/>
<div class="form-tip">{{ t('mall.playxConfig.lifetime_points_ratio_tip') }}</div>
</el-form-item>
<el-form-item>
<el-button
type="warning"
:loading="calculating"
:disabled="!form.lifetime_points_enabled"
@click="onCalculateLifetime()"
>
{{ t('mall.playxConfig.calculate_lifetime_btn') }}
</el-button>
<div class="form-tip">{{ t('mall.playxConfig.calculate_lifetime_tip') }}</div>
</el-form-item>
<el-divider content-position="left">{{ t('mall.playxConfig.section_mall_open') }}</el-divider>
<el-form-item :label="t('mall.playxConfig.mall_open_date')" prop="mall_open_date">
<el-date-picker
v-model="form.mall_open_date"
type="date"
value-format="YYYY-MM-DD"
class="w100"
:placeholder="t('Please select field', { field: t('mall.playxConfig.mall_open_date') })"
/>
<div class="form-tip">{{ t('mall.playxConfig.mall_open_date_tip') }}</div>
<div v-if="activeMallOpenDate" class="form-tip">
{{ t('mall.playxConfig.active_mall_open_date') }}{{ activeMallOpenDate }}
</div>
</el-form-item>
<el-divider content-position="left">{{ t('mall.playxConfig.section_other') }}</el-divider>
<el-form-item :label="t('mall.playxConfig.unlock_ratio')" prop="unlock_ratio">
<el-input-number
v-model="form.unlock_ratio"
@@ -60,9 +113,10 @@
<script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessageBox } from 'element-plus'
import { onMounted, reactive, ref, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { index, save } from '/@/api/backend/mall/playxConfig'
import { calculateLifetimePoints, index, save } from '/@/api/backend/mall/playxConfig'
import MallPageIntro from '/@/components/mall/MallPageIntro.vue'
defineOptions({
@@ -73,18 +127,25 @@ const { t } = useI18n()
const formRef = useTemplateRef<FormInstance>('formRef')
const loading = ref(true)
const submitting = ref(false)
const calculating = ref(false)
const remark = ref('')
const activeMallOpenDate = ref('')
const form = reactive({
return_ratio: 0.1,
unlock_ratio: 0.1,
points_to_cash_ratio: 0.1,
daily_points_enabled: true,
lifetime_points_enabled: false,
lifetime_points_ratio: 0.1,
mall_open_date: '' as string | null,
})
const rules: FormRules = {
return_ratio: [{ required: true, message: t('Please input field', { field: t('mall.playxConfig.return_ratio') }) }],
unlock_ratio: [{ required: true, message: t('Please input field', { field: t('mall.playxConfig.unlock_ratio') }) }],
points_to_cash_ratio: [{ required: true, message: t('Please input field', { field: t('mall.playxConfig.points_to_cash_ratio') }) }],
lifetime_points_ratio: [{ required: true, message: t('Please input field', { field: t('mall.playxConfig.lifetime_points_ratio') }) }],
}
const loadData = () => {
@@ -93,6 +154,7 @@ const loadData = () => {
.then((res) => {
remark.value = res.data.remark ?? ''
const row = res.data.row ?? {}
activeMallOpenDate.value = row.active_mall_open_date ?? ''
if (row.return_ratio !== undefined && row.return_ratio !== null) {
form.return_ratio = parseFloat(String(row.return_ratio))
}
@@ -102,6 +164,12 @@ const loadData = () => {
if (row.points_to_cash_ratio !== undefined && row.points_to_cash_ratio !== null) {
form.points_to_cash_ratio = parseFloat(String(row.points_to_cash_ratio))
}
form.daily_points_enabled = Number(row.daily_points_enabled ?? 1) === 1
form.lifetime_points_enabled = Number(row.lifetime_points_enabled ?? 0) === 1
if (row.lifetime_points_ratio !== undefined && row.lifetime_points_ratio !== null) {
form.lifetime_points_ratio = parseFloat(String(row.lifetime_points_ratio))
}
form.mall_open_date = row.mall_open_date ? String(row.mall_open_date).slice(0, 10) : null
})
.finally(() => {
loading.value = false
@@ -116,6 +184,10 @@ const onSubmit = () => {
return_ratio: form.return_ratio,
unlock_ratio: form.unlock_ratio,
points_to_cash_ratio: form.points_to_cash_ratio,
daily_points_enabled: form.daily_points_enabled ? 1 : 0,
lifetime_points_enabled: form.lifetime_points_enabled ? 1 : 0,
lifetime_points_ratio: form.lifetime_points_ratio,
mall_open_date: form.mall_open_date || null,
})
.then(() => {
loadData()
@@ -126,6 +198,21 @@ const onSubmit = () => {
})
}
const onCalculateLifetime = () => {
ElMessageBox.confirm(t('mall.playxConfig.calculate_lifetime_confirm'), t('Reminder'), {
type: 'warning',
}).then(() => {
calculating.value = true
calculateLifetimePoints()
.then(() => {
loadData()
})
.finally(() => {
calculating.value = false
})
})
}
onMounted(() => {
loadData()
})

View File

@@ -39,9 +39,11 @@ const baTable = new baTableClass(
{ label: t('mall.playxDailyPush.date'), prop: 'date', align: 'center', render: 'date', operator: 'RANGE', comSearchRender: 'date', sortable: 'custom', width: 120, operatorPlaceholder: t('Fuzzy query') },
{ label: t('mall.playxDailyPush.username'), prop: 'username', align: 'center', operatorPlaceholder: t('Fuzzy query'), sortable: false, operator: 'LIKE' },
{ label: t('mall.playxDailyPush.yesterday_win_loss_net'), prop: 'yesterday_win_loss_net', align: 'center', operator: 'RANGE', sortable: false },
{ label: t('mall.playxDailyPush.converted_points'), prop: 'converted_points', align: 'center', operator: 'RANGE', sortable: false, width: 100 },
{ label: t('mall.playxDailyPush.yesterday_total_deposit'), prop: 'yesterday_total_deposit', align: 'center', operator: 'RANGE', sortable: false },
{ label: t('mall.playxDailyPush.lifetime_total_deposit'), prop: 'lifetime_total_deposit', align: 'center', operator: 'RANGE', sortable: false },
{ label: t('mall.playxDailyPush.lifetime_total_withdraw'), prop: 'lifetime_total_withdraw', align: 'center', operator: 'RANGE', sortable: false },
{ label: t('mall.playxDailyPush.lifetime_win_loss_net'), prop: 'lifetime_win_loss_net', align: 'center', operator: 'RANGE', sortable: false },
{ label: t('mall.playxDailyPush.create_time'), prop: 'create_time', align: 'center', render: 'datetime', operator: 'RANGE', comSearchRender: 'datetime', sortable: 'custom', width: 160, timeFormat: 'yyyy-mm-dd hh:MM:ss' },
],
dblClickNotEditColumn: [undefined],

View File

@@ -68,6 +68,8 @@ const baTable = new baTableClass(
{ label: t('mall.userAsset.available_points'), prop: 'available_points', align: 'center', operator: 'RANGE', sortable: false },
{ label: t('mall.userAsset.today_limit'), prop: 'today_limit', align: 'center', operator: 'RANGE', sortable: false },
{ label: t('mall.userAsset.today_claimed'), prop: 'today_claimed', align: 'center', operator: 'RANGE', sortable: false },
{ label: t('mall.userAsset.points_claim_cap'), prop: 'points_claim_cap', align: 'center', operator: 'RANGE', sortable: false },
{ label: t('mall.userAsset.total_points_claimed'), prop: 'total_points_claimed', align: 'center', operator: 'RANGE', sortable: false },
{
label: t('mall.userAsset.today_limit_date'),
prop: 'today_limit_date',