Browse Source

feat: 调试本地everrightForm

luoyali 1 year ago
parent
commit
f76c4161d9

+ 3 - 0
.gitignore

@@ -29,3 +29,6 @@ tests/**/coverage/
 *.njsproj
 *.sln
 *.sw?
+
+
+

+ 36 - 4
package.json

@@ -13,8 +13,8 @@
     "build:test": "vite build --mode test",
     "build:pre": "vite build --mode staging",
     "preview": "vite preview",
-    "dev:ckeditor5": "pnpm -C src/components/external/ckeditor5 dev",
-    "build:ckeditor5": "pnpm -C src/components/external/ckeditor5 build",
+    "dev:ckeditor5": "pnpm -C ./src/components/external/ckeditor5 dev",
+    "build:ckeditor5": "pnpm -C ./src/components/external/ckeditor5 build",
     "lint:eslint": "eslint --fix --ext .js,.ts, .tsx,.vue ./src",
     "lint:prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
     "lint:lint-staged": "lint-staged"
@@ -45,7 +45,21 @@
     "vue-ls": "^4.2.0",
     "vue-router": "^4.2.1",
     "vuedraggable": "^4.1.0",
-    "webpack": "^5.91.0"
+    "webpack": "^5.91.0",
+		"@vant/area-data": "^1.4.0",
+		"@vant/touch-emulator": "^1.4.0",
+		"@vuelidate/core": "^2.0.0",
+		"@vuelidate/validators": "^2.0.0",
+		"async": "^3.2.4",
+		"canvas": "^2.11.2",
+		"everright-filter": "^1.1.1",
+		"jss": "^10.9.2",
+		"jss-preset-default": "^10.9.2",
+		"nanoid": "^4.0.0",
+		"nzh": "^1.0.8",
+		"signature_pad": "^4.1.4",
+		"vant": "^4.0.8",
+		"vite-svg-loader": "^4.0.0"
   },
   "devDependencies": {
     "@types/js-md5": "^0.7.0",
@@ -74,7 +88,25 @@
     "vite-plugin-eslint": "^1.8.1",
     "vite-plugin-html": "^3.2.0",
     "vite-plugin-svg-icons": "^2.0.1",
-    "vue-tsc": "^1.6.5"
+    "vue-tsc": "^1.6.5",
+		"@babel/core": "^7.21.0",
+		"@babel/eslint-parser": "^7.19.1",
+		"@ckeditor/ckeditor5-alignment": "^35.4.0",
+		"@ckeditor/ckeditor5-build-classic": "^35.4.0",
+		"@ckeditor/ckeditor5-build-decoupled-document": "^35.4.0",
+		"@ckeditor/ckeditor5-build-inline": "^35.4.0",
+		"@ckeditor/ckeditor5-vue": "^4.0.1",
+		"@vue/compiler-sfc": "^3.2.47",
+		"@vue/test-utils": "^2.3.2",
+		"better-sqlite3": "^8.2.0",
+		"connect-multiparty": "^2.2.0",
+		"conventional-changelog-cli": "^4.1.0",
+		"eslint-config-standard": "^17.0.0",
+		"eslint-plugin-import": "^2.27.5",
+		"eslint-plugin-n": "^15.6.1",
+		"eslint-plugin-promise": "^6.1.1",
+		"jsdom": "^22.0.0",
+		"resize-observer-polyfill": "^1.5.1"
   },
   "engines": {
     "node": ">=16.0.0"

+ 184 - 180
src/components/packages/ckeditor/__index.jsx

@@ -4,7 +4,7 @@
  */
 
 /* global window, console */
-import CKEDITOR from '/external/ckeditor5/build/ckeditor.js'
+import CKEDITOR from '@/components/external/ckeditor5/build/ckeditor.js'
 import { h, markRaw, defineComponent } from 'vue'
 import { debounce } from 'lodash-es'
 
@@ -12,183 +12,187 @@ const SAMPLE_READ_ONLY_LOCK_ID = 'Integration Sample'
 const INPUT_EVENT_DEBOUNCE_WAIT = 300
 
 export default defineComponent({
-  name: 'ckeditor',
-
-  created () {
-    const { CKEDITOR_VERSION } = window
-
-    // Starting from v34.0.0, CKEditor 5 introduces a lock mechanism enabling/disabling the read-only mode.
-    // As it is a breaking change between major releases of the integration, the component requires using
-    // CKEditor 5 in version 34 or higher.
-    if (CKEDITOR_VERSION) {
-      const [major] = CKEDITOR_VERSION.split('.').map(Number)
-
-      if (major < 34) {
-        console.warn('The <CKEditor> component requires using CKEditor 5 in version 34 or higher.')
-      }
-    } else {
-      console.warn('Cannot find the "CKEDITOR_VERSION" in the "window" scope.')
-    }
-  },
-
-  render () {
-    return h(this.tagName)
-  },
-
-  model: {
-    prop: 'modelValue',
-    event: 'update:modelValue'
-  },
-
-  props: {
-    modelValue: {
-      type: String,
-      default: ''
-    },
-    config: {
-      type: Object,
-      default: () => ({})
-    },
-    tagName: {
-      type: String,
-      default: 'div'
-    },
-    disabled: {
-      type: Boolean,
-      default: false
-    }
-  },
-
-  data () {
-    return {
-      // Don't define it in #props because it produces a warning.
-      // https://v3.vuejs.org/guide/component-props.html#one-way-data-flow
-      instance: null,
-
-      lastEditorData: {
-        type: String,
-        default: ''
-      }
-    }
-  },
-
-  mounted () {
-    // Clone the config first so it never gets mutated (across multiple editor instances).
-    // https://github.com/ckeditor/ckeditor5-vue/issues/101
-    const editorConfig = Object.assign({}, this.config)
-
-    if (this.modelValue) {
-      editorConfig.initialData = this.modelValue
-    }
-
-    CKEDITOR.ClassicEditor.create(this.$el, editorConfig)
-      .then(editor => {
-        // Save the reference to the instance for further use.
-        this.instance = markRaw(editor)
-
-        this.setUpEditorEvents()
-
-        // Synchronize the editor content. The #modelValue may change while the editor is being created, so the editor content has
-        // to be synchronized with these potential changes as soon as it is ready.
-        if (this.modelValue !== editorConfig.initialData) {
-          editor.setData(this.modelValue)
-        }
-
-        // Set initial disabled state.
-        if (this.disabled) {
-          editor.enableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
-        }
-
-        // Let the world know the editor is ready.
-        this.$emit('ready', editor)
-      })
-      .catch(error => {
-        console.error(error)
-      })
-  },
-
-  beforeUnmount () {
-    if (this.instance) {
-      this.instance.destroy()
-      this.instance = null
-    }
-
-    // Note: By the time the editor is destroyed (promise resolved, editor#destroy fired)
-    // the Vue component will not be able to emit any longer. So emitting #destroy a bit earlier.
-    this.$emit('destroy', this.instance)
-  },
-
-  watch: {
-    modelValue (value) {
-      // Synchronize changes of #modelValue. There are two sources of changes:
-      //
-      //                External modelValue change      ──────╮
-      //                                                      ╰─────> ┏━━━━━━━━━━━┓
-      //                                                              ┃ Component ┃
-      //                                                      ╭─────> ┗━━━━━━━━━━━┛
-      //                   Internal data change         ──────╯
-      //             (typing, commands, collaboration)
-      //
-      // Case 1: If the change was external (via props), the editor data must be synced with
-      // the component using instance#setData() and it is OK to destroy the selection.
-      //
-      // Case 2: If the change is the result of internal data change, the #modelValue is the
-      // same as this.lastEditorData, which has been cached on #change:data. If we called
-      // instance#setData() at this point, that would demolish the selection.
-      //
-      // To limit the number of instance#setData() which is time-consuming when there is a
-      // lot of data we make sure:
-      //    * the new modelValue is at least different than the old modelValue (Case 1.)
-      //    * the new modelValue is different than the last internal instance state (Case 2.)
-      //
-      // See: https://github.com/ckeditor/ckeditor5-vue/issues/42.
-      if (this.instance && value !== this.lastEditorData) {
-        this.instance.setData(value)
-      }
-    },
-
-    // Synchronize changes of #disabled.
-    disabled (readOnlyMode) {
-      if (readOnlyMode) {
-        this.instance.enableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
-      } else {
-        this.instance.disableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
-      }
-    }
-  },
-
-  methods: {
-    setUpEditorEvents () {
-      const editor = this.instance
-
-      // Use the leading edge so the first event in the series is emitted immediately.
-      // Failing to do so leads to race conditions, for instance, when the component modelValue
-      // is set twice in a time span shorter than the debounce time.
-      // See https://github.com/ckeditor/ckeditor5-vue/issues/149.
-      const emitDebouncedInputEvent = debounce(evt => {
-        // Cache the last editor data. This kind of data is a result of typing,
-        // editor command execution, collaborative changes to the document, etc.
-        // This data is compared when the component modelValue changes in a 2-way binding.
-        const data = this.lastEditorData = editor.getData()
-
-        // The compatibility with the v-model and general Vue.js concept of input–like components.
-        this.$emit('update:modelValue', data, evt, editor)
-        this.$emit('input', data, evt, editor)
-      }, INPUT_EVENT_DEBOUNCE_WAIT, { leading: true })
-
-      // Debounce emitting the #input event. When data is huge, instance#getData()
-      // takes a lot of time to execute on every single key press and ruins the UX.
-      //
-      // See: https://github.com/ckeditor/ckeditor5-vue/issues/42
-      editor.model.document.on('change:data', emitDebouncedInputEvent)
-
-      editor.editing.view.document.on('focus', evt => {
-        this.$emit('focus', evt, editor)
-      })
-
-      editor.editing.view.document.on('blur', evt => {
-        this.$emit('blur', evt, editor)
-      })
-    }
-  }
+	name: 'Ckeditor',
+
+	model: {
+		prop: 'modelValue',
+		event: 'update:modelValue'
+	},
+
+	props: {
+		modelValue: {
+			type: String,
+			default: ''
+		},
+		config: {
+			type: Object,
+			default: () => ({})
+		},
+		tagName: {
+			type: String,
+			default: 'div'
+		},
+		disabled: {
+			type: Boolean,
+			default: false
+		}
+	},
+
+	data() {
+		return {
+			// Don't define it in #props because it produces a warning.
+			// https://v3.vuejs.org/guide/component-props.html#one-way-data-flow
+			instance: null,
+
+			lastEditorData: {
+				type: String,
+				default: ''
+			}
+		}
+	},
+
+	watch: {
+		modelValue(value) {
+			// Synchronize changes of #modelValue. There are two sources of changes:
+			//
+			//                External modelValue change      ──────╮
+			//                                                      ╰─────> ┏━━━━━━━━━━━┓
+			//                                                              ┃ Component ┃
+			//                                                      ╭─────> ┗━━━━━━━━━━━┛
+			//                   Internal data change         ──────╯
+			//             (typing, commands, collaboration)
+			//
+			// Case 1: If the change was external (via props), the editor data must be synced with
+			// the component using instance#setData() and it is OK to destroy the selection.
+			//
+			// Case 2: If the change is the result of internal data change, the #modelValue is the
+			// same as this.lastEditorData, which has been cached on #change:data. If we called
+			// instance#setData() at this point, that would demolish the selection.
+			//
+			// To limit the number of instance#setData() which is time-consuming when there is a
+			// lot of data we make sure:
+			//    * the new modelValue is at least different than the old modelValue (Case 1.)
+			//    * the new modelValue is different than the last internal instance state (Case 2.)
+			//
+			// See: https://github.com/ckeditor/ckeditor5-vue/issues/42.
+			if (this.instance && value !== this.lastEditorData) {
+				this.instance.setData(value)
+			}
+		},
+
+		// Synchronize changes of #disabled.
+		disabled(readOnlyMode) {
+			if (readOnlyMode) {
+				this.instance.enableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
+			} else {
+				this.instance.disableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
+			}
+		}
+	},
+
+	created() {
+		const { CKEDITOR_VERSION } = window
+
+		// Starting from v34.0.0, CKEditor 5 introduces a lock mechanism enabling/disabling the read-only mode.
+		// As it is a breaking change between major releases of the integration, the component requires using
+		// CKEditor 5 in version 34 or higher.
+		if (CKEDITOR_VERSION) {
+			const [major] = CKEDITOR_VERSION.split('.').map(Number)
+
+			if (major < 34) {
+				console.warn('The <CKEditor> component requires using CKEditor 5 in version 34 or higher.')
+			}
+		} else {
+			console.warn('Cannot find the "CKEDITOR_VERSION" in the "window" scope.')
+		}
+	},
+
+	mounted() {
+		// Clone the config first so it never gets mutated (across multiple editor instances).
+		// https://github.com/ckeditor/ckeditor5-vue/issues/101
+		const editorConfig = Object.assign({}, this.config)
+
+		if (this.modelValue) {
+			editorConfig.initialData = this.modelValue
+		}
+
+		CKEDITOR.ClassicEditor.create(this.$el, editorConfig)
+			.then(editor => {
+				// Save the reference to the instance for further use.
+				this.instance = markRaw(editor)
+
+				this.setUpEditorEvents()
+
+				// Synchronize the editor content. The #modelValue may change while the editor is being created, so the editor content has
+				// to be synchronized with these potential changes as soon as it is ready.
+				if (this.modelValue !== editorConfig.initialData) {
+					editor.setData(this.modelValue)
+				}
+
+				// Set initial disabled state.
+				if (this.disabled) {
+					editor.enableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
+				}
+
+				// Let the world know the editor is ready.
+				this.$emit('ready', editor)
+			})
+			.catch(error => {
+				console.error(error)
+			})
+	},
+
+	beforeUnmount() {
+		if (this.instance) {
+			this.instance.destroy()
+			this.instance = null
+		}
+
+		// Note: By the time the editor is destroyed (promise resolved, editor#destroy fired)
+		// the Vue component will not be able to emit any longer. So emitting #destroy a bit earlier.
+		this.$emit('destroy', this.instance)
+	},
+
+	methods: {
+		setUpEditorEvents() {
+			const editor = this.instance
+
+			// Use the leading edge so the first event in the series is emitted immediately.
+			// Failing to do so leads to race conditions, for instance, when the component modelValue
+			// is set twice in a time span shorter than the debounce time.
+			// See https://github.com/ckeditor/ckeditor5-vue/issues/149.
+			const emitDebouncedInputEvent = debounce(
+				evt => {
+					// Cache the last editor data. This kind of data is a result of typing,
+					// editor command execution, collaborative changes to the document, etc.
+					// This data is compared when the component modelValue changes in a 2-way binding.
+					const data = (this.lastEditorData = editor.getData())
+
+					// The compatibility with the v-model and general Vue.js concept of input–like components.
+					this.$emit('update:modelValue', data, evt, editor)
+					this.$emit('input', data, evt, editor)
+				},
+				INPUT_EVENT_DEBOUNCE_WAIT,
+				{ leading: true }
+			)
+
+			// Debounce emitting the #input event. When data is huge, instance#getData()
+			// takes a lot of time to execute on every single key press and ruins the UX.
+			//
+			// See: https://github.com/ckeditor/ckeditor5-vue/issues/42
+			editor.model.document.on('change:data', emitDebouncedInputEvent)
+
+			editor.editing.view.document.on('focus', evt => {
+				this.$emit('focus', evt, editor)
+			})
+
+			editor.editing.view.document.on('blur', evt => {
+				this.$emit('blur', evt, editor)
+			})
+		}
+	},
+
+	render() {
+		return h(this.tagName)
+	}
 })

+ 225 - 210
src/components/packages/ckeditor/index.jsx

@@ -5,7 +5,7 @@
 
 /* global window, console */
 import { ElMessage } from 'element-plus'
-import CKEDITOR from '/external/ckeditor5/build/ckeditor.js'
+import CKEDITOR from '@/components/external/ckeditor5/build/ckeditor.js'
 import { h, markRaw, defineComponent, onMounted, defineEmits, ref, onBeforeUnmount, watch } from 'vue'
 import { debounce } from 'lodash-es'
 import './style/index.js'
@@ -15,223 +15,238 @@ const INPUT_EVENT_DEBOUNCE_WAIT = 300
 const ns = hooks.useNamespace('Main', 'ckeditor')
 
 class MyUploadAdapter {
-  constructor (editor, loader) {
-    this.loader = loader
-    this.editor = editor
-  }
+	constructor(editor, loader) {
+		this.loader = loader
+		this.editor = editor
+	}
 
-  upload () {
-    const editor = this.editor
-    return this.loader.file
-      .then(file => new Promise((resolve, reject) => {
-        // console.log(editor)
-        const {
-          action,
-          maxSize
-        } = editor.config.get('ER.params')
-        if (file.size > maxSize) {
-          ElMessage({
-            message: `文件大小不能超过 ${maxSize / 1024 / 1024} MB`,
-            type: 'warning'
-          })
-          reject()
-        } else {
-          this._initRequest(action)
-          this._initListeners(resolve, reject, file)
-          this._sendRequest(file)
-        }
-      }))
-  }
+	upload() {
+		const editor = this.editor
+		return this.loader.file.then(
+			file =>
+				new Promise((resolve, reject) => {
+					// console.log(editor)
+					const { action, maxSize } = editor.config.get('ER.params')
+					if (file.size > maxSize) {
+						ElMessage({
+							message: `文件大小不能超过 ${maxSize / 1024 / 1024} MB`,
+							type: 'warning'
+						})
+						reject()
+					} else {
+						this._initRequest(action)
+						this._initListeners(resolve, reject, file)
+						this._sendRequest(file)
+					}
+				})
+		)
+	}
 
-  abort () {
-    if (this.xhr) {
-      this.xhr.abort()
-    }
-  }
+	abort() {
+		if (this.xhr) {
+			this.xhr.abort()
+		}
+	}
 
-  _initRequest (action) {
-    const xhr = this.xhr = new XMLHttpRequest()
-    xhr.open('POST', action, true)
-    xhr.responseType = 'json'
-  }
+	_initRequest(action) {
+		const xhr = (this.xhr = new XMLHttpRequest())
+		xhr.open('POST', action, true)
+		xhr.responseType = 'json'
+	}
 
-  _initListeners (resolve, reject, file) {
-    const xhr = this.xhr
-    const loader = this.loader
-    const genericErrorText = `Couldn't upload file: ${file.name}.`
-    xhr.addEventListener('error', () => reject(genericErrorText))
-    xhr.addEventListener('abort', () => reject())
-    xhr.addEventListener('load', () => {
-      const response = xhr.response
-      if (!response || response.error) {
-        return reject(response && response.error ? response.error.message : genericErrorText)
-      }
-      resolve({
-        default: response.data[0].url
-      })
-    })
-    if (xhr.upload) {
-      xhr.upload.addEventListener('progress', evt => {
-        if (evt.lengthComputable) {
-          loader.uploadTotal = evt.total
-          loader.uploaded = evt.loaded
-        }
-      })
-    }
-  }
+	_initListeners(resolve, reject, file) {
+		const xhr = this.xhr
+		const loader = this.loader
+		const genericErrorText = `Couldn't upload file: ${file.name}.`
+		xhr.addEventListener('error', () => reject(genericErrorText))
+		xhr.addEventListener('abort', () => reject())
+		xhr.addEventListener('load', () => {
+			const response = xhr.response
+			if (!response || response.error) {
+				return reject(response && response.error ? response.error.message : genericErrorText)
+			}
+			resolve({
+				default: response.data[0].url
+			})
+		})
+		if (xhr.upload) {
+			xhr.upload.addEventListener('progress', evt => {
+				if (evt.lengthComputable) {
+					loader.uploadTotal = evt.total
+					loader.uploaded = evt.loaded
+				}
+			})
+		}
+	}
 
-  _sendRequest (file) {
-    // Prepare the form data.
-    const data = new FormData()
+	_sendRequest(file) {
+		// Prepare the form data.
+		const data = new FormData()
 
-    data.append('file', file)
-    this.xhr.send(data)
-  }
+		data.append('file', file)
+		this.xhr.send(data)
+	}
 }
-function MyCustomUploadAdapterPlugin (editor) {
-  editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
-    // Configure the URL to the upload script in your back-end here!
-    return new MyUploadAdapter(editor, loader)
-  }
+function MyCustomUploadAdapterPlugin(editor) {
+	editor.plugins.get('FileRepository').createUploadAdapter = loader => {
+		// Configure the URL to the upload script in your back-end here!
+		return new MyUploadAdapter(editor, loader)
+	}
 }
 export default defineComponent({
-  name: 'ckeditor',
-  inheritAttrs: false,
-  customOptions: {},
-  props: {
-    platform: {
-      type: String,
-      default: 'pc'
-    },
-    modelValue: {
-      type: String,
-      default: ''
-    },
-    config: {
-      type: Object,
-      default: () => ({})
-    },
-    disabled: {
-      type: Boolean,
-      default: false
-    },
-    action: {
-      type: String,
-      required: true
-    },
-    maxSize: {
-      type: [Number, String],
-      required: true
-    }
-  },
-  setup (props, { emit }) {
-    const { CKEDITOR_VERSION } = window
-    if (CKEDITOR_VERSION) {
-      const [major] = CKEDITOR_VERSION.split('.').map(Number)
+	name: 'Ckeditor',
+	inheritAttrs: false,
+	customOptions: {},
+	props: {
+		platform: {
+			type: String,
+			default: 'pc'
+		},
+		modelValue: {
+			type: String,
+			default: ''
+		},
+		config: {
+			type: Object,
+			default: () => ({})
+		},
+		disabled: {
+			type: Boolean,
+			default: false
+		},
+		action: {
+			type: String,
+			required: true
+		},
+		maxSize: {
+			type: [Number, String],
+			required: true
+		}
+	},
+	setup(props, { emit }) {
+		const { CKEDITOR_VERSION } = window
+		if (CKEDITOR_VERSION) {
+			const [major] = CKEDITOR_VERSION.split('.').map(Number)
 
-      if (major < 34) {
-        console.warn('The <CKEditor> component requires using CKEditor 5 in version 34 or higher.')
-      }
-    } else {
-      console.warn('Cannot find the "CKEDITOR_VERSION" in the "window" scope.')
-    }
-    let instance = null
-    let lastEditorData = {
-      type: String,
-      default: ''
-    }
-    const element = ref('')
-    const toolbar = ref('')
-    const container = ref('')
-    const setUpEditorEvents = () => {
-      const editor = instance
-      const emitDebouncedInputEvent = debounce(evt => {
-        const data = lastEditorData = editor.getData()
-        emit('update:modelValue', data, evt, editor)
-        emit('input', data, evt, editor)
-      }, INPUT_EVENT_DEBOUNCE_WAIT, { leading: true })
-      editor.model.document.on('change:data', emitDebouncedInputEvent)
-      editor.editing.view.document.on('focus', evt => {
-        emit('focus', evt, editor)
-      })
-      editor.editing.view.document.on('blur', evt => {
-        emit('blur', evt, editor)
-      })
-    }
-    watch(() => props.modelValue, (value) => {
-      if (instance && value !== lastEditorData) {
-        instance.setData(value)
-      }
-    })
-    watch(() => props.disabled, (readOnlyMode) => {
-      if (readOnlyMode) {
-        instance.enableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
-      } else {
-        instance.disableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
-      }
-    })
-    watch(() => props.config.placeholder, (newVal) => {
-      if (instance) {
-        instance.sourceElement.querySelector('.ck-placeholder').dataset.placeholder = newVal
-      }
-    })
-    onBeforeUnmount(() => {
-      if (instance) {
-        instance.destroy()
-        instance = null
-      }
-      emit('destroy', instance)
-    })
-    onMounted(() => {
-      const editorConfig = Object.assign({
-        list: {
-          properties: {
-            styles: true,
-            startIndex: true,
-            reversed: true
-          }
-        },
-        ER: {
-          params: {
-            action: props.action,
-            maxSize: props.maxSize
-          }
-        },
-        extraPlugins: [MyCustomUploadAdapterPlugin]
-      }, props.config)
-      if (props.modelValue) {
-        editorConfig.initialData = props.modelValue
-      }
-      if (props.platform === 'mobile') {
-        // console.log(CKEDITOR)
-        editorConfig.extraPlugins.push(CKEDITOR.plugins.FormattingOptions)
-      }
-      CKEDITOR.DecoupledEditor.create(element.value, editorConfig)
-        .then(editor => {
-          toolbar.value.appendChild(editor.ui.view.toolbar.element)
-          container.value.appendChild(editor.ui.view.editable.element)
-          instance = markRaw(editor)
-          setUpEditorEvents()
-          if (props.modelValue !== editorConfig.initialData) {
-            editor.setData(props.modelValue)
-          }
-          if (props.disabled) {
-            editor.enableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
-          }
-          emit('ready', editor)
-        })
-        .catch(error => {
-          console.error(error)
-        })
-    })
-    return () => {
-      return (
-        <div class={[ns.b(), props.platform === 'mobile' && ns.e('mobile'), 'formatted']}>
-          <div class={[ns.e('toolbar')]} ref={toolbar}></div>
-          <div class={[ns.e('container')]} ref={container}></div>
-          <div ref={element}></div>
-        </div>
-      )
-    }
-  }
+			if (major < 34) {
+				console.warn('The <CKEditor> component requires using CKEditor 5 in version 34 or higher.')
+			}
+		} else {
+			console.warn('Cannot find the "CKEDITOR_VERSION" in the "window" scope.')
+		}
+		let instance = null
+		let lastEditorData = {
+			type: String,
+			default: ''
+		}
+		const element = ref('')
+		const toolbar = ref('')
+		const container = ref('')
+		const setUpEditorEvents = () => {
+			const editor = instance
+			const emitDebouncedInputEvent = debounce(
+				evt => {
+					const data = (lastEditorData = editor.getData())
+					emit('update:modelValue', data, evt, editor)
+					emit('input', data, evt, editor)
+				},
+				INPUT_EVENT_DEBOUNCE_WAIT,
+				{ leading: true }
+			)
+			editor.model.document.on('change:data', emitDebouncedInputEvent)
+			editor.editing.view.document.on('focus', evt => {
+				emit('focus', evt, editor)
+			})
+			editor.editing.view.document.on('blur', evt => {
+				emit('blur', evt, editor)
+			})
+		}
+		watch(
+			() => props.modelValue,
+			value => {
+				if (instance && value !== lastEditorData) {
+					instance.setData(value)
+				}
+			}
+		)
+		watch(
+			() => props.disabled,
+			readOnlyMode => {
+				if (readOnlyMode) {
+					instance.enableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
+				} else {
+					instance.disableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
+				}
+			}
+		)
+		watch(
+			() => props.config.placeholder,
+			newVal => {
+				if (instance) {
+					instance.sourceElement.querySelector('.ck-placeholder').dataset.placeholder = newVal
+				}
+			}
+		)
+		onBeforeUnmount(() => {
+			if (instance) {
+				instance.destroy()
+				instance = null
+			}
+			emit('destroy', instance)
+		})
+		onMounted(() => {
+			const editorConfig = Object.assign(
+				{
+					list: {
+						properties: {
+							styles: true,
+							startIndex: true,
+							reversed: true
+						}
+					},
+					ER: {
+						params: {
+							action: props.action,
+							maxSize: props.maxSize
+						}
+					},
+					extraPlugins: [MyCustomUploadAdapterPlugin]
+				},
+				props.config
+			)
+			if (props.modelValue) {
+				editorConfig.initialData = props.modelValue
+			}
+			if (props.platform === 'mobile') {
+				// console.log(CKEDITOR)
+				editorConfig.extraPlugins.push(CKEDITOR.plugins.FormattingOptions)
+			}
+			CKEDITOR.DecoupledEditor.create(element.value, editorConfig)
+				.then(editor => {
+					toolbar.value.appendChild(editor.ui.view.toolbar.element)
+					container.value.appendChild(editor.ui.view.editable.element)
+					instance = markRaw(editor)
+					setUpEditorEvents()
+					if (props.modelValue !== editorConfig.initialData) {
+						editor.setData(props.modelValue)
+					}
+					if (props.disabled) {
+						editor.enableReadOnlyMode(SAMPLE_READ_ONLY_LOCK_ID)
+					}
+					emit('ready', editor)
+				})
+				.catch(error => {
+					console.error(error)
+				})
+		})
+		return () => {
+			return (
+				<div class={[ns.b(), props.platform === 'mobile' && ns.e('mobile'), 'formatted']}>
+					<div class={[ns.e('toolbar')]} ref={toolbar}></div>
+					<div class={[ns.e('container')]} ref={container}></div>
+					<div ref={element}></div>
+				</div>
+			)
+		}
+	}
 })

+ 44 - 0
src/styles/variables.scss

@@ -52,3 +52,47 @@ $le-hover-color_2: #f0f7ff;
 //$le-bg-color-gray: $le-bg-color_1;
 
 //$le-link-background-gray: $le-color-primary;
+
+$primary-color: #4285f4;
+$secondary-color: #e6a23c;
+$disabled-color: #a8abb2;
+$element-separator: '__' !default;
+$state-prefix: 'is-' !default;
+$modifier-separator: '--' !default;
+$namespace: 'ER';
+@mixin b($block) {
+	$B: $namespace + '-' + $block !global;
+	.#{$B} {
+		@content;
+	}
+}
+@mixin e($element) {
+	$E: $element !global;
+	$selector: &;
+	$currentSelector: '';
+	@each $unit in $element {
+		$currentSelector: #{$currentSelector +
+      '.' +
+      $B +
+      $element-separator +
+      $unit +
+      ','};
+	}
+	@at-root {
+		#{$currentSelector} {
+			@content;
+		}
+	}
+}
+@mixin when($state) {
+	@at-root {
+		&.#{$state-prefix + $state} {
+			@content;
+		}
+	}
+}
+@mixin theme($theme: DarkGray) {
+	background: $theme;
+	box-shadow: 0 0 1px rgba($theme, .25);
+	color: #fff;
+}

