Pārlūkot izejas kodu

Merge branch 'master_mergeErForm'

luoyali 1 gadu atpakaļ
vecāks
revīzija
911193f225
100 mainītis faili ar 1338 papildinājumiem un 2093 dzēšanām
  1. 7 0
      .gitignore
  2. 41 10
      package.json
  3. 0 0
      src/assets/icons/status/flw01.svg
  4. 0 0
      src/assets/icons/status/flw02.svg
  5. 0 0
      src/assets/icons/status/flw03.svg
  6. 0 0
      src/assets/icons/status/flw04.svg
  7. 0 0
      src/assets/icons/status/flw05.svg
  8. 0 0
      src/assets/icons/status/flw06.svg
  9. 6 6
      src/components/Flow/FlowStatusStamp.vue
  10. 0 34
      src/components/FormCreateDesigner/DragBox.vue
  11. 0 136
      src/components/FormCreateDesigner/DragTool.vue
  12. 0 1216
      src/components/FormCreateDesigner/FcDesigner.vue
  13. 0 170
      src/components/FormCreateDesigner/Fetch.vue
  14. 0 16
      src/components/FormCreateDesigner/IconRefresh.vue
  15. 0 67
      src/components/FormCreateDesigner/Required.vue
  16. 0 124
      src/components/FormCreateDesigner/Struct.vue
  17. 0 78
      src/components/FormCreateDesigner/TableOptions.vue
  18. 0 236
      src/components/FormCreateDesigner/Validate.vue
  19. 14 0
      src/components/external/ckeditor5/.eslintrc.js
  20. 101 0
      src/components/external/ckeditor5/___webpack.config.js
  21. 0 0
      src/components/external/ckeditor5/build/ckeditor.js
  22. 1 0
      src/components/external/ckeditor5/build/translations/af.js
  23. 0 0
      src/components/external/ckeditor5/build/translations/ar.js
  24. 0 0
      src/components/external/ckeditor5/build/translations/ast.js
  25. 0 0
      src/components/external/ckeditor5/build/translations/az.js
  26. 0 0
      src/components/external/ckeditor5/build/translations/bg.js
  27. 0 0
      src/components/external/ckeditor5/build/translations/bn.js
  28. 1 0
      src/components/external/ckeditor5/build/translations/bs.js
  29. 0 0
      src/components/external/ckeditor5/build/translations/ca.js
  30. 0 0
      src/components/external/ckeditor5/build/translations/cs.js
  31. 0 0
      src/components/external/ckeditor5/build/translations/da.js
  32. 0 0
      src/components/external/ckeditor5/build/translations/de-ch.js
  33. 0 0
      src/components/external/ckeditor5/build/translations/de.js
  34. 0 0
      src/components/external/ckeditor5/build/translations/el.js
  35. 0 0
      src/components/external/ckeditor5/build/translations/en-au.js
  36. 0 0
      src/components/external/ckeditor5/build/translations/en-gb.js
  37. 0 0
      src/components/external/ckeditor5/build/translations/eo.js
  38. 1 0
      src/components/external/ckeditor5/build/translations/es-co.js
  39. 0 0
      src/components/external/ckeditor5/build/translations/es.js
  40. 0 0
      src/components/external/ckeditor5/build/translations/et.js
  41. 0 0
      src/components/external/ckeditor5/build/translations/eu.js
  42. 0 0
      src/components/external/ckeditor5/build/translations/fa.js
  43. 0 0
      src/components/external/ckeditor5/build/translations/fi.js
  44. 0 0
      src/components/external/ckeditor5/build/translations/fr.js
  45. 0 0
      src/components/external/ckeditor5/build/translations/gl.js
  46. 1 0
      src/components/external/ckeditor5/build/translations/gu.js
  47. 0 0
      src/components/external/ckeditor5/build/translations/he.js
  48. 0 0
      src/components/external/ckeditor5/build/translations/hi.js
  49. 0 0
      src/components/external/ckeditor5/build/translations/hr.js
  50. 0 0
      src/components/external/ckeditor5/build/translations/hu.js
  51. 0 0
      src/components/external/ckeditor5/build/translations/id.js
  52. 0 0
      src/components/external/ckeditor5/build/translations/it.js
  53. 0 0
      src/components/external/ckeditor5/build/translations/ja.js
  54. 0 0
      src/components/external/ckeditor5/build/translations/jv.js
  55. 1 0
      src/components/external/ckeditor5/build/translations/kk.js
  56. 0 0
      src/components/external/ckeditor5/build/translations/km.js
  57. 0 0
      src/components/external/ckeditor5/build/translations/kn.js
  58. 0 0
      src/components/external/ckeditor5/build/translations/ko.js
  59. 0 0
      src/components/external/ckeditor5/build/translations/ku.js
  60. 0 0
      src/components/external/ckeditor5/build/translations/lt.js
  61. 0 0
      src/components/external/ckeditor5/build/translations/lv.js
  62. 0 0
      src/components/external/ckeditor5/build/translations/ms.js
  63. 0 0
      src/components/external/ckeditor5/build/translations/nb.js
  64. 0 0
      src/components/external/ckeditor5/build/translations/ne.js
  65. 0 0
      src/components/external/ckeditor5/build/translations/nl.js
  66. 0 0
      src/components/external/ckeditor5/build/translations/no.js
  67. 1 0
      src/components/external/ckeditor5/build/translations/oc.js
  68. 0 0
      src/components/external/ckeditor5/build/translations/pl.js
  69. 0 0
      src/components/external/ckeditor5/build/translations/pt-br.js
  70. 0 0
      src/components/external/ckeditor5/build/translations/pt.js
  71. 0 0
      src/components/external/ckeditor5/build/translations/ro.js
  72. 0 0
      src/components/external/ckeditor5/build/translations/ru.js
  73. 1 0
      src/components/external/ckeditor5/build/translations/si.js
  74. 0 0
      src/components/external/ckeditor5/build/translations/sk.js
  75. 1 0
      src/components/external/ckeditor5/build/translations/sl.js
  76. 0 0
      src/components/external/ckeditor5/build/translations/sq.js
  77. 0 0
      src/components/external/ckeditor5/build/translations/sr-latn.js
  78. 0 0
      src/components/external/ckeditor5/build/translations/sr.js
  79. 0 0
      src/components/external/ckeditor5/build/translations/sv.js
  80. 0 0
      src/components/external/ckeditor5/build/translations/th.js
  81. 0 0
      src/components/external/ckeditor5/build/translations/tk.js
  82. 0 0
      src/components/external/ckeditor5/build/translations/tr.js
  83. 0 0
      src/components/external/ckeditor5/build/translations/tt.js
  84. 0 0
      src/components/external/ckeditor5/build/translations/ug.js
  85. 0 0
      src/components/external/ckeditor5/build/translations/uk.js
  86. 0 0
      src/components/external/ckeditor5/build/translations/ur.js
  87. 0 0
      src/components/external/ckeditor5/build/translations/uz.js
  88. 0 0
      src/components/external/ckeditor5/build/translations/vi.js
  89. 0 0
      src/components/external/ckeditor5/build/translations/zh-cn.js
  90. 0 0
      src/components/external/ckeditor5/build/translations/zh.js
  91. 86 0
      src/components/external/ckeditor5/package.json
  92. 73 0
      src/components/external/ckeditor5/sample/index.html
  93. 305 0
      src/components/external/ckeditor5/src/ckeditor.js
  94. 119 0
      src/components/external/ckeditor5/webpack.config.js
  95. 198 0
      src/components/packages/ckeditor/__index.jsx
  96. 252 0
      src/components/packages/ckeditor/index.jsx
  97. 2 0
      src/components/packages/ckeditor/style/index.js
  98. 50 0
      src/components/packages/formEditor/components/CompleteButton.vue
  99. 38 0
      src/components/packages/formEditor/components/DeviceSwitch.vue
  100. 38 0
      src/components/packages/formEditor/components/FormTypes/Cascader/mobile.vue

+ 7 - 0
.gitignore

@@ -29,3 +29,10 @@ tests/**/coverage/
 *.njsproj
 *.sln
 *.sw?
+
+# ckeditor
+components/external/ckeditor5/node_modules
+components/external/ckeditor5/build
+
+
+

+ 41 - 10
package.json

