feat(admin): 权益等级管理功能完善 - 添加新增/删除权益等级功能 - 隐藏奖品配置中的中奖概率字段
This commit is contained in:
parent
14ebb2221e
commit
0c93aa7d62
|
|
@ -203,6 +203,41 @@ export function updateQyLevel(id: number, data: QyLevelUpdateRequest): Promise<A
|
|||
})
|
||||
}
|
||||
|
||||
/** 权益等级创建请求 */
|
||||
export interface QyLevelCreateRequest {
|
||||
/** 等级 */
|
||||
level: number
|
||||
/** 等级名称 */
|
||||
title: string
|
||||
/** 所需欧气值 */
|
||||
requiredPoints: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建权益等级
|
||||
* @param data 创建请求数据
|
||||
* @returns 新权益等级ID
|
||||
*/
|
||||
export function createQyLevel(data: QyLevelCreateRequest): Promise<ApiResponse<{ id: number }>> {
|
||||
return request({
|
||||
url: QYLEVEL_BASE_URL,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除权益等级(软删除)
|
||||
* @param id 权益等级ID
|
||||
* @returns 操作结果
|
||||
*/
|
||||
export function deleteQyLevel(id: number): Promise<ApiResponse<string>> {
|
||||
return request({
|
||||
url: `${QYLEVEL_BASE_URL}/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// ==================== 权益等级奖品 API ====================
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
title="编辑权益等级"
|
||||
:title="isEdit ? '编辑权益等级' : '新增权益等级'"
|
||||
width="500px"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
|
|
@ -55,14 +55,17 @@
|
|||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
||||
import {
|
||||
createQyLevel,
|
||||
updateQyLevel,
|
||||
type QyLevelResponse,
|
||||
type QyLevelCreateRequest,
|
||||
type QyLevelUpdateRequest
|
||||
} from '@/api/business/qylevel'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
level: QyLevelResponse | null
|
||||
isEdit: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
@ -131,13 +134,18 @@ const formRules: FormRules = {
|
|||
|
||||
// 监听弹窗打开,初始化数据
|
||||
watch(() => props.modelValue, (visible) => {
|
||||
if (visible && props.level) {
|
||||
// 编辑模式:回显数据
|
||||
Object.assign(formData, {
|
||||
level: props.level.level || 1,
|
||||
title: props.level.title || '',
|
||||
requiredPoints: props.level.requiredPoints || 0
|
||||
})
|
||||
if (visible) {
|
||||
if (props.isEdit && props.level) {
|
||||
// 编辑模式:回显数据
|
||||
Object.assign(formData, {
|
||||
level: props.level.level || 1,
|
||||
title: props.level.title || '',
|
||||
requiredPoints: props.level.requiredPoints || 0
|
||||
})
|
||||
} else {
|
||||
// 新增模式:重置数据
|
||||
resetForm()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -179,22 +187,32 @@ const handleSubmit = async () => {
|
|||
return
|
||||
}
|
||||
|
||||
if (!props.level) {
|
||||
ElMessage.error('未选择要编辑的等级')
|
||||
return
|
||||
}
|
||||
|
||||
submitLoading.value = true
|
||||
try {
|
||||
const submitData: QyLevelUpdateRequest = {
|
||||
level: formData.level,
|
||||
title: formData.title,
|
||||
requiredPoints: formData.requiredPoints
|
||||
if (props.isEdit) {
|
||||
// 编辑模式
|
||||
if (!props.level) {
|
||||
ElMessage.error('未选择要编辑的等级')
|
||||
return
|
||||
}
|
||||
const submitData: QyLevelUpdateRequest = {
|
||||
level: formData.level,
|
||||
title: formData.title,
|
||||
requiredPoints: formData.requiredPoints
|
||||
}
|
||||
await updateQyLevel(props.level.id, submitData)
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
// 新增模式
|
||||
const submitData: QyLevelCreateRequest = {
|
||||
level: formData.level,
|
||||
title: formData.title,
|
||||
requiredPoints: formData.requiredPoints
|
||||
}
|
||||
await createQyLevel(submitData)
|
||||
ElMessage.success('创建成功')
|
||||
}
|
||||
|
||||
await updateQyLevel(props.level.id, submitData)
|
||||
ElMessage.success('更新成功')
|
||||
|
||||
emit('success')
|
||||
handleClose()
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -29,12 +29,6 @@
|
|||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="概率" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<span class="probability-value">{{ row.probability ?? 0 }}%</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="130" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link size="small" @click="handleEdit(row)">
|
||||
|
|
@ -201,11 +195,6 @@ const handleClose = () => {
|
|||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.probability-value {
|
||||
color: #409eff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 16px;
|
||||
justify-content: flex-end;
|
||||
|
|
|
|||
|
|
@ -39,20 +39,6 @@
|
|||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 通用字段 -->
|
||||
<el-form-item label="中奖概率" prop="probability">
|
||||
<el-input-number
|
||||
v-model="formData.probability"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:precision="2"
|
||||
:step="0.1"
|
||||
placeholder="请输入中奖概率"
|
||||
style="width: 100%"
|
||||
/>
|
||||
<div class="form-tip">概率范围:0-100,最多2位小数</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
|
|
@ -107,43 +93,19 @@ const couponLoading = ref(false)
|
|||
interface FormDataType {
|
||||
couponId: number | undefined
|
||||
quantity: number
|
||||
probability: number
|
||||
}
|
||||
|
||||
const formData = reactive<FormDataType>({
|
||||
couponId: undefined,
|
||||
quantity: 1,
|
||||
probability: 0
|
||||
quantity: 1
|
||||
})
|
||||
|
||||
// 概率验证器
|
||||
const probabilityValidator = (_rule: any, value: any, callback: any) => {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
callback(new Error('请输入中奖概率'))
|
||||
} else if (typeof value !== 'number') {
|
||||
callback(new Error('概率必须为数字'))
|
||||
} else if (value < 0 || value > 100) {
|
||||
callback(new Error('概率必须在0-100之间'))
|
||||
} else {
|
||||
// 检查小数位数
|
||||
const decimalPart = value.toString().split('.')[1]
|
||||
if (decimalPart && decimalPart.length > 2) {
|
||||
callback(new Error('概率最多保留2位小数'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = computed<FormRules>(() => ({
|
||||
couponId: [{ required: true, message: '请选择优惠券', trigger: 'change' }],
|
||||
quantity: [
|
||||
{ required: true, message: '请输入数量', trigger: 'blur' },
|
||||
{ type: 'number', min: 1, message: '数量必须大于0', trigger: 'blur' }
|
||||
],
|
||||
probability: [
|
||||
{ required: true, validator: probabilityValidator, trigger: 'blur' }
|
||||
]
|
||||
}))
|
||||
|
||||
|
|
@ -170,8 +132,7 @@ watch(() => props.modelValue, (visible) => {
|
|||
// 编辑模式:回显数据
|
||||
Object.assign(formData, {
|
||||
couponId: props.prize.couponId,
|
||||
quantity: props.prize.quantity || 1,
|
||||
probability: props.prize.probability || 0
|
||||
quantity: props.prize.quantity || 1
|
||||
})
|
||||
} else {
|
||||
// 新增模式:重置数据
|
||||
|
|
@ -184,8 +145,7 @@ watch(() => props.modelValue, (visible) => {
|
|||
const resetForm = () => {
|
||||
Object.assign(formData, {
|
||||
couponId: undefined,
|
||||
quantity: 1,
|
||||
probability: 0
|
||||
quantity: 1
|
||||
})
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
|
|
@ -206,19 +166,6 @@ const handleSubmit = async () => {
|
|||
return
|
||||
}
|
||||
|
||||
// 额外验证:概率范围
|
||||
if (formData.probability < 0 || formData.probability > 100) {
|
||||
ElMessage.error('概率必须在0-100之间')
|
||||
return
|
||||
}
|
||||
|
||||
// 检查概率小数位数
|
||||
const decimalPart = formData.probability.toString().split('.')[1]
|
||||
if (decimalPart && decimalPart.length > 2) {
|
||||
ElMessage.error('概率最多保留2位小数')
|
||||
return
|
||||
}
|
||||
|
||||
// 优惠券验证
|
||||
if (!formData.couponId) {
|
||||
ElMessage.error('请选择优惠券')
|
||||
|
|
@ -234,8 +181,7 @@ const handleSubmit = async () => {
|
|||
const submitData: QyLevelPrizeCreateRequest | QyLevelPrizeUpdateRequest = {
|
||||
type: QyLevelPrizeType.Coupon,
|
||||
couponId: formData.couponId,
|
||||
quantity: formData.quantity,
|
||||
probability: formData.probability
|
||||
quantity: formData.quantity
|
||||
}
|
||||
|
||||
if (props.isEdit && props.prize) {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link size="small" @click="handleEdit(row)">
|
||||
编辑
|
||||
|
|
@ -41,6 +41,9 @@
|
|||
<el-button type="success" link size="small" @click="handlePrizes(row)">
|
||||
奖品
|
||||
</el-button>
|
||||
<el-button type="danger" link size="small" @click="handleDelete(row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
|
@ -78,6 +81,7 @@ const emit = defineEmits<{
|
|||
(e: 'size-change', size: number): void
|
||||
(e: 'edit', row: QyLevelResponse): void
|
||||
(e: 'prizes', row: QyLevelResponse): void
|
||||
(e: 'delete', row: QyLevelResponse): void
|
||||
}>()
|
||||
|
||||
const currentPage = ref(props.page)
|
||||
|
|
@ -106,6 +110,10 @@ const handleEdit = (row: QyLevelResponse) => {
|
|||
const handlePrizes = (row: QyLevelResponse) => {
|
||||
emit('prizes', row)
|
||||
}
|
||||
|
||||
const handleDelete = (row: QyLevelResponse) => {
|
||||
emit('delete', row)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>权益等级管理</span>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>新增
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -38,6 +41,7 @@
|
|||
@size-change="handleSizeChange"
|
||||
@edit="handleEdit"
|
||||
@prizes="handlePrizes"
|
||||
@delete="handleDelete"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
|
|
@ -45,6 +49,7 @@
|
|||
<QyLevelFormDialog
|
||||
v-model="formDialogVisible"
|
||||
:level="currentLevel"
|
||||
:is-edit="isEdit"
|
||||
@success="fetchData"
|
||||
/>
|
||||
|
||||
|
|
@ -58,12 +63,14 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { Search, Refresh } from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search, Refresh, Plus } from '@element-plus/icons-vue'
|
||||
import QyLevelTable from './components/QyLevelTable.vue'
|
||||
import QyLevelFormDialog from './components/QyLevelFormDialog.vue'
|
||||
import QyLevelPrizeDialog from './components/QyLevelPrizeDialog.vue'
|
||||
import {
|
||||
getQyLevels,
|
||||
deleteQyLevel,
|
||||
type QyLevelListRequest,
|
||||
type QyLevelResponse
|
||||
} from '@/api/business/qylevel'
|
||||
|
|
@ -84,6 +91,7 @@ const queryParams = reactive<QyLevelListRequest>({
|
|||
const formDialogVisible = ref(false)
|
||||
const prizeDialogVisible = ref(false)
|
||||
const currentLevel = ref<QyLevelResponse | null>(null)
|
||||
const isEdit = ref(false)
|
||||
|
||||
// 获取权益等级列表
|
||||
const fetchData = async () => {
|
||||
|
|
@ -122,12 +130,36 @@ const handleSizeChange = (size: number) => {
|
|||
fetchData()
|
||||
}
|
||||
|
||||
// 新增权益等级
|
||||
const handleAdd = () => {
|
||||
isEdit.value = false
|
||||
currentLevel.value = null
|
||||
formDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 编辑权益等级
|
||||
const handleEdit = (row: QyLevelResponse) => {
|
||||
isEdit.value = true
|
||||
currentLevel.value = { ...row }
|
||||
formDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 删除权益等级
|
||||
const handleDelete = async (row: QyLevelResponse) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定要删除等级"${row.title}"吗?删除后不可恢复!`,
|
||||
'删除确认',
|
||||
{ type: 'warning' }
|
||||
)
|
||||
await deleteQyLevel(row.id)
|
||||
ElMessage.success('删除成功')
|
||||
fetchData()
|
||||
} catch {
|
||||
// 取消操作
|
||||
}
|
||||
}
|
||||
|
||||
// 查看奖品
|
||||
const handlePrizes = (row: QyLevelResponse) => {
|
||||
currentLevel.value = { ...row }
|
||||
|
|
@ -150,6 +182,11 @@ onMounted(() => {
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user