Commit 4fba732a by lijiabin

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

parent e0529745
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
</div> </div>
<div class="flex gap-3"> <div class="flex gap-3">
<div class="left basis-3/4 transition-all duration-500"> <div class="left basis-7/10 xl:basis-3/4 transition-all duration-500">
<div <div
id="tabsRef" id="tabsRef"
ref="tabsRef" ref="tabsRef"
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
</div> </div>
</div> </div>
<!-- 屏幕变小直接隐藏 --> <!-- 屏幕变小直接隐藏 -->
<div class="right flex-col gap-3 flex basis-1/4"> <div class="right flex-col gap-3 flex basis-3/10 xl:basis-1/4 min-w-0">
<!-- 等级等相关信息 --> <!-- 等级等相关信息 -->
<div <div
ref="levelContainerRef" ref="levelContainerRef"
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
:content="`当前经验:${userAccountData.expTotal}/${currentLevelData.expScope[1]} (${currentLevelData.percentage}%)`" :content="`当前经验:${userAccountData.expTotal}/${currentLevelData.expScope[1]} (${currentLevelData.percentage}%)`"
placement="top" placement="top"
> >
<div class="relative w-20 cursor-pointer"> <div class="relative w-20 cursor-pointer flex-1">
<div <div
class="relative w-full h-4 bg-#A5E4FF rounded-full border-1 border-#30C4FF border-solid" class="relative w-full h-4 bg-#A5E4FF rounded-full border-1 border-#30C4FF border-solid"
> >
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
<!-- v-if="!userRecordData.isSign" --> <!-- v-if="!userRecordData.isSign" -->
<svg-icon name="sign_in" size="24" class="mr-2 mb-1" /> <svg-icon name="sign_in" size="24" class="mr-2 mb-1" />
<span class="text-black text-xs sm:text-sm">立即签到</span> <span class="text-#333 text-xs sm:text-sm">立即签到</span>
</el-button> </el-button>
</div> </div>
<el-button <el-button
...@@ -115,7 +115,7 @@ ...@@ -115,7 +115,7 @@
@click="router.push('/pointsStore')" @click="router.push('/pointsStore')"
> >
<svg-icon name="points_store" size="24" class="mr-2 mb-1" /> <svg-icon name="points_store" size="24" class="mr-2 mb-1" />
<span class="text-black text-xs sm:text-sm">积分商城</span> <span class="text-#333 text-xs sm:text-sm">积分商城</span>
</el-button> </el-button>
</div> </div>
</div> </div>
...@@ -136,7 +136,7 @@ ...@@ -136,7 +136,7 @@
@click="router.push('/publishCase')" @click="router.push('/publishCase')"
> >
<svg-icon name="submit" size="20" class="mr-2" /> <svg-icon name="submit" size="20" class="mr-2" />
<span class="text-black text-xs sm:text-sm">去投稿</span> <span class="text-#333 text-xs sm:text-sm">去投稿</span>
</el-button> </el-button>
</div> </div>
</div> </div>
...@@ -148,7 +148,7 @@ ...@@ -148,7 +148,7 @@
@click="publishTopic" @click="publishTopic"
> >
<svg-icon name="topic_release" size="80" /> <svg-icon name="topic_release" size="80" />
<div class="text-xs 2xl:text-sm">话题发布</div> <div class="text-xs xl:text-sm">话题发布</div>
</div> </div>
<div <div
class="flex flex-col items-center justify-center text-center cursor-pointer hover:-translate-y-1 transition-transform duration-200 p-2 rounded-lg hover:bg-white/10" class="flex flex-col items-center justify-center text-center cursor-pointer hover:-translate-y-1 transition-transform duration-200 p-2 rounded-lg hover:bg-white/10"
...@@ -158,7 +158,7 @@ ...@@ -158,7 +158,7 @@
<svg-icon name="answer" size="80" /> <svg-icon name="answer" size="80" />
</el-badge> </el-badge>
<div class="text-xs 2xl:text-sm">回答问题</div> <div class="text-xs xl:text-sm">回答问题</div>
</div> </div>
<div <div
...@@ -166,7 +166,7 @@ ...@@ -166,7 +166,7 @@
class="flex flex-col items-center justify-center text-center cursor-pointer hover:-translate-y-1 transition-transform duration-200 p-2 rounded-lg hover:bg-white/10" class="flex flex-col items-center justify-center text-center cursor-pointer hover:-translate-y-1 transition-transform duration-200 p-2 rounded-lg hover:bg-white/10"
> >
<svg-icon name="video_release" size="80" /> <svg-icon name="video_release" size="80" />
<div class="text-xs 2xl:text-sm">视频发布</div> <div class="text-xs xl:text-sm">视频发布</div>
</div> </div>
</div> </div>
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
...@@ -176,7 +176,7 @@ ...@@ -176,7 +176,7 @@
type="primary" type="primary"
> >
<svg-icon name="my_answer" size="20" class="mr-2" /> <svg-icon name="my_answer" size="20" class="mr-2" />
<span class="text-black text-xs sm:text-sm">我的回答</span> <span class="text-#333 text-xs sm:text-sm">我的回答</span>
</el-button> </el-button>
</div> </div>
</div> </div>
...@@ -216,7 +216,7 @@ ...@@ -216,7 +216,7 @@
class="flex items-center justify-between hover:bg-white/10 rounded-lg transition-colors duration-200 group" class="flex items-center justify-between hover:bg-white/10 rounded-lg transition-colors duration-200 group"
> >
<div class="flex items-center min-w-0 flex-1"> <div class="flex items-center min-w-0 flex-1">
<div class="h-16 2xl:h-19 flex items-center justify-center"> <div class="h-16 xl:h-19 flex items-center justify-center">
<svg-icon :name="item.svgName" size="46" /> <svg-icon :name="item.svgName" size="46" />
</div> </div>
<div <div
...@@ -239,7 +239,7 @@ ...@@ -239,7 +239,7 @@
</div> </div>
</div> </div>
<button <button
class="w-16 h-8 2xl:w-18 2xl:h-9 shadow-[0_1px_8px_0_rgba(255,141,54,0.25)] border-none text-xs sm:text-sm rounded-full" class="w-16 h-8 xl:w-18 xl:h-9 shadow-[0_1px_8px_0_rgba(255,141,54,0.25)] border-none text-xs sm:text-sm rounded-full"
:class="[ :class="[
item.currentCount === item.limitCount item.currentCount === item.limitCount
? 'bg-#FFC5A1 cursor-not-allowed' ? 'bg-#FFC5A1 cursor-not-allowed'
...@@ -266,6 +266,48 @@ ...@@ -266,6 +266,48 @@
</div> </div>
</div> </div>
</div> </div>
<!-- 每日抽奖 -->
<div v-if="lotteryPrizesDetail" class="lottery-container common-box rounded-lg bg-#FFF7E6">
<div class="flex items-center gap-2 mb-3">
<div class="w-1 h-4 bg-gradient-to-b from-amber-400 to-orange-400 rounded-full"></div>
<h1 class="text-sm sm:text-base font-bold">每日抽奖</h1>
</div>
<div class="flex items-center gap-3 min-w-0">
<el-image
class="h-20 rounded-lg"
:src="lotteryPrizesDetail.prizesImg"
fit="cover"
:preview-src-list="[lotteryPrizesDetail.prizesImg]"
/>
<div class="flex flex-col min-w-0">
<div class="font-semibold truncate mb-1">
奖品名称:{{ lotteryPrizesDetail.prizesName }}
</div>
<div class="text-13px text-gray-500 truncate tracking-wider">
参与费用:{{ lotteryPrizesDetail.registrationFee }}YA币
</div>
<div class="text-13px text-gray-500 truncate tracking-wider">
今日参与:{{ lotteryPrizesDetail.number }}
</div>
</div>
</div>
<div class="text-sm text-gray-500 my-2" v-if="lotteryPrizesDetail.winner">
恭喜昨日中奖者{{ lotteryPrizesDetail.winner }}
</div>
<div class="flex justify-center items-center mt-3">
<el-button
class="w-80%! bg-[linear-gradient(to_right,#FFD06A_0%,#FFB143_100%)] shadow-[0px_1px_8px_0_rgba(255,173,91,0.25)] border-none hover:-translate-y-1 hover:shadow-[0px_4px_10px_0_rgba(255,173,91,0.4)] hover:scale-105 active:scale-95 active:translate-y-0 transition-all duration-200 flex-1 text-xs sm:text-sm text-#333!"
type="primary"
@click="handleLottery"
>
<svg-icon name="daily_lottery" size="18" class="mr-2 mb-1" />
参与抽奖
</el-button>
</div>
</div>
</div> </div>
</div> </div>
...@@ -283,9 +325,23 @@ import front from '@/assets/img/culture/front_page.png' ...@@ -283,9 +325,23 @@ import front from '@/assets/img/culture/front_page.png'
import ya from '@/assets/img/culture/ya_culture.png' import ya from '@/assets/img/culture/ya_culture.png'
import ask from '@/assets/img/culture/ask.png' import ask from '@/assets/img/culture/ask.png'
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router' import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router'
import { getTaskList, dailySign, getCarouselList, getUserAccountData, getRecordData } from '@/api' import {
getTaskList,
dailySign,
getCarouselList,
getUserAccountData,
getRecordData,
getUserDailyLotteryInfo,
userJoinLottery,
} from '@/api'
import { TaskTypeEnum, TaskDateLimitTypeText, ArticleTypeEnum } from '@/constants' import { TaskTypeEnum, TaskDateLimitTypeText, ArticleTypeEnum } from '@/constants'
import type { CarouselItemDto, TaskItemDto, UserAccountDataDto, UserRecordDataDto } from '@/api' import type {
CarouselItemDto,
TaskItemDto,
UserAccountDataDto,
UserRecordDataDto,
DailyLotteryInfo,
} from '@/api'
import { TABS_REF_KEY, levelListOptions } from '@/constants' import { TABS_REF_KEY, levelListOptions } from '@/constants'
import { useScrollTop } from '@/hooks' import { useScrollTop } from '@/hooks'
import { useQuestionStore } from '@/stores/question' import { useQuestionStore } from '@/stores/question'
...@@ -378,7 +434,6 @@ const currentLevelData = computed<{ ...@@ -378,7 +434,6 @@ const currentLevelData = computed<{
100 100
).toFixed(2), ).toFixed(2),
) )
console.log(percentage)
return { return {
label: levelData.label, label: levelData.label,
iconUrl: levelData.iconUrl, iconUrl: levelData.iconUrl,
...@@ -391,13 +446,27 @@ const userRecordData = ref({} as UserRecordDataDto) ...@@ -391,13 +446,27 @@ const userRecordData = ref({} as UserRecordDataDto)
const onDailySign = async () => { const onDailySign = async () => {
await dailySign() await dailySign()
await refreshTaskData(true) refreshTaskData(true)
const { data } = await getUserAccountData() refreshUserAccountData()
userAccountData.value = data
ElMessage.success('签到成功') ElMessage.success('签到成功')
open.value = false open.value = false
} }
const lotteryPrizesDetail = ref<DailyLotteryInfo | null>(null)
// 获取抽奖配置详情
const getLotteryPrizesDetail = async () => {
const { data } = await getUserDailyLotteryInfo()
lotteryPrizesDetail.value = data
}
// 参与抽奖
const handleLottery = async () => {
await userJoinLottery()
getLotteryPrizesDetail()
refreshUserAccountData()
ElMessage.success('参与每日抽奖成功!')
}
const handleTask = async (item: TaskItemDto) => { const handleTask = async (item: TaskItemDto) => {
console.log(item) console.log(item)
if (item.currentCount === item.limitCount) return if (item.currentCount === item.limitCount) return
...@@ -444,21 +513,33 @@ const handleClickCarousel = (item: CarouselItemDto) => { ...@@ -444,21 +513,33 @@ const handleClickCarousel = (item: CarouselItemDto) => {
} }
const initPage = () => { const initPage = () => {
Promise.allSettled([getCarouselList(), getUserAccountData(), getRecordData()]).then( Promise.allSettled([
([r1, r2, r3]) => { getCarouselList(),
if (r1.status === 'fulfilled') { getUserAccountData(),
carouselList.value = r1.value.data getRecordData(),
} getUserDailyLotteryInfo(),
]).then(([r1, r2, r3, r4]) => {
if (r2.status === 'fulfilled') { if (r1.status === 'fulfilled') {
userAccountData.value = r2.value.data carouselList.value = r1.value.data
} }
if (r3.status === 'fulfilled') {
userRecordData.value = r3.value.data if (r2.status === 'fulfilled') {
} userAccountData.value = r2.value.data
}, }
) if (r3.status === 'fulfilled') {
userRecordData.value = r3.value.data
}
if (r4.status === 'fulfilled') {
lotteryPrizesDetail.value = r4.value.data
}
})
}
const refreshUserAccountData = async () => {
const { data } = await getUserAccountData()
userAccountData.value = data
} }
const refreshTaskData = async (refreshRecordData = false) => { const refreshTaskData = async (refreshRecordData = false) => {
if (refreshRecordData) { if (refreshRecordData) {
const { data } = await getRecordData() const { data } = await getRecordData()
...@@ -473,6 +554,8 @@ const refreshTaskData = async (refreshRecordData = false) => { ...@@ -473,6 +554,8 @@ const refreshTaskData = async (refreshRecordData = false) => {
onActivated(async () => { onActivated(async () => {
questionStore.fetchUserQestionNum() questionStore.fetchUserQestionNum()
refreshTaskData(false) refreshTaskData(false)
refreshUserAccountData()
getLotteryPrizesDetail()
if (route.fullPath.includes('#levelContainerRef')) { if (route.fullPath.includes('#levelContainerRef')) {
await handleBackTop() await handleBackTop()
open.value = true open.value = true
......
...@@ -10,7 +10,13 @@ ...@@ -10,7 +10,13 @@
<el-form ref="formRef" :model="form" :rules="rules" label-width="60px" class="px-4"> <el-form ref="formRef" :model="form" :rules="rules" label-width="60px" class="px-4">
<!-- 昵称 --> <!-- 昵称 -->
<el-form-item label="昵称" prop="hiddenName"> <el-form-item label="昵称" prop="hiddenName">
<el-input v-model="form.hiddenName" placeholder="将心比心" clearable class="w-full" /> <el-input
v-model="form.hiddenName"
placeholder="请输入昵称"
clearable
class="w-full"
maxlength="15"
/>
</el-form-item> </el-form-item>
<!-- 签名 --> <!-- 签名 -->
......
<template> <template>
<div class="flex-1 flex flex-col" v-loading="loading"> <div class="flex-1 flex flex-col">
<div class="flex-1 p-4 pt-1"> <div class="flex-1 p-4 pt-1">
<div class="relative"> <div class="relative">
<el-tabs v-model="searchParams.type" @tab-change="toggleTab"> <el-tabs v-model="tab" @tab-change="toggleTab">
<el-tab-pane <el-tab-pane
v-for="tab in activityTypeListOptions" v-for="tab in activityTypeListOptions"
:key="tab.value" :key="tab.value"
:label="tab.label" :label="tab.label"
:name="tab.value" :name="tab.value"
/> >
<component :is="tab.component" />
</el-tab-pane>
</el-tabs> </el-tabs>
<div class="absolute right-0 top-2.5 z-1000"> <div class="absolute right-0 top-2.5 z-1000">
<el-icon <el-icon
...@@ -20,7 +22,7 @@ ...@@ -20,7 +22,7 @@
</div> </div>
</div> </div>
<!-- 加一行提示 --> <!-- 加一行提示 -->
<div class="flex justify-end"> <!-- <div class="flex justify-end">
<p class="text-gray-500 text-sm mb-1 flex items-center gap-1"> <p class="text-gray-500 text-sm mb-1 flex items-center gap-1">
<el-icon><IEpInfoFilled /></el-icon> <el-icon><IEpInfoFilled /></el-icon>
页面仅展示竞拍成功的记录 页面仅展示竞拍成功的记录
...@@ -58,41 +60,168 @@ ...@@ -58,41 +60,168 @@
class="custom-pagination" class="custom-pagination"
/> />
</div> </div>
</div> -->
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="tsx" setup>
import { getSelfAuctionRecord } from '@/api' import { getSelfAuctionRecord, getUserLotteryRecordList } from '@/api'
import { usePageSearch } from '@/hooks' import { usePageSearch } from '@/hooks'
import { activityTypeListOptions } from '@/constants/options'
import { ActivityTypeEnum } from '@/constants/enums' import { ActivityTypeEnum } from '@/constants/enums'
import type { TabPaneName } from 'element-plus' import type { UserLotteryRecordItemDto } from '@/api/dailyLottery/types'
const toggleTab = (key: TabPaneName) => { const EmptyComp = () => (
searchParams.value.type = key as ActivityTypeEnum <div class="flex flex-col items-center justify-center h-64">
refresh() <div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mb-4">
} <el-icon class="text-2xl text-gray-300">
<IEpDocument />
</el-icon>
</div>
<div class="text-gray-500 text-lg mb-2">暂无内容</div>
</div>
)
const { list, loading, searchParams, total, refresh, goToPage, changePageSize } = usePageSearch( const activityTypeListOptions = [
getSelfAuctionRecord,
{ {
defaultParams: { label: '限时竞拍',
type: activityTypeListOptions[0]!.value, value: ActivityTypeEnum.AUCTION,
}, component: () => (
immediate: false, <>
<div class="flex justify-end">
<p class="text-gray-500 text-sm mb-1 flex items-center gap-1">
<el-icon>
<IEpInfoFilled />
</el-icon>
页面仅展示竞拍成功的记录
</p>
</div>
{!list1.value.length ? (
<EmptyComp />
) : (
<>
<div class="space-y-4">
<el-table height="500" data={list1.value} stripe border loading={loading1.value}>
<el-table-column prop="name" label="名称" />
<el-table-column prop="startingPrice" label="起拍价" />
<el-table-column prop="bidPrice" label="支出YA币" />
</el-table>
</div>
<div class="flex items-center justify-end px-6 py-4 border-t border-gray-200">
<div class="pagination-wrapper bg-white rounded-lg shadow-sm border border-gray-100 p-2">
<el-pagination
v-model:current-page={searchParams1.value.current}
v-model:page-size={searchParams1.value.size}
onSizeChange={changePageSize1}
onCurrentChange={goToPage1}
page-sizes={[10, 20, 30, 40]}
layout="prev, pager, next, jumper, total"
total={total1.value}
class="custom-pagination"
/>
</div>
</div>
</>
)}
</>
),
refresh: () => refresh1(),
}, },
) {
label: '每日抽奖',
value: ActivityTypeEnum.DAILY_LOTTERY,
component: () => (
<>
{!list2.value.length ? (
<EmptyComp />
) : (
<>
<div class="space-y-4">
<el-table height="500" data={list2.value} stripe border loading={loading2.value}>
<el-table-column prop="prizeName" label="名称" />
<el-table-column prop="activityDateRange" label="参与时间" />
<el-table-column prop="isLotteryDone" label="是否开奖">
{({ row }: { row: UserLotteryRecordItemDto }) => (
<div>{row.isLotteryDone ? <span></span> : <span>否</span>}</div>
)}
</el-table-column>
<el-table-column prop="isWin" label="是否中奖">
{({ row }: { row: UserLotteryRecordItemDto }) => (
<div>
{row.isLotteryDone ? (
row.isWin ? (
<span class="text-green-500"></span>
) : (
<span class="text-red-500"></span>
)
) : (
'暂未开奖'
)}
</div>
)}
</el-table-column>
</el-table>
</div>
<div class="flex items-center justify-end px-6 py-4 border-t border-gray-200">
<div class="pagination-wrapper bg-white rounded-lg shadow-sm border border-gray-100 p-2">
<el-pagination
v-model:current-page={searchParams2.value.current}
v-model:page-size={searchParams2.value.size}
onSizeChange={changePageSize2}
onCurrentChange={goToPage2}
page-sizes={[10, 20, 30, 40]}
layout="prev, pager, next, jumper, total"
total={total2.value}
class="custom-pagination"
/>
</div>
</div>
</>
)}
</>
),
refresh: () => refresh2(),
},
]
const tab = ref(activityTypeListOptions[0]!.value)
const toggleTab = () => {
refresh()
}
const {
list: list1,
loading: loading1,
searchParams: searchParams1,
total: total1,
refresh: refresh1,
goToPage: goToPage1,
changePageSize: changePageSize1,
} = usePageSearch(getSelfAuctionRecord, {
immediate: false,
})
const {
list: list2,
loading: loading2,
searchParams: searchParams2,
total: total2,
refresh: refresh2,
goToPage: goToPage2,
changePageSize: changePageSize2,
} = usePageSearch(getUserLotteryRecordList, {
immediate: false,
})
const refresh = () => {
activityTypeListOptions.find((item) => item.value === tab.value)?.refresh?.()
}
onActivated(() => { onActivated(() => {
searchParams.value.type = activityTypeListOptions[0]!.value
refresh() refresh()
}) })
defineExpose({ defineExpose({
refresh: () => { refresh: () => refresh(),
searchParams.value.type = activityTypeListOptions[0]!.value
refresh()
},
}) })
</script> </script>
...@@ -227,7 +227,7 @@ const menuUserItems = [ ...@@ -227,7 +227,7 @@ const menuUserItems = [
{ {
path: 'selfActivity', path: 'selfActivity',
label: '参与活动', label: '参与活动',
icon: () => <IEpPointer />, icon: () => <IEpTrophy />,
tab: '活动', tab: '活动',
}, },
{ {
......
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