@@ -13,43 +13,63 @@
     "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",
     "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"
   },
   "dependencies": {
     "@element-plus/icons-vue": "^2.3.1",
-    "@form-create/component-wangeditor": "^3.1",
-    "@form-create/element-ui": "^3.1.16",
-    "@form-create/utils": "^3.1.15",
-    "@logicflow/core": "^1.2.26",
-    "@logicflow/extension": "^1.2.26",
+		"@logicflow/core": "^1.2.26",
+		"@logicflow/extension": "^1.2.26",
     "@popperjs/core": "^2.11.8",
+    "@vant/area-data": "^1.4.0",
+    "@vant/touch-emulator": "^1.4.0",
     "@vue/shared": "^3.4.21",
+    "@vuelidate/core": "^2.0.0",
+    "@vuelidate/validators": "^2.0.0",
     "@vueuse/core": "^10.1.2",
+    "async": "^3.2.4",
     "axios": "^1.4.0",
+    "canvas": "^2.11.2",
     "colord": "^2.9.3",
     "dayjs": "^1.11.7",
     "echarts": "^5.4.2",
     "element-plus": "^2.3.4",
-    "everright-formeditor": "^1.3.0-beta.2",
+    "everright-filter": "^1.1.1",
     "js-md5": "^0.7.3",
+    "jss": "^10.9.2",
+    "jss-preset-default": "^10.9.2",
     "lodash-es": "^4.17.21",
     "lodash-unified": "^1.0.3",
     "mitt": "^3.0.0",
+    "nanoid": "^4.0.0",
     "nprogress": "^0.2.0",
+    "nzh": "^1.0.8",
     "path-browserify": "^1.0.1",
     "path-to-regexp": "^6.2.0",
-    "pinia": "^2.1.3",
+    "pinia": "^2.1.7",
     "pinia-plugin-persistedstate": "^3.1.0",
-    "sortablejs": "^1.15.0",
-    "vue": "^3.2.47",
+		"sortablejs": "^1.15.0",
+    "signature_pad": "^4.1.4",
+    "vant": "^4.0.8",
+    "vite-svg-loader": "^4.0.0",
+    "vue": "^3.4.26",
     "vue-i18n": "^9.2.2",
     "vue-ls": "^4.2.0",
     "vue-router": "^4.2.1",
-    "vuedraggable": "^4.1.0"
+    "vuedraggable": "^4.1.0",
+    "webpack": "^5.91.0"
   },
   "devDependencies": {
+    "@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",
     "@types/js-md5": "^0.7.0",
     "@types/nprogress": "^0.2.0",
     "@types/path-browserify": "^1.0.0",
@@ -59,14 +79,25 @@
     "@typescript-eslint/parser": "^5.59.6",
     "@vitejs/plugin-vue": "^4.2.3",
     "@vitejs/plugin-vue-jsx": "^3.0.1",
+    "@vue/compiler-sfc": "^3.2.47",
+    "@vue/test-utils": "^2.3.2",
     "autoprefixer": "^10.4.16",
+    "better-sqlite3": "^8.2.0",
     "codemirror": "^5.60.0",
+    "connect-multiparty": "^2.2.0",
+    "conventional-changelog-cli": "^4.1.0",
     "eslint": "^8.40.0",
     "eslint-config-prettier": "^8.7.0",
+    "eslint-config-standard": "^17.0.0",
+    "eslint-plugin-import": "^2.27.5",
+    "eslint-plugin-n": "^15.6.1",
     "eslint-plugin-prettier": "^4.2.1",
+    "eslint-plugin-promise": "^6.1.1",
     "eslint-plugin-vue": "^9.9.0",
+    "jsdom": "^22.0.0",
     "postcss": "^8.4.30",
     "prettier": "^2.8.8",
+    "resize-observer-polyfill": "^1.5.1",
     "rollup-plugin-visualizer": "^5.9.0",
     "sass": "^1.62.1",
     "typescript": "^5.0.4",

+ 0 - 0
src/assets/images/flw01.svg → src/assets/icons/status/flw01.svg


+ 0 - 0
src/assets/images/flw02.svg → src/assets/icons/status/flw02.svg


+ 0 - 0
src/assets/images/flw03.svg → src/assets/icons/status/flw03.svg


+ 0 - 0
src/assets/images/flw04.svg → src/assets/icons/status/flw04.svg


+ 0 - 0
src/assets/images/flw05.svg → src/assets/icons/status/flw05.svg


+ 0 - 0
src/assets/images/flw06.svg → src/assets/icons/status/flw06.svg


+ 6 - 6
src/components/Flow/FlowStatusStamp.vue

@@ -1,11 +1,11 @@
 <template>
 	<div class="flow-stamp-container">
-		<img v-if="status == FlowStatusEnum.ACTIVE" :style="style" src="@/assets/images/flw01.svg" />
-		<img v-else-if="status == FlowStatusEnum.COMPLETE" :style="style" src="@/assets/images/flw03.svg" />
-		<img v-else-if="status == FlowStatusEnum.REJECT" :style="style" src="@/assets/images/flw04.svg" />
-		<img v-else-if="status == FlowStatusEnum.REVOKE" :style="style" src="@/assets/images/flw02.svg" />
-		<img v-else-if="status == FlowStatusEnum.TIMEOUT" :style="style" src="@/assets/images/flw05.svg" />
-		<img v-else-if="status == FlowStatusEnum.TERMINATE" :style="style" src="@/assets/images/flw06.svg" />
+		<LeIcon v-if="status == FlowStatusEnum.ACTIVE" :style="style" icon-class="icon-status-flw01" />
+		<LeIcon v-if="status == FlowStatusEnum.COMPLETE" :style="style" icon-class="icon-status-flw03" />
+		<LeIcon v-if="status == FlowStatusEnum.REJECT" :style="style" icon-class="icon-status-flw04" />
+		<LeIcon v-if="status == FlowStatusEnum.REVOKE" :style="style" icon-class="icon-status-flw02" />
+		<LeIcon v-if="status == FlowStatusEnum.TIMEOUT" :style="style" icon-class="icon-status-flw05" />
+		<LeIcon v-if="status == FlowStatusEnum.TERMINATE" :style="style" icon-class="icon-status-flw06" />
 	</div>
 </template>
 

+ 0 - 34
src/components/FormCreateDesigner/DragBox.vue

@@ -1,34 +0,0 @@
-<script>
-import { h, defineComponent } from 'vue'
-import draggable from 'vuedraggable/src/vuedraggable'
-
-export default defineComponent({
-	name: 'DragBox',
-	props: ['rule', 'tag', 'formCreateInject'],
-	render(ctx) {
-		const subRule = { ...ctx.$props.rule.props, ...ctx.$attrs }
-		let _class = subRule.tag + '-drag drag-box'
-		if (!Object.keys(ctx.$slots).length) {
-			_class += ' ' + subRule.tag + '-holder'
-		}
-		subRule.class = _class
-		subRule.modelValue = [...this.$props.formCreateInject.children]
-
-		const keys = {}
-		if (ctx.$slots.default) {
-			const children = ctx.$slots.default()
-			children.forEach(v => {
-				if (v.key) {
-					keys[v.key] = v
-				}
-			})
-		}
-
-		return h(draggable, subRule, {
-			item: ({ element }) => {
-				return h('div', {}, keys[element.__fc__.key + 'fc'])
-			}
-		})
-	}
-})
-</script>

+ 0 - 136
src/components/FormCreateDesigner/DragTool.vue

@@ -1,136 +0,0 @@
-<template>
-	<div class="drag-tool" :class="{ active: state.active === id }" @click.stop="active">
-		<div v-if="mask" class="drag-mask"></div>
-		<div class="drag-l">
-			<div v-if="state.active === id && dragBtn !== false" class="drag-btn _fc-drag-btn" style="cursor: move">
-				<i class="fc-icon icon-move"></i>
-			</div>
-		</div>
-		<div class="drag-r">
-			<div class="drag-btn" @click="$emit('create')">
-				<i class="fc-icon icon-add"></i>
-			</div>
-			<div class="drag-btn" @click="$emit('copy')">
-				<i class="fc-icon icon-copy"></i>
-			</div>
-			<div v-if="children" class="drag-btn" @click="$emit('addChild')">
-				<i class="fc-icon icon-add-child"></i>
-			</div>
-			<div class="drag-btn drag-btn-danger" @click="$emit('delete')">
-				<i class="fc-icon icon-delete"></i>
-			</div>
-		</div>
-		<slot name="default"></slot>
-	</div>
-</template>
-
-<script>
-import { computed, inject, toRefs, defineComponent } from 'vue'
-
-let uni = 1
-export default defineComponent({
-	name: 'DragTool',
-	props: ['dragBtn', 'children', 'unique', 'mask'],
-	setup(props) {
-		const { unique } = toRefs(props)
-		const id = computed(() => unique.value || uni++)
-		const state = inject('fcx')
-		return {
-			id,
-			state
-		}
-	},
-	beforeUnmount() {
-		this.state = {}
-	},
-	methods: {
-		active() {
-			if (this.state.active === this.id) return
-			this.state.active = this.id
-			this.$emit('active')
-		}
-	}
-})
-</script>
-
-<style>
-.drag-tool {
-	position: relative;
-	display: flex;
-	min-height: 20px;
-	box-sizing: border-box;
-	padding: 2px;
-	outline: 1px dashed #2e73ff;
-	overflow: hidden;
-	word-wrap: break-word;
-	word-break: break-all;
-}
-
-.drag-tool .drag-tool {
-	margin: 5px;
-}
-
-.drag-tool + .drag-tool {
-	margin-top: 5px;
-}
-
-.drag-tool.active {
-	outline: 2px solid #2e73ff;
-}
-
-.drag-tool.active > div > .drag-btn {
-	display: flex;
-}
-
-.drag-tool .drag-btn {
-	display: none;
-}
-
-.drag-r {
-	position: absolute;
-	right: 2px;
-	bottom: 2px;
-	z-index: 1904;
-}
-
-.drag-l {
-	position: absolute;
-	top: 0;
-	left: 0;
-	z-index: 1904;
-}
-
-.drag-btn {
-	height: 18px;
-	width: 18px;
-	color: #fff;
-	background-color: #2e73ff;
-	text-align: center;
-	line-height: 20px;
-	padding-bottom: 1px;
-	float: left;
-	cursor: pointer;
-	justify-content: center;
-}
-
-.drag-btn + .drag-btn {
-	margin-left: 2px;
-}
-
-.drag-btn-danger {
-	background-color: #ff2e2e;
-}
-
-.drag-btn i {
-	font-size: 13px;
-}
-
-.drag-mask {
-	z-index: 1900;
-	position: absolute;
-	top: 0;
-	left: 0;
-	right: 0;
-	bottom: 0;
-}
-</style>

+ 0 - 1216
src/components/FormCreateDesigner/FcDesigner.vue

@@ -1,1216 +0,0 @@
-<template>
-	<ElContainer class="_fc-designer" :style="'height:' + dragHeight">
-		<ElMain>
-			<ElContainer style="height: 100%">
-				<el-aside class="_fc-l" width="266px">
-					<template v-for="(item, index) in menuList" :key="index">
-						<div class="_fc-l-group">
-							<h4 class="_fc-l-title">{{ item.title }}</h4>
-							<draggable :group="{ name: 'default', pull: 'clone', put: false }" :sort="false" item-key="name" :list="item.list">
-								<template #item="{ element }">
-									<div class="_fc-l-item">
-										<div class="_fc-l-icon">
-											<i class="fc-icon" :class="element.icon || 'icon-input'"></i>
-										</div>
-										<span class="_fc-l-name">{{ t('components.' + element.name + '.name') || element.label }}</span>
-									</div>
-								</template>
-							</draggable>
-						</div>
-					</template>
-				</el-aside>
-				<ElContainer class="_fc-m">
-					<el-header v-if="false" class="_fc-m-tools" height="45">
-						<slot name="handle"></slot>
-						<el-button size="small" @click="setJson">导入JSON</el-button>
-						<el-button size="small" type="primary" @click="showJson">生成JSON</el-button>
-						<el-button size="small" type="primary" @click="saveAsForm">暂存表单</el-button>
-						<el-button type="primary" plain round size="small" @click="previewFc">
-							<i class="fc-icon icon-preview"></i> {{ t('designer.preview') }}
-						</el-button>
-						<el-popconfirm
-							:title="t('designer.clearConfirmTitle')"
-							width="200px"
-							:confirm-button-text="t('designer.clearConfirm')"
-							:cancel-button-text="t('designer.clearCancel')"
-							@confirm="clearDragRule"
-						>
-							<template #reference>
-								<el-button type="danger" plain round size="small"><i class="fc-icon icon-delete"></i>{{ t('designer.clear') }} </el-button>
-							</template>
-						</el-popconfirm>
-					</el-header>
-					<ElMain class="_fc-el-main">
-						<div class="_fc-m-drag">
-							<DragForm v-model:api="dragForm.api" :rule="dragForm.rule" :option="form.value"></DragForm>
-						</div>
-					</ElMain>
-				</ElContainer>
-				<ElAside v-if="!config || config.showConfig !== false" class="_fc-r" width="320px">
-					<ElContainer style="height: 100%">
-						<el-header height="40px" class="_fc-r-tabs">
-							<div
-								v-if="!!activeRule || (config && config.showFormConfig === false)"
-								class="_fc-r-tab"
-								:class="{ active: activeTab === 'props' }"
-								@click="activeTab = 'props'"
-							>
-								{{ t('designer.config.component') }}
-							</div>
-							<div
-								v-if="!config || config.showFormConfig !== false"
-								class="_fc-r-tab"
-								:class="{ active: activeTab === 'form' && !!activeRule }"
-								@click="activeTab = 'form'"
-							>
-								{{ t('designer.config.form') }}
-							</div>
-						</el-header>
-						<ElMain v-show="activeTab === 'form'" v-if="!config || config.showFormConfig !== false">
-							<DragForm v-model="form.value.form" v-model:api="form.api" :rule="form.rule" :option="form.option"></DragForm>
-						</ElMain>
-						<ElMain v-show="activeTab === 'props'" :key="activeRule ? activeRule._id : ''" style="padding: 0 20px">
-							<div>
-								<ElDivider v-if="showBaseRule">{{ t('designer.config.rule') }}</ElDivider>
-								<DragForm
-									v-show="showBaseRule"
-									v-model:api="baseForm.api"
-									:rule="baseForm.rule"
-									:option="baseForm.options"
-									:model-value="baseForm.value"
-									@change="baseChange"
-								></DragForm>
-								<ElDivider>{{ t('designer.config.props') }}</ElDivider>
-								<DragForm
-									v-model:api="propsForm.api"
-									:rule="propsForm.rule"
-									:option="propsForm.options"
-									:model-value="propsForm.value"
-									@change="propChange"
-									@remove-field="propRemoveField"
-								></DragForm>
-								<ElDivider v-if="showBaseRule">{{ t('designer.config.validate') }}</ElDivider>
-								<DragForm
-									v-show="showBaseRule"
-									v-model:api="validateForm.api"
-									:rule="validateForm.rule"
-									:option="validateForm.options"
-									:model-value="validateForm.value"
-									@update:model-value="validateChange"
-								></DragForm>
-							</div>
-						</ElMain>
-					</ElContainer>
-				</ElAside>
-				<!-- 预览表单 -->
-				<ElDialog v-model="preview.state" width="800px" append-to-body>
-					<ViewForm v-if="preview.state" :rule="preview.rule" :option="preview.option"></ViewForm>
-				</ElDialog>
-				<!-- 生成JSON / 导入JSON -->
-				<el-dialog v-model="state" :title="title[type]" class="_fc-t-dialog">
-					<div v-if="state" id="editor" ref="editorRef"></div>
-					<span v-if="err" style="color: red">输入内容格式有误!</span>
-					<template v-if="type > 2" #footer>
-						<span slot="footer" class="dialog-footer">
-							<el-button size="small" @click="state = false">取 消</el-button>
-							<el-button type="primary" size="small" @click="onOk">确 定</el-button>
-						</span>
-					</template>
-				</el-dialog>
-			</ElContainer>
-		</ElMain>
-	</ElContainer>
-</template>
-<script>
-// 代码样式
-import 'codemirror/lib/codemirror.css'
-import 'codemirror/addon/lint/lint.css'
-import CodeMirror from 'codemirror/lib/codemirror'
-import 'codemirror/addon/lint/lint'
-import 'codemirror/addon/lint/json-lint'
-import 'codemirror/mode/javascript/javascript'
-import 'codemirror/mode/vue/vue'
-import 'codemirror/mode/xml/xml'
-import 'codemirror/mode/css/css'
-import 'codemirror/addon/mode/overlay'
-import 'codemirror/addon/mode/simple'
-import 'codemirror/addon/selection/selection-pointer'
-import 'codemirror/mode/handlebars/handlebars'
-import 'codemirror/mode/htmlmixed/htmlmixed'
-import 'codemirror/mode/pug/pug'
-// 代码样式
-import form from '../../config/base/form'
-import field from '../../config/base/field'
-import validate from '../../config/base/validate'
-import { deepCopy } from '@form-create/utils/lib/deepextend'
-import is, { hasProperty } from '@form-create/utils/lib/type'
-import { lower } from '@form-create/utils/lib/tocase'
-import ruleList from '../../config/rule'
-import draggable from 'vuedraggable/src/vuedraggable'
-import createMenu from '../../config/menu'
-import { upper, useLocale } from '../../utils/formCreateIndex'
-import { designerForm } from '../../utils/form'
-import viewForm from '../../utils/form'
-import { t as globalT } from '../../utils/locale'
-import { computed, reactive, toRefs, toRef, ref, getCurrentInstance, provide, nextTick, watch, defineComponent, markRaw, defineExpose } from 'vue'
-
-export default defineComponent({
-	name: 'FcDesigner',
-	components: {
-		draggable,
-		DragForm: designerForm.$form(),
-		ViewForm: viewForm.$form()
-	},
-	props: ['menu', 'height', 'config', 'mask', 'locale'],
-	setup(props) {
-		const { menu, height, mask, locale } = toRefs(props)
-		const vm = getCurrentInstance()
-		provide('fcx', ref({ active: null }))
-		provide('designer', vm)
-
-		const config = toRef(props, 'config', {})
-		const baseRule = toRef(config.value, 'baseRule', null)
-		const componentRule = toRef(config.value, 'componentRule', {})
-		const validateRule = toRef(config.value, 'validateRule', null)
-		const formRule = toRef(config.value, 'formRule', null)
-		const dragHeight = computed(() => {
-			const h = height.value
-			if (!h) return '100%'
-			return is.Number(h) ? `${h}px` : h
-		})
-		let _t = globalT
-		if (locale.value) {
-			_t = useLocale(locale).t
-		}
-		const t = (...args) => _t(...args)
-
-		const tidyRuleConfig = (orgRule, configRule, ...args) => {
-			if (configRule) {
-				if (is.Function(configRule)) {
-					return configRule(...args)
-				}
-				if (configRule.rule) {
-					let rule = configRule.rule(...args)
-					if (configRule.append) {
-						rule = [...rule, ...orgRule(...args)]
-					}
-					return rule
-				}
-			}
-			return orgRule(...args)
-		}
-		const editorRef = ref()
-		const data = reactive({
-			cacheProps: {},
-			moveRule: null,
-			addRule: null,
-			added: null,
-			activeTab: 'form',
-			activeRule: null,
-			children: ref([]),
-			menuList: menu.value || createMenu({ t }),
-			showBaseRule: false,
-			visible: {
-				preview: false
-			},
-			t,
-			preview: {
-				state: false,
-				rule: [],
-				option: {}
-			},
-			dragForm: ref({
-				rule: [],
-				api: {}
-			}),
-			form: {
-				rule: tidyRuleConfig(form, formRule.value, { t }),
-				api: {},
-				option: {
-					form: {
-						labelPosition: 'top',
-						size: 'small'
-					},
-					submitBtn: false
-				},
-				value: {
-					form: {
-						inline: false,
-						hideRequiredAsterisk: false,
-						labelPosition: 'right',
-						size: 'small',
-						labelWidth: '125px',
-						formCreateSubmitBtn: true,
-						formCreateResetBtn: false
-					},
-					submitBtn: false
-				}
-			},
-			baseForm: {
-				rule: tidyRuleConfig(field, baseRule.value, { t }),
-				api: {},
-				value: {},
-				options: {
-					form: {
-						labelPosition: 'top',
-						size: 'small'
-					},
-					submitBtn: false,
-					mounted: fapi => {
-						fapi.activeRule = data.activeRule
-						fapi.setValue(fapi.options.formData || {})
-					}
-				}
-			},
-			validateForm: {
-				rule: tidyRuleConfig(validate, validateRule.value, { t }),
-				api: {},
-				value: [],
-				options: {
-					form: {
-						labelPosition: 'top',
-						size: 'small'
-					},
-					submitBtn: false,
-					mounted: fapi => {
-						fapi.activeRule = data.activeRule
-						fapi.setValue(fapi.options.formData || {})
-					}
-				}
-			},
-			propsForm: {
-				rule: [],
-				api: {},
-				value: {},
-				options: {
-					form: {
-						labelPosition: 'top',
-						size: 'small'
-					},
-					submitBtn: false,
-					mounted: fapi => {
-						fapi.activeRule = data.activeRule
-						fapi.setValue(fapi.options.formData || {})
-					}
-				}
-			},
-			// 生成JSON / 导入JSON
-			title: ['生成规则', '表单规则', '生成组件', '设置生成规则', '设置表单规则'],
-			state: false,
-			value: null,
-			err: false,
-			type: -1,
-			editor: null
-		})
-
-		watch(
-			() => data.preview.state,
-			function (n) {
-				if (!n) {
-					nextTick(() => {
-						data.preview.rule = data.preview.option = null
-					})
-				}
-			}
-		)
-
-		watch(
-			() => data.state,
-			n => {
-				if (!n) {
-					data.value = null
-					data.err = false
-				}
-			}
-		)
-
-		watch(
-			() => data.value,
-			n => {
-				methods.load()
-			}
-		)
-
-		let unWatchActiveRule = null
-
-		watch(
-			() => locale.value,
-			n => {
-				_t = n ? useLocale(locale).t : globalT
-				const formVal = data.form.api.formData && data.form.api.formData()
-				const baseFormVal = data.baseForm.api.formData && data.baseForm.api.formData()
-				const validateFormVal = data.validateForm.api.formData && data.validateForm.api.formData()
-				data.validateForm.rule = tidyRuleConfig(validate, validateRule.value, { t })
-				data.baseForm.rule = tidyRuleConfig(field, baseRule.value, { t })
-				data.form.rule = tidyRuleConfig(form, formRule.value, { t })
-				data.cacheProps = {}
-				const rule = data.activeRule
-				let propsVal = null
-				if (rule) {
-					propsVal = data.propsForm.api.formData && data.propsForm.api.formData()
-					data.propsForm.rule = data.cacheProps[rule._id] = tidyRuleConfig(
-						rule.config.config.props,
-						componentRule.value && componentRule.value[rule.config.config.name],
-						rule,
-						{ t, api: data.dragForm.api }
-					)
-				}
-				nextTick(() => {
-					formVal && data.form.api.setValue(formVal)
-					baseFormVal && data.baseForm.api.setValue(baseFormVal)
-					validateFormVal && data.validateForm.api.setValue(validateFormVal)
-					propsVal && data.propsForm.api.setValue(propsVal)
-				})
-			}
-		)
-
-		const methods = {
-			unWatchActiveRule() {
-				unWatchActiveRule && unWatchActiveRule()
-				unWatchActiveRule = null
-			},
-			watchActiveRule() {
-				methods.unWatchActiveRule()
-				unWatchActiveRule = watch(
-					() => data.activeRule,
-					function (n) {
-						n && methods.updateRuleFormData()
-					},
-					{ deep: true, flush: 'post' }
-				)
-			},
-			makeChildren(children) {
-				return reactive({ children }).children
-			},
-			addMenu(config) {
-				if (!config.name || !config.list) return
-				let flag = true
-				data.menuList.forEach((v, i) => {
-					if (v.name === config.name) {
-						data.menuList[i] = config
-						flag = false
-					}
-				})
-				if (flag) {
-					data.menuList.push(config)
-				}
-			},
-			removeMenu(name) {
-				;[...data.menuList].forEach((v, i) => {
-					if (v.name === name) {
-						data.menuList.splice(i, 1)
-					}
-				})
-			},
-			setMenuItem(name, list) {
-				data.menuList.forEach(v => {
-					if (v.name === name) {
-						v.list = list
-					}
-				})
-			},
-			appendMenuItem(name, item) {
-				data.menuList.forEach(v => {
-					if (v.name === name) {
-						v.list.push(...(Array.isArray(item) ? item : [item]))
-					}
-				})
-			},
-			removeMenuItem(item) {
-				data.menuList.forEach(v => {
-					let idx
-					if (is.String(item)) {
-						;[...v.list].forEach((menu, idx) => {
-							if (menu.name === item) {
-								v.list.splice(idx, 1)
-							}
-						})
-					} else {
-						if ((idx = v.list.indexOf(item)) > -1) {
-							v.list.splice(idx, 1)
-						}
-					}
-				})
-			},
-			addComponent(component) {
-				if (Array.isArray(component)) {
-					component.forEach(v => {
-						ruleList[v.name] = v
-					})
-				} else {
-					ruleList[component.name] = component
-				}
-			},
-			getParent(rule) {
-				let parent = rule.__fc__.parent.rule
-				const config = parent.config
-				if (config && config.config.inside) {
-					rule = parent
-					parent = parent.__fc__.parent.rule
-				}
-				return { root: parent, parent: rule }
-			},
-			makeDrag(group, tag, children, on) {
-				return {
-					type: 'DragBox',
-					wrap: {
-						show: false
-					},
-					col: {
-						show: false
-					},
-					inject: true,
-					props: {
-						rule: {
-							props: {
-								tag: 'el-col',
-								group: group === true ? 'default' : group,
-								ghostClass: 'ghost',
-								animation: 150,
-								handle: '._fc-drag-btn',
-								emptyInsertThreshold: 0,
-								direction: 'vertical',
-								itemKey: 'type'
-							}
-						},
-						tag
-					},
-					children,
-					on
-				}
-			},
-			clearDragRule() {
-				methods.setRule([])
-			},
-			makeDragRule(children) {
-				return methods.makeChildren([
-					methods.makeDrag(true, 'draggable', children, {
-						add: (inject, evt) => methods.dragAdd(children, evt),
-						end: (inject, evt) => methods.dragEnd(children, evt),
-						start: (inject, evt) => methods.dragStart(children, evt),
-						unchoose: (inject, evt) => methods.dragUnchoose(children, evt)
-					})
-				])
-			},
-			previewFc() {
-				data.preview.state = true
-				data.preview.rule = methods.getRule()
-				data.preview.option = methods.getOption()
-			},
-			getRule() {
-				return methods.parseRule(deepCopy(data.dragForm.api.rule[0].children))
-			},
-			getJson() {
-				return designerForm.toJson(methods.getRule())
-			},
-			getOption() {
-				const option = deepCopy(data.form.value)
-				option.submitBtn = option._submitBtn
-				option.resetBtn = option._resetBtn
-				if (typeof option.submitBtn === 'object') {
-					option.submitBtn.show = option.form.formCreateSubmitBtn
-				} else {
-					option.submitBtn = {
-						show: option.form.formCreateSubmitBtn,
-						innerText: t('form.submit')
-					}
-				}
-				if (typeof option.resetBtn === 'object') {
-					option.resetBtn.show = option.form.formCreateResetBtn
-				} else {
-					option.resetBtn = {
-						show: option.form.formCreateResetBtn,
-						innerText: t('form.reset')
-					}
-				}
-				delete option.form.formCreateSubmitBtn
-				delete option.form.formCreateResetBtn
-				delete option._submitBtn
-				delete option._resetBtn
-				return option
-			},
-			getOptions() {
-				methods.getOption()
-			},
-			setRule(rules) {
-				if (!rules) {
-					rules = []
-				}
-				data.children = methods.makeChildren(methods.loadRule(is.String(rules) ? designerForm.parseJson(rules) : deepCopy(rules)))
-				methods.clearActiveRule()
-				data.dragForm.rule = methods.makeDragRule(data.children)
-			},
-			setBaseRuleConfig(rule, append) {
-				baseRule.value = { rule, append }
-				data.baseForm.rule = tidyRuleConfig(field, baseRule.value, { t })
-			},
-			setComponentRuleConfig(name, rule, append) {
-				componentRule.value[name] = { rule, append }
-				data.cacheProps = {}
-				const activeRule = data.activeRule
-				if (activeRule) {
-					const propsVal = data.propsForm.api.formData && data.propsForm.api.formData()
-					data.propsForm.rule = data.cacheProps[activeRule._id] = tidyRuleConfig(
-						activeRule.config.config.props,
-						componentRule.value && componentRule.value[activeRule.config.config.name],
-						activeRule,
-						{ t, api: data.dragForm.api }
-					)
-					nextTick(() => {
-						propsVal && data.propsForm.api.setValue(propsVal)
-					})
-				}
-			},
-			setValidateRuleConfig(rule, append) {
-				validateRule.value = { rule, append }
-				data.validateForm.rule = tidyRuleConfig(field, validateRule.value, { t })
-			},
-			setFormRuleConfig(rule, append) {
-				formRule.value = { rule, append }
-				data.form.rule = tidyRuleConfig(field, formRule.value, { t })
-			},
-			clearActiveRule() {
-				data.activeRule = null
-				data.activeTab = 'form'
-			},
-			setOption(opt) {
-				let option = { ...opt }
-				option.form.formCreateSubmitBtn =
-					typeof option.submitBtn === 'object' ? (option.submitBtn.show === undefined ? true : !!option.submitBtn.show) : !!option.submitBtn
-				option.form.formCreateResetBtn = typeof option.resetBtn === 'object' ? !!option.resetBtn.show : !!option.resetBtn
-				option._resetBtn = option.resetBtn
-				option.resetBtn = false
-				option._submitBtn = option.submitBtn
-				option.submitBtn = false
-				data.form.value = option
-			},
-			setOptions(opt) {
-				methods.setOption(opt)
-			},
-			loadRule(rules) {
-				const loadRule = []
-				rules.forEach(rule => {
-					if (is.String(rule)) {
-						return loadRule.push(rule)
-					}
-					const config = ruleList[rule._fc_drag_tag] || ruleList[rule.type]
-					const _children = rule.children
-					rule.children = []
-					if (rule.control) {
-						rule._control = rule.control
-						delete rule.control
-					}
-					if (config) {
-						rule = methods.makeRule(config, rule)
-						if (_children) {
-							let children = rule.children[0].children
-
-							if (config.drag) {
-								children = children[0].children
-							}
-							children.push(...methods.loadRule(_children))
-						}
-					} else if (_children) {
-						rule.children = methods.loadRule(_children)
-					}
-					loadRule.push(rule)
-				})
-				return loadRule
-			},
-			parseRule(children) {
-				return [...children].reduce((initial, rule) => {
-					if (is.String(rule)) {
-						initial.push(rule)
-						return initial
-					} else if (rule.type === 'DragBox') {
-						initial.push(...methods.parseRule(rule.children))
-						return initial
-					} else if (rule.type === 'DragTool') {
-						rule = rule.children[0]
-						if (rule.type === 'DragBox') {
-							initial.push(...methods.parseRule(rule.children))
-							return initial
-						}
-					}
-					if (!rule) return initial
-					rule = { ...rule }
-					if (rule.children.length) {
-						rule.children = methods.parseRule(rule.children)
-					}
-
-					delete rule._id
-					delete rule.key
-					delete rule.component
-					if (rule.config) {
-						delete rule.config.config
-					}
-					if (rule.effect) {
-						delete rule.effect._fc
-						delete rule.effect._fc_tool
-					}
-					if (rule._control) {
-						rule.control = rule._control
-						delete rule._control
-					}
-					Object.keys(rule)
-						.filter(k => (Array.isArray(rule[k]) && rule[k].length === 0) || (is.Object(rule[k]) && Object.keys(rule[k]).length === 0))
-						.forEach(k => {
-							delete rule[k]
-						})
-					initial.push(rule)
-					return initial
-				}, [])
-			},
-			baseChange(field, value, _, fapi) {
-				if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
-					methods.unWatchActiveRule()
-					data.activeRule[field] = value
-					methods.watchActiveRule()
-					data.activeRule.config.config?.watch?.['$' + field]?.({
-						field,
-						value,
-						api: fapi,
-						rule: data.activeRule
-					})
-				}
-			},
-			propRemoveField(field, _, fapi) {
-				if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
-					methods.unWatchActiveRule()
-					const org = field
-					data.dragForm.api.sync(data.activeRule)
-					if (field.indexOf('formCreate') === 0) {
-						field = field.replace('formCreate', '')
-						if (!field) return
-						field = lower(field)
-						if (field.indexOf('effect') === 0 && field.indexOf('>') > -1) {
-							delete data.activeRule.effect[field.split('>')[1]]
-						} else if (field.indexOf('props') === 0 && field.indexOf('>') > -1) {
-							delete data.activeRule.props[field.split('>')[1]]
-						} else if (field.indexOf('attrs') === 0 && field.indexOf('>') > -1) {
-							data.activeRule.attrs[field.split('>')[1]] = value
-						} else if (field === 'child') {
-							delete data.activeRule.children[0]
-						} else if (field) {
-							data.activeRule[field] = undefined
-						}
-					} else {
-						delete data.activeRule.props[field]
-					}
-					methods.watchActiveRule()
-					data.activeRule.config.config?.watch?.[org]?.({
-						field: org,
-						value: undefined,
-						api: fapi,
-						rule: data.activeRule
-					})
-				}
-			},
-			propChange(field, value, _, fapi) {
-				if (data.activeRule && fapi[data.activeRule._id] === data.activeRule) {
-					methods.unWatchActiveRule()
-					const org = field
-					if (field.indexOf('formCreate') === 0) {
-						field = field.replace('formCreate', '')
-						if (!field) return
-						field = lower(field)
-						if (field.indexOf('effect') === 0 && field.indexOf('>') > -1) {
-							data.activeRule.effect[field.split('>')[1]] = value
-						} else if (field.indexOf('props') === 0 && field.indexOf('>') > -1) {
-							data.activeRule.props[field.split('>')[1]] = value
-						} else if (field.indexOf('attrs') === 0 && field.indexOf('>') > -1) {
-							data.activeRule.attrs[field.split('>')[1]] = value
-						} else if (field === 'child') {
-							data.activeRule.children[0] = value
-						} else {
-							data.activeRule[field] = value
-						}
-					} else {
-						data.activeRule.props[field] = value
-					}
-					methods.watchActiveRule()
-					data.activeRule.config.config?.watch?.[org]?.({
-						field: org,
-						value,
-						api: fapi,
-						rule: data.activeRule
-					})
-				}
-			},
-			validateChange(formData) {
-				if (!data.activeRule || data.validateForm.api[data.activeRule._id] !== data.activeRule) return
-				data.activeRule.validate = formData.validate || []
-				data.dragForm.api.refreshValidate()
-        data.dragForm.api.nextTick(() => {
-					data.dragForm.api.clearValidateState(data.activeRule.__fc__.id)
-				})
-			},
-			toolActive(rule) {
-				methods.unWatchActiveRule()
-				if (data.activeRule) {
-					delete data.propsForm.api[data.activeRule._id]
-					delete data.baseForm.api[data.activeRule._id]
-					delete data.validateForm.api[data.activeRule._id]
-					delete data.dragForm.api.activeRule
-				}
-				data.activeRule = rule
-				data.dragForm.api.activeRule = rule
-
-				nextTick(() => {
-					data.activeTab = 'props'
-					nextTick(() => {
-						data.propsForm.api[data.activeRule._id] = data.activeRule
-						data.baseForm.api[data.activeRule._id] = data.activeRule
-						data.validateForm.api[data.activeRule._id] = data.activeRule
-					})
-				})
-				if (!data.cacheProps[rule._id]) {
-					data.cacheProps[rule._id] = tidyRuleConfig(
-						rule.config.config.props,
-						componentRule.value && componentRule.value[rule.config.config.name],
-						rule,
-						{ t, api: data.dragForm.api }
-					) // rule.config.config.props(rule, {t, api: data.dragForm.api});
-				}
-
-				data.propsForm.rule = data.cacheProps[rule._id]
-				methods.updateRuleFormData()
-				methods.watchActiveRule()
-			},
-			updateRuleFormData() {
-				const rule = data.activeRule
-				const formData = { ...rule.props, formCreateChild: deepCopy(rule.children[0]) }
-				Object.keys(rule).forEach(k => {
-					if (['effect', 'config', 'payload', 'id', 'type'].indexOf(k) < 0) formData['formCreate' + upper(k)] = deepCopy(rule[k])
-				})
-				;['props', 'effect', 'attrs'].forEach(name => {
-					rule[name] &&
-						Object.keys(rule[name]).forEach(k => {
-							formData['formCreate' + upper(name) + '>' + k] = deepCopy(rule[name][k])
-						})
-				})
-				data.propsForm.value = formData
-
-				data.showBaseRule = hasProperty(rule, 'field') && rule.input !== false && (!config.value || config.value.showBaseForm !== false)
-
-				if (data.showBaseRule) {
-					data.baseForm.value = {
-						field: rule.field,
-						title: rule.title || '',
-						info: rule.info,
-						_control: rule._control
-					}
-					data.validateForm.value = { validate: rule.validate ? [...rule.validate] : [] }
-					data.dragForm.api.refreshValidate()
-          data.dragForm.api.nextTick(() => {
-						data.dragForm.api.clearValidateState(rule.__fc__.id)
-					})
-				}
-			},
-			dragStart(children) {
-				data.moveRule = children
-				data.added = false
-			},
-			dragUnchoose(children, evt) {
-				data.addRule = {
-					children,
-					oldIndex: evt.oldIndex
-				}
-			},
-			dragAdd(children, evt) {
-				const newIndex = evt.newIndex
-				const menu = evt.item._underlying_vm_
-				if (!menu || menu.__fc__) {
-					if (data.addRule) {
-						const rule = data.addRule.children.splice(data.addRule.oldIndex, 1)
-						children.splice(newIndex, 0, rule[0])
-					}
-				} else {
-					const rule = methods.makeRule(ruleList[menu.name])
-					children.splice(newIndex, 0, rule)
-				}
-				data.added = true
-				// data.dragForm.api.refresh();
-			},
-			dragEnd(children, { newIndex, oldIndex }) {
-				if (!data.added && !(data.moveRule === children && newIndex === oldIndex)) {
-					const rule = data.moveRule.splice(oldIndex, 1)
-					children.splice(newIndex, 0, rule[0])
-				}
-				data.moveRule = null
-				data.addRule = null
-				data.added = false
-				// data.dragForm.api.refresh();
-			},
-			makeRule(config, _rule) {
-				const rule = _rule || config.rule({ t })
-				rule.config = { config }
-				if (config.component) {
-					rule.component = markRaw(config.component)
-				}
-				if (!rule.effect) rule.effect = {}
-				rule.effect._fc = true
-				rule._fc_drag_tag = config.name
-
-				let drag
-
-				if (config.drag) {
-					rule.children.push(
-						(drag = methods.makeDrag(config.drag, rule.type, methods.makeChildren([]), {
-							end: (inject, evt) => methods.dragEnd(inject.self.children, evt),
-							add: (inject, evt) => methods.dragAdd(inject.self.children, evt),
-							start: (inject, evt) => methods.dragStart(inject.self.children, evt),
-							unchoose: (inject, evt) => methods.dragUnchoose(inject.self.children, evt)
-						}))
-					)
-				}
-
-				if (config.children && !_rule) {
-					for (let i = 0; i < (config.childrenLen || 1); i++) {
-						const child = methods.makeRule(ruleList[config.children])
-						;(drag || rule).children.push(child)
-					}
-				}
-
-				const dragMask = mask.value !== undefined ? mask.value !== false : config.mask !== false
-
-				if (config.inside) {
-					rule.children = methods.makeChildren([
-						{
-							type: 'DragTool',
-							props: {
-								dragBtn: config.dragBtn !== false,
-								children: config.children,
-								mask: dragMask
-							},
-							effect: {
-								_fc_tool: true
-							},
-							inject: true,
-							on: {
-								delete: ({ self }) => {
-									const parent = methods.getParent(self).parent
-									parent.__fc__.rm()
-									vm.emit('delete', parent)
-									methods.clearActiveRule()
-								},
-								create: ({ self }) => {
-									const top = methods.getParent(self)
-									vm.emit('create', top.parent)
-									top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, methods.makeRule(top.parent.config.config))
-								},
-								addChild: ({ self }) => {
-									const top = methods.getParent(self)
-									const config = top.parent.config.config
-									const item = ruleList[config.children]
-									if (!item) return
-									;(!config.drag ? top.parent : top.parent.children[0]).children[0].children.push(methods.makeRule(item))
-								},
-								copy: ({ self }) => {
-									const top = methods.getParent(self)
-									vm.emit('copy', top.parent)
-									top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, designerForm.copyRule(top.parent))
-								},
-								active: ({ self }) => {
-									const top = methods.getParent(self)
-									vm.emit('active', top.parent)
-									methods.toolActive(top.parent)
-								}
-							},
-							children: rule.children
-						}
-					])
-					return rule
-				} else {
-					return {
-						type: 'DragTool',
-						props: {
-							dragBtn: config.dragBtn !== false,
-							children: config.children,
-							mask: dragMask
-						},
-						effect: {
-							_fc_tool: true
-						},
-						inject: true,
-						on: {
-							delete: ({ self }) => {
-								vm.emit('delete', self.children[0])
-								self.__fc__.rm()
-								methods.clearActiveRule()
-							},
-							create: ({ self }) => {
-								vm.emit('create', self.children[0])
-								const top = methods.getParent(self)
-								top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, methods.makeRule(self.children[0].config.config))
-							},
-							addChild: ({ self }) => {
-								const config = self.children[0].config.config
-								const item = ruleList[config.children]
-								if (!item) return
-								;(!config.drag ? self : self.children[0]).children[0].children.push(methods.makeRule(item))
-							},
-							copy: ({ self }) => {
-								vm.emit('copy', self.children[0])
-								const top = methods.getParent(self)
-								top.root.children.splice(top.root.children.indexOf(top.parent) + 1, 0, designerForm.copyRule(top.parent))
-							},
-							active: ({ self }) => {
-								vm.emit('active', self.children[0])
-								methods.toolActive(self.children[0])
-							}
-						},
-						children: methods.makeChildren([rule])
-					}
-				}
-			},
-			load() {
-				let val
-				if (data.type === 2) {
-					val = data.value
-				} else if (data.type === 0) {
-					val = formCreate.toJson(data.value, 2)
-				} else {
-					val = JSON.stringify(data.value, null, 2)
-				}
-				nextTick(() => {
-					data.editor = CodeMirror(document.getElementById('editor'), {
-						lineNumbers: true,
-						mode: data.type === 2 ? { name: 'vue' } : 'application/json',
-						gutters: ['CodeMirror-lint-markers'],
-						// lint: true,
-						line: true,
-						tabSize: 2,
-						lineWrapping: true,
-						value: val || ''
-					})
-				})
-			},
-			showJson() {
-				data.state = true
-				data.type = 0
-				data.value = methods.getRule()
-				let val = JSON.parse(JSON.stringify(data.value))
-				vm.emit('export-json', val)
-			},
-			setJson() {
-				data.state = true
-				data.type = 3
-				data.value = []
-			},
-			onOk() {
-				if (data.err) return
-				const json = data.editor.getValue()
-				let val = JSON.parse(json)
-				if (data.type === 3) {
-					if (!Array.isArray(val)) {
-						data.err = true
-						return
-					}
-					methods.setRule(formCreate.parseJson(json))
-				} else {
-					if (!is.Object(val) || !val.form) {
-						data.err = true
-						return
-					}
-					methods.setOption(val)
-				}
-				data.state = false
-			},
-			// 暂存
-			saveAsForm() {
-				data.value = methods.getRule()
-				let val = JSON.parse(JSON.stringify(data.value))
-				console.log('--------saveAsForm------', val)
-				vm.emit('export-json', val)
-			},
-			// 初始化
-			initForm(json) {
-				// todo 这里需要针对json为空做处理
-				try {
-					methods.setRule(formCreate.parseJson(json))
-				} catch (e) {
-					console.log(e)
-				}
-			}
-		}
-		data.dragForm.rule = methods.makeDragRule(methods.makeChildren(data.children))
-
-		// defineExpose({
-		// 	initForm: methods.initForm,
-		// 	saveFormJson: methods.showJson
-		// })
-		return {
-			editorRef,
-			...toRefs(data),
-			...methods,
-			dragHeight,
-			t
-		}
-	},
-	created() {
-		document.body.ondrop = e => {
-			e.preventDefault()
-			e.stopPropagation()
-		}
-	}
-})
-</script>
-<style>
-._fc-designer {
-	height: 100%;
-	min-height: 500px;
-	overflow: hidden;
-	cursor: default;
-	position: relative;
-}
-
-._fc-designer > .el-main {
-	position: absolute;
-	top: 0;
-	bottom: 0;
-	left: 0;
-	right: 0;
-	padding: 0px;
-}
-
-._fc-m .form-create ._fc-l-item {
-	background: var(--el-color-primary);
-	width: 100%;
-	height: 10px;
-	overflow: hidden;
-	transition: all 0.3s ease;
-}
-
-._fc-l,
-._fc-m,
-._fc-r {
-	/* #ececec */
-	border-top: 1px solid var(--el-border-color-lighter);
-	box-sizing: border-box;
-}
-
-._fc-l-group {
-	padding: 0 12px;
-}
-
-._fc-l-title {
-	font-weight: 600;
-	font-size: 14px;
-	margin: 18px 0px 5px;
-}
-
-._fc-l-item {
-	display: inline-block;
-	background: var(--el-bg-color);
-	color: var(--el-text-color-primary);
-	min-width: 70px;
-	width: 33.33%;
-	height: 70px;
-	line-height: 1;
-	text-align: center;
-	transition: all 0.2s ease;
-	cursor: pointer;
-}
-
-._fc-l-item i {
-	font-size: 21px;
-	display: inline-block;
-}
-
-._fc-l-item ._fc-l-name {
-	font-size: 12px;
-}
-
-._fc-l-item ._fc-l-icon {
-	padding: 10px 5px 12px;
-}
-
-._fc-l-item:hover {
-	/*background: #2e73ff;*/
-	background: var(--el-color-primary);
-	/*color: #fff;*/
-	color: var(--el-color-white);
-}
-
-._fc-m-tools {
-	height: 40px;
-	align-items: center;
-	display: flex;
-	justify-content: flex-end;
-	/*border: 1px solid #ececec;*/
-	border: 1px solid var(--el-border-color);
-	border-top: 0 none;
-}
-
-._fc-m-tools button.el-button {
-	padding: 5px 14px;
-	display: flex;
-	align-items: center;
-}
-
-._fc-m-tools .fc-icon {
-	font-size: 14px;
-	margin-right: 2px;
-}
-
-._fc-r .el-tabs__nav-wrap::after {
-	height: 1px;
-	/*background-color: #ececec;*/
-	background-color: var(--el-bg-color-page);
-}
-
-._fc-r ._fc-r-tabs {
-	display: flex;
-	padding: 0;
-	/*border-bottom: 1px solid #ececec;*/
-	border-bottom: 1px solid var(--el-border-color-extra-light);
-}
-
-._fc-r ._fc-r-tab {
-	height: 40px;
-	box-sizing: border-box;
-	line-height: 40px;
-	display: inline-block;
-	list-style: none;
-	font-size: 14px;
-	font-weight: 600;
-	color: #303133;
-	position: relative;
-	flex: 1;
-	text-align: center;
-}
-
-._fc-r ._fc-r-tab.active {
-	color: var(--el-color-primary);
-	border-bottom: 2px solid var(--el-color-primary);
-}
-
-.drag-box {
-	min-height: 60px;
-	width: 100%;
-}
-
-._fc-m-drag {
-	overflow: auto;
-	padding: 2px;
-	box-sizing: border-box;
-}
-
-._fc-m-drag,
-.draggable-drag {
-	background: var(--el-bg-color);
-	height: 100%;
-	position: relative;
-}
-
-._fc-m-drag > form,
-._fc-m-drag > form > .el-row {
-	height: 100%;
-}
-
-._fc-el-main {
-	background: var(--el-bg-color-page);
-	padding: 20px;
-}
-</style>

