Browse Source

feat: 新增iframe 展示功能

lanceJiang 1 year ago
parent
commit
7ad4e0f0a1

+ 164 - 190
src/components/packages/formEditor/components/Panels/Config/components/GlobalConfigPanel.vue

@@ -10,20 +10,14 @@ import PanelsConfigComponentsTypeComponent from './TypeComponent.vue'
 import PanelsConfigComponentsLogicComponent from './LogicComponent.vue'
 import utils from '@ER/utils'
 export default {
-  name: 'GlobalConfigPanel',
-  inheritAttrs: false,
-  customOptions: {}
+	name: 'GlobalConfigPanel',
+	inheritAttrs: false,
+	customOptions: {}
 }
 </script>
 <script setup>
-const {
-  target,
-  state,
-  isPc
-} = hooks.useTarget()
-const {
-  t
-} = hooks.useI18n()
+const { target, state, isPc } = hooks.useTarget()
+const { t } = hooks.useI18n()
 const ER = inject('Everright')
 const ns = hooks.useNamespace('GlobalConfigPanel')
 const compareKeys = ['labelPosition', 'completeButton']
@@ -32,200 +26,180 @@ const buttonRef = ref()
 const popoverRef = ref()
 const radio1 = ref('pc')
 const handleModelValue = (type, value) => {
-  const platforms = target.value.isSync ? ['pc', 'mobile'] : [state.platform]
-  platforms.forEach((e) => {
-    _.set(target.value, `${e}.${type}`, value)
-  })
+	const platforms = target.value.isSync ? ['pc', 'mobile'] : [state.platform]
+	platforms.forEach(e => {
+		_.set(target.value, `${e}.${type}`, value)
+	})
 }
 const popperPaneRef = computed(() => {
-  return _.get(unref(popoverRef), 'popperRef.contentRef', '')
+	return _.get(unref(popoverRef), 'popperRef.contentRef', '')
 })
 let handleConfirm = ''
 const handleBeforeChange = () => {
-  return new Promise((resolve, reject) => {
-    const pcObj = _.pick(unref(target).pc, compareKeys)
-    const mobileObj = _.pick(unref(target).mobile, compareKeys)
-    if (_.isEqual(pcObj, mobileObj)) {
-      resolve(true)
-    } else {
-      visible.value = true
-      handleConfirm = resolve
-    }
-  })
+	return new Promise((resolve, reject) => {
+		const pcObj = _.pick(unref(target).pc, compareKeys)
+		const mobileObj = _.pick(unref(target).mobile, compareKeys)
+		if (_.isEqual(pcObj, mobileObj)) {
+			resolve(true)
+		} else {
+			visible.value = true
+			handleConfirm = resolve
+		}
+	})
 }
 const onClickOutside = () => {
-  visible.value = false
+	visible.value = false
 }
