parent
							
								
									25b3d69041
								
							
						
					
					
						commit
						65493e128a
					
				| @ -0,0 +1,76 @@ | ||||
| /** | ||||
|  * @name: createProps | ||||
|  * @author: 卜启缘 | ||||
|  * @date: 2021/5/30 10:50 | ||||
|  * @description:createProps | ||||
|  * @update: 2021/5/30 10:50 | ||||
|  */ | ||||
| 
 | ||||
| import { | ||||
|   createEditorInputProp, | ||||
|   createEditorSelectProp, | ||||
|   createEditorSwitchProp, | ||||
|   createEditorTableProp | ||||
| } from '@/visual-editor/visual-editor.props' | ||||
| 
 | ||||
| // 对齐方式
 | ||||
| const alignOptions = [ | ||||
|   { | ||||
|     label: '左对齐', | ||||
|     value: 'left' | ||||
|   }, | ||||
|   { | ||||
|     label: '右对齐', | ||||
|     value: 'right' | ||||
|   }, | ||||
|   { | ||||
|     label: '居中对齐', | ||||
|     value: 'center' | ||||
|   } | ||||
| ] | ||||
| 
 | ||||
| export const compProps = { | ||||
|   'slots.default.children': createEditorTableProp({ | ||||
|     label: '表单项', | ||||
|     option: { | ||||
|       options: [ | ||||
|         { label: '显示值', field: 'label' }, | ||||
|         { label: '绑定值', field: 'value' }, | ||||
|         { label: '备注', field: 'comments' } | ||||
|       ], | ||||
|       showKey: 'label' | ||||
|     }, | ||||
|     defaultValue: [] | ||||
|   }), | ||||
|   colon: createEditorSwitchProp({ label: '是否在 label 后面添加冒号' }), | ||||
|   disabled: createEditorSwitchProp({ label: '是否禁用表单中的所有输入框' }), | ||||
|   errorMessageAlign: createEditorSelectProp({ | ||||
|     label: '错误提示文案对齐方式', | ||||
|     defaultValue: 'left', | ||||
|     options: alignOptions | ||||
|   }), | ||||
|   inputAlign: createEditorSelectProp({ | ||||
|     label: '输入框对齐方式', | ||||
|     defaultValue: 'left', | ||||
|     options: alignOptions | ||||
|   }), | ||||
|   labelAlign: createEditorSelectProp({ | ||||
|     label: '表单项 label 对齐方式', | ||||
|     defaultValue: 'left', | ||||
|     options: alignOptions | ||||
|   }), | ||||
|   labelWidth: createEditorInputProp({ label: '表单项 label 宽度,默认单位为px' }), | ||||
|   readonly: createEditorSwitchProp({ label: '是否将表单中的所有输入框设置为只读状态' }), | ||||
|   scrollToError: createEditorSwitchProp({ | ||||
|     label: '在提交表单且校验不通过时滚动至错误的表单项' | ||||
|   }), | ||||
|   showError: createEditorSwitchProp({ label: '是否在校验不通过时标红输入框' }), | ||||
|   showErrorMessage: createEditorSwitchProp({ | ||||
|     label: '是否在校验不通过时在输入框下方展示错误提示' | ||||
|   }), | ||||
|   submitOnEnter: createEditorSwitchProp({ label: '是否在按下回车键时提交表单' }), | ||||
|   validateFirst: createEditorSwitchProp({ label: '是否在某一项校验不通过时停止校验' }), | ||||
|   validateTrigger: createEditorInputProp({ | ||||
|     label: '表单校验触发时机,可选值为 onChange、onSubmit,详见下表' | ||||
|   }) | ||||
| } | ||||
| @ -1,2 +1,9 @@ | ||||
| import { App } from 'vue' | ||||
| import '@vant/touch-emulator' | ||||
| import 'vant/lib/index.css' | ||||
| 
 | ||||
| import { Lazyload } from 'vant' | ||||
| 
 | ||||
