@neatui/nuxt 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +3 -0
  2. package/package.json +43 -0
  3. package/rollup.config.js +35 -0
  4. package/src/components/basic/IDraggable.vue +84 -0
  5. package/src/components/basic/IDraggable@b.vue +80 -0
  6. package/src/components/basic/IFollowView.vue +211 -0
  7. package/src/components/basic/IPickerView.vue +351 -0
  8. package/src/components/basic/IRouterView.vue +360 -0
  9. package/src/components/basic/IScrollView.vue +127 -0
  10. package/src/components/basic/Icon.vue +54 -0
  11. package/src/components/basic/LayerView/Layer.vue +339 -0
  12. package/src/components/basic/LayerView/index.ts +5 -0
  13. package/src/components/basic/index.ts +7 -0
  14. package/src/components/display/Avatar.vue +1 -0
  15. package/src/components/display/Badge.vue +1 -0
  16. package/src/components/display/Calendar.vue +245 -0
  17. package/src/components/display/CalendarReg.vue +245 -0
  18. package/src/components/display/Card.vue +1 -0
  19. package/src/components/display/Carousel.vue +1 -0
  20. package/src/components/display/ChartView.vue +123 -0
  21. package/src/components/display/Collapse.vue +1 -0
  22. package/src/components/display/Desriptions.vue +1 -0
  23. package/src/components/display/Empty.vue +1 -0
  24. package/src/components/display/Image.vue +112 -0
  25. package/src/components/display/List.vue +1 -0
  26. package/src/components/display/PhotoEditor.vue +181 -0
  27. package/src/components/display/PhotoViewer.vue +50 -0
  28. package/src/components/display/Popover.vue +1 -0
  29. package/src/components/display/QRCode.vue +1 -0
  30. package/src/components/display/Segmented.vue +1 -0
  31. package/src/components/display/Statistic.vue +1 -0
  32. package/src/components/display/Table.vue +1 -0
  33. package/src/components/display/Tabs.vue +1 -0
  34. package/src/components/display/Tag.vue +1 -0
  35. package/src/components/display/Timeline.vue +1 -0
  36. package/src/components/display/Tooltip.vue +1 -0
  37. package/src/components/display/Tour.vue +1 -0
  38. package/src/components/display/Tree.vue +431 -0
  39. package/src/components/display/TreeView.vue +225 -0
  40. package/src/components/display/index.ts +8 -0
  41. package/src/components/form/Cascader.vue +435 -0
  42. package/src/components/form/DatePicker.vue +124 -0
  43. package/src/components/form/DateRangePicker@v2.vue.backup +224 -0
  44. package/src/components/form/DateRangePicker@v3.vue +116 -0
  45. package/src/components/form/DateRangeView@v3.vue +386 -0
  46. package/src/components/form/DateView.vue +229 -0
  47. package/src/components/form/DateView@v2.vue +386 -0
  48. package/src/components/form/DateView@v3.vue +471 -0
  49. package/src/components/form/EditUpload.vue +4 -0
  50. package/src/components/form/ImgUpload.vue +174 -0
  51. package/src/components/form/Input.vue.backup +230 -0
  52. package/src/components/form/Input@v3.vue +267 -0
  53. package/src/components/form/InputNumber.vue +200 -0
  54. package/src/components/form/InputRange.vue +235 -0
  55. package/src/components/form/MoreSelect.vue.backup +144 -0
  56. package/src/components/form/MoreSelect@v3.vue +195 -0
  57. package/src/components/form/MoreSelectList.vue +125 -0
  58. package/src/components/form/MoreSelectPanel@v3.vue +190 -0
  59. package/src/components/form/MoreSelectPicker.vue +124 -0
  60. package/src/components/form/MoreSelectTags.vue +124 -0
  61. package/src/components/form/PageMoreSelect.vue +187 -0
  62. package/src/components/form/PageSelect.vue +189 -0
  63. package/src/components/form/SearchMoreSelect.vue +173 -0
  64. package/src/components/form/SearchSelect.vue.backup +194 -0
  65. package/src/components/form/SearchSelect@v3.vue +202 -0
  66. package/src/components/form/Select@v3.vue +201 -0
  67. package/src/components/form/SelectList.vue +58 -0
  68. package/src/components/form/SelectPicker.vue +97 -0
  69. package/src/components/form/SelectTags.vue +52 -0
  70. package/src/components/form/SelectTree/SelectTree@v1.vue +227 -0
  71. package/src/components/form/Switch.vue +135 -0
  72. package/src/components/form/TextArea.vue +193 -0
  73. package/src/components/form/TimePicker.vue +11 -0
  74. package/src/components/form/TimeView.vue +244 -0
  75. package/src/components/form/Upload.vue +346 -0
  76. package/src/components/form/index.ts +82 -0
  77. package/src/components/loader/FormLoader/FormLoader@v2.vue +422 -0
  78. package/src/components/loader/FormLoader/FormLoader@v3.vue.backup +318 -0
  79. package/src/components/loader/FormLoader/index.ts +2 -0
  80. package/src/components/loader/FormLoader@v1/FormLoader.vue +506 -0
  81. package/src/components/loader/FormLoader@v1/FormRender.vue +277 -0
  82. package/src/components/loader/LimitLoader/LimitLoader.vue.backup +131 -0
  83. package/src/components/loader/LimitLoader/LimitLoader@v2.vue.backup +174 -0
  84. package/src/components/loader/LimitLoader/LimitLoader@v3.vue +183 -0
  85. package/src/components/loader/LimitLoader/index.ts +2 -0
  86. package/src/components/loader/TableLoader/TableColView.vue +115 -0
  87. package/src/components/loader/TableLoader/TableLoader.vue +360 -0
  88. package/src/components/loader/TableLoader/index.ts +2 -0
  89. package/src/components/loader/ViewLoader/ViewLoader@v1.vue +256 -0
  90. package/src/components/loader/ViewLoader/index.ts +2 -0
  91. package/src/components/loader/index.ts +5 -0
  92. package/src/components/tools/FormDraftsView.vue +330 -0
  93. package/src/components/tools/FormVerifyView.vue +206 -0
  94. package/src/components/tools/MoreTools.vue +74 -0
  95. package/src/components/tools/MoreTools@v2.vue +74 -0
  96. package/src/components/tools/Pagination@a.vue +222 -0
  97. package/src/components/tools/Pagination@b.vue +221 -0
  98. package/src/components/tools/index.ts +5 -0
  99. package/src/index.ts +9 -0
  100. package/src/shims-vue.d.ts +5 -0
  101. package/src/store/myui.ts +50 -0
  102. package/tsconfig.json +24 -0