+ 0 - 170
src/components/FormCreateDesigner/Fetch.vue

@@ -1,170 +0,0 @@
-<template>
-	<div class="_fc_fetch">
-		<DragForm v-model:api="api" :model-value="formValue" :rule="rule" :option="option" @change="input" />
-	</div>
-</template>
-
-<script>
-import debounce from '@form-create/utils/lib/debounce'
-import is from '@form-create/utils/lib/type'
-import { designerForm } from '../../utils/form'
-import { defineComponent } from 'vue'
-
-export default defineComponent({
-	name: 'Fetch',
-	props: {
-		modelValue: [Object, String],
-		to: String
-	},
-	components: {
-		DragForm: designerForm.$form()
-	},
-	inject: ['designer'],
-	data() {
-		const t = this.designer.setupState.t
-		return {
-			api: {},
-			fetch: {},
-			t,
-			option: {
-				form: {
-					labelPosition: 'right',
-					size: 'small',
-					labelWidth: '90px'
-				},
-				submitBtn: false
-			},
-			rule: [
-				{
-					type: 'input',
-					field: 'action',
-					title: t('fetch.action') + ': ',
-					validate: [{ required: true, message: t('fetch.actionRequired') }]
-				},
-				{
-					type: 'select',
-					field: 'method',
-					title: t('fetch.method') + ': ',
-					value: 'GET',
-					options: [
-						{ label: 'GET', value: 'GET' },
-						{ label: 'POST', value: 'POST' }
-					],
-					control: [
-						{
-							value: 'POST',
-							rule: [
-								{
-									type: 'select',
-									field: 'dataType',
-									title: t('fetch.dataType') + ': ',
-									value: 'FormData',
-									options: [
-										{ label: 'FormData', value: 'FormData' },
-										{ label: 'JSON', value: 'JSON' }
-									]
-								}
-							]
-						}
-					]
-				},
-				{
-					type: 'Struct',
-					field: 'data',
-					title: t('fetch.data') + ': ',
-					value: {},
-					props: {
-						defaultValue: {}
-					}
-				},
-				{
-					type: 'Struct',
-					field: 'headers',
-					title: t('fetch.headers') + ': ',
-					value: {},
-					props: {
-						defaultValue: {}
-					}
-				},
-				{
-					type: 'Struct',
-					field: 'parse',
-					title: t('fetch.parse') + ': ',
-					info: t('fetch.parseInfo'),
-					value: null,
-					props: {
-						defaultValue: function parse(res) {
-							return res
-						}
-					}
-				}
-				// {
-				//     type: 'input',
-				//     field: '_parse',
-				//     title: t('fetch.parse') + ': ',
-				//     info: t('fetch.parseInfo'),
-				//     value: 'function (res){\n   return res.data;\n}',
-				//     props: {
-				//         type: 'textarea',
-				//         rows: 8,
-				//     },
-				//     validate: [{
-				//         validator: (_, v, cb) => {
-				//             if (!v) return cb();
-				//             try {
-				//                 this.parseFn(v);
-				//             } catch (e) {
-				//                 return cb(false);
-				//             }
-				//             cb();
-				//         }, message: t('fetch.parseValidate')
-				//     }]
-				// },
-			]
-		}
-	},
-	computed: {
-		formValue() {
-			const val = this.modelValue
-			if (!val) return {}
-			if (is.String(val)) {
-				return {
-					action: val
-				}
-			}
-			return val
-		}
-	},
-	methods: {
-		parseFn(v) {
-			return new Function('return ' + v)()
-		},
-		_input() {
-			this.api.submit(formData => {
-				formData.to = this.to || 'options'
-				// if (formData._parse) formData.parse = this.parseFn(formData._parse);
-				this.$emit('update:modelValue', formData)
-			})
-		},
-		input: debounce(function () {
-			this._input()
-		}, 1000)
-	},
-	mounted() {
-		this._input()
-	}
-})
-</script>
-<style>
-._fc_fetch .el-form-item__label {
-	float: left;
-	display: inline-block;
-	text-align: right;
-	padding-right: 5px;
-}
-
-._fc_fetch {
-	background-color: #bfdaf7;
-	padding: 10px;
-}
-</style>

