@ebiz/designer-components 0.0.18-kzy.6 → 0.0.18-kzy.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ebiz/designer-components",
3
- "version": "0.0.18-kzy.6",
3
+ "version": "0.0.18-kzy.7",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -22,7 +22,7 @@
22
22
  "@opentiny/vue-icon": "~3.20.0",
23
23
  "axios": "^1.8.1",
24
24
  "echarts": "^5.6.0",
25
- "tdesign-vue-next": "^1.11.5",
25
+ "tdesign-vue-next": "^1.12.0",
26
26
  "unplugin-auto-import": "^19.0.0",
27
27
  "unplugin-vue-components": "^28.0.0",
28
28
  "vue": "^3.5.13",
@@ -66,6 +66,10 @@ const props = defineProps({
66
66
  onFinish: {//调用接口后置事件
67
67
  type: Function,
68
68
  default: () => { }
69
+ },
70
+ onError: {
71
+ type: Function,
72
+ default: () => { }
69
73
  }
70
74
  })
71
75
 
@@ -82,13 +86,21 @@ const apiMap = [
82
86
  'MULTIPLE_DATA_LINK_SEARCH'
83
87
  ];
84
88
 
85
- const emit = defineEmits(['click'])
89
+ const emit = defineEmits(['click', 'success', 'error', 'prepare'])
86
90
 
87
- const { text, isNormal, disabled, type, size, apiConfig, data, isUseMethod } = toRefs(props)
91
+ const { text, isNormal, disabled, type, size, variant, apiConfig, data } = toRefs(props)
88
92
 
89
93
  const tooltipText = ref('请先设置接口配置')
90
94
 
