@truenewx/tnxvue3 3.0.10 → 3.0.12

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/index.html ADDED
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>tnxvue3</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="./sample/main.js"></script>
11
+ </body>
12
+ </html>
package/package.json CHANGED
@@ -1,11 +1,9 @@
1
1
  {
2
2
  "name": "@truenewx/tnxvue3",
3
- "version": "3.0.10",
3
+ "version": "3.0.12",
4
4
  "description": "互联网技术解决方案:Vue3扩展支持",
5
5
  "private": false,
6
- "publishConfig": {
7
- "access": "public"
8
- },
6
+ "type": "module",
9
7
  "main": "src/tnxvue.js",
10
8
  "keywords": [
11
9
  "truenewx",
@@ -15,8 +13,9 @@
15
13
  "author": "truenewx",
16
14
  "license": "Apache-2.0",
17
15
  "scripts": {
18
- "serve": "vue-cli-service serve",
19
- "build": "vue-cli-service build"
16
+ "dev": "vite",
17
+ "build": "vite build",
18
+ "preview": "vite preview"
20
19
  },
21
20
  "peerDependencies": {
22
21
  "element-plus": "~2.8.0",
@@ -25,22 +24,16 @@
25
24
  "vue-router": "~4.4.0"
26
25
  },
27
26
  "dependencies": {
28
- "@truenewx/tnxcore": "3.0.7",
27
+ "@truenewx/tnxcore": "3.0.10",
29
28
  "@element-plus/icons-vue": "2.3.1",
30
29
  "async-validator": "4.2.5",
31
30
  "mitt": "3.0.1"
32
31
  },
33
32
  "devDependencies": {
34
- "@babel/core": "7.22.5",
35
- "@babel/eslint-parser": "7.22.5",
36
- "@babel/preset-env": "7.22.5",
37
- "@vue/cli-plugin-babel": "5.0.8",
38
- "@vue/cli-plugin-eslint": "5.0.8",
39
- "@vue/cli-service": "5.0.8",
33
+ "@vitejs/plugin-vue": "5.2.1",
34
+ "vite": "6.2.0",
40
35
  "eslint": "7.32.0",
41
- "eslint-plugin-vue": "8.7.1",
42
- "copy-webpack-plugin": "11.0.0",
43
- "terser-webpack-plugin": "5.3.7"
36
+ "eslint-plugin-vue": "8.7.1"
44
37
  },
45
38
  "eslintConfig": {
46
39
  "root": true,
@@ -51,9 +44,6 @@
51
44
  "plugin:vue/vue3-essential",
52
45
  "eslint:recommended"
53
46
  ],
54
- "parserOptions": {
55
- "parser": "@babel/eslint-parser"
56
- },
57
47
  "rules": {
58
48
  "eqeqeq": "warn",
59
49
  "no-unused-vars": [
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <BButton class="tnxbsv-button" :variant="type || 'outline-secondary'" :loading="loading" :disabled="loading">
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="outline-secondary" class="btn-append">
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>
@@ -10,6 +10,10 @@
10
10
  color: var(--bs-tertiary-color) !important;
11
11
  }
12
12
 
13
+ .btn-light {
14
+ border-color: var(--bs-border-color);
15
+ }
16
+
13
17
  .link {
14
18
  cursor: pointer;
15
19
  color: var(--bs-link-color);
@@ -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 dialogVm = window.tnx.createVueInstance(componentDefinition, null, {
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,173 @@
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
+ mounted() {
80
+ this.file = null;
81
+ this.uploading = false;
82
+ this.errorMessage = null;
83
+ },
84
+ methods: {
85
+ toSelect() {
86
+ const $ = window.tnx.libs.$;
87
+ $('.tnxbsv-upload input[type="file"]').trigger('click')
88
+ },
89
+ clear() {
90
+ this.file.handled = true;
91
+ this.$nextTick(() => {
92
+ this.file = null;
93
+ });
94
+ },
95
+ uploadFile() {
96
+ if (this.file) {
97
+ if (this.beforeUpload && this.beforeUpload(this.file) === false) {
98
+ return;
99
+ }
100
+ const formData = new FormData();
101
+ formData.append('file', this.file);
102
+ this.uploading = true;
103
+ this.errorMessage = null;
104
+
105
+ window.tnx.app.rpc.request(this.actionUrl, {
106
+ method: 'POST',
107
+ body: formData,
108
+ timeout: 0, // 文件上传不设置超时
109
+ app: this.app, // 指定目标应用
110
+ success: result => {
111
+ if (this.onSuccess) {
112
+ this.onSuccess(result);
113
+ } else {
114
+ console.log('文件上传成功:', result);
115
+ }
116
+ this.uploading = false;
117
+ },
118
+ error: error => {
119
+ this.uploading = false;
120
+ if (this.onError && this.onError(error) === false) {
121
+ return;
122
+ }
123
+ this.errorMessage = error.message;
124
+ }
125
+ });
126
+ }
127
+ }
128
+ }
129
+ }
130
+ </script>
131
+
132
+ <style>
133
+ .tnxbsv-upload input:focus {
134
+ outline: none;
135
+ box-shadow: none;
136
+ border-color: var(--bs-border-color);
137
+ }
138
+
139
+ .tnxbsv-upload .input-group-append {
140
+ position: relative;
141
+ }
142
+
143
+ .tnxbsv-upload .input-group-append .icon-clear {
144
+ position: absolute;
145
+ right: calc(100% + 0.75rem);
146
+ top: 50%;
147
+ transform: translateY(-50%);
148
+ cursor: pointer;
149
+ z-index: 10;
150
+ color: var(--bs-tertiary-color);
151
+ }
152
+
153
+ .tnxbsv-upload .input-group-append .icon-clear:hover {
154
+ color: var(--bs-secondary-color);
155
+ }
156
+
157
+ .tnxbsv-upload .input-group-append .btn {
158
+ border-top-left-radius: 0;
159
+ border-bottom-left-radius: 0;
160
+ }
161
+
162
+ .tnxbsv-upload-error {
163
+ margin-top: 0.25rem;
164
+ color: var(--bs-danger);
165
+ font-size: 87.5%;
166
+ }
167
+
168
+ .tnxbsv-upload-placeholder {
169
+ margin-top: 0.25rem;
170
+ color: var(--bs-tertiary-color);
171
+ font-size: 87.5%;
172
+ }
173
+ </style>
@@ -103,7 +103,7 @@ export default {
103
103
  return height;
104
104
  },
105
105
  downloadUrl() {
106
- let baseUrl = process.env.VUE_APP_API_BASE_URL;
106
+ let baseUrl = window.tnx.app.rpc.getDefaultBaseUrl();
107
107
  if (this.app) {
108
108
  baseUrl = window.tnx.app.rpc.getBaseUrl(this.app);
109
109
  }
package/src/tnxvue.js CHANGED
@@ -175,7 +175,7 @@ export default build('tnxvue', () => {
175
175
  } else if (type === 'close') {
176
176
  return [{
177
177
  text: '关闭',
178
- type: theme || 'default',
178
+ type: theme,
179
179
  click(close) {
180
180
  if (typeof callback === 'function') {
181
181
  return callback.call(this, close);
package/src/tnxvue-cli.js DELETED
@@ -1,64 +0,0 @@
1
- // tnxvue-cli.js
2
- const TerserPlugin = require('terser-webpack-plugin');
3
- const CopyWebpackPlugin = require('copy-webpack-plugin');
4
-
5
- module.exports = {
6
- uglify(config, options) {
7
- Object.assign(config, {
8
- optimization: {
9
- minimizer: [new TerserPlugin({
10
- terserOptions: Object.assign({
11
- compress: {
12
- warnings: false,
13
- drop_console: false,
14
- drop_debugger: true,
15
- }
16
- }, options)
17
- })]
18
- }
19
- });
20
- },
21
- copy(config, dependencies, libs, patterns) {
22
- let pluginPatterns = [];
23
- for (let lib of libs) {
24
- let from = lib.path;
25
- let to = 'libs/js/' + lib.name;
26
- if (config.mode === 'production') {
27
- let version = dependencies[lib.name];
28
- if (version) {
29
- to += '-' + version;
30
- }
31
- from += lib.prod;
32
- to += lib.prod;
33
- }
34
- if (!from.endsWith('/')) {
35
- from += '.js';
36
- }
37
- if (!to.endsWith('/')) {
38
- to += '.js';
39
- }
40
- pluginPatterns.push({
41
- from: './node_modules/' + from,
42
- to: './' + to,
43
- });
44
- let globalVarName = config.externals[lib.name];
45
- if (globalVarName) {
46
- let baseUrl = process.env.VUE_APP_VIEW_BASE_URL;
47
- if (!baseUrl.endsWith('/')) {
48
- baseUrl += '/';
49
- }
50
- process.env['VUE_APP_LIBS_' + globalVarName] = baseUrl + to;
51
- }
52
- if (lib.map) {
53
- pluginPatterns.push({
54
- from: './node_modules/' + lib.path + lib.map,
55
- to: './libs/js/',
56
- });
57
- }
58
- }
59
- if (patterns && patterns.length) {
60
- pluginPatterns = pluginPatterns.concat(patterns);
61
- }
62
- config.plugins.push(new CopyWebpackPlugin({patterns: pluginPatterns}));
63
- },
64
- }