hookehuyr

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

重构 TotalPointsDisplay 和 PointsCollector 组件结构,添加容器样式和 header/footer 插槽
调整组件样式,移除全屏宽度限制并添加圆角和阴影
优化 Dashboard 页面布局,将步数显示和拍照按钮整合到组件插槽中
......@@ -19,7 +19,6 @@ declare module 'vue' {
NutDialog: typeof import('@nutui/nutui-taro')['Dialog']
NutImagePreview: typeof import('@nutui/nutui-taro')['ImagePreview']
NutInput: typeof import('@nutui/nutui-taro')['Input']
NutLoading: typeof import('@nutui/nutui-taro')['Loading']
NutPicker: typeof import('@nutui/nutui-taro')['Picker']
NutPopup: typeof import('@nutui/nutui-taro')['Popup']
NutRow: typeof import('@nutui/nutui-taro')['Row']
......
<template>
<view class="points-collector" :style="{ height: height }">
<!-- 积分规则提示 -->
<view class="points-rule-tip" @tap="handleGoToPointsRule">
<view class="tip-icon">💡</view>
<text class="tip-text">积分规则</text>
<view class="points-collector-container">
<!-- 头部slot -->
<view v-if="$slots.header" class="points-collector-header">
<slot name="header"></slot>
</view>
<!-- 中心圆形显示总积分 -->
<view class="center-circle">
<view class="total-points" @tap="handleGoToRewards">
<text v-if="!isOwner" class="family-points-label">家庭总积分</text>
<text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
<text v-if="isOwner" class="points-label">去兑换</text>
<!-- 积分收集器主体 -->
<view class="points-collector" :style="{ height: height }">
<!-- 积分规则提示 -->
<view class="points-rule-tip" @tap="handleGoToPointsRule">
<view class="tip-icon">💡</view>
<text class="tip-text">积分规则</text>
</view>
<!-- 中心圆形显示总积分 -->
<view class="center-circle">
<view class="total-points" @tap="handleGoToRewards">
<text v-if="!isOwner" class="family-points-label">家庭总积分</text>
<text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
<text v-if="isOwner" class="points-label">去兑换</text>
</view>
</view>
</view>
<!-- 周围漂浮的小圆圈 -->
<view
v-for="(item) in floatingItems"
:key="item.id"
class="floating-item"
:style="getItemStyle(item)"
@tap="collectItem(item)"
>
<view class="item-content">
<text class="item-value">{{ item.sourceLabel }}</text>
<text class="item-type">{{ item.points }}分</text>
<!-- 周围漂浮的小圆圈 -->
<view
v-for="(item) in floatingItems"
:key="item.id"
class="floating-item"
:style="getItemStyle(item)"
@tap="collectItem(item)"
>
<view class="item-content">
<text class="item-value">{{ item.sourceLabel }}</text>
<text class="item-type">{{ item.points }}分</text>
</view>
</view>
<!-- 一键收取按钮 -->
<!-- <view
v-if="floatingItems.length > 0"
class="collect-all-btn"
@tap="collectAll"
>
<text>一键收取</text>
</view> -->
</view>
<!-- 一键收取按钮 -->
<!-- <view
v-if="floatingItems.length > 0"
class="collect-all-btn"
@tap="collectAll"
>
<text>一键收取</text>
</view> -->
<!-- 底部slot -->
<view v-if="$slots.footer" class="points-collector-footer">
<slot name="footer"></slot>
</view>
</view>
</template>
......@@ -435,9 +448,22 @@ const handleGoToPointsRule = () => {
</script>
<style lang="less">
.points-collector-container {
background: white;
border-radius: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
margin: 32rpx;
overflow: hidden;
}
.points-collector-header,
.points-collector-footer {
padding: 40rpx;
}
.points-collector {
position: relative;
width: 100vw;
width: 100%;
height: 100vh;
// background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
overflow: hidden;
......@@ -447,7 +473,7 @@ const handleGoToPointsRule = () => {
position: absolute;
// background-color: white;
top: 0rpx;
right: 0rpx;
right: 15rpx;
display: flex;
flex-direction: column;
align-items: center;
......
<template>
<view class="total-points-display" :style="{ height: height }">
<!-- 积分规则提示 -->
<view class="points-rule-tip" @tap="handleGoToPointsRule">
<view class="tip-icon">💡</view>
<text class="tip-text">积分规则</text>
<view class="total-points-display-container">
<!-- 头部slot -->
<view v-if="$slots.header" class="total-points-display-header">
<slot name="header"></slot>
</view>
<!-- 中心圆形显示总积分 -->
<view class="center-circle1">
<view class="total-points" @tap="handleGoToRewards">
<text v-if="!isOwner" class="family-points-label">家庭总积分</text>
<text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
<text v-if="isOwner" class="points-label">去兑换</text>
<!-- 积分显示器主体 -->
<view class="total-points-display" :style="{ height: height }">
<!-- 积分规则提示 -->
<view class="points-rule-tip" @tap="handleGoToPointsRule">
<view class="tip-icon">💡</view>
<text class="tip-text">积分规则</text>
</view>
<!-- 中心圆形显示总积分 -->
<view class="center-circle1">
<view class="total-points" @tap="handleGoToRewards">
<text v-if="!isOwner" class="family-points-label">家庭总积分</text>
<text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
<text v-if="isOwner" class="points-label">去兑换</text>
</view>
</view>
</view>
<!-- 底部slot -->
<view v-if="$slots.footer" class="total-points-display-footer">
<slot name="footer"></slot>
</view>
</view>
</template>
......@@ -121,9 +134,22 @@ const handleGoToPointsRule = () => {
</script>
<style lang="less">
.total-points-display-container {
background: white;
border-radius: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
margin: 32rpx;
overflow: hidden;
}
.total-points-display-header,
.total-points-display-footer {
padding: 40rpx;
}
.total-points-display {
position: relative;
width: 100vw;
width: 100%;
overflow: hidden;
display: flex;
justify-content: center;
......@@ -134,7 +160,7 @@ const handleGoToPointsRule = () => {
position: absolute;
// background-color: white;
top: 0rpx;
right: 0rpx;
right: 10rpx;
display: flex;
flex-direction: column;
align-items: center;
......
<template>
<view class="min-h-screen flex flex-col bg-white pb-16" style="background-color: #F9FAFB;">
<!-- Hero section with family name and background image -->
<view class="relative h-48">
<image :src="familyCover" alt="Family background" class="w-full h-full object-cover" />
<view class="relative" style="height: 30vh;">
<image :src="familyCover" mode="aspectFill" alt="Family background" class="w-full h-full object-cover" />
<view class="absolute inset-0 bg-black bg-opacity-30 flex flex-col justify-end p-5">
<view v-if="familyOwner" class="absolute top-4 right-4 text-white flex items-center" @click="goToProfile">
<Setting size="24" />
......@@ -22,57 +22,85 @@
@sync-failed="handleSyncFailed"
>
<template #default>
<!-- Today's steps section -->
<view class="px-5 py-6 bg-white rounded-xl shadow-md mx-4 mt-4">
<view class="flex justify-between items-center mb-1">
<span class="text-gray-500">今日</span>
</view>
<view class="flex justify-between items-center">
<view class="flex items-baseline">
<span class="text-4xl font-bold">
{{ todaySteps?.toLocaleString() }}
</span>
<span class="ml-1 text-gray-500">步</span>
</view>
<view class="flex gap-2">
<view class="bg-blue-500 text-white px-4 py-2 rounded-full text-sm" @click="handleCollectAll">
一键收取
<!-- 合并的大卡片:今日步数 + 积分收集器 + 拍照留念 -->
<template v-if="!showTotalPointsOnly">
<PointsCollector
ref="pointsCollectorRef"
height="30vh"
:total-points="finalTotalPoints"
:pending-points="pendingPoints"
:family-id="family_id"
:is-owner="familyOwner"
@collection-complete="handleCollectionComplete"
>
<!-- 头部:今日步数 -->
<template #header>
<view class="flex justify-between items-center mb-1">
<span class="text-gray-500">今日</span>
</view>
</view>
</view>
</view>
<!-- Points circles -->
<view class="flex justify-between px-3 py-3 my-4 bg-white rounded-xl shadow-md mx-4">
<template v-if="!showTotalPointsOnly">
<PointsCollector
ref="pointsCollectorRef"
height="30vh"
:total-points="finalTotalPoints"
:pending-points="pendingPoints"
:family-id="family_id"
:is-owner="familyOwner"
@collection-complete="handleCollectionComplete"
/>
</template>
<template v-else>
<TotalPointsDisplay
:total-points="finalTotalPoints"
:is-owner="familyOwner"
height="13vh"
/>
</template>
</view>
<!-- Photo button -->
<view class="px-5 mb-4">
<view @tap="openCamera" class="w-full bg-blue-500 text-white py-3 rounded-lg flex flex-col items-center justify-center">
<view class="flex items-center justify-center">
<Photograph size="20" class="mr-2" />
拍照留念,奖励积分
</view>
</view>
</view>
<view class="flex justify-between items-center">
<view class="flex items-baseline">
<span class="text-4xl font-bold">
{{ todaySteps?.toLocaleString() }}
</span>
<span class="ml-1 text-gray-500">步</span>
</view>
<view class="flex gap-2">
<view class="bg-blue-500 text-white px-4 py-2 rounded-full text-sm" @click="handleCollectAll">
一键收取
</view>
</view>
</view>
</template>
<!-- 底部:拍照留念 -->
<template #footer>
<view @tap="openCamera" class="w-full bg-blue-500 text-white py-3 rounded-lg flex flex-col items-center justify-center">
<view class="flex items-center justify-center">
<Photograph size="20" class="mr-2" />
拍照留念,奖励积分
</view>
</view>
</template>
</PointsCollector>
</template>
<template v-else>
<TotalPointsDisplay
:total-points="finalTotalPoints"
:is-owner="familyOwner"
height="13vh"
>
<!-- 头部:今日步数 -->
<template #header>
<view class="flex justify-between items-center mb-1">
<span class="text-gray-500">今日</span>
</view>
<view class="flex justify-between items-center">
<view class="flex items-baseline">
<span class="text-4xl font-bold">
{{ todaySteps?.toLocaleString() }}
</span>
<span class="ml-1 text-gray-500">步</span>
</view>
<view class="flex gap-2">
<view class="bg-blue-500 text-white px-4 py-2 rounded-full text-sm" @click="handleCollectAll">
一键收取
</view>
</view>
</view>
</template>
<!-- 底部:拍照留念 -->
<template #footer>
<view @tap="openCamera" class="w-full bg-blue-500 text-white py-3 rounded-lg flex flex-col items-center justify-center">
<view class="flex items-center justify-center">
<Photograph size="20" class="mr-2" />
拍照留念,奖励积分
</view>
</view>
</template>
</TotalPointsDisplay>
</template>
<!-- Family step ranking -->
<view class="p-5 bg-white rounded-xl shadow-md mx-4">
......