Commit 0543e4c9 by lijiabin

【需求 20331】 feat: 完成后台相关每日抽奖内容

parent 4fba732a
......@@ -141,7 +141,7 @@ const { loading, list, total, reset, goToPage, changePageSize, refresh, searchPa
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
......@@ -147,7 +147,7 @@ const { loading, list, total, reset, goToPage, changePageSize, refresh, searchPa
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
......@@ -140,7 +140,7 @@ const { loading, list, total, reset, goToPage, changePageSize, refresh, searchPa
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
......@@ -18,7 +18,7 @@ const { loading, list, total, reset, goToPage, changePageSize, refresh, searchPa
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
......@@ -18,7 +18,7 @@ const { loading, list, total, reset, goToPage, changePageSize, refresh, searchPa
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
......@@ -18,7 +18,7 @@ const { loading, list, total, reset, goToPage, changePageSize, refresh, searchPa
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
......@@ -18,7 +18,7 @@ const { loading, list, total, reset, goToPage, changePageSize, refresh, searchPa
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
......@@ -244,7 +244,7 @@ const columns: ExportColumn<BackendShopItemDto>[] = [
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
<script lang="tsx">
import { Transition } from 'vue'
import { KeepAlive, Transition } from 'vue'
import type { Component as VueComponent } from 'vue'
export default defineComponent(() => {
interface MenuItem {
path: string
......@@ -42,6 +43,7 @@ export default defineComponent(() => {
children: [
{ path: '/backend/settingsMenu/auctionManage', title: '限时竞拍配置' },
{ path: '/backend/settingsMenu/goodsManage', title: '积分商城配置' },
{ path: '/backend/settingsMenu/dailyLotteryManage', title: '每日抽奖配置' },
],
},
// 栏目管理
......@@ -57,9 +59,23 @@ export default defineComponent(() => {
]
const activeMenu = computed(() => route.path)
const findTitle = (menuList: MenuItem[], path: string): string | undefined => {
for (const item of menuList) {
if (item.path === path) {
return item.title
}
if (item.children?.length) {
const result = findTitle(item.children, path)
if (result) return result
}
}
return undefined
}
const currentTitle = computed(() => {
const current = menuList.find((item) => item.path === route.path)
return current?.title || ''
return findTitle(menuList, route.path)
})
const handleMenuSelect = (path: string) => {
......@@ -108,7 +124,6 @@ export default defineComponent(() => {
<div class="backend-content">
<header class="content-header">
<div class="header-left">
<img src="/webicon.png" alt="" class="header-icon" />
<h1 class="header-title">{currentTitle.value}</h1>
</div>
<div class="header-right"></div>
......@@ -116,9 +131,9 @@ export default defineComponent(() => {
<main class="content-main">
<RouterView>
{({ Component }: { Component: VNode }) => (
{({ Component }: { Component: VueComponent }) => (
<Transition name="fade" mode="out-in">
{Component}
<KeepAlive>{Component}</KeepAlive>
</Transition>
)}
</RouterView>
......
......@@ -233,7 +233,7 @@ const auctionRecordDialogRef = ref<InstanceType<typeof AuctionRecordDialog>>()
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
<template>
<el-dialog v-model="visible" title="抽奖配置" width="600px">
<el-form :model="form" label-width="120px" :rules="formRules" ref="formRef">
<el-form-item label="开放时间" prop="openRangeTime">
<el-date-picker
v-model="form.openRangeTime"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="X"
/>
</el-form-item>
<el-form-item label="自动关闭" prop="autoCloseWeekend">
<el-switch
v-model="form.autoCloseWeekend"
:active-value="1"
:inactive-value="0"
active-text="是"
inactive-text="否"
/>
</el-form-item>
<!-- 报名时间 整点 -->
<el-form-item label="报名时间" prop="registrationRangeTime">
<el-time-picker
v-model="form.registrationRangeTime"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
is-range
format="HH:00"
value-format="H"
/>
</el-form-item>
<!-- 报名费用 -->
<el-form-item label="报名费用" prop="registrationFee">
<el-input-number
v-model="form.registrationFee"
:min="0"
:max="1000000"
controls-position="right"
/>
<span class="ml-2">YA币</span>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit" :loading="loading">保存</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { getLotteryConfigDetail, setLotteryConfig } from '@/api/backend'
import { useResetData } from '@/hooks'
import type { FormInstance, FormRules } from 'element-plus'
import { BooleanFlag } from '@/constants'
import { formatSeconds } from '@/utils'
const formRules: FormRules = {
openRangeTime: [{ required: true, message: '请选择开放时间', trigger: 'change' }],
autoCloseWeekend: [{ required: true, message: '请选择是否自动关闭', trigger: 'change' }],
registrationRangeTime: [{ required: true, message: '请选择报名开始时间', trigger: 'change' }],
registrationFee: [{ required: true, message: '请输入报名费用', trigger: 'change' }],
}
const [form, resetForm] = useResetData<{
id: number | undefined
openRangeTime: string[]
autoCloseWeekend: BooleanFlag
registrationRangeTime: string[]
registrationFee: number
}>({
id: undefined,
openRangeTime: [],
autoCloseWeekend: 1,
registrationRangeTime: [],
registrationFee: 0,
})
const visible = ref(false)
const formRef = ref<FormInstance>()
const loading = ref(false)
const open = async () => {
const { data } = await getLotteryConfigDetail()
console.log(data)
if (!data) {
resetForm()
} else {
form.value = {
id: data.id,
openRangeTime: [String(data.startDate), String(data.endDate)],
autoCloseWeekend: data.autoCloseWeekend,
registrationRangeTime: [String(data.registrationStartHour), String(data.registrationEndHour)],
registrationFee: data.registrationFee,
}
}
visible.value = true
}
const handleSubmit = async () => {
await formRef.value?.validate()
const data = {
startDate: form.value.openRangeTime[0]!,
endDate: formatSeconds(form.value.openRangeTime[1]!),
autoCloseWeekend: form.value.autoCloseWeekend,
registrationStartHour: form.value.registrationRangeTime[0]!,
registrationEndHour: form.value.registrationRangeTime[1]!,
registrationFee: form.value.registrationFee,
}
loading.value = true
try {
await setLotteryConfig(data)
visible.value = false
} catch (error) {
console.error(error)
} finally {
loading.value = false
}
}
defineExpose({
open,
})
</script>
<template>
<div class="official-tag-page">
<!-- 搜索栏 -->
<div class="search-section">
<el-select
v-model="searchParams.isCurrent"
placeholder="请选择是否是本期奖品"
clearable
class="w-200px! mr-12px"
>
<el-option label="是" :value="1" />
<el-option label="否" :value="0" />
</el-select>
<el-button type="primary" @click="refresh">
<el-icon><IEpSearch /></el-icon>
搜索
</el-button>
<el-button @click="reset">重置</el-button>
<el-button type="primary" @click="handleAdd">
<el-icon><IEpPlus /></el-icon>
新增
</el-button>
<el-button type="primary" @click="handleLotteryConfig">
<el-icon class="mr-2"><IEpSetting /></el-icon>
抽奖配置
</el-button>
</div>
<!-- 表格区域 -->
<div class="table-section">
<!-- 表格 -->
<div class="table-wrapper">
<el-table v-loading="loading" :data="list" height="100%">
<el-table-column prop="name" label="名称" />
<el-table-column prop="imageUrl" label="图片">
<template #default="{ row }">
<el-image
v-if="row.imageUrl"
:preview-teleported="true"
:src="row.imageUrl"
class="w-20 h-20 object-cover"
:preview-src-list="[row.imageUrl]"
/>
<span v-else>暂无图片</span>
</template>
</el-table-column>
<el-table-column prop="isCurrent" label="本期奖品">
<template #default="{ row }">
{{ row.isCurrent ? '是' : '否' }}
</template>
</el-table-column>
<el-table-column prop="createdAt" label="创建时间">
<template #default="{ row }">
{{ dayjs(row.createdAt * 1000).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)" :disabled="row.isCurrent"
>编辑</el-button
>
<el-button type="danger" link @click="handleDelete(row)" :disabled="row.isCurrent"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination-wrapper">
<el-pagination
v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size"
:total="total"
:page-sizes="[10, 20, 30]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="changePageSize"
@current-change="goToPage"
/>
</div>
</div>
<!-- 新增/编辑对话框 -->
<el-dialog
v-model="dialogVisible"
:title="dialogTitle"
width="510px"
top="30vh"
:close-on-click-modal="false"
>
<el-form ref="formRef" :model="form" :rules="formRules" label-width="auto">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入名称(最多25个字符)" maxlength="25" />
</el-form-item>
<el-form-item label="图片" prop="imageUrl">
<UploadFile v-model="form.imageUrl" :limit="1" />
</el-form-item>
<el-form-item label="本期奖品" prop="isCurrent">
<el-switch
v-model="form.isCurrent"
:active-value="1"
:inactive-value="0"
active-text="是"
inactive-text="否"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">
<el-icon class="btn-icon"><IEpUpload /></el-icon>
保存
</el-button>
</template>
</el-dialog>
<LotteryConfig ref="lotteryConfigRef" />
</div>
</template>
<script setup lang="tsx">
import { usePageSearch, useResetData } from '@/hooks'
import { getLotteryPrizeList, addOrUpdateLotteryPrize, deleteLotteryPrize } from '@/api/backend'
import type { FormInstance, FormRules } from 'element-plus'
import type { BackendAuctionListItemDto, BackendAddOrUpdateLotteryPrizeDto } from '@/api/backend'
import UploadFile from '@/components/common/UploadFile/index.vue'
import dayjs from 'dayjs'
import LotteryConfig from './components/lotteryConfigDialog.vue'
const { loading, list, total, reset, goToPage, changePageSize, refresh, searchParams, search } =
usePageSearch(getLotteryPrizeList)
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
const [form, resetForm] = useResetData<BackendAddOrUpdateLotteryPrizeDto>({
id: undefined,
imageUrl: '',
name: '',
isCurrent: 0,
})
// 表单验证规则
const formRules: FormRules = {
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
isCurrent: [{ required: true, message: '请选择是否展示在前台', trigger: 'blur' }],
imageUrl: [{ required: true, message: '请上传图片', trigger: 'change' }],
}
const submitLoading = ref(false)
// 新增
const handleAdd = () => {
resetForm()
dialogVisible.value = true
}
// 编辑
const handleEdit = (row: BackendAddOrUpdateLotteryPrizeDto) => {
resetForm()
form.value = {
...row,
}
dialogVisible.value = true
}
//
const handleDelete = async (row: BackendAuctionListItemDto) => {
try {
await ElMessageBox.confirm(`确定要删除竞拍物品"${row.name}"吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
await deleteLotteryPrize([row.id])
refresh()
ElMessage.success('删除成功')
refresh()
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('删除失败')
}
}
}
// 提交表单
const handleSubmit = async () => {
if (!formRef.value) return
try {
submitLoading.value = true
await formRef.value.validate()
if (form.value.id) {
await addOrUpdateLotteryPrize(form.value)
} else {
await addOrUpdateLotteryPrize(form.value)
}
ElMessage.success(form.value.id ? '编辑成功' : '新增成功')
dialogVisible.value = false
if (form.value.id) {
search()
} else {
refresh()
}
} catch (error) {
console.error('表单验证失败:', error)
} finally {
submitLoading.value = false
}
}
const lotteryConfigRef = ref<InstanceType<typeof LotteryConfig>>()
const handleLotteryConfig = () => {
lotteryConfigRef.value?.open()
}
</script>
<style scoped lang="scss">
.official-tag-page {
height: 100%;
display: flex;
flex-direction: column;
gap: 16px;
}
// 搜索区域
.search-section {
background: #fff;
border-radius: 8px;
padding: 20px;
display: flex;
flex-wrap: wrap;
gap: 12px 0;
flex-shrink: 0;
.search-select {
width: 200px;
}
}
// 表格区域
.table-section {
flex: 1;
background: #fff;
border-radius: 8px;
padding: 20px;
display: flex;
flex-direction: column;
min-height: 0;
}
.table-wrapper {
flex: 1;
min-height: 0;
.color-cell {
display: flex;
align-items: center;
gap: 12px;
.color-block {
width: 100%;
height: 36px;
border-radius: 4px;
border: 1px solid #e5e7eb;
flex: 1;
}
.color-text {
color: #fff;
font-size: 14px;
font-weight: 500;
position: absolute;
left: 50%;
transform: translateX(-50%);
text-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
}
}
}
.pagination-wrapper {
display: flex;
justify-content: flex-end;
padding-top: 16px;
flex-shrink: 0;
}
// 对话框内的颜色显示
.color-value {
margin-left: 12px;
color: #606266;
font-family: monospace;
}
.btn-icon {
margin-right: 4px;
}
</style>
......@@ -194,13 +194,13 @@ import dayjs from 'dayjs'
import { BooleanFlag, ShopGoodsTypeEnum, regionListOptions } from '@/constants'
import UploadFile from '@/components/common/UploadFile/index.vue'
import type { BackendShopItemDto } from '@/api/backend'
console.log('goodsManage', UploadFile)
const { loading, list, total, reset, goToPage, changePageSize, refresh, searchParams, search } =
usePageSearch(getShopItemList)
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
......@@ -132,7 +132,7 @@ const { loading, list, total, reset, goToPage, changePageSize, refresh, searchPa
// 对话框
const dialogVisible = ref(false)
const dialogTitle = computed(() => (form.value.id ? '编辑标签' : '新增标签'))
const dialogTitle = computed(() => (form.value.id ? '编辑' : '新增'))
const formRef = ref<FormInstance>()
// 表单数据
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment