mirror of
https://github.com/vform666/variant-form3-vite.git
synced 2025-06-21 09:35:58 +08:00
Vue 3版本初次提交,继续测试中。
This commit is contained in:
23
src/extension/extension-helper.js
Normal file
23
src/extension/extension-helper.js
Normal file
@ -0,0 +1,23 @@
|
||||
import {
|
||||
addContainerWidgetSchema,
|
||||
addBasicFieldSchema,
|
||||
addAdvancedFieldSchema,
|
||||
addCustomWidgetSchema
|
||||
} from '@/components/form-designer/widget-panel/widgetsConfig'
|
||||
import {
|
||||
registerCommonProperty,
|
||||
registerAdvancedProperty,
|
||||
registerEventProperty
|
||||
} from '@/components/form-designer/setting-panel/propertyRegister'
|
||||
|
||||
|
||||
export default {
|
||||
addContainerWidgetSchema,
|
||||
addBasicFieldSchema,
|
||||
addAdvancedFieldSchema,
|
||||
addCustomWidgetSchema,
|
||||
|
||||
registerCommonProperty,
|
||||
registerAdvancedProperty,
|
||||
registerEventProperty,
|
||||
}
|
112
src/extension/extension-loader.js
Normal file
112
src/extension/extension-loader.js
Normal file
@ -0,0 +1,112 @@
|
||||
//import { vfApp } from '@/utils/create-app'
|
||||
|
||||
import {
|
||||
addContainerWidgetSchema,
|
||||
addCustomWidgetSchema
|
||||
} from '@/components/form-designer/widget-panel/widgetsConfig'
|
||||
import * as PERegister from '@/components/form-designer/setting-panel/propertyRegister'
|
||||
import * as PEFactory from '@/components/form-designer/setting-panel/property-editor-factory.jsx'
|
||||
|
||||
import {cardSchema} from "@/extension/samples/extension-schema"
|
||||
import CardWidget from '@/extension/samples/card/card-widget'
|
||||
import CardItem from '@/extension/samples/card/card-item'
|
||||
import {registerCWGenerator} from '@/utils/sfc-generator'
|
||||
import {cardTemplateGenerator} from '@/extension/samples/extension-sfc-generator'
|
||||
|
||||
import {alertSchema} from "@/extension/samples/extension-schema"
|
||||
import AlertWidget from '@/extension/samples/alert/alert-widget'
|
||||
import {registerFWGenerator} from '@/utils/sfc-generator'
|
||||
import {alertTemplateGenerator} from '@/extension/samples/extension-sfc-generator'
|
||||
|
||||
export const loadExtension = function (app) {
|
||||
|
||||
/**
|
||||
* 加载容器组件步骤:
|
||||
* 1. 加载组件Json Schema;
|
||||
* 2. 全局注册容器组件,容器组件有两种状态——设计期和运行期,故需要注册两个组件;
|
||||
* 3. 全局注册属性编辑器组件(基本属性、高级属性、事件属性);
|
||||
* 4. 注册容器组件的代码生成器;
|
||||
* 5. 加载完毕。
|
||||
*/
|
||||
addContainerWidgetSchema(cardSchema) //加载组件Json Schema
|
||||
/* -------------------------------------------------- */
|
||||
app.component(CardWidget.name, CardWidget) //注册设计期的容器组件
|
||||
app.component(CardItem.name, CardItem) //注册运行期的容器组件
|
||||
/* -------------------------------------------------- */
|
||||
PERegister.registerCPEditor(app, 'card-folded', 'card-folded-editor',
|
||||
PEFactory.createBooleanEditor('folded', 'extension.setting.cardFolded'))
|
||||
|
||||
PERegister.registerCPEditor(app, 'card-showFold', 'card-showFold-editor',
|
||||
PEFactory.createBooleanEditor('showFold', 'extension.setting.cardShowFold'))
|
||||
|
||||
PERegister.registerCPEditor(app, 'card-cardWidth', 'card-cardWidth-editor',
|
||||
PEFactory.createInputTextEditor('cardWidth', 'extension.setting.cardWidth'))
|
||||
|
||||
let shadowOptions = [
|
||||
{label: 'never', value: 'never'},
|
||||
{label: 'hover', value: 'hover'},
|
||||
{label: 'always', value: 'always'},
|
||||
]
|
||||
PERegister.registerCPEditor(app, 'card-shadow', 'card-shadow-editor',
|
||||
PEFactory.createSelectEditor('shadow', 'extension.setting.cardShadow',
|
||||
{optionItems: shadowOptions}))
|
||||
/* -------------------------------------------------- */
|
||||
registerCWGenerator('card', cardTemplateGenerator) //注册容器组件的代码生成器
|
||||
/* -------------------------------------------------- */
|
||||
/* 容器组件加载完毕 end */
|
||||
|
||||
/**
|
||||
* 加载字段组件步骤:
|
||||
* 1. 加载组件Json Schema;
|
||||
* 2. 全局注册字段组件,字段组件设计期和运行期共用,故仅需注册一个组件;
|
||||
* 3. 全局注册属性编辑器组件(基本属性、高级属性、事件属性);
|
||||
* 4. 注册字段组件的代码生成器;
|
||||
* 5. 加载完毕。
|
||||
*/
|
||||
addCustomWidgetSchema(alertSchema) //加载组件Json Schema
|
||||
/* -------------------------------------------------- */
|
||||
app.component(AlertWidget.name, AlertWidget) //注册组件
|
||||
/* -------------------------------------------------- */
|
||||
PERegister.registerCPEditor(app, 'alert-title', 'alert-title-editor',
|
||||
PEFactory.createInputTextEditor('title', 'extension.setting.alertTitle'))
|
||||
|
||||
let typeOptions = [
|
||||
{label: 'success', value: 'success'},
|
||||
{label: 'warning', value: 'warning'},
|
||||
{label: 'info', value: 'info'},
|
||||
{label: 'error', value: 'error'},
|
||||
]
|
||||
PERegister.registerCPEditor(app, 'alert-type', 'alert-type-editor',
|
||||
PEFactory.createSelectEditor('type', 'extension.setting.alertType',
|
||||
{optionItems: typeOptions}))
|
||||
|
||||
PERegister.registerCPEditor(app, 'alert-description', 'alert-description-editor',
|
||||
PEFactory.createInputTextEditor('description', 'extension.setting.description'))
|
||||
|
||||
PERegister.registerCPEditor(app, 'alert-closable', 'alert-closable-editor',
|
||||
PEFactory.createBooleanEditor('closable', 'extension.setting.closable'))
|
||||
|
||||
PERegister.registerCPEditor(app, 'alert-closeText', 'alert-closeText-editor',
|
||||
PEFactory.createInputTextEditor('closeText', 'extension.setting.closeText'))
|
||||
|
||||
PERegister.registerCPEditor(app, 'alert-center', 'alert-center-editor',
|
||||
PEFactory.createBooleanEditor('center', 'extension.setting.center'))
|
||||
|
||||
PERegister.registerCPEditor(app, 'alert-showIcon', 'alert-showIcon-editor',
|
||||
PEFactory.createBooleanEditor('showIcon', 'extension.setting.showIcon'))
|
||||
|
||||
let effectOptions = [
|
||||
{label: 'light', value: 'light'},
|
||||
{label: 'dark', value: 'dark'},
|
||||
]
|
||||
PERegister.registerCPEditor(app, 'alert-effect', 'alert-effect-editor',
|
||||
PEFactory.createRadioButtonGroupEditor('effect', 'extension.setting.effect',
|
||||
{optionItems: effectOptions}))
|
||||
|
||||
PERegister.registerEPEditor(app, 'alert-onClose', 'alert-onClose-editor',
|
||||
PEFactory.createEventHandlerEditor('onClose', []))
|
||||
/* -------------------------------------------------- */
|
||||
registerFWGenerator('alert', alertTemplateGenerator) //注册字段组件的代码生成器
|
||||
/* -------------------------------------------------- */
|
||||
/* 字段组件加载完毕 end */
|
||||
}
|
72
src/extension/samples/alert/alert-widget.vue
Normal file
72
src/extension/samples/alert/alert-widget.vue
Normal file
@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<static-content-wrapper :designer="designer" :field="field" :design-state="designState"
|
||||
:parent-widget="parentWidget" :parent-list="parentList" :index-of-parent-list="indexOfParentList"
|
||||
:sub-form-row-index="subFormRowIndex" :sub-form-col-index="subFormColIndex" :sub-form-row-id="subFormRowId">
|
||||
<el-alert ref="fieldEditor" :title="field.options.title" :type="field.options.type"
|
||||
:description="field.options.description" :closable="field.options.closable"
|
||||
:center="field.options.center" :close-text="field.options.closeText"
|
||||
:show-icon="field.options.showIcon" :effect="field.options.effect" @close="handelCloseCustomEvent"></el-alert>
|
||||
</static-content-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import StaticContentWrapper from '@/components/form-designer/form-widget/field-widget/static-content-wrapper'
|
||||
import emitter from '@/utils/emitter'
|
||||
import i18n from "@/utils/i18n"
|
||||
import fieldMixin from "@/components/form-designer/form-widget/field-widget/fieldMixin"
|
||||
|
||||
export default {
|
||||
name: "alert-widget",
|
||||
componentName: 'FieldWidget', //必须固定为FieldWidget,用于接收父级组件的broadcast事件
|
||||
mixins: [emitter, fieldMixin, i18n],
|
||||
props: {
|
||||
field: Object,
|
||||
parentWidget: Object,
|
||||
parentList: Array,
|
||||
indexOfParentList: Number,
|
||||
designer: Object,
|
||||
|
||||
designState: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
subFormRowIndex: { /* 子表单组件行索引,从0开始计数 */
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
subFormColIndex: { /* 子表单组件列索引,从0开始计数 */
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
subFormRowId: { /* 子表单组件行Id,唯一id且不可变 */
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
},
|
||||
components: {
|
||||
StaticContentWrapper,
|
||||
},
|
||||
created() {
|
||||
this.registerToRefList()
|
||||
this.initEventHandler()
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.unregisterFromRefList()
|
||||
},
|
||||
methods: {
|
||||
handelCloseCustomEvent() {
|
||||
if (!!this.field.options.onClose) {
|
||||
let changeFn = new Function(this.field.options.onClose)
|
||||
changeFn.call(this)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
102
src/extension/samples/card/card-item.vue
Normal file
102
src/extension/samples/card/card-item.vue
Normal file
@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<container-item-wrapper :widget="widget">
|
||||
<el-card :key="widget.id" class="card-container" :class="[!!widget.options.folded ? 'folded' : '', customClass]"
|
||||
:shadow="widget.options.shadow" :style="{width: widget.options.cardWidth + '!important' || ''}"
|
||||
:ref="widget.id" v-show="!widget.options.hidden">
|
||||
<template #header>
|
||||
<div class="clear-fix">
|
||||
<span>{{widget.options.label}}</span>
|
||||
<i v-if="widget.options.showFold" class="float-right"
|
||||
:class="[!widget.options.folded ? 'el-icon-arrow-down' : 'el-icon-arrow-up']" @click="toggleCard"></i>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="!!widget.widgetList && (widget.widgetList.length > 0)">
|
||||
<template v-for="(subWidget, swIdx) in widget.widgetList">
|
||||
<template v-if="'container' === subWidget.category">
|
||||
<component :is="subWidget.type + '-item'" :widget="subWidget" :key="swIdx" :parent-list="widget.widgetList"
|
||||
:index-of-parent-list="swIdx" :parent-widget="widget">
|
||||
<!-- 递归传递插槽!!! -->
|
||||
<template v-for="slot in Object.keys($slots)" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"/>
|
||||
</template>
|
||||
</component>
|
||||
</template>
|
||||
<template v-else>
|
||||
<component :is="subWidget.type + '-widget'" :field="subWidget" :designer="null" :key="swIdx" :parent-list="widget.widgetList"
|
||||
:index-of-parent-list="swIdx" :parent-widget="widget">
|
||||
<!-- 递归传递插槽!!! -->
|
||||
<template v-for="slot in Object.keys($slots)" v-slot:[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope"/>
|
||||
</template>
|
||||
</component>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</el-card>
|
||||
</container-item-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import emitter from '@/utils/emitter'
|
||||
import i18n from "@/utils/i18n"
|
||||
import refMixin from "@/components/form-render/refMixin"
|
||||
import ContainerItemWrapper from '@/components/form-render/container-item/container-item-wrapper'
|
||||
import containerItemMixin from "@/components/form-render/container-item/containerItemMixin"
|
||||
import FieldComponents from '@/components/form-designer/form-widget/field-widget/index'
|
||||
|
||||
export default {
|
||||
name: "card-item",
|
||||
componentName: 'ContainerItem',
|
||||
mixins: [emitter, i18n, refMixin, containerItemMixin],
|
||||
components: {
|
||||
ContainerItemWrapper,
|
||||
...FieldComponents,
|
||||
},
|
||||
props: {
|
||||
widget: Object,
|
||||
},
|
||||
inject: ['refList', 'sfRefList', 'globalModel'],
|
||||
computed: {
|
||||
customClass() {
|
||||
return this.widget.options.customClass || ''
|
||||
},
|
||||
|
||||
},
|
||||
created() {
|
||||
this.initRefList()
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.unregisterFromRefList()
|
||||
},
|
||||
methods: {
|
||||
toggleCard() {
|
||||
this.widget.options.folded = !this.widget.options.folded
|
||||
},
|
||||
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-card__header) {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.folded :deep(.el-card__body) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.clear-fix:before, .clear-fix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.clear-fix:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
</style>
|
121
src/extension/samples/card/card-widget.vue
Normal file
121
src/extension/samples/card/card-widget.vue
Normal file
@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<container-wrapper :designer="designer" :widget="widget" :parent-widget="parentWidget" :parent-list="parentList"
|
||||
:index-of-parent-list="indexOfParentList">
|
||||
<el-card :key="widget.id" class="card-container" @click.stop="selectWidget(widget)"
|
||||
:shadow="widget.options.shadow" :style="{width: widget.options.cardWidth + '!important' || ''}"
|
||||
:class="[selected ? 'selected' : '', !!widget.options.folded ? 'folded' : '', customClass]">
|
||||
<template #header>
|
||||
<div class="clear-fix">
|
||||
<span>{{widget.options.label}}</span>
|
||||
<i v-if="widget.options.showFold" class="float-right"
|
||||
:class="[!widget.options.folded ? 'el-icon-arrow-down' : 'el-icon-arrow-up']"
|
||||
@click="toggleCard"></i>
|
||||
</div>
|
||||
</template>
|
||||
<draggable :list="widget.widgetList" item-key="id" v-bind="{group:'dragGroup', ghostClass: 'ghost',animation: 200}"
|
||||
handle=".drag-handler" tag="transition-group" :component-data="{name: 'fade'}"
|
||||
@add="(evt) => onContainerDragAdd(evt, widget.widgetList)"
|
||||
@update="onContainerDragUpdate" :move="checkContainerMove">
|
||||
<template #item="{ element: subWidget, index: swIdx }">
|
||||
<div class="form-widget-list">
|
||||
<template v-if="'container' === subWidget.category">
|
||||
<component :is="subWidget.type + '-widget'" :widget="subWidget" :designer="designer" :key="subWidget.id" :parent-list="widget.widgetList"
|
||||
:index-of-parent-list="swIdx" :parent-widget="widget"></component>
|
||||
</template>
|
||||
<template v-else>
|
||||
<component :is="subWidget.type + '-widget'" :field="subWidget" :designer="designer" :key="subWidget.id" :parent-list="widget.widgetList"
|
||||
:index-of-parent-list="swIdx" :parent-widget="widget" :design-state="true"></component>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
</el-card>
|
||||
</container-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import i18n from "@/utils/i18n"
|
||||
import containerMixin from "@/components/form-designer/form-widget/container-widget/containerMixin"
|
||||
import Draggable from 'vuedraggable'
|
||||
import ContainerWrapper from "@/components/form-designer/form-widget/container-widget/container-wrapper"
|
||||
import FieldComponents from '@/components/form-designer/form-widget/field-widget/index'
|
||||
|
||||
export default {
|
||||
name: "card-widget",
|
||||
componentName: 'ContainerWidget',
|
||||
mixins: [i18n, containerMixin],
|
||||
components: {
|
||||
Draggable,
|
||||
ContainerWrapper,
|
||||
...FieldComponents,
|
||||
},
|
||||
props: {
|
||||
widget: Object,
|
||||
parentWidget: Object,
|
||||
parentList: Array,
|
||||
indexOfParentList: Number,
|
||||
designer: Object,
|
||||
},
|
||||
computed: {
|
||||
selected() {
|
||||
return this.widget.id === this.designer.selectedId
|
||||
},
|
||||
|
||||
customClass() {
|
||||
return this.widget.options.customClass || ''
|
||||
},
|
||||
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 检查接收哪些组件拖放,如不接受某些组件拖放,则根据组件类型判断后返回false
|
||||
* @param evt
|
||||
* @returns {boolean}
|
||||
*/
|
||||
checkContainerMove(evt) {
|
||||
return true
|
||||
},
|
||||
|
||||
toggleCard() {
|
||||
this.widget.options.folded = !this.widget.options.folded
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置折叠/打开状态
|
||||
* @param folded
|
||||
*/
|
||||
setFolded(folded) {
|
||||
this.widget.options.folded = !!folded
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-container.selected {
|
||||
outline: 2px solid $--color-primary !important;
|
||||
}
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.folded :deep(.el-card__body) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.clear-fix:before, .clear-fix:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.clear-fix:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
</style>
|
36
src/extension/samples/extension-schema.js
Normal file
36
src/extension/samples/extension-schema.js
Normal file
@ -0,0 +1,36 @@
|
||||
export const cardSchema = {
|
||||
type: 'card',
|
||||
category: 'container',
|
||||
icon: 'card',
|
||||
widgetList: [],
|
||||
options: {
|
||||
name: '',
|
||||
label: 'card',
|
||||
hidden: false,
|
||||
folded: false,
|
||||
showFold: true,
|
||||
cardWidth: '100%',
|
||||
shadow: 'never',
|
||||
customClass: '',
|
||||
}
|
||||
}
|
||||
|
||||
export const alertSchema = {
|
||||
type: 'alert',
|
||||
icon: 'alert',
|
||||
formItemFlag: false,
|
||||
options: {
|
||||
name: '',
|
||||
title: 'Good things are coming...',
|
||||
type: 'info',
|
||||
description: '',
|
||||
closable: true,
|
||||
closeText: '',
|
||||
center: true,
|
||||
showIcon: false,
|
||||
effect: 'light',
|
||||
hidden: false,
|
||||
onClose: '',
|
||||
customClass: '',
|
||||
}
|
||||
}
|
52
src/extension/samples/extension-sfc-generator.js
Normal file
52
src/extension/samples/extension-sfc-generator.js
Normal file
@ -0,0 +1,52 @@
|
||||
import {buildClassAttr, buildContainerWidget, buildFieldWidget} from '@/utils/sfc-generator'
|
||||
|
||||
export const cardTemplateGenerator = function (cw, formConfig) {
|
||||
const wop = cw.options
|
||||
//const headerAttr = `header="${wop.label}"`
|
||||
const classAttr = buildClassAttr(cw)
|
||||
const styleAttr = !!wop.cardWidth ? `style="{width: ${wop.cardWidth} !important}"` : ''
|
||||
const shadowAttr = `shadow="${wop.shadow}"`
|
||||
const vShowAttr = !!wop.hidden ? `v-show="false"` : ''
|
||||
|
||||
const cardTemplate =
|
||||
`<div class="card-container">
|
||||
<el-card ${classAttr} ${styleAttr} ${shadowAttr} ${vShowAttr}>
|
||||
<template #header>
|
||||
<div class="clear-fix">
|
||||
<span>${wop.label}</span>
|
||||
${!!wop.showFold ? `<i class="float-right el-icon-arrow-down"></i>` : ''}
|
||||
</div>
|
||||
</template>
|
||||
${
|
||||
cw.widgetList.map(wItem => {
|
||||
if (wItem.category === 'container') {
|
||||
return buildContainerWidget(wItem, formConfig)
|
||||
} else {
|
||||
return buildFieldWidget(wItem, formConfig)
|
||||
}
|
||||
}).join('')
|
||||
}
|
||||
</el-card>
|
||||
</div>`
|
||||
|
||||
return cardTemplate
|
||||
}
|
||||
|
||||
export const alertTemplateGenerator = function(fw, formConfig) {
|
||||
const wop = fw.options
|
||||
const titleAttr = `title="${wop.title}"`
|
||||
const typeAttr = `type=${wop.type}`
|
||||
const descriptionAttr = !!wop.description ? `description="${wop.description}"` : ''
|
||||
const closableAttr = `:closable="${wop.closable}"`
|
||||
const closeTextAttr = !!wop.closeText ? `close-text="${wop.closeText}"` : ''
|
||||
const centerAttr = `:center="${wop.center}"`
|
||||
const showIconAttr = `:show-icon="${wop.showIcon}"`
|
||||
const effectAttr = `effect="${wop.effect}"`
|
||||
|
||||
const alertTemplate =
|
||||
`<el-alert ${titleAttr} ${typeAttr} ${descriptionAttr} ${closableAttr} ${closeTextAttr} ${centerAttr}
|
||||
${showIconAttr} ${effectAttr}>
|
||||
</el-alert>`
|
||||
|
||||
return alertTemplate
|
||||
}
|
Reference in New Issue
Block a user