hookehuyr

feat: 添加权限控制显示兑换相关功能

根据用户角色控制显示兑换按钮和积分信息
在多个组件中添加isOwner/isCreator判断
修改头像显示模式为aspectFill
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
3 <!-- 中心圆形显示总积分 --> 3 <!-- 中心圆形显示总积分 -->
4 <view class="center-circle"> 4 <view class="center-circle">
5 <view class="total-points" @tap="handleGoToRewards"> 5 <view class="total-points" @tap="handleGoToRewards">
6 + <text v-if="!isOwner" class="family-points-label">家庭总积分</text>
6 <text class="points-number">{{ animatedTotalPoints }}分</text> 7 <text class="points-number">{{ animatedTotalPoints }}分</text>
7 - <text class="points-label">去兑换</text> 8 + <text v-if="isOwner" class="points-label">去兑换</text>
8 </view> 9 </view>
9 </view> 10 </view>
10 11
...@@ -55,7 +56,11 @@ const props = defineProps({ ...@@ -55,7 +56,11 @@ const props = defineProps({
55 familyId: { 56 familyId: {
56 type: [String, Number], 57 type: [String, Number],
57 required: true 58 required: true
58 - } 59 + },
60 + isOwner: {
61 + type: Boolean,
62 + default: false
63 + },
59 }) 64 })
60 65
61 // 响应式数据 66 // 响应式数据
...@@ -80,7 +85,7 @@ const generatePointsData = () => { ...@@ -80,7 +85,7 @@ const generatePointsData = () => {
80 if (!props.pendingPoints || props.pendingPoints.length === 0) { 85 if (!props.pendingPoints || props.pendingPoints.length === 0) {
81 return []; 86 return [];
82 } 87 }
83 - 88 +
84 const pointsItems = props.pendingPoints.map(item => ({ 89 const pointsItems = props.pendingPoints.map(item => ({
85 id: item.id, 90 id: item.id,
86 points: parseInt(item.points), 91 points: parseInt(item.points),
...@@ -335,6 +340,9 @@ useDidShow(() => { ...@@ -335,6 +340,9 @@ useDidShow(() => {
335 * 处理去兑换点击事件 340 * 处理去兑换点击事件
336 */ 341 */
337 const handleGoToRewards = () => { 342 const handleGoToRewards = () => {
343 + if (!props.isOwner) {
344 + return
345 + }
338 Taro.navigateTo({ 346 Taro.navigateTo({
339 url: '/pages/RewardCategories/index', 347 url: '/pages/RewardCategories/index',
340 }) 348 })
...@@ -382,7 +390,14 @@ const handleGoToRewards = () => { ...@@ -382,7 +390,14 @@ const handleGoToRewards = () => {
382 .points-label { 390 .points-label {
383 display: block; 391 display: block;
384 font-size: 24rpx; 392 font-size: 24rpx;
385 - margin-top: 8rpx; 393 + margin-top: 10rpx;
394 + opacity: 0.9;
395 +}
396 +
397 +.family-points-label {
398 + display: block;
399 + font-size: 24rpx;
400 + margin-bottom: 10rpx;
386 opacity: 0.9; 401 opacity: 0.9;
387 } 402 }
388 403
......
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
3 <!-- 中心圆形显示总积分 --> 3 <!-- 中心圆形显示总积分 -->
4 <view class="center-circle1"> 4 <view class="center-circle1">
5 <view class="total-points" @tap="handleGoToRewards"> 5 <view class="total-points" @tap="handleGoToRewards">
6 + <text v-if="!isOwner" class="family-points-label">家庭总积分</text>
6 <text class="points-number">{{ animatedTotalPoints }}分</text> 7 <text class="points-number">{{ animatedTotalPoints }}分</text>
7 - <text class="points-label">去兑换</text> 8 + <text v-if="isOwner" class="points-label">去兑换</text>
8 </view> 9 </view>
9 </view> 10 </view>
10 </view> 11 </view>
...@@ -24,6 +25,10 @@ const props = defineProps({ ...@@ -24,6 +25,10 @@ const props = defineProps({
24 height: { 25 height: {
25 type: String, 26 type: String,
26 default: '30vh' 27 default: '30vh'
28 + },
29 + isOwner: {
30 + type: Boolean,
31 + default: false
27 } 32 }
28 }) 33 })
29 34
...@@ -72,6 +77,9 @@ onMounted(() => { ...@@ -72,6 +77,9 @@ onMounted(() => {
72 * 处理去兑换点击事件 77 * 处理去兑换点击事件
73 */ 78 */
74 const handleGoToRewards = () => { 79 const handleGoToRewards = () => {
80 + if (!props.isOwner) {
81 + return
82 + }
75 Taro.navigateTo({ 83 Taro.navigateTo({
76 url: '/pages/RewardCategories/index', 84 url: '/pages/RewardCategories/index',
77 }) 85 })
...@@ -116,10 +124,17 @@ const handleGoToRewards = () => { ...@@ -116,10 +124,17 @@ const handleGoToRewards = () => {
116 line-height: 1; 124 line-height: 1;
117 } 125 }
118 126
127 +.family-points-label {
128 + display: block;
129 + font-size: 24rpx;
130 + margin-bottom: 10rpx;
131 + opacity: 0.9;
132 +}
133 +
119 .points-label { 134 .points-label {
120 display: block; 135 display: block;
121 font-size: 24rpx; 136 font-size: 24rpx;
122 - margin-top: 8rpx; 137 + margin-top: 10rpx;
123 opacity: 0.9; 138 opacity: 0.9;
124 } 139 }
125 140
......
...@@ -55,12 +55,14 @@ ...@@ -55,12 +55,14 @@
55 :total-points="finalTotalPoints" 55 :total-points="finalTotalPoints"
56 :pending-points="pendingPoints" 56 :pending-points="pendingPoints"
57 :family-id="family_id" 57 :family-id="family_id"
58 + :is-owner="familyOwner"
58 @collection-complete="handleCollectionComplete" 59 @collection-complete="handleCollectionComplete"
59 /> 60 />
60 </template> 61 </template>
61 <template v-else> 62 <template v-else>
62 <TotalPointsDisplay 63 <TotalPointsDisplay
63 :total-points="finalTotalPoints" 64 :total-points="finalTotalPoints"
65 + :is-owner="familyOwner"
64 height="13vh" 66 height="13vh"
65 /> 67 />
66 </template> 68 </template>
...@@ -86,7 +88,7 @@ ...@@ -86,7 +88,7 @@
86 </view> 88 </view>
87 <view class="grid grid-cols-4 gap-2"> 89 <view class="grid grid-cols-4 gap-2">
88 <view v-for="member in familyMembers" :key="member.user_id" class="flex flex-col items-center"> 90 <view v-for="member in familyMembers" :key="member.user_id" class="flex flex-col items-center">
89 - <image :src="member.avatar_url || defaultAvatar" :alt="member.role" class="w-16 h-16 rounded-full mb-1" /> 91 + <image :src="member.avatar_url || defaultAvatar" mode="aspectFill" :alt="member.role" class="w-16 h-16 rounded-full mb-1" />
90 <span class="text-sm text-gray-700"> 92 <span class="text-sm text-gray-700">
91 {{ member?.today_step?.toLocaleString() }}步 93 {{ member?.today_step?.toLocaleString() }}步
92 </span> 94 </span>
......
1 <!-- 1 <!--
2 * @Date: 2025-08-27 17:47:46 2 * @Date: 2025-08-27 17:47:46
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-09-03 20:02:11 4 + * @LastEditTime: 2025-09-03 21:30:51
5 * @FilePath: /lls_program/src/pages/Profile/index.vue 5 * @FilePath: /lls_program/src/pages/Profile/index.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
14 <!-- User profile section --> 14 <!-- User profile section -->
15 <view class="px-4 pt-8 pb-6 flex items-center justify-between"> 15 <view class="px-4 pt-8 pb-6 flex items-center justify-between">
16 <view class="flex items-center"> 16 <view class="flex items-center">
17 - <image :src="userInfo.avatarUrl || defaultAvatar" alt="User avatar" class="w-16 h-16 rounded-full border-2 border-white" /> 17 + <image :src="userInfo.avatarUrl || defaultAvatar" alt="User avatar" mode="aspectFill" class="w-16 h-16 rounded-full border-2 border-white" />
18 <view class="ml-4"> 18 <view class="ml-4">
19 <h1 class="text-xl font-bold text-white">{{ userInfo.nickName }}</h1> 19 <h1 class="text-xl font-bold text-white">{{ userInfo.nickName }}</h1>
20 </view> 20 </view>
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
54 </view> 54 </view>
55 55
56 <!-- Bottom Button --> 56 <!-- Bottom Button -->
57 - <view class="fixed bottom-0 left-0 right-0 p-4 bg-white border-t border-gray-100"> 57 + <view v-if="isCreator" class="fixed bottom-0 left-0 right-0 p-4 bg-white border-t border-gray-100">
58 <nut-button type="primary" size="large" block color="#3B82F6" @click="handleRedeem"> 58 <nut-button type="primary" size="large" block color="#3B82F6" @click="handleRedeem">
59 立即兑换 59 立即兑换
60 </nut-button> 60 </nut-button>
...@@ -64,8 +64,11 @@ ...@@ -64,8 +64,11 @@
64 64
65 <script setup> 65 <script setup>
66 import { ref } from 'vue'; 66 import { ref } from 'vue';
67 -import Taro from '@tarojs/taro'; 67 +import Taro, { useDidShow } from '@tarojs/taro';
68 import AppHeader from '../../components/AppHeader.vue'; 68 import AppHeader from '../../components/AppHeader.vue';
69 +import { getUserProfileAPI } from '@/api/user';
70 +
71 +const isCreator = ref(false);
69 72
70 // Mock reward data based on the image 73 // Mock reward data based on the image
71 const reward = ref({ 74 const reward = ref({
...@@ -120,4 +123,21 @@ const handleRedeem = () => { ...@@ -120,4 +123,21 @@ const handleRedeem = () => {
120 } 123 }
121 }); 124 });
122 }; 125 };
126 +
127 +const initData = async () => {
128 + // 获取用户信息,判断是否为创建者
129 + try {
130 + const { code, data } = await getUserProfileAPI();
131 + if (code) {
132 + isCreator.value = data?.user?.is_creator || false;
133 + }
134 + } catch (error) {
135 + console.error('获取用户信息失败:', error);
136 + isCreator.value = false;
137 + }
138 +};
139 +
140 +useDidShow(() => {
141 + initData();
142 +});
123 </script> 143 </script>
......
1 <!-- 1 <!--
2 * @Date: 2025-08-27 17:47:26 2 * @Date: 2025-08-27 17:47:26
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-08-29 20:32:08 4 + * @LastEditTime: 2025-09-03 21:43:41
5 * @FilePath: /lls_program/src/pages/Rewards/index.vue 5 * @FilePath: /lls_program/src/pages/Rewards/index.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
8 <template> 8 <template>
9 <view class="min-h-screen flex flex-col bg-white"> 9 <view class="min-h-screen flex flex-col bg-white">
10 <!-- Blue header background --> 10 <!-- Blue header background -->
11 - <view class="bg-blue-500 h-48 absolute w-full top-0 left-0 z-0"></view> 11 + <view v-if="isCreator" class="bg-blue-500 h-48 absolute w-full top-0 left-0 z-0"></view>
12 <!-- <AppHeader title="兑换中心" :showBack="false" /> --> 12 <!-- <AppHeader title="兑换中心" :showBack="false" /> -->
13 <!-- Content --> 13 <!-- Content -->
14 <view class="relative z-10 flex-1 pb-20"> 14 <view class="relative z-10 flex-1 pb-20">
15 <!-- Points display --> 15 <!-- Points display -->
16 - <view class="pt-8 pb-8 flex flex-col items-center"> 16 + <view v-if="isCreator" class="pt-8 pb-8 flex flex-col items-center">
17 <h2 class="text-4xl font-bold text-white mb-1">{{ totalPoints }}分</h2> 17 <h2 class="text-4xl font-bold text-white mb-1">{{ totalPoints }}分</h2>
18 <p class="text-white text-opacity-80">我的积分</p> 18 <p class="text-white text-opacity-80">我的积分</p>
19 </view> 19 </view>
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
60 </view> 60 </view>
61 <view class="ml-4 px-4 py-2 bg-blue-500 text-white rounded-lg text-sm flex-shrink-0" 61 <view class="ml-4 px-4 py-2 bg-blue-500 text-white rounded-lg text-sm flex-shrink-0"
62 @click="goToRewardDetail(reward)"> 62 @click="goToRewardDetail(reward)">
63 - {{ reward.points }}分兑换 63 + {{ isCreator ? reward.points + '分兑换' : '查看' }}
64 </view> 64 </view>
65 </view> 65 </view>
66 </view> 66 </view>
...@@ -74,12 +74,14 @@ ...@@ -74,12 +74,14 @@
74 import { ref, computed, onMounted } from 'vue'; 74 import { ref, computed, onMounted } from 'vue';
75 import Taro, { useDidShow } from '@tarojs/taro'; 75 import Taro, { useDidShow } from '@tarojs/taro';
76 import { ScreenLittle, Search2 } from '@nutui/icons-vue-taro'; 76 import { ScreenLittle, Search2 } from '@nutui/icons-vue-taro';
77 +import { getUserProfileAPI } from '@/api/user';
77 78
78 const searchQuery = ref(''); 79 const searchQuery = ref('');
79 const selectedPoints = ref(null); 80 const selectedPoints = ref(null);
80 const sortOrder = ref('desc'); // 'asc' or 'desc' 81 const sortOrder = ref('desc'); // 'asc' or 'desc'
81 82
82 const totalPoints = ref(0); 83 const totalPoints = ref(0);
84 +const isCreator = ref(false);
83 85
84 const sortedRewardItems = computed(() => { 86 const sortedRewardItems = computed(() => {
85 let items = [...rewardItems.value]; 87 let items = [...rewardItems.value];
...@@ -156,7 +158,20 @@ const goToRewardDetail = (reward) => { ...@@ -156,7 +158,20 @@ const goToRewardDetail = (reward) => {
156 }; 158 };
157 159
158 const initData = async () => { 160 const initData = async () => {
159 - totalPoints.value = '9856'; 161 + // 获取用户信息,判断是否为创建者
162 + try {
163 + const { code, data } = await getUserProfileAPI();
164 + if (code) {
165 + isCreator.value = data?.user?.is_creator || false;
166 + // 只有创建者才显示积分
167 + if (isCreator.value) {
168 + totalPoints.value = '9856';
169 + }
170 + }
171 + } catch (error) {
172 + console.error('获取用户信息失败:', error);
173 + isCreator.value = false;
174 + }
160 console.warn('初始化数据') 175 console.warn('初始化数据')
161 } 176 }
162 177
......
1 <!-- 1 <!--
2 * @Date: 2022-09-19 14:11:06 2 * @Date: 2022-09-19 14:11:06
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-09-03 17:02:11 4 + * @LastEditTime: 2025-09-03 21:05:25
5 * @FilePath: /lls_program/src/pages/auth/index.vue 5 * @FilePath: /lls_program/src/pages/auth/index.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
......