@truenewx/tnxvue3 3.4.3 → 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.
Files changed (47) hide show
  1. package/package.json +12 -6
  2. package/src/bootstrap-vue/dialog/Dialog.vue +22 -10
  3. package/src/element-plus/aj-captcha/api/index.js +2 -2
  4. package/src/element-plus/avatar/Avatar.vue +4 -27
  5. package/src/element-plus/date-picker/DatePicker.vue +8 -9
  6. package/src/element-plus/dialog/Dialog.vue +34 -22
  7. package/src/element-plus/drawer/Drawer.vue +22 -5
  8. package/src/element-plus/edit-table/EditTable.vue +10 -10
  9. package/src/element-plus/enum-select/EnumSelect.vue +30 -30
  10. package/src/element-plus/enum-view/EnumView.vue +1 -3
  11. package/src/element-plus/fetch-cascader/FetchCascader.vue +4 -4
  12. package/src/element-plus/fetch-select/FetchSelect.vue +3 -3
  13. package/src/element-plus/fetch-tags/FetchTags.vue +1 -1
  14. package/src/element-plus/fss-upload/FssUpload.vue +76 -115
  15. package/src/element-plus/fss-view/FssView.vue +28 -30
  16. package/src/element-plus/icon/Icon.vue +3 -0
  17. package/src/element-plus/query-form/QueryForm.vue +3 -3
  18. package/src/element-plus/query-table/QueryTable.vue +12 -12
  19. package/src/element-plus/region-cascader/RegionCascader.vue +3 -3
  20. package/src/element-plus/select/Select.vue +56 -56
  21. package/src/element-plus/submit-form/SubmitForm.vue +5 -5
  22. package/src/element-plus/tnxel-validator.ts +347 -0
  23. package/src/element-plus/tnxel.css +0 -8
  24. package/src/element-plus/tnxel.ts +561 -0
  25. package/src/element-plus/transfer/Transfer.vue +2 -2
  26. package/src/element-plus/upload/Upload.vue +68 -70
  27. package/src/tdesign/desktop/tnxtdd.ts +5 -5
  28. package/src/tdesign/mobile/calendar/Calendar.vue +121 -0
  29. package/src/tdesign/mobile/date-time-picker/DateTimePicker.vue +147 -0
  30. package/src/tdesign/mobile/dialog/Dialog.vue +179 -0
  31. package/src/tdesign/mobile/dialog/DialogContent.vue +13 -0
  32. package/src/tdesign/mobile/drawer/Drawer.vue +176 -0
  33. package/src/tdesign/mobile/drawer/DrawerContent.vue +13 -0
  34. package/src/tdesign/mobile/enum-select/EnumSelect.vue +160 -0
  35. package/src/tdesign/mobile/popup/Popup.vue +106 -0
  36. package/src/tdesign/mobile/region-picker/RegionPicker.vue +223 -0
  37. package/src/tdesign/mobile/select/Select.vue +478 -0
  38. package/src/tdesign/mobile/slide-radio-group/SlideRadioGroup.vue +392 -0
  39. package/src/tdesign/mobile/tnxtdm.css +132 -0
  40. package/src/tdesign/mobile/tnxtdm.ts +310 -7
  41. package/src/tdesign/{foundation/validator.ts → tnxtd-validator.ts} +18 -17
  42. package/src/tdesign/tnxtd.css +66 -0
  43. package/src/tdesign/tnxtd.ts +10 -7
  44. package/src/tnxvue-router.ts +65 -18
  45. package/src/tnxvue.ts +71 -31
  46. package/tsconfig.json +33 -19
  47. package/src/element-plus/tnxel.js +0 -598
