@truenewx/tnxvue3 3.0.5 → 3.0.7
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/button/Button.vue +3 -3
- package/src/bootstrap-vue/cascader/Cascader.vue +491 -0
- package/src/bootstrap-vue/dialog/Dialog.vue +164 -158
- package/src/bootstrap-vue/enum-select/EnumSelect.vue +1 -3
- package/src/bootstrap-vue/form/Form.vue +56 -43
- package/src/bootstrap-vue/form/FormGroup.vue +26 -1
- package/src/bootstrap-vue/{loading/Loading.vue → loading-icon/LoadingIcon.vue} +2 -2
- package/src/bootstrap-vue/loading-overlay/LoadingOverlay.vue +60 -0
- package/src/bootstrap-vue/query-form/QueryForm.vue +41 -0
- package/src/bootstrap-vue/region-cascader/RegionCascader.vue +119 -0
- package/src/bootstrap-vue/select/Select.vue +32 -14
- package/src/bootstrap-vue/tags-input/TagsInput.vue +64 -0
- package/src/bootstrap-vue/tnxbsv.css +47 -7
- package/src/bootstrap-vue/tnxbsv.js +123 -2
- package/src/element-plus/tnxel.js +2 -3
- package/src/tnxvue.js +2 -2
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<TnxbsvForm class="tnxbsv-query-form" :model="params" inline>
|
|
3
|
+
<slot></slot>
|
|
4
|
+
<slot name="actions">
|
|
5
|
+
<div class="tnxbsv-query-form-actions">
|
|
6
|
+
<TnxbsvButton variant="outline-primary" icon="bi bi-search" @click="query" v-if="query">
|
|
7
|
+
{{ queryText }}
|
|
8
|
+
</TnxbsvButton>
|
|
9
|
+
</div>
|
|
10
|
+
</slot>
|
|
11
|
+
</TnxbsvForm>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
import TnxbsvForm from '../form/Form.vue';
|
|
16
|
+
import TnxbsvButton from '../button/Button.vue';
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
name: 'TnxbsvQueryForm',
|
|
20
|
+
components: {TnxbsvForm, TnxbsvButton},
|
|
21
|
+
props: {
|
|
22
|
+
params: {
|
|
23
|
+
type: Object,
|
|
24
|
+
default: () => ({}),
|
|
25
|
+
},
|
|
26
|
+
query: Function,
|
|
27
|
+
queryText: {
|
|
28
|
+
type: String,
|
|
29
|
+
default: '查询',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
data() {
|
|
33
|
+
return {};
|
|
34
|
+
},
|
|
35
|
+
methods: {}
|
|
36
|
+
}
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<style>
|
|
40
|
+
|
|
41
|
+
</style>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<TnxbsvCascader v-model="model"
|
|
3
|
+
:options="region.subs"
|
|
4
|
+
:props="{
|
|
5
|
+
value: 'code',
|
|
6
|
+
label: 'caption',
|
|
7
|
+
children: 'subs',
|
|
8
|
+
}"
|
|
9
|
+
:placeholder="placeholder"
|
|
10
|
+
:disabled="disabled"
|
|
11
|
+
:clearable="empty"
|
|
12
|
+
:parent-selectable="parentSelectable"
|
|
13
|
+
/>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script>
|
|
17
|
+
import TnxbsvCascader from '../cascader/Cascader.vue';
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
name: 'TnxbsvRegionCascader',
|
|
21
|
+
components: {TnxbsvCascader},
|
|
22
|
+
props: {
|
|
23
|
+
modelValue: String,
|
|
24
|
+
scope: {
|
|
25
|
+
type: String,
|
|
26
|
+
default: () => 'CN',
|
|
27
|
+
},
|
|
28
|
+
maxLevel: {
|
|
29
|
+
type: [Number, String],
|
|
30
|
+
default: 3,
|
|
31
|
+
},
|
|
32
|
+
minLevel: {
|
|
33
|
+
type: [Number, String],
|
|
34
|
+
default: 3,
|
|
35
|
+
},
|
|
36
|
+
empty: {
|
|
37
|
+
type: Boolean,
|
|
38
|
+
default: false,
|
|
39
|
+
},
|
|
40
|
+
placeholder: String,
|
|
41
|
+
disabled: Boolean,
|
|
42
|
+
change: Function, // 选中值变化后的事件处理函数,由于比element的change事件传递更多参数,所以以prop的形式指定,以尽量节省性能
|
|
43
|
+
app: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: () => window.tnx.componentDefaultApp,
|
|
46
|
+
},
|
|
47
|
+
parentSelectable: Boolean,
|
|
48
|
+
},
|
|
49
|
+
data() {
|
|
50
|
+
return {
|
|
51
|
+
model: this.modelValue,
|
|
52
|
+
region: {},
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
watch: {
|
|
56
|
+
model(value) {
|
|
57
|
+
this.$emit('update:modelValue', value);
|
|
58
|
+
this.triggerChange(value);
|
|
59
|
+
},
|
|
60
|
+
modelValue() {
|
|
61
|
+
this.model = this.getModel();
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
mounted() {
|
|
65
|
+
window.tnx.app.rpc.loadRegion(this.scope, parseInt(this.maxLevel), region => {
|
|
66
|
+
this.region = region;
|
|
67
|
+
this.model = this.getModel();
|
|
68
|
+
}, {
|
|
69
|
+
app: this.app,
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
methods: {
|
|
73
|
+
triggerChange(value) {
|
|
74
|
+
if (this.change) {
|
|
75
|
+
let item = this.getItem(this.region.subs, value);
|
|
76
|
+
this.change(item);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
getItem(items, value) {
|
|
80
|
+
if (items && value !== undefined) {
|
|
81
|
+
for (let item of items) {
|
|
82
|
+
if (item.code === value) {
|
|
83
|
+
return item;
|
|
84
|
+
}
|
|
85
|
+
let sub = this.getItem(item.subs, value);
|
|
86
|
+
if (sub) {
|
|
87
|
+
return sub;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
},
|
|
93
|
+
getModel() {
|
|
94
|
+
if (this.region) {
|
|
95
|
+
let items = this.region.subs;
|
|
96
|
+
if (items && items.length) {
|
|
97
|
+
let item = this.getItem(items, this.modelValue);
|
|
98
|
+
if (item) {
|
|
99
|
+
return item.code;
|
|
100
|
+
} else { // 如果当前值找不到匹配的选项,则需要考虑是设置为空还是默认选项
|
|
101
|
+
if (!this.empty) { // 如果不能为空,则默认选中第一个叶子节点选项
|
|
102
|
+
let firstItem = items[0];
|
|
103
|
+
while (firstItem.subs && firstItem.subs.length) {
|
|
104
|
+
firstItem = firstItem.subs[0];
|
|
105
|
+
}
|
|
106
|
+
return firstItem ? firstItem.code : null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
</script>
|
|
116
|
+
|
|
117
|
+
<style>
|
|
118
|
+
|
|
119
|
+
</style>
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
|
+
<BFormRadioGroup class="tnxbsv-select tnxbsv-radio-group"
|
|
3
|
+
v-model="model"
|
|
4
|
+
:options="items"
|
|
5
|
+
:value-field="valueName"
|
|
6
|
+
:text-field="textName"
|
|
7
|
+
:buttons="selector === 'radio-button'"
|
|
8
|
+
button-variant="outline-primary"
|
|
9
|
+
v-if="items && (selector==='radio' || selector === 'radio-button')"/>
|
|
2
10
|
<BDropdown class="tnxbsv-select tnxbsv-dropdown"
|
|
3
11
|
:key="groupKey"
|
|
4
12
|
:text="currentText"
|
|
5
13
|
:variant="theme"
|
|
6
14
|
:size="size"
|
|
7
|
-
v-if="selector==='dropdown'">
|
|
8
|
-
<BDropdownItem :active="isSelected(emptyValue)" @click="select(emptyValue)" v-if="empty">
|
|
15
|
+
v-else-if="selector==='dropdown'">
|
|
16
|
+
<BDropdownItem class="empty-item" :active="isSelected(emptyValue)" @click="select(emptyValue)" v-if="empty">
|
|
9
17
|
<span>{{ emptyText || ' ' }}</span>
|
|
10
18
|
</BDropdownItem>
|
|
11
19
|
<template v-if="items">
|
|
@@ -21,10 +29,11 @@
|
|
|
21
29
|
</BDropdownItem>
|
|
22
30
|
</template>
|
|
23
31
|
<BDropdownItem v-else>
|
|
24
|
-
<
|
|
32
|
+
<LoadingIcon/>
|
|
25
33
|
</BDropdownItem>
|
|
26
34
|
</BDropdown>
|
|
27
35
|
<BFormSelect class="tnxbsv-select"
|
|
36
|
+
:class="{'is-empty': model === emptyValue}"
|
|
28
37
|
v-model="model"
|
|
29
38
|
:key="groupKey"
|
|
30
39
|
:variant="theme"
|
|
@@ -32,13 +41,9 @@
|
|
|
32
41
|
:value-field="valueName"
|
|
33
42
|
:text-field="textName"
|
|
34
43
|
:size="size"
|
|
35
|
-
:required="!empty"
|
|
36
44
|
v-else-if="items">
|
|
37
|
-
<template #default>
|
|
38
|
-
{{ currentText || placeholder }}
|
|
39
|
-
</template>
|
|
40
45
|
<template #first v-if="empty">
|
|
41
|
-
<BFormSelectOption :value="emptyValue">{{ emptyText || ' ' }}</BFormSelectOption>
|
|
46
|
+
<BFormSelectOption class="empty-item" :value="emptyValue">{{ emptyText || ' ' }}</BFormSelectOption>
|
|
42
47
|
</template>
|
|
43
48
|
<template #option="{value, text}">
|
|
44
49
|
<slot name="option" :item="getItem(value)" v-if="$slots.option"></slot>
|
|
@@ -49,20 +54,20 @@
|
|
|
49
54
|
</template>
|
|
50
55
|
</BFormSelect>
|
|
51
56
|
<div class="flex-v-center" v-else>
|
|
52
|
-
<
|
|
57
|
+
<LoadingIcon/>
|
|
53
58
|
</div>
|
|
54
59
|
</template>
|
|
55
60
|
|
|
56
61
|
<script>
|
|
57
|
-
import {BDropdown, BDropdownItem, BFormSelect, BFormSelectOption} from 'bootstrap-vue-next';
|
|
58
|
-
import
|
|
62
|
+
import {BFormRadioGroup, BDropdown, BDropdownItem, BFormSelect, BFormSelectOption} from 'bootstrap-vue-next';
|
|
63
|
+
import LoadingIcon from '../loading-icon/LoadingIcon.vue';
|
|
59
64
|
|
|
60
65
|
export const isMultiSelector = function (selector) {
|
|
61
66
|
return selector === 'checkbox' || selector === 'tags' || selector === 'multi-select' || selector === 'texts';
|
|
62
67
|
}
|
|
63
68
|
export default {
|
|
64
69
|
name: 'TnxbsvSelect',
|
|
65
|
-
components: {BDropdown, BDropdownItem, BFormSelect, BFormSelectOption,
|
|
70
|
+
components: {BFormRadioGroup, BDropdown, BDropdownItem, BFormSelect, BFormSelectOption, LoadingIcon},
|
|
66
71
|
props: {
|
|
67
72
|
id: [Number, String],
|
|
68
73
|
modelValue: {
|
|
@@ -97,10 +102,9 @@ export default {
|
|
|
97
102
|
},
|
|
98
103
|
emptyValue: {
|
|
99
104
|
type: [String, Number, Boolean, Array],
|
|
100
|
-
default:
|
|
105
|
+
default: null,
|
|
101
106
|
},
|
|
102
107
|
emptyClass: String,
|
|
103
|
-
placeholder: String,
|
|
104
108
|
disabled: Boolean,
|
|
105
109
|
tagClick: Function, // 点击一个标签选项时调用,如果返回false,则选项不会被选中
|
|
106
110
|
change: Function, // 选中值变化后的事件处理函数,比change事件传递更多参数数据
|
|
@@ -349,4 +353,18 @@ export default {
|
|
|
349
353
|
.tnxbsv-select[variant="danger"]:focus {
|
|
350
354
|
box-shadow: 0 0 0 0.25rem rgba(var(--bs-danger-rgb), 0.25);
|
|
351
355
|
}
|
|
356
|
+
|
|
357
|
+
select.tnxbsv-select.is-empty,
|
|
358
|
+
.tnxbsv-select .empty-item {
|
|
359
|
+
color: var(--bs-tertiary-color);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
select.tnxbsv-select.is-empty option:not(.empty-item) {
|
|
363
|
+
color: var(--bs-body-color);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.tnxbsv-radio-group.btn-group > .btn {
|
|
367
|
+
flex: none;
|
|
368
|
+
--bs-btn-padding-x: 1rem;
|
|
369
|
+
}
|
|
352
370
|
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<BFormTags class="tnxbsv-tags-input"
|
|
3
|
+
v-model="model"
|
|
4
|
+
:placeholder="placeholder"
|
|
5
|
+
:separator="separator"
|
|
6
|
+
:tag-variant="tagVariant || 'light'"
|
|
7
|
+
add-button-text="+"
|
|
8
|
+
:duplicate-tag-text="duplicateTagText"
|
|
9
|
+
remove-on-delete
|
|
10
|
+
/>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import {BFormTags} from 'bootstrap-vue-next';
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
name: 'TnxbsvTagsInput',
|
|
18
|
+
components: {BFormTags},
|
|
19
|
+
props: {
|
|
20
|
+
modelValue: {
|
|
21
|
+
type: Array,
|
|
22
|
+
default: () => [],
|
|
23
|
+
},
|
|
24
|
+
placeholder: {
|
|
25
|
+
type: String,
|
|
26
|
+
default: '输入后回车以添加',
|
|
27
|
+
},
|
|
28
|
+
separator: {
|
|
29
|
+
type: String,
|
|
30
|
+
default: ','
|
|
31
|
+
},
|
|
32
|
+
tagVariant: String,
|
|
33
|
+
duplicateTagText: {
|
|
34
|
+
type: String,
|
|
35
|
+
default: '标签重复',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
data() {
|
|
39
|
+
return {
|
|
40
|
+
model: this.modelValue,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
watch: {
|
|
44
|
+
modelValue() {
|
|
45
|
+
this.model = this.modelValue;
|
|
46
|
+
},
|
|
47
|
+
model() {
|
|
48
|
+
this.$emit('update:modelValue', this.model);
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
methods: {}
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style>
|
|
56
|
+
.tnxbsv-tags-input .b-form-tag + .b-from-tags-field > div {
|
|
57
|
+
padding-left: 0.25rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.tnxbsv-tags-input .btn.b-form-tags-button {
|
|
61
|
+
--bs-btn-padding-x: 0.5rem;
|
|
62
|
+
margin-left: 0.5rem;
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
::placeholder {
|
|
2
|
+
color: var(--bs-tertiary-color) !important;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
::-webkit-input-placeholder {
|
|
6
|
+
color: var(--bs-tertiary-color) !important;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
::-moz-placeholder {
|
|
10
|
+
color: var(--bs-tertiary-color) !important;
|
|
11
|
+
}
|
|
12
|
+
|
|
1
13
|
.link {
|
|
2
14
|
cursor: pointer;
|
|
3
15
|
color: var(--bs-link-color);
|
|
@@ -6,22 +18,17 @@
|
|
|
6
18
|
.form-inline {
|
|
7
19
|
display: flex;
|
|
8
20
|
flex-wrap: wrap;
|
|
9
|
-
align-items: center;
|
|
10
21
|
}
|
|
11
22
|
|
|
12
|
-
.form-inline-group {
|
|
23
|
+
.form-inline .b-form-group {
|
|
13
24
|
display: flex;
|
|
14
25
|
flex-wrap: nowrap;
|
|
15
26
|
height: fit-content;
|
|
27
|
+
margin-right: 1.5rem;
|
|
16
28
|
margin-bottom: 1rem;
|
|
17
29
|
width: fit-content;
|
|
18
30
|
}
|
|
19
31
|
|
|
20
|
-
.form-inline-group .col-form-label {
|
|
21
|
-
white-space: nowrap;
|
|
22
|
-
margin-right: 1rem;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
32
|
.badge {
|
|
26
33
|
border: 1px solid transparent;
|
|
27
34
|
}
|
|
@@ -34,3 +41,36 @@
|
|
|
34
41
|
.accordion-body {
|
|
35
42
|
padding: 1rem;
|
|
36
43
|
}
|
|
44
|
+
|
|
45
|
+
.toast {
|
|
46
|
+
width: fit-content;
|
|
47
|
+
min-width: 5rem;
|
|
48
|
+
text-align: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.toast::before {
|
|
52
|
+
content: '';
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 0;
|
|
55
|
+
left: 0;
|
|
56
|
+
width: 100%;
|
|
57
|
+
height: 100%;
|
|
58
|
+
background-color: rgba(255, 255, 255, 0.3);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.form-check {
|
|
62
|
+
margin-top: 0.125rem;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.form-check > * {
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.tnxbsv-dialog-confirm {
|
|
70
|
+
display: flex;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.tnxbsv-dialog-confirm i {
|
|
74
|
+
color: var(--bs-secondary-color);
|
|
75
|
+
margin-right: 0.5rem;
|
|
76
|
+
}
|
|
@@ -7,21 +7,39 @@ import 'bootstrap-vue-next/dist/bootstrap-vue-next.css';
|
|
|
7
7
|
import './tnxbsv.css';
|
|
8
8
|
|
|
9
9
|
import Button from './button/Button.vue';
|
|
10
|
+
import Cascader from './cascader/Cascader.vue';
|
|
10
11
|
import Dialog from './dialog/Dialog.vue';
|
|
11
12
|
import EnumSelect from './enum-select/EnumSelect.vue';
|
|
12
13
|
import Form from './form/Form.vue';
|
|
13
14
|
import FormGroup from './form/FormGroup.vue';
|
|
14
|
-
import
|
|
15
|
+
import LoadingIcon from './loading-icon/LoadingIcon.vue';
|
|
16
|
+
import LoadingOverlay from './loading-overlay/LoadingOverlay.vue';
|
|
15
17
|
import Paged from './paged/Paged.vue';
|
|
18
|
+
import QueryForm from './query-form/QueryForm.vue';
|
|
16
19
|
import QueryTable from './query-table/QueryTable.vue';
|
|
20
|
+
import RegionCascader from './region-cascader/RegionCascader.vue';
|
|
17
21
|
import Select from './select/Select.vue';
|
|
18
22
|
import SubmitForm from './submit-form/SubmitForm.vue';
|
|
23
|
+
import TagsInput from './tags-input/TagsInput.vue';
|
|
19
24
|
|
|
20
25
|
export const build = tnxvue.build;
|
|
21
26
|
|
|
22
27
|
export default build('tnxbsv', () => {
|
|
23
28
|
const components = Object.assign({}, tnxvue.components, {
|
|
24
|
-
Button,
|
|
29
|
+
Button,
|
|
30
|
+
Cascader,
|
|
31
|
+
Dialog,
|
|
32
|
+
EnumSelect,
|
|
33
|
+
Form,
|
|
34
|
+
FormGroup,
|
|
35
|
+
LoadingIcon,
|
|
36
|
+
Paged,
|
|
37
|
+
QueryForm,
|
|
38
|
+
QueryTable,
|
|
39
|
+
RegionCascader,
|
|
40
|
+
Select,
|
|
41
|
+
SubmitForm,
|
|
42
|
+
TagsInput,
|
|
25
43
|
});
|
|
26
44
|
|
|
27
45
|
const tnxbsv = Object.assign({}, tnxjq, tnxvue, {
|
|
@@ -55,6 +73,109 @@ export default build('tnxbsv', () => {
|
|
|
55
73
|
this._dialogs.push(dialog);
|
|
56
74
|
return dialogVm;
|
|
57
75
|
},
|
|
76
|
+
_closeMessage() {
|
|
77
|
+
this.hideLoading();
|
|
78
|
+
this.removeToast();
|
|
79
|
+
},
|
|
80
|
+
confirm(message, title, callback, options) {
|
|
81
|
+
if (typeof title === 'function') {
|
|
82
|
+
options = callback;
|
|
83
|
+
callback = title;
|
|
84
|
+
title = '确认';
|
|
85
|
+
}
|
|
86
|
+
let buttons = tnxvue.getDefaultDialogButtons('confirm', callback);
|
|
87
|
+
message =
|
|
88
|
+
`<div class="tnxbsv-dialog-confirm"><i class="bi bi-question-circle-fill"></i><div>${message}</div></div>`;
|
|
89
|
+
return this.dialog(message, title, buttons, options);
|
|
90
|
+
},
|
|
91
|
+
toast(message, timeout, callback, options = {}) {
|
|
92
|
+
if (typeof timeout === 'function') {
|
|
93
|
+
options = callback || {};
|
|
94
|
+
callback = timeout;
|
|
95
|
+
timeout = undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this._closeMessage();
|
|
99
|
+
|
|
100
|
+
const div = document.createElement('div');
|
|
101
|
+
document.body.appendChild(div);
|
|
102
|
+
|
|
103
|
+
const Vue = window.tnx.libs.Vue;
|
|
104
|
+
const ToastComponent = {
|
|
105
|
+
components: {
|
|
106
|
+
BToast: BootstrapVue.BToast
|
|
107
|
+
},
|
|
108
|
+
setup() {
|
|
109
|
+
const visible = Vue.ref(true);
|
|
110
|
+
Vue.onMounted(() => {
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
visible.value = false;
|
|
113
|
+
// 延迟移除组件,确保动画效果完成
|
|
114
|
+
setTimeout(() => {
|
|
115
|
+
window.tnx.toastInstance?.unmount();
|
|
116
|
+
try {
|
|
117
|
+
document.body.removeChild(div);
|
|
118
|
+
} catch (e) {
|
|
119
|
+
// 忽略异常
|
|
120
|
+
}
|
|
121
|
+
}, 500);
|
|
122
|
+
}, timeout || 1500);
|
|
123
|
+
});
|
|
124
|
+
return {visible};
|
|
125
|
+
},
|
|
126
|
+
render() {
|
|
127
|
+
return Vue.h(BootstrapVue.BToast, {
|
|
128
|
+
modelValue: this.visible,
|
|
129
|
+
variant: options.type || 'success',
|
|
130
|
+
static: true,
|
|
131
|
+
noCloseButton: true,
|
|
132
|
+
class: 'position-fixed',
|
|
133
|
+
style: {
|
|
134
|
+
top: '50%',
|
|
135
|
+
left: '50%',
|
|
136
|
+
transform: 'translate(-50%, -50%)',
|
|
137
|
+
zIndex: window.tnx.util.dom.minTopZIndex(),
|
|
138
|
+
}
|
|
139
|
+
}, () => message);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const instance = window.tnx.createVueInstance(ToastComponent);
|
|
144
|
+
instance.mount(div);
|
|
145
|
+
window.tnx.toastInstance = instance;
|
|
146
|
+
},
|
|
147
|
+
removeToast() {
|
|
148
|
+
if (window.tnx.toastInstance) {
|
|
149
|
+
window.tnx.toastInstance.unmount();
|
|
150
|
+
try {
|
|
151
|
+
document.body.removeChild(window.tnx.toastInstance._container);
|
|
152
|
+
} catch (e) {
|
|
153
|
+
// 忽略异常
|
|
154
|
+
}
|
|
155
|
+
window.tnx.toastInstance = null;
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
showLoading(message = '', options) {
|
|
159
|
+
this._closeMessage();
|
|
160
|
+
|
|
161
|
+
let div = document.createElement('div');
|
|
162
|
+
document.body.appendChild(div);
|
|
163
|
+
let instance = window.tnx.createVueInstance(LoadingOverlay, null, {message});
|
|
164
|
+
let component = instance.mount(div);
|
|
165
|
+
window.tnx.loadingInstance = instance;
|
|
166
|
+
window.tnx.app.eventBus.emit('tnx.showLoading', options);
|
|
167
|
+
return component;
|
|
168
|
+
},
|
|
169
|
+
hideLoading() {
|
|
170
|
+
if (window.tnx.loadingInstance) {
|
|
171
|
+
window.tnx.loadingInstance.unmount();
|
|
172
|
+
document.body.removeChild(window.tnx.loadingInstance._container);
|
|
173
|
+
window.tnx.loadingInstance = null;
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
closeLoading() {
|
|
177
|
+
this.hideLoading();
|
|
178
|
+
},
|
|
58
179
|
});
|
|
59
180
|
|
|
60
181
|
tnxbsv.install = tnxbsv.util.function.around(tnxbsv.install, function (install, vm) {
|
|
@@ -218,9 +218,8 @@ export default build('tnxel', () => {
|
|
|
218
218
|
this.closeLoading();
|
|
219
219
|
},
|
|
220
220
|
_handleZIndex(selector) {
|
|
221
|
-
const util = this.util;
|
|
222
221
|
setTimeout(function () {
|
|
223
|
-
const topZIndex = util.dom.minTopZIndex(2);
|
|
222
|
+
const topZIndex = window.tnx.util.dom.minTopZIndex(2);
|
|
224
223
|
if (selector.endsWith(':last')) {
|
|
225
224
|
selector = selector.substring(0, selector.length - ':last'.length);
|
|
226
225
|
}
|
|
@@ -355,7 +354,7 @@ export default build('tnxel', () => {
|
|
|
355
354
|
try {
|
|
356
355
|
window.tnx.loadingInstance = ElLoading.service(options);
|
|
357
356
|
this._handleZIndex('.el-loading-mask');
|
|
358
|
-
|
|
357
|
+
window.tnx.app.eventBus.emit('tnx.showLoading', options);
|
|
359
358
|
} catch (e) {
|
|
360
359
|
window.tnx.loadingInstance = null;
|
|
361
360
|
console.error(e);
|
package/src/tnxvue.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* 基于Vue 3的扩展支持
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
import tnxcore from '../../core/src/tnxcore';
|
|
5
|
+
import tnxcore from '@truenewx/tnxcore';
|
|
6
|
+
// import tnxcore from '../../core/src/tnxcore';
|
|
7
7
|
import validator from './tnxvue-validator';
|
|
8
8
|
import createRouter from './tnxvue-router';
|
|
9
9
|
import Text from './text/Text.vue';
|