@truenewx/tnxvue3 3.4.3 → 3.4.5

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 (47) hide show
  1. package/package.json +12 -6
  2. package/src/bootstrap-vue/dialog/Dialog.vue +22 -10
  3. package/src/element-plus/aj-captcha/api/index.js +2 -2
  4. package/src/element-plus/avatar/Avatar.vue +4 -27
  5. package/src/element-plus/date-picker/DatePicker.vue +8 -9
  6. package/src/element-plus/dialog/Dialog.vue +34 -22
  7. package/src/element-plus/drawer/Drawer.vue +22 -5
  8. package/src/element-plus/edit-table/EditTable.vue +10 -10
  9. package/src/element-plus/enum-select/EnumSelect.vue +30 -30
  10. package/src/element-plus/enum-view/EnumView.vue +1 -3
  11. package/src/element-plus/fetch-cascader/FetchCascader.vue +4 -4
  12. package/src/element-plus/fetch-select/FetchSelect.vue +3 -3
  13. package/src/element-plus/fetch-tags/FetchTags.vue +1 -1
  14. package/src/element-plus/fss-upload/FssUpload.vue +76 -115
  15. package/src/element-plus/fss-view/FssView.vue +28 -30
  16. package/src/element-plus/icon/Icon.vue +3 -0
  17. package/src/element-plus/query-form/QueryForm.vue +3 -3
  18. package/src/element-plus/query-table/QueryTable.vue +12 -12
  19. package/src/element-plus/region-cascader/RegionCascader.vue +3 -3
  20. package/src/element-plus/select/Select.vue +56 -56
  21. package/src/element-plus/submit-form/SubmitForm.vue +5 -5
  22. package/src/element-plus/tnxel-validator.ts +347 -0
  23. package/src/element-plus/tnxel.css +0 -8
  24. package/src/element-plus/tnxel.ts +561 -0
  25. package/src/element-plus/transfer/Transfer.vue +2 -2
  26. package/src/element-plus/upload/Upload.vue +68 -70
  27. package/src/tdesign/desktop/tnxtdd.ts +5 -5
  28. package/src/tdesign/mobile/calendar/Calendar.vue +121 -0
  29. package/src/tdesign/mobile/date-time-picker/DateTimePicker.vue +147 -0
  30. package/src/tdesign/mobile/dialog/Dialog.vue +179 -0
  31. package/src/tdesign/mobile/dialog/DialogContent.vue +13 -0
  32. package/src/tdesign/mobile/drawer/Drawer.vue +176 -0
  33. package/src/tdesign/mobile/drawer/DrawerContent.vue +13 -0
  34. package/src/tdesign/mobile/enum-select/EnumSelect.vue +160 -0
  35. package/src/tdesign/mobile/popup/Popup.vue +106 -0
  36. package/src/tdesign/mobile/region-picker/RegionPicker.vue +223 -0
  37. package/src/tdesign/mobile/select/Select.vue +478 -0
  38. package/src/tdesign/mobile/slide-radio-group/SlideRadioGroup.vue +392 -0
  39. package/src/tdesign/mobile/tnxtdm.css +132 -0
  40. package/src/tdesign/mobile/tnxtdm.ts +310 -7
  41. package/src/tdesign/{foundation/validator.ts → tnxtd-validator.ts} +18 -17
  42. package/src/tdesign/tnxtd.css +66 -0
  43. package/src/tdesign/tnxtd.ts +10 -7
  44. package/src/tnxvue-router.ts +65 -18
  45. package/src/tnxvue.ts +71 -31
  46. package/tsconfig.json +33 -19
  47. package/src/element-plus/tnxel.js +0 -598
@@ -1,69 +1,69 @@
1
1
  <template>
