index.vue
5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<template>
<view class="min-h-screen flex flex-col bg-white">
<!-- <AppHeader title="加入家庭" /> -->
<view class="flex-1 px-4 pt-3 pb-6 flex flex-col">
<!-- Title -->
<h2 class="text-xl font-bold text-center mb-2">
输入家训口令
</h2>
<!-- Description -->
<view class="text-gray-600 text-center text-sm mb-6">
请输入家人提供的家训口令,加入家庭一起参与健康挑战
</view>
<!-- Input boxes -->
<view class="flex justify-center gap-3 w-full mb-6">
<view
v-for="(char, index) in mottoChars"
:key="index"
class="w-16 h-16 border border-gray-300 rounded-md flex items-center justify-center"
:style="{
borderColor: focusedIndex === index ? '#3b82f6' : '#d1d5db'
}"
>
<input
:ref="(el) => (inputRefs[index] = el)"
type="text"
v-model="mottoChars[index]"
@input="(e) => handleInputChange(index, e.target.value)"
@keydown="(e) => handleKeyDown(index, e)"
@focus="focusedIndex = index"
@blur="handleBlur(index)"
class="w-full h-full text-center text-xl bg-transparent outline-none"
style="border: none;"
/>
</view>
</view>
<!-- Help text -->
<view class="text-gray-500 text-center text-sm mb-8">
没有口令?请联系您的大家长获取
</view>
<!-- Role selection -->
<view class="mb-6">
<h3 class="text-base font-medium mb-4 border-t border-gray-300 pt-4">
选择您的身份
</h3>
<view class="grid grid-cols-2 gap-3">
<view
v-for="role in familyRoles"
:key="role.id"
:class="[
'flex items-center justify-center p-3 border rounded-md',
selectedRole === role.id
? 'border-blue-500 bg-blue-50'
: 'border-gray-200'
]"
@click="selectedRole = role.id"
>
<view class="flex flex-col items-center">
<My
size="20"
:class="[
'mb-1',
selectedRole === role.id ? 'text-blue-500' : 'text-gray-400'
]"
/>
<span
:class="[
selectedRole === role.id ? 'text-blue-500' : 'text-gray-600'
]"
>
{{ role.label }}
</span>
</view>
</view>
</view>
</view>
<!-- Submit Button -->
<view
@click="handleJoinFamily"
:disabled="!isComplete"
:class="[
'w-full py-4 text-white text-lg font-medium rounded-lg mt-auto text-center',
isComplete ? 'bg-blue-500' : 'bg-gray-300'
]"
>
加入家庭
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import Taro from '@tarojs/taro';
import { My } from '@nutui/icons-vue-taro';
import AppHeader from '../../components/AppHeader.vue';
const mottoChars = ref(['', '', '', '']);
const selectedRole = ref('');
const inputRefs = ref([]);
const focusedIndex = ref(-1);
const handleInputChange = (index, value) => {
// 允许输入多个字符,但只保留第一个有效字符(汉字、数字、大小写字母),兼容输入法
if (value) {
// 提取第一个有效字符(汉字、数字、大小写字母)
const firstChar = value.match(/[\u4e00-\u9fa5a-zA-Z0-9]/)?.[0] || '';
mottoChars.value[index] = firstChar;
// 如果输入了有效字符且不是最后一个输入框,自动聚焦下一个
if (firstChar && index < 3) {
// Taro中无法直接操作DOM进行focus,这里仅保留逻辑
// 在小程序中,可以通过设置 `focus` 属性来控制
}
} else {
mottoChars.value[index] = '';
}
};
const handleKeyDown = (index, e) => {
if (e.key === 'Backspace' && !mottoChars.value[index] && index > 0) {
// 同样,在Taro中处理光标移动需要不同的方式
}
};
/**
* 处理输入框失焦事件
* @param {number} index - 输入框索引
*/
const handleBlur = (index) => {
// 重置焦点状态
focusedIndex.value = -1;
// 失焦时再次验证输入值,确保只保留有效字符(汉字、数字、大小写字母)
const currentValue = mottoChars.value[index];
if (currentValue) {
const firstChar = currentValue.match(/[\u4e00-\u9fa5a-zA-Z0-9]/)?.[0] || '';
mottoChars.value[index] = firstChar;
}
};
const familyRoles = [
{ id: 'husband', label: '丈夫' },
{ id: 'wife', label: '妻子' },
{ id: 'son', label: '儿子' },
{ id: 'daughter-in-law', label: '儿媳' },
{ id: 'son-in-law', label: '女婿' },
{ id: 'daughter', label: '女儿' },
{ id: 'grandson', label: '孙子' },
{ id: 'maternal-grandson', label: '外孙' },
{ id: 'granddaughter', label: '孙女' },
{ id: 'maternal-granddaughter', label: '外孙女' }
];
const isComplete = computed(() => {
return mottoChars.value.every((char) => char) && selectedRole.value;
});
const handleJoinFamily = () => {
if (isComplete.value) {
Taro.navigateTo({
url: '/pages/Dashboard/index'
});
}
};
</script>