This commit is contained in:
2026-07-27 16:19:31 +08:00
parent f91eb186ca
commit abfa8e0cae
13 changed files with 198 additions and 64 deletions

View File

@@ -96,26 +96,40 @@
type="number"
v-model="baTable.form.items!.score"
prop="score"
:block-help="t('mall.item.score_tip')"
:input-attr="{ step: 1 }"
:placeholder="t('Please input field', { field: t('mall.item.score') })"
/>
<!-- BONUS / WITHDRAW现金面值流水倍数 -->
<FormItem
v-if="isBonusOrWithdraw"
:label="t('mall.item.amount')"
type="number"
v-model="baTable.form.items!.amount"
prop="amount"
:input-attr="{ step: 0.01 }"
:placeholder="t('Please input field', { field: t('mall.item.amount') })"
/>
<el-form-item v-if="isBonusOrWithdraw" :label="t('mall.item.amount')" prop="amount">
<el-input-number
v-model="baTable.form.items!.amount"
:min="0"
:step="0.01"
:precision="2"
controls-position="right"
class="w100"
:placeholder="t('Please input field', { field: t('mall.item.amount') })"
/>
<div v-if="suggestedAmount !== null" class="form-tip amount-suggest-row">
<span>{{ suggestedAmountHint }}</span>
<el-button type="primary" link @click="applySuggestedAmount">
{{ t('mall.item.amount_apply_suggested') }}
</el-button>
</div>
<div v-else-if="isBonusOrWithdraw && pointsRatioLoaded" class="form-tip">
{{ t('mall.item.amount_ratio_missing') }}
</div>
<div class="form-tip">{{ amountBlockHelp }}</div>
</el-form-item>
<FormItem
v-if="isBonusOrWithdraw"
:label="t('mall.item.multiplier')"
type="number"
v-model="baTable.form.items!.multiplier"
prop="multiplier"
:block-help="t('mall.item.multiplier_tip')"
:input-attr="{ step: 1 }"
:placeholder="t('Please input field', { field: t('mall.item.multiplier') })"
/>
@@ -190,8 +204,9 @@
<script setup lang="ts">
import type { FormItemRule } from 'element-plus'
import { computed, inject, reactive, useTemplateRef, watch } from 'vue'
import { computed, inject, reactive, ref, useTemplateRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { index as fetchPlayxConfig } from '/@/api/backend/mall/playxConfig'
import FormItem from '/@/components/formItem/index.vue'
import { useConfig } from '/@/stores/config'
import type baTableClass from '/@/utils/baTable'
@@ -203,6 +218,79 @@ const baTable = inject('baTable') as baTableClass
const { t } = useI18n()
const pointsToCashRatio = ref<number | null>(null)
const pointsRatioLoaded = ref(false)
const loadPointsToCashRatio = () => {
pointsRatioLoaded.value = false
fetchPlayxConfig()
.then((res) => {
const row = res.data.row ?? {}
const raw = row.points_to_cash_ratio
if (raw !== undefined && raw !== null && raw !== '') {
const parsed = parseFloat(String(raw))
pointsToCashRatio.value = Number.isFinite(parsed) ? parsed : null
} else {
pointsToCashRatio.value = null
}
})
.catch(() => {
pointsToCashRatio.value = null
})
.finally(() => {
pointsRatioLoaded.value = true
})
}
watch(
() => baTable.form.operate,
(op) => {
if (op === 'Add' || op === 'Edit') {
loadPointsToCashRatio()
}
},
{ immediate: true }
)
const suggestedAmount = computed(() => {
const ratio = pointsToCashRatio.value
if (ratio === null || ratio < 0) {
return null
}
const score = Number(baTable.form.items?.score)
if (!Number.isFinite(score) || score < 0) {
return null
}
return Math.round(score * ratio * 100) / 100
})
const suggestedAmountHint = computed(() => {
if (suggestedAmount.value === null || pointsToCashRatio.value === null) {
return ''
}
const score = Number(baTable.form.items?.score)
return t('mall.item.amount_suggested', {
amount: suggestedAmount.value,
score: Number.isFinite(score) ? score : 0,
ratio: pointsToCashRatio.value,
})
})
const amountBlockHelp = computed(() => {
const base = t('mall.item.amount_tip')
if (pointsToCashRatio.value === null) {
return base
}
return `${base} ${t('mall.item.points_to_cash_ratio_label')}${pointsToCashRatio.value}`
})
const applySuggestedAmount = () => {
if (suggestedAmount.value === null || !baTable.form.items) {
return
}
baTable.form.items.amount = suggestedAmount.value
}
const itemType = computed(() => baTable.form.items!.type)
const isBonus = computed(() => itemType.value === 1 || itemType.value === '1')
const isPhysical = computed(() => itemType.value === 2 || itemType.value === '2')
@@ -359,4 +447,20 @@ const rules: Partial<Record<string, FormItemRule[]>> = reactive({
})
</script>
<style scoped lang="scss"></style>
<style scoped lang="scss">
.w100 {
width: 100%;
}
.form-tip {
margin-top: 6px;
font-size: 12px;
color: var(--el-text-color-secondary);
line-height: 1.5;
}
.amount-suggest-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 4px 8px;
}
</style>