2
- <el-upload ref="upload" name="file" class="tnxel-upload-container"
3
- :class="{center: center, 'hide-file-list': !showFileList}"
4
- :id="id"
5
- :action="actionUrl"
6
- :before-upload="_beforeUpload"
7
- :on-progress="_onProgress"
8
- :on-success="_onSuccess"
9
- :on-error="_onError"
10
- :with-credentials="true"
11
- :list-type="listType"
12
- :file-list="fileList"
13
- :show-file-list="true"
14
- :headers="uploadHeaders"
15
- :multiple="uploadOptions && uploadOptions.number !== 1"
16
- :accept="uploadAccept" :disabled="disabled" v-if="uploadOptions">
17
- <template #file="{file}">
18
- <div class="el-upload-list__panel" :data-file-id="getFileId(file)" :style="itemPanelStyle"
19
- v-if="showFileList">
20
- <img class="el-upload-list__item-thumbnail" :src="file.url" v-if="imageable">
21
- <div class="el-upload-list__item-name" v-else>
22
- <tnxel-icon :value="getFileIcon(file)"/>
23
- <span>{{ file.name }}</span>
24
- </div>
25
- <span class="el-upload-list__item-uploading" v-if="isUploading(file) && listType !== 'text'">
2
+ <el-upload ref="upload" name="file" class="tnxel-upload-container"
3
+ :class="{center: center, 'hide-file-list': !showFileList}"
4
+ :id="id"
5
+ :action="actionUrl"
6
+ :before-upload="_beforeUpload"
7
+ :on-progress="_onProgress"
8
+ :on-success="_onSuccess"
9
+ :on-error="_onError"
10
+ :with-credentials="true"
11
+ :list-type="listType"
12
+ :file-list="fileList"
13
+ :show-file-list="true"
14
+ :headers="uploadHeaders"
15
+ :multiple="uploadOptions && uploadOptions.number !== 1"
16
+ :accept="uploadAccept" :disabled="disabled" v-if="uploadOptions">
17
+ <template #file="{file}">
18
+ <div class="el-upload-list__panel" :data-file-id="getFileId(file)" :style="itemPanelStyle"
19
+ v-if="showFileList">
20
+ <img class="el-upload-list__item-thumbnail" :src="file.url" v-if="imageable">
21
+ <div class="el-upload-list__item-name" v-else>
22
+ <tnxel-icon :value="getFileIcon(file)"/>
23
+ <span>{{ file.name }}</span>
24
+ </div>
25
+ <span class="el-upload-list__item-uploading" v-if="isUploading(file) && listType !== 'text'">
26
26
  <tnxel-icon value="Loading"/>
27
27
  </span>
28
- <label class="el-upload-list__item-status-label">
29
- <el-progress type="circle" :percentage="file.percentage" :width="16" :stroke-width="3"
30
- :show-text="false" v-if="isUploading(file)"/>
31
- <tnxel-icon value="CircleCheck" class="text-success" v-else-if="listType === 'text'"/>
32
- <tnxel-icon value="Check" style="margin-top: 8px;" v-else/>
33
- </label>
34
- <div class="el-upload-list__item-actions">
35
- <tnxel-icon value="ZoomIn" @click="previewFile(file)" v-if="isPreviewable(file)"/>
36
- <tnxel-icon :value="listType === 'text' ? 'Close' : 'Delete'" @click="removeFile(file)"/>
37
- </div>
28
+ <label class="el-upload-list__item-status-label">
29
+ <el-progress type="circle" :percentage="file.percentage" :width="16" :stroke-width="3"
30
+ :show-text="false" v-if="isUploading(file)"/>
31
+ <tnxel-icon value="CircleCheck" class="text-success" v-else-if="listType === 'text'"/>
32
+ <tnxel-icon value="Check" style="margin-top: 8px;" v-else/>
33
+ </label>
34
+ <div class="el-upload-list__item-actions">
35
+ <tnxel-icon value="ZoomIn" @click="previewFile(file)" v-if="isPreviewable(file)"/>
36
+ <tnxel-icon :value="listType === 'text' ? 'Close' : 'Delete'" @click="removeFile(file)"/>
37
+ </div>
38
+ </div>
39
+ </template>
40
+ <template #trigger>
41
+ <el-tooltip :content="tipContent" placement="top" :disabled="tip !== 'tooltip'">
42
+ <div class="upload-trigger" :title="tip === 'title' ? tipContent : undefined"
43
+ :class="{'text-placeholder': disabled}" v-if="$slots.trigger">
44
+ <slot name="trigger"></slot>
45
+ </div>
46
+ <el-button class="upload-trigger" :title="tip === 'title' ? tipContent : undefined"
47
+ :disabled="disabled" v-else-if="listType === 'text'">
48
+ <tnxel-icon :value="triggerIcon" :size="uploadIconSize"/>
49
+ <div class="upload-trigger-text" v-if="triggerText">{{ triggerText }}</div>
50
+ </el-button>
51
+ <div class="upload-trigger" :title="tip === 'title' ? tipContent : undefined"
52
+ :class="{'text-placeholder': disabled}" v-else>
53
+ <tnxel-icon :value="triggerIcon" :size="uploadIconSize"/>
54
+ <div class="upload-trigger-text" v-if="triggerText">{{ triggerText }}</div>
55
+ </div>
56
+ </el-tooltip>
57
+ </template>
58
+ <template #tip v-if="(tipContent && (typeof tip !== 'string')) || errors.length">
59
+ <tnxel-alert type="error" class="w-fit-content my-0" v-if="errors.length">
60
+ <div v-for="error of errors" :key="error.code">
61
+ {{ error.message }}
38
62
  </div>
