Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
corporate-culture-qd
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
王立鹏
corporate-culture-qd
Commits
feb96717
Commit
feb96717
authored
Apr 02, 2026
by
lijiabin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【需求 20520】 feat: 完成后台大转盘
parent
6f7c627b
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
381 additions
and
0 deletions
+381
-0
wheelConfigDialog.vue
...ngsMenu/luckyWheelManage/components/wheelConfigDialog.vue
+88
-0
index.vue
src/views/backend/settingsMenu/luckyWheelManage/index.vue
+293
-0
No files found.
src/views/backend/settingsMenu/luckyWheelManage/components/wheelConfigDialog.vue
0 → 100644
View file @
feb96717
<
template
>
<el-dialog
v-model=
"visible"
title=
"抽奖配置"
width=
"500px"
>
<el-form
:model=
"form"
label-width=
"100px"
: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=
"costYaCoin"
>
<el-input-number
v-model=
"form.costYaCoin"
: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
{
getWheelConfig
,
setWheelConfig
}
from
'@/api/backend'
import
{
useResetData
}
from
'@/hooks'
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
{
push
}
from
'notivue'
import
{
formatSeconds
}
from
'@/utils'
const
formRules
:
FormRules
=
{
openRangeTime
:
[{
required
:
true
,
message
:
'请选择开放时间'
,
trigger
:
'change'
}],
costYaCoin
:
[{
required
:
true
,
message
:
'请输入参与费用'
,
trigger
:
'change'
}],
}
const
[
form
,
resetForm
]
=
useResetData
<
{
openRangeTime
:
string
[]
costYaCoin
:
number
}
>
({
openRangeTime
:
[],
costYaCoin
:
0
,
})
const
visible
=
ref
(
false
)
const
formRef
=
ref
<
FormInstance
>
()
const
loading
=
ref
(
false
)
const
open
=
async
()
=>
{
const
{
data
}
=
await
getWheelConfig
()
if
(
!
data
)
{
resetForm
()
}
else
{
form
.
value
=
{
openRangeTime
:
[
String
(
data
.
startTime
),
String
(
data
.
endTime
)],
costYaCoin
:
data
.
costYaCoin
,
}
}
visible
.
value
=
true
}
const
handleSubmit
=
async
()
=>
{
await
formRef
.
value
?.
validate
()
loading
.
value
=
true
try
{
await
setWheelConfig
({
startTime
:
form
.
value
.
openRangeTime
[
0
]
!
,
endTime
:
formatSeconds
(
form
.
value
.
openRangeTime
[
1
]
!
),
costYaCoin
:
form
.
value
.
costYaCoin
,
})
push
.
success
(
'保存成功'
)
visible
.
value
=
false
}
catch
(
error
)
{
console
.
error
(
error
)
}
finally
{
loading
.
value
=
false
}
}
defineExpose
({
open
})
</
script
>
src/views/backend/settingsMenu/luckyWheelManage/index.vue
0 → 100644
View file @
feb96717
<
template
>
<div
class=
"official-tag-page"
>
<!-- 搜索栏 -->
<div
class=
"search-section"
>
<el-input
v-model=
"searchParams.name"
placeholder=
"请输入奖品名称"
clearable
class=
"w-200px! mr-12px"
/>
<el-select
v-model=
"searchParams.isEnabled"
placeholder=
"是否启用"
clearable
class=
"w-200px! mr-12px"
>
<el-option
label=
"是"
:value=
"BooleanFlag.YES"
/>
<el-option
label=
"否"
:value=
"BooleanFlag.NO"
/>
</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=
"handleWheelConfig"
>
<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=
"quantity"
label=
"奖品数量"
/>
<el-table-column
prop=
"probability"
label=
"中奖概率"
>
<
template
#
default=
"{ row }"
>
{{
row
.
probability
}}
%
</
template
>
</el-table-column>
<el-table-column
prop=
"isEnabled"
label=
"是否启用"
>
<
template
#
default=
"{ row }"
>
{{
row
.
isEnabled
===
BooleanFlag
.
YES
?
'是'
:
'否'
}}
</
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"
width=
"140"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"primary"
link
@
click=
"handleEdit(row)"
>
编辑
</el-button>
<el-button
type=
"danger"
link
@
click=
"handleDelete(row)"
>
删除
</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=
"20vh"
: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=
"quantity"
>
<el-input-number
v-model=
"form.quantity"
:min=
"0"
:max=
"999999"
controls-position=
"right"
/>
</el-form-item>
<el-form-item
label=
"中奖概率"
prop=
"probability"
>
<el-input-number
v-model=
"form.probability"
:min=
"0"
:max=
"100"
:precision=
"2"
:step=
"0.01"
controls-position=
"right"
/>
<span
class=
"ml-2"
>
%
</span>
</el-form-item>
<el-form-item
label=
"是否启用"
prop=
"isEnabled"
>
<el-switch
v-model=
"form.isEnabled"
:active-value=
"BooleanFlag.YES"
:inactive-value=
"BooleanFlag.NO"
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>
<WheelConfig
ref=
"wheelConfigRef"
/>
</div>
</template>
<
script
setup
lang=
"tsx"
>
import
{
usePageSearch
,
useResetData
}
from
'@/hooks'
import
{
getWheelPrizeList
,
addOrUpdateWheelPrize
,
deleteWheelPrize
}
from
'@/api/backend'
import
type
{
FormInstance
,
FormRules
}
from
'element-plus'
import
type
{
BackendWheelPrizeListItemDto
,
BackendAddOrUpdateWheelPrizeDto
}
from
'@/api/backend'
import
UploadFile
from
'@/components/common/UploadFile/index.vue'
import
dayjs
from
'dayjs'
import
WheelConfig
from
'./components/wheelConfigDialog.vue'
import
{
push
}
from
'notivue'
import
{
useMessageBox
}
from
'@/hooks'
import
{
BooleanFlag
}
from
'@/constants'
const
{
confirm
}
=
useMessageBox
()
const
{
loading
,
list
,
total
,
reset
,
goToPage
,
changePageSize
,
refresh
,
searchParams
,
search
}
=
usePageSearch
(
getWheelPrizeList
)
const
dialogVisible
=
ref
(
false
)
const
dialogTitle
=
computed
(()
=>
(
form
.
value
.
id
?
'编辑'
:
'新增'
))
const
formRef
=
ref
<
FormInstance
>
()
const
[
form
,
resetForm
]
=
useResetData
<
BackendAddOrUpdateWheelPrizeDto
>
({
id
:
undefined
,
imageUrl
:
''
,
name
:
''
,
quantity
:
0
,
probability
:
0
,
isEnabled
:
BooleanFlag
.
YES
,
})
const
formRules
:
FormRules
=
{
name
:
[{
required
:
true
,
message
:
'请输入名称'
,
trigger
:
'blur'
}],
imageUrl
:
[{
required
:
true
,
message
:
'请上传图片'
,
trigger
:
'change'
}],
quantity
:
[{
required
:
true
,
message
:
'请输入奖品数量'
,
trigger
:
'change'
}],
probability
:
[{
required
:
true
,
message
:
'请输入中奖概率'
,
trigger
:
'change'
}],
isEnabled
:
[{
required
:
true
,
message
:
'请选择是否启用'
,
trigger
:
'change'
}],
}
const
submitLoading
=
ref
(
false
)
const
handleAdd
=
()
=>
{
resetForm
()
dialogVisible
.
value
=
true
}
const
handleEdit
=
(
row
:
BackendWheelPrizeListItemDto
)
=>
{
resetForm
()
form
.
value
=
{
id
:
row
.
id
,
name
:
row
.
name
,
imageUrl
:
row
.
imageUrl
,
quantity
:
row
.
quantity
,
probability
:
row
.
probability
,
isEnabled
:
row
.
isEnabled
,
}
dialogVisible
.
value
=
true
}
const
handleDelete
=
async
(
row
:
BackendWheelPrizeListItemDto
)
=>
{
await
confirm
({
title
:
'提示'
,
message
:
`确定要删除奖品"
${
row
.
name
}
"吗?`
,
type
:
'danger'
,
})
try
{
await
deleteWheelPrize
([
row
.
id
])
push
.
success
(
'删除成功'
)
refresh
()
}
catch
(
error
)
{
if
(
error
!==
'cancel'
)
{
push
.
error
(
'删除失败'
)
}
}
}
const
handleSubmit
=
async
()
=>
{
if
(
!
formRef
.
value
)
return
try
{
submitLoading
.
value
=
true
await
formRef
.
value
.
validate
()
await
addOrUpdateWheelPrize
(
form
.
value
)
push
.
success
(
form
.
value
.
id
?
'编辑成功'
:
'新增成功'
)
dialogVisible
.
value
=
false
if
(
form
.
value
.
id
)
{
search
()
}
else
{
refresh
()
}
}
catch
(
error
)
{
console
.
error
(
'表单验证失败:'
,
error
)
}
finally
{
submitLoading
.
value
=
false
}
}
const
wheelConfigRef
=
ref
<
InstanceType
<
typeof
WheelConfig
>>
()
const
handleWheelConfig
=
()
=>
{
wheelConfigRef
.
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
;
}
.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
;
}
.pagination-wrapper
{
display
:
flex
;
justify-content
:
flex-end
;
padding-top
:
16px
;
flex-shrink
:
0
;
}
.btn-icon
{
margin-right
:
4px
;
}
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment