553 lines
18 KiB
Vue
553 lines
18 KiB
Vue
<template>
|
||
<div class="zhuanpan-page">
|
||
<el-alert
|
||
type="info"
|
||
:closable="false"
|
||
show-icon
|
||
class="tip"
|
||
title="转盘 = 一种商品"
|
||
description="在此新建转盘商品(名称/价格/类型),再配奖池概率与库存。控奖可指定某用户必中某奖。按顶部俱乐部隔离,不影响其他俱乐部。"
|
||
/>
|
||
|
||
<div class="toolbar">
|
||
<el-button type="primary" @click="openCreate()">新建转盘商品</el-button>
|
||
<el-button @click="reloadAll">刷新</el-button>
|
||
</div>
|
||
|
||
<el-table :data="huodongList" v-loading="loading" border stripe>
|
||
<el-table-column prop="id" label="ID" width="70" />
|
||
<el-table-column prop="biaoqian" label="商品名称" min-width="140" />
|
||
<el-table-column prop="jiage" label="购票价" width="100" />
|
||
<el-table-column label="启用" width="90">
|
||
<template #default="{ row }">
|
||
<el-tag :type="row.qiyong ? 'success' : 'info'">{{ row.qiyong ? '启用' : '停用' }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="beizhu" label="备注" min-width="120" />
|
||
<el-table-column label="操作" width="320" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button link type="primary" @click="openEdit(row)">编辑</el-button>
|
||
<el-button link type="primary" @click="openJiangpin(row)">奖池</el-button>
|
||
<el-button link type="primary" @click="openKongjiang(row)">控奖</el-button>
|
||
<el-button link type="warning" @click="toggleHuodong(row)">{{ row.qiyong ? '停用' : '启用' }}</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 新建转盘商品 -->
|
||
<el-dialog v-model="createVisible" title="新建转盘商品" width="520px">
|
||
<el-form label-width="110px">
|
||
<el-form-item label="商品名称" required>
|
||
<el-input v-model="createForm.biaoqian" maxlength="45" placeholder="用户看到的购票商品名" />
|
||
</el-form-item>
|
||
<el-form-item label="购票价格" required>
|
||
<el-input-number v-model="createForm.jiage" :min="0.01" :step="1" :precision="2" controls-position="right" />
|
||
</el-form-item>
|
||
<el-form-item label="商品类型" required>
|
||
<el-select v-model="createForm.leixing_id" filterable placeholder="选择类型" style="width: 100%">
|
||
<el-option v-for="t in leixingList" :key="t.id" :label="t.jieshao" :value="t.id" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="所属专区">
|
||
<el-select v-model="createForm.zhuanqu_id" clearable filterable placeholder="可选" style="width: 100%">
|
||
<el-option
|
||
v-for="z in zhuanquFiltered"
|
||
:key="z.id"
|
||
:label="z.mingzi"
|
||
:value="z.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="商品图URL">
|
||
<el-input v-model="createForm.tupian_url" placeholder="相对路径或完整 URL" />
|
||
</el-form-item>
|
||
<el-form-item label="备注">
|
||
<el-input v-model="createForm.beizhu" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="createVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="saving" @click="saveCreate">创建</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 编辑 -->
|
||
<el-dialog v-model="editVisible" title="编辑转盘商品" width="520px">
|
||
<el-form label-width="110px">
|
||
<el-form-item label="商品名称">
|
||
<el-input v-model="editForm.biaoqian" maxlength="45" />
|
||
</el-form-item>
|
||
<el-form-item label="展示名">
|
||
<el-input v-model="editForm.mingzi" maxlength="64" />
|
||
</el-form-item>
|
||
<el-form-item label="购票价格">
|
||
<el-input-number v-model="editForm.jiage" :min="0.01" :step="1" :precision="2" controls-position="right" />
|
||
</el-form-item>
|
||
<el-form-item label="商品图URL">
|
||
<el-input v-model="editForm.tupian_url" />
|
||
</el-form-item>
|
||
<el-form-item label="备注">
|
||
<el-input v-model="editForm.beizhu" />
|
||
</el-form-item>
|
||
<el-form-item label="启用">
|
||
<el-switch v-model="editForm.qiyong" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="editVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="saving" @click="saveEdit">保存</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 奖池 -->
|
||
<el-dialog v-model="jpVisible" :title="'奖池 - ' + (currentHd?.biaoqian || currentHd?.mingzi || '')" width="860px">
|
||
<div class="toolbar">
|
||
<el-button type="primary" size="small" @click="openJpEdit()">添加奖品</el-button>
|
||
<el-button size="small" @click="loadJiangpin">刷新</el-button>
|
||
</div>
|
||
<el-table :data="jiangpinList" v-loading="jpLoading" border size="small">
|
||
<el-table-column prop="paixu" label="格子序" width="70" />
|
||
<el-table-column prop="mingzi" label="名称" min-width="110" />
|
||
<el-table-column prop="quanzhong" label="权重" width="70" />
|
||
<el-table-column label="库存" width="90">
|
||
<template #default="{ row }">{{ row.kucun === -1 ? '不限' : row.kucun }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="履约商品" min-width="140">
|
||
<template #default="{ row }">
|
||
{{ row.shi_xiexie ? '—' : (row.shangpin_biaoqian || (row.shangpin_id ? '#' + row.shangpin_id : '未绑')) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="谢谢参与" width="90">
|
||
<template #default="{ row }">{{ row.shi_xiexie ? '是' : '否' }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="140">
|
||
<template #default="{ row }">
|
||
<el-button link type="primary" @click="openJpEdit(row)">编辑</el-button>
|
||
<el-button link type="danger" @click="delJiangpin(row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-dialog>
|
||
|
||
<el-dialog v-model="jpEditVisible" :title="jpForm.id ? '编辑奖品' : '添加奖品'" width="520px">
|
||
<el-form label-width="110px">
|
||
<el-form-item label="名称"><el-input v-model="jpForm.mingzi" /></el-form-item>
|
||
<el-form-item label="格子序号"><el-input-number v-model="jpForm.paixu" :min="0" :max="50" /></el-form-item>
|
||
<el-form-item label="中奖权重"><el-input-number v-model="jpForm.quanzhong" :min="0" /></el-form-item>
|
||
<el-form-item label="库存">
|
||
<el-input-number v-model="jpForm.kucun" :min="-1" />
|
||
<div class="form-tip">-1 = 不限;0 = 普通抽奖抽不中(控奖仍可强制)</div>
|
||
</el-form-item>
|
||
<el-form-item label="谢谢参与"><el-switch v-model="jpForm.shi_xiexie" /></el-form-item>
|
||
<el-form-item v-if="!jpForm.shi_xiexie" label="履约商品">
|
||
<el-select
|
||
v-model="jpForm.shangpin_id"
|
||
clearable
|
||
filterable
|
||
placeholder="中奖后进抢池的商品(可选)"
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="g in goodsList"
|
||
:key="g.id"
|
||
:label="`${g.biaoqian}(¥${g.jiage})`"
|
||
:value="g.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="图标URL"><el-input v-model="jpForm.tupian_url" placeholder="相对路径或完整URL" /></el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="jpEditVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="saving" @click="saveJiangpin">保存</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 控奖 -->
|
||
<el-dialog v-model="kjVisible" :title="'控奖 - ' + (currentHd?.biaoqian || '')" width="760px">
|
||
<div class="toolbar">
|
||
<el-button type="primary" size="small" @click="openKjEdit()">指定必中</el-button>
|
||
<el-button size="small" @click="loadKongjiang">刷新</el-button>
|
||
</div>
|
||
<el-table :data="kongjiangList" v-loading="kjLoading" border size="small">
|
||
<el-table-column prop="yonghuid" label="用户UID" min-width="120" />
|
||
<el-table-column prop="jiangpin_mingzi" label="必中奖品" min-width="120" />
|
||
<el-table-column prop="cishu" label="剩余次数" width="90" />
|
||
<el-table-column label="启用" width="80">
|
||
<template #default="{ row }">{{ row.qiyong ? '是' : '否' }}</template>
|
||
</el-table-column>
|
||
<el-table-column prop="beizhu" label="备注" min-width="100" />
|
||
<el-table-column label="操作" width="140">
|
||
<template #default="{ row }">
|
||
<el-button link type="primary" @click="openKjEdit(row)">编辑</el-button>
|
||
<el-button link type="danger" @click="delKongjiang(row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-dialog>
|
||
|
||
<el-dialog v-model="kjEditVisible" :title="kjForm.id ? '编辑控奖' : '指定必中'" width="480px">
|
||
<el-form label-width="110px">
|
||
<el-form-item label="用户UID" required>
|
||
<el-input v-model="kjForm.yonghuid" placeholder="小程序用户 UID" />
|
||
</el-form-item>
|
||
<el-form-item label="必中奖品" required>
|
||
<el-select v-model="kjForm.jiangpin_id" filterable style="width: 100%">
|
||
<el-option v-for="p in jiangpinList" :key="p.id" :label="p.mingzi" :value="p.id" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="次数">
|
||
<el-input-number v-model="kjForm.cishu" :min="1" />
|
||
</el-form-item>
|
||
<el-form-item label="启用"><el-switch v-model="kjForm.qiyong" /></el-form-item>
|
||
<el-form-item label="备注"><el-input v-model="kjForm.beizhu" /></el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="kjEditVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="saving" @click="saveKongjiang">保存</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, computed, onMounted } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import request from '@/utils/request'
|
||
|
||
const loading = ref(false)
|
||
const jpLoading = ref(false)
|
||
const kjLoading = ref(false)
|
||
const saving = ref(false)
|
||
const huodongList = ref([])
|
||
const jiangpinList = ref([])
|
||
const kongjiangList = ref([])
|
||
const leixingList = ref([])
|
||
const zhuanquList = ref([])
|
||
const goodsList = ref([])
|
||
const currentHd = ref(null)
|
||
|
||
const createVisible = ref(false)
|
||
const createForm = reactive({
|
||
biaoqian: '幸运转盘',
|
||
jiage: 9.9,
|
||
leixing_id: null,
|
||
zhuanqu_id: null,
|
||
tupian_url: '',
|
||
beizhu: '',
|
||
})
|
||
|
||
const editVisible = ref(false)
|
||
const editForm = reactive({
|
||
id: null, biaoqian: '', mingzi: '', jiage: 0, tupian_url: '', beizhu: '', qiyong: true,
|
||
})
|
||
|
||
const jpVisible = ref(false)
|
||
const jpEditVisible = ref(false)
|
||
const jpForm = reactive({
|
||
id: null, mingzi: '', paixu: 0, quanzhong: 1, kucun: -1,
|
||
shangpin_id: null, tupian_url: '', shi_xiexie: false,
|
||
})
|
||
|
||
const kjVisible = ref(false)
|
||
const kjEditVisible = ref(false)
|
||
const kjForm = reactive({
|
||
id: null, yonghuid: '', jiangpin_id: null, cishu: 1, qiyong: true, beizhu: '',
|
||
})
|
||
|
||
const zhuanquFiltered = computed(() => {
|
||
if (!createForm.leixing_id) return zhuanquList.value
|
||
return zhuanquList.value.filter((z) => !z.leixing_id || z.leixing_id === createForm.leixing_id)
|
||
})
|
||
|
||
async function loadMeta() {
|
||
const res = await request.post('/shangpin/adzhuanpanhd', { action: 'meta' })
|
||
if (res.code === 0) {
|
||
leixingList.value = res.data?.leixing || []
|
||
zhuanquList.value = res.data?.zhuanqu || []
|
||
goodsList.value = res.data?.goods || []
|
||
}
|
||
}
|
||
|
||
async function loadHuodong() {
|
||
loading.value = true
|
||
try {
|
||
const res = await request.post('/shangpin/adzhuanpanhd', { action: 'list' })
|
||
if (res.code === 0) huodongList.value = res.data || []
|
||
else ElMessage.error(res.msg || '加载失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
async function reloadAll() {
|
||
await loadMeta()
|
||
await loadHuodong()
|
||
}
|
||
|
||
function openCreate() {
|
||
Object.assign(createForm, {
|
||
biaoqian: '幸运转盘',
|
||
jiage: 9.9,
|
||
leixing_id: leixingList.value[0]?.id || null,
|
||
zhuanqu_id: null,
|
||
tupian_url: '',
|
||
beizhu: '',
|
||
})
|
||
createVisible.value = true
|
||
}
|
||
|
||
async function saveCreate() {
|
||
if (!createForm.biaoqian) {
|
||
ElMessage.warning('请填写商品名称')
|
||
return
|
||
}
|
||
if (!createForm.leixing_id) {
|
||
ElMessage.warning('请选择商品类型')
|
||
return
|
||
}
|
||
saving.value = true
|
||
try {
|
||
const res = await request.post('/shangpin/adzhuanpanhd', {
|
||
action: 'create_product',
|
||
...createForm,
|
||
mingzi: createForm.biaoqian,
|
||
})
|
||
if (res.code === 0) {
|
||
ElMessage.success('已创建转盘商品')
|
||
createVisible.value = false
|
||
await loadHuodong()
|
||
} else ElMessage.error(res.msg || '创建失败')
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
function openEdit(row) {
|
||
Object.assign(editForm, {
|
||
id: row.id,
|
||
biaoqian: row.biaoqian || row.mingzi,
|
||
mingzi: row.mingzi,
|
||
jiage: Number(row.jiage) || 0,
|
||
tupian_url: row.tupian_url || '',
|
||
beizhu: row.beizhu || '',
|
||
qiyong: !!row.qiyong,
|
||
})
|
||
editVisible.value = true
|
||
}
|
||
|
||
async function saveEdit() {
|
||
saving.value = true
|
||
try {
|
||
const res = await request.post('/shangpin/adzhuanpanhd', {
|
||
action: 'save',
|
||
id: editForm.id,
|
||
biaoqian: editForm.biaoqian,
|
||
mingzi: editForm.mingzi,
|
||
jiage: editForm.jiage,
|
||
tupian_url: editForm.tupian_url,
|
||
beizhu: editForm.beizhu,
|
||
qiyong: editForm.qiyong,
|
||
})
|
||
if (res.code === 0) {
|
||
ElMessage.success('已保存')
|
||
editVisible.value = false
|
||
loadHuodong()
|
||
} else ElMessage.error(res.msg || '保存失败')
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
async function toggleHuodong(row) {
|
||
const res = await request.post('/shangpin/adzhuanpanhd', { action: 'toggle', id: row.id })
|
||
if (res.code === 0) {
|
||
ElMessage.success('已更新')
|
||
loadHuodong()
|
||
} else ElMessage.error(res.msg || '操作失败')
|
||
}
|
||
|
||
async function openJiangpin(row) {
|
||
currentHd.value = row
|
||
jpVisible.value = true
|
||
await loadMeta()
|
||
await loadJiangpin()
|
||
}
|
||
|
||
async function loadJiangpin() {
|
||
if (!currentHd.value) return
|
||
jpLoading.value = true
|
||
try {
|
||
const res = await request.post('/shangpin/adzhuanpanjp', {
|
||
action: 'list',
|
||
huodong_id: currentHd.value.id,
|
||
})
|
||
if (res.code === 0) jiangpinList.value = res.data || []
|
||
else ElMessage.error(res.msg || '加载失败')
|
||
} finally {
|
||
jpLoading.value = false
|
||
}
|
||
}
|
||
|
||
function openJpEdit(row) {
|
||
if (row) {
|
||
Object.assign(jpForm, {
|
||
id: row.id,
|
||
mingzi: row.mingzi,
|
||
paixu: row.paixu,
|
||
quanzhong: row.quanzhong,
|
||
kucun: row.kucun == null ? -1 : row.kucun,
|
||
shangpin_id: row.shangpin_id,
|
||
tupian_url: row.tupian_url || '',
|
||
shi_xiexie: !!row.shi_xiexie,
|
||
})
|
||
} else {
|
||
Object.assign(jpForm, {
|
||
id: null,
|
||
mingzi: '',
|
||
paixu: jiangpinList.value.length,
|
||
quanzhong: 1,
|
||
kucun: -1,
|
||
shangpin_id: null,
|
||
tupian_url: '',
|
||
shi_xiexie: false,
|
||
})
|
||
}
|
||
jpEditVisible.value = true
|
||
}
|
||
|
||
async function saveJiangpin() {
|
||
if (!currentHd.value) return
|
||
saving.value = true
|
||
try {
|
||
const res = await request.post('/shangpin/adzhuanpanjp', {
|
||
action: 'save',
|
||
huodong_id: currentHd.value.id,
|
||
id: jpForm.id,
|
||
mingzi: jpForm.mingzi,
|
||
paixu: jpForm.paixu,
|
||
quanzhong: jpForm.quanzhong,
|
||
kucun: jpForm.kucun,
|
||
shangpin_id: jpForm.shi_xiexie ? null : (jpForm.shangpin_id || null),
|
||
tupian_url: jpForm.tupian_url,
|
||
shi_xiexie: jpForm.shi_xiexie,
|
||
})
|
||
if (res.code === 0) {
|
||
ElMessage.success('已保存')
|
||
jpEditVisible.value = false
|
||
loadJiangpin()
|
||
} else ElMessage.error(res.msg || '保存失败')
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
async function delJiangpin(row) {
|
||
await ElMessageBox.confirm('确认删除该奖品?', '提示')
|
||
const res = await request.post('/shangpin/adzhuanpanjp', {
|
||
action: 'delete',
|
||
huodong_id: currentHd.value.id,
|
||
id: row.id,
|
||
})
|
||
if (res.code === 0) {
|
||
ElMessage.success('已删除')
|
||
loadJiangpin()
|
||
} else ElMessage.error(res.msg || '删除失败')
|
||
}
|
||
|
||
async function openKongjiang(row) {
|
||
currentHd.value = row
|
||
kjVisible.value = true
|
||
await loadJiangpin()
|
||
await loadKongjiang()
|
||
}
|
||
|
||
async function loadKongjiang() {
|
||
if (!currentHd.value) return
|
||
kjLoading.value = true
|
||
try {
|
||
const res = await request.post('/shangpin/adzhuanpankj', {
|
||
action: 'list',
|
||
huodong_id: currentHd.value.id,
|
||
})
|
||
if (res.code === 0) kongjiangList.value = res.data || []
|
||
else ElMessage.error(res.msg || '加载失败')
|
||
} finally {
|
||
kjLoading.value = false
|
||
}
|
||
}
|
||
|
||
function openKjEdit(row) {
|
||
if (row) {
|
||
Object.assign(kjForm, {
|
||
id: row.id,
|
||
yonghuid: row.yonghuid,
|
||
jiangpin_id: row.jiangpin_id,
|
||
cishu: row.cishu,
|
||
qiyong: !!row.qiyong,
|
||
beizhu: row.beizhu || '',
|
||
})
|
||
} else {
|
||
Object.assign(kjForm, {
|
||
id: null,
|
||
yonghuid: '',
|
||
jiangpin_id: jiangpinList.value[0]?.id || null,
|
||
cishu: 1,
|
||
qiyong: true,
|
||
beizhu: '',
|
||
})
|
||
}
|
||
kjEditVisible.value = true
|
||
}
|
||
|
||
async function saveKongjiang() {
|
||
if (!currentHd.value) return
|
||
if (!kjForm.yonghuid || !kjForm.jiangpin_id) {
|
||
ElMessage.warning('请填写用户与奖品')
|
||
return
|
||
}
|
||
saving.value = true
|
||
try {
|
||
const res = await request.post('/shangpin/adzhuanpankj', {
|
||
action: 'save',
|
||
huodong_id: currentHd.value.id,
|
||
id: kjForm.id,
|
||
yonghuid: kjForm.yonghuid,
|
||
jiangpin_id: kjForm.jiangpin_id,
|
||
cishu: kjForm.cishu,
|
||
qiyong: kjForm.qiyong,
|
||
beizhu: kjForm.beizhu,
|
||
})
|
||
if (res.code === 0) {
|
||
ElMessage.success('已保存')
|
||
kjEditVisible.value = false
|
||
loadKongjiang()
|
||
} else ElMessage.error(res.msg || '保存失败')
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
async function delKongjiang(row) {
|
||
await ElMessageBox.confirm('确认删除该控奖?', '提示')
|
||
const res = await request.post('/shangpin/adzhuanpankj', {
|
||
action: 'delete',
|
||
huodong_id: currentHd.value.id,
|
||
id: row.id,
|
||
})
|
||
if (res.code === 0) {
|
||
ElMessage.success('已删除')
|
||
loadKongjiang()
|
||
} else ElMessage.error(res.msg || '删除失败')
|
||
}
|
||
|
||
onMounted(reloadAll)
|
||
</script>
|
||
|
||
<style scoped>
|
||
.zhuanpan-page { padding: 8px; }
|
||
.tip { margin-bottom: 12px; }
|
||
.toolbar { margin-bottom: 12px; display: flex; gap: 8px; }
|
||
.form-tip { color: #909399; font-size: 12px; line-height: 1.4; margin-top: 4px; }
|
||
</style>
|