refactor(components): 重构积分显示组件布局并添加插槽支持
重构 TotalPointsDisplay 和 PointsCollector 组件结构,添加容器样式和 header/footer 插槽 调整组件样式,移除全屏宽度限制并添加圆角和阴影 优化 Dashboard 页面布局,将步数显示和拍照按钮整合到组件插槽中
Showing
4 changed files
with
106 additions
and
27 deletions
| ... | @@ -19,7 +19,6 @@ declare module 'vue' { | ... | @@ -19,7 +19,6 @@ declare module 'vue' { |
| 19 | NutDialog: typeof import('@nutui/nutui-taro')['Dialog'] | 19 | NutDialog: typeof import('@nutui/nutui-taro')['Dialog'] |
| 20 | NutImagePreview: typeof import('@nutui/nutui-taro')['ImagePreview'] | 20 | NutImagePreview: typeof import('@nutui/nutui-taro')['ImagePreview'] |
| 21 | NutInput: typeof import('@nutui/nutui-taro')['Input'] | 21 | NutInput: typeof import('@nutui/nutui-taro')['Input'] |
| 22 | - NutLoading: typeof import('@nutui/nutui-taro')['Loading'] | ||
| 23 | NutPicker: typeof import('@nutui/nutui-taro')['Picker'] | 22 | NutPicker: typeof import('@nutui/nutui-taro')['Picker'] |
| 24 | NutPopup: typeof import('@nutui/nutui-taro')['Popup'] | 23 | NutPopup: typeof import('@nutui/nutui-taro')['Popup'] |
| 25 | NutRow: typeof import('@nutui/nutui-taro')['Row'] | 24 | NutRow: typeof import('@nutui/nutui-taro')['Row'] | ... | ... |
| 1 | <template> | 1 | <template> |
| 2 | + <view class="points-collector-container"> | ||
| 3 | + <!-- 头部slot --> | ||
| 4 | + <view v-if="$slots.header" class="points-collector-header"> | ||
| 5 | + <slot name="header"></slot> | ||
| 6 | + </view> | ||
| 7 | + | ||
| 8 | + <!-- 积分收集器主体 --> | ||
| 2 | <view class="points-collector" :style="{ height: height }"> | 9 | <view class="points-collector" :style="{ height: height }"> |
| 3 | <!-- 积分规则提示 --> | 10 | <!-- 积分规则提示 --> |
| 4 | <view class="points-rule-tip" @tap="handleGoToPointsRule"> | 11 | <view class="points-rule-tip" @tap="handleGoToPointsRule"> |
| ... | @@ -38,6 +45,12 @@ | ... | @@ -38,6 +45,12 @@ |
| 38 | <text>一键收取</text> | 45 | <text>一键收取</text> |
| 39 | </view> --> | 46 | </view> --> |
| 40 | </view> | 47 | </view> |
| 48 | + | ||
| 49 | + <!-- 底部slot --> | ||
| 50 | + <view v-if="$slots.footer" class="points-collector-footer"> | ||
| 51 | + <slot name="footer"></slot> | ||
| 52 | + </view> | ||
| 53 | + </view> | ||
| 41 | </template> | 54 | </template> |
| 42 | 55 | ||
| 43 | <script setup> | 56 | <script setup> |
| ... | @@ -435,9 +448,22 @@ const handleGoToPointsRule = () => { | ... | @@ -435,9 +448,22 @@ const handleGoToPointsRule = () => { |
| 435 | </script> | 448 | </script> |
| 436 | 449 | ||
| 437 | <style lang="less"> | 450 | <style lang="less"> |
| 451 | +.points-collector-container { | ||
| 452 | + background: white; | ||
| 453 | + border-radius: 24rpx; | ||
| 454 | + box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08); | ||
| 455 | + margin: 32rpx; | ||
| 456 | + overflow: hidden; | ||
| 457 | +} | ||
| 458 | + | ||
| 459 | +.points-collector-header, | ||
| 460 | +.points-collector-footer { | ||
| 461 | + padding: 40rpx; | ||
| 462 | +} | ||
| 463 | + | ||
| 438 | .points-collector { | 464 | .points-collector { |
| 439 | position: relative; | 465 | position: relative; |
| 440 | - width: 100vw; | 466 | + width: 100%; |
| 441 | height: 100vh; | 467 | height: 100vh; |
| 442 | // background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | 468 | // background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| 443 | overflow: hidden; | 469 | overflow: hidden; |
| ... | @@ -447,7 +473,7 @@ const handleGoToPointsRule = () => { | ... | @@ -447,7 +473,7 @@ const handleGoToPointsRule = () => { |
| 447 | position: absolute; | 473 | position: absolute; |
| 448 | // background-color: white; | 474 | // background-color: white; |
| 449 | top: 0rpx; | 475 | top: 0rpx; |
| 450 | - right: 0rpx; | 476 | + right: 15rpx; |
| 451 | display: flex; | 477 | display: flex; |
| 452 | flex-direction: column; | 478 | flex-direction: column; |
| 453 | align-items: center; | 479 | align-items: center; | ... | ... |
| 1 | <template> | 1 | <template> |
| 2 | + <view class="total-points-display-container"> | ||
| 3 | + <!-- 头部slot --> | ||
| 4 | + <view v-if="$slots.header" class="total-points-display-header"> | ||
| 5 | + <slot name="header"></slot> | ||
| 6 | + </view> | ||
| 7 | + | ||
| 8 | + <!-- 积分显示器主体 --> | ||
| 2 | <view class="total-points-display" :style="{ height: height }"> | 9 | <view class="total-points-display" :style="{ height: height }"> |
| 3 | <!-- 积分规则提示 --> | 10 | <!-- 积分规则提示 --> |
| 4 | <view class="points-rule-tip" @tap="handleGoToPointsRule"> | 11 | <view class="points-rule-tip" @tap="handleGoToPointsRule"> |
| ... | @@ -15,6 +22,12 @@ | ... | @@ -15,6 +22,12 @@ |
| 15 | </view> | 22 | </view> |
| 16 | </view> | 23 | </view> |
| 17 | </view> | 24 | </view> |
| 25 | + | ||
| 26 | + <!-- 底部slot --> | ||
| 27 | + <view v-if="$slots.footer" class="total-points-display-footer"> | ||
| 28 | + <slot name="footer"></slot> | ||
| 29 | + </view> | ||
| 30 | + </view> | ||
| 18 | </template> | 31 | </template> |
| 19 | 32 | ||
| 20 | <script setup> | 33 | <script setup> |
| ... | @@ -121,9 +134,22 @@ const handleGoToPointsRule = () => { | ... | @@ -121,9 +134,22 @@ const handleGoToPointsRule = () => { |
| 121 | </script> | 134 | </script> |
| 122 | 135 | ||
| 123 | <style lang="less"> | 136 | <style lang="less"> |
| 137 | +.total-points-display-container { | ||
| 138 | + background: white; | ||
| 139 | + border-radius: 24rpx; | ||
| 140 | + box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08); | ||
| 141 | + margin: 32rpx; | ||
| 142 | + overflow: hidden; | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +.total-points-display-header, | ||
| 146 | +.total-points-display-footer { | ||
| 147 | + padding: 40rpx; | ||
| 148 | +} | ||
| 149 | + | ||
| 124 | .total-points-display { | 150 | .total-points-display { |
| 125 | position: relative; | 151 | position: relative; |
| 126 | - width: 100vw; | 152 | + width: 100%; |
| 127 | overflow: hidden; | 153 | overflow: hidden; |
| 128 | display: flex; | 154 | display: flex; |
| 129 | justify-content: center; | 155 | justify-content: center; |
| ... | @@ -134,7 +160,7 @@ const handleGoToPointsRule = () => { | ... | @@ -134,7 +160,7 @@ const handleGoToPointsRule = () => { |
| 134 | position: absolute; | 160 | position: absolute; |
| 135 | // background-color: white; | 161 | // background-color: white; |
| 136 | top: 0rpx; | 162 | top: 0rpx; |
| 137 | - right: 0rpx; | 163 | + right: 10rpx; |
| 138 | display: flex; | 164 | display: flex; |
| 139 | flex-direction: column; | 165 | flex-direction: column; |
| 140 | align-items: center; | 166 | align-items: center; | ... | ... |
| 1 | <template> | 1 | <template> |
| 2 | <view class="min-h-screen flex flex-col bg-white pb-16" style="background-color: #F9FAFB;"> | 2 | <view class="min-h-screen flex flex-col bg-white pb-16" style="background-color: #F9FAFB;"> |
| 3 | <!-- Hero section with family name and background image --> | 3 | <!-- Hero section with family name and background image --> |
| 4 | - <view class="relative h-48"> | 4 | + <view class="relative" style="height: 30vh;"> |
| 5 | - <image :src="familyCover" alt="Family background" class="w-full h-full object-cover" /> | 5 | + <image :src="familyCover" mode="aspectFill" alt="Family background" class="w-full h-full object-cover" /> |
| 6 | <view class="absolute inset-0 bg-black bg-opacity-30 flex flex-col justify-end p-5"> | 6 | <view class="absolute inset-0 bg-black bg-opacity-30 flex flex-col justify-end p-5"> |
| 7 | <view v-if="familyOwner" class="absolute top-4 right-4 text-white flex items-center" @click="goToProfile"> | 7 | <view v-if="familyOwner" class="absolute top-4 right-4 text-white flex items-center" @click="goToProfile"> |
| 8 | <Setting size="24" /> | 8 | <Setting size="24" /> |
| ... | @@ -22,8 +22,19 @@ | ... | @@ -22,8 +22,19 @@ |
| 22 | @sync-failed="handleSyncFailed" | 22 | @sync-failed="handleSyncFailed" |
| 23 | > | 23 | > |
| 24 | <template #default> | 24 | <template #default> |
| 25 | - <!-- Today's steps section --> | 25 | + <!-- 合并的大卡片:今日步数 + 积分收集器 + 拍照留念 --> |
| 26 | - <view class="px-5 py-6 bg-white rounded-xl shadow-md mx-4 mt-4"> | 26 | + <template v-if="!showTotalPointsOnly"> |
| 27 | + <PointsCollector | ||
| 28 | + ref="pointsCollectorRef" | ||
| 29 | + height="30vh" | ||
| 30 | + :total-points="finalTotalPoints" | ||
| 31 | + :pending-points="pendingPoints" | ||
| 32 | + :family-id="family_id" | ||
| 33 | + :is-owner="familyOwner" | ||
| 34 | + @collection-complete="handleCollectionComplete" | ||
| 35 | + > | ||
| 36 | + <!-- 头部:今日步数 --> | ||
| 37 | + <template #header> | ||
| 27 | <view class="flex justify-between items-center mb-1"> | 38 | <view class="flex justify-between items-center mb-1"> |
| 28 | <span class="text-gray-500">今日</span> | 39 | <span class="text-gray-500">今日</span> |
| 29 | </view> | 40 | </view> |
| ... | @@ -40,39 +51,56 @@ | ... | @@ -40,39 +51,56 @@ |
| 40 | </view> | 51 | </view> |
| 41 | </view> | 52 | </view> |
| 42 | </view> | 53 | </view> |
| 43 | - </view> | 54 | + </template> |
| 44 | 55 | ||
| 45 | - <!-- Points circles --> | 56 | + <!-- 底部:拍照留念 --> |
| 46 | - <view class="flex justify-between px-3 py-3 my-4 bg-white rounded-xl shadow-md mx-4"> | 57 | + <template #footer> |
| 47 | - <template v-if="!showTotalPointsOnly"> | 58 | + <view @tap="openCamera" class="w-full bg-blue-500 text-white py-3 rounded-lg flex flex-col items-center justify-center"> |
| 48 | - <PointsCollector | 59 | + <view class="flex items-center justify-center"> |
| 49 | - ref="pointsCollectorRef" | 60 | + <Photograph size="20" class="mr-2" /> |
| 50 | - height="30vh" | 61 | + 拍照留念,奖励积分 |
| 51 | - :total-points="finalTotalPoints" | 62 | + </view> |
| 52 | - :pending-points="pendingPoints" | 63 | + </view> |
| 53 | - :family-id="family_id" | 64 | + </template> |
| 54 | - :is-owner="familyOwner" | 65 | + </PointsCollector> |
| 55 | - @collection-complete="handleCollectionComplete" | ||
| 56 | - /> | ||
| 57 | </template> | 66 | </template> |
| 58 | <template v-else> | 67 | <template v-else> |
| 59 | <TotalPointsDisplay | 68 | <TotalPointsDisplay |
| 60 | :total-points="finalTotalPoints" | 69 | :total-points="finalTotalPoints" |
| 61 | :is-owner="familyOwner" | 70 | :is-owner="familyOwner" |
| 62 | height="13vh" | 71 | height="13vh" |
| 63 | - /> | 72 | + > |
| 64 | - </template> | 73 | + <!-- 头部:今日步数 --> |
| 74 | + <template #header> | ||
| 75 | + <view class="flex justify-between items-center mb-1"> | ||
| 76 | + <span class="text-gray-500">今日</span> | ||
| 65 | </view> | 77 | </view> |
| 78 | + <view class="flex justify-between items-center"> | ||
| 79 | + <view class="flex items-baseline"> | ||
| 80 | + <span class="text-4xl font-bold"> | ||
| 81 | + {{ todaySteps?.toLocaleString() }} | ||
| 82 | + </span> | ||
| 83 | + <span class="ml-1 text-gray-500">步</span> | ||
| 84 | + </view> | ||
| 85 | + <view class="flex gap-2"> | ||
| 86 | + <view class="bg-blue-500 text-white px-4 py-2 rounded-full text-sm" @click="handleCollectAll"> | ||
| 87 | + 一键收取 | ||
| 88 | + </view> | ||
| 89 | + </view> | ||
| 90 | + </view> | ||
| 91 | + </template> | ||
| 66 | 92 | ||
| 67 | - <!-- Photo button --> | 93 | + <!-- 底部:拍照留念 --> |
| 68 | - <view class="px-5 mb-4"> | 94 | + <template #footer> |
| 69 | <view @tap="openCamera" class="w-full bg-blue-500 text-white py-3 rounded-lg flex flex-col items-center justify-center"> | 95 | <view @tap="openCamera" class="w-full bg-blue-500 text-white py-3 rounded-lg flex flex-col items-center justify-center"> |
| 70 | <view class="flex items-center justify-center"> | 96 | <view class="flex items-center justify-center"> |
| 71 | <Photograph size="20" class="mr-2" /> | 97 | <Photograph size="20" class="mr-2" /> |
| 72 | 拍照留念,奖励积分 | 98 | 拍照留念,奖励积分 |
| 73 | </view> | 99 | </view> |
| 74 | </view> | 100 | </view> |
| 75 | - </view> | 101 | + </template> |
| 102 | + </TotalPointsDisplay> | ||
| 103 | + </template> | ||
| 76 | 104 | ||
| 77 | <!-- Family step ranking --> | 105 | <!-- Family step ranking --> |
| 78 | <view class="p-5 bg-white rounded-xl shadow-md mx-4"> | 106 | <view class="p-5 bg-white rounded-xl shadow-md mx-4"> | ... | ... |
-
Please register or login to post a comment