@truenewx/tnxvue3 2.6.0

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 (60) hide show
  1. package/README.md +3 -0
  2. package/package.json +76 -0
  3. package/sample/App.vue +19 -0
  4. package/sample/main.js +11 -0
  5. package/sample/pages/index.vue +79 -0
  6. package/sample/pages/info.vue +28 -0
  7. package/sample/tnx.js +31 -0
  8. package/src/aj-captcha/Verify/VerifyPoints.vue +258 -0
  9. package/src/aj-captcha/Verify/VerifySlide.vue +379 -0
  10. package/src/aj-captcha/Verify.vue +375 -0
  11. package/src/aj-captcha/api/index.js +19 -0
  12. package/src/aj-captcha/utils/ase.js +11 -0
  13. package/src/aj-captcha/utils/util.js +35 -0
  14. package/src/ant-design/tnxad-theme.css +5 -0
  15. package/src/ant-design/tnxad.css +8 -0
  16. package/src/ant-design/tnxad.js +23 -0
  17. package/src/element-plus/alert/Alert.vue +112 -0
  18. package/src/element-plus/avatar/Avatar.vue +124 -0
  19. package/src/element-plus/button/Button.vue +184 -0
  20. package/src/element-plus/check-icon/CheckIcon.vue +61 -0
  21. package/src/element-plus/close-error-button/CloseErrorButton.vue +45 -0
  22. package/src/element-plus/curd/Curd.vue +224 -0
  23. package/src/element-plus/date-picker/DatePicker.vue +206 -0
  24. package/src/element-plus/date-range/DateRange.vue +78 -0
  25. package/src/element-plus/datetime-picker/DateTimePicker.vue +129 -0
  26. package/src/element-plus/detail-form/DetailForm.vue +88 -0
  27. package/src/element-plus/dialog/Dialog.vue +259 -0
  28. package/src/element-plus/dialog/DialogContent.vue +13 -0
  29. package/src/element-plus/drawer/Drawer.vue +175 -0
  30. package/src/element-plus/dropdown-item/DropdownItem.vue +30 -0
  31. package/src/element-plus/enum-select/EnumSelect.vue +125 -0
  32. package/src/element-plus/fetch-cascader/FetchCascader.vue +138 -0
  33. package/src/element-plus/fetch-select/FetchSelect.vue +166 -0
  34. package/src/element-plus/fetch-tags/FetchTags.vue +122 -0
  35. package/src/element-plus/fss-upload/FssUpload.vue +306 -0
  36. package/src/element-plus/fss-view/FssView.vue +163 -0
  37. package/src/element-plus/icon/Icon.vue +221 -0
  38. package/src/element-plus/input-number/InputNumber.vue +150 -0
  39. package/src/element-plus/paged/Paged.vue +76 -0
  40. package/src/element-plus/permission-tree/PermissionTree.vue +184 -0
  41. package/src/element-plus/query-form/QueryForm.vue +138 -0
  42. package/src/element-plus/query-table/QueryTable.vue +402 -0
  43. package/src/element-plus/region-cascader/RegionCascader.vue +108 -0
  44. package/src/element-plus/select/Select.vue +446 -0
  45. package/src/element-plus/slider/Slider.vue +88 -0
  46. package/src/element-plus/steps-nav/StepsNav.vue +57 -0
  47. package/src/element-plus/submit-form/SubmitForm.vue +236 -0
  48. package/src/element-plus/table-column/TableColumn.vue +32 -0
  49. package/src/element-plus/tabs/Tabs.vue +93 -0
  50. package/src/element-plus/tnxel.css +890 -0
  51. package/src/element-plus/tnxel.js +528 -0
  52. package/src/element-plus/transfer/Transfer.vue +117 -0
  53. package/src/element-plus/upload/Upload.vue +856 -0
  54. package/src/percent/Percent.vue +12 -0
  55. package/src/text/Text.vue +33 -0
  56. package/src/tnxvue-cli.js +64 -0
  57. package/src/tnxvue-router.js +161 -0
  58. package/src/tnxvue-validator.js +365 -0
  59. package/src/tnxvue.css +12 -0
  60. package/src/tnxvue.js +343 -0
