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

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.
@@ -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>
@@ -19,7 +19,7 @@ export default {
19
19
  </script>
20
20
 
21
21
  <script setup>
22
- import { ref, onMounted, toRefs, computed } from 'vue';
22
+ import { ref, onMounted, toRefs, computed, watch } from 'vue';
23
23
  import { Select as TSelect } from 'tdesign-vue-next';
24
24
  import dataService from '../apiService/simpleDataService';
25
25
 
@@ -112,10 +112,17 @@ const props = defineProps({
112
112
  popupProps: {
113
113
  type: Object,
114
114
  default: () => ({})
115
+ },
116
+ /**
117
+ * 字典配置
118
+ */
119
+ distConfig: {
120
+ type: Array,
121
+ default: () => []
115
122
  }
116
123
  });
117
124
 
118
- const { modelValue, apiConfig, labelField, valueField, queryParams } = toRefs(props)
125
+ const { modelValue, apiConfig, labelField, valueField, queryParams, distConfig } = toRefs(props)
119
126
 
120
127
  const emit = defineEmits(['update:modelValue', 'change', 'selectOption', 'focus', 'blur']);
121
128
 
@@ -163,11 +170,26 @@ const handleRemoteSearch = async (keyword) => {
163
170
  apiType: 'MULTIPLE_DATA_SEARCH'
164
171
  });
165
172
 
166
- options.value = res.data.map(item => ({
167
- ...item,
168
- label: labelField.value ? item[labelField.value] : (item.label || item.name),
169
- value: valueField.value ? item[valueField.value] : (item.value || item.id)
170
- }));
173
+ if (distConfig.value.length > 0 && props.queryParams?.code) {
174
+ const currentDistConfig = distConfig.value.find(item => item.dist_code === props.queryParams.code)?.content;
175
+ if (currentDistConfig) {
176
+ const { value, cn_value, en_value } = currentDistConfig;
177
+ options.value = res.data.map(item => {
178
+ const label = [(value ? item.value : ''), (cn_value ? item.cn_value : ''), (en_value ? item.en_value : '')].filter(Boolean).join('-');
179
+ return {
180
+ ...item,
181
+ label,
182
+ value: valueField.value ? item[valueField.value] : (item.value || item.id)
183
+ }
184
+ });
185
+ }
186
+ } else {
187
+ options.value = res.data.map(item => ({
188
+ ...item,
189
+ label: labelField.value ? item[labelField.value] : (item.label || item.name),
190
+ value: valueField.value ? item[valueField.value] : (item.value || item.id)
191
+ }));
192
+ }
171
193
  } catch (error) {
172
194
  console.error('远程搜索失败:', error);
173
195
  options.value = [];
@@ -202,6 +224,10 @@ const handleChange = (value, context) => {
202
224
  }
203
225
  };
204
226
 
227
+ watch(distConfig, () => {
228
+ handleRemoteSearch('');
229
+ }, { deep: true });
230
+
205
231
  // 组件挂载时,如果有默认值则加载对应的选项