@@ -0,0 +1,176 @@
1
+ <template>
2
+ <tnxtdm-popup
3
+ class="tnxtdm-drawer"
4
+ v-model="visible"
5
+ :placement="placement"
6
+ :title="title"
7
+ @closed="onClosed"
8
+ >
9
+ <template #default>
10
+ <div class="tnxtdm-drawer-body">
11
+ <div v-if="content" v-html="content"></div>
12
+ <tnxtdm-drawer-content ref="content" v-bind="contentProps" v-else/>
13
+ </div>
14
+ <div class="tnxtdm-drawer-footer" v-if="buttons?.length">
15
+ <t-button v-for="(button, index) in buttons" :key="index" :theme="button.type || 'default'"
16
+ :loading="buttonLoadings[index]" @click="btnClick(index)" block>
17
+ {{ button.caption || button.text }}
18
+ </t-button>
19
+ </div>
20
+ </template>
21
+ </tnxtdm-popup>
22
+ </template>
23
+
24
+ <script>
25
+ import DrawerContent from './DrawerContent.vue';
26
+ import Popup from '../popup/Popup.vue';
27
+
28
+ export default {
29
+ name: 'TnxtdmDrawer',
30
+ components: {
31
+ 'tnxtdm-drawer-content': DrawerContent,
32
+ 'tnxtdm-popup': Popup,
33
+ },
34
+ props: {
35
+ id: {
36
+ type: String,
37
+ default: () => window.tnx.util.string.uuid32(),
38
+ },
39
+ modelValue: Boolean,
40
+ container: String,
41
+ title: String,
42
+ content: String,
43
+ contentProps: Object,
44
+ buttons: Array,
45
+ theme: String,
46
+ placement: {
47
+ type: String, // 'top' | 'left' | 'right' | 'bottom' | 'center'
48
+ default: 'bottom', // 默认底部弹出
49
+ },
50
+ },
51
+ emits: ['update:modelValue', 'shown', 'closed'],
52
+ data() {
53
+ return {
54
+ visible: false,
55
+ initialized: false,
56
+ options: {
57
+ modal: true,
58
+ onShown: undefined,
59
+ onClosed: undefined,
60
+ beforeClose: undefined,
61
+ },
62
+ buttonLoadings: [],
63
+ };
64
+ },
65
+ watch: {
66
+ modelValue(val) {
67
+ this.visible = val;
68
+ },
69
+ visible(val) {
70
+ if (this.initialized) {
71
+ this.$emit('update:modelValue', val);
72
+ }
73
+ }
74
+ },
75
+ mounted() {
76
+ this.$nextTick(() => {
77
+ this.initialized = true;
78
+ this.visible = this.modelValue;
79
+ if (this.$refs.content && !this.$refs.content.close) {
80
+ this.$refs.content.close = () => {
81
+ this.close();
82
+ }
83
+ }
84
+
85
+ if (typeof this.options.onShown === 'function') {
86
+ this.options.onShown.call(this);
87
+ } else {
88
+ this.$emit('shown');
89
+ }
90
+ });
91
+ },
92
+ methods: {
93
+ btnClick(index) {
94
+ const button = this.buttons[index];
95
+ if (button) {
96
+ let click = button.click;
97
+ if (typeof click === 'string') {
98
+ if (typeof this.$refs.content[click] === 'function') {
99
+ click = this.$refs.content[click];
100
+ } else {
101
+ console.error(`Method '${click}' not found in component:`, this.$refs.content);
102
+ click = null;
103
+ }
104
+ }
105
+
106
+ if (typeof click === 'function') {
107
+ let result = click.call(this.$refs.content, this.close);
108
+ if (result === 'loading') {
109
+ this.buttonLoadings[index] = true;
110
+ return;
111
+ }
112
+ if (result === false) {
113
+ return;
114
+ }
115
+ }
116
+ }
117
+ this.close();
118
+ },
119
+ close() {
120
+ return new Promise((resolve) => {
121
+ this.beforeClose(() => {
122
+ const originalOnClosed = this.options.onClosed;
123
+ this.options.onClosed = window.tnx.util.function.around(originalOnClosed, function (onClosed) {
124
+ if (onClosed) {
125
+ onClosed();
126
+ }
127
+ resolve();
128
+ });
129
+ this.visible = false;
130
+ });
131
+ });
132
+ },
133
+ beforeClose(done) {
134
+ try {
135
+ if (typeof this.options.beforeClose === 'function') {
136
+ if (this.options.beforeClose.call(this.$refs.content) === false) {
137
+ return;
138
+ }
139
+ }
140
+ done();
141
+ } catch (e) {
142
+ console.error(e);
143
+ }
144
+ },
145
+ onClosed() {
146
+ if (typeof this.options.onClosed === 'function') {
147
+ this.options.onClosed.call(this.$refs.content);
148
+ } else {
149
+ this.$emit('closed');
150
+ }
151
+ }
152
+ }
153
+ }
154
+ </script>
155
+
156
+ <style>
157
+ .tnxtdm-drawer {
158
+ .tnxtdm-drawer-body {
159
+ flex: 1;
160
+ overflow-y: auto;
161
+ padding: 16px;
162
+ }
163
+
164
+ .tnxtdm-drawer-footer {
165
+ padding: 12px 1rem calc(12px + env(safe-area-inset-bottom, 0));
166
+ border-top: 1px solid var(--td-border-level-1-color);
167
+ display: flex;
168
+ flex-direction: row-reverse;
169
+
170
+ .t-button {
171
+ width: fit-content;
172
+ margin-left: 12px;
173
+ }
174
+ }
175
+ }
176
+ </style>
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <div></div>
3
+ </template>
4
+
5
+ <script>
6
+ export default {
7
+ components: {},
8
+ data() {
9
+ return {};
10
+ },
11
+ methods: {}
12
+ }
13
+ </script>
@@ -0,0 +1,160 @@
1
+ <template>
2
+ <tnxtdm-select ref="select"
3
+ v-model="model"
4
+ :id="id"
5
+ :selector="selector"
6
+ :items="items"
7
+ value-name="key" text-name="caption" index-name="searchIndex"
8
+ :default-value="defaultValue"
9
+ :empty="empty"
10
+ :empty-value="emptyValue"
11
+ :placeholder="placeholder"
12
+ :width="width"
13
+ :disabled="isDisabled"
14
+ :filterable="filterable"
15
+ :theme="theme"
16
+ :size="size"
17
+ :tag-click="tagClick"
18
+ :change="change">
19
+ <template #option="{item}" v-if="$slots.option">
20
+ <slot name="option" :item="item"></slot>
21
+ </template>
22
+ </tnxtdm-select>
23
+ </template>
24
+
25
+ <script>
26
+ import Select, {isMultiSelector} from '../select/Select.vue';
27
+
28
+ export default {
29
+ name: 'TnxtdmEnumSelect',
30
+ components: {
31
+ 'tnxtdm-select': Select,
32
+ },
33
+ props: {
34
+ id: [Number, String],
35
+ modelValue: [String, Number, Boolean, Array],
36
+ selector: String,
37
+ type: {
38
+ type: String,
39
+ required: true,
40
+ },
41
+ subtype: String,
42
+ defaultValue: String,
43
+ empty: {
44
+ type: [Boolean, String],
45
+ default: false,
46
+ },
47
+ emptyValue: {
48
+ type: [String, Number, Boolean, Array],
49
+ default: '',
50
+ },
51
+ placeholder: String,
52
+ width: String,
53
+ disabled: Boolean,
54
+ tagClick: Function,
55
+ change: Function,
56
+ grouped: {
57
+ type: Boolean,
58
+ default: false,
59
+ },
60
+ filterable: Boolean,
61
+ theme: String,
62
+ size: String,
63
+ },
64
+ emits: ['update:modelValue'],
65
+ data() {
66
+ return {
67
+ model: this.modelValue,
68
+ items: null,
69
+ formDisabled: false,
70
+ };
71
+ },
72
+ computed: {
73
+ isDisabled() {
74
+ return this.disabled || this.formDisabled;
75
+ },
76
+ },
77
+ watch: {
78
+ model(value) {
79
+ this.$emit('update:modelValue', value);
80
+ },
81
+ modelValue() {
82
+ this.initModel();
83
+ },
84
+ type() {
85
+ this.init();
86
+ },
87
+ subtype() {
88
+ this.init();
89
+ }
90
+ },
91
+ mounted() {
92
+ this.init();
93
+ this.initFormDisabled();
94
+ },
95
+ methods: {
96
+ initFormDisabled() {
97
+ let parent = this.$parent;
98
+ while (parent) {
99
+ if (parent.$options && (parent.$options.name === 't-form' || parent.$options.name === 'TForm')) {
100
+ this.$watch(() => parent.disabled || (parent.$props && parent.$props.disabled), (val) => {
101
+ this.formDisabled = val;
102
+ }, {immediate: true});
103
+ break;
104
+ }
105
+ parent = parent.$parent;
106
+ }
107
+ },
108
+ init() {
109
+ if (typeof this.type === 'string') {
110
+ if (this.type.toLowerCase() === 'boolean') {
111
+ this.items = [{
112
+ key: true,
113
+ caption: true.toText(),
114
+ }, {
115
+ key: false,
116
+ caption: false.toText(),
117
+ }];
118
+ this.initModel();
119
+ } else {
120
+ if (window.tnx && window.tnx.meta) {
121
+ window.tnx.meta.resolveEnumItems(this.type, this.subtype).then((items) => {
122
+ this.items = items;
123
+ this.initModel();
124
+ });
125
+ }
126
+ }
127
+ }
128
+ },
129
+ initModel() {
130
+ let oldModel = this.model;
131
+ this.model = this.modelValue;
132
+ if (isMultiSelector(this.selector)) {
133
+ return;
134
+ }
135
+ if ((this.model === undefined || this.model === null) && !this.empty && this.items && this.items.length) {
136
+ let item = this.items[0];
137
+ this.model = item.key;
138
+ if (this.model !== oldModel && this.change) {
139
+ this.change(item);
140
+ }
141
+ }
142
+ },
143
+ getText(value) {
144
+ if (this.$refs.select) {
145
+ return this.$refs.select.getText(value);
146
+ }
147
+ return undefined;
148
+ },
149
+ disableItem(itemKey, disabled, reverseOther) {
150
+ if (this.$refs.select) {
151
+ this.$refs.select.disableItem(itemKey, disabled, reverseOther);
152
+ }
153
+ },
154
+ }
155
+ }
156
+ </script>
157
+
158
+ <style>
159
+
160
+ </style>
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <slot name="trigger" :show="open" :visible="visible"></slot>
3
+ <t-popup
4
+ class="tnxtdm-popup"
5
+ v-model="visible"
6
+ :placement="placement"
7
+ :destroy-on-close="true"
8
+ v-bind="$attrs"
9
+ >
10
+ <div class="tnxtdm-popup-header" v-if="title || $slots.left || $slots.right">
11
+ <div class="tnxtdm-popup-header-left">
12
+ <slot name="left">
13
+ <t-icon name="blank" size="24px"/>
14
+ </slot>
15
+ </div>
16
+ <div class="tnxtdm-popup-header-title">
17
+ <slot name="title">{{ title }}</slot>
18
+ </div>
19
+ <div class="tnxtdm-popup-header-right">
20
+ <slot name="right">
21
+ <t-icon class="text-placeholder" name="close" size="24px" @click="close"/>
22
+ </slot>
23
+ </div>
24
+ </div>
25
+ <div class="tnxtdm-popup-content">
26
+ <slot></slot>
27
+ </div>
28
+ </t-popup>
29
+ </template>
30
+
31
+ <script>
32
+ export default {
33
+ name: 'TnxtdmPopup',
34
+ props: {
35
+ modelValue: Boolean,
36
+ title: String,
37
+ placement: {
38
+ type: String,
39
+ default: 'bottom',
40
+ },
41
+ },
42
+ data() {
43
+ return {
44
+ visible: false,
45
+ }
46
+ },
47
+ watch: {
48
+ modelValue(val) {
49
+ this.visible = val;
50
+ },
51
+ visible(val) {
52
+ this.$emit('update:modelValue', val);
53
+ },
54
+ },
55
+ emits: ['update:modelValue', 'close'],
56
+ mounted() {
57
+ this.visible = this.modelValue;
58
+ },
59
+ methods: {
60
+ open() {
61
+ this.visible = true;
62
+ },
63
+ close() {
64
+ this.visible = false;
65
+ this.$emit('close');
66
+ },
67
+ },
68
+ };
69
+ </script>
70
+
71
+ <style>
72
+ .tnxtdm-popup {
73
+ border-radius: 12px 12px 0 0;
74
+ max-height: 80vh;
75
+ display: flex;
76
+ flex-direction: column;
77
+ }
78
+
79
+ .tnxtdm-popup .tnxtdm-popup-header {
80
+ display: flex;
81
+ justify-content: space-between;
82
+ align-items: center;
83
+ padding: 12px 1rem;
84
+ border-bottom: 1px solid var(--td-border-level-1-color);
85
+ }
86
+
87
+ .tnxtdm-popup .tnxtdm-popup-header .tnxtdm-popup-header-title {
88
+ font-size: 1rem;
89
+ font-weight: 600;
90
+ color: var(--td-text-color-primary);
91
+ flex: 1;
92
+ text-align: center;
93
+ }
94
+
95
+ .tnxtdm-popup .tnxtdm-popup-header .tnxtdm-popup-header-left,
96
+ .tnxtdm-popup .tnxtdm-popup-header .tnxtdm-popup-header-right {
97
+ display: flex;
98
+ align-items: center;
99
+ min-width: 24px;
100
+ }
101
+
102
+ .tnxtdm-popup .tnxtdm-popup-content {
103
+ flex: 1;
104
+ overflow-y: auto;
105
+ }
106
+ </style>
@@ -0,0 +1,223 @@
1
+ <template>
2
+ <TnxtdmPopup class="tnxtdm-region-picker" v-model="pickerVisible">
3
+ <template #trigger="{ show }">
4
+ <div class="flex-v-center" :class="triggerClass">
5
+ <div @click="show">{{ displayValue || placeholder }}</div>
6
+ <t-icon
7
+ class="ml-3 text-secondary"
8
+ name="close-circle-filled"
9
+ @click="onClear"
10
+ v-if="empty && displayValue"
11
+ />
12
+ <t-icon
13
+ class="ml-3 text-secondary"
14
+ :name="iconName"
15
+ @click="show"
16
+ v-else-if="iconName"
17
+ />
18
+ </div>
19
+ </template>
20
+ <t-picker
21
+ v-if="pickerVisible"
22
+ v-model="pickerValue"
23
+ :title="title"
24
+ :columns="pickerColumns"
25
+ :keys="{ label: 'caption', value: 'code' }"
26
+ @pick="onPickerPick"
27
+ @confirm="onPickerConfirm"
28
+ @cancel="onPickerCancel"
29
+ >
30
+ </t-picker>
31
+ </TnxtdmPopup>
32
+ </template>
33
+
34
+ <script>
35
+ import TnxtdmPopup from '../popup/Popup.vue';
36
+
37
+ export default {
38
+ name: 'TnxtdmRegionPicker',
39
+ components: {TnxtdmPopup},
40
+ props: {
41
+ modelValue: {
42
+ type: String,
43
+ required: true,
44
+ },
45
+ code: {
46
+ type: String,
47
+ default: 'CN',
48
+ },
49
+ level: {
50
+ type: Number,
51
+ default: 3,
52
+ },
53
+ title: {
54
+ type: String,
55
+ default: '地区',
56
+ },
57
+ triggerClass: String,
58
+ placeholder: {
59
+ type: String,
60
+ default: '请选择地区',
61
+ },
62
+ empty: [String, Boolean],
63
+ iconName: {
64
+ type: String,
65
+ default: 'location',
66
+ },
67
+ },
68
+ data() {
69
+ return {
70
+ region: null,
71
+ displayValue: '',
72
+ pickerVisible: false,
73
+ pickerValue: [],
74
+ pickerColumns: [],
75
+ };
76
+ },
77
+ watch: {
78
+ modelValue() {
79
+ this.initPicker();
80
+ this.initDisplay();
81
+ },
82
+ pickerVisible(val) {
83
+ if (val) {
84
+ this.initPicker();
85
+ }
86
+ },
87
+ },
88
+ emits: ['update:modelValue', 'change'],
89
+ async mounted() {
90
+ this.region = await window.tnx.meta.loadRegion(this.code, this.level);
91
+ this.initPicker();
92
+ this.initDisplay();
93
+ },
94
+ methods: {
95
+ initDisplay() {
96
+ if (!this.region || !this.modelValue) {
97
+ this.displayValue = '';
98
+ return;
99
+ }
100
+ const path = this.getPath(this.region.subs, this.modelValue);
101
+ if (path && path.length) {
102
+ this.displayValue = path.map(item => item.caption).join(' / ');
103
+ } else {
104
+ this.displayValue = '';
105
+ }
106
+ },
107
+ initPicker() {
108
+ if (!this.region) {
109
+ return;
110
+ }
111
+
112
+ let path = [];
113
+ if (this.modelValue) {
114
+ path = this.getPath(this.region.subs, this.modelValue) || [];
115
+ }
116
+
117
+ this.pickerColumns = [];
118
+ this.pickerValue = [];
119
+
120
+ let currentOptions = this.region.subs || [];
121
+
122
+ for (let i = 0; i < this.level; i++) {
123
+ this.pickerColumns.push(currentOptions);
124
+
125
+ let selectedCode;
126
+ if (i < path.length) {
127
+ selectedCode = path[i].code;
128
+ } else {
129
+ if (currentOptions.length > 0) {
130
+ selectedCode = currentOptions[0].code;
131
+ }
132
+ }
133
+
134
+ if (selectedCode) {
135
+ this.pickerValue.push(selectedCode);
136
+ let selectedOption = currentOptions.find(opt => opt.code === selectedCode);
137
+ if (selectedOption && selectedOption.subs) {
138
+ currentOptions = selectedOption.subs;
139
+ } else {
140
+ currentOptions = [];
141
+ }
142
+ } else {
143
+ this.pickerValue.push(null);
144
+ currentOptions = [];
145
+ }
146
+ }
147
+ },
148
+ getPath(options, code) {
149
+ if (!options) {
150
+ return null;
151
+ }
152
+ for (let item of options) {
153
+ if (item.code === code) {
154
+ return [item];
155
+ }
156
+ if (item.subs) {
157
+ let subPath = this.getPath(item.subs, code);
158
+ if (subPath) {
159
+ return [item, ...subPath];
160
+ }
161
+ }
162
+ }
163
+ return null;
164
+ },
165
+ onPickerPick(values, {column, index}) {
166
+ const newColumns = [];
167
+ const newValues = [];
168
+
169
+ for (let i = 0; i < this.pickerColumns.length; i++) {
170
+ if (i <= column) {
171
+ newColumns.push(this.pickerColumns[i]);
172
+ newValues.push(values[i]);
173
+ } else {
174
+ let region = newColumns[i - 1][index];
175
+ let subs = region.subs || [];
176
+ if (subs.length > 0) {
177
+ newColumns.push(subs);
178
+ if (subs.length > 0) {
179
+ newValues.push(subs[0].code);
180
+ }
181
+ } else if (newColumns.length < this.level) {
182
+ newColumns.push([]);
183
+ newValues.push(null);
184
+ }
185
+ }
186
+ }
187
+
188
+ this.pickerColumns = newColumns;
189
+ this.pickerValue = newValues;
190
+ },
191
+ onPickerConfirm() {
192
+ this.pickerVisible = false;
193
+ this.onConfirm();
194
+ },
195
+ onPickerCancel() {
196
+ this.pickerVisible = false;
197
+ },
198
+ onConfirm() {
199
+ let code = null;
200
+ for (let i = this.pickerValue.length - 1; i >= 0; i--) {
201
+ if (this.pickerValue[i]) {
202
+ code = this.pickerValue[i];
203
+ break;
204
+ }
205
+ }
206
+
207
+ if (code) {
208
+ this.$emit('update:modelValue', code);
209
+ this.$emit('change', code);
210
+ }
211
+ },
212
+ onClear() {
213
+ this.$emit('update:modelValue', '');
214
+ },
215
+ open() {
216
+ this.pickerVisible = true;
217
+ },
218
+ }
219
+ }
220
+ </script>
221
+
222
+ <style>
223
+ </style>