@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,402 @@
1
+ <template>
2
+ <div class="tnxel-query-table" :id="id" :class="{selectable: selectable}">
3
+ <el-table ref="table" :data="records" scrollbar-always-on
4
+ :size="size" :border="border" :stripe="stripe" :max-height="tableMaxHeight"
5
+ @sort-change="sort" :default-sort="defaultSort" :key="defaultSortString"
6
+ :row-class-name="rowClassName" @cell-click="selectRow">
7
+ <el-table-column header-align="center" align="center" :width="selectable === 'all' ? 40 : 54"
8
+ v-if="selectable">
9
+ <template #header>
10
+ <el-checkbox :model-value="pageAllSelected" :indeterminate="allSelectedIndeterminate"
11
+ @change="selectAll" v-if="selectable === 'all'"/>
12
+ <span v-else>选择</span>
13
+ </template>
14
+ <template #default="scope">
15
+ <el-checkbox v-model="pageSelectedIndexes[scope.$index]" @change="selectPageToAll"
16
+ v-if="selectable === 'multi' || selectable === 'all'"/>
17
+ </template>
18
+ </el-table-column>
19
+ <slot></slot>
20
+ <template #empty>
21
+ <template v-if="records === null">
22
+ <tnxel-icon value="Loading" :size="18" v-if="querying"/>
23
+ <template v-else>
24
+ <span>尚未开始查询</span>
25
+ <span v-if="paramRequired && emptyParams">,请至少提供一个查询条件</span>
26
+ </template>
27
+ </template>
28
+ <span v-else>&lt;空&gt;</span>
29
+ </template>
30
+ <template #append v-if="records?.length && paged && typeof paged.total !== 'number'">
31
+ <tnxel-button class="py-0 px-1 mx-2 border-0" icon="Top" tooltip="回到顶部" plain
32
+ @click="scrollToTop"/>
33
+ <tnxel-icon class="text-secondary" value="Loading" :size="18" v-if="querying"/>
34
+ <el-button type="primary" link class="m-0" @click="onPagedChange(paged.pageNo + 1)"
35
+ v-else-if="paged.morePage">
36
+ 加载更多
37
+ </el-button>
38
+ <el-button type="info" link v-else>已没有更多</el-button>
39
+ <tnxel-button class="py-0 px-1 mx-2 border-0" icon="Top" tooltip="回到顶部" plain @click="scrollToTop"/>
40
+ </template>
41
+ </el-table>
42
+ <slot name="paged" :paged="paged" :show="showPaged" :query="query"
43
+ v-if="params.pageSize > 0 && typeof paged?.total === 'number'">
44
+ <tnxel-paged :value="paged" :change="onPagedChange" :align="pagedAlign" v-if="showPaged"/>
45
+ </slot>
46
+ </div>
47
+ </template>
48
+
49
+ <script>
50
+ import $ from 'jquery';
51
+ import Icon from '../icon/Icon.vue';
52
+ import Button from '../button/Button.vue';
53
+ import Paged from '../paged/Paged.vue';
54
+
55
+ export default {
56
+ components: {
57
+ 'tnxel-icon': Icon,
58
+ 'tnxel-button': Button,
59
+ 'tnxel-paged': Paged
60
+ },
61
+ name: 'TnxelQueryTable',
62
+ props: {
63
+ url: {
64
+ type: String,
65
+ required: true,
66
+ },
67
+ modelValue: Object, // 查询参数
68
+ size: String,
69
+ border: {
70
+ type: Boolean,
71
+ default: true,
72
+ },
73
+ stripe: {
74
+ type: Boolean,
75
+ default: true,
76
+ },
77
+ showPaged: {
78
+ type: Boolean,
79
+ default: true,
80
+ },
81
+ pagedAlign: String,
82
+ success: Function,
83
+ rowClassName: String,
84
+ formatter: Function,
85
+ order: Function,
86
+ pagedChange: Function,
87
+ selectable: { // 是否可选择
88
+ type: [Boolean, String], // false-不可选择;true/'single'-可单选;'multi'-可多选但不可全选;'all'-可多选且可全选
89
+ default() {
90
+ return false;
91
+ }
92
+ },
93
+ selectName: { // 比较已选对象与表格数据中行对象是否相等的字段名称,这要求数据对象必须具有唯一标识字段
94
+ type: String,
95
+ default() {
96
+ return 'id';
97
+ }
98
+ },
99
+ selected: [Object, Array], // 已选择的行对象
100
+ init: Boolean,
101
+ paramRequired: Boolean, // 是否至少需要一个查询参数
102
+ appendMore: Boolean, // 是否记录追加模式,即当查询页码>1时,后续页记录是否追加到现有记录清单中,false-替代现有记录清单
103
+ fixedHeight: Boolean, // 是否固定高度,true-表格的最大高度固定为容器的高度
104
+ },
105
+ emits: ['update:modelValue', 'update:selected'],
106
+ data() {
107
+ return {
108
+ id: window.tnx.util.string.random(16),
109
+ params: this.getParams(this.modelValue),
110
+ records: null,
111
+ paged: null,
112
+ querying: false,
113
+ pageSelectedIndexes: [], // 当前页已选择记录的索引
114
+ allSelectedRecords: this.selected || [], // 所有已选择的记录
115
+ containerHeight: 0,
116
+ }
117
+ },
118
+ computed: {
119
+ emptyParams() {
120
+ if (this.params) {
121
+ let keys = Object.keys(this.params);
122
+ if (keys.length) {
123
+ let invalidKeys = ['pageSize', 'pageNo', 'orders', 'ignoring'];
124
+ for (let key of keys) {
125
+ if (!invalidKeys.contains(key)) {
126
+ let value = this.params[key];
127
+ if (value !== undefined && value !== null && value !== '') {
128
+ return false;
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+ return true;
135
+ },
136
+ tableMaxHeight() {
137
+ if (this.fixedHeight && this.containerHeight) {
138
+ return typeof this.paged?.total === 'number' ? (this.containerHeight - 40) : this.containerHeight;
139
+ }
140
+ return undefined;
141
+ },
142
+ defaultSort() {
143
+ let sortableColumnNames = [];
144
+ if (this.$slots.default) {
145
+ let columns = this.$slots.default();
146
+ for (let column of columns) {
147
+ if (column.props.prop && column.props.sortable === 'custom') {
148
+ sortableColumnNames.push(column.props.prop);
149
+ }
150
+ }
151
+ }
152
+ if (sortableColumnNames.length) {
153
+ if (this.paged && this.paged.orders && this.paged.orders.length) {
154
+ let fieldOrder = this.paged.orders[0];
155
+ let fieldName = fieldOrder.name;
156
+ if (sortableColumnNames.contains(fieldName)) {
157
+ return {
158
+ prop: fieldName,
159
+ order: fieldOrder.desc ? 'descending' : 'ascending',
160
+ };
161
+ }
162
+ }
163
+ if (this.params && this.params.orderBy) {
164
+ let array = this.params.orderBy.split(' ');
165
+ let fieldName = array[0];
166
+ if (sortableColumnNames.contains(fieldName)) {
167
+ return {
168
+ prop: fieldName,
169
+ order: (array[1] || 'asc').toLowerCase() === 'desc' ? 'descending' : 'ascending',
170
+ }
171
+ }
172
+ }
173
+ }
174
+ return undefined;
175
+ },
176
+ defaultSortString() {
177
+ if (this.defaultSort) {
178
+ return this.defaultSort.prop + ' ' + this.defaultSort.order;
179
+ }
180
+ return undefined;
181
+ },
182
+ pageAllSelected() {
183
+ if (this.records?.length) {
184
+ let selected = null;
185
+ for (let i = 0; i < this.records.length; i++) {
186
+ if (selected === null) {
187
+ selected = this.pageSelectedIndexes[i];
188
+ } else if (selected !== this.pageSelectedIndexes[i]) {
189
+ return null;
190
+ }
191
+ }
192
+ return selected;
193
+ }
194
+ return false;
195
+ },
196
+ allSelectedIndeterminate() {
197
+ if (this.records?.length) {
198
+ let firstSelected = this.pageSelectedIndexes[0] || false;
199
+ if (this.records.length === 1) {
200
+ return firstSelected;
201
+ }
202
+ for (let i = 1; i < this.records.length; i++) {
203
+ let selected = this.pageSelectedIndexes[i] || false;
204
+ if (selected !== firstSelected) {
205
+ return true;
206
+ }
207
+ }
208
+ }
209
+ return false;
210
+ },
211
+ },
212
+ watch: {
213
+ modelValue(value) {
214
+ this.params = this.getParams(value);
215
+ },
216
+ allSelectedRecords() {
217
+ this.$emit('update:selected', this.allSelectedRecords);
218
+ },
219
+ },
220
+ mounted() {
221
+ if (this.init) {
222
+ this.query();
223
+ }
224
+ let vm = this;
225
+ this.$nextTick(() => {
226
+ vm.containerHeight = $('.tnxel-query-table[id="' + vm.id + '"]').height();
227
+ });
228
+ },
229
+ methods: {
230
+ getParams(modelValue) {
231
+ return Object.assign({}, modelValue); // 避免改动传入的参数对象
232
+ },
233
+ onPagedChange(pageNo) {
234
+ if (this.pagedChange && this.pagedChange(pageNo) === false) {
235
+ return;
236
+ }
237
+ this.query(pageNo);
238
+ },
239
+ query(params) {
240
+ if (typeof params === 'number') { // 参数为页码
241
+ this.params.pageNo = params;
242
+ if (this.modelValue) { // 指定了modelValue属性,在页码变更时需要触发更新事件
243
+ this.$emit('update:modelValue', this.params);
244
+ }
245
+ } else if (typeof params === 'object') {
246
+ this.params = this.getParams(params);
247
+ this.params.pageNo = this.params.pageNo || 1;
248
+ // 带查询条件参数对象的为全新查询,清空已选清单
249
+ this.pageSelectedIndexes = [];
250
+ this.allSelectedRecords = [];
251
+ }
252
+
253
+ if (this.paramRequired && this.emptyParams) {
254
+ this.records = null;
255
+ this.paged = null;
256
+ } else {
257
+ this.querying = true;
258
+ // 在追加记录模式中,如果查询页码大于1,则不清除现有记录,否则清除现有记录
259
+ if (!this.appendMore || !this.params.pageNo || this.params.pageNo <= 1) {
260
+ this.records = null;
261
+ this.paged = null;
262
+ }
263
+ let vm = this;
264
+ window.tnx.app.rpc.get(this.url, this.params, function (result) {
265
+ vm.querying = false;
266
+ if (Array.isArray(result)) {
267
+ vm.records = vm.format(result);
268
+ } else {
269
+ let records = vm.format(result.records);
270
+ if (result.paged.pageNo > 1 && vm.appendMore) { // 追加记录
271
+ vm.records = vm.records || [];
272
+ // 结果页码大于当前页码才追加记录
273
+ if (result.paged.pageNo > vm.paged.pageNo) {
274
+ vm.records = vm.records.concat(records);
275
+ }
276
+ } else { // 替代记录
277
+ vm.records = records;
278
+ }
279
+ vm.paged = result.paged;
280
+ }
281
+ vm.selectAllToPage();
282
+ if (vm.success) {
283
+ vm.success(vm.records, vm.paged);
284
+ }
285
+ });
286
+ }
287
+ },
288
+ format(records) {
289
+ if (this.formatter) {
290
+ return this.formatter(records);
291
+ }
292
+ return records;
293
+ },
294
+ sort(options) {
295
+ if (options && options.prop && options.order) {
296
+ this.params.orderBy = options.prop + (options.order === 'descending' ? ' desc' : '');
297
+ } else {
298
+ delete this.params.orderBy;
299
+ }
300
+ this.params.pageNo = 1;
301
+ if (this.modelValue) {
302
+ this.$emit('update:modelValue', this.params);
303
+ }
304
+ if (this.order && this.order(this.params.orderBy) === false) {
305
+ return;
306
+ }
307
+ this.query();
308
+ },
309
+ selectRow(row, column, cell) {
310
+ if (this.selectable && this.records && column.getColumnIndex() > 0 && !cell.innerHTML.contains('</a>')) {
311
+ let vm = this;
312
+ let index = window.tnx.util.array.indexOf(this.records, function (element) {
313
+ return row[vm.selectName] === element[vm.selectName];
314
+ });
315
+ if (index >= 0) {
316
+ this.pageSelectedIndexes[index] = !this.pageSelectedIndexes[index];
317
+ this.selectPageToAll();
318
+ }
319
+ }
320
+ },
321
+ selectAll(selected) {
322
+ if (this.records?.length) {
323
+ for (let i = 0; i < this.records.length; i++) {
324
+ this.pageSelectedIndexes[i] = selected;
325
+ }
326
+ this.selectPageToAll();
327
+ }
328
+ },
329
+ selectPageToAll() {
330
+ let vm = this;
331
+ for (let index = 0; index < this.pageSelectedIndexes.length; index++) {
332
+ let selectedInPage = this.pageSelectedIndexes[index];
333
+ let record = this.records[index];
334
+ let fnEquals = function (element) {
335
+ return record[vm.selectName] === element[vm.selectName];
336
+ };
337
+ let selectedInAll = this.allSelectedRecords.contains(fnEquals);
338
+ if (selectedInPage && !selectedInAll) { // 当前页已选但全局未选,则加入全局已选清单
339
+ this.allSelectedRecords.push(record);
340
+ } else if (!selectedInPage && selectedInAll) { // 当前页未选但全局已选,则从全局已选中移除
341
+ this.allSelectedRecords.remove(fnEquals);
342
+ }
343
+ }
344
+ this.$emit('update:selected', this.allSelectedRecords);
345
+ },
346
+ selectAllToPage() {
347
+ if (this.selectable) {
348
+ let vm = this;
349
+ if (!Array.isArray(this.allSelectedRecords)) {
350
+ this.allSelectedRecords = [this.allSelectedRecords];
351
+ }
352
+ this.pageSelectedIndexes = [];
353
+ for (let selectedRecord of this.allSelectedRecords) {
354
+ for (let i = 0; i < this.records.length; i++) {
355
+ let record = this.records[i];
356
+ if (record[vm.selectName] === selectedRecord[vm.selectName]) {
357
+ this.pageSelectedIndexes[i] = true;
358
+ }
359
+ }
360
+ }
361
+ }
362
+ },
363
+ scrollToTop() {
364
+ if (this.tableMaxHeight) {
365
+ this.$refs.table.setScrollTop(0);
366
+ } else {
367
+ window.tnx.util.dom.scrollToTop();
368
+ }
369
+ },
370
+ }
371
+ }
372
+ </script>
373
+
374
+ <style>
375
+ .tnxel-query-table .el-table__empty-text {
376
+ min-width: 260px;
377
+ display: flex;
378
+ align-items: center;
379
+ justify-content: center;
380
+ }
381
+
382
+ .tnxel-query-table .el-table__append-wrapper {
383
+ height: 41px;
384
+ display: flex;
385
+ align-items: center;
386
+ justify-content: space-between;
387
+ }
388
+
389
+ .tnxel-query-table.selectable .el-table__row {
390
+ cursor: pointer;
391
+ }
392
+
393
+ .tnxel-query-table.selectable .el-checkbox {
394
+ height: auto;
395
+ }
396
+
397
+ .tnxel-query-table.selectable .el-table__cell:first-child .cell {
398
+ display: flex;
399
+ align-items: center;
400
+ justify-content: center;
401
+ }
402
+ </style>
@@ -0,0 +1,108 @@
1
+ <template>
2
+ <el-cascader v-model="model" class="ignore-feedback" :options="region.subs" :props="options"
3
+ :placeholder="placeholder" :disabled="disabled" :clearable="empty"/>
4
+ </template>
5
+
6
+ <script>
7
+ export default {
8
+ name: 'TnxelRegionCascader',
9
+ props: {
10
+ modelValue: String,
11
+ scope: {
12
+ type: String,
13
+ default: () => 'CN',
14
+ },
15
+ maxLevel: {
16
+ type: [Number, String],
17
+ default: 3,
18
+ },
19
+ minLevel: {
20
+ type: [Number, String],
21
+ default: 3,
22
+ },
23
+ empty: {
24
+ type: Boolean,
25
+ default: false,
26
+ },
27
+ placeholder: String,
28
+ disabled: Boolean,
29
+ change: Function, // 选中值变化后的事件处理函数,由于比element的change事件传递更多参数,所以以prop的形式指定,以尽量节省性能
30
+ },
31
+ emits: ['update:modelValue'],
32
+ data() {
33
+ // 最小级别小于最大级别,则取消父子节点选中关联,允许选择中间级别的节点
34
+ let checkStrictly = parseInt(this.minLevel) < parseInt(this.maxLevel);
35
+ return {
36
+ options: {
37
+ expandTrigger: 'hover',
38
+ emitPath: false,
39
+ value: 'code',
40
+ label: 'caption',
41
+ children: 'subs',
42
+ leaf: 'includingSub',
43
+ checkStrictly: checkStrictly,
44
+ },
45
+ model: null,
46
+ region: {},
47
+ };
48
+ },
49
+ watch: {
50
+ model(value) {
51
+ this.$emit('update:modelValue', value);
52
+ this.triggerChange(value);
53
+ },
54
+ modelValue() {
55
+ this.model = this.getModel();
56
+ }
57
+ },
58
+ created() {
59
+ let vm = this;
60
+ window.tnx.app.rpc.loadRegion(this.scope, parseInt(this.maxLevel), function(region) {
61
+ vm.region = region;
62
+ vm.model = vm.getModel();
63
+ });
64
+ },
65
+ methods: {
66
+ triggerChange(value) {
67
+ if (this.change) {
68
+ let item = this.getItem(this.region.subs, value);
69
+ this.change(item);
70
+ }
71
+ },
72
+ getItem(items, value) {
73
+ if (items && value !== undefined) {
74
+ for (let item of items) {
75
+ if (item.code === value) {
76
+ return item;
77
+ }
78
+ let sub = this.getItem(item.subs, value);
79
+ if (sub) {
80
+ return sub;
81
+ }
82
+ }
83
+ }
84
+ return undefined;
85
+ },
86
+ getModel() {
87
+ if (this.region) {
88
+ let items = this.region.subs;
89
+ if (items && items.length) {
90
+ let item = this.getItem(items, this.modelValue);
91
+ if (item) {
92
+ return item.code;
93
+ } else { // 如果当前值找不到匹配的选项,则需要考虑是设置为空还是默认选项
94
+ if (!this.empty) { // 如果不能为空,则默认选中第一个叶子节点选项
95
+ let firstItem = items[0];
96
+ while (firstItem.subs && firstItem.subs.length) {
97
+ firstItem = firstItem.subs[0];
98
+ }
99
+ return firstItem ? firstItem.code : null;
100
+ }
101
+ }
102
+ }
103
+ }
104
+ return null;
105
+ }
106
+ }
107
+ }
108
+ </script>