91
- const click = () => {
95
+ // 检查API配置是否有效
96
+ const isValidApiConfig = () => {
97
+ return apiConfig.value && apiConfig.value.apiId &&
98
+ typeof apiConfig.value.apiType === 'number' &&
99
+ apiConfig.value.apiType >= 0 &&
100
+ apiConfig.value.apiType < apiMap.length;
101
+ }
102
+
103
+ const click = async () => {
92
104
  props.onClick()
93
105
  // 如果是普通按钮或API配置无效,不调用接口
94
106
  if (isNormal.value || !isValidApiConfig()) {
@@ -97,7 +109,10 @@ const click = () => {
97
109
 
98
110
  try {
99
111
  // 调用前置处理并获取返回值
100
- const shouldContinue = props.onPrepare()
112
+ const shouldContinue = await Promise.resolve(props.onPrepare())
113
+ emit('prepare', shouldContinue)
114
+
115
+ // 只有当返回值明确为false时才中断,undefined或其他值都继续执行
101
116
  if (shouldContinue === false) {
102
117
  return null
103
118
  }
@@ -0,0 +1,341 @@
1
+ <template>
2
+ <div class="ebiz-descriptions">
3
+ <div v-if="title || $slots.title" class="ebiz-descriptions__header">
4
+ <slot name="title">{{ title }}</slot>
5
+ </div>
6
+ <table
7
+ class="ebiz-descriptions__body"
8
+ :class="[
9
+ `ebiz-descriptions--${size}`,
10
+ { 'ebiz-descriptions__body--fixed': tableLayout === 'fixed' },
11
+ { 'ebiz-descriptions__body--border': border }
12
+ ]"
13
+ :style="border && tableBorderColor ? {'--td-descriptions-border-color': tableBorderColor} : {}"
14
+ >
15
+ <tbody>
16
+ <template v-if="rows.length > 0">
17
+ <template v-if="layout === 'horizontal'">
18
+ <tr v-for="(row, rowIndex) in rows" :key="`row-${rowIndex}`">
19
+ <template v-for="(item, colIndex) in row" :key="`${rowIndex}-${colIndex}`">
20
+ <template v-if="itemLayout === 'horizontal'">
21
+ <th
22
+ class="ebiz-descriptions__label"
23
+ :class="[item.labelClassName]"
24
+ >
25
+ <slot :name="`${item.slotName}-label`">
26
+ {{ item.label }}
27
+ </slot>
28
+ <span v-if="colon" class="ebiz-descriptions__colon">:</span>
29
+ </th>
30
+ <td
31
+ :colspan="item.span * 2 - 1"
32
+ class="ebiz-descriptions__content"
33
+ :class="[item.contentClassName]"
34
+ >
35
+ <slot :name="item.slotName">
36
+ {{ item.content }}
37
+ </slot>
38
+ </td>
39
+ </template>
40
+ </template>
41
+ </tr>
42
+ </template>
43
+ <template v-else>
44
+ <template v-for="(row, rowIndex) in rows" :key="`${rowIndex}`">
45
+ <template v-if="itemLayout === 'horizontal'">
46
+ <tr>
47
+ <template v-for="(item, colIndex) in row" :key="`label-${rowIndex}-${colIndex}`">
48
+ <th
49
+ class="ebiz-descriptions__label"
50
+ :class="[item.labelClassName]"
51
+ >
52
+ <slot :name="`${item.slotName}-label`">
53
+ {{ item.label }}
54
+ </slot>
55
+ <span v-if="colon" class="ebiz-descriptions__colon">:</span>
56
+ </th>
57
+ <td
58
+ :colspan="item.span"
59
+ class="ebiz-descriptions__content"
60
+ :class="[item.contentClassName]"
61
+ >
62
+ <slot :name="item.slotName">
63
+ {{ item.content }}
64
+ </slot>
65
+ </td>
66
+ </template>
67
+ </tr>
68
+ </template>
69
+ <template v-else>
70
+ <tr>
71
+ <template v-for="(item, colIndex) in row" :key="`label-${rowIndex}-${colIndex}`">
72
+ <th
73
+ :colspan="item.span"
74
+ class="ebiz-descriptions__label"
75
+ :class="[item.labelClassName]"
76
+ >
77
+ <slot :name="`${item.slotName}-label`">
78
+ {{ item.label }}
79
+ </slot>
80
+ <span v-if="colon" class="ebiz-descriptions__colon">:</span>
81
+ </th>
82
+ </template>
83
+ </tr>
84
+ <tr>
85
+ <template v-for="(item, colIndex) in row" :key="`content-${rowIndex}-${colIndex}`">
86
+ <td
87
+ :colspan="item.span"
88
+ class="ebiz-descriptions__content"
89
+ :class="[item.contentClassName]"
90
+ >
91
+ <slot :name="item.slotName">
92
+ {{ item.content }}
93
+ </slot>
94
+ </td>
95
+ </template>
96
+ </tr>
97
+ </template>
98
+ </template>
99
+ </template>
100
+ </template>
101
+ <template v-else>
102
+ <slot></slot>
103
+ </template>
104
+ </tbody>
105
+ </table>
106
+ </div>
107
+ </template>
108
+
109
+ <script setup>
110
+ import { defineProps, defineEmits, computed, useSlots, ref } from 'vue';
111
+ import { isArray, isNil } from 'lodash-es';
112
+
113
+ const props = defineProps({
114
+ border: {
115
+ type: Boolean,
116
+ default: false
117
+ },
118
+ colon: {
119
+ type: Boolean,
120
+ default: false
121
+ },
122
+ column: {
123
+ type: Number,
124
+ default: 2
125
+ },
126
+ layout: {
127
+ type: String,
128
+ default: 'horizontal',
129
+ validator(val) {
130
+ return ['horizontal', 'vertical'].includes(val);
131
+ }
132
+ },
133
+ itemLayout: {
134
+ type: String,
135
+ default: 'horizontal',
136
+ validator(val) {
137
+ return ['horizontal', 'vertical'].includes(val);
138
+ }
139
+ },
140
+ size: {
141
+ type: String,
142
+ default: 'medium',
143
+ validator(val) {
144
+ return ['small', 'medium', 'large'].includes(val);
145
+ }
146
+ },
147
+ title: {
148
+ type: String,
149
+ default: ''
150
+ },
151
+ tableLayout: {
152
+ type: String,
153
+ default: 'fixed',
154
+ validator(val) {
155
+ return ['auto', 'fixed'].includes(val);
156
+ }
157
+ },
158
+ tableBorderColor: {
159
+ type: String,
160
+ default: ''
161
+ },
162
+ items: {
163
+ type: Array,
164
+ default: () => []
165
+ }
166
+ });
167
+
168
+ defineEmits([]);
169
+
170
+ const slots = useSlots();
171
+ const itemsType = ref('slots');
172
+
173
+ // 计算行数据
174
+ const rows = computed(() => {
175
+ // 1. 获取要渲染的 items
176
+ let items = [];
177
+
178
+ if (isArray(props.items) && props.items.length > 0) {
179
+ // 从 props.items 获取数据
180
+ items = props.items.map(item => ({
181
+ label: item.label,
182
+ content: item.content,
183
+ span: item.span || 1,
184
+ labelClassName: item.labelClassName || '',
185
+ contentClassName: item.contentClassName || '',
186
+ slotName: item.name || `item-${items.length}`
187
+ }));
188
+ itemsType.value = 'props';
189
+ } else {
190
+ // 从 slots 获取数据
191
+ const defaultSlot = slots.default?.();
192
+ if (defaultSlot) {
193
+ items = defaultSlot
194
+ .filter(vnode => vnode.type &&
195
+ (vnode.type.name === 'EbizDescriptionsItem' ||
196
+ vnode.type.__name === 'EbizDescriptionsItem'))
197
+ .map((vnode, index) => {
198
+ const props = vnode.props || {};
199
+ const span = isNil(props.span) ? 1 : Number(props.span);
200
+ return {
201
+ label: props.label || '',
202
+ content: '',
203
+ span: span > props.column ? props.column : span,
204
+ labelClassName: props.labelClassName || '',
205
+ contentClassName: props.contentClassName || '',
206
+ slotName: props.name || `item-${index}`,
207
+ children: vnode.children
208
+ };
209
+ });
210
+ itemsType.value = 'slots';
211
+ }
212
+ }
213
+
214
+ // 2. 判断布局,如果是垂直布局则直接返回
215
+ if (props.layout === 'vertical') {
216
+ return [items];
217
+ }
218
+
219
+ // 3. 水平布局时,计算每一行的item
220
+ const rows = [];
221
+ let currentRow = [];
222
+ let currentRowSpan = 0;
223
+ const { column } = props;
224
+
225
+ items.forEach((item, index) => {
226
+ const span = item.span || 1;
227
+
228
+ // 如果当前行放不下了,创建新行
229
+ if (currentRowSpan + span > column) {
230
+ rows.push(currentRow);
231
+ currentRow = [];
232
+ currentRowSpan = 0;
233
+ }
234
+
235
+ // 添加到当前行
236
+ currentRow.push({
237
+ ...item,
238
+ span: span
239
+ });
240
+
241
+ currentRowSpan += span;
242
+
243
+ // 处理最后一个元素
244
+ if (index === items.length - 1) {
245
+ // 最后一个元素填充剩余空间
246
+ if (currentRowSpan < column) {
247
+ currentRow[currentRow.length - 1].span += (column - currentRowSpan);
248
+ }
249
+ rows.push(currentRow);
250
+ }
251
+ });
252
+
253
+ return rows;
254
+ });
255
+ </script>
256
+
257
+ <style scoped>
258
+ .ebiz-descriptions {
259
+ font-size: 14px;
260
+ color: rgba(0, 0, 0, 0.9);
261
+ line-height: 22px;
262
+ }
263
+
264
+ .ebiz-descriptions__header {
265
+ margin-bottom: 16px;
266
+ }
267
+
268
+ .ebiz-descriptions__header > * {
269
+ font-size: 16px;
270
+ font-weight: 700;
271
+ color: rgba(0, 0, 0, 0.9);
272
+ line-height: 24px;
273
+ }
274
+
275
+ .ebiz-descriptions__body {
276
+ width: 100%;
277
+ border-collapse: collapse;
278
+ table-layout: fixed;
279
+ }
280
+
281
+ .ebiz-descriptions__body--fixed {
282
+ table-layout: fixed;
283
+ }
284
+
285
+ .ebiz-descriptions__body--border {
286
+ border-collapse: separate;
287
+ border-spacing: 0;
288
+ border-top: 1px solid var(--td-descriptions-border-color, #dcdcdc);
289
+ border-left: 1px solid var(--td-descriptions-border-color, #dcdcdc);
290
+ }
291
+
292
+ .ebiz-descriptions__body--border .ebiz-descriptions__label,
293
+ .ebiz-descriptions__body--border .ebiz-descriptions__content {
294
+ border-right: 1px solid var(--td-descriptions-border-color, #dcdcdc);
295
+ border-bottom: 1px solid var(--td-descriptions-border-color, #dcdcdc);
296
+ }
297
+
298
+ .ebiz-descriptions__label {
299
+ font-weight: normal;
300
+ color: rgba(0, 0, 0, 0.6);
301
+ background-color: #fafafa;
302
+ text-align: left;
303
+ padding: 12px 24px 12px 12px;
304
+ vertical-align: top;
305
+ }
306
+
307
+ .ebiz-descriptions__colon {
308
+ margin: 0 8px 0 2px;
309
+ }
310
+
311
+ .ebiz-descriptions__content {
312
+ padding: 12px;
313
+ text-align: left;
314
+ vertical-align: top;
315
+ }
316
+
317
+ /* 尺寸相关样式 */
318
+ .ebiz-descriptions--small .ebiz-descriptions__label,
319
+ .ebiz-descriptions--small .ebiz-descriptions__content {
320
+ padding: 8px;
321
+ }
322
+
323
+ .ebiz-descriptions--medium .ebiz-descriptions__label,
324
+ .ebiz-descriptions--medium .ebiz-descriptions__content {
325
+ padding: 12px;
326
+ }
327
+
328
+ .ebiz-descriptions--large .ebiz-descriptions__label,
329
+ .ebiz-descriptions--large .ebiz-descriptions__content {
330
+ padding: 16px;
331
+ }
332
+
333
+ /* 不同布局的padding调整 */
334
+ .ebiz-descriptions__body:not(.ebiz-descriptions__body--border) .ebiz-descriptions__label {
335
+ padding-left: 0;
336
+ }
337
+
338
+ .ebiz-descriptions__body:not(.ebiz-descriptions__body--border) .ebiz-descriptions__content {
339
+ padding-right: 0;
340
+ }
341
+ </style>
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <div>
3
+ <slot></slot>
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+ import { defineProps } from 'vue';
9
+
10
+ defineProps({
11
+ label: {
12
+ type: String,
13
+ default: ''
14
+ },
15
+ span: {
16
+ type: Number,
17
+ default: 1
18
+ },
19
+ className: {
20
+ type: String,
21
+ default: ''
22
+ },
23
+ labelClassName: {
24
+ type: String,
25
+ default: ''
26
+ },
27
+ contentClassName: {
28
+ type: String,
29
+ default: ''
30
+ },
31
+ layout: {
32
+ type: String,
33
+ default: '',
34
+ validator(val) {
35
+ if (!val) return true;
36
+ return ['horizontal', 'vertical'].includes(val);
37
+ }
38
+ }
39
+ });
40
+ </script>
41
+
42
+ <style scoped>
43
+ .ebiz-descriptions-item {
44
+ box-sizing: border-box;
45
+ padding: 0;
46
+ margin: 0;
47
+ }
48
+ </style>
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <t-popconfirm
3
+ :content="content"
4
+ @cancel="handleCancel"
5
+ @confirm="handleConfirm"
6
+ >
7
+ <slot></slot>
8
+ </t-popconfirm>
9
+ </template>
10
+
11
+ <script>
12
+ export default {
13
+ name: "EbizPopconfirm"
14
+ }
15
+ </script>
16
+
17
+ <script setup>
18
+ import { Popconfirm as TPopconfirm } from 'tdesign-vue-next';
19
+
20
+ // 定义属性
21
+ const props = defineProps({
22
+ // 确认框内容
23
+ content: {
24
+ type: [String, Function],
25
+ default: ''
26
+ }
27
+ });
28
+
29
+ // 定义事件
30
+ const emit = defineEmits([
31
+ 'cancel',
32
+ 'confirm'
33
+ ]);
34
+
35
+ // 取消按钮点击事件
36
+ const handleCancel = ({ e }) => {
37
+ emit('cancel', { e });
38
+ };
39
+
40
+ // 确认按钮点击事件
41
+ const handleConfirm = ({ e }) => {
42
+ emit('confirm', { e });
43
+ };
44
+ </script>
45
+
46
+ <style lang="less" scoped>
47
+ /* 自定义样式可在此处添加 */
48
+ </style>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div>
3
- <t-table :data="data" :columns="mergedColumns" :row-key="rowKey" :vertical-align="verticalAlign"
3
+ <t-table ref="tableRef" :data="data" :columns="mergedColumns" :row-key="rowKey" :vertical-align="verticalAlign"
4
4
  :horizontal-align="horizontalAlign" :size="size" :bordered="bordered" :stripe="stripe" :hover="hover"
5
5
  :height="height" :max-height="maxHeight" :loading="loading" :loading-props="loadingProps" :load-more="loadMore"
6
6
  :empty="empty" :table-layout="tableLayout" :cell-empty-content="cellEmptyContent" :pagination="pagination"
@@ -459,6 +459,10 @@ const handleDragSort = (params) => {
459
459
  const handleValidate = (context) => {
460
460
  emit('validate', context);
461
461
  };
462
+ const tableRef = ref();
463
+ defineExpose({
464
+ tableRef
465
+ })
462
466
  </script>
463
467
 
464
468
  <style lang="less" scoped>