+ 0 - 16
src/components/FormCreateDesigner/IconRefresh.vue

@@ -1,16 +0,0 @@
-<template>
-	<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-029747aa="">
-		<path
-			fill="currentColor"
-			d="M771.776 794.88A384 384 0 0 1 128 512h64a320 320 0 0 0 555.712 216.448H654.72a32 32 0 1 1 0-64h149.056a32 32 0 0 1 32 32v148.928a32 32 0 1 1-64 0v-50.56zM276.288 295.616h92.992a32 32 0 0 1 0 64H220.16a32 32 0 0 1-32-32V178.56a32 32 0 0 1 64 0v50.56A384 384 0 0 1 896.128 512h-64a320 320 0 0 0-555.776-216.384z"
-		></path>
-	</svg>
-</template>
-
-<script>
-import { defineComponent } from 'vue'
-
-export default defineComponent({
-	name: 'IconRefresh'
-})
-</script>

+ 0 - 67
src/components/FormCreateDesigner/Required.vue

@@ -1,67 +0,0 @@
-<template>
-	<div class="_fc-required">
-		<ElSwitch v-model="required"></ElSwitch>
-		<ElInput v-if="required" v-model="requiredMsg" :placeholder="t('validate.requiredPlaceholder')"></ElInput>
-	</div>
-</template>
-
-<script>
-import is from '@form-create/utils/lib/type'
-import { defineComponent } from 'vue'
-
-export default defineComponent({
-	name: 'Required',
-	inject: ['designer'],
-	props: {
-		modelValue: {}
-	},
-	data() {
-		const flag = is.String(this.modelValue)
-		const t = this.designer.setupState.t
-		return {
-			t,
-			required: this.modelValue === undefined ? false : flag ? true : !!this.modelValue,
-			requiredMsg: flag ? this.modelValue : ''
-		}
-	},
-	watch: {
-		required() {
-			this.update()
-		},
-		requiredMsg() {
-			this.update()
-		},
-		modelValue(n) {
-			const flag = is.String(n)
-			this.required = n === undefined ? false : flag ? true : !!n
-			this.requiredMsg = flag ? n : ''
-		}
-	},
-	methods: {
-		update() {
-			let val
-			if (this.required === false) {
-				val = false
-			} else {
-				val = this.requiredMsg || true
-			}
-			this.$emit('update:modelValue', val)
-		}
-	}
-})
-</script>
-
-<style>
-._fc-required {
-	display: flex;
-	align-items: center;
-}
-
-._fc-required .el-input {
-	margin-left: 15px;
-}
-
-._fc-required .el-switch {
-	height: 28px;
-}
-</style>