@@ -0,0 +1,124 @@
1
+ <template>
2
+ <el-image :class="shape === 'square' ? 'rounded' : 'rounded-circle'" :style="style" :src="src"
3
+ :preview-src-list="previewSrcList" v-if="preview && src">
4
+ <template #error>
5
+ <div class="text-muted h-100 flex-center">
6
+ <i class="el-icon-picture-outline"/>
7
+ </div>
8
+ </template>
9
+ </el-image>
10
+ <el-avatar :size="size" :style="style" :shape="shape" :src="src" v-else>
11
+ <tnxel-icon :value="icon" :size="size / 2" style="margin:0" v-if="!src && icon"/>
12
+ </el-avatar>
13
+ </template>
14
+
15
+ <script>
16
+ import Icon from '../icon/Icon.vue';
17
+
18
+ export default {
19
+ name: 'TnxelAvatar',
20
+ components: {
21
+ 'tnxel-icon': Icon,
22
+ },
23
+ props: {
24
+ url: String,
25
+ shape: String,
26
+ size: {
27
+ type: Number,
28
+ required: true,
29
+ },
30
+ icon: {
31
+ type: String,
32
+ default: 'UserFilled',
33
+ },
34
+ preview: {
35
+ type: Boolean,
36
+ default: false,
37
+ }
38
+ },
39
+ data() {
40
+ return {
41
+ src: null,
42
+ previewSrcList: null,
43
+ }
44
+ },
45
+ computed: {
46
+ style() {
47
+ let style = {
48
+ 'min-width': this.size + 'px',
49
+ 'min-height': this.size + 'px',
50
+ };
51
+ if (this.preview && this.src) {
52
+ Object.assign(style, {
53
+ width: this.size + 'px',
54
+ height: this.size + 'px',
55
+ 'font-size': (this.size / 2) + 'px',
56
+ });
57
+ } else {
58
+ style['font-size'] = (this.size / 2) + 'px';
59
+ if (this.src) {
60
+ style['background-color'] = 'transparent';
61
+ }
62
+ }
63
+ return style;
64
+ }
65
+ },
66
+ watch: {
67
+ url() {
68
+ this.load();
69
+ }
70
+ },
71
+ created() {
72
+ this.load();
73
+ },
74
+ methods: {
75
+ load() {
76
+ if (this.url && this.url.startsWith(window.tnx.fss.PROTOCOL)) {
77
+ let rpc = window.tnx.app.rpc;
78
+ let fssConfig = window.tnx.fss.getClientConfig();
79
+ let vm = this;
80
+ if (vm.preview) {
81
+ rpc.get(fssConfig.contextUrl + '/meta', {
82
+ locationUrl: vm.url
83
+ }, function (meta) {
84
+ vm.src = meta.thumbnailReadUrl;
85
+ vm.previewSrcList = [meta.readUrl];
86
+ }, {
87
+ app: fssConfig.appName,
88
+ error(errors) {
89
+ console.error(errors[0].message);
90
+ }
91
+ });
92
+ } else {
93
+ rpc.get(fssConfig.contextUrl + '/read/url', {
94
+ locationUrl: vm.url,
95
+ thumbnail: true,
96
+ }, function (readUrl) {
97
+ vm.src = readUrl;
98
+ }, {
99
+ app: fssConfig.appName,
100
+ error(errors) {
101
+ console.error(errors[0].message);
102
+ }
103
+ });
104
+ }
105
+ } else {
106
+ this.src = this.url;
107
+ }
108
+ }
109
+ }
110
+ }
111
+ </script>
112
+
113
+ <style>
114
+ .el-avatar,
115
+ .el-avatar .el-icon {
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ }
120
+
121
+ .el-avatar img {
122
+ background-color: white;
123
+ }
124
+ </style>
@@ -0,0 +1,184 @@
1
+ <template>
2
+ <el-tooltip :content="tooltipContent" :placement="tooltipPlacement" :disabled="disabled || !tooltipContent"
3
+ v-if="disabled === false || disabledTip !== false">
4
+ <el-dropdown split-button :type="type" :class="className" :disabled="disabled" :title="title" :size="size"
5
+ :style="$attrs.style" @click="clickButton" @command="clickItem" v-if="dropdownItems.length">
6
+ <i :class="icon" style="margin-right: 0.5rem;" v-if="icon"></i>
7
+ <template v-if="!hiddenCaption">
8
+ <slot v-if="$slots.default"></slot>
9
+ <template v-else-if="menuItem">{{ menuItem.caption }}</template>
10
+ </template>
11
+ <template #dropdown>
12
+ <el-dropdown-menu>
13
+ <el-dropdown-item v-for="dropdownItem of dropdownItems" :key="dropdownItem.path"
14
+ :icon="dropdownItem.icon" :disabled="dropdownItem.disabled"
15
+ :title="dropdownItem.title"
16
+ :command="dropdownItem">
17
+ {{ dropdownItem.caption || (dropdownItem.menuItem ? dropdownItem.menuItem.caption : '') }}
18
+ </el-dropdown-item>
19
+ </el-dropdown-menu>
20
+ </template>
21
+ </el-dropdown>
22
+ <el-button :type="type" :class="className" :disabled="disabled" :title="title" @click="clickButton" :size="size"
23
+ :loading="loading" :plain="plain" :link="link" :text="text" :bg="bg" :autofocus="autofocus"
24
+ :round="round"
25
+ :circle="circle" :style="$attrs.style" v-else>
26
+ <tnxel-icon :value="icon" v-if="icon"/>
27
+ <span v-if="!hiddenCaption && ($slots.default || menuItem)">
28
+ <slot>{{ menuItem ? menuItem.caption : '' }}</slot>
29
+ </span>
30
+ </el-button>
31
+ </el-tooltip>
32
+ </template>
33
+
34
+ <script>
35
+ import Icon from '../icon/Icon.vue';
36
+
37
+ export default {
38
+ name: 'TnxelButton',
39
+ components: {
40
+ 'tnxel-icon': Icon,
41
+ },
42
+ props: {
43
+ menu: Object,
44
+ path: String,
45
+ granted: { // 是否已授权可用,默认不指定,如果指定值,则不再根据menu和path判断是否授权可用
46
+ type: Boolean,
47
+ default: null,
48
+ },
49
+ click: {
50
+ type: [Function, Boolean],
51
+ default: false,
52
+ },
53
+ type: String,
54
+ icon: String,
55
+ size: String,
56
+ loading: Boolean,
57
+ plain: Boolean,
58
+ link: Boolean,
59
+ text: Boolean,
60
+ bg: Boolean,
61
+ autofocus: Boolean,
62
+ round: Boolean,
63
+ circle: Boolean,
64
+ tooltip: {
65
+ type: [String, Boolean],
66
+ default: '',
67
+ },
68
+ tooltipPlacement: {
69
+ type: String,
70
+ default: 'top',
71
+ },
72
+ disabledTip: {
73
+ type: [String, Boolean],
74
+ default: '没有操作权限',
75
+ },
76
+ hiddenCaption: Boolean,
77
+ dropdown: [Object, Array],
78
+ },
79
+ emits: ['click'],
80
+ data() {
81
+ let menuItem = null;
82
+ if (this.menu && this.path) {
83
+ menuItem = this.menu.getItemByPath(this.path);
84
+ }
85
+ return {
86
+ menuItem: menuItem,
87
+ disabled: null,
88
+ dropdownItems: [],
89
+ }
90
+ },
91
+ computed: {
92
+ className() {
93
+ return this.$attrs.class;
94
+ },
95
+ tooltipContent() {
96
+ let content = this.tooltip;
97
+ if (content === false) {
98
+ return undefined;
99
+ }
100
+ if (typeof content === 'string' && content) {
101
+ return content;
102
+ }
103
+ if (content === true && this.menuItem) {
104
+ return this.menuItem.desc || this.menuItem.caption;
105
+ }
106
+ return undefined;
107
+ },
108
+ title() {
109
+ return this.disabled ? this.disabledTip : this.$attrs.title;
110
+ }
111
+ },
112
+ created() {
113
+ this.init();
114
+ },
115
+ watch: {
116
+ granted() {
117
+ this.init();
118
+ },
119
+ dropdown() {
120
+ this.buildDropdownItems();
121
+ },
122
+ },
123
+ methods: {
124
+ init() {
125
+ if (this.granted !== null) {
126
+ this.disabled = !this.granted;
127
+ } else if (this.menu && this.path) {
128
+ let vm = this;
129
+ this.menu.loadGrantedItems(function () {
130
+ vm.disabled = !vm.menu.isGranted(vm.path);
131
+ vm.buildDropdownItems();
132
+ });
133
+ }
134
+ },
135
+ buildDropdownItems() {
136
+ let dropdownItems = [];
137
+ if (this.dropdown) {
138
+ let dropdowns = Array.isArray(this.dropdown) ? this.dropdown : [this.dropdown];
139
+ for (let dropdown of dropdowns) {
140
+ let dropdownItem = typeof dropdown === 'string' ? {
141
+ path: dropdown
142
+ } : (dropdown || {});
143
+
144
+ if (this.menu && dropdownItem.path) {
145
+ dropdownItem.disabled = !this.menu.isGranted(dropdownItem.path);
146
+ if (dropdownItem.disabled && typeof this.disabledTip === 'string') {
147
+ dropdownItem.title = this.disabledTip;
148
+ }
149
+ dropdownItem.menuItem = this.menu.getItemByPath(dropdownItem.path);
150
+ }
151
+
152
+ dropdownItems.push(dropdownItem);
153
+ }
154
+ }
155
+ this.dropdownItems = dropdownItems;
156
+ },
157
+ clickButton() {
158
+ this.clickItem(this);
159
+ },
160
+ clickItem(item) {
161
+ if (!item.disabled) {
162
+ if (typeof this.click === 'function') {
163
+ this.click(item.path);
164
+ } else if (this.$router && this.click !== true && item.menuItem && item.menuItem.path) {
165
+ // click属性为true时执行点击动作而不是跳转
166
+ let vm = this;
167
+ this.$router.push(item.path).catch(function () {
168
+ // 指定路径无法跳转,则触发点击事件
169
+ vm.$emit('click', item.path);
170
+ });
171
+ } else { // 触发点击事件兜底
172
+ this.$emit('click', item.path);
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
178
+ </script>
179
+
180
+ <style>
181
+ tnxel-button {
182
+ visibility: hidden;
183
+ }
184
+ </style>
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <tnxel-icon :value="checked ? trueIcon : falseIcon" class="tnxel-check-icon"
3
+ :class="'text-' + (checked ? trueTheme : falseTheme)" :size="size" @click="click"/>
4
+ </template>
5
+
6
+ <script>
7
+ export default {
8
+ name: 'TnxelCheckIcon',
9
+ props: {
10
+ modelValue: Boolean,
11
+ size: Number,
12
+ trueIcon: {
13
+ type: String,
14
+ default: 'CircleCheckFilled',
15
+ },
16
+ falseIcon: {
17
+ type: String,
18
+ default: 'CircleCheck',
19
+ },
20
+ trueTheme: {
21
+ type: String,
22
+ default: 'primary',
23
+ },
24
+ falseTheme: {
25
+ type: String,
26
+ default: 'secondary',
27
+ },
28
+ trigger: {
29
+ type: Boolean,
30
+ default: true,
31
+ }
32
+ },
33
+ emits: ['update:modelValue'],
34
+ data() {
35
+ return {
36
+ checked: this.modelValue,
37
+ }
38
+ },
39
+ watch: {
40
+ modelValue(value) {
41
+ this.checked = value;
42
+ },
43
+ checked(value) {
44
+ this.$emit('update:modelValue', value);
45
+ }
46
+ },
47
+ methods: {
48
+ click() {
49
+ if (this.trigger) {
50
+ this.checked = !this.checked;
51
+ }
52
+ }
53
+ }
54
+ }
55
+ </script>
56
+
57
+ <style>
58
+ .tnxel-check-icon {
59
+ cursor: pointer;
60
+ }
61
+ </style>
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <el-button type="danger" @click="close()" v-if="text">{{ text }}</el-button>
3
+ </template>
4
+
5
+ <script>
6
+ export default {
7
+ name: 'TnxelCloseErrorButton',
8
+ props: {
9
+ prev: String,
10
+ },
11
+ data() {
12
+ return {};
13
+ },
14
+ computed: {
15
+ backable() {
16
+ return this.prev || window.history.length > 2; // 前两个为新标签页和当前页,需排除
17
+ },
18
+ closeable() {
19
+ return window.opener !== undefined && window.opener !== null;
20
+ },
21
+ text() {
22
+ if (this.backable) {
23
+ return '返回';
24
+ }
25
+ if (this.closeable) {
26
+ return '关闭';
27
+ }
28
+ return undefined;
29
+ },
30
+ },
31
+ methods: {
32
+ close() {
33
+ if (this.backable) {
34
+ if (this.prev) {
35
+ window.location.href = this.prev;
36
+ } else {
37
+ window.history.back();
38
+ }
39
+ } else if (this.closeable) {
40
+ window.close();
41
+ }
42
+ },
43
+ }
44
+ }
45
+ </script>
@@ -0,0 +1,224 @@
1
+ <template>
2
+ <el-col :span="span">
3
+ <el-button :type="btnType" :icon="btnIcon" @click="toAdd" v-if="addable">{{ addText }}</el-button>
4
+ <el-table :data="list" border stripe v-if="showEmpty || (list && list.length)">
5
+ <slot></slot>
6
+ <el-table-column label="操作" header-align="center" align="center"
7
+ :width="util.string.getPixelString(actionWidth)" v-if="updatable || removable">
8
+ <template #default="scope">
9
+ <slot name="actionPrepend" :$index="scope.$index" :row="scope.row" :column="scope.column"></slot>
10
+ <el-button type="primary" link @click="toUpdate(scope.$index)" v-if="updatable">
11
+ {{ updateText }}
12
+ </el-button>
13
+ <el-button type="primary" link @click="toRemove(scope.$index)" v-if="removable">
14
+ {{ removeText }}
15
+ </el-button>
16
+ <slot name="actionAppend" :$index="scope.$index" :row="scope.row" :column="scope.column"></slot>
17
+ </template>
18
+ </el-table-column>
19
+ </el-table>
20
+ </el-col>
21
+ </template>
22
+
23
+ <script>
24
+ export default {
25
+ name: 'TnxelCurd',
26
+ props: {
27
+ page: {
28
+ type: Object,
29
+ required: true,
30
+ },
31
+ pageProps: Object,
32
+ modelValue: Array,
33
+ modelName: String,
34
+ span: Number,
35
+ btnType: {
36
+ type: String,
37
+ default: 'primary',
38
+ },
39
+ btnIcon: String,
40
+ addable: {
41
+ type: Boolean,
42
+ default: true,
43
+ },
44
+ addText: {
45
+ type: String,
46
+ default: '新增',
47
+ },
48
+ add: Function,
49
+ updatable: {
50
+ type: Boolean,
51
+ default: true,
52
+ },
53
+ updateText: {
54
+ type: String,
55
+ default: '修改',
56
+ },
57
+ update: Function,
58
+ removable: {
59
+ type: Boolean,
60
+ default: true,
61
+ },
62
+ removeText: {
63
+ type: String,
64
+ default: '移除',
65
+ },
66
+ remove: Function,
67
+ formatter: Function,
68
+ order: [String, Function],
69
+ showEmpty: {
70
+ type: Boolean,
71
+ default: false,
72
+ },
73
+ toast: {
74
+ type: Boolean,
75
+ default() {
76
+ return null;
77
+ }
78
+ },
79
+ actionWidth: {
80
+ type: [String, Number],
81
+ default() {
82
+ return '100px';
83
+ }
84
+ }
85
+ },
86
+ emits: ['update:modelValue'],
87
+ data() {
88
+ return {
89
+ util: window.tnx.util,
90
+ list: this.modelValue,
91
+ }
92
+ },
93
+ watch: {
94
+ list() {
95
+ this.format();
96
+ this.$emit('update:modelValue', this.list);
97
+ },
98
+ modelValue(modelValue) {
99
+ this.list = modelValue;
100
+ this.format();
101
+ }
102
+ },
103
+ methods: {
104
+ format() {
105
+ if (this.formatter && this.list && this.list.length) {
106
+ for (let i = 0; i < this.list.length; i++) {
107
+ this.list[i] = this.formatter(this.list[i]);
108
+ }
109
+ }
110
+ },
111
+ toAdd() {
112
+ let vm = this;
113
+ window.tnx.open(this.page, this.pageProps, {
114
+ title: vm.addText + (vm.modelName || ''),
115
+ click: function(yes, close) {
116
+ if (yes) {
117
+ if (typeof this.validateForm === 'function') {
118
+ this.validateForm(function(model) {
119
+ if (vm.add) {
120
+ vm.add(model, function() {
121
+ vm._onAdded(model, close);
122
+ });
123
+ } else {
124
+ vm._onAdded(model, close);
125
+ }
126
+ });
127
+ return false;
128
+ }
129
+ }
130
+ }
131
+ });
132
+ },
133
+ _onAdded(model, close) {
134
+ this.list = this.list || [];
135
+ this.list.push(model);
136
+ this._sort();
137
+ if (this.toast === true || (this.toast !== false && this.add)) {
138
+ window.tnx.toast(this.addText + '成功');
139
+ }
140
+ close();
141
+ },
142
+ _sort() {
143
+ let sort = this.order;
144
+ if (typeof sort === 'string') {
145
+ let array = sort.split(' ');
146
+ let orderBy = array[0].trim();
147
+ let desc = array[1] === 'desc';
148
+ sort = function(o1, o2) {
149
+ let v1 = o1[orderBy];
150
+ let v2 = o2[orderBy];
151
+ if (v1 < v2) {
152
+ return desc ? 1 : -1;
153
+ } else if (v1 === v2) {
154
+ return 0;
155
+ } else {
156
+ return desc ? -1 : 1;
157
+ }
158
+ }
159
+ }
160
+ if (typeof sort === 'function') {
161
+ this.list.sort(sort);
162
+ }
163
+ },
164
+ toUpdate(index) {
165
+ let model = Object.assign({}, this.list[index]);
166
+ if (model) {
167
+ let vm = this;
168
+ window.tnx.open(this.page, {
169
+ modelValue: model
170
+ }, {
171
+ title: vm.updateText + (vm.modelName || ''),
172
+ click: function(yes, close) {
173
+ if (yes) {
174
+ if (typeof this.validateForm === 'function') {
175
+ this.validateForm(function(model) {
176
+ if (vm.update) {
177
+ vm.update(index, model, function() {
178
+ vm._onUpdated(index, model, close);
179
+ });
180
+ } else {
181
+ vm._onUpdated(index, model, close);
182
+ }
183
+ });
184
+ return false;
185
+ } else {
186
+ vm._onUpdated(index, model, close);
187
+ }
188
+ }
189
+ }
190
+ });
191
+ }
192
+ },
193
+ _onUpdated(index, model, close) {
194
+ Object.assign(this.list[index], model);
195
+ this._sort();
196
+ if (this.toast === true || (this.toast !== false && this.update)) {
197
+ window.tnx.toast(this.updateText + '成功');
198
+ }
199
+ close();
200
+ },
201
+ toRemove(index) {
202
+ let vm = this;
203
+ let modelName = this.modelName ? ('该' + this.modelName) : '';
204
+ window.tnx.confirm('确定要' + this.removeText + modelName + '吗?', function(yes) {
205
+ if (yes) {
206
+ if (vm.remove) {
207
+ vm.remove(index, function() {
208
+ vm._onRemoved(index);
209
+ });
210
+ } else {
211
+ vm._onRemoved(index);
212
+ }
213
+ }
214
+ });
215
+ },
216
+ _onRemoved(index) {
217
+ this.list.splice(index, 1);
218
+ if (this.toast === true || (this.toast !== false && this.remove)) {
219
+ window.tnx.toast(this.removeText + '成功');
220
+ }
221
+ }
222
+ }
223
+ }
224
+ </script>