-const handleClick = (type) => {
-  visible.value = false
-  switch (type) {
-    case 2:
-      const targetObj = target.value[radio1.value === 'pc' ? 'mobile' : 'pc']
-      const sourceObj = _.pick(unref(target)[radio1.value], compareKeys)
-      Object.assign(targetObj, _.cloneDeep(sourceObj))
-      handleConfirm(true)
-      break
-  }
+const handleClick = type => {
+	visible.value = false
+	switch (type) {
+		case 2:
+			const targetObj = target.value[radio1.value === 'pc' ? 'mobile' : 'pc']
+			const sourceObj = _.pick(unref(target)[radio1.value], compareKeys)
+			Object.assign(targetObj, _.cloneDeep(sourceObj))
+			handleConfirm(true)
+			break
+	}
 }
 const options0 = computed(() => {
-  return [
-    {
-      label: t('er.config.globalConfig.labelPosition.top'),
-      value: 'top',
-      icon: 'labelStructureP1'
-    },
-    {
-      label: t('er.config.globalConfig.labelPosition.left'),
-      value: 'left',
-      icon: 'labelStructureP2'
-    },
-    {
-      label: t('er.config.globalConfig.labelPosition.right'),
-      value: 'right',
-      icon: 'labelStructureP3'
-    }
-  ]
+	return [
+		{
+			label: t('er.config.globalConfig.labelPosition.top'),
+			value: 'top',
+			icon: 'labelStructureP1'
+		},
+		{
+			label: t('er.config.globalConfig.labelPosition.left'),
+			value: 'left',
+			icon: 'labelStructureP2'
+		},
+		{
+			label: t('er.config.globalConfig.labelPosition.right'),
+			value: 'right',
+			icon: 'labelStructureP3'
+		}
+	]
 })
 const options1 = computed(() => {
-  return [
-    {
-      label: t('er.config.globalConfig.componentSize.large'),
-      value: 'large'
-    },
-    {
-      label: t('er.config.globalConfig.componentSize.default'),
-      value: 'default'
-    },
-    {
-      label: t('er.config.globalConfig.componentSize.small'),
-      value: 'small'
-    }
-  ]
+	return [
+		{
+			label: t('er.config.globalConfig.componentSize.large'),
+			value: 'large'
+		},
+		{
+			label: t('er.config.globalConfig.componentSize.default'),
+			value: 'default'
+		},
+		{
+			label: t('er.config.globalConfig.componentSize.small'),
+			value: 'small'
+		}
+	]
 })
 const handleTypeListener = ({ property, data }) => {
-  switch (property) {
-    case 'labelPosition':
-      handleModelValue('labelPosition', data.value)
-      break
-    case 'size':
-      target.value[state.platform].size = data.value
-      break
-  }
+	switch (property) {
+		case 'labelPosition':
+			handleModelValue('labelPosition', data.value)
+			break
+		case 'size':
+			target.value[state.platform].size = data.value
+			break
+	}
 }
 </script>
 <template>
-  <div>
-    <el-popover
-      virtual-triggering
-      :visible="visible"
-      ref="popoverRef"
-      :virtual-ref="buttonRef"
-      :width="200">
-      <div>
-        <div :class="[ns.e('syncContent')]">
-          <el-icon color="#f90">
-            <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-ea893728=""><path fill="currentColor" d="M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896zm23.744 191.488c-52.096 0-92.928 14.784-123.2 44.352-30.976 29.568-45.76 70.4-45.76 122.496h80.256c0-29.568 5.632-52.8 17.6-68.992 13.376-19.712 35.2-28.864 66.176-28.864 23.936 0 42.944 6.336 56.32 19.712 12.672 13.376 19.712 31.68 19.712 54.912 0 17.6-6.336 34.496-19.008 49.984l-8.448 9.856c-45.76 40.832-73.216 70.4-82.368 89.408-9.856 19.008-14.08 42.24-14.08 68.992v9.856h80.96v-9.856c0-16.896 3.52-31.68 10.56-45.76 6.336-12.672 15.488-24.64 28.16-35.2 33.792-29.568 54.208-48.576 60.544-55.616 16.896-22.528 26.048-51.392 26.048-86.592 0-42.944-14.08-76.736-42.24-101.376-28.16-25.344-65.472-37.312-111.232-37.312zm-12.672 406.208a54.272 54.272 0 0 0-38.72 14.784 49.408 49.408 0 0 0-15.488 38.016c0 15.488 4.928 28.16 15.488 38.016A54.848 54.848 0 0 0 523.072 768c15.488 0 28.16-4.928 38.72-14.784a51.52 51.52 0 0 0 16.192-38.72 51.968 51.968 0 0 0-15.488-38.016 55.936 55.936 0 0 0-39.424-14.784z"></path></svg>
-          </el-icon>
-          {{ t('er.config.globalConfig.sync.warning') }}
-        </div>
-        <el-radio-group :class="[ns.e('syncType')]" v-model="radio1" class="ml-4">
-          <el-radio label="pc">pc</el-radio>
-          <el-radio label="mobile">mobile</el-radio>
-        </el-radio-group>
-      </div>
-      <div :class="[ns.e('syncActions')]">
-        <el-button
-          size="small"
-          :text="true"
-          @click="handleClick(1)"
-        >{{t('er.public.cancel')}}</el-button>
-        <el-button
-          size="small"
-          type="primary"
-          @click="handleClick(2)"
-        >
-          {{ t('er.public.confirm') }}
-        </el-button>
-      </div>
-    </el-popover>
-    <el-form-item
-      :label="t('er.config.globalConfig.sync.label')"
-      label-position="left"
-      v-bind="utils.addTestId('configPanel:isSync')"
-    >
-      <el-switch
-        ref="buttonRef"
-        v-click-outside:[popperPaneRef]="onClickOutside"
-        :before-change="handleBeforeChange"
-        v-model="target.isSync"/>
-    </el-form-item>
-    <PanelsConfigComponentsTypeComponent
-      v-if="isPc"
-      @listener="handleTypeListener"
-      property="size"
-      :layoutType="2"
-      :label="t('er.config.globalConfig.componentSize.label')"
-      :val="target[state.platform].size"
-      :nodes="options1"
-      v-bind="utils.addTestId('configPanel:size')"
-    />
-    <PanelsConfigComponentsTypeComponent
-      @listener="handleTypeListener"
-      property="labelPosition"
-      :label="t('er.config.globalConfig.labelPosition.label')"
-      :height="66"
-      :fontSize="80"
-      :val="target[state.platform].labelPosition"
-      :nodes="options0"
-      v-bind="utils.addTestId('configPanel:labelPosition')"
-    />
-    <el-form-item
-      v-if="ER.props.isShowCompleteButton"
-      :label="t('er.public.button')"
-      v-bind="utils.addTestId('configPanel:completeButton')"
-    >
-      <div style="width: 100%;">
-        <div>
-          <CompleteButton mode="preview"/>
-        </div>
-        <div>
-          <el-row :gutter="8">
-            <el-col>
-              <el-form-item :label="t('er.public.text')">
-                <el-input
-                  :model-value="target[state.platform].completeButton.text"
-                  show-word-limit
-                  :maxlength="20"
-                  @update:modelValue="(e) => handleModelValue('completeButton.text', e)"
-                ></el-input>
-              </el-form-item>
-            </el-col>
-          </el-row>
-          <el-row :gutter="8" style="margin-top: 20px;">
-            <el-col :span="12">
-              <el-form-item :label="t('er.public.color')">
-                <el-color-picker
-                  :popper-class="ns.e('completeButtonColor')"
-                  :model-value="target[state.platform].completeButton.color"
-                  @update:modelValue="(e) => handleModelValue('completeButton.color', e)"
-                  show-alpha
-                />
-              </el-form-item>
-            </el-col>
-            <el-col :span="12">
-              <el-form-item :label="t('er.public.backgroundColor')">
-                <el-color-picker
-                  :popper-class="ns.e('completeButtonColor')"
-                  :model-value="target[state.platform].completeButton.backgroundColor"
-                  @update:modelValue="(e) => handleModelValue('completeButton.backgroundColor', e)"
-                  show-alpha
-                />
-              </el-form-item>
-            </el-col>
-          </el-row>
-        </div>
-      </div>
-    </el-form-item>
-    <PanelsConfigComponentsLogicComponent/>
-  </div>
+	<div>
+		<el-popover ref="popoverRef" virtual-triggering :visible="visible" :virtual-ref="buttonRef" :width="200">
+			<div>
+				<div :class="[ns.e('syncContent')]">
+					<el-icon color="#f90">
+						<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-ea893728="">
+							<path
+								fill="currentColor"
+								d="M512 64a448 448 0 1 1 0 896 448 448 0 0 1 0-896zm23.744 191.488c-52.096 0-92.928 14.784-123.2 44.352-30.976 29.568-45.76 70.4-45.76 122.496h80.256c0-29.568 5.632-52.8 17.6-68.992 13.376-19.712 35.2-28.864 66.176-28.864 23.936 0 42.944 6.336 56.32 19.712 12.672 13.376 19.712 31.68 19.712 54.912 0 17.6-6.336 34.496-19.008 49.984l-8.448 9.856c-45.76 40.832-73.216 70.4-82.368 89.408-9.856 19.008-14.08 42.24-14.08 68.992v9.856h80.96v-9.856c0-16.896 3.52-31.68 10.56-45.76 6.336-12.672 15.488-24.64 28.16-35.2 33.792-29.568 54.208-48.576 60.544-55.616 16.896-22.528 26.048-51.392 26.048-86.592 0-42.944-14.08-76.736-42.24-101.376-28.16-25.344-65.472-37.312-111.232-37.312zm-12.672 406.208a54.272 54.272 0 0 0-38.72 14.784 49.408 49.408 0 0 0-15.488 38.016c0 15.488 4.928 28.16 15.488 38.016A54.848 54.848 0 0 0 523.072 768c15.488 0 28.16-4.928 38.72-14.784a51.52 51.52 0 0 0 16.192-38.72 51.968 51.968 0 0 0-15.488-38.016 55.936 55.936 0 0 0-39.424-14.784z"
+							></path>
+						</svg>
+					</el-icon>
+					{{ t('er.config.globalConfig.sync.warning') }}
+				</div>
+				<el-radio-group v-model="radio1" :class="[ns.e('syncType')]" class="ml-4">
+					<el-radio label="pc">pc</el-radio>
+					<el-radio label="mobile">mobile</el-radio>
+				</el-radio-group>
+			</div>
+			<div :class="[ns.e('syncActions')]">
+				<el-button size="small" :text="true" @click="handleClick(1)">{{ t('er.public.cancel') }}</el-button>
+				<el-button size="small" type="primary" @click="handleClick(2)">
+					{{ t('er.public.confirm') }}
+				</el-button>
+			</div>
+		</el-popover>
+		<el-form-item :label="t('er.config.globalConfig.sync.label')" label-position="left" v-bind="utils.addTestId('configPanel:isSync')">
+			<el-switch ref="buttonRef" v-model="target.isSync" v-click-outside:[popperPaneRef]="onClickOutside" :before-change="handleBeforeChange" />
+		</el-form-item>
+		<PanelsConfigComponentsTypeComponent
+			v-if="isPc"
+			property="size"
+			:layoutType="2"
+			:label="t('er.config.globalConfig.componentSize.label')"
+			:val="target[state.platform].size"
+			:nodes="options1"
+			v-bind="utils.addTestId('configPanel:size')"
+			@listener="handleTypeListener"
+		/>
+		<PanelsConfigComponentsTypeComponent
+			property="labelPosition"
+			:label="t('er.config.globalConfig.labelPosition.label')"
+			:height="66"
+			:fontSize="80"
+			:val="target[state.platform].labelPosition"
+			:nodes="options0"
+			v-bind="utils.addTestId('configPanel:labelPosition')"
+			@listener="handleTypeListener"
+		/>
+		<el-form-item v-if="ER.props.isShowCompleteButton" :label="t('er.public.button')" v-bind="utils.addTestId('configPanel:completeButton')">
+			<div style="width: 100%">
+				<div>
+					<CompleteButton mode="preview" />
+				</div>
+				<div>
+					<el-row :gutter="8">
+						<el-col>
+							<el-form-item :label="t('er.public.text')">
+								<el-input
+									:model-value="target[state.platform].completeButton.text"
+									show-word-limit
+									:maxlength="20"
+									@update:modelValue="e => handleModelValue('completeButton.text', e)"
+								></el-input>
+							</el-form-item>
+						</el-col>
+					</el-row>
+					<el-row :gutter="8" style="margin-top: 20px">
+						<el-col :span="12">
+							<el-form-item :label="t('er.public.color')">
+								<el-color-picker
+									:popper-class="ns.e('completeButtonColor')"
+									:model-value="target[state.platform].completeButton.color"
+									show-alpha
+									@update:modelValue="e => handleModelValue('completeButton.color', e)"
+								/>
+							</el-form-item>
+						</el-col>
+						<el-col :span="12">
+							<el-form-item :label="t('er.public.backgroundColor')">
+								<el-color-picker
+									:popper-class="ns.e('completeButtonColor')"
+									:model-value="target[state.platform].completeButton.backgroundColor"
+									show-alpha
+									@update:modelValue="e => handleModelValue('completeButton.backgroundColor', e)"
+								/>
+							</el-form-item>
+						</el-col>
+					</el-row>
+				</div>
+			</div>
+		</el-form-item>
+		<PanelsConfigComponentsLogicComponent />
+	</div>
 </template>

+ 160 - 159
src/components/packages/formEditor/components/Panels/Config/index.vue

@@ -7,193 +7,194 @@ import Icon from '@ER/icon'
 import PanelsConfigComponentsPropsPanel from '@ER/formEditor/components/Panels/Config/components/PropsPanel.vue'
 import GlobalConfigPanel from './components/GlobalConfigPanel.vue'
 export default {
-  name: 'Config',
-  inheritAttrs: false,
-  customOptions: {}
+	name: 'Config',
+	inheritAttrs: false,
+	customOptions: {}
 }
 </script>
 <script setup>
 const props = defineProps({
-  mode: {
-    type: String,
-    default: 'editor'
-  }
+	mode: {
+		type: String,
+		default: 'editor'
+	}
 })
 const {
-  state,
-  isSelectAnyElement,
-  isSelectField,
-  isSelectRoot,
-  setSelection,
-  type,
-  checkTypeBySelected,
-  target,
-  isSelectGrid,
-  isSelectTabs,
-  isSelectCollapse,
-  isSelectTable
+	state,
+	isSelectAnyElement,
+	isSelectField,
+	isSelectRoot,
+	setSelection,
+	type,
+	checkTypeBySelected,
+	target,
+	isSelectGrid,
+	isSelectTabs,
+	isSelectCollapse,
+	isSelectTable
 } = hooks.useTarget()
 const ER = inject('Everright')
-const {
-  t
-} = hooks.useI18n()
+const { t } = hooks.useI18n()
 const activeName0 = ref('props')
 const isShow = computed(() => {
-  return !_.isEmpty(state.selected) && state.selected.type !== 'grid'
+	return !_.isEmpty(state.selected) && state.selected.type !== 'grid'
 })
 const ns = hooks.useNamespace('Config')
 const form = ref()
-const handleChangePanel = (panel) => {
-  // activeName0.value = panel
+const handleChangePanel = panel => {
+	// activeName0.value = panel
 }
 const validator = (rule, value, callback) => {
-  const newValue = value.trim()
-  const fn = (type) => {
-    switch (type) {
-      case 0:
-        callback(new Error(t('er.validateMsg.required')))
-        break
-      case 1:
-        callback()
-        break
-      case 2:
-        callback(new Error(t('er.validateMsg.idUnique')))
-        break
+	const newValue = value.trim()
+	const fn = type => {
+		switch (type) {
+			case 0:
+				callback(new Error(t('er.validateMsg.required')))
+				break
+			case 1:
+				callback()
+				break
+			case 2:
+				callback(new Error(t('er.validateMsg.idUnique')))
+				break
 			case 3:
 				callback(new Error(t('er.validateMsg.chartAndNumber')))
 				break
-    }
-  }
-  if (props.mode === 'editor') {
-    state.validator(target.value, fn)
-  } else {
-    if (utils.isNull(newValue)) {
-      fn(0)
-    } else {
-      fn(1)
-    }
-  }
+		}
+	}
+	if (props.mode === 'editor') {
+		state.validator(target.value, fn)
+	} else {
+		if (utils.isNull(newValue)) {
+			fn(0)
+		} else {
+			fn(1)
+		}
+	}
 
-  // if (newValue === '' || newValue === null || newValue === undefined) {
-  //   callback(new Error('必填'))
-  //   return false
-  // } else {
-  //   state.validator(newValue, (valid) => {
-  //     if (valid) {
-  //       callback()
-  //     } else {
-  //       callback(new Error('重复'))
-  //     }
-  //   })
-  //
-  // }
+	// if (newValue === '' || newValue === null || newValue === undefined) {
+	//   callback(new Error('必填'))
+	//   return false
+	// } else {
+	//   state.validator(newValue, (valid) => {
+	//     if (valid) {
+	//       callback()
+	//     } else {
+	//       callback(new Error('重复'))
+	//     }
+	//   })
+	//
+	// }
 }
 onMounted(() => {
-  form.value.validate()
+	form.value.validate()
 })
 const rules = reactive({
-  key: [
-    {
-      required: true,
-      trigger: 'blur',
-      validator
-    }
-  ]
+	key: [
+		{
+			required: true,
+			trigger: 'blur',
+			validator
+		}
+	]
 })
 const bars = computed(() => {
-  let nodes = ['root']
-  let result = []
-  // if (!_.isEmpty(target.value)) {
-  //   result = result.concat(target.value.context.parents)
-  // }
-  if (!isSelectRoot.value) {
-    nodes = nodes.concat(target.value.context.parents.filter(e => !/^(inline|tr)$/.test(e.type)))
-  }
-  if (nodes.length > 4) {
-    result.push(nodes[0])
-    result.push({
-      value: 'placeholder'
-    })
-    result.push(nodes[nodes.length - 2])
-    result.push(nodes[nodes.length - 1])
-  } else {
-    result = nodes
-  }
-  return result.map(node => {
-    const result = {
-      // eslint-disable-next-line
+	let nodes = ['root']
+	let result = []
+	// if (!_.isEmpty(target.value)) {
+	//   result = result.concat(target.value.context.parents)
+	// }
+	if (!isSelectRoot.value) {
+		nodes = nodes.concat(target.value.context.parents.filter(e => !/^(inline|tr)$/.test(e.type)))
+	}
+	if (nodes.length > 4) {
+		result.push(nodes[0])
+		result.push({
+			value: 'placeholder'
+		})
+		result.push(nodes[nodes.length - 2])
+		result.push(nodes[nodes.length - 1])
+	} else {
+		result = nodes
+	}
+	return result.map(node => {
+		const result = {
+			// eslint-disable-next-line
       node: node,
-      label: ''
-    }
-    if (node === 'root') {
-      result.label = t('er.panels.config')
-    } else if (node.value !== 'placeholder') {
-      if (/^(col|collapseCol|tabsCol|td)$/.test(node.type)) {
-        result.label = t(`er.layout.${node.type}`)
-      } else {
-        result.label = utils.fieldLabel(t, node)
-      }
-    }
-    return result
-  })
+			label: ''
+		}
+		if (node === 'root') {
+			result.label = t('er.panels.config')
+		} else if (node.value !== 'placeholder') {
+			if (/^(col|collapseCol|tabsCol|td)$/.test(node.type)) {
+				result.label = t(`er.layout.${node.type}`)
+			} else {
+				result.label = utils.fieldLabel(t, node)
+			}
+		}
+		return result
+	})
 })
-const handleBreadcrumbClick = (item) => {
-  if (item !== 'root') {
-    setSelection(item)
-  } else {
-    setSelection('root')
-  }
+const handleBreadcrumbClick = item => {
+	if (item !== 'root') {
+		setSelection(item)
+	} else {
+		setSelection('root')
+	}
 }
-watch(target, () => {
-  if (isSelectRoot.value) {
-    activeName0.value = 'root'
-  } else {
-    activeName0.value = 'props'
-  }
-}, {
-  immediate: true
-})
+watch(
+	target,
+	() => {
+		if (isSelectRoot.value) {
+			activeName0.value = 'root'
+		} else {
+			activeName0.value = 'props'
+		}
+	},
+	{
+		immediate: true
+	}
+)
 </script>
 <template>
-  <el-aside :class="[ns.b()]" :width="ER.props.configPanelWidth">
-    <el-breadcrumb
-      :class="[ns.e('breadcrumb')]"
-      :separator-icon="() => (
-        h('svg', {
-          viewBox: '0 0 1024 1024',
-          xmlns: 'http://www.w3.org/2000/svg'
-        },
-         h('path', {
-           fill: 'currentColor',
-           d: 'M340.864 149.312a30.592 30.592 0 0 0 0 42.752L652.736 512 340.864 831.872a30.592 30.592 0 0 0 0 42.752 29.12 29.12 0 0 0 41.728 0L714.24 534.336a32 32 0 0 0 0-44.672L382.592 149.376a29.12 29.12 0 0 0-41.728 0z'
-         })
-        )
-        )"
-      v-bind="utils.addTestId('configPanel:breadcrumb')"
-    >
-      <el-breadcrumb-item
-        @click="(index !== bars.length - 1 && item.node.value !== 'placeholder') && handleBreadcrumbClick(item.node)" v-for="(item, index) in bars" :key="index">
-        {{item.node.value === 'placeholder' ? '...' : item.label}}
-      </el-breadcrumb-item>
-    </el-breadcrumb>
-    <el-form
-      ref="form"
-      :model="target"
-      :rules="rules"
-      label-width="120px"
-      label-position="top">
-      <el-scrollbar>
-        <div :class="[ns.e('wrap')]">
-          <div v-if="isSelectAnyElement">
-            <PanelsConfigComponentsPropsPanel
-              :key="target.id"
-            />
-          </div>
-          <div v-if="isSelectRoot">
-            <GlobalConfigPanel></GlobalConfigPanel>
-          </div>
-        </div>
-      </el-scrollbar>
-    </el-form>
-  </el-aside>
+	<el-aside :class="[ns.b()]" :width="ER.props.configPanelWidth">
+		<el-breadcrumb
+			:class="[ns.e('breadcrumb')]"
+			:separator-icon="
+				() =>
+					h(
+						'svg',
+						{
+							viewBox: '0 0 1024 1024',
+							xmlns: 'http://www.w3.org/2000/svg'
+						},
+						h('path', {
+							fill: 'currentColor',
+							d: 'M340.864 149.312a30.592 30.592 0 0 0 0 42.752L652.736 512 340.864 831.872a30.592 30.592 0 0 0 0 42.752 29.12 29.12 0 0 0 41.728 0L714.24 534.336a32 32 0 0 0 0-44.672L382.592 149.376a29.12 29.12 0 0 0-41.728 0z'
+						})
+					)
+			"
+			v-bind="utils.addTestId('configPanel:breadcrumb')"
+		>
+			<el-breadcrumb-item
+				v-for="(item, index) in bars"
+				:key="index"
+				@click="index !== bars.length - 1 && item.node.value !== 'placeholder' && handleBreadcrumbClick(item.node)"
+			>
+				{{ item.node.value === 'placeholder' ? '...' : item.label }}
+			</el-breadcrumb-item>
+		</el-breadcrumb>
+		<el-form ref="form" :model="target" :rules="rules" label-width="120px" label-position="top">
+			<el-scrollbar>
+				<div :class="[ns.e('wrap')]">
+					<div v-if="isSelectAnyElement">
+						<PanelsConfigComponentsPropsPanel :key="target.id" />
+					</div>
+					<div v-if="isSelectRoot">
+						<GlobalConfigPanel></GlobalConfigPanel>
+					</div>
+				</div>
+			</el-scrollbar>
+		</el-form>
+	</el-aside>
 </template>

+ 18 - 0
src/components/packages/formEditor/componentsConfig.js

@@ -662,6 +662,24 @@ export const fieldsConfig = [
 					required: false,
 					disabled: false
 				}
+			},
+			{
+				type: 'iframe', // 定义的itemType
+				label: '网页iframe', // 名称
+				icon: 'iframe', // icon 定义 from 'src/components/packages/icon/svg *.svg'
+				key: '',
+				id: '',
+				options: {
+					// 额外配置
+					defaultValue: '',
+					placeholder: '',
+					labelWidth: 100, // labelWidth
+					height: 200, // iframe高度
+					src: '', // iframe地址
+					isShowLabel: true,
+					required: false,
+					disabled: false
+				}
 			}
 		]
 	}