+ 0 - 124
src/components/FormCreateDesigner/Struct.vue

@@ -1,124 +0,0 @@
-<template>
-	<div class="_fc_struct">
-		<ElButton style="width: 100%" @click="visible = true">{{ title || t('struct.title') }}</ElButton>
-		<ElDialog v-model="visible" :title="title || t('struct.title')" :close-on-click-modal="false" append-to-body>
-			<div v-if="visible" ref="editor"></div>
-			<template #footer>
-				<span class="dialog-footer">
-					<span v-if="err" class="_fc_err"> {{ t('struct.error') }}{{ err !== true ? err : '' }}</span>
-					<ElButton size="small" @click="visible = false">{{ t('struct.cancel') }}</ElButton>
-					<ElButton type="primary" size="small" @click="onOk">{{ t('struct.submit') }}</ElButton>
-				</span>
-			</template>
-		</ElDialog>
-	</div>
-</template>
-
-<script>
-import 'codemirror/lib/codemirror.css'
-import CodeMirror from 'codemirror/lib/codemirror'
-import 'codemirror/mode/javascript/javascript'
-import { deepParseFn, toJSON } from '../../utils/formCreateIndex'
-import { deepCopy } from '@form-create/utils/lib/deepextend'
-import { defineComponent } from 'vue'
-
-export default defineComponent({
-	name: 'Struct',
-	inject: ['designer'],
-	props: {
-		modelValue: [Object, Array, Function],
-		title: String,
-		defaultValue: {
-			require: false
-		},
-		validate: Function
-	},
-	data() {
-		return {
-			editor: null,
-			visible: false,
-			err: false,
-			oldVal: null,
-			t: this.designer.setupState.t
-		}
-	},
-	watch: {
-		modelValue() {
-			this.load()
-		},
-		visible(n) {
-			if (n) {
-				this.load()
-			} else {
-				this.err = false
-			}
-		}
-	},
-	methods: {
-		load() {
-			const val = toJSON(deepParseFn(this.modelValue ? deepCopy(this.modelValue) : this.defaultValue))
-			this.oldVal = val
-			this.$nextTick(() => {
-				this.editor = CodeMirror(this.$refs.editor, {
-					lineNumbers: true,
-					mode: 'javascript',
-					gutters: ['CodeMirror-lint-markers'],
-					lint: true,
-					line: true,
-					tabSize: 2,
-					lineWrapping: true,
-					value: val || ''
-				})
-			})
-		},
-		onOk() {
-			const str = this.editor.getValue()
-			let val
-			try {
-				val = new Function('return ' + str)()
-			} catch (e) {
-				this.err = ` (${e})`
-				return
-			}
-			if (this.validate && false === this.validate(val)) {
-				this.err = true
-				return
-			}
-			this.visible = false
-			if (toJSON(val, null, 2) !== this.oldVal) {
-				this.$emit('update:modelValue', val)
-			}
-		}
-	}
-})
-</script>
-
-<style>
-._fc_struct {
-	width: 100%;
-}
-
-._fc_struct .CodeMirror {
-	height: 450px;
-}
-
-._fc_struct .CodeMirror-line {
-	line-height: 16px !important;
-	font-size: 13px !important;
-}
-
-.CodeMirror-lint-tooltip {
-	z-index: 2021 !important;
-}
-
-._fc_struct .el-dialog__body {
-	padding: 0px 20px;
-}
-
-._fc_err {
-	color: red;
-	float: left;
-	text-align: left;
-	width: 65%;
-}
-</style>

+ 0 - 78
src/components/FormCreateDesigner/TableOptions.vue

@@ -1,78 +0,0 @@
-<template>
-	<div class="_fc_table_opt">
-		<el-table :data="modelValue" border size="small" style="width: 100%">
-			<template v-for="(col, idx) in column" :key="col.label + idx">
-				<el-table-column :label="col.label">
-					<template #default="scope">
-						<el-input
-							size="small"
-							:model-value="scope.row[col.key] || ''"
-							@Update:modelValue="n => ((scope.row[col.key] = n), onInput(scope.row))"
-						></el-input>
-					</template>
-				</el-table-column>
-			</template>
-			<el-table-column min-width="50" align="center" fixed="right" :label="t('tableOptions.handle')">
-				<template #default="scope">
-					<i class="fc-icon icon-delete" @click="del(scope.$index)"></i>
-				</template>
-			</el-table-column>
-		</el-table>
-		<el-button link type="primary" @click="add"> <i class="fc-icon icon-add"></i> {{ t('tableOptions.add') }} </el-button>
-	</div>
-</template>
-
-<script>
-import { defineComponent } from 'vue'
-
-export default defineComponent({
-	name: 'TableOptions',
-	inject: ['designer'],
-	inheritAttrs: false,
-	props: {
-		modelValue: [Object, Array, String]
-	},
-	data() {
-		return {
-			column: [
-				{ label: 'label', key: 'label' },
-				{ label: 'value', key: 'value' }
-			],
-			t: this.designer.setupState.t
-		}
-	},
-	created() {
-		if (!Array.isArray(this.modelValue)) {
-			this.$emit('input', [])
-		}
-	},
-	methods: {
-		onInput(item) {
-			if (item.label && item.value) {
-				this.input()
-			}
-		},
-		input() {
-			this.$emit('update:modelValue', this.modelValue)
-		},
-		add() {
-			this.modelValue.push(
-				this.column.reduce((initial, v) => {
-					initial[v.key] = ''
-					return initial
-				}, {})
-			)
-		},
-		del(idx) {
-			this.modelValue.splice(idx, 1)
-			this.input(this.modelValue)
-		}
-	}
-})
-</script>
-
-<style scoped>
-._fc_table_opt {
-	width: 100%;
-}
-</style>

+ 0 - 236
src/components/FormCreateDesigner/Validate.vue

