hookehuyr

feat(海报打卡): 添加页面状态管理及空状态处理

添加页面状态管理逻辑,包括正常状态、无打卡信息状态和无活动信息状态
为空状态添加UI展示和处理逻辑
优化组件显示条件,根据状态动态渲染
...@@ -15,6 +15,7 @@ declare module 'vue' { ...@@ -15,6 +15,7 @@ declare module 'vue' {
15 NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet'] 15 NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet']
16 NutButton: typeof import('@nutui/nutui-taro')['Button'] 16 NutButton: typeof import('@nutui/nutui-taro')['Button']
17 NutDatePicker: typeof import('@nutui/nutui-taro')['DatePicker'] 17 NutDatePicker: typeof import('@nutui/nutui-taro')['DatePicker']
18 + NutDialog: typeof import('@nutui/nutui-taro')['Dialog']
18 NutImagePreview: typeof import('@nutui/nutui-taro')['ImagePreview'] 19 NutImagePreview: typeof import('@nutui/nutui-taro')['ImagePreview']
19 NutInput: typeof import('@nutui/nutui-taro')['Input'] 20 NutInput: typeof import('@nutui/nutui-taro')['Input']
20 NutPicker: typeof import('@nutui/nutui-taro')['Picker'] 21 NutPicker: typeof import('@nutui/nutui-taro')['Picker']
......
1 <template> 1 <template>
2 <view class="poster-checkin-page bg-gray-50 h-screen flex flex-col"> 2 <view class="poster-checkin-page bg-gray-50 h-screen flex flex-col">
3 <!-- 活动信息区域 --> 3 <!-- 活动信息区域 -->
4 - <view class="bg-white mx-4 mt-4 mb-2 rounded-lg shadow-sm p-4"> 4 + <view v-if="pageState === 'normal' || pageState === 'no-checkin'" class="bg-white mx-4 mt-4 mb-2 rounded-lg shadow-sm p-4">
5 <!-- 活动主题 --> 5 <!-- 活动主题 -->
6 <view class="text-lg font-bold text-gray-800 mb-2"> 6 <view class="text-lg font-bold text-gray-800 mb-2">
7 {{ activityInfo.title }} 7 {{ activityInfo.title }}
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
27 </view> 27 </view>
28 </view> 28 </view>
29 29
30 - <!-- 海报预览区域 --> 30 + <!-- 海报预览区域 - 正常状态 -->
31 - <view class="flex-1 mx-4 mb-2 bg-white rounded-lg shadow-sm relative" style="overflow: visible;"> 31 + <view v-if="pageState === 'normal'" class="flex-1 mx-4 mb-2 bg-white rounded-lg shadow-sm relative" style="overflow: visible;">
32 <view class="h-full relative bg-gray-100 flex items-center justify-center"> 32 <view class="h-full relative bg-gray-100 flex items-center justify-center">
33 <view v-if="currentPoster.path" class="w-full h-full relative"> 33 <view v-if="currentPoster.path" class="w-full h-full relative">
34 <image 34 <image
...@@ -68,8 +68,18 @@ ...@@ -68,8 +68,18 @@
68 </view> 68 </view>
69 </view> 69 </view>
70 70
71 - <!-- 底部操作按钮 --> 71 + <!-- 没有打卡信息的空状态 -->
72 - <view class="bg-white border-t border-gray-200 p-4 safe-area-bottom"> 72 + <view v-if="pageState === 'no-checkin'" class="flex-1 mx-4 mb-2 flex justify-center">
73 + <view class="bg-white rounded-lg shadow-sm p-8 text-center max-w-sm">
74 + <view class="text-6xl mb-4">📸</view>
75 + <view class="text-lg font-bold text-gray-800 mb-2">打卡信息为空</view>
76 + <view class="text-sm text-gray-500 mb-4">您还没有打卡记录,请先参加活动打卡后再来生成海报</view>
77 + <view class="text-xs text-orange-500">完成打卡后即可生成专属海报</view>
78 + </view>
79 + </view>
80 +
81 + <!-- 底部操作按钮 - 仅在正常状态显示 -->
82 + <view v-if="pageState === 'normal'" class="bg-white border-t border-gray-200 p-4 safe-area-bottom">
73 <view class="flex gap-4"> 83 <view class="flex gap-4">
74 <view 84 <view
75 class="flex-1 bg-gradient-to-r from-orange-400 to-orange-500 text-white py-3 px-6 rounded-lg font-medium shadow-lg active:scale-95 transition-transform duration-150 flex items-center justify-center gap-2" 85 class="flex-1 bg-gradient-to-r from-orange-400 to-orange-500 text-white py-3 px-6 rounded-lg font-medium shadow-lg active:scale-95 transition-transform duration-150 flex items-center justify-center gap-2"
...@@ -88,9 +98,9 @@ ...@@ -88,9 +98,9 @@
88 </view> 98 </view>
89 </view> 99 </view>
90 100
91 - <!-- 海报生成组件 --> 101 + <!-- 海报生成组件 - 仅在正常状态显示 -->
92 <PosterBuilder 102 <PosterBuilder
93 - v-if="shouldGeneratePoster" 103 + v-if="shouldGeneratePoster && pageState === 'normal'"
94 :config="posterConfig" 104 :config="posterConfig"
95 :show-loading="true" 105 :show-loading="true"
96 @success="onPosterSuccess" 106 @success="onPosterSuccess"
...@@ -104,6 +114,8 @@ ...@@ -104,6 +114,8 @@
104 :init-no="0" 114 :init-no="0"
105 @close="closePreview" 115 @close="closePreview"
106 /> 116 />
117 +
118 +
107 </view> 119 </view>
108 </template> 120 </template>
109 121
...@@ -149,7 +161,7 @@ const pageParams = ref({ ...@@ -149,7 +161,7 @@ const pageParams = ref({
149 const previewVisible = ref(false) 161 const previewVisible = ref(false)
150 const previewImages = ref([]) 162 const previewImages = ref([])
151 163
152 -// 活动信息数据 164 +// 活动信息数据 - 模拟不同状态,实际使用时从API获取
153 const activityInfo = ref({ 165 const activityInfo = ref({
154 title: '南京路乐龄时尚消费主题路线', 166 title: '南京路乐龄时尚消费主题路线',
155 checkPoints: [ 167 checkPoints: [
...@@ -164,7 +176,9 @@ const activityInfo = ref({ ...@@ -164,7 +176,9 @@ const activityInfo = ref({
164 endDate: '2025年9月7日' 176 endDate: '2025年9月7日'
165 }) 177 })
166 178
167 -// 海报列表数据 179 +// activityInfo.value = {};
180 +
181 +// 海报列表数据 - 模拟不同状态,实际使用时从API获取
168 const posterList = ref([ 182 const posterList = ref([
169 { 183 {
170 id: 1, 184 id: 1,
...@@ -189,6 +203,30 @@ const posterList = ref([ ...@@ -189,6 +203,30 @@ const posterList = ref([
189 } 203 }
190 ]) 204 ])
191 205
206 +// posterList.value = []
207 +
208 +// 数据状态检查
209 +const hasActivityInfo = computed(() => {
210 + return activityInfo.value && activityInfo.value.title && activityInfo.value.checkPoints && activityInfo.value.checkPoints.length > 0
211 +})
212 +
213 +const hasCheckinInfo = computed(() => {
214 + return posterList.value && posterList.value.length > 0
215 +})
216 +
217 +// 页面显示状态
218 +const pageState = computed(() => {
219 + if (!hasActivityInfo.value) {
220 + return 'no-activity' // 没有活动信息
221 + }
222 + if (!hasCheckinInfo.value) {
223 + return 'no-checkin' // 有活动信息但没有打卡信息
224 + }
225 + return 'normal' // 正常状态
226 +})
227 +
228 +
229 +
192 // 当前海报 230 // 当前海报
193 const currentPoster = computed(() => { 231 const currentPoster = computed(() => {
194 return posterList.value[currentPosterIndex.value] || { path: '', title: '' } 232 return posterList.value[currentPosterIndex.value] || { path: '', title: '' }
...@@ -572,6 +610,43 @@ const savePoster = () => { ...@@ -572,6 +610,43 @@ const savePoster = () => {
572 } 610 }
573 }) 611 })
574 } 612 }
613 +
614 +/**
615 + * 显示没有活动信息的确认对话框
616 + */
617 +const showNoActivityConfirm = () => {
618 + Taro.showModal({
619 + title: '温馨提示',
620 + content: '您还没有参加过活动,请先参加活动后再来生成海报',
621 + showCancel: false,
622 + confirmText: '知道了',
623 + success: (res) => {
624 + if (res.confirm) {
625 + // 返回上一页
626 + Taro.navigateBack({
627 + delta: 1
628 + })
629 + }
630 + }
631 + })
632 +}
633 +
634 +/**
635 + * 页面初始化
636 + */
637 +onMounted(() => {
638 + // 获取页面参数
639 + const instance = Taro.getCurrentInstance()
640 + if (instance.router && instance.router.params) {
641 + pageParams.value = instance.router.params
642 + }
643 +
644 + // 检查页面状态
645 + if (pageState.value === 'no-activity') {
646 + // 没有活动信息,显示确认对话框
647 + showNoActivityConfirm()
648 + }
649 +})
575 </script> 650 </script>
576 651
577 <style lang="less"> 652 <style lang="less">
......