+ 2 - 1
src/views/flow/create/components/FormDesign.vue

@@ -1,6 +1,7 @@
 <script setup name="FormDesign">
 import { onBeforeUnmount, onMounted, ref } from 'vue'
-import { erFormEditor } from 'everright-formeditor'
+// import { erFormEditor } from 'everright-formeditor'
+import { erFormEditor } from '@ER/formEditor'
 import 'Everright-formEditor/dist/style.css'
 import useFlowStore from '@/store/modules/flow'
 import { storeToRefs } from 'pinia'

+ 71 - 0
src/views/flow/create/components/FormDesign1.vue

@@ -0,0 +1,71 @@
+<script setup name="FormDesign">
+import { onBeforeUnmount, onMounted, ref } from 'vue'
+import { erFormEditor } from 'everright-formeditor'
+import 'Everright-formEditor/dist/style.css'
+import useFlowStore from '@/store/modules/flow'
+import { storeToRefs } from 'pinia'
+const flowStore = useFlowStore()
+const { processForm } = storeToRefs(flowStore)
+const { VITE_APP_BASE_API } = import.meta.env
+const EReditorRef = ref()
+const uploadFileApi = ref(`${VITE_APP_BASE_API}/v1/oss/upload`)
+
+const handleListener = obj => {}
+
+// 保存当前的表单数据 processForm.value = '{formStructure: 表单结构值, formData: {}}
+const exportJsonEv = () => {
+	const formStructure = EReditorRef.value.getData()
+	const finallyForm = { formStructure, formData: {} }
+	processForm.value = JSON.stringify(finallyForm)
+}
+
+const validate = () => {
+	// 根据后续的业务需求 调整 validate 的功能
+	exportJsonEv()
+	return new Promise((resolve, reject) => {
+		const formStructure = EReditorRef.value.getData()
+		const fields = formStructure?.fields || []
+		const bool = fields.length
+		if (bool) {
+			resolve(true)
+		} else {
+			reject(false)
+		}
+	})
+}
+
+// onBeforeUnmount(() => {
+// 	const formData = EReditorRef.value.getData()
+// 	if (formData.hasOwnProperty('fields')) {
+// 		// 离开前 做处理
+// 		// const { fields } = formData
+// 		// console.log(fields.length, '=======')
+// 	} else {
+// 		ElMessage.error(`表单设计有误,请重新配置`)
+// 	}
+// })
+
+const updateCompInfo = () => {
+	if (processForm.value) {
+		// {formStructure: 表单结构值, formData: {}}
+		const { formStructure } = JSON.parse(processForm.value)
+		EReditorRef.value.setData(formStructure || {})
+	}
+}
+
+// 初始化的时候,渲染当前组件的值
+onMounted(() => {
+	updateCompInfo()
+})
+
+defineExpose({
+	exportJsonEv,
+	validate,
+	updateCompInfo
+})
+</script>
+<template>
+	<div class="form-design-wrap">
+		<er-form-editor ref="EReditorRef" :is-show-i18n="false" :fileUploadURI="uploadFileApi" @listener="handleListener" />
+	</div>
+</template>