@@ -1,236 +0,0 @@
-<template>
-	<DragForm class="_fc-validate" :rule="rule" :option="option" :model-value="formValue" @update:modelValue="onInput"></DragForm>
-</template>
-
-<script>
-import { designerForm } from '../../utils/form'
-import { defineComponent } from 'vue'
-import { deepCopy } from '@form-create/utils/lib/deepextend'
-
-export default defineComponent({
-	name: 'Validate',
-	inject: ['designer'],
-	props: {
-		modelValue: Array
-	},
-	components: {
-		DragForm: designerForm.$form()
-	},
-	data() {
-		const t = this.designer.setupState.t
-		return {
-			formValue: {},
-			t,
-			option: {
-				form: {
-					labelPosition: 'top',
-					size: 'small',
-					labelWidth: '90px'
-				},
-				submitBtn: false,
-				appendValue: true,
-				formData: this.parseValue(this.modelValue)
-			},
-			rule: [
-				{
-					type: 'select',
-					field: 'type',
-					value: '',
-					title: t('validate.type'),
-					options: [
-						{ value: '', label: t('validate.typePlaceholder') },
-						{ value: 'string', label: 'String' },
-						{ value: 'array', label: 'Array' },
-						{ value: 'number', label: 'Number' },
-						{ value: 'integer', label: 'Integer' },
-						{ value: 'float', label: 'Float' },
-						{ value: 'object', label: 'Object' },
-						{ value: 'date', label: 'Date' },
-						{ value: 'url', label: 'url' },
-						{ value: 'hex', label: 'hex' },
-						{ value: 'email', label: 'email' }
-					],
-					control: [
-						{
-							handle: v => {
-								return !!v
-							},
-							rule: [
-								{
-									type: 'group',
-									field: 'validate',
-									props: {
-										expand: 1,
-										sortBtn: false,
-										rule: [
-											{
-												type: 'select',
-												title: t('validate.trigger'),
-												field: 'trigger',
-												value: 'change',
-												options: [
-													{ label: 'change', value: 'change' },
-													{ label: 'submit', value: 'submit' },
-													{ label: 'blur', value: 'blur' }
-												]
-											},
-											{
-												type: 'hidden',
-												field: 'validator',
-												value: undefined
-											},
-											{
-												type: 'select',
-												title: t('validate.mode'),
-												field: 'mode',
-												options: [
-													{ value: 'required', label: t('validate.modes.required') },
-													{ value: 'pattern', label: t('validate.modes.pattern') },
-													{ value: 'min', label: t('validate.modes.min') },
-													{ value: 'max', label: t('validate.modes.max') },
-													{ value: 'len', label: t('validate.modes.len') }
-												],
-												value: 'required',
-												control: [
-													{
-														value: 'required',
-														rule: [
-															{
-																type: 'hidden',
-																field: 'required',
-																value: true
-															}
-														]
-													},
-													{
-														value: 'pattern',
-														rule: [
-															{
-																type: 'input',
-																field: 'pattern',
-																title: t('validate.modes.pattern')
-															}
-														]
-													},
-													{
-														value: 'min',
-														rule: [
-															{
-																type: 'inputNumber',
-																field: 'min',
-																title: t('validate.modes.min')
-															}
-														]
-													},
-													{
-														value: 'max',
-														rule: [
-															{
-																type: 'inputNumber',
-																field: 'max',
-																title: t('validate.modes.max')
-															}
-														]
-													},
-													{
-														value: 'len',
-														rule: [
-															{
-																type: 'inputNumber',
-																field: 'len',
-																title: t('validate.modes.len')
-															}
-														]
-													}
-												]
-											},
-											{
-												type: 'input',
-												title: t('validate.message'),
-												field: 'message',
-												value: '',
-												children: [
-													{
-														type: 'span',
-														slot: 'append',
-														inject: true,
-														class: 'append-msg',
-														on: {
-															click: inject => {
-																const title = this.designer.setupState.activeRule.title
-																if (this.designer.setupState.activeRule) {
-																	inject.api.setValue(
-																		'message',
-																		t(inject.api.form.mode !== 'required' ? 'validate.autoMode' : 'validate.autoRequired', { title })
-																	)
-																}
-															}
-														},
-														children: [t('validate.auto')]
-													}
-												]
-											}
-										]
-									},
-									value: []
-								}
-							]
-						}
-					]
-				}
-			]
-		}
-	},
-	watch: {
-		modelValue(n) {
-			this.formValue = this.parseValue(n)
-		}
-	},
-	methods: {
-		onInput: function (formData) {
-			let val = []
-			const { validate, type } = deepCopy(formData)
-			if (type && (!validate || !validate.length)) {
-				return
-			} else if (type) {
-				validate.forEach(v => {
-					v.type = type
-				})
-				val = [...validate]
-			}
-			this.$emit('update:modelValue', val)
-		},
-		parseValue(n) {
-			let val = {
-				validate: n ? [...n] : [],
-				type: n.length ? n[0].type || 'string' : undefined
-			}
-			val.validate.forEach(v => {
-				if (!v.mode) {
-					Object.keys(v).forEach(k => {
-						if (['message', 'type', 'trigger', 'mode'].indexOf(k) < 0) {
-							v.mode = k
-						}
-					})
-				}
-			})
-
-			return val
-		}
-	}
-})
-</script>
-
-<style>
-._fc-validate .form-create .el-form-item {
-	margin-bottom: 22px !important;
-}
-
-._fc-validate .append-msg {
-	cursor: pointer;
-}
-
-._fc-validate .el-input-group__append {
-	padding: 0 10px;
-}
-</style>

+ 14 - 0
src/components/external/ckeditor5/.eslintrc.js

@@ -0,0 +1,14 @@
+/**
+ * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* eslint-env node */
+
+'use strict'
+
+module.exports = {
+  rules: {
+    'ckeditor5-rules/ckeditor-imports': 'off'
+  }
+}

+ 101 - 0
src/components/external/ckeditor5/___webpack.config.js

