Commit 4fba732a by lijiabin

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

parent e0529745
......@@ -15,7 +15,7 @@
</div>
<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
id="tabsRef"
ref="tabsRef"
......@@ -57,7 +57,7 @@
</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
ref="levelContainerRef"
......@@ -73,7 +73,7 @@
:content="`当前经验:${userAccountData.expTotal}/${currentLevelData.expScope[1]} (${currentLevelData.percentage}%)`"
placement="top"
>
<div class="relative w-20 cursor-pointer">
<div class="relative w-20 cursor-pointer flex-1">
<div
class="relative w-full h-4 bg-#A5E4FF rounded-full border-1 border-#30C4FF border-solid"
>
......@@ -106,7 +106,7 @@
<!-- v-if="!userRecordData.isSign" -->
<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>
</div>
<el-button
......@@ -115,7 +115,7 @@
@click="router.push('/pointsStore')"
>
<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>
</div>
</div>
......@@ -136,7 +136,7 @@
@click="router.push('/publishCase')"
>
<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>
</div>
</div>
......@@ -148,7 +148,7 @@
@click="publishTopic"
>
<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
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 @@
<svg-icon name="answer" size="80" />
</el-badge>
<div class="text-xs 2xl:text-sm">回答问题</div>
<div class="text-xs xl:text-sm">回答问题</div>
</div>
<div
......@@ -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"
>
<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 class="flex justify-center items-center">
......@@ -176,7 +176,7 @@
type="primary"
>
<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>
</div>
</div>
......@@ -216,7 +216,7 @@
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="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" />
</div>
<div
......@@ -239,7 +239,7 @@
</div>
</div>
<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="[
item.currentCount === item.limitCount
? 'bg-#FFC5A1 cursor-not-allowed'
......@@ -266,6 +266,48 @@
</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>
......@@ -283,9 +325,23 @@ import front from '@/assets/img/culture/front_page.png'
import ya from '@/assets/img/culture/ya_culture.png'
import ask from '@/assets/img/culture/ask.png'
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 type { CarouselItemDto, TaskItemDto, UserAccountDataDto, UserRecordDataDto } from '@/api'
import type {
CarouselItemDto,
TaskItemDto,
UserAccountDataDto,
UserRecordDataDto,
DailyLotteryInfo,
} from '@/api'
import { TABS_REF_KEY, levelListOptions } from '@/constants'
import { useScrollTop } from '@/hooks'
import { useQuestionStore } from '@/stores/question'
......@@ -378,7 +434,6 @@ const currentLevelData = computed<{
100
).toFixed(2),
)
console.log(percentage)
return {
label: levelData.label,
iconUrl: levelData.iconUrl,
......@@ -391,13 +446,27 @@ const userRecordData = ref({} as UserRecordDataDto)
const onDailySign = async () => {
await dailySign()
await refreshTaskData(true)
const { data } = await getUserAccountData()
userAccountData.value = data
refreshTaskData(true)
refreshUserAccountData()
ElMessage.success('签到成功')
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) => {
console.log(item)
if (item.currentCount === item.limitCount) return
......@@ -444,21 +513,33 @@ const handleClickCarousel = (item: CarouselItemDto) => {
}
const initPage = () => {
Promise.allSettled([getCarouselList(), getUserAccountData(), getRecordData()]).then(
([r1, r2, r3]) => {
if (r1.status === 'fulfilled') {
carouselList.value = r1.value.data
}
if (r2.status === 'fulfilled') {
userAccountData.value = r2.value.data
}
if (r3.status === 'fulfilled') {
userRecordData.value = r3.value.data
}
},
)
Promise.allSettled([
getCarouselList(),
getUserAccountData(),
getRecordData(),
getUserDailyLotteryInfo(),
]).then(([r1, r2, r3, r4]) => {
if (r1.status === 'fulfilled') {
carouselList.value = r1.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) => {
if (refreshRecordData) {
const { data } = await getRecordData()
......@@ -473,6 +554,8 @@ const refreshTaskData = async (refreshRecordData = false) => {
onActivated(async () => {
questionStore.fetchUserQestionNum()
refreshTaskData(false)
refreshUserAccountData()
getLotteryPrizesDetail()
if (route.fullPath.includes('#levelContainerRef')) {
await handleBackTop()
open.value = true
......
......@@ -10,7 +10,13 @@
<el-form ref="formRef" :model="form" :rules="rules" label-width="60px" class="px-4">
<!-- 昵称 -->
<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>
<!-- 签名 -->
......
<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="relative">
<el-tabs v-model="searchParams.type" @tab-change="toggleTab">
<el-tabs v-model="tab" @tab-change="toggleTab">
<el-tab-pane
v-for="tab in activityTypeListOptions"
:key="tab.value"
:label="tab.label"
:name="tab.value"
/>
>
<component :is="tab.component" />
</el-tab-pane>
</el-tabs>
<div class="absolute right-0 top-2.5 z-1000">
<el-icon
......@@ -20,7 +22,7 @@
</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">
<el-icon><IEpInfoFilled /></el-icon>
页面仅展示竞拍成功的记录
......@@ -58,41 +60,168 @@
class="custom-pagination"
/>
</div>
</div> -->
</div>
</div>
</template>
<script lang="ts" setup>
import { getSelfAuctionRecord } from '@/api'
<script lang="tsx" setup>
import { getSelfAuctionRecord, getUserLotteryRecordList } from '@/api'
import { usePageSearch } from '@/hooks'
import { activityTypeListOptions } from '@/constants/options'
import { ActivityTypeEnum } from '@/constants/enums'
import type { TabPaneName } from 'element-plus'
import type { UserLotteryRecordItemDto } from '@/api/dailyLottery/types'
const toggleTab = (key: TabPaneName) => {
searchParams.value.type = key as ActivityTypeEnum
refresh()
}
const EmptyComp = () => (
<div class="flex flex-col items-center justify-center h-64">
<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(
getSelfAuctionRecord,
const activityTypeListOptions = [
{
defaultParams: {
type: activityTypeListOptions[0]!.value,
},
immediate: false,
label: '限时竞拍',
value: ActivityTypeEnum.AUCTION,
component: () => (
<>
<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(() => {
searchParams.value.type = activityTypeListOptions[0]!.value
refresh()
})
defineExpose({
refresh: () => {
searchParams.value.type = activityTypeListOptions[0]!.value
refresh()
},
refresh: () => refresh(),
})
</script>
......@@ -227,7 +227,7 @@ const menuUserItems = [
{
path: 'selfActivity',
label: '参与活动',
icon: () => <IEpPointer />,
icon: () => <IEpTrophy />,
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