@@ -0,0 +1,230 @@
1
+ <template>
2
+ <div
3
+ :ui-form="`${theme} sz:${sz} ${state.error.co} type:input ${block ? ' :block' : ''} ${disabled ? 'disabled' : ''} ${readonly ? 'readonly' : ''}`"
4
+ @click="emits('click', $event)"
5
+ >
6
+ <div :ui-form-tips="state.error.ontips">{{ state.error.tips }}</div>
7
+ <div ui-form-prefix="">
8
+ <template v-for="(item, idx) in prefix" :key="idx">
9
+ <div v-html="isObject(item) ? item.html : item"></div>
10
+ </template>
11
+ <slot name="prefix"></slot>
12
+ </div>
13
+ <slot>
14
+ <input
15
+ v-model="state.value"
16
+ :type="type"
17
+ :placeholder="placeholder"
18
+ :readonly="readonly || disabled"
19
+ autocomplete="new-password"
20
+ @focus="emits('focus', $event, state)"
21
+ @input="input($event)"
22
+ @change="emits('change', $event, state)"
23
+ @blur="blur($event)"
24
+ />
25
+ </slot>
26
+ <div ui-form-suffix="">
27
+ <i ui-form-clean="" v-if="clearable && state.value && !readonly && !disabled" @click.stop="clear"></i>
28
+ <slot name="suffix"></slot>
29
+ <template v-for="(item, idx) in suffix" :key="idx">
30
+ <div v-html="isObject(item) ? item.html : item"></div>
31
+ </template>
32
+ </div>
33
+ <i v-if="ready && verify" :ui-form-verify="verify"></i>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup lang="ts">
38
+ import { reactive, watch } from 'vue';
39
+ import { isObject } from '@fekit/utils';
40
+
41
+ const emits = defineEmits(['update:modelValue', 'click', 'blur', 'focus', 'change', 'input', 'clear']);
42
+
43
+ /**
44
+ * 入参说明
45
+ *
46
+ * modelValue 值
47
+ * theme 主题
48
+ * sz 尺寸
49
+ * co 颜色
50
+ * block 撑满
51
+ * ready 准备就绪
52
+ * type 类型
53
+ * tips 提示文案
54
+ * placeholder 内容占位
55
+ * maxlength 最大长度
56
+ * minlength 最小长度
57
+ * disabled 是否禁用
58
+ * readonly 是否只读
59
+ * clearable 是否显示清除按钮
60
+ * rules 校验规则
61
+ * verify 是否是示校验图标
62
+ * prefix 前缀内容
63
+ * suffix 后缀内容
64
+ * interacted 用户是否交互
65
+ */
66
+
67
+ // 类型
68
+ interface Props {
69
+ modelValue?: string | number;
70
+ placeholder?: string;
71
+ rules?: Array<object>;
72
+ theme?: string;
73
+ sz?: '' | 'xs' | 's' | 'm' | 'l' | 'xl';
74
+ co?: string;
75
+ block?: boolean;
76
+ ready?: boolean;
77
+ type?: string;
78
+ tips?: string;
79
+ maxlength?: null | number;
80
+ minlength?: null | number;
81
+ disabled?: boolean;
82
+ readonly?: boolean;
83
+ clearable?: boolean;
84
+ verify?: boolean;
85
+ prefix?: Array<any>;
86
+ suffix?: Array<any>;
87
+ interacted?: boolean;
88
+ }
89
+ const props: any = withDefaults(defineProps<Props>(), {
90
+ modelValue: '',
91
+ placeholder: '',
92
+ rules: () => [],
93
+ theme: '@a',
94
+ sz: '',
95
+ co: '',
96
+ block: true,
97
+ ready: false,
98
+ type: 'text',
99
+ tips: '',
100
+ maxlength: null,
101
+ minlength: null,
102
+ disabled: false,
103
+ readonly: false,
104
+ clearable: true,
105
+ verify: false,
106
+ prefix: () => [],
107
+ suffix: () => [],
108
+ interacted: false
109
+ });
110
+
111
+ const state: any = reactive({
112
+ // 用户是否交互
113
+ interacted: false,
114
+ // 值
115
+ value: props.modelValue,
116
+ // 错误
117
+ error: {}
118
+ });
119
+ // 外部传入交互标识,主要用于外部没有输入但点击了提交
120
+ watch(
121
+ () => props.interacted,
122
+ (interacted: any) => {
123
+ if (interacted) {
124
+ state.interacted = interacted;
125
+ }
126
+ },
127
+ { deep: true, immediate: true }
128
+ );
129
+
130
+ // 监听异步数据
131
+ watch(
132
+ () => props.modelValue,
133
+ (value: any) => {
134
+ if (state.value !== value) {
135
+ state.value = value;
136
+ }
137
+ },
138
+ { deep: true, immediate: true }
139
+ );
140
+ watch(
141
+ () => state.value,
142
+ (value: any) => {
143
+ emits('update:modelValue', value);
144
+ },
145
+ { deep: true, immediate: true }
146
+ );
147
+
148
+ // 校验
149
+ watch(
150
+ [() => state.interacted, () => state.value],
151
+ async () => {
152
+ if (state.interacted) {
153
+ // 提示文案
154
+ let tips = '';
155
+ // 错误类型
156
+ let type = '';
157
+ // 验证结果
158
+ let verify = '';
159
+
160
+ if (props.modelValue) {
161
+ // 有值
162
+ let hasError = false;
163
+ // 遍历校验规则
164
+ for (const rule of props.rules) {
165
+ if (rule && rule.validator) {
166
+ const yes = !(await rule.validator(props.modelValue));
167
+ if (yes) {
168
+ tips = rule.msg;
169
+ type = rule.type;
170
+ hasError = true;
171
+ break;
172
+ }
173
+ }
174
+ }
175
+ verify = hasError ? 'no' : 'ok';
176
+ } else {
177
+ // 无值
178
+ let hasError = false;
179
+ // 遍历校验规则
180
+ for (const rule of props.rules) {
181
+ if (rule) {
182
+ tips = rule.msg;
183
+ type = rule.type;
184
+ if (rule.required) {
185
+ hasError = true;
186
+ break;
187
+ }
188
+ }
189
+ }
190
+ verify = hasError ? 'no' : '';
191
+ }
192
+ if (verify !== 'no' && props.tips) {
193
+ tips = props.tips;
194
+ }
195
+ // 是否显示提示
196
+ const ontips = (verify === 'no' && tips) || props.tips ? 'show' : '';
197
+ // 状态颜色
198
+ const co = verify === 'no' ? 'co:' + type : props.co ? 'co:' + props.co : '';
199
+ state.error = { tips, ontips, verify, co };
200
+ } else {
201
+ state.error = { tips: props.tips, ontips: props.tips ? 'show' : '', verify: '', co: '' };
202
+ }
203
+ },
204
+ { deep: true, immediate: true }
205
+ );
206
+
207
+ // 清空
208
+ function clear() {
209
+ emits('update:modelValue', '');
210
+ emits('clear');
211
+ }
212
+ // 输入
213
+ const input = (e: any) => {
214
+ if (!state.interacted) {
215
+ setTimeout(() => {
216
+ state.interacted = true;
217
+ }, 50);
218
+ }
219
+ emits('input', e, state);
220
+ };
221
+ // 失焦
222
+ const blur = (e: any) => {
223
+ if (!state.interacted) {
224
+ setTimeout(() => {
225
+ state.interacted = true;
226
+ }, 50);
227
+ }
228
+ emits('blur', e, state);
229
+ };
230
+ </script>
@@ -0,0 +1,267 @@
1
+ <template>
2
+ <div
3
+ :ui-form="`${theme} sz:${sz} ${state.error.co} type:input ${block ? ' :block' : ''} ${disabled ? 'disabled' : ''} ${readonly ? 'readonly' : ''}`"
4
+ @click="emits('click', $event)"
5
+ >
6
+ <div :ui-form-tips="state.error.ontips">{{ state.error.tips }}</div>
7
+ <div ui-form-prefix="">
8
+ <template v-for="(item, idx) in prefix" :key="idx">
9
+ <div v-if="isObject(item)" v-bind="item.attrs" v-on="event(item, props.modelValue)">
10
+ <div v-html="isFunction(item.value) ? item.value(props.modelValue) : item.value"></div>
11
+ </div>
12
+ <div v-else v-html="isFunction(item) ? item(props.modelValue) : item"></div>
13
+ </template>
14
+ <slot name="prefix"></slot>
15
+ </div>
16
+ <slot>
17
+ <input
18
+ :title="props.modelValue"
19
+ :value="props.modelValue"
20
+ :type="type"
21
+ :placeholder="placeholder"
22
+ :disabled="disabled"
23
+ :readonly="readonly"
24
+ autocomplete="new-password"
25
+ @focus="emits('focus', $event, state)"
26
+ @input="input($event)"
27
+ @change="emits('change', $event, state)"
28
+ @blur="blur($event)"
29
+ />
30
+ </slot>
31
+ <div ui-form-suffix="">
32
+ <i ui-form-clean="" v-if="clearable && props.modelValue && !readonly && !disabled" @click.stop="clear"></i>
33
+ <slot name="suffix"></slot>
34
+ <template v-for="(item, idx) in suffix" :key="idx">
35
+ <div v-if="isObject(item)" v-bind="item.attrs" v-on="event(item, props.modelValue)">
36
+ <div v-html="isFunction(item.value) ? item.value(props.modelValue) : item.value"></div>
37
+ </div>
38
+ <div v-else v-html="isFunction(item) ? item(props.modelValue) : item"></div>
39
+ </template>
40
+ </div>
41
+ <i v-if="verify && state.interacted" :ui-form-verify="state.error.verify"></i>
42
+ </div>
43
+ </template>
44
+
45
+ <script setup lang="ts">
46
+ import { reactive, watch } from 'vue';
47
+ import { isObject, isFunction } from '@fekit/utils';
48
+
49
+ const emits = defineEmits(['update:modelValue', 'click', 'blur', 'focus', 'change', 'input', 'clear']);
50
+
51
+ /**
52
+ * 入参说明
53
+ *
54
+ * modelValue 值
55
+ * theme 主题
56
+ * sz 尺寸
57
+ * co 颜色
58
+ * block 撑满
59
+ * ready 准备就绪
60
+ * type 类型
61
+ * tips 提示文案
62
+ * placeholder 内容占位
63
+ * maxlength 最大长度
64
+ * minlength 最小长度
65
+ * disabled 是否禁用
66
+ * readonly 是否只读
67
+ * clearable 是否显示清除按钮
68
+ * rules 校验规则
69
+ * verify 是否是示校验图标 2=tips 3=text 4=icon 5=tips+text 6=text+icon 7=text+icon
70
+ * prefix 前缀内容
71
+ * suffix 后缀内容
72
+ * interacted 用户是否交互
73
+ */
74
+
75
+ // 类型
76
+ interface Props {
77
+ modelValue?: string | number;
78
+ placeholder?: string;
79
+ rules?: Array<object>;
80
+ theme?: string;
81
+ sz?: '' | 'xs' | 's' | 'm' | 'l' | 'xl';
82
+ co?: string;
83
+ block?: boolean;
84
+ ready?: boolean;
85
+ type?: string;
86
+ tips?: string;
87
+ maxlength?: null | number;
88
+ minlength?: null | number;
89
+ disabled?: boolean;
90
+ readonly?: boolean;
91
+ clearable?: boolean;
92
+ verify?: boolean;
93
+ prefix?: Array<any>;
94
+ suffix?: Array<any>;
95
+ interacted?: boolean;
96
+ }
97
+ const props: any = withDefaults(defineProps<Props>(), {
98
+ modelValue: '',
99
+ placeholder: '',
100
+ rules: () => [],
101
+ theme: '@a',
102
+ sz: '',
103
+ co: '',
104
+ block: true,
105
+ ready: false,
106
+ type: 'text',
107
+ tips: '',
108
+ maxlength: null,
109
+ minlength: null,
110
+ disabled: false,
111
+ readonly: false,
112
+ clearable: true,
113
+ verify: false,
114
+ prefix: () => [],
115
+ suffix: () => [],
116
+ interacted: false
117
+ });
118
+
119
+ const state: any = reactive({
120
+ // 用户是否交互
121
+ interacted: false,
122
+ // 值
123
+ value: props.modelValue,
124
+ // 错误
125
+ error: {}
126
+ });
127
+ // 外部传入交互标识,主要用于外部没有输入但点击了提交
128
+ watch(
129
+ () => props.interacted,
130
+ (interacted: any) => {
131
+ if (interacted) {
132
+ state.interacted = interacted;
133
+ }
134
+ },
135
+ { deep: true, immediate: true }
136
+ );
137
+
138
+ // 监听外部数据
139
+ // watch(
140
+ // () => props.modelValue,
141
+ // (value: any) => {
142
+ // state.value = value;
143
+ // },
144
+ // { deep: true, immediate: true }
145
+ // );
146
+ // watch(
147
+ // () => state.value,
148
+ // (value: any) => {
149
+ // emits('update:modelValue', value);
150
+ // },
151
+ // { deep: true, immediate: true }
152
+ // );
153
+
154
+ // 校验
155
+ watch(
156
+ [() => state.interacted, () => props.modelValue],
157
+ async () => {
158
+ if (state.interacted) {
159
+ // 提示文案
160
+ let tips = '';
161
+ // 错误类型
162
+ let type = '';
163
+ // 验证结果
164
+ let verify = '';
165
+
166
+ if (props.modelValue) {
167
+ // 有值
168
+ let hasError = false;
169
+ // 遍历校验规则
170
+ for (const rule of props.rules) {
171
+ if (rule && rule.validator) {
172
+ const yes = !(await rule.validator(props.modelValue));
173
+ if (yes) {
174
+ tips = rule.msg;
175
+ type = rule.type;
176
+ hasError = true;
177
+ break;
178
+ }
179
+ }
180
+ }
181
+ verify = hasError ? 'no' : 'ok';
182
+ } else {
183
+ // 无值
184
+ let hasError = false;
185
+ // 遍历校验规则
186
+ for (const rule of props.rules) {
187
+ if (rule) {
188
+ tips = rule.msg;
189
+ type = rule.type;
190
+ if (rule.required) {
191
+ hasError = true;
192
+ break;
193
+ }
194
+ }
195
+ }
196
+ verify = hasError ? 'no' : '';
197
+ }
198
+ if (verify !== 'no' && props.tips) {
199
+ tips = props.tips;
200
+ }
201
+ // 是否显示提示
202
+ const ontips = (verify === 'no' && tips) || props.tips ? 'show' : '';
203
+ // 状态颜色
204
+ const co = verify === 'no' ? 'co:' + type : props.co ? 'co:' + props.co : '';
205
+ state.error = { tips, ontips, verify, co };
206
+ } else {
207
+ state.error = { tips: props.tips, ontips: props.tips ? 'show' : '', verify: '', co: '' };
208
+ }
209
+ },
210
+ { deep: true, immediate: true }
211
+ );
212
+
213
+ // 清空
214
+ function clear() {
215
+ emits('update:modelValue', '');
216
+ emits('clear');
217
+ }
218
+ // 输入
219
+ const input = (e: any) => {
220
+ // 用户交互
221
+ if (!state.interacted) {
222
+ setTimeout(() => {
223
+ state.interacted = true;
224
+ }, 50);
225
+ }
226
+
227
+ // 长度限制
228
+ const value = e?.target?.value || '';
229
+ if (props.maxlength && value.length > props.maxlength) {
230
+ e.target.value = props.modelValue;
231
+ return false;
232
+ }
233
+ // 数字类型
234
+ if (props.type === 'number' && !value && props.modelValue?.length !== 1) {
235
+ e.target.value = props.modelValue;
236
+ return false;
237
+ }
238
+ // 输入事件
239
+ emits('input', e, state);
240
+ emits('update:modelValue', value);
241
+ };
242
+ // 失焦
243
+ const blur = (e: any) => {
244
+ if (!state.interacted) {
245
+ setTimeout(() => {
246
+ state.interacted = true;
247
+ }, 50);
248
+ }
249
+ emits('blur', e, state);
250
+ };
251
+
252
+ // 事件处理
253
+ const event: any = (item: any, data: any): object => {
254
+ const _event: any = {};
255
+ if (isObject(item.event)) {
256
+ for (const key in item.event) {
257
+ const fun = item.event[key];
258
+ if (isFunction(fun)) {
259
+ _event[key] = (...args: any) => {
260
+ return fun({ data }, ...args);
261
+ };
262
+ }
263
+ }
264
+ }
265
+ return { ..._event };
266
+ };
267
+ </script>
@@ -0,0 +1,200 @@
1
+ <template>
2
+ <div
3
+ :ui-form="`${theme} sz:${sz} ${state.error.co} type:input ${block ? ' :block' : ''} ${disabled ? 'disabled' : ''} ${readonly ? 'readonly' : ''}`"
4
+ @click="emits('click', $event)"
5
+ >
6
+ <div :ui-form-tips="state.error.ontips">{{ state.error.tips }}</div>
7
+ <div ui-form-prefix="">
8
+ <template v-for="(item, idx) in prefix" :key="idx">
9
+ <div v-html="isObject(item) ? item.html : item"></div>
10
+ </template>
11
+ <slot name="prefix"></slot>
12
+ </div>
13
+ <slot>
14
+ <input
15
+ v-model="state.value"
16
+ :type="type"
17
+ :placeholder="placeholder"
18
+ :readonly="readonly || disabled"
19
+ autocomplete="new-password"
20
+ @focus="emits('focus', $event, state)"
21
+ @input="input($event)"
22
+ @change="emits('change', $event, state)"
23
+ @blur="blur($event)"
24
+ />
25
+ </slot>
26
+ <div ui-form-suffix="">
27
+ <i ui-form-clean="" v-if="clearable && state.value && !readonly && !disabled" @click.stop="clear"></i>
28
+ <slot name="suffix"></slot>
29
+ <template v-for="(item, idx) in suffix" :key="idx">
30
+ <div v-html="isObject(item) ? item.html : item"></div>
31
+ </template>
32
+ </div>
33
+ <i v-if="ready && verify" :ui-form-verify="verify"></i>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup lang="ts">
38
+ import { reactive, watch, PropType } from 'vue';
39
+ import { isObject } from '@fekit/utils';
40
+
41
+ const emits = defineEmits(['update:modelValue', 'click', 'blur', 'focus', 'change', 'input', 'clear']);
42
+ const props = defineProps({
43
+ // 主题
44
+ theme: { type: String, default: '@a' },
45
+ // 尺寸
46
+ sz: { type: String, default: '' },
47
+ // 颜色
48
+ co: { type: String, default: '' },
49
+ // 撑满
50
+ block: { type: Boolean, default: true },
51
+ // 准备就绪
52
+ ready: { type: Boolean, default: false },
53
+ // 值
54
+ modelValue: { type: [String, Number], default: '' },
55
+ // 类型
56
+ type: { type: String, default: 'text' },
57
+ // 提示文案
58
+ tips: { type: String, default: '' },
59
+ // 内容占位
60
+ placeholder: { type: String, default: '' },
61
+ // 最大长度
62
+ maxlength: { type: Number, default: null },
63
+ // 最小长度
64
+ minlength: { type: Number, default: null },
65
+ // 是否禁用
66
+ disabled: { type: Boolean, default: false },
67
+ // 是否只读
68
+ readonly: { type: Boolean, default: false },
69
+ // 是否显示清除按钮
70
+ clearable: { type: Boolean, default: true },
71
+ // 校验规则
72
+ rules: { type: Array as PropType<any[]>, default: () => [] },
73
+ // 是否是示校验图标
74
+ verify: { type: Boolean, default: false },
75
+ prefix: { type: Array as PropType<any[]>, default: () => [] },
76
+ suffix: { type: Array as PropType<any[]>, default: () => [] },
77
+ // 用户是否交互
78
+ interacted: { type: Boolean, default: false }
79
+ });
80
+
81
+ const state: any = reactive({
82
+ // 用户是否交互
83
+ interacted: false,
84
+ // 值
85
+ value: props.modelValue,
86
+ // 错误
87
+ error: {}
88
+ });
89
+ // 外部传入交互标识,主要用于外部没有输入但点击了提交
90
+ watch(
91
+ () => props.interacted,
92
+ (interacted: any) => {
93
+ if (interacted) {
94
+ state.interacted = interacted;
95
+ }
96
+ },
97
+ { deep: true, immediate: true }
98
+ );
99
+
100
+ // 监听异步数据
101
+ watch(
102
+ () => props.modelValue,
103
+ (value: any) => {
104
+ if (state.value !== value) {
105
+ state.value = value;
106
+ }
107
+ },
108
+ { deep: true, immediate: true }
109
+ );
110
+ watch(
111
+ () => state.value,
112
+ (value: any) => {
113
+ emits('update:modelValue', value);
114
+ },
115
+ { deep: true, immediate: true }
116
+ );
117
+
118
+ // 校验
119
+ watch(
120
+ [() => state.interacted, () => state.value],
121
+ async () => {
122
+ if (state.interacted) {
123
+ // 提示文案
124
+ let tips = '';
125
+ // 错误类型
126
+ let type = '';
127
+ // 验证结果
128
+ let verify = '';
129
+
130
+ if (props.modelValue) {
131
+ // 有值
132
+ let hasError = false;
133
+ // 遍历校验规则
134
+ for (const rule of props.rules) {
135
+ if (rule && rule.validator) {
136
+ const yes = !(await rule.validator(props.modelValue));
137
+ if (yes) {
138
+ tips = rule.msg;
139
+ type = rule.type;
140
+ hasError = true;
141
+ break;
142
+ }
143
+ }
144
+ }
145
+ verify = hasError ? 'no' : 'ok';
146
+ } else {
147
+ // 无值
148
+ let hasError = false;
149
+ // 遍历校验规则
150
+ for (const rule of props.rules) {
151
+ if (rule) {
152
+ tips = rule.msg;
153
+ type = rule.type;
154
+ if (rule.required) {
155
+ hasError = true;
156
+ break;
157
+ }
158
+ }
159
+ }
160
+ verify = hasError ? 'no' : '';
161
+ }
162
+ if (verify !== 'no' && props.tips) {
163
+ tips = props.tips;
164
+ }
165
+ // 是否显示提示
166
+ const ontips = verify === 'no' && tips ? 'show' : '';
167
+ // 状态颜色
168
+ const co = verify === 'no' ? 'co:' + type : props.co ? 'co:' + props.co : '';
169
+ state.error = { tips, ontips, verify, co };
170
+ } else {
171
+ state.error = { tips: '', ontips: '', verify: '', co: '' };
172
+ }
173
+ },
174
+ { deep: true, immediate: true }
175
+ );
176
+
177
+ // 清空
178
+ function clear() {
179
+ emits('update:modelValue', '');
180
+ emits('clear');
181
+ }
182
+ // 输入
183
+ const input = (e: any) => {
184
+ if (!state.interacted) {
185
+ setTimeout(() => {
186
+ state.interacted = true;
187
+ }, 50);
188
+ }
189
+ emits('input', e, state);
190
+ };
191
+ // 失焦
192
+ const blur = (e: any) => {
193
+ if (!state.interacted) {
194
+ setTimeout(() => {
195
+ state.interacted = true;
196
+ }, 50);
197
+ }
198
+ emits('blur', e, state);
199
+ };
200
+ </script>