+ 0 - 1
src/views/setting/dict/index.vue

@@ -107,7 +107,6 @@ import { ElMessage, ElTree, ElMessageBox } from 'element-plus'
 import { useTablePage } from '@/hooks/useTablePage'
 import { Plus, Delete, Edit } from '@element-plus/icons-vue'
 import StatusIndicator from '@/components/StatusIndicator'
-import tree from '@/config/rule/tree.ts'
 
 const visible = ref(false) // 弹窗显示隐藏
 const isCreate = ref(true)

+ 2 - 0
vite.config.ts

@@ -1,6 +1,7 @@
 import { defineConfig, loadEnv, ConfigEnv, UserConfig } from 'vite'
 import vue from '@vitejs/plugin-vue'
 import vueJsx from '@vitejs/plugin-vue-jsx'
+import svgLoader from 'vite-svg-loader'
 // import eslintPlugin from 'vite-plugin-eslint'
 import { createHtmlPlugin } from 'vite-plugin-html'
 import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
@@ -80,6 +81,7 @@ export default defineConfig(({ mode /*command,*/ }: ConfigEnv): UserConfig => {
 					data: { title: viteEnv.VITE_APP_TITLE }
 				}
 			}),
+			svgLoader(),
 			// 使用 svg 图标
 			createSvgIconsPlugin({
 				// 指定需要缓存的图标文件夹