hookehuyr

refactor(components): 重构积分显示组件布局并添加插槽支持

重构 TotalPointsDisplay 和 PointsCollector 组件结构,添加容器样式和 header/footer 插槽
调整组件样式,移除全屏宽度限制并添加圆角和阴影
优化 Dashboard 页面布局,将步数显示和拍照按钮整合到组件插槽中
...@@ -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">
......