@truenewx/tnxvue3 3.4.1 → 3.4.2
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.
- package/package.json +9 -4
- package/src/element-plus/select/Select.vue +9 -5
- package/src/element-plus/tnxel.js +4 -1
- package/src/tdesign/desktop/tnxtdd.ts +16 -0
- package/src/tdesign/foundation/validator.ts +367 -0
- package/src/tdesign/mobile/tnxtdm.ts +16 -0
- package/src/tdesign/tnxtd.ts +20 -0
- package/src/{tnxvue-router.js → tnxvue-router.ts} +65 -47
- package/src/tnxvue.ts +248 -0
- package/src/types.d.ts +7 -0
- package/tsconfig.json +21 -0
- package/eslint.config.cjs +0 -58
- package/index.html +0 -12
- package/src/tnxvue-validator.js +0 -371
- package/src/tnxvue.js +0 -426
- /package/src/{aj-captcha → element-plus/aj-captcha}/Verify/VerifyPoints.vue +0 -0
- /package/src/{aj-captcha → element-plus/aj-captcha}/Verify/VerifySlide.vue +0 -0
- /package/src/{aj-captcha → element-plus/aj-captcha}/Verify.vue +0 -0
- /package/src/{aj-captcha → element-plus/aj-captcha}/api/index.js +0 -0
- /package/src/{aj-captcha → element-plus/aj-captcha}/utils/ase.js +0 -0
- /package/src/{aj-captcha → element-plus/aj-captcha}/utils/util.js +0 -0
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truenewx/tnxvue3",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.2",
|
|
4
4
|
"description": "互联网技术解决方案:Vue3扩展支持",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
|
-
"main": "src/tnxvue.
|
|
7
|
+
"main": "src/tnxvue.ts",
|
|
8
|
+
"types": "src/types.d.ts",
|
|
8
9
|
"keywords": [
|
|
9
10
|
"truenewx",
|
|
10
11
|
"tnxvue3",
|
|
@@ -18,15 +19,19 @@
|
|
|
18
19
|
"tnxvue3-preview": "vite preview"
|
|
19
20
|
},
|
|
20
21
|
"peerDependencies": {
|
|
22
|
+
"@element-plus/icons-vue": "~2.3.0",
|
|
23
|
+
"async-validator": "~4.2.0",
|
|
21
24
|
"element-plus": "~2.11.0",
|
|
22
25
|
"bootstrap-vue-next": "~0.40.0",
|
|
26
|
+
"tdesign-icons-vue-next": "~0.4.0",
|
|
27
|
+
"tdesign-mobile-vue": "~1.11.0",
|
|
28
|
+
"tdesign-vue-next": "~1.17.0",
|
|
29
|
+
"validator": "~13.15.0",
|
|
23
30
|
"vue": "~3.5.0",
|
|
24
31
|
"vue-router": "~4.6.0"
|
|
25
32
|
},
|
|
26
33
|
"dependencies": {
|
|
27
34
|
"@truenewx/tnxcore": "3.4.1",
|
|
28
|
-
"@element-plus/icons-vue": "2.3.2",
|
|
29
|
-
"async-validator": "4.2.5",
|
|
30
35
|
"mitt": "3.0.1"
|
|
31
36
|
},
|
|
32
37
|
"devDependencies": {
|
|
@@ -101,11 +101,9 @@
|
|
|
101
101
|
:size="size"
|
|
102
102
|
@command="onDropdownCommand"
|
|
103
103
|
v-else-if="selector === 'dropdown'">
|
|
104
|
-
<el-button style="width: 100%" :type="theme">
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
<tnxel-icon value="ArrowDown"/>
|
|
108
|
-
</div>
|
|
104
|
+
<el-button style="max-width: 100%" :type="theme" :title="currentText">
|
|
105
|
+
<span class="flex-1 overflow-ellipsis me-2">{{ currentText }}</span>
|
|
106
|
+
<tnxel-icon value="ArrowDown"/>
|
|
109
107
|
</el-button>
|
|
110
108
|
<template #dropdown v-if="items && items.length">
|
|
111
109
|
<el-dropdown-menu>
|
|
@@ -542,4 +540,10 @@ export default {
|
|
|
542
540
|
color: var(--el-color-primary);
|
|
543
541
|
font-weight: 600;
|
|
544
542
|
}
|
|
543
|
+
|
|
544
|
+
.tnxel-dropdown .el-button > span {
|
|
545
|
+
max-width: 100%;
|
|
546
|
+
display: flex;
|
|
547
|
+
align-items: center;
|
|
548
|
+
}
|
|
545
549
|
</style>
|
|
@@ -7,6 +7,7 @@ import ElementPlus_zh_CN from 'element-plus/es/locale/lang/zh-cn';
|
|
|
7
7
|
import tnxbs from '@truenewx/tnxcore/src/tnxbs'; // 二次封装组件中使用了Bootstrap的基础样式
|
|
8
8
|
import tnxvue from '../tnxvue.js';
|
|
9
9
|
|
|
10
|
+
import CaptchaVerify from './aj-captcha/Verify.vue';
|
|
10
11
|
import Avatar from './avatar/Avatar.vue';
|
|
11
12
|
import Alert from './alert/Alert.vue';
|
|
12
13
|
import Button from './button/Button.vue';
|
|
@@ -53,8 +54,10 @@ export const build = tnxvue.build;
|
|
|
53
54
|
|
|
54
55
|
export default build('tnxel', () => {
|
|
55
56
|
const components = Object.assign({}, tnxvue.components, {
|
|
56
|
-
|
|
57
|
+
CaptchaVerify, // 只使用了ElementPlus的图标
|
|
58
|
+
|
|
57
59
|
Alert,
|
|
60
|
+
Avatar,
|
|
58
61
|
Button,
|
|
59
62
|
CheckIcon,
|
|
60
63
|
CloseErrorButton,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { App, Component } from 'vue';
|
|
2
|
+
import { Router } from 'vue-router';
|
|
3
|
+
import TnxTd from '../tnxtd';
|
|
4
|
+
import TDesign from 'tdesign-vue-next';
|
|
5
|
+
|
|
6
|
+
export default class TnxTdd extends TnxTd {
|
|
7
|
+
|
|
8
|
+
constructor(apiBaseUrl: string) {
|
|
9
|
+
super(apiBaseUrl);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
createVueApp(rootComponent: Component, router: Router, rootProps?: Record<string, any>): App {
|
|
13
|
+
return super.createVueApp(rootComponent, router, rootProps).use(TDesign);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
}
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 校验规则转换器,将服务端元数据中的校验规则转换为validator组件的规则。
|
|
3
|
+
* validator组件详见:https://github.com/validatorjs/validator.js
|
|
4
|
+
*/
|
|
5
|
+
import validator from 'validator';
|
|
6
|
+
import {Validator} from '../../../../tnxcore/src/tnxcore';
|
|
7
|
+
import {ApiModelPropertyMeta, ApiModelMeta} from '../../../../tnxcore/src/api/meta';
|
|
8
|
+
|
|
9
|
+
export type ValidateResultType = 'error' | 'warning' | 'success';
|
|
10
|
+
|
|
11
|
+
export type ValidateResult = {
|
|
12
|
+
result: boolean;
|
|
13
|
+
message?: string;
|
|
14
|
+
type?: ValidateResultType;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type ValidatorRule = {
|
|
18
|
+
name?: string;
|
|
19
|
+
required?: boolean;
|
|
20
|
+
message?: string;
|
|
21
|
+
type?: ValidateResultType;
|
|
22
|
+
trigger?: 'blur' | 'change';
|
|
23
|
+
validator?: (fieldValue: string) => ValidateResult;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default class TnxTdValidator extends Validator {
|
|
27
|
+
|
|
28
|
+
getRule(validationName: string, validationValue: any, fieldMeta: ApiModelPropertyMeta): ValidatorRule | undefined {
|
|
29
|
+
let rule: ValidatorRule;
|
|
30
|
+
let fieldCaption = '';
|
|
31
|
+
// 据目前观察,字段格式校验的错误消息均显示在字段旁,无需显示字段名称,未来如果出现不在字段旁显示的场景,再考虑扩展
|
|
32
|
+
// if (fieldMeta && fieldMeta.caption) {
|
|
33
|
+
// fieldCaption = fieldMeta.caption;
|
|
34
|
+
// }
|
|
35
|
+
switch (validationName) {
|
|
36
|
+
case 'required':
|
|
37
|
+
case 'notNull':
|
|
38
|
+
case 'notEmpty':
|
|
39
|
+
case 'notBlank':
|
|
40
|
+
if (validationValue === true) {
|
|
41
|
+
rule = {
|
|
42
|
+
required: true,
|
|
43
|
+
validator(fieldValue: string): ValidateResult {
|
|
44
|
+
if (validationValue) {
|
|
45
|
+
let blank = fieldValue === undefined || fieldValue === null;
|
|
46
|
+
if (!blank && typeof fieldValue === 'string') {
|
|
47
|
+
blank = fieldValue.trim().length === 0;
|
|
48
|
+
}
|
|
49
|
+
if (blank) {
|
|
50
|
+
let message = this.getErrorMessage(validationName, fieldCaption);
|
|
51
|
+
return {result: false, message, type: 'error'};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return {result: true};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
case 'minLength':
|
|
60
|
+
rule = {
|
|
61
|
+
validator(fieldValue: string): ValidateResult {
|
|
62
|
+
if (typeof validationValue === 'number' && typeof fieldValue === 'string') {
|
|
63
|
+
let enterLength = fieldValue.indexOf('\n') < 0 ? 0 : (fieldValue.match(/\n/g) as any).length;
|
|
64
|
+
let fieldLength = fieldValue.length + enterLength;
|
|
65
|
+
if (fieldLength < validationValue) {
|
|
66
|
+
let message = this.getErrorMessage(validationName, fieldCaption,
|
|
67
|
+
validationValue, validationValue - fieldLength);
|
|
68
|
+
return {result: false, message, type: 'error'};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {result: true};
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
break;
|
|
75
|
+
case 'maxLength':
|
|
76
|
+
rule = {
|
|
77
|
+
validator(fieldValue: string): ValidateResult {
|
|
78
|
+
if (typeof validationValue === 'number' && typeof fieldValue === 'string') {
|
|
79
|
+
let enterLength = fieldValue.indexOf('\n') < 0 ? 0 : (fieldValue.match(/\n/g) as any).length;
|
|
80
|
+
let fieldLength = fieldValue.length + enterLength;
|
|
81
|
+
if (fieldLength > validationValue) {
|
|
82
|
+
let message = this.getErrorMessage(validationName, fieldCaption,
|
|
83
|
+
validationValue, fieldLength - validationValue);
|
|
84
|
+
return {result: false, message, type: 'error'};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return {result: true};
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
break;
|
|
91
|
+
case 'number':
|
|
92
|
+
if (validationValue === true) {
|
|
93
|
+
rule = {
|
|
94
|
+
validator(fieldValue: string): ValidateResult {
|
|
95
|
+
if (fieldValue && typeof fieldValue === 'string') {
|
|
96
|
+
if (!validator.isNumeric(fieldValue, {no_symbols: true})) {
|
|
97
|
+
let message = this.getErrorMessage(validationName, fieldCaption);
|
|
98
|
+
return {result: false, message, type: 'error'};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return {result: true};
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
case 'notContainsHtmlChars':
|
|
107
|
+
if (validationValue === true) {
|
|
108
|
+
rule = {
|
|
109
|
+
validator(fieldValue: string): ValidateResult {
|
|
110
|
+
if (typeof fieldValue === 'string') {
|
|
111
|
+
let limitedValues = ['<', '>', "'", '"', '\\'];
|
|
112
|
+
for (let i = 0; i < limitedValues.length; i++) {
|
|
113
|
+
if (fieldValue.indexOf(limitedValues[i]) >= 0) {
|
|
114
|
+
let s = limitedValues.join(' ');
|
|
115
|
+
let message = this.getErrorMessage('notContains', fieldCaption, s);
|
|
116
|
+
return {result: false, message, type: 'error'};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {result: true};
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
case 'notContainsIllegalFilenameChars':
|
|
126
|
+
if (validationValue === true) {
|
|
127
|
+
rule = {
|
|
128
|
+
validator(fieldValue: string): ValidateResult {
|
|
129
|
+
if (typeof fieldValue === 'string') {
|
|
130
|
+
let limitedValues = ['/', '\\', ':', '*', '?', '"', '<', '>', '|'];
|
|
131
|
+
for (let i = 0; i < limitedValues.length; i++) {
|
|
132
|
+
if (fieldValue.indexOf(limitedValues[i]) >= 0) {
|
|
133
|
+
let s = limitedValues.join(' ');
|
|
134
|
+
let message = this.getErrorMessage('notContains', fieldCaption, s);
|
|
135
|
+
return {result: false, message, type: 'error'};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return {result: true};
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
case 'notContains':
|
|
145
|
+
if (validationValue) {
|
|
146
|
+
rule = {
|
|
147
|
+
validator(fieldValue: string): ValidateResult {
|
|
148
|
+
if (typeof fieldValue === 'string') {
|
|
149
|
+
let limitedValues = (validationValue as string).split(' ');
|
|
150
|
+
for (let i = 0; i < limitedValues.length; i++) {
|
|
151
|
+
if (validator.contains(fieldValue, limitedValues[i])) {
|
|
152
|
+
let message = this.getErrorMessage('notContains', fieldCaption,
|
|
153
|
+
validationValue);
|
|
154
|
+
return {result: false, message, type: 'error'};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return {result: true};
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
case 'rejectHtmlTags':
|
|
164
|
+
if (validationValue === true) {
|
|
165
|
+
rule = {
|
|
166
|
+
validator(fieldValue: string): ValidateResult {
|
|
167
|
+
if (fieldValue) {
|
|
168
|
+
if (/<[a-z]+[ ]*[/]?[ ]*>/gi.test(fieldValue)) {
|
|
169
|
+
let message = this.getErrorMessage(validationName, fieldCaption);
|
|
170
|
+
return {result: false, message, type: 'error'};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return {result: true};
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
case 'allowedHtmlTags':
|
|
179
|
+
if (validationValue) {
|
|
180
|
+
rule = {
|
|
181
|
+
validator(fieldValue: string): ValidateResult {
|
|
182
|
+
if (typeof fieldValue === 'string') {
|
|
183
|
+
let tags = (validationValue as string).toLowerCase().split(',');
|
|
184
|
+
if (tags.length) {
|
|
185
|
+
let value = fieldValue.toLowerCase();
|
|
186
|
+
let leftIndex = value.indexOf('<');
|
|
187
|
+
let rightIndex = leftIndex >= 0 ? value.indexOf('>', leftIndex) : -1;
|
|
188
|
+
while (leftIndex >= 0 && rightIndex >= 0) {
|
|
189
|
+
let sub = value.substring(leftIndex + 1, rightIndex);
|
|
190
|
+
let spaceIndex = sub.indexOf(' ');
|
|
191
|
+
let tag = spaceIndex >= 0 ? sub.substring(0, spaceIndex) : sub;
|
|
192
|
+
if (tag.startsWith('/')) {
|
|
193
|
+
tag = tag.substring(1);
|
|
194
|
+
}
|
|
195
|
+
if (!tags.contains(tag.toLowerCase())) {
|
|
196
|
+
let message = this.getErrorMessage(validationName, fieldCaption,
|
|
197
|
+
tags.join(', '));
|
|
198
|
+
return {result: false, message, type: 'error'};
|
|
199
|
+
}
|
|
200
|
+
leftIndex = value.indexOf('<', rightIndex);
|
|
201
|
+
rightIndex = leftIndex >= 0 ? value.indexOf('>', leftIndex) : -1;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return {result: true};
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
case 'forbiddenHtmlTags':
|
|
211
|
+
if (validationValue) {
|
|
212
|
+
rule = {
|
|
213
|
+
validator(fieldValue: string): ValidateResult {
|
|
214
|
+
if (fieldValue) {
|
|
215
|
+
let tags = (validationValue as string).toLowerCase().split(',');
|
|
216
|
+
if (tags.length) {
|
|
217
|
+
let value = fieldValue.toLowerCase();
|
|
218
|
+
for (let tag of tags) {
|
|
219
|
+
if (value.includes('<' + tag + '>') || value.includes('<' + tag + ' ')) {
|
|
220
|
+
let message = this.getErrorMessage(validationName, fieldCaption,
|
|
221
|
+
tags.join(', '));
|
|
222
|
+
return {result: false, message, type: 'error'};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return {result: true};
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
232
|
+
case 'email':
|
|
233
|
+
if (validationValue === true) {
|
|
234
|
+
rule = {
|
|
235
|
+
validator(fieldValue: string): ValidateResult {
|
|
236
|
+
if (typeof fieldValue === 'string' && fieldValue) {
|
|
237
|
+
if (!validator.isEmail(fieldValue)) {
|
|
238
|
+
let message = this.getErrorMessage(validationName, fieldCaption);
|
|
239
|
+
return {result: false, message, type: 'error'};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return {result: true};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
break;
|
|
247
|
+
case 'cellphone':
|
|
248
|
+
case 'idCardNo':
|
|
249
|
+
case 'url':
|
|
250
|
+
case 'opposableUrl':
|
|
251
|
+
rule = {
|
|
252
|
+
validator(fieldValue: string): ValidateResult {
|
|
253
|
+
if (validationValue) {
|
|
254
|
+
let message = this.validateRegExp(validationName, fieldValue, fieldCaption);
|
|
255
|
+
if (message) {
|
|
256
|
+
return {result: false, message, type: 'error'};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return {result: true};
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
break;
|
|
263
|
+
case 'regex':
|
|
264
|
+
rule = {
|
|
265
|
+
validator(fieldValue: string): ValidateResult {
|
|
266
|
+
if (fieldValue) {
|
|
267
|
+
let pattern = (validationValue as any).pattern;
|
|
268
|
+
if (!pattern.startsWith('^')) {
|
|
269
|
+
pattern = '^' + pattern;
|
|
270
|
+
}
|
|
271
|
+
if (!pattern.endsWith('$')) {
|
|
272
|
+
pattern += '$';
|
|
273
|
+
}
|
|
274
|
+
let regexp = new RegExp(pattern, 'gi');
|
|
275
|
+
if (!regexp.test(fieldValue)) {
|
|
276
|
+
let message = (validationValue as any).message;
|
|
277
|
+
if (message) {
|
|
278
|
+
message = fieldCaption + message;
|
|
279
|
+
} else {
|
|
280
|
+
message = this.getErrorMessage('regex', fieldCaption, '');
|
|
281
|
+
}
|
|
282
|
+
return {result: false, message, type: 'error'};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return {result: true};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
break;
|
|
289
|
+
case 'custom':
|
|
290
|
+
if (typeof validationValue === 'function') {
|
|
291
|
+
rule = {
|
|
292
|
+
validator(fieldValue: string): ValidateResult {
|
|
293
|
+
let message = validationValue(fieldValue);
|
|
294
|
+
if (message) {
|
|
295
|
+
return {result: false, message, type: 'error'};
|
|
296
|
+
}
|
|
297
|
+
return {result: true};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
if (rule) {
|
|
304
|
+
rule.name = validationName;
|
|
305
|
+
let metaType = 'text';
|
|
306
|
+
if (fieldMeta && fieldMeta.type) {
|
|
307
|
+
metaType = fieldMeta.type.toLowerCase();
|
|
308
|
+
}
|
|
309
|
+
let optional = metaType === 'option' || metaType === 'datetime' || metaType === 'date' || metaType === 'time';
|
|
310
|
+
rule.trigger = optional ? 'change' : 'blur';
|
|
311
|
+
}
|
|
312
|
+
return rule;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
getRules(meta: ApiModelMeta): Record<string, ValidatorRule[]> {
|
|
316
|
+
let rules: Record<string, ValidatorRule[]> = {};
|
|
317
|
+
Object.keys(meta).forEach(fieldName => {
|
|
318
|
+
let fieldMeta = meta[fieldName];
|
|
319
|
+
if (fieldMeta.validation) {
|
|
320
|
+
let fieldRules: ValidatorRule[] = [];
|
|
321
|
+
Object.keys(fieldMeta.validation).forEach(validationName => {
|
|
322
|
+
let validationValue = fieldMeta.validation[validationName];
|
|
323
|
+
let rule = this.getRule(validationName, validationValue, fieldMeta);
|
|
324
|
+
if (rule) {
|
|
325
|
+
fieldRules.push(rule);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
// 将可能包含的引用字段路径中的.替换为__,以符合async-validator规则名称的规范
|
|
329
|
+
let ruleName = fieldName.replace('.', '__');
|
|
330
|
+
rules[ruleName] = fieldRules;
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
return rules;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* 用指定规则集校验指定模型中的所有字符串值字段
|
|
338
|
+
* @return 校验结果错误消息集映射,key-字段名,value-错误消息集,校验通过的不包含在内
|
|
339
|
+
*/
|
|
340
|
+
validate(rules: Record<string, ValidatorRule[]>, model: Record<string, any>): Record<string, string[]> {
|
|
341
|
+
let result: Record<string, string[]> = {};
|
|
342
|
+
if (rules && model) {
|
|
343
|
+
Object.keys(rules).forEach(fieldName => {
|
|
344
|
+
const fieldRules = rules[fieldName];
|
|
345
|
+
if (Array.isArray(fieldRules) && fieldRules.length) {
|
|
346
|
+
const messages: string[] = [];
|
|
347
|
+
const fieldValue = model[fieldName];
|
|
348
|
+
if (typeof fieldValue === 'string') {
|
|
349
|
+
for (let rule of fieldRules) {
|
|
350
|
+
if (typeof rule.validator === 'function') {
|
|
351
|
+
const r = rule.validator(fieldValue);
|
|
352
|
+
if (r && r.result !== true && r.message) {
|
|
353
|
+
messages.push(r.message);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (messages.length > 0) {
|
|
358
|
+
result[fieldName] = messages;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { App, Component } from 'vue';
|
|
2
|
+
import { Router } from 'vue-router';
|
|
3
|
+
import TnxTd from '../tnxtd';
|
|
4
|
+
import TDesign from 'tdesign-mobile-vue';
|
|
5
|
+
|
|
6
|
+
export default class TnxTdm extends TnxTd {
|
|
7
|
+
|
|
8
|
+
constructor(apiBaseUrl: string) {
|
|
9
|
+
super(apiBaseUrl);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
createVueApp(rootComponent: Component, router: Router, rootProps?: Record<string, any>): App {
|
|
13
|
+
return super.createVueApp(rootComponent, router, rootProps).use(TDesign);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import TnxVue from '../tnxvue';
|
|
2
|
+
import {Icon} from 'tdesign-icons-vue-next';
|
|
3
|
+
import Validator from './foundation/validator';
|
|
4
|
+
|
|
5
|
+
export {Validator};
|
|
6
|
+
|
|
7
|
+
export default class TnxTd extends TnxVue {
|
|
8
|
+
|
|
9
|
+
static {
|
|
10
|
+
TnxTd.Foundations.Validator = Validator;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
constructor(apiBaseUrl: string) {
|
|
14
|
+
super(apiBaseUrl);
|
|
15
|
+
Object.assign(this.components, {
|
|
16
|
+
Icon,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
}
|