+ 4 - 1
src/components/packages/formEditor/locale/en.js

@@ -28,7 +28,8 @@ export default {
 			container: 'Container',
 			field: 'Basic field',
 			defaultField: 'Default field',
-			subform: 'Sub-form'
+			subform: 'Sub-form',
+			iframe: 'Web Iframe'
 		},
 		layout: {
 			tabsCol: 'Tab panel',
@@ -98,6 +99,8 @@ export default {
 				placeholder: 'Placeholder',
 				dictCode: 'Dict Code',
 				brushColor: 'Brush color',
+				iframeHeight: 'Iframe Height',
+				url: 'Url Address',
 				format: 'Format',
 				dateType: 'Date type',
 				layout: {

+ 4 - 1
src/components/packages/formEditor/locale/zh-cn.js

@@ -28,7 +28,8 @@ export default {
 			container: '容器',
 			field: '基础字段',
 			defaultField: '预设字段',
-			subform: '子表单'
+			subform: '子表单',
+			iframe: '网页Iframe'
 		},
 		layout: {
 			tabsCol: '标签面板',
@@ -98,6 +99,8 @@ export default {
 				placeholder: '提示文字',
 				dictCode: '字典Code',
 				brushColor: '画笔颜色',
+				iframeHeight: 'Iframe高度',
+				url: 'Url地址',
 				format: '显示格式',
 				dateType: '日期类型',
 				layout: {

+ 1 - 1
src/components/packages/icon/svg/ID.svg

@@ -1 +1 @@
-<svg viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><g class="ID"><path class="Union" d="M2 3.167a.167.167 0 0 0-.167.166v9.334c0 .092.075.166.167.166h12a.167.167 0 0 0 .167-.166V3.333A.167.167 0 0 0 14 3.167H2Zm-1.167.166c0-.644.523-1.166 1.167-1.166h12c.645 0 1.167.522 1.167 1.166v9.334c0 .644-.522 1.166-1.167 1.166H2a1.167 1.167 0 0 1-1.167-1.166V3.333Zm3.537 2.37a1.833 1.833 0 0 1 2.653 2.53 2.5 2.5 0 0 1 1.143 2.1.5.5 0 0 1-1 0 1.5 1.5 0 1 0-3 0 .5.5 0 0 1-1 0 2.5 2.5 0 0 1 1.144-2.1 1.833 1.833 0 0 1 .06-2.53Zm1.297.464a.833.833 0 1 0 0 1.666.833.833 0 0 0 0-1.666Zm3.666 0a.5.5 0 1 0 0 1H12a.5.5 0 1 0 0-1H9.333ZM10 8.833a.5.5 0 1 0 0 1h2a.5.5 0 1 0 0-1h-2Z"/></g></svg>
+<svg viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><g class="ID"><path class="Union" d="M2 3.167a.167.167 0 0 0-.167.166v9.334c0 .092.075.166.167.166h12a.167.167 0 0 0 .167-.166V3.333A.167.167 0 0 0 14 3.167H2Zm-1.167.166c0-.644.523-1.166 1.167-1.166h12c.645 0 1.167.522 1.167 1.166v9.334c0 .644-.522 1.166-1.167 1.166H2a1.167 1.167 0 0 1-1.167-1.166V3.333Zm3.537 2.37a1.833 1.833 0 0 1 2.653 2.53 2.5 2.5 0 0 1 1.143 2.1.5.5 0 0 1-1 0 1.5 1.5 0 1 0-3 0 .5.5 0 0 1-1 0 2.5 2.5 0 0 1 1.144-2.1 1.833 1.833 0 0 1 .06-2.53Zm1.297.464a.833.833 0 1 0 0 1.666.833.833 0 0 0 0-1.666Zm3.666 0a.5.5 0 1 0 0 1H12a.5.5 0 1 0 0-1H9.333ZM10 8.833a.5.5 0 1 0 0 1h2a.5.5 0 1 0 0-1h-2Z"/></g></svg>

+ 1 - 1
src/components/packages/icon/svg/collapse.svg

@@ -1 +1 @@
-<svg viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><g class="collapse"><path class="Union" d="M1.5 3A1.5 1.5 0 0 1 3 1.5h10A1.5 1.5 0 0 1 14.5 3v10a1.5 1.5 0 0 1-1.5 1.5H3A1.5 1.5 0 0 1 1.5 13V3Zm12 0a.5.5 0 0 0-.5-.5H3a.5.5 0 0 0-.5.5v3h11V3Zm0 4h-11v6a.5.5 0 0 0 .5.5h10a.5.5 0 0 0 .5-.5V7Zm-3.189-3.752a.5.5 0 1 0-.707.707l.849.849a.8.8 0 0 0 1.13 0l.85-.849a.5.5 0 0 0-.708-.707l-.707.707-.707-.707Z"/></g></svg>
+<svg viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><g><path d="M1.5 3A1.5 1.5 0 0 1 3 1.5h10A1.5 1.5 0 0 1 14.5 3v10a1.5 1.5 0 0 1-1.5 1.5H3A1.5 1.5 0 0 1 1.5 13V3Zm12 0a.5.5 0 0 0-.5-.5H3a.5.5 0 0 0-.5.5v3h11V3Zm0 4h-11v6a.5.5 0 0 0 .5.5h10a.5.5 0 0 0 .5-.5V7Zm-3.189-3.752a.5.5 0 1 0-.707.707l.849.849a.8.8 0 0 0 1.13 0l.85-.849a.5.5 0 0 0-.708-.707l-.707.707-.707-.707Z"/></g></svg>

+ 1 - 0
src/components/packages/icon/svg/iframe.svg

@@ -0,0 +1 @@
+<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="currentColor" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M896 85.333333H128a85.333333 85.333333 0 0 0-85.333333 85.333334v682.666666a85.333333 85.333333 0 0 0 85.333333 85.333334h768a85.333333 85.333333 0 0 0 85.333333-85.333334V170.666667a85.333333 85.333333 0 0 0-85.333333-85.333334zM469.333333 746.666667L405.333333 810.666667 213.333333 618.666667 405.333333 426.666667l64 64-128 128 128 128z m149.333334 64L554.666667 746.666667l128-128-128-128 64-64 192 192-192 192zM896 298.666667H128V170.666667h768v128z"></path></svg>

+ 79 - 0
src/components/packages/theme/formEditor/FormTypes/Iframe.scss

@@ -0,0 +1,79 @@
+@include b(FormTypesIframe_pc) {
+  position: relative;
+  width: 100%;
+	background-color: var(--el-input-bg-color, var(--el-fill-color-blank));
+	border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
+	border: 1px solid var(--el-input-border-color, var(--el-border-color));
+	overflow: hidden;
+	.actions {
+		//padding: 8px;
+		//background-color: var(--el-fill-color-lighter);
+		/*display: flex;
+		justify-content: flex-end;
+		align-items: center;*/
+		position: absolute;
+		//z-index: 999;
+		right: -10px;
+		top: -10px;
+		.icon-button {
+			width: 36px;
+			height: 36px;
+			padding: 0;
+			border-radius: 0 0 0 32px;
+			font-size: 16px;
+		}
+	}
+  @include e(clear) {
+    color: $primary-color;
+    position: absolute;
+    z-index: 1;
+    right: 10px;
+    top: 10px;
+    cursor: pointer;
+    font-size: 30px;
+  }
+  @include e(noData) {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+  @include e(canvas) {
+    border: 1px dashed #d3d3d3;
+    width: 100%;
+    height: 400px;
+  }
+}
+/*@include b(FormTypesIframe_mobile) {
+  @include e(canvasWrap) {
+    border: 1px dashed #d3d3d3;
+    box-sizing: border-box;
+    width: 100%;
+    height: calc(100vh - 50px);
+    position: relative;
+    &>canvas {
+      width: 100%;
+      height: 100%;
+    }
+  }
+  @include e(clear) {
+    color: $primary-color;
+    position: absolute;
+    z-index: 1;
+    right: 10px;
+    top: 10px;
+    cursor: pointer;
+    font-size: 30px;
+  }
+}*/
+.FormTypesIframe--maximize {
+	position: fixed;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	max-width: 100%;
+	background-color: var(--el-fill-color-extra-light) !important;
+	z-index: 2000;
+}

+ 1 - 0
src/components/packages/theme/formEditor/index.scss

@@ -19,6 +19,7 @@ $namespace: 'Everright-formEditor';
 @import './DragGableLayout';
 @import './SelectElement';
 @import './FormTypes/Signature';
+@import './FormTypes/Iframe';
 @import './FormTypes/Radio';
 @import './FormTypes/Checkbox';
 @import './FormTypes/Cascader';