完善接口和后台页面

This commit is contained in:
2026-04-18 15:19:36 +08:00
parent a4878a9bbd
commit e3f26ba1f7
45 changed files with 3071 additions and 232 deletions

View File

@@ -0,0 +1,251 @@
<template>
<div class="default-main ba-table-box deposit-tier-page">
<el-alert type="info" :closable="false" show-icon>
{{ t('config.depositTier.desc') }}
</el-alert>
<div class="toolbar">
<el-button type="primary" :disabled="loading" @click="onAdd">
<Icon name="el-icon-Plus" />
<span class="ml-6">{{ t('config.depositTier.btn_add') }}</span>
</el-button>
<el-button type="success" :loading="saving" :disabled="loading" @click="onSave">
{{ t('config.depositTier.btn_save') }}
</el-button>
</div>
<el-table v-loading="loading" border stripe :data="items" row-key="_rowKey" max-height="720">
<el-table-column prop="sort" :label="t('config.depositTier.sort')" width="100" align="center">
<template #default="{ row }">
<el-input-number v-model="row.sort" :min="0" :max="9999" :controls="false" style="width: 100%" />
</template>
</el-table-column>
<el-table-column :label="t('config.depositTier.status')" width="100" align="center">
<template #default="{ row }">
<el-switch v-model="row.status" :active-value="1" :inactive-value="0" />
</template>
</el-table-column>
<el-table-column :label="t('config.depositTier.title_col')" min-width="180">
<template #default="{ row }">
<el-input v-model="row.title" maxlength="64" :placeholder="t('config.depositTier.title_ph')" />
</template>
</el-table-column>
<el-table-column :label="t('config.depositTier.title_en_col')" min-width="180">
<template #default="{ row }">
<el-input v-model="row.title_en" maxlength="64" :placeholder="t('config.depositTier.title_en_ph')" />
</template>
</el-table-column>
<el-table-column :label="t('config.depositTier.amount')" min-width="140">
<template #default="{ row }">
<el-input v-model="row.amount" :placeholder="t('config.depositTier.amount_ph')">
<template #suffix>
<span class="currency">{{ t('config.depositTier.currency') }}</span>
</template>
</el-input>
</template>
</el-table-column>
<el-table-column :label="t('config.depositTier.bonus_amount')" min-width="140">
<template #default="{ row }">
<el-input v-model="row.bonus_amount" :placeholder="t('config.depositTier.bonus_ph')">
<template #suffix>
<span class="currency">{{ t('config.depositTier.currency') }}</span>
</template>
</el-input>
</template>
</el-table-column>
<el-table-column :label="t('config.depositTier.desc_col')" min-width="220">
<template #default="{ row }">
<el-input v-model="row.desc" maxlength="255" :autosize="{ minRows: 1, maxRows: 3 }" type="textarea" :placeholder="t('config.depositTier.desc_ph')" />
</template>
</el-table-column>
<el-table-column :label="t('config.depositTier.desc_en_col')" min-width="220">
<template #default="{ row }">
<el-input v-model="row.desc_en" maxlength="255" :autosize="{ minRows: 1, maxRows: 3 }" type="textarea" :placeholder="t('config.depositTier.desc_en_ph')" />
</template>
</el-table-column>
<el-table-column :label="t('config.depositTier.tier_id')" width="140">
<template #default="{ row }">
<el-text class="tier-id" truncated>{{ row.id || t('config.depositTier.auto_id') }}</el-text>
</template>
</el-table-column>
<el-table-column :label="t('config.depositTier.operate')" width="90" align="center" fixed="right">
<template #default="{ $index }">
<el-button type="danger" link @click="onRemove($index)">
{{ t('config.depositTier.btn_remove') }}
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { ElMessage, ElMessageBox } from 'element-plus'
import createAxios from '/@/utils/axios'
import { auth } from '/@/utils/common'
defineOptions({
name: 'config/depositTier',
})
const { t } = useI18n()
type Tier = {
id: string
title: string
title_en: string
amount: string
bonus_amount: string
desc: string
desc_en: string
sort: number
status: number
_rowKey?: string
}
const loading = ref(false)
const saving = ref(false)
const items = ref<Tier[]>([])
function genRowKey(): string {
return 'r_' + Math.random().toString(36).slice(2, 10)
}
function emptyTier(): Tier {
return {
id: '',
title: '',
title_en: '',
amount: '',
bonus_amount: '0',
desc: '',
desc_en: '',
sort: 0,
status: 1,
_rowKey: genRowKey(),
}
}
async function load() {
loading.value = true
try {
const res = await createAxios({
url: '/admin/config.DepositTier/index',
method: 'get',
})
if (res.code === 1 && res.data) {
const list = (res.data.items || []) as Tier[]
items.value = (Array.isArray(list) ? list : []).map((it) => ({
...emptyTier(),
...it,
_rowKey: genRowKey(),
}))
}
} finally {
loading.value = false
}
}
function onAdd() {
items.value.push(emptyTier())
}
async function onRemove(idx: number) {
try {
await ElMessageBox.confirm(t('config.depositTier.confirm_remove'), t('Warning'), {
type: 'warning',
confirmButtonText: t('Delete'),
cancelButtonText: t('Cancel'),
})
} catch {
return
}
items.value.splice(idx, 1)
}
async function onSave() {
if (!auth('save')) {
return
}
for (let i = 0; i < items.value.length; i++) {
const row = items.value[i]
if (!row.title || !row.title.trim()) {
ElMessage.warning(t('config.depositTier.err_title', { no: i + 1 }))
return
}
const amount = Number(row.amount)
if (!row.amount || Number.isNaN(amount) || amount <= 0) {
ElMessage.warning(t('config.depositTier.err_amount', { no: i + 1 }))
return
}
const bonusRaw = row.bonus_amount === '' || row.bonus_amount === null || row.bonus_amount === undefined ? '0' : row.bonus_amount
const bonus = Number(bonusRaw)
if (Number.isNaN(bonus) || bonus < 0) {
ElMessage.warning(t('config.depositTier.err_bonus', { no: i + 1 }))
return
}
}
saving.value = true
try {
await createAxios({
url: '/admin/config.DepositTier/save',
method: 'post',
data: {
items: items.value.map((r) => ({
id: r.id,
title: r.title,
title_en: r.title_en || '',
amount: r.amount,
bonus_amount: r.bonus_amount === '' || r.bonus_amount === null || r.bonus_amount === undefined ? '0' : r.bonus_amount,
desc: r.desc || '',
desc_en: r.desc_en || '',
sort: r.sort,
status: r.status,
})),
},
showSuccessMessage: true,
})
await load()
} finally {
saving.value = false
}
}
onMounted(() => {
void load()
})
</script>
<style scoped lang="scss">
.deposit-tier-page {
.toolbar {
margin: 12px 0;
display: flex;
gap: 12px;
}
.currency {
color: var(--el-text-color-placeholder);
font-size: 12px;
}
.tier-id {
display: inline-block;
max-width: 120px;
color: var(--el-text-color-secondary);
font-size: 12px;
}
}
</style>