39
- </template>
40
- <template #trigger>
41
- <el-tooltip :content="tipContent" placement="top" :disabled="tip !== 'tooltip'">
42
- <div class="upload-trigger" :title="tip === 'title' ? tipContent : undefined"
43
- :class="{'text-placeholder': disabled}" v-if="$slots.trigger">
44
- <slot name="trigger"></slot>
45
- </div>
46
- <el-button class="upload-trigger" :title="tip === 'title' ? tipContent : undefined"
47
- :disabled="disabled" v-else-if="listType === 'text'">
48
- <tnxel-icon :value="triggerIcon" :size="uploadIconSize"/>
49
- <div class="upload-trigger-text" v-if="triggerText">{{ triggerText }}</div>
50
- </el-button>
51
- <div class="upload-trigger" :title="tip === 'title' ? tipContent : undefined"
52
- :class="{'text-placeholder': disabled}" v-else>
53
- <tnxel-icon :value="triggerIcon" :size="uploadIconSize"/>
54
- <div class="upload-trigger-text" v-if="triggerText">{{ triggerText }}</div>
55
- </div>
56
- </el-tooltip>
57
- </template>
58
- <template #tip v-if="(tipContent && (typeof tip !== 'string')) || errors.length">
59
- <tnxel-alert type="error" class="w-fit-content my-0" v-if="errors.length">
60
- <div v-for="error of errors" :key="error.code">
61
- {{ error.message }}
62
- </div>
63
- </tnxel-alert>
64
- <div class="el-upload__tip" v-text="tipContent" v-else></div>
65
- </template>
66
- </el-upload>
63
+ </tnxel-alert>
64
+ <div class="el-upload__tip" v-text="tipContent" v-else></div>
65
+ </template>
66
+ </el-upload>
67
67
  </template>
68
68
 
69
69
  <script>