206
232
  onMounted(async () => {
207
233
  if (apiConfig.value.apiId && apiConfig.value.apiType >= 0) {
@@ -216,11 +242,26 @@ onMounted(async () => {
216
242
  apiType: 'MULTIPLE_DATA_SEARCH'
217
243
  });
218
244
 
219
- options.value = res.data.map(item => ({
220
- ...item,
221
- label: labelField.value ? item[labelField.value] : (item.label || item.name),
222
- value: valueField.value ? item[valueField.value] : (item.value || item.id)
223
- }));
245
+ if (distConfig.value.length > 0 && props.queryParams?.code) {
246
+ const currentDistConfig = distConfig.value.find(item => item.dist_code === props.queryParams.code)?.content;
247
+ if (currentDistConfig) {
248
+ const { value, cn_value, en_value } = currentDistConfig;
249
+ options.value = res.data.map(item => {
250
+ const label = [(value ? item.value : ''), (cn_value ? item.cn_value : ''), (en_value ? item.en_value : '')].filter(Boolean).join('-');
251
+ return {
252
+ ...item,
253
+ label,
254
+ value: valueField.value ? item[valueField.value] : (item.value || item.id)
255
+ }
256
+ });
257
+ }
258
+ } else {
259
+ options.value = res.data.map(item => ({
260
+ ...item,
261
+ label: labelField.value ? item[labelField.value] : (item.label || item.name),
262
+ value: valueField.value ? item[valueField.value] : (item.value || item.id)
263
+ }));
264
+ }
224
265
  } catch (error) {
225
266
  console.error('加载默认选项失败:', error);
226
267
  } finally {
@@ -3,6 +3,8 @@
3
3
  <tiny-fluent-editor
4
4
  v-model="editorContent"
5
5
  :disabled="disabled"
6
+ :data-type="false"
7
+ :data-upgrade="false",
6
8
  :placeholder="placeholder"
7
9
  :height="height"
8
10
  :menu-bar="toolbar !== false"
@@ -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>
@@ -0,0 +1,108 @@
1
+ <template>
2
+ <t-loading :delay="delay" :duration="duration" :indicator="indicator" :inherit-color="inheritColor" :layout="layout"
3
+ :loading="loading" :loading-props="loadingProps" :pause="pause" :reverse="reverse" :show-overlay="showOverlay"
4
+ :size="size" :text="text" :theme="theme">
5
+ <!-- 默认插槽 -->
6
+ <slot></slot>
7
+
8
+ <!-- 文本内容插槽 -->
9
+ <template v-if="$slots.text" #text>
10
+ <slot name="text"></slot>
11
+ </template>
12
+
13
+ <!-- 加载指示器插槽 -->
14
+ <template v-if="$slots.indicator" #indicator>
15
+ <slot name="indicator"></slot>
16
+ </template>
17
+
18
+ <!-- 加载内容插槽 -->
19
+ <template v-if="$slots.content" #content>
20
+ <slot name="content"></slot>
21
+ </template>
22
+ </t-loading>
23
+ </template>
24
+
25
+ <script>
26
+ export default {
27
+ name: "EbizTdesignLoading"
28
+ }
29
+ </script>
30
+
31
+ <script setup>
32
+ import { defineProps } from 'vue';
33
+ import { Loading as TLoading } from 'tdesign-vue-next';
34
+
35
+ const props = defineProps({
36
+ // 延迟显示加载效果的时间,用于防止请求速度过快引起的加载闪烁,单位:毫秒
37
+ delay: {
38
+ type: Number,
39
+ default: 0
40
+ },
41
+ // 加载动画执行完成一次的时间,单位:毫秒
42
+ duration: {
43
+ type: Number,
44
+ default: 800
45
+ },
46
+ // 加载指示符,值为 true 显示默认指示符,值为 false 则不显示,也可以自定义指示符
47
+ indicator: {
48
+ type: [Boolean, Function],
49
+ default: true
50
+ },
51
+ // 是否继承父元素颜色
52
+ inheritColor: {
53
+ type: Boolean,
54
+ default: false
55
+ },
56
+ // 对齐方式
57
+ layout: {
58
+ type: String,
59
+ default: 'horizontal',
60
+ validator: (val) => ['horizontal', 'vertical'].includes(val)
61
+ },
62
+ // 是否处于加载状态
63
+ loading: {
64
+ type: Boolean,
65
+ default: true
66
+ },
67
+ // 透传加载组件全部属性
68
+ loadingProps: {
69
+ type: Object,
70
+ default: () => ({})
71
+ },
72
+ // 是否暂停动画
73
+ pause: {
74
+ type: Boolean,
75
+ default: false
76
+ },
77
+ // 加载动画是否反向
78
+ reverse: {
79
+ type: Boolean,
80
+ default: false
81
+ },
82
+ // 是否需要遮罩层
83
+ showOverlay: {
84
+ type: Boolean,
85
+ default: true
86
+ },
87
+ // 尺寸,示例:small/medium/large/12px/56px
88
+ size: {
89
+ type: String,
90
+ default: 'medium'
91
+ },
92
+ // 加载提示文案
93
+ text: {
94
+ type: String,
95
+ default: ''
96
+ },
97
+ // 加载组件类型
98
+ theme: {
99
+ type: String,
100
+ default: 'circular',
101
+ validator: (val) => ['circular', 'spinner', 'dots', 'bar'].includes(val)
102
+ }
103
+ });
104
+ </script>
105
+
106
+ <style lang="less" scoped>
107
+ /* 自定义样式 */
108
+ </style>