hookehuyr

✨ feat(手机号控件): 样式和功能调整

...@@ -31,6 +31,7 @@ declare module '@vue/runtime-core' { ...@@ -31,6 +31,7 @@ declare module '@vue/runtime-core' {
31 NutCheckboxGroup: typeof import('@nutui/nutui-taro')['CheckboxGroup'] 31 NutCheckboxGroup: typeof import('@nutui/nutui-taro')['CheckboxGroup']
32 NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider'] 32 NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider']
33 NutDialog: typeof import('@nutui/nutui-taro')['Dialog'] 33 NutDialog: typeof import('@nutui/nutui-taro')['Dialog']
34 + NutField: typeof import('@nutui/nutui-taro')['Field']
34 NutForm: typeof import('@nutui/nutui-taro')['Form'] 35 NutForm: typeof import('@nutui/nutui-taro')['Form']
35 NutFormItem: typeof import('@nutui/nutui-taro')['FormItem'] 36 NutFormItem: typeof import('@nutui/nutui-taro')['FormItem']
36 NutInput: typeof import('@nutui/nutui-taro')['Input'] 37 NutInput: typeof import('@nutui/nutui-taro')['Input']
......
1 <!-- 1 <!--
2 * @Date: 2022-09-02 10:46:03 2 * @Date: 2022-09-02 10:46:03
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2023-03-20 07:45:28 4 + * @LastEditTime: 2023-04-06 16:52:13
5 - * @FilePath: /data-table/src/components/PhoneField/index.vue 5 + * @FilePath: /custom_form/src/components/PhoneField/index.vue
6 * @Description: 手机输入框 6 * @Description: 手机输入框
7 --> 7 -->
8 <template> 8 <template>
9 <div v-if="HideShow" class="phone-field-page"> 9 <div v-if="HideShow" class="phone-field-page">
10 <div class="label"> 10 <div class="label">
11 - <span v-if="item.component_props.required">&nbsp;*</span> 11 + <text v-if="item.component_props.required">&nbsp;*</text>
12 {{ item.component_props.label }} 12 {{ item.component_props.label }}
13 </div> 13 </div>
14 <!-- <van-field 14 <!-- <van-field
...@@ -25,20 +25,26 @@ ...@@ -25,20 +25,26 @@
25 @touchstart.stop="openKeyboard($event)" 25 @touchstart.stop="openKeyboard($event)"
26 :border="false" 26 :border="false"
27 > --> 27 > -->
28 - <van-field 28 + <nut-input
29 :id="item.name" 29 :id="item.name"
30 - v-model="item.value" 30 + v-model="input_value"
31 - :name="item.name" 31 + :label="item.name"
32 type="digit" 32 type="digit"
33 - maxlength="11" 33 + max-length="11"
34 :placeholder="item.component_props.placeholder ? item.component_props.placeholder : '请输入手机号码'" 34 :placeholder="item.component_props.placeholder ? item.component_props.placeholder : '请输入手机号码'"
35 - :rules="rules"
36 - :required="item.component_props.required"
37 :disabled="item.component_props.readonly" 35 :disabled="item.component_props.readonly"
38 :border="false" 36 :border="false"
37 + @blur="onBlur"
38 + style="border: 1px solid #eaeaea; border-radius: 0.25rem; padding: 0.25rem 0.5rem;"
39 > 39 >
40 - </van-field> 40 + </nut-input>
41 - <van-field 41 + <div
42 + v-if="show_error"
43 + style="padding-left: 20px; color: red; font-size: 12px;"
44 + >
45 + {{ error_msg }}
46 + </div>
47 + <!-- <van-field
42 v-if="is_sms" 48 v-if="is_sms"
43 name="ignore" 49 name="ignore"
44 v-model="sms" 50 v-model="sms"
...@@ -58,46 +64,65 @@ ...@@ -58,46 +64,65 @@
58 :maxlength="11" 64 :maxlength="11"
59 @blur="blurKeyboard()" 65 @blur="blurKeyboard()"
60 safe-area-inset-bottom 66 safe-area-inset-bottom
61 - /> 67 + /> -->
62 </div> 68 </div>
63 </template> 69 </template>
64 70
65 <script setup> 71 <script setup>
66 import { wxInfo } from "@/utils/tools"; 72 import { wxInfo } from "@/utils/tools";
67 -import $ from "jquery"; 73 +import Taro, { useLoad } from '@tarojs/taro'
68 -import { storeToRefs, mainStore } from "@/utils/generatePackage"; 74 +import { ref, computed, watch, onMounted, nextTick } from "vue";
75 +import { $ } from '@tarojs/extend';
76 +import { storeToRefs } from "pinia";
77 +import { mainStore } from '@/stores'
69 78
70 const props = defineProps({ 79 const props = defineProps({
71 item: Object, 80 item: Object,
72 }); 81 });
82 +const emit = defineEmits(["active"]);
83 +
73 // 隐藏显示 84 // 隐藏显示
74 const HideShow = computed(() => { 85 const HideShow = computed(() => {
75 return !props.item.component_props.disabled 86 return !props.item.component_props.disabled
76 }) 87 })
88 +
77 // web端判断 89 // web端判断
78 const readonly = computed(() => wxInfo().isMobile); 90 const readonly = computed(() => wxInfo().isMobile);
79 // 打开短信验证模式 91 // 打开短信验证模式
80 const is_sms = ref(false); 92 const is_sms = ref(false);
81 93
82 -// 校验函数返回 true 表示校验通过,false 表示不通过 94 +const input_value = ref('');
83 -const validator = (val) => { 95 +
84 - if (props.item.component_props.required && !val) { 96 +const show_error = ref(false);
85 - return false; 97 +const error_msg = ref('');
86 - } else if (val && !/1\d{10}/.test(val)) { 98 +
87 - return false;
88 - } else {
89 - return true;
90 - }
91 -};
92 // 错误提示文案 99 // 错误提示文案
93 -const validatorMessage = (val, rule) => { 100 +const validPhone = () => {
94 - if (props.item.component_props.required && !val) { 101 + if (props.item.component_props.required && !input_value.value) {
95 - return "手机号码不能为空"; 102 + show_error.value = true;
96 - } else if (val && !/1\d{10}/.test(val)) { 103 + error_msg.value = '必填项不能为空';
97 - return "请输入正确手机号码"; 104 + } else if (input_value.value && !/1\d{10}/.test(input_value.value)) {
105 + show_error.value = true;
106 + error_msg.value = '请输入正确手机号码';
107 + } else {
108 + show_error.value = false;
109 + error_msg.value = '';
98 } 110 }
111 + return !show_error.value;
99 }; 112 };
100 -const rules = [{ validator, message: validatorMessage }]; 113 +
114 +defineExpose({ validPhone, id: props.item.key });
115 +
116 +const onBlur = () => {
117 + // 发送自定义回调
118 + props.item.value = {
119 + key: "phone",
120 + filed_name: props.item.key,
121 + value: input_value.value,
122 + };
123 + emit("active", props.item.value);
124 + validPhone()
125 +}
101 126
102 const show = ref(false); 127 const show = ref(false);
103 let content = ""; 128 let content = "";
...@@ -106,67 +131,71 @@ const store = mainStore(); ...@@ -106,67 +131,71 @@ const store = mainStore();
106 const { fieldName } = storeToRefs(store); 131 const { fieldName } = storeToRefs(store);
107 132
108 // 监听字段变化 133 // 监听字段变化
109 -watch( 134 +// watch(
110 - () => fieldName.value, 135 +// () => fieldName.value,
111 - (v) => { 136 +// (v) => {
112 - // 如果不是点击本输入框 137 +// // 如果不是点击本输入框
113 - if (v !== props.item.name) { 138 +// if (v !== props.item.name) {
114 - // 还原border颜色 139 +// // 还原border颜色
115 - $(`#${props.item.name}`).parent().css("border-color", "#eaeaea"); 140 +// $(`#${props.item.name}`).parent().css("border-color", "#eaeaea");
116 - show.value = false; 141 +// show.value = false;
117 - document.getElementById("app").style.paddingBottom = "0"; 142 +// document.getElementById("app").style.paddingBottom = "0";
118 - } 143 +// }
119 - } 144 +// }
120 -); 145 +// );
121 - 146 +
122 -const openKeyboard = (e) => { 147 +// const openKeyboard = (e) => {
123 - if (props.item.component_props.readonly) return false; // 如果为只读,不能设置 148 +// if (props.item.component_props.readonly) return false; // 如果为只读,不能设置
124 - // 键盘上移动 149 +// // 键盘上移动
125 - const target_to_view_height = 150 +// const target_to_view_height =
126 - window.innerHeight - e.target.getBoundingClientRect().bottom; // 元素到适口高度 151 +// window.innerHeight - e.target.getBoundingClientRect().bottom; // 元素到适口高度
127 - const target_top = document.body.scrollHeight - $(e.target).offset().top; // 元素到正文高度 152 +// const target_top = document.body.scrollHeight - $(e.target).offset().top; // 元素到正文高度
128 - let scroll_height = ""; 153 +// let scroll_height = "";
129 - if (target_to_view_height <= 250) { 154 +// if (target_to_view_height <= 250) {
130 - document.getElementById("app").style.paddingBottom = "250px"; 155 +// document.getElementById("app").style.paddingBottom = "250px";
131 - // 向上滚动位置 156 +// // 向上滚动位置
132 - document.documentElement.scrollTop = $(e.target).offset().top - 244; 157 +// document.documentElement.scrollTop = $(e.target).offset().top - 244;
133 - } 158 +// }
134 - // 选中添加border颜色 159 +// // 选中添加border颜色
135 - content = $(e.target).parent(); 160 +// content = $(e.target).parent();
136 - // TAG: 自定义主题颜色 161 +// // TAG: 自定义主题颜色
137 - content.css("border-color", "#c2915f"); 162 +// content.css("border-color", "#c2915f");
138 - setTimeout(() => { 163 +// setTimeout(() => {
139 - show.value = true; 164 +// show.value = true;
140 - }, 300); 165 +// }, 300);
141 - // 记录点击field名 166 +// // 记录点击field名
142 - store.changeFieldName(props.item.name); 167 +// store.changeFieldName(props.item.name);
143 -}; 168 +// };
144 -const blurKeyboard = () => { 169 +// const blurKeyboard = () => {
145 - show.value = false; 170 +// show.value = false;
146 - document.getElementById("app").style.paddingBottom = "0"; 171 +// document.getElementById("app").style.paddingBottom = "0";
147 - // 还原border颜色 172 +// // 还原border颜色
148 - content.css("border-color", "#eaeaea"); 173 +// content.css("border-color", "#eaeaea");
149 -}; 174 +// };
150 </script> 175 </script>
151 176
152 -<style lang="less" scoped> 177 +<style lang="less">
153 .phone-field-page { 178 .phone-field-page {
154 .label { 179 .label {
155 - padding: 1rem 1rem 0 1rem; 180 + padding: 30px 30px 0 30px;
156 - font-size: 0.9rem; 181 + font-size: 26px;
157 font-weight: bold; 182 font-weight: bold;
158 - span { 183 + text {
159 color: red; 184 color: red;
160 } 185 }
161 } 186 }
162 187
163 - :deep(.van-field__body) { 188 + .nut-input {
164 - border: 1px solid #eaeaea; 189 + padding: 20px 25px;
165 - border-radius: 0.25rem;
166 - padding: 0.25rem 0.5rem;
167 - input {
168 - color: #323233;
169 - }
170 } 190 }
191 +
192 + // :deep(.van-field__body) {
193 + // border: 1px solid #eaeaea;
194 + // border-radius: 0.25rem;
195 + // padding: 0.25rem 0.5rem;
196 + // input {
197 + // color: #323233;
198 + // }
199 + // }
171 } 200 }
172 </style> 201 </style>
......
...@@ -10,7 +10,7 @@ import PickerField from '@/components/PickerField/index.vue' ...@@ -10,7 +10,7 @@ import PickerField from '@/components/PickerField/index.vue'
10 // import DateTimePickerField from '@/components/DateTimePickerField/index.vue' 10 // import DateTimePickerField from '@/components/DateTimePickerField/index.vue'
11 // import ImageUploaderField from '@/components/ImageUploaderField/index.vue' 11 // import ImageUploaderField from '@/components/ImageUploaderField/index.vue'
12 // import FileUploaderField from '@/components/FileUploaderField/index.vue' 12 // import FileUploaderField from '@/components/FileUploaderField/index.vue'
13 -// import PhoneField from '@/components/PhoneField/index.vue' 13 +import PhoneField from '@/components/PhoneField/index.vue'
14 // import EmailField from '@/components/EmailField/index.vue' 14 // import EmailField from '@/components/EmailField/index.vue'
15 // import SignField from '@/components/SignField/index.vue' 15 // import SignField from '@/components/SignField/index.vue'
16 // import RatePickerField from '@/components/RatePickerField/index.vue' 16 // import RatePickerField from '@/components/RatePickerField/index.vue'
...@@ -111,10 +111,10 @@ export function createComponentType(data) { ...@@ -111,10 +111,10 @@ export function createComponentType(data) {
111 // if (item.component_props.tag === 'file_uploader') { 111 // if (item.component_props.tag === 'file_uploader') {
112 // item.component = FileUploaderField 112 // item.component = FileUploaderField
113 // } 113 // }
114 - // if (item.component_props.tag === 'phone') { 114 + if (item.component_props.tag === 'phone') {
115 - // item.name = item.key 115 + item.name = item.key
116 - // item.component = PhoneField 116 + item.component = PhoneField
117 - // } 117 + }
118 // if (item.component_props.tag === 'email') { 118 // if (item.component_props.tag === 'email') {
119 // item.name = item.key 119 // item.name = item.key
120 // item.component = EmailField 120 // item.component = EmailField
......
1 <!-- 1 <!--
2 * @Date: 2023-03-24 09:19:27 2 * @Date: 2023-03-24 09:19:27
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2023-04-06 14:35:26 4 + * @LastEditTime: 2023-04-06 16:38:28
5 * @FilePath: /custom_form/src/pages/table/index.vue 5 * @FilePath: /custom_form/src/pages/table/index.vue
6 * @Description: 文件描述 6 * @Description: 文件描述
7 --> 7 -->
...@@ -133,6 +133,7 @@ const checkbox = ref([]); ...@@ -133,6 +133,7 @@ const checkbox = ref([]);
133 const multi_rule = ref([]); 133 const multi_rule = ref([]);
134 const picker = ref([]); 134 const picker = ref([]);
135 const number = ref([]); 135 const number = ref([]);
136 +const phone = ref([]);
136 const area_picker = ref([]); 137 const area_picker = ref([]);
137 const image_uploader = ref([]); 138 const image_uploader = ref([]);
138 const file_uploader = ref([]); 139 const file_uploader = ref([]);
...@@ -162,6 +163,9 @@ const setRefMap = (el, item) => { ...@@ -162,6 +163,9 @@ const setRefMap = (el, item) => {
162 if (item.component_props.tag === "number") { 163 if (item.component_props.tag === "number") {
163 number.value.push(el); 164 number.value.push(el);
164 } 165 }
166 + if (item.component_props.tag === "phone") {
167 + phone.value.push(el);
168 + }
165 if (item.component_props.tag === "area_picker") { 169 if (item.component_props.tag === "area_picker") {
166 area_picker.value.push(el); 170 area_picker.value.push(el);
167 } 171 }
...@@ -424,6 +428,9 @@ const onActive = (item) => { ...@@ -424,6 +428,9 @@ const onActive = (item) => {
424 if (item.key === "number") { 428 if (item.key === "number") {
425 postData.value[item.filed_name] = item.value; 429 postData.value[item.filed_name] = item.value;
426 } 430 }
431 + if (item.key === "phone") {
432 + postData.value[item.filed_name] = item.value;
433 + }
427 if (item.key === "image_uploader") { 434 if (item.key === "image_uploader") {
428 postData.value[item.filed_name] = item.value; 435 postData.value[item.filed_name] = item.value;
429 } 436 }
...@@ -541,6 +548,19 @@ const validOther = () => { ...@@ -541,6 +548,19 @@ const validOther = () => {
541 } 548 }
542 }); 549 });
543 } 550 }
551 + if (phone.value) {
552 + // 手机号
553 + phone.value.forEach((item, index) => {
554 + if (!phone.value[index].validPhone()) {
555 + valid = {
556 + status: phone.value[index].validPhone(),
557 + key: "phone",
558 + id: phone.value[index]?.id
559 + };
560 + return false;
561 + }
562 + });
563 + }
544 if (area_picker.value) { 564 if (area_picker.value) {
545 // 省市区地址 565 // 省市区地址
546 area_picker.value.forEach((item, index) => { 566 area_picker.value.forEach((item, index) => {
......