@@ -171,7 +171,7 @@ export default {
171
171
  computed: {
172
172
  actionUrl() {
173
173
  if (this.app) {
174
- let baseUrl = this.tnx.app.rpc.getBaseUrl(this.app);
174
+ let baseUrl = this.tnx.api.getBaseUrl(this.app);
175
175
  if (baseUrl) {
176
176
  return baseUrl + this.action;
177
177
  }
@@ -233,7 +233,7 @@ export default {
233
233
  },
234
234
  uploadAccept() {
235
235
  if (this.uploadOptions && !this.uploadOptions.extensionsRejected && this.uploadOptions.extensions
236
- && this.uploadOptions.extensions.length) {
236
+ && this.uploadOptions.extensions.length) {
237
237
  let accept = '';
238
238
  for (let extension of this.uploadOptions.extensions) {
239
239
  accept += ',.' + extension;
@@ -342,7 +342,7 @@ export default {
342
342
  } else {
343
343
  // 没有URL的文件,通过文件类型+文件名+文件大小+最后修改时间,几乎可以唯一区分一个文件,重复的概率极低,即使重复也不破坏业务一致性和完整性
344
344
  file.id = this.tnx.util.string.md5(
345
- file.type + '-' + file.name + '-' + file.size + '-' + file.lastModified);
345
+ file.type + '-' + file.name + '-' + file.size + '-' + file.lastModified);
346
346
  }
347
347
  }
348
348
  return file.id;
@@ -382,7 +382,7 @@ export default {
382
382
  const capacity = this.tnx.util.string.getCapacityCaption(this.uploadOptions.capacity);
383
383
  let message = this.tipMessages.capacity.format(capacity, 2);
384
384
  message += ',文件"' + file.name + '"大小为' + this.tnx.util.string.getCapacityCaption(file.size, 2)
385
- + ',不符合要求,未加入上传队列';
385
+ + ',不符合要求,未加入上传队列';
386
386
  this.handleErrors([{
387
387
  code: 'error.upload.capacity',
388
388
  message: message,
@@ -429,7 +429,7 @@ export default {
429
429
  this.handleErrors([]); // 先清除可能存在的错误提示,以便于重新提示
430
430
 
431
431
  const vm = this;
432
- const rpc = this.tnx.app.rpc;
432
+ const rpc = this.tnx.api;
433
433
  return new Promise((resolve, reject) => {
434
434
  if (vm.validate(file)) {
435
435
  let $upload = $('#' + vm.id + ' .el-upload');
@@ -532,9 +532,7 @@ export default {
532
532
  if (this.onError) {
533
533
  this.onError(file, message.message);
534
534
  } else {
535
- this.tnx.app.rpc.handle500Error(message.message, {
536
- error: this.handleErrors
537
- });
535
+ window.tnx.error(message.message);
538
536
  }
539
537
  return;
540
538
  } else if (message.errors) {
@@ -1,12 +1,12 @@
1
- import { App, Component } from 'vue';
2
- import { Router } from 'vue-router';
3
- import TnxTd from '../tnxtd';
1
+ import {App, Component} from 'vue';
2
+ import {Router} from 'vue-router';
3
+ import TnxTd from '../tnxtd.ts';
4
4
  import TDesign from 'tdesign-vue-next';
5
5
 
6
6
  export default class TnxTdd extends TnxTd {
7
7
 
8
- constructor(apiBaseUrl: string) {
9
- super(apiBaseUrl);
8
+ constructor(apiBaseUrl: string, id: string = 'tnxtdd') {
9
+ super(apiBaseUrl, id);
10
10
  }
11
11
 
12
12
  createVueApp(rootComponent: Component, router: Router, rootProps?: Record<string, any>): App {
@@ -0,0 +1,121 @@
1
+ <template>
2
+ <div class="tnxtdm-calendar">
3
+ <div class="tnxtdm-calendar__value">{{ modelValue }}</div>
4
+ <div class="tnxtdm-calendar__icon" :style="{color: iconColor}" @click="visible = true">
5
+ <t-icon name="calendar-1"/>
6
+ </div>
7
+ <t-calendar
8
+ v-model:visible="visible"
9
+ :value="calendarValue"
10
+ type="single"
11
+ switch-mode="year-month"
12
+ :min-date="finalMinDate"
13
+ :max-date="finalMaxDate"
14
+ :title="title"
15
+ @confirm="confirm"
16
+ />
17
+ </div>
18
+ </template>
19
+
20
+ <script>
21
+ const pattern = 'yyyy-MM-dd';
22
+
23
+ function parseDate(val) {
24
+ if (!val) {
25
+ return undefined;
26
+ }
27
+ if (val instanceof Date) {
28
+ return val;
29
+ }
30
+ if (typeof val === 'number') {
31
+ return new Date(val);
32
+ }
33
+ if (typeof val === 'string') {
34
+ val = val.replace(/-/g, '/');
35
+ }
36
+ const d = new Date(val);
37
+ if (!isNaN(d.getTime())) {
38
+ return d;
39
+ }
40
+ return undefined;
41
+ }
42
+
43
+ export default {
44
+ name: 'TnxtdmCalendar',
45
+ props: {
46
+ modelValue: String,
47
+ title: String,
48
+ defaultValue: {
49
+ type: String,
50
+ default: () => {
51
+ return new Date().format(pattern);
52
+ },
53
+ },
54
+ minDate: {
55
+ type: [String, Number, Date],
56
+ default: '1900-01-01',
57
+ },
58
+ maxDate: {
59
+ type: [String, Number, Date],
60
+ default: '2099-12-31',
61
+ },
62
+ iconColor: String,
63
+ },
64
+ data() {
65
+ return {
66
+ visible: false,
67
+ calendarValue: parseDate(this.modelValue || this.defaultValue),
68
+ };
69
+ },
70
+ computed: {
71
+ finalMinDate() {
72
+ return parseDate(this.minDate);
73
+ },
74
+ finalMaxDate() {
75
+ return parseDate(this.maxDate);
76
+ },
77
+ },
78
+ emits: ['update:modelValue'],
79
+ watch: {
80
+ modelValue() {
81
+ this.init();
82
+ },
83
+ visible(val) {
84
+ if (val) {
85
+ this.init();
86
+ }
87
+ },
88
+ },
89
+ mounted() {
90
+ this.init();
91
+ },
92
+ methods: {
93
+ init() {
94
+ let value = this.modelValue || this.defaultValue;
95
+ this.calendarValue = parseDate(value);
96
+ },
97
+ confirm(val) {
98
+ let result = new Date(val).format(pattern);
99
+ this.$emit('update:modelValue', result);
100
+ this.visible = false;
101
+ },
102
+ },
103
+ };
104
+ </script>
105
+
106
+ <style>
107
+ .tnxtdm-calendar {
108
+ display: flex;
109
+ align-items: center;
110
+
111
+ .tnxtdm-calendar__value {
112
+ min-width: 95px;
113
+ }
114
+
115
+ .tnxtdm-calendar__icon {
116
+ display: flex;
117
+ align-items: center;
118
+ color: var(--td-text-color-primary);
119
+ }
120
+ }
121
+ </style>
@@ -0,0 +1,147 @@
1
+ <template>
2
+ <div class="tnxtdm-date-time-picker">
3
+ <div class="tnxtdm-date-time-picker__value" :data-mode="mode">{{ model }}</div>
4
+ <div class="tnxtdm-date-time-picker__icon" :style="{color: iconColor}" @click="visible = true">
5
+ <t-icon name="calendar-1"/>
6
+ </div>
7
+ <t-popup v-model="visible" placement="bottom">
8
+ <t-date-time-picker
9
+ v-model="pickerValue"
10
+ :format="format"
11
+ :mode="mode"
12
+ :title="title"
13
+ :start="getDateValue(start)"
14
+ :end="getDateValue(end)"
15
+ @confirm="confirm"
16
+ @cancel="visible = false"
17
+ v-if="visible"/>
18
+ </t-popup>
19
+ </div>
20
+ </template>
21
+
22
+ <script>
23
+ export default {
24
+ name: 'TnxtdmDateTimePicker',
25
+ props: {
26
+ modelValue: String,
27
+ title: String,
28
+ defaultValue: {
29
+ type: [String, Number],
30
+ default: () => {
31
+ return new Date().getTime();
32
+ },
33
+ },
34
+ mode: {
35
+ type: String,
36
+ default: 'date',
37
+ },
38
+ showCellTitle: Boolean,
39
+ start: {
40
+ type: [String, Number],
41
+ default: '1000-01-01 00:00:00',
42
+ },
43
+ end: {
44
+ type: [String, Number],
45
+ default: '9999-12-31 23:59:59',
46
+ },
47
+ iconColor: String,
48
+ },
49
+ data() {
50
+ return {
51
+ visible: false,
52
+ model: this.modelValue || '',
53
+ pickerValue: '',
54
+ };
55
+ },
56
+ computed: {
57
+ format() {
58
+ switch (this.mode) {
59
+ case 'year':
60
+ return 'YYYY';
61
+ case 'month':
62
+ return 'YYYY-MM';
63
+ case 'date':
64
+ return 'YYYY-MM-DD';
65
+ case 'hour':
66
+ return 'YYYY-MM-DD HH';
67
+ case 'minute':
68
+ return 'YYYY-MM-DD HH:mm';
69
+ case 'second':
70
+ return 'YYYY-MM-DD HH:mm:ss';
71
+ }
72
+ return undefined;
73
+ },
74
+ pattern() {
75
+ return this.format.replace('YYYY', 'yyyy').replace('DD', 'dd');
76
+ },
77
+ },
78
+ emits: ['update:modelValue'],
79
+ watch: {
80
+ modelValue(val) {
81
+ this.model = val;
82
+ },
83
+ model(val) {
84
+ this.$emit('update:modelValue', val);
85
+ },
86
+ visible(val) {
87
+ if (val) {
88
+ this.pickerValue = this.model || this.getDateValue(this.defaultValue);
89
+ }
90
+ }
91
+ },
92
+ methods: {
93
+ getDateValue(date) {
94
+ if (date) {
95
+ return new Date(date).format(this.pattern);
96
+ }
97
+ return undefined;
98
+ },
99
+ confirm(value) {
100
+ this.model = String(value);
101
+ this.visible = false;
102
+ },
103
+ }
104
+ }
105
+ </script>
106
+
107
+ <style>
108
+ .tnxtdm-date-time-picker {
109
+ display: flex;
110
+ align-items: center;
111
+
112
+ .tnxtdm-date-time-picker__value {
113
+ display: flex;
114
+ align-items: center;
115
+
116
+ &[data-mode="year"] {
117
+ min-width: 44px;
118
+ }
119
+
120
+ &[data-mode="month"] {
121
+ min-width: 70px;
122
+ }
123
+
124
+ &[data-mode="date"] {
125
+ min-width: 95px;
126
+ }
127
+
128
+ &[data-mode="hour"] {
129
+ min-width: 119px;
130
+ }
131
+
132
+ &[data-mode="minute"] {
133
+ min-width: 141px;
134
+ }
135
+
136
+ &[data-mode="second"] {
137
+ min-width: 164px;
138
+ }
139
+ }
140
+
141
+ .tnxtdm-date-time-picker__icon {
142
+ display: flex;
143
+ align-items: center;
144
+ color: var(--td-text-color-primary);
145
+ }
146
+ }
147
+ </style>
@@ -0,0 +1,179 @@
1
+ <template>
2
+ <t-dialog
3
+ class="tnxtdm-dialog"
4
+ v-model:visible="visible"
5
+ :title="title"
6
+ :width="width"
7
+ :close-on-overlay-click="options['close-on-overlay-click']"
8
+ :close-btn="!buttons?.length"
9
+ :destroy-on-close="true"
10
+ @closed="onClosed"
11
+ >
12
+ <template #default>
13
+ <div v-if="content" v-html="content"></div>
14
+ <tnxtdm-dialog-content ref="content" v-bind="contentProps" v-else/>
15
+ </template>
16
+ <template #actions v-if="buttons?.length">
17
+ <div class="tnxtdm-dialog-footer">
18
+ <t-button v-for="(button, index) in buttons" :key="index" :theme="button.type || 'primary'"
19
+ :loading="buttonLoadings[index]" @click="btnClick(index)" block>
20
+ {{ button.caption || button.text }}
21
+ </t-button>
22
+ </div>
23
+ </template>
24
+ </t-dialog>
25
+ </template>
26
+
27
+ <script>
28
+ import DialogContent from './DialogContent.vue';
29
+
30
+ export default {
31
+ name: 'TnxtdmDialog',
32
+ components: {
33
+ 'tnxtdm-dialog-content': DialogContent,
34
+ },
35
+ props: {
36
+ id: {
37
+ type: String,
38
+ default: () => window.tnx.util.string.uuid32(),
39
+ },
40
+ modelValue: Boolean,
41
+ container: String,
42
+ title: String,
43
+ content: String,
44
+ contentProps: Object,
45
+ buttons: Array,
46
+ theme: String,
47
+ width: {
48
+ type: [Number, String],
49
+ default: '100%',
50
+ },
51
+ },
52
+ emits: ['update:modelValue', 'shown', 'closed'],
53
+ data() {
54
+ return {
55
+ visible: this.modelValue,
56
+ options: {
57
+ modal: true,
58
+ 'close-on-overlay-click': true,
59
+ onShown: undefined,
60
+ onClosed: undefined,
61
+ beforeClose: undefined,
62
+ },
63
+ buttonLoadings: [],
64
+ };
65
+ },
66
+ watch: {
67
+ modelValue(val) {
68
+ this.visible = val;
69
+ },
70
+ visible(val) {
71
+ this.$emit('update:modelValue', val);
72
+ }
73
+ },
74
+ mounted() {
75
+ this.$nextTick(() => {
76
+ if (this.$refs.content && !this.$refs.content.close) {
77
+ this.$refs.content.close = () => {
78
+ this.close();
79
+ }
80
+ }
81
+
82
+ if (typeof this.options.onShown === 'function') {
83
+ this.options.onShown.call(this);
84
+ } else {
85
+ this.$emit('shown');
86
+ }
87
+ });
88
+ },
89
+ methods: {
90
+ btnClick(index) {
91
+ const button = this.buttons[index];
92
+ if (button) {
93
+ let click = button.click;
94
+ if (typeof click === 'string') {
95
+ if (typeof this.$refs.content[click] === 'function') {
96
+ click = this.$refs.content[click];
97
+ } else {
98
+ console.error(`Method '${click}' not found in component:`, this.$refs.content);
99
+ click = null;
100
+ }
101
+ }
102
+
103
+ if (typeof click === 'function') {
104
+ let result = click.call(this.$refs.content, this.close);
105
+ if (result === 'loading') {
106
+ this.buttonLoadings[index] = true;
107
+ return;
108
+ }
109
+ if (result === false) {
110
+ return;
111
+ }
112
+ }
113
+ }
114
+ this.close();
115
+ },
116
+ close() {
117
+ return new Promise((resolve) => {
118
+ this.beforeClose(() => {
119
+ const originalOnClosed = this.options.onClosed;
120
+ this.options.onClosed = window.tnx.util.function.around(originalOnClosed, function (onClosed) {
121
+ if (onClosed) {
122
+ onClosed();
123
+ }
124
+ resolve();
125
+ });
126
+ this.visible = false;
127
+ });
128
+ });
129
+ },
130
+ beforeClose(done) {
131
+ try {
132
+ if (typeof this.options.beforeClose === 'function') {
133
+ if (this.options.beforeClose.call(this.$refs.content) === false) {
134
+ return;
135
+ }
136
+ }
137
+ done();
138
+ } catch (e) {
139
+ console.error(e);
140
+ }
141
+ },
142
+ onClosed() {
143
+ if (typeof this.options.onClosed === 'function') {
144
+ this.options.onClosed.call(this.$refs.content);
145
+ } else {
146
+ this.$emit('closed');
147
+ }
148
+ }
149
+ }
150
+ }
151
+ </script>
152
+
153
+ <style>
154
+ .tnxtdm-dialog {
155
+
156
+ &.t-dialog__wrapper.t-popup--center {
157
+ width: calc(100% - 48px);
158
+ max-width: calc(var(--max-page-width) - 48px);
159
+ }
160
+
161
+ .t-dialog__content {
162
+ padding-top: 1rem;
163
+ }
164
+
165
+ .t-dialog__close-btn {
166
+ right: 12px;
167
+ }
168
+
169
+ .t-dialog__footer {
170
+ padding: 12px 24px;
171
+
172
+ .tnxtdm-dialog-footer {
173
+ padding: 12px 0;
174
+ width: 100%;
175
+ }
176
+ }
177
+
178
+ }
179
+ </style>
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <div></div>
3
+ </template>
4
+
5
+ <script>
6
+ export default {
7
+ components: {},
8
+ data() {
9
+ return {};
10
+ },
11
+ methods: {}
12
+ }
13
+ </script>