@@ -0,0 +1,101 @@
+/**
+ * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+'use strict'
+
+/* eslint-env node */
+
+const path = require('path')
+const webpack = require('webpack')
+const { bundler, styles } = require('@ckeditor/ckeditor5-dev-utils')
+const CKEditorWebpackPlugin = require('@ckeditor/ckeditor5-dev-webpack-plugin')
+const TerserPlugin = require('terser-webpack-plugin')
+
+module.exports = {
+  devtool: 'source-map',
+  performance: { hints: false },
+
+  entry: path.resolve(__dirname, 'src', 'ckeditor.js'),
+
+  output: {
+    // The name under which the editor will be exported.
+    library: 'CKEDITOR',
+
+    path: path.resolve(__dirname, 'build'),
+    filename: 'ckeditor.js',
+    libraryTarget: 'umd'
+  },
+
+  optimization: {
+    minimizer: [
+      new TerserPlugin({
+        sourceMap: true,
+        terserOptions: {
+          output: {
+            // Preserve CKEditor 5 license comments.
+            comments: /^!/
+          }
+        },
+        extractComments: false
+      })
+    ]
+  },
+
+  plugins: [
+    new CKEditorWebpackPlugin({
+      // UI language. Language codes follow the https://en.wikipedia.org/wiki/ISO_639-1 format.
+      // When changing the built-in language, remember to also change it in the editor's configuration (src/ckeditor.js).
+      language: 'en',
+      additionalLanguages: 'all'
+    }),
+    new webpack.BannerPlugin({
+      banner: bundler.getLicenseBanner(),
+      raw: true
+    })
+  ],
+
+  module: {
+    rules: [
+      {
+        test: /\.svg$/,
+        use: ['raw-loader']
+      },
+      {
+        test: /\.css$/,
+        use: [
+          {
+            loader: 'style-loader',
+            options: {
+              injectType: 'singletonStyleTag',
+              attributes: {
+                'data-cke': true
+              }
+            }
+          },
+          'css-loader',
+          {
+            loader: 'postcss-loader',
+            options: {
+              postcssOptions: styles.getPostCssConfig({
+                themeImporter: {
+                  themePath: require.resolve('@ckeditor/ckeditor5-theme-lark')
+                },
+                minify: true
+              })
+            }
+          }
+        ]
+      },
+      {
+        test: /\.ts$/,
+        use: ['ts-loader']
+      }
+    ]
+  },
+
+  resolve: {
+    extensions: ['.ts', '.js', '.json']
+  }
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/ckeditor.js


+ 1 - 0
src/components/external/ckeditor5/build/translations/af.js

@@ -0,0 +1 @@
+!function(e){const n=e.af=e.af||{};n.dictionary=Object.assign(n.dictionary||{},{"%0 of %1":"%0 van %1","Align center":"Belyn in die middel","Align left":"Belyn links","Align right":"Belyn regs","Block quote":"Verwysingsaanhaling",Bold:"Vet",Cancel:"Kanselleer","Cannot upload file:":"Lêer nie opgelaai nie:",Italic:"Kursief",Justify:"Belyn beide kante","Remove color":"Verwyder kleur","Rich Text Editor. Editing area: %0":"",Save:"Stoor","Show more items":"Wys meer items",Strikethrough:"Deurstreep","Text alignment":"Teksbelyning","Text alignment toolbar":"Teksbelyning nutsbank",Underline:"Onderstreep"}),n.getPluralForm=function(e){return 1!=e}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ar.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ast.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/az.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/bg.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/bn.js


+ 1 - 0
src/components/external/ckeditor5/build/translations/bs.js

@@ -0,0 +1 @@
+!function(i){const a=i.bs=i.bs||{};a.dictionary=Object.assign(a.dictionary||{},{"%0 of %1":"%0 od %1","Align center":"Centrirati","Align left":"Lijevo poravnanje","Align right":"Desno poravnanje",Big:"","Block quote":"Citat",Bold:"Podebljano","Break text":"",Cancel:"Poništi","Cannot upload file:":"Nije moguće učitati fajl:","Caption for image: %0":"","Caption for the image":"","Centered image":"Centrirana slika","Change image text alternative":"Promijeni ALT atribut za sliku","Choose heading":"Odaberi naslov",Default:"Zadani","Document colors":"","Enter image caption":"Unesi naziv slike","Font Background Color":"Boja pozadine","Font Color":"Boja","Font Family":"Font","Font Size":"Veličina fonta","Full size image":"",Heading:"Naslov","Heading 1":"Naslov 1","Heading 2":"Naslov 2","Heading 3":"Naslov 3","Heading 4":"Naslov 4","Heading 5":"Naslov 5","Heading 6":"Naslov 6",Huge:"","Image resize list":"Lista veličina slike","Image toolbar":"","image widget":"","In line":"","Insert image":"Umetni sliku",Italic:"Zakrivljeno",Justify:"","Left aligned image":"Lijevo poravnata slika",Original:"Original",Paragraph:"Paragraf","Remove color":"Ukloni boju","Resize image":"Promijeni veličinu slike","Resize image to %0":"","Resize image to the original size":"Postavi originalnu veličinu slike","Rich Text Editor. Editing area: %0":"","Right aligned image":"Desno poravnata slika",Save:"Sačuvaj","Show more items":"Prikaži više stavki","Side image":"",Small:"",Strikethrough:"Precrtano","Text alignment":"Poravnanje teksta","Text alignment toolbar":"Traka za poravnanje teksta","Text alternative":"ALT atribut",Tiny:"",Underline:"Podcrtano","Upload failed":"Učitavanje slike nije uspjelo","Wrap text":"Prelomi tekst"}),a.getPluralForm=function(i){return i%10==1&&i%100!=11?0:i%10>=2&&i%10<=4&&(i%100<10||i%100>=20)?1:2}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ca.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/cs.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/da.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/de-ch.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/de.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/el.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/en-au.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/en-gb.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/eo.js


+ 1 - 0
src/components/external/ckeditor5/build/translations/es-co.js

@@ -0,0 +1 @@
+!function(e){const a=e["es-co"]=e["es-co"]||{};a.dictionary=Object.assign(a.dictionary||{},{"%0 of %1":"%0 de %1","Align center":"Centrar","Align left":"Alinear a la izquierda","Align right":"Alinear a la derecha","Block quote":"Cita de bloque",Bold:"Negrita",Cancel:"Cancelar","Cannot upload file:":"No se pudo cargar el archivo:",Italic:"Cursiva",Justify:"Justificar","Remove color":"Quitar color","Rich Text Editor. Editing area: %0":"Editor de texto enriquecido. Área de edición: %0",Save:"Guardar","Show more items":"Mostrar más elementos",Strikethrough:"Tachado","Text alignment":"Alineación de texto","Text alignment toolbar":"Herramientas de alineación de texto",Underline:"Subrayado","Upload in progress":"Carga en progreso"}),a.getPluralForm=function(e){return 1==e?0:0!=e&&e%1e6==0?1:2}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/es.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/et.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/eu.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/fa.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/fi.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/fr.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/gl.js


+ 1 - 0
src/components/external/ckeditor5/build/translations/gu.js

@@ -0,0 +1 @@
+!function(o){const i=o.gu=o.gu||{};i.dictionary=Object.assign(i.dictionary||{},{"%0 of %1":"","Block quote":" વિચાર ટાંકો",Bold:"ઘાટુ - બોલ્ડ્",Cancel:"","Cannot upload file:":"ફાઇલ અપલોડ ન થઇ શકી",Italic:"ત્રાંસુ - ઇટલિક્","Remove color":"","Rich Text Editor. Editing area: %0":"",Save:"","Show more items":"",Strikethrough:"",Underline:"નીચે લિટી - અન્ડરલાઇન્"}),i.getPluralForm=function(o){return 1!=o}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/he.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/hi.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/hr.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/hu.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/id.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/it.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ja.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/jv.js


+ 1 - 0
src/components/external/ckeditor5/build/translations/kk.js

@@ -0,0 +1 @@
+!function(n){const t=n.kk=n.kk||{};t.dictionary=Object.assign(t.dictionary||{},{"Align center":"Ортадан туралау","Align left":"Солға туралау","Align right":"Оңға туралау",Justify:"","Text alignment":"Мәтінді туралау","Text alignment toolbar":"Мәтінді туралау құралдар тақтасы"}),t.getPluralForm=function(n){return 1!=n}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/km.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/kn.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ko.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ku.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/lt.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/lv.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ms.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/nb.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ne.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/nl.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/no.js


+ 1 - 0
src/components/external/ckeditor5/build/translations/oc.js

@@ -0,0 +1 @@
+!function(o){const i=o.oc=o.oc||{};i.dictionary=Object.assign(i.dictionary||{},{"%0 of %1":"",Bold:"Gras",Cancel:"Anullar","Cannot upload file:":"",Italic:"Italica","Remove color":"","Rich Text Editor. Editing area: %0":"",Save:"Enregistrar","Show more items":"",Strikethrough:"",Underline:""}),i.getPluralForm=function(o){return o>1}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/pl.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/pt-br.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/pt.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ro.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ru.js


+ 1 - 0
src/components/external/ckeditor5/build/translations/si.js

@@ -0,0 +1 @@
+!function(e){const t=e.si=e.si||{};t.dictionary=Object.assign(t.dictionary||{},{"%0 of %1":"",Bold:"තදකුරු","Break text":"","Bulleted List":"බුලටිත ලැයිස්තුව","Bulleted list styles toolbar":"",Cancel:"","Cannot upload file:":"ගොනුව යාවත්කාලීන කළ නොහැක:","Caption for image: %0":"","Caption for the image":"","Centered image":"","Change image text alternative":"",Circle:"",Decimal:"","Decimal with leading zero":"",Disc:"","Enter image caption":"","Full size image":"","Image resize list":"","Image toolbar":"","image widget":"","In line":"","Insert image":"පින්තූරය ඇතුල් කරන්න",Italic:"ඇලකුරු","Left aligned image":"","List properties":"","Lower-latin":"","Lower–roman":"","Numbered List":"අංකිත ලැයිස්තුව","Numbered list styles toolbar":"",Original:"",Redo:"නැවත කරන්න","Remove color":"","Resize image":"","Resize image to %0":"","Resize image to the original size":"","Reversed order":"","Rich Text Editor. Editing area: %0":"","Right aligned image":"",Save:"","Show more items":"","Side image":"",Square:"","Start at":"","Start index must be greater than 0.":"",Strikethrough:"","Text alternative":"","Toggle the circle list style":"","Toggle the decimal list style":"","Toggle the decimal with leading zero list style":"","Toggle the disc list style":"","Toggle the lower–latin list style":"","Toggle the lower–roman list style":"","Toggle the square list style":"","Toggle the upper–latin list style":"","Toggle the upper–roman list style":"",Underline:"",Undo:"අහෝසි කරන්න","Upload failed":"උඩුගත කිරීම අසාර්ථක විය","Upper-latin":"","Upper-roman":"","Wrap text":""}),t.getPluralForm=function(e){return 1!=e}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/sk.js


+ 1 - 0
src/components/external/ckeditor5/build/translations/sl.js

@@ -0,0 +1 @@
+!function(a){const o=a.sl=a.sl||{};o.dictionary=Object.assign(o.dictionary||{},{"%0 of %1":"","Align center":"Sredinska poravnava","Align left":"Poravnava levo","Align right":"Poravnava desno",Aquamarine:"Akvamarin",Big:"Veliko",Black:"Črna","Block quote":"Blokiraj citat",Blue:"Modra",Bold:"Krepko",Cancel:"Prekliči","Cannot upload file:":"Ni možno naložiti datoteke:","Choose heading":"Izberi naslov",Default:"Privzeto","Dim grey":"Temno siva","Document colors":"Barve dokumenta","Dropdown toolbar":"","Edit block":"","Editor block content toolbar":"","Editor contextual toolbar":"","Editor editing area: %0":"","Editor toolbar":"","Font Background Color":"Barva ozadja pisave","Font Color":"Barva pisave","Font Family":"Vrsta oz. tip pisave","Font Size":"Velikost pisave",Green:"Zelena",Grey:"Siva",Heading:"Naslov","Heading 1":"Naslov 1","Heading 2":"Naslov 2","Heading 3":"Naslov 3","Heading 4":"Naslov 4","Heading 5":"Naslov 5","Heading 6":"Naslov 6",Huge:"Ogromno",Italic:"Poševno",Justify:"Postavi na sredino","Light blue":"Svetlo modra","Light green":"Svetlo zelena","Light grey":"Svetlo siva",Next:"",Orange:"Oranžna",Paragraph:"Odstavek",Previous:"",Purple:"Vijolična",Red:"Rdeča","Remove color":"Odstrani barvo","Rich Text Editor":"","Rich Text Editor. Editing area: %0":"",Save:"Shrani","Show more items":"",Small:"Majhna",Strikethrough:"Prečrtano","Text alignment":"Poravnava besedila","Text alignment toolbar":"Orodna vrstica besedila",Tiny:"Drobna",Turquoise:"Turkizna",Underline:"Podčrtaj",White:"Bela",Yellow:"Rumena"}),o.getPluralForm=function(a){return a%100==1?0:a%100==2?1:a%100==3||a%100==4?2:3}}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/sq.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/sr-latn.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/sr.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/sv.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/th.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/tk.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/tr.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/tt.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ug.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/uk.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/ur.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/uz.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/vi.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/zh-cn.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
src/components/external/ckeditor5/build/translations/zh.js


+ 86 - 0
src/components/external/ckeditor5/package.json

@@ -0,0 +1,86 @@
+{
+  "name": "@ckeditor/ckeditor5-build-decoupled-document",
+  "version": "35.3.1",
+  "description": "The document editor build of CKEditor 5 – the best browser-based rich text editor.",
+  "keywords": [
+    "ckeditor5-build",
+    "ckeditor",
+    "ckeditor5",
+    "ckeditor 5",
+    "wysiwyg",
+    "rich text",
+    "editor",
+    "html",
+    "contentEditable",
+    "editing",
+    "operational transformation",
+    "ot",
+    "collaboration",
+    "collaborative",
+    "real-time",
+    "framework"
+  ],
+  "main": "./build/ckeditor.js",
+  "files": [
+    "build",
+    "ckeditor5-metadata.json",
+    "CHANGELOG.md"
+  ],
+  "dependencies": {
+    "@ckeditor/ckeditor5-adapter-ckfinder": "^35.3.1",
+    "@ckeditor/ckeditor5-alignment": "^35.3.1",
+    "@ckeditor/ckeditor5-autoformat": "^35.3.1",
+    "@ckeditor/ckeditor5-basic-styles": "^35.3.1",
+    "@ckeditor/ckeditor5-block-quote": "^35.3.1",
+    "@ckeditor/ckeditor5-ckbox": "^35.3.1",
+    "@ckeditor/ckeditor5-ckfinder": "^35.3.1",
+    "@ckeditor/ckeditor5-cloud-services": "^35.3.1",
+    "@ckeditor/ckeditor5-easy-image": "^35.3.1",
+    "@ckeditor/ckeditor5-editor-decoupled": "^35.3.1",
+    "@ckeditor/ckeditor5-essentials": "^35.3.1",
+    "@ckeditor/ckeditor5-font": "^35.3.1",
+    "@ckeditor/ckeditor5-heading": "^35.3.1",
+    "@ckeditor/ckeditor5-image": "^35.3.1",
+    "@ckeditor/ckeditor5-indent": "^35.3.1",
+    "@ckeditor/ckeditor5-link": "^35.3.1",
+    "@ckeditor/ckeditor5-list": "^35.3.1",
+    "@ckeditor/ckeditor5-media-embed": "^35.3.1",
+    "@ckeditor/ckeditor5-paragraph": "^35.3.1",
+    "@ckeditor/ckeditor5-paste-from-office": "^35.3.1",
+    "@ckeditor/ckeditor5-table": "^35.3.1",
+    "@ckeditor/ckeditor5-typing": "^35.3.1",
+    "@ckeditor/ckeditor5-ui": "^35.4.0"
+  },
+  "devDependencies": {
+    "@ckeditor/ckeditor5-core": "^35.3.1",
+    "@ckeditor/ckeditor5-dev-utils": "^31.0.0",
+    "@ckeditor/ckeditor5-dev-webpack-plugin": "^31.0.0",
+    "@ckeditor/ckeditor5-theme-lark": "^35.3.1",
+    "css-loader": "^5.2.7",
+    "postcss-loader": "^4.3.0",
+    "raw-loader": "^4.0.1",
+    "style-loader": "^2.0.0",
+    "terser-webpack-plugin": "^4.2.3",
+    "ts-loader": "^9.3.0",
+    "webpack": "^5.58.1",
+    "webpack-cli": "^4.10.0"
+  },
+  "engines": {
+    "node": ">=14.0.0",
+    "npm": ">=5.7.1"
+  },
+  "author": "CKSource (http://cksource.com/)",
+  "license": "GPL-2.0-or-later",
+  "homepage": "https://ckeditor.com/ckeditor-5",
+  "bugs": "https://github.com/ckeditor/ckeditor5/issues",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/ckeditor/ckeditor5.git",
+    "directory": "packages/ckeditor5-build-decoupled-document"
+  },
+  "scripts": {
+    "dev": "webpack --mode development --watch",
+    "build": "webpack --mode production",
+    "preversion": "npm run build"
+  }
+}

+ 73 - 0
src/components/external/ckeditor5/sample/index.html

@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="utf-8">
+  <title>CKEditor 5 – document editor build – development sample</title>
+  <style>
+      body {
+          max-width: 1000px;
+          margin: 20px auto;
+      }
+  </style>
+</head>
+<body>
+
+<h1>CKEditor 5 – document editor build – development sample</h1>
+
+<h2>The toolbar</h2>
+<div class="toolbar-container"></div>
+
+<h2>The editable</h2>
+<div class="editable-container"></div>
+
+<style>
+    .editable-container,
+    .toolbar-container {
+        position: relative;
+        border: 1px solid #ddd;
+        background: #eee;
+    }
+
+    .toolbar-container {
+        padding: 1em;
+    }
+
+    .editable-container {
+        padding: 3em;
+        overflow-y: scroll;
+        max-height: 500px;
+    }
+
+    .editable-container .ck-content {
+        min-height: 21cm;
+        padding: 2em;
+        border: 1px #D3D3D3 solid;
+        border-radius: var(--ck-border-radius);
+        background: white;
+        box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
+    }
+</style>
+
+<script src="../build/ckeditor.js"></script>
+<script>
+  const editorData = `<h2>Sample</h2>
+		<p>This is an instance of the <a href="https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/predefined-builds.html#document-editor">document editor build</a>.</p>
+		<figure class="image">
+			<img src="../tests/manual/sample.jpg" alt="Autumn fields" />
+		</figure>
+		<p>You can use this sample to validate whether your <a href="https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/alternative-setups/custom-builds.html">custom build</a> works fine.</p>`;
+
+  CKEDITOR.default.DecoupledEditor.create( editorData )
+    .then( editor => {
+      window.editor = editor;
+
+      document.querySelector( '.toolbar-container' ).appendChild( editor.ui.view.toolbar.element );
+      document.querySelector( '.editable-container' ).appendChild( editor.ui.view.editable.element );
+    } )
+    .catch( error => {
+      console.error( 'There was a problem initializing the editor.', error );
+    } );
+</script>
+
+</body>
+</html>

+ 305 - 0
src/components/external/ckeditor5/src/ckeditor.js

@@ -0,0 +1,305 @@
+/**
+ * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+import DecoupledEditorBase from '@ckeditor/ckeditor5-editor-decoupled/src/decouplededitor'
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin'
+import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials'
+import Alignment from '@ckeditor/ckeditor5-alignment/src/alignment'
+import FontSize from '@ckeditor/ckeditor5-font/src/fontsize'
+import FontFamily from '@ckeditor/ckeditor5-font/src/fontfamily'
+import FontColor from '@ckeditor/ckeditor5-font/src/fontcolor'
+import FontBackgroundColor from '@ckeditor/ckeditor5-font/src/fontbackgroundcolor'
+import UploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter'
+import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat'
+import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold'
+import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic'
+import Strikethrough from '@ckeditor/ckeditor5-basic-styles/src/strikethrough'
+import Underline from '@ckeditor/ckeditor5-basic-styles/src/underline'
+import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote'
+// import CKBox from '@ckeditor/ckeditor5-ckbox/src/ckbox';
+// import CKFinder from '@ckeditor/ckeditor5-ckfinder/src/ckfinder';
+// import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
+import Heading from '@ckeditor/ckeditor5-heading/src/heading'
+import Image from '@ckeditor/ckeditor5-image/src/image'
+import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption'
+import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize'
+import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle'
+import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar'
+import ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload'
+import Indent from '@ckeditor/ckeditor5-indent/src/indent'
+import IndentBlock from '@ckeditor/ckeditor5-indent/src/indentblock'
+import Link from '@ckeditor/ckeditor5-link/src/link'
+import List from '@ckeditor/ckeditor5-list/src/list'
+import ListProperties from '@ckeditor/ckeditor5-list/src/listproperties'
+// import MediaEmbed from '@ckeditor/ckeditor5-media-embed/src/mediaembed';
+import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'
+import PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice'
+import PictureEditing from '@ckeditor/ckeditor5-image/src/pictureediting'
+import Table from '@ckeditor/ckeditor5-table/src/table'
+import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar'
+import TextTransformation from '@ckeditor/ckeditor5-typing/src/texttransformation'
+// import CloudServices from '@ckeditor/ckeditor5-cloud-services/src/cloudservices';
+import DropdownButtonView from '@ckeditor/ckeditor5-ui/src/dropdown/button/dropdownbuttonview'
+import DropdownPanelView from '@ckeditor/ckeditor5-ui/src/dropdown/dropdownpanelview'
+import DropdownView from '@ckeditor/ckeditor5-ui/src/dropdown/dropdownview'
+import clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler'
+import fontColorIcon from '@ckeditor/ckeditor5-font/theme/icons/font-color.svg'
+import ToolbarView from '@ckeditor/ckeditor5-ui/src/toolbar/toolbarview'
+class DecoupledEditor extends DecoupledEditorBase {}
+function overrideDropdownPositionsToNorth (editor, toolbarView) {
+  const {
+    south, north, southEast, southWest, northEast, northWest,
+    southMiddleEast, southMiddleWest, northMiddleEast, northMiddleWest
+  } = DropdownView.defaultPanelPositions
+
+  let panelPositions
+
+  if (editor.locale.uiLanguageDirection !== 'rtl') {
+    panelPositions = [
+      northEast, northWest, northMiddleEast, northMiddleWest, north,
+      southEast, southWest, southMiddleEast, southMiddleWest, south
+    ]
+  } else {
+    panelPositions = [
+      northWest, northEast, northMiddleWest, northMiddleEast, north,
+      southWest, southEast, southMiddleWest, southMiddleEast, south
+    ]
+  }
+
+  for (const item of toolbarView.items) {
+    if (!(item instanceof DropdownView)) {
+      continue
+    }
+
+    item.on('change:isOpen', () => {
+      if (!item.isOpen) {
+        return
+      }
+
+      item.panelView.position = DropdownView._getOptimalPosition({
+        element: item.panelView.element,
+        target: item.buttonView.element,
+        fitInViewport: true,
+        positions: panelPositions
+      }).name
+    })
+  }
+}
+function overrideTooltipPositions (toolbarView) {
+  for (const item of toolbarView.items) {
+    if (item.buttonView) {
+      item.buttonView.tooltipPosition = 'n'
+    } else if (item.tooltipPosition) {
+      item.tooltipPosition = 'n'
+    }
+  }
+}
+class FormattingOptions extends Plugin {
+  /**
+   * @inheritDoc
+   */
+  static get pluginName () {
+    return 'FormattingOptions'
+  }
+
+  /**
+   * @inheritDoc
+   */
+  constructor (editor) {
+    super(editor)
+
+    editor.ui.componentFactory.add('formattingOptions', locale => {
+      const t = locale.t
+      const buttonView = new DropdownButtonView(locale)
+      const panelView = new DropdownPanelView(locale)
+      const dropdownView = new DropdownView(locale, buttonView, panelView)
+      const toolbarView = this.toolbarView = dropdownView.toolbarView = new ToolbarView(locale)
+
+      // Accessibility: Give the toolbar a human-readable ARIA label.
+      toolbarView.set({
+        ariaLabel: t('Formatting options toolbar')
+      })
+
+      // Accessibility: Give the dropdown a human-readable ARIA label.
+      dropdownView.set({
+        label: t('Formatting options')
+      })
+
+      // Toolbars in dropdowns need specific styling, hence the class.
+      dropdownView.extendTemplate({
+        attributes: {
+          class: ['ck-toolbar-dropdown']
+        }
+      })
+
+      // Accessibility: If the dropdown panel is already open, the arrow down key should focus the first child of the #panelView.
+      dropdownView.keystrokes.set('arrowdown', (data, cancel) => {
+        if (dropdownView.isOpen) {
+          toolbarView.focus()
+          cancel()
+        }
+      })
+
+      // Accessibility: If the dropdown panel is already open, the arrow up key should focus the last child of the #panelView.
+      dropdownView.keystrokes.set('arrowup', (data, cancel) => {
+        if (dropdownView.isOpen) {
+          toolbarView.focusLast()
+          cancel()
+        }
+      })
+
+      // The formatting options should not close when the user clicked:
+      // * the dropdown or it contents,
+      // * any editing root,
+      // * any floating UI in the "body" collection
+      // It should close, for instance, when another (main) toolbar button was pressed, though.
+      dropdownView.on('render', () => {
+        clickOutsideHandler({
+          emitter: dropdownView,
+          activator: () => dropdownView.isOpen,
+          callback: () => { dropdownView.isOpen = false },
+          contextElements: [
+            dropdownView.element,
+            ...[...editor.ui.getEditableElementsNames()].map(name => editor.ui.getEditableElement(name)),
+            document.querySelector('.ck-body-wrapper')
+          ]
+        })
+      })
+
+      // The main button of the dropdown should be bound to the state of the dropdown.
+      buttonView.bind('isOn').to(dropdownView, 'isOpen')
+      buttonView.bind('isEnabled').to(dropdownView)
+
+      // Using the font color icon to visually represent the formatting.
+      buttonView.set({
+        tooltip: t('Formatting options'),
+        icon: fontColorIcon
+      })
+
+      dropdownView.panelView.children.add(toolbarView)
+
+      toolbarView.fillFromConfig(
+        editor.config.get('formattingOptions'),
+        editor.ui.componentFactory
+      )
+
+      return dropdownView
+    })
+  }
+}
+const defaultConfig = {
+  toolbar: {
+    items: [
+      'heading',
+      '|',
+      'fontfamily',
+      'fontsize',
+      'fontColor',
+      'fontBackgroundColor',
+      '|',
+      'bold',
+      'italic',
+      'underline',
+      'strikethrough',
+      '|',
+      'alignment',
+      '|',
+      'numberedList',
+      'bulletedList',
+      '|',
+      'outdent',
+      'indent',
+      '|',
+      'link',
+      'blockquote',
+      'uploadImage',
+      'insertTable',
+      '|',
+      'undo',
+      'redo'
+    ]
+  },
+  image: {
+    resizeUnit: 'px',
+    toolbar: [
+      'imageStyle:inline',
+      'imageStyle:wrapText',
+      'imageStyle:breakText',
+      '|',
+      'toggleImageCaption',
+      'imageTextAlternative'
+    ]
+  },
+  table: {
+    contentToolbar: [
+      'tableColumn',
+      'tableRow',
+      'mergeTableCells'
+    ]
+  },
+  list: {
+    properties: {
+      styles: true,
+      startIndex: true,
+      reversed: true
+    }
+  },
+  // This value must be kept in sync with the language defined in webpack.config.js.
+  language: 'en'
+}
+const builtinPlugins = [
+  Essentials,
+  Alignment,
+  FontSize,
+  FontFamily,
+  FontColor,
+  FontBackgroundColor,
+  UploadAdapter,
+  Autoformat,
+  Bold,
+  Italic,
+  Strikethrough,
+  Underline,
+  BlockQuote,
+  // CKBox,
+  // CKFinder,
+  // CloudServices,
+  // EasyImage,
+  Heading,
+  Image,
+  ImageCaption,
+  ImageResize,
+  ImageStyle,
+  ImageToolbar,
+  ImageUpload,
+  Indent,
+  IndentBlock,
+  Link,
+  List,
+  ListProperties,
+  // MediaEmbed,
+  Paragraph,
+  PasteFromOffice,
+  PictureEditing,
+  Table,
+  TableToolbar,
+  TextTransformation
+]
+
+// ClassicEditor.builtinPlugins = builtinPlugins
+// ClassicEditor.defaultConfig = defaultConfig
+DecoupledEditor.builtinPlugins = builtinPlugins
+DecoupledEditor.defaultConfig = defaultConfig
+export default {
+  // ClassicEditor,
+  DecoupledEditor,
+  plugins: {
+    FormattingOptions
+  },
+  utils: {
+    overrideDropdownPositionsToNorth,
+    overrideTooltipPositions
+  }
+}

+ 119 - 0
src/components/external/ckeditor5/webpack.config.js

@@ -0,0 +1,119 @@
+/**
+ * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+'use strict'
+
+/* eslint-env node */
+
+const path = require('path')
+const webpack = require('webpack')
+const { bundler, styles } = require('@ckeditor/ckeditor5-dev-utils')
+const CKEditorWebpackPlugin = require('@ckeditor/ckeditor5-dev-webpack-plugin')
+const TerserPlugin = require('terser-webpack-plugin')
+// console.log(process.argv)
+// console.log(process.env.NODE_ENV === 'development')
+module.exports = (env, argv) => {
+  const config = {
+    // devtool: 'source-map',
+    // devtool: false,
+    performance: { hints: false },
+
+    entry: path.resolve(__dirname, 'src', 'ckeditor.js'),
+    experiments: {
+      outputModule: true
+    },
+    optimization: {
+      minimizer: [
+        new TerserPlugin({
+          sourceMap: true,
+          terserOptions: {
+            output: {
+              // Preserve CKEditor 5 license comments.
+              comments: /^!/
+            }
+          },
+          extractComments: false
+        })
+      ]
+    },
+
+    plugins: [
+      new CKEditorWebpackPlugin({
+        // UI language. Language codes follow the https://en.wikipedia.org/wiki/ISO_639-1 format.
+        // When changing the built-in language, remember to also change it in the editor's configuration (src/ckeditor.js).
+        language: 'en',
+        additionalLanguages: 'all'
+      }),
+      new webpack.BannerPlugin({
+        banner: bundler.getLicenseBanner(),
+        raw: true
+      })
+    ],
+
+    module: {
+      rules: [
+        {
+          test: /\.svg$/,
+          use: ['raw-loader']
+        },
+        {
+          test: /\.css$/,
+          use: [
+            {
+              loader: 'style-loader',
+              options: {
+                injectType: 'singletonStyleTag',
+                attributes: {
+                  'data-cke': true
+                }
+              }
+            },
+            'css-loader',
+            {
+              loader: 'postcss-loader',
+              options: {
+                postcssOptions: styles.getPostCssConfig({
+                  themeImporter: {
+                    themePath: require.resolve('@ckeditor/ckeditor5-theme-lark')
+                  },
+                  minify: true
+                })
+              }
+            }
+          ]
+        },
+        {
+          test: /\.ts$/,
+          use: ['ts-loader']
+        }
+      ]
+    },
+
+    resolve: {
+      extensions: ['.ts', '.js', '.json']
+    }
+  }
+  if (argv.mode === 'development') {
+    config.output = {
+      library: 'CKEDITOR',
+      path: path.resolve(__dirname, 'build'),
+      filename: 'ckeditor.js',
+      libraryTarget: 'umd'
+    }
+    config.output = {
+      library: 'CKEDITOR',
+      path: path.resolve(__dirname, 'build'),
+      filename: 'ckeditor.js',
+      libraryTarget: 'umd'
+    }
+  } else {
+    config.output = {
+      path: path.resolve(__dirname, 'build'),
+      filename: 'ckeditor.js',
+      libraryTarget: 'module'
+    }
+  }
+  return config
+}

+ 198 - 0
src/components/packages/ckeditor/__index.jsx

@@ -0,0 +1,198 @@
+/**
+ * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global window, console */
+import CKEDITOR from '@/components/external/ckeditor5/build/ckeditor.js'
+import { h, markRaw, defineComponent } from 'vue'
+import { debounce } from 'lodash-es'
+
+const SAMPLE_READ_ONLY_LOCK_ID = 'Integration Sample'
+const INPUT_EVENT_DEBOUNCE_WAIT = 300
+
+export default defineComponent({
+	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)
+	}
+})

+ 252 - 0
src/components/packages/ckeditor/index.jsx

@@ -0,0 +1,252 @@
+/**
+ * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global window, console */
+import { ElMessage } from 'element-plus'
+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'
+import hooks from '@ER/hooks'
+const SAMPLE_READ_ONLY_LOCK_ID = 'Integration Sample'
+const INPUT_EVENT_DEBOUNCE_WAIT = 300
+const ns = hooks.useNamespace('Main', 'ckeditor')
+
+class MyUploadAdapter {
+	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)
+					}
+				})
+		)
+	}
+
+	abort() {
+		if (this.xhr) {
+			this.xhr.abort()
+		}
+	}
+
+	_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
+				}
+			})
+		}
+	}
+
+	_sendRequest(file) {
+		// Prepare the form data.
+		const data = new FormData()
+
+		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)
+	}
+}
+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)
+
+			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>
+			)
+		}
+	}
+})

