@ebiz/designer-components 0.0.18-kzy.7 → 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.
@@ -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"
@@ -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>
@@ -161,7 +161,7 @@
161
161
  <div class="org-selected-container">
162
162
  <div v-if="tempGlobalSelectedOrgs.length === 0" class="no-selected-tip">请从左侧选择组织</div>
163
163
  <div v-else class="selected-orgs-tags">
164
- <t-tag v-for="org in tempGlobalSelectedOrgs" :key="org.id" closable @close="removeGlobalOrg(org.id)"
164
+ <t-tag v-for="org in tempGlobalSelectedOrgs" :key="org.id" closable @close="removeGlobalSelectedOrg(org.id)"
165
165
  theme="primary" variant="light" class="org-tag">
166
166
  {{ org.name }}
167
167
  </t-tag>
@@ -310,7 +310,8 @@ import {
310
310
  Input as TInput,
311
311
  Tree as TTree,
312
312
  Tag as TTag,
313
- Icon as TIcon
313
+ Icon as TIcon,
314
+ Message
314
315
  } from 'tdesign-vue-next'
315
316
 
316
317
  const apis = {
@@ -372,10 +373,12 @@ function getRoleConfig() {
372
373
  if (matchedFunction) {
373
374
  // 设置功能勾选状态为true
374
375
  matchedFunction.checked = true;
375
-
376
+
376
377
  // 保存数据权限配置(如果有)
377
378
  if (item.dataScope) {
378
379
  row.dataPermission = item.dataScope;
380
+ // 标记为自定义配置
381
+ row.hasCustomConfig = true;
379
382
  // 如果是自定义数据权限,则设置已选组织
380
383
  if (item.dataScope === 6 && item.deptIds && item.deptIds.length > 0) {
381
384
  row.selectedOrgs = item.deptIds.map(id => {
@@ -387,7 +390,7 @@ function getRoleConfig() {
387
390
  });
388
391
  }
389
392
  }
390
-
393
+
391
394
  // 更新父级勾选状态(模块、子模块)
392
395
  updateParentCheckStatus(row);
393
396
  }
@@ -761,16 +764,17 @@ const handleOrgNodeExpand = (value) => {
761
764
  // 打开数据权限配置弹窗
762
765
  const openPermissionDialog = (row) => {
763
766
  currentRow.value = row
764
- // 只做展示,不写入行权限
765
- if (row.dataPermission) {
766
- selectedPermission.value = row.dataPermission
767
+ // 检查是否已有自定义配置
768
+ if (row.hasCustomConfig) {
769
+ // 已有自定义配置,使用自身配置
770
+ selectedPermission.value = row.dataPermission || 1
767
771
  if (row.dataPermission === 6 && row.selectedOrgs) {
768
772
  selectedOrgs.value = [...row.selectedOrgs]
769
773
  } else {
770
774
  selectedOrgs.value = []
771
775
  }
772
776
  } else {
773
- // 没有配置则展示全局,但不写入行
777
+ // 没有自定义配置,继承全局配置
774
778
  selectedPermission.value = globalPermission.value
775
779
  if (globalPermission.value === 6) {
776
780
  selectedOrgs.value = [...globalSelectedOrgs.value]
@@ -818,15 +822,19 @@ const handleGlobalOrgNodeSelect = (node, checked) => {
818
822
  }
819
823
  } else {
820
824
  // 从已选中中移除
821
- removeGlobalOrg(node.id)
825
+ removeGlobalSelectedOrg(node.id)
822
826
  }
823
827
  }
824
828
 
825
829
  // 移除选中的全局组织(对话框中使用)
826
830
  const removeGlobalSelectedOrg = (id) => {
827
- const index = tempGlobalSelectedOrgs.value.findIndex((org) => org.id === id)
831
+ console.log('移除临时全局组织', id);
832
+ const index = tempGlobalSelectedOrgs.value.findIndex((org) => org.id === id);
828
833
  if (index !== -1) {
829
- tempGlobalSelectedOrgs.value.splice(index, 1)
834
+ tempGlobalSelectedOrgs.value.splice(index, 1);
835
+ console.log('移除成功,剩余组织数量:', tempGlobalSelectedOrgs.value.length);
836
+ } else {
837
+ console.log('未找到对应组织');
830
838
  }
831
839
  }
832
840
 
@@ -864,7 +872,7 @@ const handleGlobalOrgConfirm = () => {
864
872
  // 保存选择结果
865
873
  globalSelectedOrgs.value = [...tempGlobalSelectedOrgs.value]
866
874
 
867
- // 应用到所有选择了自定义数据的行
875
+ // 应用到未配置自定义数据权限的行
868
876
  applyGlobalOrgsToCustomRows()
869
877
 
870
878
  globalOrgDialogVisible.value = false
@@ -875,11 +883,21 @@ const handleGlobalOrgCancel = () => {
875
883
  globalOrgDialogVisible.value = false
876
884
  }
877
885
 
878
- // 将全局组织应用到所有自定义数据权限的行
886
+ // 将全局组织应用到未配置自定义数据权限的行
879
887
  const applyGlobalOrgsToCustomRows = () => {
888
+ // 遍历每一行数据
880
889
  data.value.forEach((row) => {
881
- if (row.dataPermission === 6) {
882
- row.selectedOrgs = [...globalSelectedOrgs.value]
890
+ // 只对没有自定义配置的行应用全局设置
891
+ if (!row.hasCustomConfig) {
892
+ // 应用全局权限设置
893
+ row.dataPermission = globalPermission.value
894
+
895
+ // 如果全局设置是自定义数据权限,则应用全局选择的组织
896
+ if (globalPermission.value === 6) {
897
+ row.selectedOrgs = [...globalSelectedOrgs.value]
898
+ } else {
899
+ row.selectedOrgs = []
900
+ }
883
901
  }
884
902
  })
885
903
  }
@@ -887,6 +905,8 @@ const applyGlobalOrgsToCustomRows = () => {
887
905
  // 确认权限配置(修改处理全局配置的情况)
888
906
  const handlePermissionConfirm = () => {
889
907
  if (currentRow.value) {
908
+ // 标记该行已有自定义配置
909
+ currentRow.value.hasCustomConfig = true;
890
910
  currentRow.value.dataPermission = selectedPermission.value
891
911
  if (selectedPermission.value === 6) {
892
912
  currentRow.value.selectedOrgs = [...selectedOrgs.value]
@@ -899,6 +919,7 @@ const handlePermissionConfirm = () => {
899
919
 
900
920
  // 取消权限配置(修改处理全局配置的情况)
901
921
  const handlePermissionCancel = () => {
922
+ // 只关闭弹窗,不做其他操作
902
923
  permissionDialogVisible.value = false
903
924
  }
904
925
 
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <div>
3
- <slot name="content"></slot>
3
+ <slot></slot>
4
+ <slot v-if="$slots.content" name="content"></slot>
4
5
  </div>
5
6
  </template>
6
7
 
package/src/index.js CHANGED
@@ -60,6 +60,8 @@ import EbizTimePicker from './components/EbizTimePicker.vue';
60
60
  import EbizGridEditorSelect from './components/EbizGridEditorSelect.vue';
61
61
  import EbizPopconfirm from './components/EbizPopconfirm.vue';
62
62
  import EbizTreeMergeTable from './components/EbizTreeMergeTable.vue';
63
+ import EbizTdesignLoading from './components/EbizTdesignLoading.vue';
64
+ import EbizAutoForm from './components/EbizAutoForm.vue';
63
65
  import { MessagePlugin as EbizMessage } from 'tdesign-vue-next';
64
66
 
65
67
  // import EbizDescriptions from './components/EbizDescriptions.vue';
@@ -185,8 +187,11 @@ export {
185
187
  EbizPopconfirm,
186
188
  // 树形合并表格组件
187
189
  EbizTreeMergeTable,
190
+ // 自动表单组件
191
+ EbizAutoForm,
188
192
  // 新增 EbizDescriptions 和 EbizDescriptionsItem
189
193
  EbizDescriptions,
190
194
  EbizDescriptionsItem,
191
- TDescriptionsItem
195
+ TDescriptionsItem,
196
+ EbizTdesignLoading
192
197
  };
@@ -0,0 +1,130 @@
1
+ <template>
2
+ <div class="demo-container">
3
+ <h1>EbizAutoForm 自动表单组件示例</h1>
4
+
5
+ <div class="demo-section">
6
+ <h2>基本使用</h2>
7
+ <ebiz-auto-form
8
+ :api-config="apiConfig"
9
+ :initial-data="initialData"
10
+ @submit="handleSubmit"
11
+ @reset="handleReset"
12
+ />
13
+ </div>
14
+
15
+ <div class="demo-section">
16
+ <h2>表单提交结果</h2>
17
+ <pre v-if="submittedData">{{ JSON.stringify(submittedData, null, 2) }}</pre>
18
+ <p v-else>尚未提交表单</p>
19
+ </div>
20
+
21
+ <div class="demo-section">
22
+ <h2>自定义配置</h2>
23
+ <ebiz-auto-form
24
+ :api-config="customApiConfig"
25
+ :initial-data="customInitialData"
26
+ label-width="150px"
27
+ label-align="left"
28
+ :show-reset-button="false"
29
+ submit-button-text="保存信息"
30
+ @submit="handleCustomSubmit"
31
+ />
32
+ </div>
33
+ </div>
34
+ </template>
35
+
36
+ <script>
37
+ export default {
38
+ name: "EbizAutoFormDemo"
39
+ }
40
+ </script>
41
+
42
+ <script setup>
43
+ import { ref } from 'vue';
44
+ import { EbizAutoForm } from '../index.js';
45
+
46
+ // 基本配置示例
47
+ const apiConfig = ref({
48
+ apiId: 'getUserForm',
49
+ apiType: 'DETAILS_DATA',
50
+ key: 'user'
51
+ });
52
+
53
+ // 初始数据
54
+ const initialData = ref({
55
+ name: '张三',
56
+ email: 'zhangsan@example.com',
57
+ gender: 'male'
58
+ });
59
+
60
+ // 自定义配置示例
61
+ const customApiConfig = ref({
62
+ apiId: 'getProductForm',
63
+ apiType: 'DETAILS_DATA',
64
+ key: 'product'
65
+ });
66
+
67
+ // 自定义初始数据
68
+ const customInitialData = ref({
69
+ productName: '智能手机',
70
+ price: 2999,
71
+ status: true
72
+ });
73
+
74
+ // 提交结果
75
+ const submittedData = ref(null);
76
+
77
+ // 处理提交
78
+ const handleSubmit = (data) => {
79
+ console.log('表单提交数据:', data);
80
+ submittedData.value = data;
81
+ alert('表单提交成功!');
82
+ };
83
+
84
+ // 处理重置
85
+ const handleReset = () => {
86
+ console.log('表单已重置');
87
+ submittedData.value = null;
88
+ };
89
+
90
+ // 处理自定义表单提交
91
+ const handleCustomSubmit = (data) => {
92
+ console.log('自定义表单提交数据:', data);
93
+ alert('自定义表单提交成功!');
94
+ };
95
+ </script>
96
+
97
+ <style lang="less" scoped>
98
+ .demo-container {
99
+ max-width: 1000px;
100
+ margin: 0 auto;
101
+ padding: 20px;
102
+
103
+ h1 {
104
+ margin-bottom: 24px;
105
+ font-size: 24px;
106
+ color: #0052d9;
107
+ }
108
+
109
+ .demo-section {
110
+ margin-bottom: 40px;
111
+ padding: 20px;
112
+ border: 1px solid #e7e7e7;
113
+ border-radius: 6px;
114
+
115
+ h2 {
116
+ margin-bottom: 16px;
117
+ font-size: 18px;
118
+ color: #333;
119
+ }
120
+
121
+ pre {
122
+ padding: 12px;
123
+ background-color: #f5f7fa;
124
+ border-radius: 4px;
125
+ font-family: monospace;
126
+ overflow: auto;
127
+ }
128
+ }
129
+ }
130
+ </style>
@@ -78,7 +78,8 @@ export default {
78
78
  { path: '/time-picker', title: 'Ebiz时间选择器组件示例' },
79
79
  { path: '/tdesign-descriptions', title: 'Ebiz描述列表组件示例' },
80
80
  { path: '/popconfirm', title: 'Ebiz气泡确认框组件示例' },
81
- { path: '/tree-merge-table-demo', title: '树形合并表格组件示例' }
81
+ { path: '/tree-merge-table-demo', title: '树形合并表格组件示例' },
82
+ { path: '/auto-form-demo', title: 'Ebiz自动表单组件示例' }
82
83
  ]
83
84
 
84
85
  return {