hookehuyr

feat(家庭表单): 添加家庭名称和介绍的字数验证及错误提示

为家庭创建和编辑表单添加字数限制验证功能
- 家庭名称限制20字并显示错误提示
- 家庭介绍限制100字并显示错误提示
- 在表单提交时进行验证
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-08-29 13:58:07 4 + * @LastEditTime: 2025-08-29 15:49:47
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,8 +21,11 @@ ...@@ -21,8 +21,11 @@
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="请输入家庭名称" 24 + placeholder="请输入家庭名称(最多20个字)"
25 + @blur="validateFamilyName"
26 + maxlength="20"
25 /> 27 />
28 + <view v-if="familyNameError" class="text-red-500 text-sm mt-2">{{ familyNameError }}</view>
26 </view> 29 </view>
27 </view> 30 </view>
28 <!-- Family Introduction --> 31 <!-- Family Introduction -->
...@@ -32,9 +35,12 @@ ...@@ -32,9 +35,12 @@
32 <textarea 35 <textarea
33 v-model="familyIntro" 36 v-model="familyIntro"
34 class="w-full text-gray-600 focus:outline-none resize-none" 37 class="w-full text-gray-600 focus:outline-none resize-none"
35 - placeholder="请输入您家庭的特色、成员特点等家庭标签" 38 + placeholder="请输入您家庭的特色、成员特点等家庭标签(最多100个字)"
36 :rows="2" 39 :rows="2"
40 + @blur="validateFamilyIntro"
41 + maxlength="100"
37 /> 42 />
43 + <view v-if="familyIntroError" class="text-red-500 text-sm mt-2">{{ familyIntroError }}</view>
38 </view> 44 </view>
39 </view> 45 </view>
40 <!-- District Selection --> 46 <!-- District Selection -->
...@@ -180,6 +186,10 @@ const selectedDistrictText = ref(''); ...@@ -180,6 +186,10 @@ const selectedDistrictText = ref('');
180 const familyMotto = ref(['', '', '', '']); 186 const familyMotto = ref(['', '', '', '']);
181 const familyMottoPlaceholder = ref(['孝', '敬', '和', '睦']); 187 const familyMottoPlaceholder = ref(['孝', '敬', '和', '睦']);
182 188
189 +// 字数验证错误信息
190 +const familyNameError = ref('');
191 +const familyIntroError = ref('');
192 +
183 // 区域选择器相关 193 // 区域选择器相关
184 const showDistrictPicker = ref(false); 194 const showDistrictPicker = ref(false);
185 const districtValue = ref([]); 195 const districtValue = ref([]);
...@@ -380,21 +390,63 @@ const closePreview = () => { ...@@ -380,21 +390,63 @@ const closePreview = () => {
380 }; 390 };
381 391
382 /** 392 /**
393 + * 验证家庭名称字数
394 + */
395 +const validateFamilyName = () => {
396 + familyNameError.value = '';
397 + if (familyName.value.length > 20) {
398 + familyNameError.value = '家庭名称不能超过20个字';
399 + }
400 +};
401 +
402 +/**
403 + * 验证家庭介绍字数
404 + */
405 +const validateFamilyIntro = () => {
406 + familyIntroError.value = '';
407 + if (familyIntro.value.length > 100) {
408 + familyIntroError.value = '家庭介绍不能超过100个字';
409 + }
410 +};
411 +
412 +/**
383 * 表单验证 413 * 表单验证
384 */ 414 */
385 const validateForm = () => { 415 const validateForm = () => {
416 + // 先验证字数
417 + validateFamilyName();
418 + validateFamilyIntro();
419 +
386 if (!familyName.value.trim()) { 420 if (!familyName.value.trim()) {
387 showToast('请输入家庭名称', 'error'); 421 showToast('请输入家庭名称', 'error');
388 return false; 422 return false;
389 } 423 }
390 424
425 + if (familyName.value.length > 20) {
426 + Taro.showModal({
427 + title: '提示',
428 + content: '家庭名称不能超过20个字,请重新输入',
429 + showCancel: false
430 + });
431 + return false;
432 + }
433 +
391 if (!familyIntro.value.trim()) { 434 if (!familyIntro.value.trim()) {
392 showToast('请输入家庭介绍', 'error'); 435 showToast('请输入家庭介绍', 'error');
393 return false; 436 return false;
394 } 437 }
395 438
396 - if (!familySize.value) { 439 + if (familyIntro.value.length > 100) {
397 - showToast('请选择家庭规模', 'error'); 440 + Taro.showModal({
441 + title: '提示',
442 + content: '家庭介绍不能超过100个字,请重新输入',
443 + showCancel: false
444 + });
445 + return false;
446 + }
447 +
448 + if (!selectedDistrict.value) {
449 + showToast('请选择区域战队', 'error');
398 return false; 450 return false;
399 } 451 }
400 452
...@@ -412,6 +464,10 @@ const validateForm = () => { ...@@ -412,6 +464,10 @@ const validateForm = () => {
412 * 创建家庭 464 * 创建家庭
413 */ 465 */
414 const handleCreateFamily = () => { 466 const handleCreateFamily = () => {
467 + if (!validateForm()) {
468 + return;
469 + }
470 +
415 // 在实际应用中,这里会调用API创建家庭 471 // 在实际应用中,这里会调用API创建家庭
416 // 目前仅作为演示跳转到仪表盘页面 472 // 目前仅作为演示跳转到仪表盘页面
417 showToast('家庭创建成功', 'success'); 473 showToast('家庭创建成功', 'success');
......
...@@ -21,8 +21,11 @@ ...@@ -21,8 +21,11 @@
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="请输入家庭名称" 24 + placeholder="请输入家庭名称(最多20个字)"
25 + @blur="validateFamilyName"
26 + maxlength="20"
25 /> 27 />
28 + <view v-if="familyNameError" class="text-red-500 text-sm mt-2">{{ familyNameError }}</view>
26 </view> 29 </view>
27 </view> 30 </view>
28 <!-- Family Introduction --> 31 <!-- Family Introduction -->
...@@ -32,9 +35,12 @@ ...@@ -32,9 +35,12 @@
32 <textarea 35 <textarea
33 v-model="familyIntro" 36 v-model="familyIntro"
34 class="w-full text-gray-600 focus:outline-none resize-none" 37 class="w-full text-gray-600 focus:outline-none resize-none"
35 - placeholder="请输入您家庭的特色、成员特点等家庭标签" 38 + placeholder="请输入您家庭的特色、成员特点等家庭标签(最多100个字)"
36 :rows="2" 39 :rows="2"
40 + @blur="validateFamilyIntro"
41 + maxlength="100"
37 /> 42 />
43 + <view v-if="familyIntroError" class="text-red-500 text-sm mt-2">{{ familyIntroError }}</view>
38 </view> 44 </view>
39 </view> 45 </view>
40 <!-- District Selection --> 46 <!-- District Selection -->
...@@ -177,6 +183,10 @@ const selectedDistrictText = ref(''); ...@@ -177,6 +183,10 @@ const selectedDistrictText = ref('');
177 const familyMotto = ref(['', '', '', '']); 183 const familyMotto = ref(['', '', '', '']);
178 const familyMottoPlaceholder = ref(['孝', '敬', '和', '睦']); 184 const familyMottoPlaceholder = ref(['孝', '敬', '和', '睦']);
179 185
186 +// 字数验证错误信息
187 +const familyNameError = ref('');
188 +const familyIntroError = ref('');
189 +
180 // 区域选择器相关 190 // 区域选择器相关
181 const showDistrictPicker = ref(false); 191 const showDistrictPicker = ref(false);
182 const districtValue = ref([]); 192 const districtValue = ref([]);
...@@ -363,19 +373,61 @@ const closePreview = () => { ...@@ -363,19 +373,61 @@ const closePreview = () => {
363 }; 373 };
364 374
365 /** 375 /**
376 + * 验证家庭名称字数
377 + */
378 +const validateFamilyName = () => {
379 + familyNameError.value = '';
380 + if (familyName.value.length > 20) {
381 + familyNameError.value = '家庭名称不能超过20个字';
382 + }
383 +};
384 +
385 +/**
386 + * 验证家庭介绍字数
387 + */
388 +const validateFamilyIntro = () => {
389 + familyIntroError.value = '';
390 + if (familyIntro.value.length > 100) {
391 + familyIntroError.value = '家庭介绍不能超过100个字';
392 + }
393 +};
394 +
395 +/**
366 * 表单验证 396 * 表单验证
367 */ 397 */
368 const validateForm = () => { 398 const validateForm = () => {
399 + // 先验证字数
400 + validateFamilyName();
401 + validateFamilyIntro();
402 +
369 if (!familyName.value.trim()) { 403 if (!familyName.value.trim()) {
370 showToast('请输入家庭名称', 'error'); 404 showToast('请输入家庭名称', 'error');
371 return false; 405 return false;
372 } 406 }
373 407
408 + if (familyName.value.length > 20) {
409 + Taro.showModal({
410 + title: '提示',
411 + content: '家庭名称不能超过20个字,请重新输入',
412 + showCancel: false
413 + });
414 + return false;
415 + }
416 +
374 if (!familyIntro.value.trim()) { 417 if (!familyIntro.value.trim()) {
375 showToast('请输入家庭介绍', 'error'); 418 showToast('请输入家庭介绍', 'error');
376 return false; 419 return false;
377 } 420 }
378 421
422 + if (familyIntro.value.length > 100) {
423 + Taro.showModal({
424 + title: '提示',
425 + content: '家庭介绍不能超过100个字,请重新输入',
426 + showCancel: false
427 + });
428 + return false;
429 + }
430 +
379 if (!selectedDistrict.value) { 431 if (!selectedDistrict.value) {
380 showToast('请选择区域战队', 'error'); 432 showToast('请选择区域战队', 'error');
381 return false; 433 return false;
......