hookehuyr

feat(MyFamily): 实现家庭列表页面及切换退出功能

添加家庭列表页面完整UI实现,包括:
- 家庭卡片展示封面、名称、成员信息
- 成员头像叠加显示效果
- 当前家庭标记
- 切换家庭和退出家庭功能
- 空状态和底部加入新家庭按钮
更新配置文件描述和样式文件
...@@ -14,6 +14,7 @@ declare module 'vue' { ...@@ -14,6 +14,7 @@ declare module 'vue' {
14 NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet'] 14 NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet']
15 NutButton: typeof import('@nutui/nutui-taro')['Button'] 15 NutButton: typeof import('@nutui/nutui-taro')['Button']
16 NutDatePicker: typeof import('@nutui/nutui-taro')['DatePicker'] 16 NutDatePicker: typeof import('@nutui/nutui-taro')['DatePicker']
17 + NutDialog: typeof import('@nutui/nutui-taro')['Dialog']
17 NutImagePreview: typeof import('@nutui/nutui-taro')['ImagePreview'] 18 NutImagePreview: typeof import('@nutui/nutui-taro')['ImagePreview']
18 NutInput: typeof import('@nutui/nutui-taro')['Input'] 19 NutInput: typeof import('@nutui/nutui-taro')['Input']
19 NutPicker: typeof import('@nutui/nutui-taro')['Picker'] 20 NutPicker: typeof import('@nutui/nutui-taro')['Picker']
......
1 /* 1 /*
2 * @Date: 2025-08-29 10:51:54 2 * @Date: 2025-08-29 10:51:54
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-08-29 10:52:16 4 + * @LastEditTime: 2025-08-29 15:11:39
5 * @FilePath: /lls_program/src/pages/MyFamily/index.config.js 5 * @FilePath: /lls_program/src/pages/MyFamily/index.config.js
6 - * @Description: 文件描述 6 + * @Description: 我的家庭页面 - 配置文件
7 */ 7 */
8 export default { 8 export default {
9 navigationBarTitleText: '我的家庭', 9 navigationBarTitleText: '我的家庭',
......
1 -.red { 1 +/* 我的家庭页面样式 */
2 - color: red; 2 +
3 +/* 渐变背景覆盖层 */
4 +.bg-gradient-to-t {
5 + background: linear-gradient(to top, rgba(0, 0, 0, 0.6), transparent);
6 +}
7 +
8 +/* 成员头像叠加效果 */
9 +.avatar-overlap {
10 + display: flex;
11 +}
12 +
13 +.avatar-overlap .avatar-item:not(:first-child) {
14 + margin-left: -10rpx;
15 +}
16 +
17 +/* 兼容Tailwind的-space-x-2类名 */
18 +.-space-x-2 > * + * {
19 + margin-left: -10rpx !important;
20 +}
21 +
22 +/* 确保头像圆形显示 */
23 +.rounded-full {
24 + border-radius: 50%;
25 +}
26 +
27 +/* 按钮悬停效果 */
28 +.bg-blue-500:active {
29 + background-color: #2563eb;
30 +}
31 +
32 +.bg-red-500:active {
33 + background-color: #dc2626;
34 +}
35 +
36 +/* 卡片阴影效果 */
37 +.shadow-sm {
38 + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
39 +}
40 +
41 +/* 固定底部按钮样式 */
42 +.fixed {
43 + position: fixed;
44 +}
45 +
46 +/* 空状态图标居中 */
47 +.text-center {
48 + text-align: center;
49 +}
50 +
51 +/* 响应式间距 */
52 +.space-y-4 > * + * {
53 + margin-top: 16rpx;
54 +}
55 +
56 +.gap-3 {
57 + gap: 12rpx;
58 +}
59 +
60 +/* 文本省略 */
61 +.line-clamp-2 {
62 + display: -webkit-box;
63 + -webkit-line-clamp: 2;
64 + -webkit-box-orient: vertical;
65 + overflow: hidden;
3 } 66 }
......
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-08-29 12:47:26 4 + * @LastEditTime: 2025-08-29 15:27:43
5 * @FilePath: /lls_program/src/pages/MyFamily/index.vue 5 * @FilePath: /lls_program/src/pages/MyFamily/index.vue
6 - * @Description: 文件描述 6 + * @Description: 我的家庭页面 - 展示用户加入的家庭列表
7 --> 7 -->
8 <template> 8 <template>
9 - <div class="red">{{ str }}</div> 9 + <view class="min-h-screen bg-gray-50 pb-20">
10 + <!-- 家庭列表 -->
11 + <view class="px-4 py-4 space-y-4">
12 + <view
13 + v-for="family in familyList"
14 + :key="family.id"
15 + class="bg-white rounded-lg overflow-hidden shadow-sm border border-gray-100"
16 + >
17 + <!-- 家庭封面图和基本信息 -->
18 + <view class="relative">
19 + <!-- 当前家庭标记 -->
20 + <view
21 + v-if="family.isCurrent"
22 + class="absolute top-2 right-2 bg-blue-500 text-white text-xs px-2 py-1 rounded-sm z-10"
23 + >
24 + 当前家庭
25 + </view>
26 +
27 + <!-- 封面图 -->
28 + <image
29 + :src="family.coverImage"
30 + class="w-full h-44 object-cover"
31 + mode="aspectFill"
32 + />
33 +
34 + <!-- 家庭名称和大家长信息覆盖层 -->
35 + <view class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/60 to-transparent p-4">
36 + <view class="text-white font-bold text-lg mb-1">{{ family.name }}</view>
37 + <view class="text-white/90 text-sm">大家长:{{ family.ownerName }}</view>
38 + </view>
39 + </view>
40 +
41 + <!-- 成员信息和操作按钮 -->
42 + <view class="p-4">
43 + <!-- 成员头像和数量 -->
44 + <view class="flex items-center justify-between mb-4">
45 + <view class="flex items-center">
46 + <!-- 成员头像叠加效果 -->
47 + <view class="avatar-overlap">
48 + <image
49 + v-for="(member, index) in family.members.slice(0, 4)"
50 + :key="member.id"
51 + :src="member.avatar"
52 + class="avatar-item w-8 h-8 rounded-full border-2 border-white object-cover"
53 + :style="{ zIndex: 10 - index }"
54 + />
55 + <!-- 更多成员数量显示 -->
56 + <view
57 + v-if="family.members.length > 4"
58 + class="w-8 h-8 rounded-full bg-gray-300 border-2 border-white flex items-center justify-center text-xs text-gray-600"
59 + :style="{ zIndex: 6 }"
60 + >
61 + +{{ family.members.length - 4 }}
62 + </view>
63 + </view>
64 + <!-- 总成员数 -->
65 + <view class="ml-3 text-sm text-gray-600">
66 + {{ family.members.length }} 位家庭成员
67 + </view>
68 + </view>
69 + </view>
70 +
71 + <!-- 操作按钮 -->
72 + <view class="flex gap-3 justify-end">
73 + <view
74 + v-if="!family.isCurrent"
75 + @tap="switchToFamily(family.id)"
76 + class="px-4 py-2 bg-blue-500 text-white text-sm rounded-lg"
77 + >
78 + 切换到此家庭
79 + </view>
80 + <view
81 + @tap="exitFamily(family.id)"
82 + class="px-4 py-2 bg-red-500 text-white text-sm rounded-lg"
83 + >
84 + 退出家庭
85 + </view>
86 + </view>
87 + </view>
88 + </view>
89 +
90 + <!-- 空状态 -->
91 + <view v-if="familyList.length === 0" class="text-center py-12">
92 + <view class="text-gray-400 mb-4">
93 + <Home size="48" />
94 + </view>
95 + <view class="text-gray-500 mb-2">您还没有加入任何家庭</view>
96 + <view class="text-gray-400 text-sm">点击下方按钮加入家庭,开始健康之旅</view>
97 + </view>
98 + </view>
99 +
100 + <!-- 底部固定按钮 -->
101 + <view class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 p-4 z-10">
102 + <view
103 + @tap="joinNewFamily"
104 + class="w-full bg-blue-500 text-white text-center py-3 rounded-lg font-medium"
105 + >
106 + + 加入新家庭
107 + </view>
108 + </view>
109 +
110 + <!-- 确认弹窗已替换为Taro.showModal -->
111 + </view>
10 </template> 112 </template>
11 113
12 <script setup> 114 <script setup>
13 -// import '@tarojs/taro/html.css' 115 +import { ref, onMounted } from 'vue';
14 -import { ref } from "vue"; 116 +import Taro from '@tarojs/taro';
15 -import "./index.less"; 117 +import { Home } from '@nutui/icons-vue-taro';
118 +import './index.less';
119 +
120 +// 响应式数据
121 +const familyList = ref([]);
122 +
123 +/**
124 + * 初始化页面数据
125 + */
126 +const initPageData = () => {
127 + // 模拟家庭数据
128 + familyList.value = [
129 + {
130 + id: 1,
131 + name: '幸福之家',
132 + ownerName: '张明明',
133 + coverImage: 'https://images.unsplash.com/photo-1511895426328-dc8714191300?w=400&h=200&fit=crop',
134 + isCurrent: true,
135 + members: [
136 + { id: 1, avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face' },
137 + { id: 2, avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face' },
138 + { id: 3, avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face' }
139 + ]
140 + },
141 + {
142 + id: 2,
143 + name: '欢乐之家',
144 + ownerName: '李志强',
145 + coverImage: 'https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?w=400&h=200&fit=crop',
146 + isCurrent: false,
147 + members: [
148 + { id: 4, avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop&crop=face' },
149 + { id: 5, avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face' }
150 + ]
151 + },
152 + {
153 + id: 3,
154 + name: '快乐之家',
155 + ownerName: '王芳',
156 + coverImage: 'https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?w=400&h=200&fit=crop',
157 + isCurrent: false,
158 + members: [
159 + { id: 6, avatar: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop&crop=face' },
160 + { id: 7, avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face' }
161 + ]
162 + },
163 + ];
164 +};
165 +
166 +/**
167 + * 切换到指定家庭
168 + * @param {number} familyId - 家庭ID
169 + */
170 +const switchToFamily = (familyId) => {
171 + const family = familyList.value.find(f => f.id === familyId);
172 + if (!family) return;
173 +
174 + Taro.showModal({
175 + title: '切换家庭',
176 + content: `确定要切换到「${family.name}」吗?`,
177 + success: (res) => {
178 + if (res.confirm) {
179 + // 切换家庭逻辑 - 先清除所有当前标记,再设置新的当前家庭
180 + familyList.value = familyList.value.map(f => ({
181 + ...f,
182 + isCurrent: f.id === familyId
183 + }));
184 +
185 + console.log('切换家庭后的列表:', familyList.value);
186 +
187 + Taro.showToast({
188 + title: '切换成功',
189 + icon: 'success'
190 + });
191 + }
192 + }
193 + });
194 +};
195 +
196 +/**
197 + * 退出家庭
198 + * @param {number} familyId - 家庭ID
199 + */
200 +const exitFamily = (familyId) => {
201 + const family = familyList.value.find(f => f.id === familyId);
202 + if (!family) return;
203 +
204 + Taro.showModal({
205 + title: '退出家庭',
206 + content: `确定要退出「${family.name}」吗?退出后将无法查看该家庭的相关信息。`,
207 + success: (res) => {
208 + if (res.confirm) {
209 + // 退出家庭逻辑
210 + const exitingFamily = familyList.value.find(f => f.id === familyId);
211 +
212 + if (exitingFamily?.isCurrent) {
213 + // 如果退出的是当前家庭,需要返回我的页面
214 + familyList.value = familyList.value.filter(f => f.id !== familyId);
215 +
216 + Taro.showToast({
217 + title: '已退出家庭',
218 + icon: 'success'
219 + });
220 +
221 + // 延迟返回我的页面
222 + setTimeout(() => {
223 + Taro.navigateBack();
224 + }, 1500);
225 + } else {
226 + // 退出非当前家庭
227 + familyList.value = familyList.value.filter(f => f.id !== familyId);
228 +
229 + Taro.showToast({
230 + title: '已退出家庭',
231 + icon: 'success'
232 + });
233 + }
234 + }
235 + }
236 + });
237 +};
238 +
239 +/**
240 + * 加入新家庭
241 + */
242 +const joinNewFamily = () => {
243 + Taro.navigateTo({
244 + url: '/pages/JoinFamily/index'
245 + });
246 +};
247 +
248 +
16 249
17 -// 定义响应式数据 250 +// 页面加载时初始化数据
18 -const str = ref('我的家庭') 251 +onMounted(() => {
252 + initPageData();
253 +});
19 </script> 254 </script>
20 255
21 <script> 256 <script>
22 export default { 257 export default {
23 - name: "MyFamily", 258 + name: 'MyFamily',
24 }; 259 };
25 </script> 260 </script>
......
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-08-27 20:41:05 4 + * @LastEditTime: 2025-08-29 14:38:56
5 * @FilePath: /lls_program/src/utils/config.js 5 * @FilePath: /lls_program/src/utils/config.js
6 * @Description: 环境配置文件 - 根据小程序运行环境自动切换API地址 6 * @Description: 环境配置文件 - 根据小程序运行环境自动切换API地址
7 */ 7 */
...@@ -25,10 +25,10 @@ function getBaseUrl() { ...@@ -25,10 +25,10 @@ function getBaseUrl() {
25 baseUrl = 'https://oa-dev.onwall.cn'; // 体验版暂时使用开发环境 25 baseUrl = 'https://oa-dev.onwall.cn'; // 体验版暂时使用开发环境
26 break; 26 break;
27 case 'release': // 正式版 27 case 'release': // 正式版
28 - baseUrl = 'https://jiangedianlv.onwall.cn'; 28 + baseUrl = 'https://walk.onwall.cn';
29 break; 29 break;
30 default: // 未知环境,默认使用正式版地址 30 default: // 未知环境,默认使用正式版地址
31 - baseUrl = 'https://jiangedianlv.onwall.cn'; 31 + baseUrl = 'https://walk.onwall.cn';
32 } 32 }
33 33
34 // eslint-disable-next-line no-console 34 // eslint-disable-next-line no-console
......