+ 2 - 0
src/components/packages/ckeditor/style/index.js

@@ -0,0 +1,2 @@
+import '@ER/theme/icon.scss'
+import '@ER/theme/ckeditor/index.scss'

+ 50 - 0
src/components/packages/formEditor/components/CompleteButton.vue

@@ -0,0 +1,50 @@
+<script>
+import { ref, unref, inject } from 'vue'
+import _ from 'lodash-es'
+import hooks from '@ER/hooks'
+export default {
+	name: 'ErCompleteButton'
+}
+</script>
+<script setup>
+const ER = inject('Everright')
+const props = defineProps({
+	handle: {
+		type: Object
+	},
+	mode: {
+		type: String,
+		default: 'edit'
+	}
+})
+const ns = hooks.useNamespace('CompleteButton')
+const { state, isPc } = hooks.useTarget()
+const element = ref('')
+const handleClick = async type => {
+	if (props.mode === 'preview') return false
+	try {
+		await Promise.resolve(unref(props.handle).validate())
+		// await ER.checkFieldsValidation()
+		ER.fireEvent('submit', ER.getData())
+	} catch (e) {
+		console.log(e)
+	}
+}
+const dataset = process.env.NODE_ENV === 'test' ? { 'data-test': 'er-complete-button' } : {}
+</script>
+<template>
+	<div v-bind="dataset">
+		<div v-if="isPc" style="text-align: center">
+			<el-button :color="state.config[state.platform].completeButton.backgroundColor" type="primary" @click="handleClick">
+				<span :style="{ color: state.config[state.platform].completeButton.color }">{{ state.config[state.platform].completeButton.text }}</span>
+			</el-button>
+		</div>
+		<div v-else>
+			<van-button round block type="primary" :color="state.config[state.platform].completeButton.backgroundColor" @click="handleClick">
+				<span :style="{ color: state.config[state.platform].completeButton.color }">{{ state.config[state.platform].completeButton.text }}</span>
+			</van-button>
+		</div>
+	</div>
+</template>
+
+<style scoped></style>

+ 38 - 0
src/components/packages/formEditor/components/DeviceSwitch.vue

@@ -0,0 +1,38 @@
+<script>
+import { ref, inject } from 'vue'
+import hooks from '@ER/hooks'
+import Icon from '@ER/icon'
+export default {
+  name: 'er-DeviceSwitch'
+}
+</script>
+<script setup>
+const props = defineProps({
+  modelValue: {
+    type: String,
+    default: 'pc'
+  }
+})
+const emit = defineEmits(['update:modelValue'])
+// const ER = inject('Everright')
+const ns = hooks.useNamespace('DeviceSwitch')
+// const {
+//   state
+// } = hooks.useTarget()
+// const element = ref('')
+// defineExpose({
+//   $el: element
+// })
+</script>
+<template>
+  <div :class="[ns.b()]">
+    <Icon @click="() => emit('update:modelValue', 'pc')" icon="PC" :class="[ns.e('icon'), props.modelValue === 'pc' && 'active']"></Icon>
+    <Icon @click="() => emit('update:modelValue', 'mobile')" icon="cellphone" :class="[ns.e('icon'), props.modelValue === 'mobile' && 'active']"></Icon>
+<!--    <Icon @click="() => ER.switchPlatform('pc')" icon="PC" :class="[ns.e('icon'), state.platform === 'pc' && 'active']"></Icon>-->
+<!--    <Icon @click="() => ER.switchPlatform('mobile')" icon="cellphone" :class="[ns.e('icon'), state.platform === 'mobile' && 'active']"></Icon>-->
+  </div>
+</template>
+
+<style scoped>
+
+</style>

+ 38 - 0
src/components/packages/formEditor/components/FormTypes/Cascader/mobile.vue

@@ -0,0 +1,38 @@
+<script>
+import { computed, ref, nextTick } from 'vue'
+import hooks from '@ER/hooks'
+export default {
+  name: 'er-cascader',
+  inheritAttrs: false,
+  customOptions: {}
+}
+</script>
+<script setup>
+const props = defineProps(['data', 'params'])
+const ns = hooks.useNamespace('FormTypesCascader_mobile')
+const onClear = () => {
+  props.data.options.defaultValue = []
+}
+</script>
+<template>
+  <van-field
+    readonly
+    :class="[ns.b()]"
+    v-bind="params"
+  >
+    <template #input>
+      <el-cascader
+        v-model="data.options.defaultValue"
+        v-bind="params"
+        :popper-class="ns.e('cascader')"
+      />
+    </template>
+    <template v-if="data.options.defaultValue && data.options.defaultValue.length && params.clearable" #button>
+      <van-icon @touchstart.stop="onClear" name="clear" />
+    </template>
+  </van-field>
+</template>
+
+<style scoped>
+
+</style>

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels