@truenewx/tnxvue3 3.4.4 → 3.4.5
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 +2 -2
- package/src/bootstrap-vue/dialog/Dialog.vue +22 -10
- package/src/element-plus/dialog/Dialog.vue +19 -7
- package/src/element-plus/drawer/Drawer.vue +20 -3
- package/src/element-plus/fss-upload/FssUpload.vue +1 -1
- package/src/element-plus/icon/Icon.vue +3 -0
- package/src/element-plus/tnxel.css +0 -8
- package/src/element-plus/tnxel.ts +58 -72
- package/src/tdesign/mobile/calendar/Calendar.vue +121 -0
- package/src/tdesign/mobile/date-time-picker/DateTimePicker.vue +147 -0
- package/src/tdesign/mobile/dialog/Dialog.vue +179 -0
- package/src/tdesign/mobile/dialog/DialogContent.vue +13 -0
- package/src/tdesign/mobile/drawer/Drawer.vue +176 -0
- package/src/tdesign/mobile/drawer/DrawerContent.vue +13 -0
- package/src/tdesign/mobile/enum-select/EnumSelect.vue +160 -0
- package/src/tdesign/mobile/popup/Popup.vue +106 -0
- package/src/tdesign/mobile/region-picker/RegionPicker.vue +223 -0
- package/src/tdesign/mobile/select/Select.vue +478 -0
- package/src/tdesign/mobile/slide-radio-group/SlideRadioGroup.vue +392 -0
- package/src/tdesign/mobile/tnxtdm.css +132 -0
- package/src/tdesign/mobile/tnxtdm.ts +303 -1
- package/src/tdesign/tnxtd-validator.ts +14 -13
- package/src/tdesign/tnxtd.css +66 -0
- package/src/tdesign/tnxtd.ts +4 -0
- package/src/tnxvue-router.ts +58 -5
- package/src/tnxvue.ts +20 -7
- package/tsconfig.json +1 -0
|
@@ -1,17 +1,319 @@
|
|
|
1
1
|
import {App, Component} from 'vue';
|
|
2
2
|
import {Router} from 'vue-router';
|
|
3
3
|
import TnxTd from '../tnxtd.ts';
|
|
4
|
-
import TDesign from 'tdesign-mobile-vue';
|
|
4
|
+
import TDesign, {Dialog as TDialogPlugin, Toast} from 'tdesign-mobile-vue/esm';
|
|
5
|
+
import 'tdesign-mobile-vue/esm/style/index.js'
|
|
5
6
|
import './tnxtdm.css';
|
|
7
|
+
import * as Vue from "vue";
|
|
8
|
+
import {type DialogOptions, type DrawerOptions, type OpenOptions} from '../../tnxvue.ts';
|
|
9
|
+
import Calendar from './calendar/Calendar.vue';
|
|
10
|
+
import DateTimePicker from './date-time-picker/DateTimePicker.vue';
|
|
11
|
+
import Dialog from './dialog/Dialog.vue';
|
|
12
|
+
import Drawer from './drawer/Drawer.vue';
|
|
13
|
+
import EnumSelect from './enum-select/EnumSelect.vue';
|
|
14
|
+
import Popup from './popup/Popup.vue';
|
|
15
|
+
import RegionPicker from './region-picker/RegionPicker.vue';
|
|
16
|
+
import Select from './select/Select.vue';
|
|
17
|
+
import SlideRadioGroup from './slide-radio-group/SlideRadioGroup.vue';
|
|
18
|
+
|
|
19
|
+
export type {OpenOptions};
|
|
20
|
+
|
|
21
|
+
const components = {
|
|
22
|
+
Calendar,
|
|
23
|
+
DateTimePicker,
|
|
24
|
+
Dialog,
|
|
25
|
+
Drawer,
|
|
26
|
+
EnumSelect,
|
|
27
|
+
Popup,
|
|
28
|
+
RegionPicker,
|
|
29
|
+
Select,
|
|
30
|
+
SlideRadioGroup,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const dialogContainerClass = 'tnxtdm-dialog-container';
|
|
34
|
+
const drawerContainerClass = 'tnxtdm-drawer-container';
|
|
35
|
+
|
|
36
|
+
type VueComponent = Vue.Component & {
|
|
37
|
+
components?: Record<string, Vue.Component>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type ModalComponentInstance = Vue.ComponentPublicInstance & {
|
|
41
|
+
id: string;
|
|
42
|
+
close: () => Promise<void>;
|
|
43
|
+
options: Record<string, any>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type ToastTheme = 'success' | 'warning' | 'error' | 'loading';
|
|
6
47
|
|
|
7
48
|
export default class TnxTdm extends TnxTd {
|
|
8
49
|
|
|
9
50
|
constructor(apiBaseUrl: string, id: string = 'tnxtdm') {
|
|
10
51
|
super(apiBaseUrl, id);
|
|
52
|
+
Object.assign(this.components, components);
|
|
11
53
|
}
|
|
12
54
|
|
|
13
55
|
createVueApp(rootComponent: Component, router?: Router, rootProps?: Record<string, any>): App {
|
|
14
56
|
return super.createVueApp(rootComponent, router, rootProps).use(TDesign);
|
|
15
57
|
}
|
|
16
58
|
|
|
59
|
+
private closeMessage() {
|
|
60
|
+
Toast.clear();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
toast(message: string, theme?: string, options?: { duration?: number }): Promise<void> {
|
|
64
|
+
return new Promise<void>((resolve) => {
|
|
65
|
+
this.closeMessage();
|
|
66
|
+
Toast({
|
|
67
|
+
direction: 'column',
|
|
68
|
+
duration: options?.duration || 2000,
|
|
69
|
+
theme: theme as ToastTheme,
|
|
70
|
+
placement: 'middle',
|
|
71
|
+
message: message,
|
|
72
|
+
onClose: () => resolve(),
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private dialogInstances: ModalComponentInstance[] = []; // 对话框实例堆栈
|
|
78
|
+
private drawerInstances: ModalComponentInstance[] = []; // 抽屉实例堆栈
|
|
79
|
+
|
|
80
|
+
dialog(content: string | Vue.Component,
|
|
81
|
+
title?: string,
|
|
82
|
+
options: DialogOptions = {},
|
|
83
|
+
contentProps: Record<string, any> = {}): ModalComponentInstance {
|
|
84
|
+
this.closeMessage();
|
|
85
|
+
|
|
86
|
+
let componentDefinition: VueComponent = Object.assign({}, Dialog);
|
|
87
|
+
if (this.isComponent(content)) {
|
|
88
|
+
const components = Object.assign({}, Dialog.components || {});
|
|
89
|
+
components['tnxtdm-dialog-content'] = content;
|
|
90
|
+
componentDefinition.components = components;
|
|
91
|
+
content = null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const dialogId = 'dialog-' + (new Date().getTime());
|
|
95
|
+
const container = document.createElement('div');
|
|
96
|
+
container.className = dialogContainerClass;
|
|
97
|
+
container.id = dialogId;
|
|
98
|
+
document.body.appendChild(container);
|
|
99
|
+
|
|
100
|
+
const buttons = this.getOptionsButtons(options);
|
|
101
|
+
const containerSelector = '.' + dialogContainerClass + '#' + dialogId;
|
|
102
|
+
let dialogVm = this.createVueApp(componentDefinition, null, {
|
|
103
|
+
modelValue: true,
|
|
104
|
+
container: containerSelector,
|
|
105
|
+
title: title,
|
|
106
|
+
content: content,
|
|
107
|
+
contentProps: contentProps,
|
|
108
|
+
buttons: buttons,
|
|
109
|
+
theme: options.theme,
|
|
110
|
+
});
|
|
111
|
+
const dialog = dialogVm.mount(containerSelector) as ModalComponentInstance;
|
|
112
|
+
dialog.options = Object.assign(dialog.options || {}, options);
|
|
113
|
+
dialog.options.onClosed = this.util.function.around(dialog.options.onClosed, (onClosed: () => void): void => {
|
|
114
|
+
dialogVm.unmount();
|
|
115
|
+
this.dialogInstances.remove(dialog);
|
|
116
|
+
|
|
117
|
+
const containerElement = document.querySelector(containerSelector) as HTMLElement | null;
|
|
118
|
+
if (containerElement) {
|
|
119
|
+
containerElement.remove();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (onClosed) {
|
|
123
|
+
onClosed.call(dialog);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
this.dialogInstances.push(dialog);
|
|
127
|
+
return dialog;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
closeDialog(all?: boolean): void {
|
|
131
|
+
if (this.dialogInstances.length) {
|
|
132
|
+
let dialog = this.dialogInstances.pop();
|
|
133
|
+
while (dialog) {
|
|
134
|
+
dialog.close();
|
|
135
|
+
if (all) {
|
|
136
|
+
dialog = this.dialogInstances.pop();
|
|
137
|
+
} else {
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
drawer(content: string | Vue.Component,
|
|
145
|
+
title?: string,
|
|
146
|
+
options: DrawerOptions = {},
|
|
147
|
+
contentProps: Record<string, any> = {}): ModalComponentInstance {
|
|
148
|
+
this.closeMessage();
|
|
149
|
+
|
|
150
|
+
let componentDefinition: VueComponent = Object.assign({}, Drawer);
|
|
151
|
+
if (this.isComponent(content)) {
|
|
152
|
+
const components = Object.assign({}, Drawer.components || {});
|
|
153
|
+
components['tnxtdm-drawer-content'] = content;
|
|
154
|
+
componentDefinition.components = components;
|
|
155
|
+
content = null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const drawerId = 'drawer-' + (new Date().getTime());
|
|
159
|
+
const container = document.createElement('div');
|
|
160
|
+
container.className = drawerContainerClass;
|
|
161
|
+
container.id = drawerId;
|
|
162
|
+
document.body.appendChild(container);
|
|
163
|
+
|
|
164
|
+
const buttons = this.getOptionsButtons(options);
|
|
165
|
+
const containerSelector = '.' + drawerContainerClass + '#' + drawerId;
|
|
166
|
+
let drawerVm = this.createVueApp(componentDefinition, null, {
|
|
167
|
+
modelValue: true,
|
|
168
|
+
container: containerSelector,
|
|
169
|
+
title: title,
|
|
170
|
+
content: content,
|
|
171
|
+
contentProps: contentProps,
|
|
172
|
+
buttons: buttons,
|
|
173
|
+
theme: options.theme,
|
|
174
|
+
placement: (options as any).placement,
|
|
175
|
+
});
|
|
176
|
+
const drawer = drawerVm.mount(containerSelector) as ModalComponentInstance;
|
|
177
|
+
drawer.options = Object.assign(drawer.options || {}, options);
|
|
178
|
+
drawer.options.onClosed = this.util.function.around(drawer.options.onClosed, (onClosed: () => void): void => {
|
|
179
|
+
drawerVm.unmount();
|
|
180
|
+
this.drawerInstances.remove(drawer);
|
|
181
|
+
|
|
182
|
+
const containerElement = document.querySelector(containerSelector) as HTMLElement | null;
|
|
183
|
+
if (containerElement) {
|
|
184
|
+
containerElement.remove();
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (onClosed) {
|
|
188
|
+
onClosed.call(drawer);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
this.drawerInstances.push(drawer);
|
|
192
|
+
return drawer;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
closeDrawer(all?: boolean): void {
|
|
196
|
+
if (this.drawerInstances.length) {
|
|
197
|
+
let drawer = this.drawerInstances.pop();
|
|
198
|
+
while (drawer) {
|
|
199
|
+
drawer.close();
|
|
200
|
+
if (all) {
|
|
201
|
+
drawer = this.drawerInstances.pop();
|
|
202
|
+
} else {
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
alert(message: string, options?: { title?: string, theme?: string, confirmButtonText?: string }): Promise<void> {
|
|
210
|
+
return new Promise<void>((resolve) => {
|
|
211
|
+
this.closeMessage();
|
|
212
|
+
let title = options?.title || '提示';
|
|
213
|
+
let theme = options?.theme || 'warning';
|
|
214
|
+
let iconName = 'info-circle';
|
|
215
|
+
let iconColor = 'var(--td-brand-color)';
|
|
216
|
+
let confirmBtn: any = {
|
|
217
|
+
content: options?.confirmButtonText || '确定',
|
|
218
|
+
theme: 'primary'
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
if (theme === 'success') {
|
|
222
|
+
iconName = 'check-circle';
|
|
223
|
+
iconColor = 'var(--td-success-color)';
|
|
224
|
+
confirmBtn.theme = 'success';
|
|
225
|
+
} else if (theme === 'error') {
|
|
226
|
+
iconName = 'close-circle';
|
|
227
|
+
iconColor = 'var(--td-error-color)';
|
|
228
|
+
confirmBtn.theme = 'danger';
|
|
229
|
+
} else if (theme === 'warning') {
|
|
230
|
+
iconName = 'error-circle';
|
|
231
|
+
iconColor = 'var(--td-warning-color)';
|
|
232
|
+
confirmBtn.theme = 'warning';
|
|
233
|
+
} else if (theme === 'info') {
|
|
234
|
+
iconName = 'info-circle';
|
|
235
|
+
iconColor = 'var(--td-info-color)';
|
|
236
|
+
confirmBtn.theme = 'info';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
let maxZIndex = 0;
|
|
240
|
+
const allElements = document.getElementsByTagName('*');
|
|
241
|
+
for (let i = 0; i < allElements.length; i++) {
|
|
242
|
+
const zIndex = parseInt(window.getComputedStyle(allElements[i]).zIndex);
|
|
243
|
+
if (!isNaN(zIndex) && zIndex > maxZIndex) {
|
|
244
|
+
maxZIndex = zIndex;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
TDialogPlugin.alert({
|
|
249
|
+
title: (h) => {
|
|
250
|
+
return h('div', {
|
|
251
|
+
style: {
|
|
252
|
+
display: 'flex',
|
|
253
|
+
alignItems: 'center',
|
|
254
|
+
justifyContent: 'center'
|
|
255
|
+
}
|
|
256
|
+
}, [
|
|
257
|
+
h(this.components.Icon, {
|
|
258
|
+
name: iconName,
|
|
259
|
+
style: {marginRight: '6px', color: iconColor, fontSize: '20px'}
|
|
260
|
+
}),
|
|
261
|
+
h('span', title)
|
|
262
|
+
]);
|
|
263
|
+
},
|
|
264
|
+
content: message,
|
|
265
|
+
confirmBtn: confirmBtn,
|
|
266
|
+
zIndex: maxZIndex + 2,
|
|
267
|
+
showOverlay: true,
|
|
268
|
+
overlayProps: {
|
|
269
|
+
zIndex: maxZIndex + 1
|
|
270
|
+
},
|
|
271
|
+
destroyOnClose: true,
|
|
272
|
+
onConfirm: () => {
|
|
273
|
+
resolve();
|
|
274
|
+
},
|
|
275
|
+
onClose: () => {
|
|
276
|
+
resolve();
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
success(message: string, options?: { title?: string, confirmButtonText?: string }): Promise<void> {
|
|
283
|
+
return this.alert(message, Object.assign({title: '成功', theme: 'success'}, options));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
error(message: string, options?: { title?: string, confirmButtonText?: string }): Promise<void> {
|
|
287
|
+
return this.alert(message, Object.assign({title: '错误', theme: 'error'}, options));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
confirm(message: string, options?: { title?: string }): Promise<boolean> {
|
|
291
|
+
return new Promise<boolean>((resolve) => {
|
|
292
|
+
this.closeMessage();
|
|
293
|
+
TDialogPlugin.confirm({
|
|
294
|
+
title: options?.title || '确认',
|
|
295
|
+
content: message,
|
|
296
|
+
confirmBtn: '确定',
|
|
297
|
+
cancelBtn: '取消',
|
|
298
|
+
onConfirm: () => {
|
|
299
|
+
resolve(true);
|
|
300
|
+
},
|
|
301
|
+
onCancel: () => {
|
|
302
|
+
resolve(false);
|
|
303
|
+
},
|
|
304
|
+
onClose: () => {
|
|
305
|
+
resolve(false);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
showLoading(message?: string): Promise<void> {
|
|
312
|
+
return this.toast(message, 'loading', {duration: 0});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
closeLoading(): void {
|
|
316
|
+
Toast.clear();
|
|
317
|
+
}
|
|
318
|
+
|
|
17
319
|
}
|
|
@@ -32,6 +32,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
32
32
|
// if (fieldMeta && fieldMeta.caption) {
|
|
33
33
|
// fieldCaption = fieldMeta.caption;
|
|
34
34
|
// }
|
|
35
|
+
let _this = this;
|
|
35
36
|
switch (validationName) {
|
|
36
37
|
case 'required':
|
|
37
38
|
case 'notNull':
|
|
@@ -47,7 +48,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
47
48
|
blank = fieldValue.trim().length === 0;
|
|
48
49
|
}
|
|
49
50
|
if (blank) {
|
|
50
|
-
let message =
|
|
51
|
+
let message = _this.getErrorMessage(validationName, fieldCaption);
|
|
51
52
|
return {result: false, message, type: 'error'};
|
|
52
53
|
}
|
|
53
54
|
}
|
|
@@ -63,7 +64,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
63
64
|
let enterLength = fieldValue.indexOf('\n') < 0 ? 0 : (fieldValue.match(/\n/g) as any).length;
|
|
64
65
|
let fieldLength = fieldValue.length + enterLength;
|
|
65
66
|
if (fieldLength < validationValue) {
|
|
66
|
-
let message =
|
|
67
|
+
let message = _this.getErrorMessage(validationName, fieldCaption,
|
|
67
68
|
validationValue, validationValue - fieldLength);
|
|
68
69
|
return {result: false, message, type: 'error'};
|
|
69
70
|
}
|
|
@@ -79,7 +80,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
79
80
|
let enterLength = fieldValue.indexOf('\n') < 0 ? 0 : (fieldValue.match(/\n/g) as any).length;
|
|
80
81
|
let fieldLength = fieldValue.length + enterLength;
|
|
81
82
|
if (fieldLength > validationValue) {
|
|
82
|
-
let message =
|
|
83
|
+
let message = _this.getErrorMessage(validationName, fieldCaption,
|
|
83
84
|
validationValue, fieldLength - validationValue);
|
|
84
85
|
return {result: false, message, type: 'error'};
|
|
85
86
|
}
|
|
@@ -94,7 +95,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
94
95
|
validator(fieldValue: string): ValidateResult {
|
|
95
96
|
if (fieldValue && typeof fieldValue === 'string') {
|
|
96
97
|
if (!validator.isNumeric(fieldValue, {no_symbols: true})) {
|
|
97
|
-
let message =
|
|
98
|
+
let message = _this.getErrorMessage(validationName, fieldCaption);
|
|
98
99
|
return {result: false, message, type: 'error'};
|
|
99
100
|
}
|
|
100
101
|
}
|
|
@@ -112,7 +113,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
112
113
|
for (let i = 0; i < limitedValues.length; i++) {
|
|
113
114
|
if (fieldValue.indexOf(limitedValues[i]) >= 0) {
|
|
114
115
|
let s = limitedValues.join(' ');
|
|
115
|
-
let message =
|
|
116
|
+
let message = _this.getErrorMessage('notContains', fieldCaption, s);
|
|
116
117
|
return {result: false, message, type: 'error'};
|
|
117
118
|
}
|
|
118
119
|
}
|
|
@@ -131,7 +132,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
131
132
|
for (let i = 0; i < limitedValues.length; i++) {
|
|
132
133
|
if (fieldValue.indexOf(limitedValues[i]) >= 0) {
|
|
133
134
|
let s = limitedValues.join(' ');
|
|
134
|
-
let message =
|
|
135
|
+
let message = _this.getErrorMessage('notContains', fieldCaption, s);
|
|
135
136
|
return {result: false, message, type: 'error'};
|
|
136
137
|
}
|
|
137
138
|
}
|
|
@@ -149,7 +150,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
149
150
|
let limitedValues = (validationValue as string).split(' ');
|
|
150
151
|
for (let i = 0; i < limitedValues.length; i++) {
|
|
151
152
|
if (validator.contains(fieldValue, limitedValues[i])) {
|
|
152
|
-
let message =
|
|
153
|
+
let message = _this.getErrorMessage('notContains', fieldCaption,
|
|
153
154
|
validationValue);
|
|
154
155
|
return {result: false, message, type: 'error'};
|
|
155
156
|
}
|
|
@@ -166,7 +167,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
166
167
|
validator(fieldValue: string): ValidateResult {
|
|
167
168
|
if (fieldValue) {
|
|
168
169
|
if (/<[a-z]+[ ]*[/]?[ ]*>/gi.test(fieldValue)) {
|
|
169
|
-
let message =
|
|
170
|
+
let message = _this.getErrorMessage(validationName, fieldCaption);
|
|
170
171
|
return {result: false, message, type: 'error'};
|
|
171
172
|
}
|
|
172
173
|
}
|
|
@@ -193,7 +194,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
193
194
|
tag = tag.substring(1);
|
|
194
195
|
}
|
|
195
196
|
if (!tags.contains(tag.toLowerCase())) {
|
|
196
|
-
let message =
|
|
197
|
+
let message = _this.getErrorMessage(validationName, fieldCaption,
|
|
197
198
|
tags.join(', '));
|
|
198
199
|
return {result: false, message, type: 'error'};
|
|
199
200
|
}
|
|
@@ -217,7 +218,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
217
218
|
let value = fieldValue.toLowerCase();
|
|
218
219
|
for (let tag of tags) {
|
|
219
220
|
if (value.includes('<' + tag + '>') || value.includes('<' + tag + ' ')) {
|
|
220
|
-
let message =
|
|
221
|
+
let message = _this.getErrorMessage(validationName, fieldCaption,
|
|
221
222
|
tags.join(', '));
|
|
222
223
|
return {result: false, message, type: 'error'};
|
|
223
224
|
}
|
|
@@ -235,7 +236,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
235
236
|
validator(fieldValue: string): ValidateResult {
|
|
236
237
|
if (typeof fieldValue === 'string' && fieldValue) {
|
|
237
238
|
if (!validator.isEmail(fieldValue)) {
|
|
238
|
-
let message =
|
|
239
|
+
let message = _this.getErrorMessage(validationName, fieldCaption);
|
|
239
240
|
return {result: false, message, type: 'error'};
|
|
240
241
|
}
|
|
241
242
|
}
|
|
@@ -251,7 +252,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
251
252
|
rule = {
|
|
252
253
|
validator(fieldValue: string): ValidateResult {
|
|
253
254
|
if (validationValue) {
|
|
254
|
-
let message =
|
|
255
|
+
let message = _this.validateRegExp(validationName, fieldValue, fieldCaption);
|
|
255
256
|
if (message) {
|
|
256
257
|
return {result: false, message, type: 'error'};
|
|
257
258
|
}
|
|
@@ -277,7 +278,7 @@ export default class TnxTdValidator extends Validator {
|
|
|
277
278
|
if (message) {
|
|
278
279
|
message = fieldCaption + message;
|
|
279
280
|
} else {
|
|
280
|
-
message =
|
|
281
|
+
message = _this.getErrorMessage('regex', fieldCaption, '');
|
|
281
282
|
}
|
|
282
283
|
return {result: false, message, type: 'error'};
|
|
283
284
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tnxtd.css
|
|
3
|
+
*/
|
|
4
|
+
:root {
|
|
5
|
+
--border: 1px solid var(--td-component-border);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
color: var(--td-text-color-primary);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.border {
|
|
13
|
+
border: var(--border);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.bg-page {
|
|
17
|
+
background-color: var(--td-bg-color-page);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.bg-container {
|
|
21
|
+
background-color: var(--td-bg-color-container);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.bg-component {
|
|
25
|
+
background-color: var(--td-bg-color-component);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.text-brand,
|
|
29
|
+
.color-brand {
|
|
30
|
+
color: var(--td-text-color-brand);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.text-primary,
|
|
34
|
+
.color-primary {
|
|
35
|
+
color: var(--td-text-color-primary);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.text-secondary,
|
|
39
|
+
.color-secondary {
|
|
40
|
+
color: var(--td-text-color-secondary);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.text-placeholder,
|
|
44
|
+
.color-placeholder {
|
|
45
|
+
color: var(--td-text-color-placeholder);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.text-disabled,
|
|
49
|
+
.color-disabled {
|
|
50
|
+
color: var(--td-text-color-disabled);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.t-icon[theme="success"] {
|
|
54
|
+
color: var(--td-success-color);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.t-button--size-large .t-icon + .t-button__content:not(:empty) {
|
|
58
|
+
margin-left: 0.5rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.t-form__item--left .t-form__label,
|
|
62
|
+
.t-form__item--right .t-form__label {
|
|
63
|
+
height: 100%;
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
}
|
package/src/tdesign/tnxtd.ts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import TnxVue from '../tnxvue.ts';
|
|
2
2
|
import {Icon} from 'tdesign-icons-vue-next';
|
|
3
3
|
import Validator from './tnxtd-validator.ts';
|
|
4
|
+
import './tnxtd.css';
|
|
4
5
|
|
|
5
6
|
export {Validator};
|
|
6
7
|
|
|
7
8
|
export default class TnxTd extends TnxVue {
|
|
8
9
|
|
|
10
|
+
validator: Validator;
|
|
11
|
+
|
|
9
12
|
constructor(apiBaseUrl: string, id: string = 'tnxtd') {
|
|
10
13
|
super(apiBaseUrl, id);
|
|
11
14
|
|
|
12
15
|
this.foundations.Validator = Validator;
|
|
16
|
+
this.validator = new Validator();
|
|
13
17
|
|
|
14
18
|
Object.assign(this.components, {
|
|
15
19
|
Icon,
|
package/src/tnxvue-router.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
5
|
createRouter,
|
|
6
|
+
createWebHistory,
|
|
6
7
|
createWebHashHistory,
|
|
7
8
|
Router,
|
|
8
9
|
RouteRecordRaw,
|
|
@@ -17,12 +18,14 @@ import * as NetUtil from '../../tnxcore/src/util/net.ts';
|
|
|
17
18
|
export type RouteItem = {
|
|
18
19
|
caption: string;
|
|
19
20
|
path: string;
|
|
21
|
+
anonymous?: boolean; // 是否可以匿名访问
|
|
20
22
|
icon?: string;
|
|
21
23
|
page?: string;
|
|
22
24
|
component?: () => Promise<any>;
|
|
23
25
|
redirect?: never;
|
|
24
26
|
alias?: string;
|
|
25
27
|
subs?: RouteItem[];
|
|
28
|
+
parent?: RouteItem;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
function addRoute(routes: RouteRecordRaw[], superiorPath: string, item: RouteItem, fnImportPage?: (page: string) => Promise<any>): void {
|
|
@@ -87,21 +90,51 @@ function getCurrentRoute(router: Router): RouteLocationNormalizedLoadedGeneric {
|
|
|
87
90
|
return router.currentRoute.value;
|
|
88
91
|
}
|
|
89
92
|
|
|
93
|
+
function findItemByPath(parent: RouteItem, items: RouteItem[], path: string): RouteItem | null {
|
|
94
|
+
for (const item of items) {
|
|
95
|
+
if (item.path === path) {
|
|
96
|
+
item.parent = parent;
|
|
97
|
+
return item;
|
|
98
|
+
}
|
|
99
|
+
if (item.subs) {
|
|
100
|
+
const found = findItemByPath(item, item.subs, path);
|
|
101
|
+
if (found) {
|
|
102
|
+
return found;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export class RouteMenu {
|
|
110
|
+
|
|
111
|
+
items: RouteItem[];
|
|
112
|
+
|
|
113
|
+
constructor(items: RouteItem[]) {
|
|
114
|
+
this.items = items;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
findItem(path: string): RouteItem | null {
|
|
118
|
+
return findItemByPath(null, this.items, path);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
90
123
|
export type VueRouter = Router & {
|
|
91
124
|
history: RouterHistory;
|
|
92
125
|
prev?: RouteLocationNormalizedLoaded;
|
|
93
|
-
$beforeLeaveHandlers: Record<string, (to: RouteLocationNormalized) => boolean
|
|
126
|
+
$beforeLeaveHandlers: Record<string, (to: RouteLocationNormalized) => boolean | Promise<boolean>>;
|
|
94
127
|
beforeLeave: (handler: (to: RouteLocationNormalized) => boolean) => void;
|
|
95
128
|
pushState: (path: string) => boolean;
|
|
96
129
|
replaceState: (path: string) => boolean;
|
|
97
130
|
backTo: (path?: string) => void;
|
|
98
131
|
}
|
|
99
132
|
|
|
100
|
-
export default function (items: RouteItem[], fnImportPage?: (page: string) => Promise<any>): VueRouter {
|
|
133
|
+
export default function (items: RouteItem[], useHashHistory = true, fnImportPage?: (page: string) => Promise<any>): VueRouter {
|
|
101
134
|
const routes: RouteRecordRaw[] = [];
|
|
102
135
|
applyItemsToRoutes('', items, routes, fnImportPage);
|
|
103
136
|
|
|
104
|
-
const routerHistory = createWebHashHistory();
|
|
137
|
+
const routerHistory = useHashHistory ? createWebHashHistory() : createWebHistory();
|
|
105
138
|
const router: VueRouter = createRouter({
|
|
106
139
|
history: routerHistory,
|
|
107
140
|
routes,
|
|
@@ -121,7 +154,7 @@ export default function (items: RouteItem[], fnImportPage?: (page: string) => Pr
|
|
|
121
154
|
|
|
122
155
|
// 注册离开页面前事件处理支持
|
|
123
156
|
router.$beforeLeaveHandlers = {};
|
|
124
|
-
router.beforeLeave = function (handler: (to: RouteLocationNormalized) => boolean): void {
|
|
157
|
+
router.beforeLeave = function (handler: (to: RouteLocationNormalized) => boolean | Promise<boolean>): void {
|
|
125
158
|
let $route = getCurrentRoute(router);
|
|
126
159
|
let path = $route.path;
|
|
127
160
|
router.$beforeLeaveHandlers[path] = handler;
|
|
@@ -130,8 +163,28 @@ export default function (items: RouteItem[], fnImportPage?: (page: string) => Pr
|
|
|
130
163
|
router.beforeEach((to: RouteLocationNormalized, from: RouteLocationNormalizedLoaded, next: NavigationGuardNext): void => {
|
|
131
164
|
let allow = true;
|
|
132
165
|
let beforeLeaveHandler = router.$beforeLeaveHandlers[from.path];
|
|
166
|
+
if (!beforeLeaveHandler) {
|
|
167
|
+
let toItem = findItemByPath(null, items, to.path);
|
|
168
|
+
if (toItem && !toItem.anonymous) {
|
|
169
|
+
beforeLeaveHandler = async (to: RouteLocationNormalized): Promise<boolean> => {
|
|
170
|
+
let logined = await window.tnx.auth.isLogined();
|
|
171
|
+
if (!logined) {
|
|
172
|
+
window.tnx.api.toLogin(to.path);
|
|
173
|
+
}
|
|
174
|
+
return logined;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
133
178
|
if (beforeLeaveHandler) {
|
|
134
|
-
|
|
179
|
+
let result = beforeLeaveHandler(to);
|
|
180
|
+
if (result instanceof Promise) {
|
|
181
|
+
result.then((allowed: boolean): void => {
|
|
182
|
+
if (allowed) {
|
|
183
|
+
next();
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return;
|
|
187
|
+
} else if (result === false) {
|
|
135
188
|
allow = false;
|
|
136
189
|
}
|
|
137
190
|
}
|