View File

@@ -15,6 +15,33 @@
@keyup.enter="onSubmit()"
>
<el-tabs v-model="activeTab" class="playx-config-tabs">
<el-tab-pane :label="t('mall.playxConfig.tab_regular')" name="regular">
<el-form-item :label="t('mall.playxConfig.unlock_ratio')" prop="unlock_ratio">
<el-input-number
v-model="form.unlock_ratio"
:min="0"
:max="100"
:step="0.01"
:precision="2"
controls-position="right"
class="w100"
/>
<div class="form-tip">{{ t('mall.playxConfig.unlock_ratio_tip') }}</div>
</el-form-item>
<el-form-item :label="t('mall.playxConfig.points_to_cash_ratio')" prop="points_to_cash_ratio">
<el-input-number
v-model="form.points_to_cash_ratio"
:min="0"
:max="100"
:step="0.01"
:precision="4"
controls-position="right"
class="w100"
/>
<div class="form-tip">{{ t('mall.playxConfig.points_to_cash_ratio_tip') }}</div>
</el-form-item>
</el-tab-pane>
<el-tab-pane :label="t('mall.playxConfig.tab_event')" name="event">
<el-divider content-position="left">{{ t('mall.playxConfig.section_event_period') }}</el-divider>
<el-form-item :label="t('mall.playxConfig.mall_open_date')" prop="mall_open_date">
@@ -94,34 +121,6 @@
<div class="form-tip">{{ t('mall.playxConfig.calculate_lifetime_tip') }}</div>
</el-form-item>
</el-tab-pane>
<el-tab-pane :label="t('mall.playxConfig.tab_regular')" name="regular">
<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"
:min="0"
:max="100"
:step="0.01"
:precision="2"
controls-position="right"
class="w100"
/>
<div class="form-tip">{{ t('mall.playxConfig.unlock_ratio_tip') }}</div>
</el-form-item>
<el-form-item :label="t('mall.playxConfig.points_to_cash_ratio')" prop="points_to_cash_ratio">
<el-input-number
v-model="form.points_to_cash_ratio"
:min="0"
:max="100"
:step="0.01"
:precision="2"
controls-position="right"
class="w100"
/>
<div class="form-tip">{{ t('mall.playxConfig.points_to_cash_ratio_tip') }}</div>
</el-form-item>
</el-tab-pane>
</el-tabs>
<el-form-item class="playx-config-submit">
@@ -150,14 +149,14 @@ const loading = ref(true)
const submitting = ref(false)
const calculating = ref(false)
const remark = ref('')
const activeTab = ref('event')
const activeTab = ref('regular')
const activeMallOpenDate = ref('')
const activeEventEndDate = ref('')
const form = reactive({
return_ratio: 0.1,
unlock_ratio: 0.1,
points_to_cash_ratio: 0.1,
points_to_cash_ratio: 0.01,
daily_points_enabled: true,
lifetime_points_enabled: false,
lifetime_points_ratio: 0.1,

View File

@@ -120,7 +120,8 @@ const baTable = new baTableClass(
label: t('mall.userAsset.event_period_win_loss_net'),
prop: 'event_period_win_loss_net',
align: 'center',
minWidth: 160,
minWidth: 140,
showOverflowTooltip: true,
operator: 'RANGE',
sortable: true,
},

View File

@@ -74,6 +74,7 @@
type="number"
v-model="baTable.form.items!.today_limit"
prop="today_limit"
:block-help="t('mall.userAsset.today_limit_tip')"
:input-attr="{ step: 1, min: 0 }"
:placeholder="t('Please input field', { field: t('mall.userAsset.today_limit') })"
/>
@@ -82,6 +83,7 @@
type="number"
v-model="baTable.form.items!.event_period_win_loss_net"
prop="event_period_win_loss_net"
:block-help="t('mall.userAsset.event_period_win_loss_net_tip')"
:input-attr="{ disabled: true, step: 0.01 }"
/>
<FormItem