@truenewx/tnxvue3 3.0.10 → 3.0.11
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 +1 -1
- package/src/bootstrap-vue/cascader/Cascader.vue +1 -1
- package/src/bootstrap-vue/dialog/Dialog.vue +1 -1
- package/src/bootstrap-vue/progress/Progress.vue +58 -0
- package/src/bootstrap-vue/tnxbsv.css +4 -0
- package/src/bootstrap-vue/tnxbsv.js +6 -1
- package/src/bootstrap-vue/upload/Upload.vue +168 -0
- package/src/tnxvue.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truenewx/tnxvue3",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.11",
|
|
4
4
|
"description": "互联网技术解决方案:Vue3扩展支持",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"vue-router": "~4.4.0"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@truenewx/tnxcore": "3.0.
|
|
28
|
+
"@truenewx/tnxcore": "3.0.8",
|
|
29
29
|
"@element-plus/icons-vue": "2.3.1",
|
|
30
30
|
"async-validator": "4.2.5",
|
|
31
31
|
"mitt": "3.0.1"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<BButton class="tnxbsv-button" :variant="type || '
|
|
2
|
+
<BButton class="tnxbsv-button" :variant="type || 'light'" :loading="loading" :disabled="loading">
|
|
3
3
|
<i class="me-1" :class="icon" v-if="icon"></i>
|
|
4
4
|
<div>
|
|
5
5
|
<slot></slot>
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
@focus="handleFocus"
|
|
11
11
|
/>
|
|
12
12
|
<template #append>
|
|
13
|
-
<BButton variant="
|
|
13
|
+
<BButton variant="light" class="btn-append">
|
|
14
14
|
<i v-if="clearable && !disabled && modelValue"
|
|
15
15
|
class="bi bi-x-circle me-1"
|
|
16
16
|
@click.stop="clearValue">
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<component ref="content" :is="content" v-bind="contentProps" v-else></component>
|
|
21
21
|
<template #footer>
|
|
22
22
|
<TnxbsvButton v-for="(button, index) in buttons" :key="index"
|
|
23
|
-
:type="button.type"
|
|
23
|
+
:type="button.type || 'light'"
|
|
24
24
|
:loading="buttonLoadings[index]"
|
|
25
25
|
@click="btnClick(index)"
|
|
26
26
|
>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="tnxbs-progress">
|
|
3
|
+
<BProgress :variant="type" :key="type" :value="value" :max="max" :show-value="showValue">
|
|
4
|
+
<div class="progress-bar" :style="{width: percent}">
|
|
5
|
+
{{ showProgress ? percent : '' }}
|
|
6
|
+
</div>
|
|
7
|
+
</BProgress>
|
|
8
|
+
<span class="tnxbs-progress-value" v-if="showValue">{{ value }}/{{ max }}</span>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
import {BProgress} from 'bootstrap-vue-next';
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
name: 'TnxbsvProgress',
|
|
17
|
+
components: {BProgress},
|
|
18
|
+
props: {
|
|
19
|
+
type: String,
|
|
20
|
+
value: {
|
|
21
|
+
type: Number,
|
|
22
|
+
default: 0
|
|
23
|
+
},
|
|
24
|
+
max: Number,
|
|
25
|
+
precision: {
|
|
26
|
+
type: Number,
|
|
27
|
+
default: 0,
|
|
28
|
+
},
|
|
29
|
+
showValue: Boolean,
|
|
30
|
+
showProgress: Boolean,
|
|
31
|
+
},
|
|
32
|
+
data() {
|
|
33
|
+
return {};
|
|
34
|
+
},
|
|
35
|
+
computed: {
|
|
36
|
+
percent() {
|
|
37
|
+
return (this.value / this.max).toPercent(this.precision);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
methods: {}
|
|
41
|
+
}
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<style>
|
|
45
|
+
.tnxbs-progress {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.tnxbs-progress .progress {
|
|
51
|
+
flex-grow: 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.tnxbs-progress .tnxbs-progress-value {
|
|
55
|
+
margin-left: 0.5rem;
|
|
56
|
+
color: var(--bs-body-color);
|
|
57
|
+
}
|
|
58
|
+
</style>
|
|
@@ -15,12 +15,14 @@ import FormGroup from './form/FormGroup.vue';
|
|
|
15
15
|
import LoadingIcon from './loading-icon/LoadingIcon.vue';
|
|
16
16
|
import LoadingOverlay from './loading-overlay/LoadingOverlay.vue';
|
|
17
17
|
import Paged from './paged/Paged.vue';
|
|
18
|
+
import Progress from './progress/Progress.vue';
|
|
18
19
|
import QueryForm from './query-form/QueryForm.vue';
|
|
19
20
|
import QueryTable from './query-table/QueryTable.vue';
|
|
20
21
|
import RegionCascader from './region-cascader/RegionCascader.vue';
|
|
21
22
|
import Select from './select/Select.vue';
|
|
22
23
|
import SubmitForm from './submit-form/SubmitForm.vue';
|
|
23
24
|
import TagsInput from './tags-input/TagsInput.vue';
|
|
25
|
+
import Upload from './upload/Upload.vue';
|
|
24
26
|
|
|
25
27
|
export const build = tnxvue.build;
|
|
26
28
|
|
|
@@ -34,12 +36,14 @@ export default build('tnxbsv', () => {
|
|
|
34
36
|
FormGroup,
|
|
35
37
|
LoadingIcon,
|
|
36
38
|
Paged,
|
|
39
|
+
Progress,
|
|
37
40
|
QueryForm,
|
|
38
41
|
QueryTable,
|
|
39
42
|
RegionCascader,
|
|
40
43
|
Select,
|
|
41
44
|
SubmitForm,
|
|
42
45
|
TagsInput,
|
|
46
|
+
Upload,
|
|
43
47
|
});
|
|
44
48
|
|
|
45
49
|
const tnxbsv = Object.assign({}, tnxjq, tnxvue, {
|
|
@@ -51,7 +55,7 @@ export default build('tnxbsv', () => {
|
|
|
51
55
|
let id = new Date().getTime();
|
|
52
56
|
let containerId = 'dialog-container-' + id;
|
|
53
57
|
let componentDefinition = Object.assign({}, Dialog,);
|
|
54
|
-
let
|
|
58
|
+
let rootProps = Object.assign({}, options, {
|
|
55
59
|
modelValue: true,
|
|
56
60
|
id: id,
|
|
57
61
|
container: '#' + containerId,
|
|
@@ -60,6 +64,7 @@ export default build('tnxbsv', () => {
|
|
|
60
64
|
contentProps,
|
|
61
65
|
buttons,
|
|
62
66
|
});
|
|
67
|
+
let dialogVm = window.tnx.createVueInstance(componentDefinition, null, rootProps);
|
|
63
68
|
const dialogContainer = document.createElement('div');
|
|
64
69
|
dialogContainer.className = 'tnxbsv-dialog-container';
|
|
65
70
|
dialogContainer.id = containerId;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="tnxbsv-upload">
|
|
3
|
+
<BOverlay :show="uploading" spinner-variant="primary" spinner-small>
|
|
4
|
+
<BInputGroup>
|
|
5
|
+
<BFormInput :value="file?.name" :placeholder="placeholder" tabindex="-1" readonly/>
|
|
6
|
+
<template #append>
|
|
7
|
+
<div class="input-group-append">
|
|
8
|
+
<i class="bi bi-x-circle icon-clear" @click="clear" v-if="empty"/>
|
|
9
|
+
<BButton :variant="buttonType" @click="toSelect">{{ buttonText }}</BButton>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
</BInputGroup>
|
|
13
|
+
<BFormFile class="d-none" v-model="file" :accept="uploadOptions.extensions || accept"/>
|
|
14
|
+
</BOverlay>
|
|
15
|
+
<div class="tnxbsv-upload-error" v-if="errorMessage">{{ errorMessage }}</div>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
import {BOverlay, BInputGroup, BFormInput, BButton, BFormFile} from 'bootstrap-vue-next';
|
|
21
|
+
|
|
22
|
+
export default {
|
|
23
|
+
name: 'TnxbsvUpload',
|
|
24
|
+
components: {BOverlay, BInputGroup, BFormInput, BButton, BFormFile,},
|
|
25
|
+
props: {
|
|
26
|
+
app: String, // 上传目标应用名称
|
|
27
|
+
action: {
|
|
28
|
+
type: String,
|
|
29
|
+
required: true,
|
|
30
|
+
},
|
|
31
|
+
accept: [String, Array],
|
|
32
|
+
uploadOptions: {
|
|
33
|
+
type: Object,
|
|
34
|
+
default: () => ({}),
|
|
35
|
+
},
|
|
36
|
+
placeholder: String,
|
|
37
|
+
buttonType: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: 'light',
|
|
40
|
+
},
|
|
41
|
+
buttonText: {
|
|
42
|
+
type: String,
|
|
43
|
+
default: '选择文件',
|
|
44
|
+
},
|
|
45
|
+
empty: Boolean,
|
|
46
|
+
beforeUpload: Function,
|
|
47
|
+
onSuccess: Function,
|
|
48
|
+
onError: Function,
|
|
49
|
+
},
|
|
50
|
+
data() {
|
|
51
|
+
return {
|
|
52
|
+
file: null,
|
|
53
|
+
uploading: false,
|
|
54
|
+
errorMessage: null,
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
computed: {
|
|
58
|
+
actionUrl() {
|
|
59
|
+
let baseUrl;
|
|
60
|
+
if (this.app) {
|
|
61
|
+
baseUrl = window.tnx.app.rpc.getBaseUrl(this.app);
|
|
62
|
+
}
|
|
63
|
+
baseUrl = baseUrl || window.tnx.app.rpc.getDefaultBaseUrl();
|
|
64
|
+
return baseUrl + this.action;
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
watch: {
|
|
68
|
+
file(newFile, oldFile) {
|
|
69
|
+
if (newFile) {
|
|
70
|
+
if (!newFile.handled) {
|
|
71
|
+
this.uploadFile();
|
|
72
|
+
}
|
|
73
|
+
} else if (!oldFile.handled) {
|
|
74
|
+
oldFile.handled = true;
|
|
75
|
+
this.file = oldFile;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
methods: {
|
|
80
|
+
toSelect() {
|
|
81
|
+
const $ = window.tnx.libs.$;
|
|
82
|
+
$('.tnxbsv-upload input[type="file"]').trigger('click')
|
|
83
|
+
},
|
|
84
|
+
clear() {
|
|
85
|
+
this.file.handled = true;
|
|
86
|
+
this.$nextTick(() => {
|
|
87
|
+
this.file = null;
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
uploadFile() {
|
|
91
|
+
if (this.file) {
|
|
92
|
+
if (this.beforeUpload && this.beforeUpload(this.file) === false) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const formData = new FormData();
|
|
96
|
+
formData.append('file', this.file);
|
|
97
|
+
this.uploading = true;
|
|
98
|
+
this.errorMessage = null;
|
|
99
|
+
|
|
100
|
+
window.tnx.app.rpc.request(this.actionUrl, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
body: formData,
|
|
103
|
+
timeout: 0, // 文件上传不设置超时
|
|
104
|
+
app: this.app, // 指定目标应用
|
|
105
|
+
success: result => {
|
|
106
|
+
if (this.onSuccess) {
|
|
107
|
+
this.onSuccess(result);
|
|
108
|
+
} else {
|
|
109
|
+
console.log('文件上传成功:', result);
|
|
110
|
+
}
|
|
111
|
+
this.uploading = false;
|
|
112
|
+
},
|
|
113
|
+
error: error => {
|
|
114
|
+
this.uploading = false;
|
|
115
|
+
if (this.onError && this.onError(error) === false) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
this.errorMessage = error.message;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<style>
|
|
128
|
+
.tnxbsv-upload input:focus {
|
|
129
|
+
outline: none;
|
|
130
|
+
box-shadow: none;
|
|
131
|
+
border-color: var(--bs-border-color);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.tnxbsv-upload .input-group-append {
|
|
135
|
+
position: relative;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.tnxbsv-upload .input-group-append .icon-clear {
|
|
139
|
+
position: absolute;
|
|
140
|
+
right: calc(100% + 0.75rem);
|
|
141
|
+
top: 50%;
|
|
142
|
+
transform: translateY(-50%);
|
|
143
|
+
cursor: pointer;
|
|
144
|
+
z-index: 10;
|
|
145
|
+
color: var(--bs-tertiary-color);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.tnxbsv-upload .input-group-append .icon-clear:hover {
|
|
149
|
+
color: var(--bs-secondary-color);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.tnxbsv-upload .input-group-append .btn {
|
|
153
|
+
border-top-left-radius: 0;
|
|
154
|
+
border-bottom-left-radius: 0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.tnxbsv-upload-error {
|
|
158
|
+
margin-top: 0.25rem;
|
|
159
|
+
color: var(--bs-danger);
|
|
160
|
+
font-size: 87.5%;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.tnxbsv-upload-placeholder {
|
|
164
|
+
margin-top: 0.25rem;
|
|
165
|
+
color: var(--bs-tertiary-color);
|
|
166
|
+
font-size: 87.5%;
|
|
167
|
+
}
|
|
168
|
+
</style>
|
package/src/tnxvue.js
CHANGED