| export const setupVant = (app: App) => { | ||||
|   app.use(Lazyload) | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,8 @@ | ||||
| /** | ||||
|  * @name: index | ||||
|  * @author: 卜启缘 | ||||
|  * @date: 2021/5/30 10:57 | ||||
|  * @description:index | ||||
|  * @update: 2021/5/30 10:57 | ||||
|  */ | ||||
| export { TablePropEditor } from './table-prop-editor/table-prop-editor' | ||||
| @ -0,0 +1,11 @@ | ||||
| /** | ||||
|  * @name: index.d | ||||
|  * @author: 卜启缘 | ||||
|  * @date: 2021/5/30 10:40 | ||||
|  * @description:index.d | ||||
|  * @update: 2021/5/30 10:40 | ||||
|  */ | ||||
| declare type LabelValueOptions = { | ||||
|   label: string | ||||
|   value: any | ||||
| }[] | ||||
| @ -1,232 +1,232 @@ | ||||
| import { useCommander } from './plugins/command.plugin' | ||||
| import { VisualEditorBlockData, VisualEditorModelValue } from './visual-editor.utils' | ||||
| import { cloneDeep } from 'lodash' | ||||
| 
 | ||||
| export function useVisualCommand({ | ||||
|   focusData, | ||||
|   updateBlocks, | ||||
|   dataModel, | ||||
|   dragstart, | ||||
|   dragend | ||||
| }: { | ||||
|   focusData: { value: { focus: VisualEditorBlockData[]; unFocus: VisualEditorBlockData[] } } | ||||
|   updateBlocks: (blocks?: VisualEditorBlockData[]) => void | ||||
|   dataModel: { value: VisualEditorModelValue } | ||||
|   dragstart: { on: (cb: () => void) => void; off: (cb: () => void) => void } | ||||
|   dragend: { on: (cb: () => void) => void; off: (cb: () => void) => void } | ||||
| }) { | ||||
|   const commander = useCommander() | ||||
| 
 | ||||
|   /** | ||||
|    * 删除命令 | ||||
|    * @author  卜启缘 | ||||
|    * @date    2021/4/22 11:37 下午 | ||||
|    */ | ||||
|   commander.registry({ | ||||
|     name: 'delete', | ||||
|     keyboard: ['backspace', 'delete', 'ctrl+d'], | ||||
|     execute: () => { | ||||
|       // console.log('执行删除命令')
 | ||||
|       const data = { | ||||
|         before: dataModel.value.blocks, | ||||
|         after: focusData.value.unFocus | ||||
|       } | ||||
|       return { | ||||
|         redo: () => { | ||||
|           // console.log('重做删除命令')
 | ||||
|           updateBlocks(cloneDeep(data.after)) | ||||
|         }, | ||||
|         undo: () => { | ||||
|           // console.log('撤回删除命令')
 | ||||
|           updateBlocks(cloneDeep(data.before)) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   /** | ||||
|    * 拖拽命令,适用于三种情况: | ||||
|    * - 从菜单拖拽组件到容器画布; | ||||
|    * - 在容器中拖拽组件调整位置 | ||||
|    * - 拖拽调整组件的宽度和高度; | ||||
|    * @author  卜启缘 | ||||
|    * @date    2021/4/22 11:38 下午 | ||||
|    */ | ||||
|   commander.registry({ | ||||
|     name: 'drag', | ||||
|     init() { | ||||
|       this.data = { before: null as null | VisualEditorBlockData[] } | ||||
|       const handler = { | ||||
|         dragstart: () => (this.data.before = cloneDeep(dataModel.value.blocks)), | ||||
|         dragend: () => commander.state.commands.drag() | ||||
|       } | ||||
|       dragstart.on(handler.dragstart) | ||||
|       dragend.on(handler.dragend) | ||||
|       return () => { | ||||
|         dragstart.off(handler.dragstart) | ||||
|         dragend.off(handler.dragend) | ||||
|       } | ||||
|     }, | ||||
|     execute() { | ||||
|       const before = cloneDeep(this.data.before) | ||||
|       const after = cloneDeep(dataModel.value.blocks) | ||||
|       return { | ||||
|         redo: () => { | ||||
|           updateBlocks(cloneDeep(after)) | ||||
|         }, | ||||
|         undo: () => { | ||||
|           updateBlocks(cloneDeep(before)) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   commander.registry({ | ||||
|     name: 'clear', | ||||
|     execute: () => { | ||||
|       const data = { | ||||
|         before: cloneDeep(dataModel.value.blocks), | ||||
|         after: cloneDeep([]) | ||||
|       } | ||||
|       return { | ||||
|         redo: () => { | ||||
|           updateBlocks(cloneDeep(data.after)) | ||||
|         }, | ||||
|         undo: () => { | ||||
|           updateBlocks(cloneDeep(data.before)) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   commander.registry({ | ||||
|     name: 'placeTop', | ||||
|     keyboard: 'ctrl+up', | ||||
|     execute: () => { | ||||
|       const data = { | ||||
|         before: cloneDeep(dataModel.value.blocks), | ||||
|         after: cloneDeep( | ||||
|           (() => { | ||||
|             const { focus, unFocus } = focusData.value | ||||
|             const maxZIndex = | ||||
|               unFocus.reduce((prev, block) => Math.max(prev, block.zIndex), -Infinity) + 1 | ||||
|             focus.forEach((block) => (block.zIndex = maxZIndex)) | ||||
|             return cloneDeep(dataModel.value.blocks) | ||||
|           })() | ||||
|         ) | ||||
|       } | ||||
|       return { | ||||
|         redo: () => { | ||||
|           updateBlocks(cloneDeep(data.after)) | ||||
|         }, | ||||
|         undo: () => { | ||||
|           updateBlocks(cloneDeep(data.before)) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   commander.registry({ | ||||
|     name: 'placeBottom', | ||||
|     keyboard: 'ctrl+down', | ||||
|     execute: () => { | ||||
|       const data = { | ||||
|         before: cloneDeep(dataModel.value.blocks), | ||||
|         after: cloneDeep( | ||||
|           (() => { | ||||
|             const { focus, unFocus } = focusData.value | ||||
|             let minZIndex = | ||||
|               unFocus.reduce((prev, block) => Math.min(prev, block.zIndex), Infinity) - 1 | ||||
|             if (minZIndex < 0) { | ||||
|               const dur = Math.abs(minZIndex) | ||||
|               unFocus.forEach((block) => (block.zIndex += dur)) | ||||
|               minZIndex = 0 | ||||
|             } | ||||
|             focus.forEach((block) => (block.zIndex = minZIndex)) | ||||
|             return cloneDeep(dataModel.value.blocks) | ||||
|           })() | ||||
|         ) | ||||
|       } | ||||
|       return { | ||||
|         redo: () => { | ||||
|           updateBlocks(cloneDeep(data.after)) | ||||
|         }, | ||||
|         undo: () => { | ||||
|           updateBlocks(cloneDeep(data.before)) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   commander.registry({ | ||||
|     name: 'updateBlock', | ||||
|     execute: (newBlock: VisualEditorBlockData, oldBlock: VisualEditorBlockData) => { | ||||
|       let blocks = cloneDeep(dataModel.value.blocks || []) | ||||
|       const data = { | ||||
|         before: blocks, | ||||
|         after: (() => { | ||||
|           blocks = [...blocks] | ||||
|           const index = dataModel.value.blocks!.indexOf(oldBlock) | ||||
|           if (index > -1) { | ||||
|             blocks.splice(index, 1, newBlock) | ||||
|           } | ||||
|           return cloneDeep(blocks) | ||||
|         })() | ||||
|       } | ||||
|       return { | ||||
|         redo: () => { | ||||
|           updateBlocks(cloneDeep(data.after)) | ||||
|         }, | ||||
|         undo: () => { | ||||
|           updateBlocks(cloneDeep(data.before)) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   commander.registry({ | ||||
|     name: 'updateModelValue', | ||||
|     execute: (val: VisualEditorModelValue) => { | ||||
|       const data = { | ||||
|         before: cloneDeep(dataModel.value), | ||||
|         after: cloneDeep(val) | ||||
|       } | ||||
|       return { | ||||
|         redo: () => { | ||||
|           dataModel.value = data.after | ||||
|         }, | ||||
|         undo: () => { | ||||
|           dataModel.value = data.before | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   commander.registry({ | ||||
|     name: 'selectAll', | ||||
|     followQueue: false, | ||||
|     keyboard: 'ctrl+a', | ||||
|     execute: () => { | ||||
|       return { | ||||
|         redo: () => { | ||||
|           ;(dataModel.value.blocks || []).forEach((block) => (block.focus = true)) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   commander.init() | ||||
| 
 | ||||
|   return { | ||||
|     undo: () => commander.state.commands.undo(), | ||||
|     redo: () => commander.state.commands.redo(), | ||||
|     delete: () => commander.state.commands.delete(), | ||||
|     clear: () => commander.state.commands.clear(), | ||||
|     placeTop: () => commander.state.commands.placeTop(), | ||||
|     placeBottom: () => commander.state.commands.placeBottom(), | ||||
|     updateBlock: (newBlock: VisualEditorBlockData, oldBlock: VisualEditorBlockData) => | ||||
|       commander.state.commands.updateBlock(newBlock, oldBlock), | ||||
|     updateModelValue: (val: VisualEditorModelValue) => | ||||
|       commander.state.commands.updateModelValue(val) | ||||
|   } | ||||
| } | ||||
| // import { useCommander } from './plugins/command.plugin'
 | ||||
| // import { VisualEditorBlockData, VisualEditorModelValue } from './visual-editor.utils'
 | ||||
| // import { cloneDeep } from 'lodash'
 | ||||
| //
 | ||||
| // export function useVisualCommand({
 | ||||
| //   focusData,
 | ||||
| //   updateBlocks,
 | ||||
| //   dataModel,
 | ||||
| //   dragstart,
 | ||||
| //   dragend
 | ||||
| // }: {
 | ||||
| //   focusData: { value: { focus: VisualEditorBlockData[]; unFocus: VisualEditorBlockData[] } }
 | ||||
| //   updateBlocks: (blocks?: VisualEditorBlockData[]) => void
 | ||||
| //   dataModel: { value: VisualEditorModelValue }
 | ||||
| //   dragstart: { on: (cb: () => void) => void; off: (cb: () => void) => void }
 | ||||
| //   dragend: { on: (cb: () => void) => void; off: (cb: () => void) => void }
 | ||||
| // }) {
 | ||||
| //   const commander = useCommander()
 | ||||
| //
 | ||||
| //   /**
 | ||||
| //    * 删除命令
 | ||||
| //    * @author  卜启缘
 | ||||
| //    * @date    2021/4/22 11:37 下午
 | ||||
| //    */
 | ||||
| //   commander.registry({
 | ||||
| //     name: 'delete',
 | ||||
| //     keyboard: ['backspace', 'delete', 'ctrl+d'],
 | ||||
| //     execute: () => {
 | ||||
| //       // console.log('执行删除命令')
 | ||||
| //       const data = {
 | ||||
| //         before: dataModel.value.blocks,
 | ||||
| //         after: focusData.value.unFocus
 | ||||
| //       }
 | ||||
| //       return {
 | ||||
| //         redo: () => {
 | ||||
| //           // console.log('重做删除命令')
 | ||||
| //           updateBlocks(cloneDeep(data.after))
 | ||||
| //         },
 | ||||
| //         undo: () => {
 | ||||
| //           // console.log('撤回删除命令')
 | ||||
| //           updateBlocks(cloneDeep(data.before))
 | ||||
| //         }
 | ||||
| //       }
 | ||||
| //     }
 | ||||
| //   })
 | ||||
| //
 | ||||
| //   /**
 | ||||
| //    * 拖拽命令,适用于三种情况:
 | ||||
| //    * - 从菜单拖拽组件到容器画布;
 | ||||
| //    * - 在容器中拖拽组件调整位置
 | ||||
| //    * - 拖拽调整组件的宽度和高度;
 | ||||
| //    * @author  卜启缘
 | ||||
| //    * @date    2021/4/22 11:38 下午
 | ||||
| //    */
 | ||||
| //   commander.registry({
 | ||||
| //     name: 'drag',
 | ||||
| //     init() {
 | ||||
| //       this.data = { before: null as null | VisualEditorBlockData[] }
 | ||||
| //       const handler = {
 | ||||
| //         dragstart: () => (this.data.before = cloneDeep(dataModel.value.blocks)),
 | ||||
| //         dragend: () => commander.state.commands.drag()
 | ||||
| //       }
 | ||||
| //       dragstart.on(handler.dragstart)
 | ||||
| //       dragend.on(handler.dragend)
 | ||||
| //       return () => {
 | ||||
| //         dragstart.off(handler.dragstart)
 | ||||
| //         dragend.off(handler.dragend)
 | ||||
| //       }
 | ||||
| //     },
 | ||||
| //     execute() {
 | ||||
| //       const before = cloneDeep(this.data.before)
 | ||||
| //       const after = cloneDeep(dataModel.value.blocks)
 | ||||
| //       return {
 | ||||
| //         redo: () => {
 | ||||
| //           updateBlocks(cloneDeep(after))
 | ||||
| //         },
 | ||||
| //         undo: () => {
 | ||||
| //           updateBlocks(cloneDeep(before))
 | ||||
| //         }
 | ||||
| //       }
 | ||||
| //     }
 | ||||
| //   })
 | ||||
| //
 | ||||
| //   commander.registry({
 | ||||
| //     name: 'clear',
 | ||||
| //     execute: () => {
 | ||||
| //       const data = {
 | ||||
| //         before: cloneDeep(dataModel.value.blocks),
 | ||||
| //         after: cloneDeep([])
 | ||||
| //       }
 | ||||
| //       return {
 | ||||
| //         redo: () => {
 | ||||
| //           updateBlocks(cloneDeep(data.after))
 | ||||
| //         },
 | ||||
| //         undo: () => {
 | ||||
| //           updateBlocks(cloneDeep(data.before))
 | ||||
| //         }
 | ||||
| //       }
 | ||||
| //     }
 | ||||
| //   })
 | ||||
| //
 | ||||
| //   commander.registry({
 | ||||
| //     name: 'placeTop',
 | ||||
| //     keyboard: 'ctrl+up',
 | ||||
| //     execute: () => {
 | ||||
| //       const data = {
 | ||||
| //         before: cloneDeep(dataModel.value.blocks),
 | ||||
| //         after: cloneDeep(
 | ||||
| //           (() => {
 | ||||
| //             const { focus, unFocus } = focusData.value
 | ||||
| //             const maxZIndex =
 | ||||
| //               unFocus.reduce((prev, block) => Math.max(prev, block.zIndex), -Infinity) + 1
 | ||||
| //             focus.forEach((block) => (block.zIndex = maxZIndex))
 | ||||
| //             return cloneDeep(dataModel.value.blocks)
 | ||||
| //           })()
 | ||||
| //         )
 | ||||
| //       }
 | ||||
| //       return {
 | ||||
| //         redo: () => {
 | ||||
| //           updateBlocks(cloneDeep(data.after))
 | ||||
| //         },
 | ||||
| //         undo: () => {
 | ||||
| //           updateBlocks(cloneDeep(data.before))
 | ||||
| //         }
 | ||||
| //       }
 | ||||
| //     }
 | ||||
| //   })
 | ||||
| //
 | ||||
| //   commander.registry({
 | ||||
| //     name: 'placeBottom',
 | ||||
| //     keyboard: 'ctrl+down',
 | ||||
| //     execute: () => {
 | ||||
| //       const data = {
 | ||||
| //         before: cloneDeep(dataModel.value.blocks),
 | ||||
| //         after: cloneDeep(
 | ||||
| //           (() => {
 | ||||
| //             const { focus, unFocus } = focusData.value
 | ||||
| //             let minZIndex =
 | ||||
| //               unFocus.reduce((prev, block) => Math.min(prev, block.zIndex), Infinity) - 1
 | ||||
| //             if (minZIndex < 0) {
 | ||||
| //               const dur = Math.abs(minZIndex)
 | ||||
| //               unFocus.forEach((block) => (block.zIndex += dur))
 | ||||
| //               minZIndex = 0
 | ||||
| //             }
 | ||||
| //             focus.forEach((block) => (block.zIndex = minZIndex))
 | ||||
| //             return cloneDeep(dataModel.value.blocks)
 | ||||
| //           })()
 | ||||
| //         )
 | ||||
| //       }
 | ||||
| //       return {
 | ||||
| //         redo: () => {
 | ||||
| //           updateBlocks(cloneDeep(data.after))
 | ||||
| //         },
 | ||||
| //         undo: () => {
 | ||||
| //           updateBlocks(cloneDeep(data.before))
 | ||||
| //         }
 | ||||
| //       }
 | ||||
| //     }
 | ||||
| //   })
 | ||||
| //
 | ||||
| //   commander.registry({
 | ||||
| //     name: 'updateBlock',
 | ||||
| //     execute: (newBlock: VisualEditorBlockData, oldBlock: VisualEditorBlockData) => {
 | ||||
| //       let blocks = cloneDeep(dataModel.value.blocks || [])
 | ||||
| //       const data = {
 | ||||
| //         before: blocks,
 | ||||
| //         after: (() => {
 | ||||
| //           blocks = [...blocks]
 | ||||
| //           const index = dataModel.value.blocks!.indexOf(oldBlock)
 | ||||
| //           if (index > -1) {
 | ||||
| //             blocks.splice(index, 1, newBlock)
 | ||||
| //           }
 | ||||
| //           return cloneDeep(blocks)
 | ||||
| //         })()
 | ||||
| //       }
 | ||||
| //       return {
 | ||||
| //         redo: () => {
 | ||||
| //           updateBlocks(cloneDeep(data.after))
 | ||||
| //         },
 | ||||
| //         undo: () => {
 | ||||
| //           updateBlocks(cloneDeep(data.before))
 | ||||
| //         }
 | ||||
| //       }
 | ||||
| //     }
 | ||||
| //   })
 | ||||
| //
 | ||||
| //   commander.registry({
 | ||||
| //     name: 'updateModelValue',
 | ||||
| //     execute: (val: VisualEditorModelValue) => {
 | ||||
| //       const data = {
 | ||||
| //         before: cloneDeep(dataModel.value),
 | ||||
| //         after: cloneDeep(val)
 | ||||
| //       }
 | ||||
| //       return {
 | ||||
| //         redo: () => {
 | ||||
| //           dataModel.value = data.after
 | ||||
| //         },
 | ||||
| //         undo: () => {
 | ||||
| //           dataModel.value = data.before
 | ||||
| //         }
 | ||||
| //       }
 | ||||
| //     }
 | ||||
| //   })
 | ||||
| //
 | ||||
| //   commander.registry({
 | ||||
| //     name: 'selectAll',
 | ||||
| //     followQueue: false,
 | ||||
| //     keyboard: 'ctrl+a',
 | ||||
| //     execute: () => {
 | ||||
| //       return {
 | ||||
| //         redo: () => {
 | ||||
| //           ;(dataModel.value.blocks || []).forEach((block) => (block.focus = true))
 | ||||
| //         }
 | ||||
| //       }
 | ||||
| //     }
 | ||||
| //   })
 | ||||
| //
 | ||||
| //   commander.init()
 | ||||
| //
 | ||||
| //   return {
 | ||||
| //     undo: () => commander.state.commands.undo(),
 | ||||
| //     redo: () => commander.state.commands.redo(),
 | ||||
| //     delete: () => commander.state.commands.delete(),
 | ||||
| //     clear: () => commander.state.commands.clear(),
 | ||||
| //     placeTop: () => commander.state.commands.placeTop(),
 | ||||
| //     placeBottom: () => commander.state.commands.placeBottom(),
 | ||||
| //     updateBlock: (newBlock: VisualEditorBlockData, oldBlock: VisualEditorBlockData) =>
 | ||||
| //       commander.state.commands.updateBlock(newBlock, oldBlock),
 | ||||
| //     updateModelValue: (val: VisualEditorModelValue) =>
 | ||||
| //       commander.state.commands.updateModelValue(val)
 | ||||
| //   }
 | ||||
| // }
 | ||||
|  | ||||
					Loading…
					
					
				
		Reference in new issue