@ebiz/designer-components 0.0.18-beta.9 → 0.0.18-kzy.2
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/dist/designer-components.css +7 -0
- package/dist/favicon.ico +0 -0
- package/dist/index.mjs +133763 -0
- package/package.json +1 -1
- package/src/apiService/simpleDataService.js +2 -2
- package/src/components/Button.vue +2 -2
- package/src/components/EbizRemoteSelect.vue +18 -17
- package/src/components/EbizRichTextEditor.vue +174 -0
- package/src/components/EbizStatusBadge.vue +182 -0
- package/src/components/EbizTabHeader.vue +2 -2
- package/src/components/EbizTable.vue +486 -0
- package/src/components/TdesignDialog.vue +5 -0
- package/src/components/TdesignUpload.vue +2 -2
- package/src/index.js +65 -59
- package/src/main.js +1 -3
- package/src/router/index.js +12 -0
- package/src/views/Home.vue +3 -1
- package/src/views/StatusBadgeExample.vue +146 -0
- package/src/views/TableDemo.vue +335 -0
- package/src/apiService/simpleDataServiceAppData.js +0 -278
package/package.json
CHANGED
@@ -8,7 +8,7 @@ import axios from 'axios'
|
|
8
8
|
import { TinyNotify } from '@opentiny/vue'
|
9
9
|
|
10
10
|
// 从环境变量获取API基础URL
|
11
|
-
const API_BASE_URL =
|
11
|
+
const API_BASE_URL = "http://localhost:8090/api";
|
12
12
|
|
13
13
|
/**
|
14
14
|
* 创建axios实例
|
@@ -30,7 +30,7 @@ axiosInstance.interceptors.request.use(
|
|
30
30
|
// 添加认证信息
|
31
31
|
const token = localStorage.getItem('token')
|
32
32
|
if (token) {
|
33
|
-
config.headers['
|
33
|
+
config.headers['AppDataAuthorization'] = `Bearer ${token}`
|
34
34
|
}
|
35
35
|
|
36
36
|
// 如果是FormData格式,不设置Content-Type,让浏览器自动设置
|
@@ -19,7 +19,7 @@ export default {
|
|
19
19
|
|
20
20
|
import { ref, reactive, computed, toRef, toRefs } from 'vue';
|
21
21
|
import { TinyButton, TinyTooltip, TinyNotify } from '@opentiny/vue';
|
22
|
-
import
|
22
|
+
import dataService from '../apiService/simpleDataService';
|
23
23
|
|
24
24
|
|
25
25
|
const props = defineProps({
|
@@ -92,7 +92,7 @@ const click = () => {
|
|
92
92
|
props.onClick()
|
93
93
|
if (!isNormal.value && apiConfig.value.apiId) {
|
94
94
|
props.onPrepare()
|
95
|
-
|
95
|
+
dataService.fetch(data.value, { key: apiConfig.value.key, apiId: apiConfig.value.apiId, apiType: apiMap[apiConfig.value.apiType] }).then((res) => {
|
96
96
|
emit('click', res)
|
97
97
|
props.onFinish()
|
98
98
|
})
|
@@ -21,7 +21,7 @@ export default {
|
|
21
21
|
<script setup>
|
22
22
|
import { ref, onMounted, toRefs, computed } from 'vue';
|
23
23
|
import { Select as TSelect } from 'tdesign-vue-next';
|
24
|
-
import
|
24
|
+
import dataService from '../apiService/simpleDataService';
|
25
25
|
|
26
26
|
const props = defineProps({
|
27
27
|
/**
|
@@ -81,12 +81,13 @@ const props = defineProps({
|
|
81
81
|
/**
|
82
82
|
* 选项配置
|
83
83
|
*/
|
84
|
-
|
85
|
-
type:
|
86
|
-
default:
|
87
|
-
|
88
|
-
|
89
|
-
|
84
|
+
labelField: {
|
85
|
+
type: String,
|
86
|
+
default: ''
|
87
|
+
},
|
88
|
+
valueField: {
|
89
|
+
type: String,
|
90
|
+
default: ''
|
90
91
|
},
|
91
92
|
/**
|
92
93
|
* 组件尺寸
|
@@ -112,9 +113,9 @@ const props = defineProps({
|
|
112
113
|
}
|
113
114
|
});
|
114
115
|
|
115
|
-
const { modelValue, apiConfig, queryParams } = toRefs(props)
|
116
|
+
const { modelValue, apiConfig, labelField, valueField, queryParams } = toRefs(props)
|
116
117
|
|
117
|
-
const emit = defineEmits(['update:modelValue', 'change', 'focus', 'blur']);
|
118
|
+
const emit = defineEmits(['update:modelValue', 'change', 'selectOption', 'focus', 'blur']);
|
118
119
|
|
119
120
|
// 选中的值
|
120
121
|
const selectedValue = computed({
|
@@ -154,12 +155,11 @@ const handleRemoteSearch = async (keyword) => {
|
|
154
155
|
keyword
|
155
156
|
}
|
156
157
|
};
|
157
|
-
const res = await
|
158
|
-
const { labelField, valueField } = props.optionsConfig;
|
158
|
+
const res = await dataService.fetch(params, props.apiConfig);
|
159
159
|
|
160
160
|
options.value = res.data.map(item => ({
|
161
|
-
label: labelField ? item[labelField] :
|
162
|
-
value: valueField ? item[valueField] :
|
161
|
+
label: labelField.value ? item[labelField.value] : item.name,
|
162
|
+
value: valueField.value ? item[valueField.value] : item.id
|
163
163
|
}));
|
164
164
|
} catch (error) {
|
165
165
|
console.error('远程搜索失败:', error);
|
@@ -188,6 +188,7 @@ const handleBlur = (value, context) => {
|
|
188
188
|
const handleChange = (value, context) => {
|
189
189
|
emit('update:modelValue', value);
|
190
190
|
emit('change', value, context);
|
191
|
+
emit('selectOption', options.value.find(item => item.value === value));
|
191
192
|
};
|
192
193
|
|
193
194
|
// 组件挂载时,如果有默认值则加载对应的选项
|
@@ -198,16 +199,16 @@ onMounted(async () => {
|
|
198
199
|
const params = {
|
199
200
|
queryParams: queryParams.value
|
200
201
|
};
|
201
|
-
const res = await
|
202
|
+
const res = await dataService.fetch(params, {
|
202
203
|
key: props.apiConfig.key,
|
203
204
|
apiId: props.apiConfig.apiId,
|
204
205
|
apiType: 'MULTIPLE_DATA_SEARCH'
|
205
206
|
});
|
206
|
-
const { labelField, valueField } = props.optionsConfig;
|
207
207
|
|
208
|
+
console.log('res', res)
|
208
209
|
options.value = res.data.map(item => ({
|
209
|
-
label: labelField ? item[labelField] :
|
210
|
-
value: valueField ? item[valueField] :
|
210
|
+
label: labelField.value ? item[labelField.value] : item.name,
|
211
|
+
value: valueField.value ? item[valueField.value] : item.id
|
211
212
|
}));
|
212
213
|
} catch (error) {
|
213
214
|
console.error('加载默认选项失败:', error);
|
@@ -0,0 +1,174 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="ebiz-rich-text-editor">
|
3
|
+
<tiny-fluent-editor
|
4
|
+
v-model="editorContent"
|
5
|
+
:disabled="disabled"
|
6
|
+
:placeholder="placeholder"
|
7
|
+
:height="height"
|
8
|
+
:menu-bar="toolbar !== false"
|
9
|
+
:toolbar="toolbar !== false ? toolbar : undefined"
|
10
|
+
@ready="handleReady"
|
11
|
+
@focus="handleFocus"
|
12
|
+
@blur="handleBlur"
|
13
|
+
@change="handleChange">
|
14
|
+
</tiny-fluent-editor>
|
15
|
+
</div>
|
16
|
+
</template>
|
17
|
+
|
18
|
+
<script>
|
19
|
+
export default {
|
20
|
+
name: "EbizRichTextEditor"
|
21
|
+
}
|
22
|
+
</script>
|
23
|
+
|
24
|
+
<script setup>
|
25
|
+
import { ref, watch, computed } from 'vue';
|
26
|
+
import { TinyFluentEditor } from '@opentiny/vue';
|
27
|
+
import dataService from "../apiService/simpleDataService";
|
28
|
+
|
29
|
+
const props = defineProps({
|
30
|
+
/**
|
31
|
+
* 编辑器内容
|
32
|
+
*/
|
33
|
+
modelValue: {
|
34
|
+
type: String,
|
35
|
+
default: ''
|
36
|
+
},
|
37
|
+
/**
|
38
|
+
* 是否禁用
|
39
|
+
*/
|
40
|
+
disabled: {
|
41
|
+
type: Boolean,
|
42
|
+
default: false
|
43
|
+
},
|
44
|
+
/**
|
45
|
+
* 占位符文本
|
46
|
+
*/
|
47
|
+
placeholder: {
|
48
|
+
type: String,
|
49
|
+
default: '请输入内容...'
|
50
|
+
},
|
51
|
+
/**
|
52
|
+
* 编辑器高度
|
53
|
+
*/
|
54
|
+
height: {
|
55
|
+
type: [String, Number],
|
56
|
+
default: '600px'
|
57
|
+
},
|
58
|
+
/**
|
59
|
+
* 图片上传API配置
|
60
|
+
*/
|
61
|
+
imageUploadConfig: {
|
62
|
+
type: Object,
|
63
|
+
default: () => ({
|
64
|
+
url: '/api/file/upload'
|
65
|
+
})
|
66
|
+
},
|
67
|
+
/**
|
68
|
+
* 工具栏配置,传入false则不显示工具栏
|
69
|
+
*/
|
70
|
+
toolbar: {
|
71
|
+
type: [Array, Boolean],
|
72
|
+
default: () => [
|
73
|
+
['fontFamily', 'fontSize', 'bold', 'italic', 'underline', 'strikeThrough'],
|
74
|
+
['color', 'bgColor'],
|
75
|
+
['alignment'],
|
76
|
+
['bulletedList', 'numberedList', 'indent', 'outdent'],
|
77
|
+
['link', 'image', 'table'],
|
78
|
+
['clean']
|
79
|
+
]
|
80
|
+
}
|
81
|
+
});
|
82
|
+
|
83
|
+
const emit = defineEmits(['update:modelValue', 'change', 'ready', 'focus', 'blur']);
|
84
|
+
|
85
|
+
// 实际的编辑器内容,作为一个计算属性,允许双向绑定
|
86
|
+
const editorContent = computed({
|
87
|
+
get: () => props.modelValue,
|
88
|
+
set: (val) => {
|
89
|
+
emit('update:modelValue', val);
|
90
|
+
}
|
91
|
+
});
|
92
|
+
|
93
|
+
// 编辑器实例
|
94
|
+
const editorInstance = ref(null);
|
95
|
+
|
96
|
+
// 处理编辑器就绪事件
|
97
|
+
const handleReady = (editor) => {
|
98
|
+
editorInstance.value = editor;
|
99
|
+
|
100
|
+
// 配置图片上传
|
101
|
+
if (props.imageUploadConfig.url) {
|
102
|
+
configureImageUpload(editor);
|
103
|
+
}
|
104
|
+
|
105
|
+
emit('ready', editor);
|
106
|
+
};
|
107
|
+
|
108
|
+
// 配置图片上传功能
|
109
|
+
const configureImageUpload = (editor) => {
|
110
|
+
// 获取编辑器实例的上传配置
|
111
|
+
if (editor && editor.setImageAction) {
|
112
|
+
editor.setImageAction({
|
113
|
+
customUploader: async (file) => {
|
114
|
+
try {
|
115
|
+
const formData = new FormData();
|
116
|
+
formData.append('file', file);
|
117
|
+
|
118
|
+
// 使用 dataService 上传图片
|
119
|
+
const response = await dataService.upload(formData, props.imageUploadConfig);
|
120
|
+
|
121
|
+
if (response && response.data && response.data.url) {
|
122
|
+
// 返回图片URL,编辑器会自动插入
|
123
|
+
return response.data.url;
|
124
|
+
} else {
|
125
|
+
throw new Error('上传失败');
|
126
|
+
}
|
127
|
+
} catch (error) {
|
128
|
+
console.error('图片上传失败:', error);
|
129
|
+
return null;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
});
|
133
|
+
}
|
134
|
+
};
|
135
|
+
|
136
|
+
// 处理内容变化事件
|
137
|
+
const handleChange = (content) => {
|
138
|
+
emit('change', content);
|
139
|
+
};
|
140
|
+
|
141
|
+
// 处理焦点事件
|
142
|
+
const handleFocus = (event) => {
|
143
|
+
emit('focus', event);
|
144
|
+
};
|
145
|
+
|
146
|
+
// 处理失焦事件
|
147
|
+
const handleBlur = (event) => {
|
148
|
+
emit('blur', event);
|
149
|
+
};
|
150
|
+
|
151
|
+
// 监听禁用状态变化
|
152
|
+
watch(() => props.imageUploadConfig, (newConfig) => {
|
153
|
+
if (editorInstance.value && (newConfig.apiId || newConfig.url)) {
|
154
|
+
configureImageUpload(editorInstance.value);
|
155
|
+
}
|
156
|
+
}, { deep: true });
|
157
|
+
</script>
|
158
|
+
|
159
|
+
<style scoped>
|
160
|
+
.ebiz-rich-text-editor {
|
161
|
+
width: 100%;
|
162
|
+
}
|
163
|
+
|
164
|
+
/* 使用@opentiny/vue的样式变量保持一致性 */
|
165
|
+
:deep(.tiny-editor-container) {
|
166
|
+
border: 1px solid var(--ti-common-color-line-normal, #dcdfe6);
|
167
|
+
border-radius: 4px;
|
168
|
+
}
|
169
|
+
|
170
|
+
:deep(.tiny-editor-toolbar) {
|
171
|
+
border-bottom: 1px solid var(--ti-common-color-line-normal, #dcdfe6);
|
172
|
+
background-color: var(--ti-common-color-bg-normal, #f5f7fa);
|
173
|
+
}
|
174
|
+
</style>
|
@@ -0,0 +1,182 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="ebiz-status-badge" :style="containerStyle">
|
3
|
+
<div class="status-indicator" :style="indicatorStyle"></div>
|
4
|
+
<div class="status-text" v-if="showText">{{ text }}</div>
|
5
|
+
</div>
|
6
|
+
</template>
|
7
|
+
|
8
|
+
<script>
|
9
|
+
export default {
|
10
|
+
name: "EbizStatusBadge"
|
11
|
+
}
|
12
|
+
</script>
|
13
|
+
|
14
|
+
<script setup>
|
15
|
+
import { computed } from 'vue';
|
16
|
+
|
17
|
+
const props = defineProps({
|
18
|
+
/**
|
19
|
+
* 状态类型
|
20
|
+
*/
|
21
|
+
status: {
|
22
|
+
type: String,
|
23
|
+
default: 'default',
|
24
|
+
validator: (val) => ['default', 'success', 'warning', 'error', 'processing'].includes(val)
|
25
|
+
},
|
26
|
+
/**
|
27
|
+
* 自定义颜色
|
28
|
+
*/
|
29
|
+
color: {
|
30
|
+
type: String,
|
31
|
+
default: ''
|
32
|
+
},
|
33
|
+
/**
|
34
|
+
* 自定义预设颜色映射
|
35
|
+
*/
|
36
|
+
colorMap: {
|
37
|
+
type: Object,
|
38
|
+
default: () => ({})
|
39
|
+
},
|
40
|
+
/**
|
41
|
+
* 指示点大小
|
42
|
+
*/
|
43
|
+
size: {
|
44
|
+
type: [String, Number],
|
45
|
+
default: 'small',
|
46
|
+
validator: (val) => ['small', 'medium', 'large'].includes(val) || typeof val === 'number'
|
47
|
+
},
|
48
|
+
/**
|
49
|
+
* 是否显示文字
|
50
|
+
*/
|
51
|
+
showText: {
|
52
|
+
type: Boolean,
|
53
|
+
default: true
|
54
|
+
},
|
55
|
+
/**
|
56
|
+
* 状态文字
|
57
|
+
*/
|
58
|
+
text: {
|
59
|
+
type: String,
|
60
|
+
default: ''
|
61
|
+
},
|
62
|
+
/**
|
63
|
+
* 状态点位置
|
64
|
+
*/
|
65
|
+
position: {
|
66
|
+
type: String,
|
67
|
+
default: 'left',
|
68
|
+
validator: (val) => ['left', 'right', 'top', 'bottom'].includes(val)
|
69
|
+
},
|
70
|
+
/**
|
71
|
+
* 闪烁效果
|
72
|
+
*/
|
73
|
+
pulse: {
|
74
|
+
type: Boolean,
|
75
|
+
default: false
|
76
|
+
}
|
77
|
+
});
|
78
|
+
|
79
|
+
// 获取预设状态颜色
|
80
|
+
const getStatusColor = (status) => {
|
81
|
+
const defaultColorMap = {
|
82
|
+
default: '#999999',
|
83
|
+
success: '#35c613',
|
84
|
+
warning: '#ed7b2f',
|
85
|
+
error: '#e34d59',
|
86
|
+
processing: '#0052d9'
|
87
|
+
};
|
88
|
+
|
89
|
+
// 优先使用props.color,其次使用用户提供的colorMap,最后使用默认颜色
|
90
|
+
return props.color || props.colorMap[status] || defaultColorMap[status];
|
91
|
+
};
|
92
|
+
|
93
|
+
// 获取点大小
|
94
|
+
const getSize = () => {
|
95
|
+
if (typeof props.size === 'number') {
|
96
|
+
return `${props.size}px`;
|
97
|
+
}
|
98
|
+
|
99
|
+
const sizeMap = {
|
100
|
+
small: '6px',
|
101
|
+
medium: '10px',
|
102
|
+
large: '14px'
|
103
|
+
};
|
104
|
+
|
105
|
+
return sizeMap[props.size];
|
106
|
+
};
|
107
|
+
|
108
|
+
// 计算指示器样式
|
109
|
+
const indicatorStyle = computed(() => {
|
110
|
+
const style = {
|
111
|
+
backgroundColor: getStatusColor(props.status),
|
112
|
+
width: getSize(),
|
113
|
+
height: getSize(),
|
114
|
+
animationName: props.pulse ? 'ebiz-status-pulse' : 'none'
|
115
|
+
};
|
116
|
+
|
117
|
+
return style;
|
118
|
+
});
|
119
|
+
|
120
|
+
// 计算容器样式
|
121
|
+
const containerStyle = computed(() => {
|
122
|
+
const style = {
|
123
|
+
flexDirection: 'row', // 默认水平排列
|
124
|
+
};
|
125
|
+
|
126
|
+
// 根据位置调整排列方向
|
127
|
+
if (props.position === 'top' || props.position === 'bottom') {
|
128
|
+
style.flexDirection = props.position === 'top' ? 'column-reverse' : 'column';
|
129
|
+
} else {
|
130
|
+
style.flexDirection = props.position === 'left' ? 'row' : 'row-reverse';
|
131
|
+
}
|
132
|
+
|
133
|
+
return style;
|
134
|
+
});
|
135
|
+
</script>
|
136
|
+
|
137
|
+
<style scoped>
|
138
|
+
.ebiz-status-badge {
|
139
|
+
display: inline-flex;
|
140
|
+
align-items: center;
|
141
|
+
font-size: 14px;
|
142
|
+
line-height: 1;
|
143
|
+
}
|
144
|
+
|
145
|
+
.status-indicator {
|
146
|
+
border-radius: 50%;
|
147
|
+
flex-shrink: 0;
|
148
|
+
}
|
149
|
+
|
150
|
+
.status-text {
|
151
|
+
margin-left: 8px;
|
152
|
+
}
|
153
|
+
|
154
|
+
.ebiz-status-badge[style*="column"] .status-text {
|
155
|
+
margin-left: 0;
|
156
|
+
margin-top: 4px;
|
157
|
+
}
|
158
|
+
|
159
|
+
.ebiz-status-badge[style*="row-reverse"] .status-text {
|
160
|
+
margin-left: 0;
|
161
|
+
margin-right: 8px;
|
162
|
+
}
|
163
|
+
|
164
|
+
@keyframes ebiz-status-pulse {
|
165
|
+
0% {
|
166
|
+
opacity: 1;
|
167
|
+
transform: scale(1);
|
168
|
+
}
|
169
|
+
50% {
|
170
|
+
opacity: 0.6;
|
171
|
+
transform: scale(1.2);
|
172
|
+
}
|
173
|
+
100% {
|
174
|
+
opacity: 1;
|
175
|
+
transform: scale(1);
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
.status-indicator[style*="ebiz-status-pulse"] {
|
180
|
+
animation: ebiz-status-pulse 1.5s infinite ease-in-out;
|
181
|
+
}
|
182
|
+
</style>
|
@@ -8,7 +8,7 @@
|
|
8
8
|
<script setup>
|
9
9
|
import { ref, computed, watch } from 'vue'
|
10
10
|
import { TinyTabs, TinyTabItem } from '@opentiny/vue'
|
11
|
-
import {
|
11
|
+
import { dataService } from "../index.js"
|
12
12
|
|
13
13
|
const emit = defineEmits(['tabChange'])
|
14
14
|
|
@@ -83,7 +83,7 @@ watch(() => showTabs.value, () => {
|
|
83
83
|
|
84
84
|
watch(() => props.apiConfig, (nVal) => {
|
85
85
|
if (!nVal?.apiId) return
|
86
|
-
|
86
|
+
dataService.fetch({}, { key: nVal.key, apiId: nVal.apiId, apiType: 'MULTIPLE_DATA_SEARCH' }).then(res => {
|
87
87
|
remoteTabs.value = (res.data ?? []).map(i => ({
|
88
88
|
label: i[props.labelKey],
|
89
89
|
value: i[props.valueKey],
|