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" :style="{ height: height }"> 2 + <view class="points-collector-container">
3 - <!-- 积分规则提示 --> 3 + <!-- 头部slot -->
4 - <view class="points-rule-tip" @tap="handleGoToPointsRule"> 4 + <view v-if="$slots.header" class="points-collector-header">
5 - <view class="tip-icon">💡</view> 5 + <slot name="header"></slot>
6 - <text class="tip-text">积分规则</text>
7 </view> 6 </view>
8 7
9 - <!-- 中心圆形显示总积分 --> 8 + <!-- 积分收集器主体 -->
10 - <view class="center-circle"> 9 + <view class="points-collector" :style="{ height: height }">
11 - <view class="total-points" @tap="handleGoToRewards"> 10 + <!-- 积分规则提示 -->
12 - <text v-if="!isOwner" class="family-points-label">家庭总积分</text> 11 + <view class="points-rule-tip" @tap="handleGoToPointsRule">
13 - <text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text> 12 + <view class="tip-icon">💡</view>
14 - <text v-if="isOwner" class="points-label">去兑换</text> 13 + <text class="tip-text">积分规则</text>
14 + </view>
15 +
16 + <!-- 中心圆形显示总积分 -->
17 + <view class="center-circle">
18 + <view class="total-points" @tap="handleGoToRewards">
19 + <text v-if="!isOwner" class="family-points-label">家庭总积分</text>
20 + <text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
21 + <text v-if="isOwner" class="points-label">去兑换</text>
22 + </view>
15 </view> 23 </view>
16 - </view>
17 24
18 - <!-- 周围漂浮的小圆圈 --> 25 + <!-- 周围漂浮的小圆圈 -->
19 - <view 26 + <view
20 - v-for="(item) in floatingItems" 27 + v-for="(item) in floatingItems"
21 - :key="item.id" 28 + :key="item.id"
22 - class="floating-item" 29 + class="floating-item"
23 - :style="getItemStyle(item)" 30 + :style="getItemStyle(item)"
24 - @tap="collectItem(item)" 31 + @tap="collectItem(item)"
25 - > 32 + >
26 - <view class="item-content"> 33 + <view class="item-content">
27 - <text class="item-value">{{ item.sourceLabel }}</text> 34 + <text class="item-value">{{ item.sourceLabel }}</text>
28 - <text class="item-type">{{ item.points }}分</text> 35 + <text class="item-type">{{ item.points }}分</text>
36 + </view>
29 </view> 37 </view>
38 +
39 + <!-- 一键收取按钮 -->
40 + <!-- <view
41 + v-if="floatingItems.length > 0"
42 + class="collect-all-btn"
43 + @tap="collectAll"
44 + >
45 + <text>一键收取</text>
46 + </view> -->
30 </view> 47 </view>
31 48
32 - <!-- 一键收取按钮 --> 49 + <!-- 底部slot -->
33 - <!-- <view 50 + <view v-if="$slots.footer" class="points-collector-footer">
34 - v-if="floatingItems.length > 0" 51 + <slot name="footer"></slot>
35 - class="collect-all-btn" 52 + </view>
36 - @tap="collectAll"
37 - >
38 - <text>一键收取</text>
39 - </view> -->
40 </view> 53 </view>
41 </template> 54 </template>
42 55
...@@ -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" :style="{ height: height }"> 2 + <view class="total-points-display-container">
3 - <!-- 积分规则提示 --> 3 + <!-- 头部slot -->
4 - <view class="points-rule-tip" @tap="handleGoToPointsRule"> 4 + <view v-if="$slots.header" class="total-points-display-header">
5 - <view class="tip-icon">💡</view> 5 + <slot name="header"></slot>
6 - <text class="tip-text">积分规则</text>
7 </view> 6 </view>
8 7
9 - <!-- 中心圆形显示总积分 --> 8 + <!-- 积分显示器主体 -->
10 - <view class="center-circle1"> 9 + <view class="total-points-display" :style="{ height: height }">
11 - <view class="total-points" @tap="handleGoToRewards"> 10 + <!-- 积分规则提示 -->
12 - <text v-if="!isOwner" class="family-points-label">家庭总积分</text> 11 + <view class="points-rule-tip" @tap="handleGoToPointsRule">
13 - <text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text> 12 + <view class="tip-icon">💡</view>
14 - <text v-if="isOwner" class="points-label">去兑换</text> 13 + <text class="tip-text">积分规则</text>
14 + </view>
15 +
16 + <!-- 中心圆形显示总积分 -->
17 + <view class="center-circle1">
18 + <view class="total-points" @tap="handleGoToRewards">
19 + <text v-if="!isOwner" class="family-points-label">家庭总积分</text>
20 + <text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
21 + <text v-if="isOwner" class="points-label">去兑换</text>
22 + </view>
15 </view> 23 </view>
16 </view> 24 </view>
25 +
26 + <!-- 底部slot -->
27 + <view v-if="$slots.footer" class="total-points-display-footer">
28 + <slot name="footer"></slot>
29 + </view>
17 </view> 30 </view>
18 </template> 31 </template>
19 32
...@@ -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,57 +22,85 @@ ...@@ -22,57 +22,85 @@
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 - <view class="flex justify-between items-center mb-1"> 27 + <PointsCollector
28 - <span class="text-gray-500">今日</span> 28 + ref="pointsCollectorRef"
29 - </view> 29 + height="30vh"
30 - <view class="flex justify-between items-center"> 30 + :total-points="finalTotalPoints"
31 - <view class="flex items-baseline"> 31 + :pending-points="pendingPoints"
32 - <span class="text-4xl font-bold"> 32 + :family-id="family_id"
33 - {{ todaySteps?.toLocaleString() }} 33 + :is-owner="familyOwner"
34 - </span> 34 + @collection-complete="handleCollectionComplete"
35 - <span class="ml-1 text-gray-500">步</span> 35 + >
36 - </view> 36 + <!-- 头部:今日步数 -->
37 - <view class="flex gap-2"> 37 + <template #header>
38 - <view class="bg-blue-500 text-white px-4 py-2 rounded-full text-sm" @click="handleCollectAll"> 38 + <view class="flex justify-between items-center mb-1">
39 - 一键收取 39 + <span class="text-gray-500">今日</span>
40 </view> 40 </view>
41 - </view> 41 + <view class="flex justify-between items-center">
42 - </view> 42 + <view class="flex items-baseline">
43 - </view> 43 + <span class="text-4xl font-bold">
44 - 44 + {{ todaySteps?.toLocaleString() }}
45 - <!-- Points circles --> 45 + </span>
46 - <view class="flex justify-between px-3 py-3 my-4 bg-white rounded-xl shadow-md mx-4"> 46 + <span class="ml-1 text-gray-500">步</span>
47 - <template v-if="!showTotalPointsOnly"> 47 + </view>
48 - <PointsCollector 48 + <view class="flex gap-2">
49 - ref="pointsCollectorRef" 49 + <view class="bg-blue-500 text-white px-4 py-2 rounded-full text-sm" @click="handleCollectAll">
50 - height="30vh" 50 + 一键收取
51 - :total-points="finalTotalPoints" 51 + </view>
52 - :pending-points="pendingPoints" 52 + </view>
53 - :family-id="family_id" 53 + </view>
54 - :is-owner="familyOwner" 54 + </template>
55 - @collection-complete="handleCollectionComplete" 55 +
56 - /> 56 + <!-- 底部:拍照留念 -->
57 - </template> 57 + <template #footer>
58 - <template v-else> 58 + <view @tap="openCamera" class="w-full bg-blue-500 text-white py-3 rounded-lg flex flex-col items-center justify-center">
59 - <TotalPointsDisplay 59 + <view class="flex items-center justify-center">
60 - :total-points="finalTotalPoints" 60 + <Photograph size="20" class="mr-2" />
61 - :is-owner="familyOwner" 61 + 拍照留念,奖励积分
62 - height="13vh" 62 + </view>
63 - /> 63 + </view>
64 - </template> 64 + </template>
65 - </view> 65 + </PointsCollector>
66 - 66 + </template>
67 - <!-- Photo button --> 67 + <template v-else>
68 - <view class="px-5 mb-4"> 68 + <TotalPointsDisplay
69 - <view @tap="openCamera" class="w-full bg-blue-500 text-white py-3 rounded-lg flex flex-col items-center justify-center"> 69 + :total-points="finalTotalPoints"
70 - <view class="flex items-center justify-center"> 70 + :is-owner="familyOwner"
71 - <Photograph size="20" class="mr-2" /> 71 + height="13vh"
72 - 拍照留念,奖励积分 72 + >
73 - </view> 73 + <!-- 头部:今日步数 -->
74 - </view> 74 + <template #header>
75 - </view> 75 + <view class="flex justify-between items-center mb-1">
76 + <span class="text-gray-500">今日</span>
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>
92 +
93 + <!-- 底部:拍照留念 -->
94 + <template #footer>
95 + <view @tap="openCamera" class="w-full bg-blue-500 text-white py-3 rounded-lg flex flex-col items-center justify-center">
96 + <view class="flex items-center justify-center">
97 + <Photograph size="20" class="mr-2" />
98 + 拍照留念,奖励积分
99 + </view>
100 + </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">
......