hookehuyr

feat(家庭功能): 优化家庭创建和编辑页面的封面图处理

- 添加默认家庭封面图资源
- 统一家庭名称输入限制为10个字符
- 优化封面图上传和预览逻辑,支持默认封面显示
- 调整上传图片大小限制为5MB
- 为输入框添加cursorSpacing属性改善用户体验
1 +<svg width="400" height="200" viewBox="0 0 400 200" fill="none" xmlns="http://www.w3.org/2000/svg">
2 + <!-- 背景渐变 -->
3 + <defs>
4 + <linearGradient id="bg-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
5 + <stop offset="0%" style="stop-color:#E3F2FD;stop-opacity:1" />
6 + <stop offset="100%" style="stop-color:#BBDEFB;stop-opacity:1" />
7 + </linearGradient>
8 + </defs>
9 +
10 + <!-- 背景 -->
11 + <rect width="400" height="200" fill="url(#bg-gradient)"/>
12 +
13 + <!-- 房子图标 -->
14 + <g transform="translate(150, 60)">
15 + <!-- 房子主体 -->
16 + <rect x="20" y="40" width="60" height="50" fill="#FFF3E0" stroke="#FF9800" stroke-width="2" rx="4"/>
17 +
18 + <!-- 屋顶 -->
19 + <polygon points="10,45 50,15 90,45" fill="#FF5722" stroke="#D84315" stroke-width="2"/>
20 +
21 + <!-- 门 -->
22 + <rect x="35" y="65" width="15" height="25" fill="#8D6E63" rx="2"/>
23 + <circle cx="46" cy="77" r="1.5" fill="#FFF"/>
24 +
25 + <!-- 窗户 -->
26 + <rect x="25" y="50" width="12" height="10" fill="#81D4FA" stroke="#0277BD" stroke-width="1" rx="1"/>
27 + <rect x="63" y="50" width="12" height="10" fill="#81D4FA" stroke="#0277BD" stroke-width="1" rx="1"/>
28 +
29 + <!-- 窗户十字 -->
30 + <line x1="31" y1="50" x2="31" y2="60" stroke="#0277BD" stroke-width="0.5"/>
31 + <line x1="25" y1="55" x2="37" y2="55" stroke="#0277BD" stroke-width="0.5"/>
32 + <line x1="69" y1="50" x2="69" y2="60" stroke="#0277BD" stroke-width="0.5"/>
33 + <line x1="63" y1="55" x2="75" y2="55" stroke="#0277BD" stroke-width="0.5"/>
34 + </g>
35 +
36 + <!-- 文字 -->
37 + <text x="200" y="130" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" fill="#666" font-weight="500">温馨家庭</text>
38 + <text x="200" y="150" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#999">点击上传家庭封面图</text>
39 +</svg>
...\ No newline at end of file ...\ No newline at end of file
1 <!-- 1 <!--
2 * @Date: 2025-08-27 17:44:53 2 * @Date: 2025-08-27 17:44:53
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-09-01 11:37:51 4 + * @LastEditTime: 2025-09-02 11:27:00
5 * @FilePath: /lls_program/src/pages/CreateFamily/index.vue 5 * @FilePath: /lls_program/src/pages/CreateFamily/index.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
21 type="text" 21 type="text"
22 v-model="familyName" 22 v-model="familyName"
23 class="w-full text-gray-600 focus:outline-none" 23 class="w-full text-gray-600 focus:outline-none"
24 - placeholder="请输入家庭名称(最多20个字)" 24 + placeholder="请输入家庭名称(最多10个字)"
25 @blur="validateFamilyName" 25 @blur="validateFamilyName"
26 - maxlength="20" 26 + maxlength="10"
27 /> 27 />
28 <view v-if="familyNameError" class="text-red-500 text-sm mt-2">{{ familyNameError }}</view> 28 <view v-if="familyNameError" class="text-red-500 text-sm mt-2">{{ familyNameError }}</view>
29 </view> 29 </view>
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
82 @blur="handleBlur(index)" 82 @blur="handleBlur(index)"
83 class="w-full h-full bg-transparent text-center" 83 class="w-full h-full bg-transparent text-center"
84 style="font-size: 38rpx;" 84 style="font-size: 38rpx;"
85 + :cursorSpacing="100"
85 /> 86 />
86 </view> 87 </view>
87 </view> 88 </view>
...@@ -103,36 +104,34 @@ ...@@ -103,36 +104,34 @@
103 <view class="block text-lg font-medium mb-2"> 104 <view class="block text-lg font-medium mb-2">
104 家庭封面图(选填) 105 家庭封面图(选填)
105 </view> 106 </view>
106 - <!-- 已上传封面显示 --> 107 + <!-- 封面显示区域 -->
107 - <view v-if="familyAvatar" class="mb-4"> 108 + <view class="mb-4">
108 <view class="relative"> 109 <view class="relative">
109 <image 110 <image
110 - :src="familyAvatar" 111 + :src="familyAvatar || defaultFamilyCover"
111 class="w-full h-48 rounded-lg object-cover" 112 class="w-full h-48 rounded-lg object-cover"
112 mode="aspectFill" 113 mode="aspectFill"
113 @tap="previewAvatar" 114 @tap="previewAvatar"
114 /> 115 />
115 <view 116 <view
117 + v-if="familyAvatar"
116 @click="deleteAvatar" 118 @click="deleteAvatar"
117 class="absolute -top-2 -right-2 w-6 h-6 bg-red-500 rounded-full flex items-center justify-center" 119 class="absolute -top-2 -right-2 w-6 h-6 bg-red-500 rounded-full flex items-center justify-center"
118 > 120 >
119 <view class="text-white text-sm">×</view> 121 <view class="text-white text-sm">×</view>
120 </view> 122 </view>
123 + <view
124 + @click="chooseImage"
125 + class="absolute bottom-2 right-2 px-3 py-1 bg-black bg-opacity-50 text-white text-sm rounded-full flex items-center"
126 + >
127 + <Photograph size="14" class="mr-1" />
128 + {{ familyAvatar ? '更换' : '上传' }}
129 + </view>
121 </view> 130 </view>
122 </view> 131 </view>
123 - <!-- 上传区域 --> 132 + <!-- 上传提示 -->
124 - <view 133 + <view class="text-center text-gray-400 text-sm">
125 - v-if="!familyAvatar" 134 + 支持图片格式(jpg、png)最大5MB
126 - class="border border-dashed border-gray-200 rounded-lg p-12 flex flex-col items-center justify-center h-48"
127 - @click="chooseImage"
128 - >
129 - <view class="text-gray-400 mb-4">
130 - <Photograph size="32" />
131 - </view>
132 - <view class="text-center text-gray-400 text-lg">点击上传封面图</view>
133 - <view class="text-center text-gray-400 text-sm mt-2">
134 - 支持图片格式(jpg、png)最大10MB
135 - </view>
136 </view> 135 </view>
137 </view> 136 </view>
138 </view> 137 </view>
...@@ -178,6 +177,7 @@ import Taro from '@tarojs/taro'; ...@@ -178,6 +177,7 @@ import Taro from '@tarojs/taro';
178 import { Edit, Tips, Photograph, Right } from '@nutui/icons-vue-taro'; 177 import { Edit, Tips, Photograph, Right } from '@nutui/icons-vue-taro';
179 // import AppHeader from '../../components/AppHeader.vue'; 178 // import AppHeader from '../../components/AppHeader.vue';
180 import BASE_URL from '@/utils/config'; 179 import BASE_URL from '@/utils/config';
180 +import defaultFamilyCoverSvg from '@/assets/images/default-family-cover.png';
181 181
182 const familyName = ref(''); 182 const familyName = ref('');
183 const familyIntro = ref(''); 183 const familyIntro = ref('');
...@@ -214,6 +214,7 @@ const districtColumns = ref([ ...@@ -214,6 +214,7 @@ const districtColumns = ref([
214 const familyAvatar = ref(''); 214 const familyAvatar = ref('');
215 const focusedIndex = ref(-1); 215 const focusedIndex = ref(-1);
216 const inputRefs = ref([]); 216 const inputRefs = ref([]);
217 +const defaultFamilyCover = ref(defaultFamilyCoverSvg);
217 218
218 const isFormValid = computed(() => { 219 const isFormValid = computed(() => {
219 return ( 220 return (
...@@ -298,14 +299,14 @@ const chooseImage = () => { ...@@ -298,14 +299,14 @@ const chooseImage = () => {
298 success: function (res) { 299 success: function (res) {
299 const tempFilePath = res.tempFilePaths[0]; 300 const tempFilePath = res.tempFilePaths[0];
300 301
301 - // 检查文件大小(10MB = 10 * 1024 * 1024 bytes) 302 + // 检查文件大小(5MB = 5 * 1024 * 1024 bytes)
302 - Taro.getFileInfo({ 303 + Taro.getFileInfo({
303 - filePath: tempFilePath, 304 + filePath: tempFilePath,
304 - success: function (fileInfo) { 305 + success: function (fileInfo) {
305 - if (fileInfo.size > 10 * 1024 * 1024) { 306 + if (fileInfo.size > 5 * 1024 * 1024) {
306 - showToast('图片大小不能超过10MB', 'none'); 307 + showToast('图片大小不能超过5MB', 'none');
307 - return; 308 + return;
308 - } 309 + }
309 uploadImage(tempFilePath); 310 uploadImage(tempFilePath);
310 }, 311 },
311 fail: function () { 312 fail: function () {
...@@ -364,11 +365,8 @@ const uploadImage = (filePath) => { ...@@ -364,11 +365,8 @@ const uploadImage = (filePath) => {
364 * 预览头像 365 * 预览头像
365 */ 366 */
366 const previewAvatar = () => { 367 const previewAvatar = () => {
367 - if (!familyAvatar.value) { 368 + const imageToPreview = familyAvatar.value || defaultFamilyCover.value;
368 - showToast('暂无图片可预览', 'error'); 369 + previewImages.value = [{ src: imageToPreview }];
369 - return;
370 - }
371 - previewImages.value = [{ src: familyAvatar.value }];
372 previewIndex.value = 0; 370 previewIndex.value = 0;
373 previewVisible.value = true; 371 previewVisible.value = true;
374 }; 372 };
...@@ -393,8 +391,8 @@ const closePreview = () => { ...@@ -393,8 +391,8 @@ const closePreview = () => {
393 */ 391 */
394 const validateFamilyName = () => { 392 const validateFamilyName = () => {
395 familyNameError.value = ''; 393 familyNameError.value = '';
396 - if (familyName.value.length > 20) { 394 + if (familyName.value.length > 10) {
397 - familyNameError.value = '家庭名称不能超过20个字'; 395 + familyNameError.value = '家庭名称不能超过10个字';
398 } 396 }
399 }; 397 };
400 398
...@@ -421,10 +419,10 @@ const validateForm = () => { ...@@ -421,10 +419,10 @@ const validateForm = () => {
421 return false; 419 return false;
422 } 420 }
423 421
424 - if (familyName.value.length > 20) { 422 + if (familyName.value.length > 10) {
425 Taro.showModal({ 423 Taro.showModal({
426 title: '提示', 424 title: '提示',
427 - content: '家庭名称不能超过20个字,请重新输入', 425 + content: '家庭名称不能超过10个字,请重新输入',
428 showCancel: false 426 showCancel: false
429 }); 427 });
430 return false; 428 return false;
......
1 <!-- 1 <!--
2 * @Date: 2025-08-27 17:44:53 2 * @Date: 2025-08-27 17:44:53
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-09-01 11:39:03 4 + * @LastEditTime: 2025-09-02 11:23:27
5 * @FilePath: /lls_program/src/pages/EditFamily/index.vue 5 * @FilePath: /lls_program/src/pages/EditFamily/index.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
21 type="text" 21 type="text"
22 v-model="familyName" 22 v-model="familyName"
23 class="w-full text-gray-600 focus:outline-none" 23 class="w-full text-gray-600 focus:outline-none"
24 - placeholder="请输入家庭名称(最多20个字)" 24 + placeholder="请输入家庭名称(最多10个字)"
25 @blur="validateFamilyName" 25 @blur="validateFamilyName"
26 - maxlength="20" 26 + maxlength="10"
27 /> 27 />
28 <view v-if="familyNameError" class="text-red-500 text-sm mt-2">{{ familyNameError }}</view> 28 <view v-if="familyNameError" class="text-red-500 text-sm mt-2">{{ familyNameError }}</view>
29 </view> 29 </view>
...@@ -103,36 +103,34 @@ ...@@ -103,36 +103,34 @@
103 <view class="block text-lg font-medium mb-2"> 103 <view class="block text-lg font-medium mb-2">
104 家庭封面图(选填) 104 家庭封面图(选填)
105 </view> 105 </view>
106 - <!-- 已上传封面显示 --> 106 + <!-- 封面显示区域 -->
107 - <view v-if="familyAvatar" class="mb-4"> 107 + <view class="mb-4">
108 <view class="relative"> 108 <view class="relative">
109 <image 109 <image
110 - :src="familyAvatar" 110 + :src="familyAvatar || defaultFamilyCover"
111 class="w-full h-48 rounded-lg object-cover" 111 class="w-full h-48 rounded-lg object-cover"
112 mode="aspectFill" 112 mode="aspectFill"
113 @tap="previewAvatar" 113 @tap="previewAvatar"
114 /> 114 />
115 <view 115 <view
116 + v-if="familyAvatar"
116 @click="deleteAvatar" 117 @click="deleteAvatar"
117 class="absolute -top-2 -right-2 w-6 h-6 bg-red-500 rounded-full flex items-center justify-center" 118 class="absolute -top-2 -right-2 w-6 h-6 bg-red-500 rounded-full flex items-center justify-center"
118 > 119 >
119 <view class="text-white text-sm">×</view> 120 <view class="text-white text-sm">×</view>
120 </view> 121 </view>
122 + <view
123 + @click="chooseImage"
124 + class="absolute bottom-2 right-2 px-3 py-1 bg-black bg-opacity-50 text-white text-sm rounded-full flex items-center"
125 + >
126 + <Photograph size="14" class="mr-1" />
127 + {{ familyAvatar ? '更换' : '上传' }}
128 + </view>
121 </view> 129 </view>
122 </view> 130 </view>
123 - <!-- 上传区域 --> 131 + <!-- 上传提示 -->
124 - <view 132 + <view class="text-center text-gray-400 text-sm">
125 - v-if="!familyAvatar" 133 + 支持图片格式(jpg、png)最大5MB
126 - class="border border-dashed border-gray-200 rounded-lg p-12 flex flex-col items-center justify-center h-48"
127 - @click="chooseImage"
128 - >
129 - <view class="text-gray-400 mb-4">
130 - <Photograph size="32" />
131 - </view>
132 - <view class="text-center text-gray-400 text-lg">点击上传封面图</view>
133 - <view class="text-center text-gray-400 text-sm mt-2">
134 - 支持图片格式(jpg、png)最大10MB
135 - </view>
136 </view> 134 </view>
137 </view> 135 </view>
138 </view> 136 </view>
...@@ -175,6 +173,7 @@ import Taro from '@tarojs/taro'; ...@@ -175,6 +173,7 @@ import Taro from '@tarojs/taro';
175 import { Edit, Tips, Photograph, Right } from '@nutui/icons-vue-taro'; 173 import { Edit, Tips, Photograph, Right } from '@nutui/icons-vue-taro';
176 // import AppHeader from '../../components/AppHeader.vue'; 174 // import AppHeader from '../../components/AppHeader.vue';
177 import BASE_URL from '@/utils/config'; 175 import BASE_URL from '@/utils/config';
176 +import defaultFamilyCoverSvg from '@/assets/images/default-family-cover.png';
178 177
179 const familyName = ref(''); 178 const familyName = ref('');
180 const familyIntro = ref(''); 179 const familyIntro = ref('');
...@@ -210,6 +209,7 @@ const districtColumns = ref([ ...@@ -210,6 +209,7 @@ const districtColumns = ref([
210 ]); 209 ]);
211 const familyAvatar = ref(''); 210 const familyAvatar = ref('');
212 const focusedIndex = ref(-1); 211 const focusedIndex = ref(-1);
212 +const defaultFamilyCover = ref(defaultFamilyCoverSvg);
213 213
214 // 图片预览相关 214 // 图片预览相关
215 const previewVisible = ref(false); 215 const previewVisible = ref(false);
...@@ -281,12 +281,12 @@ const chooseImage = () => { ...@@ -281,12 +281,12 @@ const chooseImage = () => {
281 success: function (res) { 281 success: function (res) {
282 const tempFilePath = res.tempFilePaths[0]; 282 const tempFilePath = res.tempFilePaths[0];
283 283
284 - // 检查文件大小(10MB = 10 * 1024 * 1024 bytes) 284 + // 检查文件大小(5MB = 5 * 1024 * 1024 bytes)
285 Taro.getFileInfo({ 285 Taro.getFileInfo({
286 filePath: tempFilePath, 286 filePath: tempFilePath,
287 success: function (fileInfo) { 287 success: function (fileInfo) {
288 - if (fileInfo.size > 10 * 1024 * 1024) { 288 + if (fileInfo.size > 5 * 1024 * 1024) {
289 - showToast('图片大小不能超过10MB', 'none'); 289 + showToast('图片大小不能超过5MB', 'none');
290 return; 290 return;
291 } 291 }
292 uploadImage(tempFilePath); 292 uploadImage(tempFilePath);
...@@ -347,11 +347,8 @@ const uploadImage = (filePath) => { ...@@ -347,11 +347,8 @@ const uploadImage = (filePath) => {
347 * 预览头像 347 * 预览头像
348 */ 348 */
349 const previewAvatar = () => { 349 const previewAvatar = () => {
350 - if (!familyAvatar.value) { 350 + const imageToPreview = familyAvatar.value || defaultFamilyCover.value;
351 - showToast('暂无图片可预览', 'none'); 351 + previewImages.value = [{ src: imageToPreview }];
352 - return;
353 - }
354 - previewImages.value = [{ src: familyAvatar.value }];
355 previewIndex.value = 0; 352 previewIndex.value = 0;
356 previewVisible.value = true; 353 previewVisible.value = true;
357 }; 354 };
...@@ -376,8 +373,8 @@ const closePreview = () => { ...@@ -376,8 +373,8 @@ const closePreview = () => {
376 */ 373 */
377 const validateFamilyName = () => { 374 const validateFamilyName = () => {
378 familyNameError.value = ''; 375 familyNameError.value = '';
379 - if (familyName.value.length > 20) { 376 + if (familyName.value.length > 10) {
380 - familyNameError.value = '家庭名称不能超过20个字'; 377 + familyNameError.value = '家庭名称不能超过10个字';
381 } 378 }
382 }; 379 };
383 380
...@@ -404,10 +401,10 @@ const validateForm = () => { ...@@ -404,10 +401,10 @@ const validateForm = () => {
404 return false; 401 return false;
405 } 402 }
406 403
407 - if (familyName.value.length > 20) { 404 + if (familyName.value.length > 10) {
408 Taro.showModal({ 405 Taro.showModal({
409 title: '提示', 406 title: '提示',
410 - content: '家庭名称不能超过20个字,请重新输入', 407 + content: '家庭名称不能超过10个字,请重新输入',
411 showCancel: false 408 showCancel: false
412 }); 409 });
413 return false; 410 return false;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
28 @focus="focusedIndex = index" 28 @focus="focusedIndex = index"
29 @blur="handleBlur(index)" 29 @blur="handleBlur(index)"
30 class="motto-input" 30 class="motto-input"
31 + :cursorSpacing="100"
31 /> 32 />
32 </view> 33 </view>
33 </view> 34 </view>
......