@longhongguo/form-create-ant-design-vue 3.3.10 → 3.3.12

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": "@longhongguo/form-create-ant-design-vue",
3
- "version": "3.3.10",
3
+ "version": "3.3.12",
4
4
  "description": "AntDesignVue版本低代码表单|FormCreate 是一个可以通过 JSON 生成具有动态渲染、数据收集、验证和提交功能的低代码表单生成组件。支持6个UI框架,适配移动端,并且支持生成任何 Vue 组件。内置20种常用表单组件和自定义组件,再复杂的表单都可以轻松搞定。",
5
5
  "main": "./dist/form-create.min.js",
6
6
  "module": "./dist/form-create.esm.js",
@@ -36,7 +36,15 @@ export default defineComponent({
36
36
  uploadImgCustomInsert: [String, Function],
37
37
  withCredentials: Boolean,
38
38
  // form-create 注入的 API
39
- formCreateInject: Object
39
+ formCreateInject: Object,
40
+ placeholder: {
41
+ type: String,
42
+ default: '请输入正文'
43
+ },
44
+ height: {
45
+ type: [String, Number],
46
+ default: 300
47
+ }
40
48
  },
41
49
  emits: ['update:modelValue'],
42
50
  watch: {
@@ -51,6 +59,31 @@ export default defineComponent({
51
59
  editorConfig() {
52
60
  const config = {}
53
61
 
62
+ // 设置 placeholder
63
+ if (this.placeholder) {
64
+ config.placeholder = this.placeholder
65
+ }
66
+
67
+ // 设置高度
68
+ if (this.height) {
69
+ // 如果是数字,转换为像素字符串;如果是字符串,直接使用
70
+ config.height = this.height
71
+ }
72
+
73
+ // 排除不需要的工具栏菜单项
74
+ // 移除:全屏、代码、表情、删除线、缩进、待办事项、引用、分割线、斜体
75
+ config.excludeMenus = [
76
+ 'fullScreen', // 全屏
77
+ 'code', // 代码
78
+ 'emoticon', // 表情
79
+ 'strikeThrough', // 删除线
80
+ 'indent', // 缩进
81
+ 'todo', // 待办事项
82
+ 'quote', // 引用
83
+ 'splitLine', // 分割线
84
+ 'italic' // 斜体
85
+ ]
86
+
54
87
  // 如果设置了 readOnly,配置只读模式
55
88
  if (this.readOnly) {
56
89
  // readOnly: true // 启用只读模式
@@ -61,6 +94,10 @@ export default defineComponent({
61
94
  // 禁用自动聚焦,避免在只读模式下获得焦点
62
95
  config.focus = false
63
96
  config.autoFocus = false
97
+ // 只读模式下隐藏 placeholder
98
+ delete config.placeholder
99
+ // 只读模式下移除固定高度,使用自适应
100
+ delete config.height
64
101
  }
65
102
 
66
103
  // 如果设置了 uploadImgServer,配置图片上传
@@ -506,8 +543,16 @@ export default defineComponent({
506
543
  }
507
544
 
508
545
  this.$nextTick(() => {
546
+ // 查找编辑器的根元素
547
+ let editorRootElement = null
548
+ if (this._editor.id) {
549
+ editorRootElement = document.getElementById(this._editor.id)
550
+ }
551
+
509
552
  // 查找编辑器的文本容器
510
553
  let textContainer = null
554
+ let containerElement = null
555
+
511
556
  if (this._editor.$textElem && this._editor.$textElem[0]) {
512
557
  textContainer = this._editor.$textElem[0]
513
558
  } else {
@@ -516,6 +561,7 @@ export default defineComponent({
516
561
  const editorEl = document.getElementById(editorId)
517
562
  if (editorEl) {
518
563
  textContainer = editorEl.querySelector('.w-e-text')
564
+ containerElement = editorEl.querySelector('.w-e-text-container')
519
565
  }
520
566
  }
521
567
  }
@@ -526,12 +572,43 @@ export default defineComponent({
526
572
  this._editor.$textContainerElem &&
527
573
  this._editor.$textContainerElem[0]
528
574
  ) {
529
- textContainer = this._editor.$textContainerElem[0]
575
+ containerElement = this._editor.$textContainerElem[0]
576
+ }
577
+ }
578
+
579
+ // 查找容器元素(如果还没找到)
580
+ if (
581
+ !containerElement &&
582
+ this._editor.$textContainerElem &&
583
+ this._editor.$textContainerElem[0]
584
+ ) {
585
+ containerElement = this._editor.$textContainerElem[0]
586
+ } else if (!containerElement && this._editor.id) {
587
+ const editorEl = document.getElementById(this._editor.id)
588
+ if (editorEl) {
589
+ containerElement = editorEl.querySelector('.w-e-text-container')
530
590
  }
531
591
  }
532
592
 
533
593
  if (textContainer) {
534
594
  if (readOnly) {
595
+ // 设置根元素为自适应高度(移除内联样式中的固定高度)
596
+ if (editorRootElement) {
597
+ editorRootElement.style.height = 'auto'
598
+ editorRootElement.style.minHeight = 'auto'
599
+ editorRootElement.style.maxHeight = 'none'
600
+ }
601
+ // 设置容器和文本区域为自适应高度
602
+ if (containerElement) {
603
+ containerElement.style.height = 'auto'
604
+ containerElement.style.minHeight = 'auto'
605
+ containerElement.style.maxHeight = 'none'
606
+ }
607
+ if (textContainer) {
608
+ textContainer.style.height = 'auto'
609
+ textContainer.style.minHeight = 'auto'
610
+ textContainer.style.maxHeight = 'none'
611
+ }
535
612
  // 强制设置为只读:禁用编辑,但允许选择和点击链接
536
613
  const forceReadOnly = () => {
537
614
  // 强制设置 contenteditable
@@ -542,6 +619,21 @@ export default defineComponent({
542
619
  textContainer.style.mozUserSelect = 'text'
543
620
  textContainer.style.msUserSelect = 'text'
544
621
  textContainer.style.cursor = 'text'
622
+ // 保持根元素自适应高度
623
+ if (editorRootElement) {
624
+ editorRootElement.style.height = 'auto'
625
+ editorRootElement.style.minHeight = 'auto'
626
+ editorRootElement.style.maxHeight = 'none'
627
+ }
628
+ // 保持容器和文本区域自适应高度
629
+ if (containerElement) {
630
+ containerElement.style.height = 'auto'
631
+ containerElement.style.minHeight = 'auto'
632
+ containerElement.style.maxHeight = 'none'
633
+ }
634
+ textContainer.style.height = 'auto'
635
+ textContainer.style.minHeight = 'auto'
636
+ textContainer.style.maxHeight = 'none'
545
637
  }
546
638
 
547
639
  forceReadOnly()
@@ -105,6 +105,10 @@ export default {
105
105
  // 只读模式允许复制和点击链接,但禁止编辑
106
106
  if (ctx.prop.props) {
107
107
  ctx.prop.props.readOnly = true
108
+ // 预览模式和只读模式下隐藏 placeholder
109
+ delete ctx.prop.props.placeholder
110
+ // 预览模式和只读模式下移除固定高度,使用自适应
111
+ delete ctx.prop.props.height
108
112
  }
109
113
  } else if (
110
114
  ctx.rule.type === 'input' &&
@@ -118,6 +122,10 @@ export default {
118
122
  ctx.prop.props.autoSize = true
119
123
  // 移除 rows 属性,让 autoSize 完全控制高度
120
124
  delete ctx.prop.props.rows
125
+ // 预览模式和只读模式下隐藏 placeholder
126
+ delete ctx.prop.props.placeholder
127
+ // 预览模式和只读模式下隐藏字符计数
128
+ ctx.prop.props.showCount = false
121
129
  }
122
130
  } else if (ctx.rule.type === 'select') {
123
131
  // select 组件在预览模式下使用 disabled 实现只读效果
@@ -126,6 +134,8 @@ export default {
126
134
  // 强制设置 disabled = true,覆盖用户可能设置的 disabled: false
127
135
  if (ctx.prop.props) {
128
136
  ctx.prop.props.disabled = true
137
+ // 预览模式和只读模式下隐藏 placeholder
138
+ delete ctx.prop.props.placeholder
129
139
  // 如果原本设置了 readOnly,保留这个标记以便 CSS 识别
130
140
  if (isReadOnly) {
131
141
  // 可以在这里添加一个标记,但 Select 组件不支持 readOnly
@@ -137,6 +147,30 @@ export default {
137
147
  // 如果设置了 readOnly,直接使用组件的 readOnly 属性
138
148
  if (ctx.prop.props && isReadOnly) {
139
149
  ctx.prop.props.readOnly = true
150
+ // 预览模式和只读模式下隐藏 placeholder
151
+ delete ctx.prop.props.placeholder
152
+ // 预览模式和只读模式下隐藏字符计数
153
+ ctx.prop.props.showCount = false
154
+ } else if (ctx.prop.props && isPreviewMode) {
155
+ // 全局预览模式下也隐藏 placeholder
156
+ delete ctx.prop.props.placeholder
157
+ // 全局预览模式下隐藏字符计数
158
+ ctx.prop.props.showCount = false
159
+ }
160
+ } else if (
161
+ ctx.rule.type === 'datePicker' ||
162
+ ctx.rule.type === 'timePicker' ||
163
+ ctx.rule.type === 'timeRangePicker' ||
164
+ ctx.rule.type === 'rangePicker' ||
165
+ ctx.rule.type === 'cascader'
166
+ ) {
167
+ // 日期选择器、时间选择器、级联选择器等组件
168
+ // 预览模式和只读模式下隐藏 placeholder
169
+ if (ctx.prop.props) {
170
+ if (ctx.rule.type === 'cascader') {
171
+ ctx.prop.props.disabled = true
172
+ }
173
+ delete ctx.prop.props.placeholder
140
174
  }
141
175
  }
142
176
  }
@@ -1,5 +1,6 @@
1
1
  import { hasProperty } from '@form-create/utils/lib/type'
2
2
  import { deepCopy } from '@form-create/utils/lib/deepextend'
3
+ import { h } from 'vue'
3
4
 
4
5
  // 简单的 getValue 函数,根据路径字符串获取嵌套对象的值
5
6
  function getValue(obj, path) {
@@ -165,6 +166,119 @@ export default {
165
166
  // 如果已经是数字,直接使用
166
167
  }
167
168
 
169
+ // 处理单元格表单组件
170
+ if (
171
+ column.cellType &&
172
+ ['input', 'select', 'radio'].includes(column.cellType)
173
+ ) {
174
+ const cellType = column.cellType
175
+ const dataIndex = column.dataIndex
176
+ const cellOptions = column.cellOptions || []
177
+ const cellProps = column.cellProps || {}
178
+
179
+ // 创建 customRender 函数
180
+ column.customRender = ({ text, record, index }) => {
181
+ const cellValue = record && dataIndex ? record[dataIndex] : text
182
+
183
+ if (cellType === 'input') {
184
+ // 渲染 input 组件 - 使用组件名字符串
185
+ return h('a-input', {
186
+ value: cellValue,
187
+ onChange: (e) => {
188
+ const val =
189
+ e.target?.value !== undefined
190
+ ? e.target.value
191
+ : e?.target?.inputValue !== undefined
192
+ ? e.target.inputValue
193
+ : e
194
+ if (record && dataIndex) {
195
+ record[dataIndex] = val
196
+ // 触发表格数据更新
197
+ if (ctx.api && ctx.api.form && rule.field) {
198
+ ctx.api.form[rule.field] = props.dataSource
199
+ }
200
+ }
201
+ },
202
+ placeholder: cellProps.placeholder || '',
203
+ disabled: cellProps.disabled || false,
204
+ size: cellProps.size || 'small',
205
+ ...cellProps
206
+ })
207
+ } else if (cellType === 'select') {
208
+ // 渲染 select 组件 - 使用组件名字符串
209
+ return h(
210
+ 'a-select',
211
+ {
212
+ value: cellValue,
213
+ onChange: (val) => {
214
+ if (record && dataIndex) {
215
+ record[dataIndex] = val
216
+ // 触发表格数据更新
217
+ if (ctx.api && ctx.api.form && rule.field) {
218
+ ctx.api.form[rule.field] = props.dataSource
219
+ }
220
+ }
221
+ },
222
+ placeholder: cellProps.placeholder || '',
223
+ disabled: cellProps.disabled || false,
224
+ size: cellProps.size || 'small',
225
+ ...cellProps
226
+ },
227
+ {
228
+ default: () =>
229
+ cellOptions.map((opt) => {
230
+ return h('a-select-option', {
231
+ key: opt.value,
232
+ value: opt.value,
233
+ label: opt.label
234
+ })
235
+ })
236
+ }
237
+ )
238
+ } else if (cellType === 'radio') {
239
+ // 渲染 radio 组件 - 使用组件名字符串
240
+ return h(
241
+ 'a-radio-group',
242
+ {
243
+ value: cellValue,
244
+ onChange: (e) => {
245
+ const val =
246
+ e.target?.value !== undefined ? e.target.value : e
247
+ if (record && dataIndex) {
248
+ record[dataIndex] = val
249
+ // 触发表格数据更新
250
+ if (ctx.api && ctx.api.form && rule.field) {
251
+ ctx.api.form[rule.field] = props.dataSource
252
+ }
253
+ }
254
+ },
255
+ disabled: cellProps.disabled || false,
256
+ size: cellProps.size || 'small',
257
+ ...cellProps
258
+ },
259
+ {
260
+ default: () =>
261
+ cellOptions.map((opt) => {
262
+ return h(
263
+ 'a-radio',
264
+ {
265
+ key: opt.value,
266
+ value: opt.value
267
+ },
268
+ {
269
+ default: () => opt.label || opt.value
270
+ }
271
+ )
272
+ })
273
+ }
274
+ )
275
+ }
276
+
277
+ // 如果没有匹配的类型,返回原始文本
278
+ return text
279
+ }
280
+ }
281
+
168
282
  // 确保其他列属性也被保留(align、fixed、title、dataIndex 等)
169
283
  return column
170
284
  })
@@ -420,6 +420,28 @@ textarea[readonly].ant-input {
420
420
  max-height: none !important;
421
421
  }
422
422
 
423
+ /* 只读模式:富文本编辑器样式(通过 contenteditable="false" 识别) */
424
+ .w-e-text[contenteditable='false'] {
425
+ border: none !important;
426
+ box-shadow: none !important;
427
+ background: transparent !important;
428
+ /* 移除高度限制,让内容自适应 */
429
+ height: auto !important;
430
+ min-height: auto !important;
431
+ max-height: none !important;
432
+ }
433
+
434
+ /* 预览模式:编辑器根元素自适应高度 */
435
+ .form-create.is-preview div[id^='editor'][readonly='true'],
436
+ .form-create.is-preview div[id^='editor'][readonly] {
437
+ height: auto !important;
438
+ min-height: auto !important;
439
+ max-height: none !important;
440
+ }
441
+
442
+ /* 只读模式下,通过 JavaScript 设置容器自适应高度 */
443
+ /* 容器样式会在 setReadOnlyMode 中通过 JavaScript 动态设置 */
444
+
423
445
  /* 富文本内容只读:允许选择文本和点击链接,但禁止编辑 */
424
446
  .form-create.is-preview .w-e-text p,
425
447
  .form-create.is-preview .w-e-text div,