更新到3.0.6:

1. JS代码编辑器增加语法错误提示;
2. 修复lib-render打包丢失svg图标的问题;
3. 修复其他少量bug。
This commit is contained in:
vdpAdmin 2022-03-25 16:54:18 +08:00
parent d40b6e8d2d
commit af06777daf
18 changed files with 162 additions and 79 deletions

View File

@ -3,7 +3,10 @@ import axios from 'axios'
import VFormRender from '@/components/form-render/index.vue'
import ContainerItems from '@/components/form-render/container-item/index'
import {registerIcon} from '@/utils/el-icons'
import SvgIcon from '@/components/svg-icon' //svg组件
import 'virtual:svg-icons-register'
import '@/iconfont/iconfont.css'
import { installI18n } from '@/utils/i18n'
import { loadExtension } from '@/extension/extension-loader'
@ -13,6 +16,7 @@ VFormRender.install = function (app) {
loadExtension(app)
app.use(ContainerItems)
registerIcon(app)
app.component('svg-icon', SvgIcon)
app.component(VFormRender.name, VFormRender)
}
@ -26,6 +30,7 @@ const install = (app) => {
loadExtension(app)
app.use(ContainerItems)
registerIcon(app)
app.component('svg-icon', SvgIcon)
components.forEach(component => {
app.component(component.name, component)

View File

@ -37,6 +37,7 @@ VFormRender.install = function (app) {
app.use(ContainerItems)
registerIcon(app)
app.component('svg-icon', SvgIcon)
app.component(VFormRender.name, VFormRender)
}
@ -54,6 +55,7 @@ const install = (app) => {
app.use(ContainerWidgets)
app.use(ContainerItems)
registerIcon(app)
app.component('draggable', Draggable)
app.component('svg-icon', SvgIcon)

View File

@ -1,6 +1,6 @@
{
"name": "variant-form3",
"version": "3.0.5",
"version": "3.0.6",
"private": false,
"scripts": {
"serve": "vite",

View File

@ -119,6 +119,10 @@
this.aceEditor.getSession().setMode('ace/mode/css')
},
getEditorAnnotations() {
return this.aceEditor.getSession().getAnnotations()
},
}
}
</script>

View File

@ -113,6 +113,8 @@
exportJsonButton: true, //JSON
exportCodeButton: true, //
generateSFCButton: true, //SFC
toolbarMaxWidth: 420, //
toolbarMinWidth: 300, //
presetCssCode: '', //CSS

View File

@ -85,7 +85,7 @@
:show-close="true" custom-class="drag-dialog small-padding-dialog"
:close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
<el-alert type="info" :closable="false" :title="'form.' + eventParamsMap[curEventName]"></el-alert>
<code-editor :mode="'javascript'" :readonly="false" v-model="formEventHandlerCode"></code-editor>
<code-editor :mode="'javascript'" :readonly="false" v-model="formEventHandlerCode" ref="ecEditor"></code-editor>
<el-alert type="info" :closable="false" title="}"></el-alert>
<template #footer>
<div class="dialog-footer">
@ -118,7 +118,7 @@
<el-dialog :title="i18nt('designer.setting.globalFunctions')" v-model="showEditFunctionsDialogFlag"
:show-close="true" custom-class="drag-dialog small-padding-dialog"
:close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
<code-editor :mode="'javascript'" :readonly="false" v-model="functionsCode"></code-editor>
<code-editor :mode="'javascript'" :readonly="false" v-model="functionsCode" ref="gfEditor"></code-editor>
<template #footer>
<div class="dialog-footer">
<el-button @click="showEditFunctionsDialogFlag = false">
@ -271,6 +271,21 @@
},
saveGlobalFunctions() {
const codeHints = this.$refs.gfEditor.getEditorAnnotations()
let syntaxErrorFlag = false
if (!!codeHints && (codeHints.length > 0)) {
codeHints.forEach((chItem) => {
if (chItem.type === 'error') {
syntaxErrorFlag = true
}
})
if (syntaxErrorFlag) {
this.$message.error(this.i18nt('designer.setting.syntaxCheckWarning'))
return
}
}
this.designer.formConfig.functions = this.functionsCode
insertGlobalFunctionsToHtml(this.functionsCode)
this.showEditFunctionsDialogFlag = false
@ -283,6 +298,21 @@
},
saveFormEventHandler() {
const codeHints = this.$refs.ecEditor.getEditorAnnotations()
let syntaxErrorFlag = false
if (!!codeHints && (codeHints.length > 0)) {
codeHints.forEach((chItem) => {
if (chItem.type === 'error') {
syntaxErrorFlag = true
}
})
if (syntaxErrorFlag) {
this.$message.error(this.i18nt('designer.setting.syntaxCheckWarning'))
return
}
}
this.formConfig[this.curEventName] = this.formEventHandlerCode
this.showFormEventDialogFlag = false
},

View File

@ -76,7 +76,7 @@
:show-close="true" custom-class="drag-dialog small-padding-dialog"
:close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
<el-alert type="info" :closable="false" :title="eventHeader"></el-alert>
<code-editor :mode="'javascript'" :readonly="false" v-model="eventHandlerCode"></code-editor>
<code-editor :mode="'javascript'" :readonly="false" v-model="eventHandlerCode" ref="ecEditor"></code-editor>
<el-alert type="info" :closable="false" title="}"></el-alert>
<template #footer>
<div class="dialog-footer">
@ -276,6 +276,21 @@
},
saveEventHandler() {
const codeHints = this.$refs.ecEditor.getEditorAnnotations()
let syntaxErrorFlag = false
if (!!codeHints && (codeHints.length > 0)) {
codeHints.forEach((chItem) => {
if (chItem.type === 'error') {
syntaxErrorFlag = true
}
})
if (syntaxErrorFlag) {
this.$message.error(this.i18nt('designer.setting.syntaxCheckWarning'))
return
}
}
this.selectedWidget.options[this.curEventName] = this.eventHandlerCode
this.showWidgetEventDialogFlag = false
},

View File

@ -23,22 +23,24 @@
icon-class="el-icon-arrow-right" @node-click="onNodeTreeClick"></el-tree>
</el-drawer>
<div class="right-toolbar">
<el-button v-if="showToolButton('clearDesignerButton')" type="text" @click="clearFormWidget">
<svg-icon icon-class="el-delete" />{{i18nt('designer.toolbar.clear')}}</el-button>
<el-button v-if="showToolButton('previewFormButton')" type="text" @click="previewForm">
<svg-icon icon-class="el-view" />{{i18nt('designer.toolbar.preview')}}</el-button>
<el-button v-if="showToolButton('importJsonButton')" type="text" @click="importJson">
{{i18nt('designer.toolbar.importJson')}}</el-button>
<el-button v-if="showToolButton('exportJsonButton')" type="text" @click="exportJson">
{{i18nt('designer.toolbar.exportJson')}}</el-button>
<el-button v-if="showToolButton('exportCodeButton')" type="text" @click="exportCode">
{{i18nt('designer.toolbar.exportCode')}}</el-button>
<el-button v-if="showToolButton('generateSFCButton')" type="text" @click="generateSFC">
<svg-icon icon-class="vue-sfc" />{{i18nt('designer.toolbar.generateSFC')}}</el-button>
<template v-for="(idx, slotName) in $slots">
<slot :name="slotName"></slot>
</template>
<div class="right-toolbar" :style="{width: toolbarWidth + 'px'}">
<div class="right-toolbar-con">
<el-button v-if="showToolButton('clearDesignerButton')" type="text" @click="clearFormWidget">
<svg-icon icon-class="el-delete" />{{i18nt('designer.toolbar.clear')}}</el-button>
<el-button v-if="showToolButton('previewFormButton')" type="text" @click="previewForm">
<svg-icon icon-class="el-view" />{{i18nt('designer.toolbar.preview')}}</el-button>
<el-button v-if="showToolButton('importJsonButton')" type="text" @click="importJson">
{{i18nt('designer.toolbar.importJson')}}</el-button>
<el-button v-if="showToolButton('exportJsonButton')" type="text" @click="exportJson">
{{i18nt('designer.toolbar.exportJson')}}</el-button>
<el-button v-if="showToolButton('exportCodeButton')" type="text" @click="exportCode">
{{i18nt('designer.toolbar.exportCode')}}</el-button>
<el-button v-if="showToolButton('generateSFCButton')" type="text" @click="generateSFC">
<svg-icon icon-class="vue-sfc" />{{i18nt('designer.toolbar.generateSFC')}}</el-button>
<template v-for="(idx, slotName) in $slots">
<slot :name="slotName"></slot>
</template>
</div>
</div>
<div v-if="showPreviewDialogFlag" class="" v-drag="['.drag-dialog.el-dialog', '.drag-dialog .el-dialog__header']">
@ -188,12 +190,12 @@
copyToClipboard,
generateId,
getQueryParam,
traverseAllWidgets
} from "@/utils/util";
traverseAllWidgets, addWindowResizeHandler
} from "@/utils/util"
import i18n from '@/utils/i18n'
import {generateCode} from "@/utils/code-generator";
import {genSFC} from "@/utils/sfc-generator";
import loadBeautifier from "@/utils/beautifierLoader";
import {generateCode} from "@/utils/code-generator"
import {genSFC} from "@/utils/sfc-generator"
import loadBeautifier from "@/utils/beautifierLoader"
import { saveAs } from 'file-saver'
import axios from 'axios'
@ -213,6 +215,7 @@
return {
designerConfig: this.getDesignerConfig(),
toolbarWidth: 420,
showPreviewDialogFlag: false,
showImportJsonDialogFlag: false,
showExportJsonDialogFlag: false,
@ -288,7 +291,18 @@
}
},
},
mounted() {
let maxTBWidth = this.designerConfig.toolbarMaxWidth || 420
let minTBWidth = this.designerConfig.toolbarMinWidth || 300
let newTBWidth = window.innerWidth - 260 - 300 - 320 - 80
this.toolbarWidth = newTBWidth >= maxTBWidth ? maxTBWidth : (newTBWidth <= minTBWidth ? minTBWidth : newTBWidth)
addWindowResizeHandler(() => {
this.$nextTick(() => {
let newTBWidth2 = window.innerWidth - 260 - 300 - 320 - 80
this.toolbarWidth = newTBWidth2 >= maxTBWidth ? maxTBWidth : (newTBWidth2 <= minTBWidth ? minTBWidth : newTBWidth2)
})
})
},
methods: {
showToolButton(configName) {
@ -662,7 +676,8 @@
<style lang="scss" scoped>
div.toolbar-container {
min-width: 728px; /* 解决工具按钮栏换行的问题!! */
//min-width: 728px; /* */
/* 上一行css有问题当窗口宽度不足时会把按钮挤出到右边的属性设置区弃之 */
}
.left-toolbar {
@ -676,10 +691,26 @@
display: flex;
margin-top: 5px;
float: right;
text-align: right;
overflow: hidden;
.right-toolbar-con {
text-align: left;
width: 600px;
}
:deep(.el-button) {
margin-left: 10px;
}
:deep(.el-button--text) {
font-size: 14px !important;
}
:deep(.svg-icon) {
margin-left: 0;
margin-right: 0.05em;
}
}
.el-button i {

View File

@ -71,9 +71,9 @@
<el-card :bord-style="{ padding: '0' }" shadow="hover" class="ft-card">
<el-popover placement="right" trigger="hover">
<template #reference>
<img :src="ftImages[idx].imgUrl" style="width: 200px">
<img :src="ft.imgUrl" style="width: 200px">
</template>
<img :src="ftImages[idx].imgUrl" style="height: 600px;width: 720px">
<img :src="ft.imgUrl" style="height: 600px;width: 720px">
</el-popover>
<div class="bottom clear-fix">
<span class="ft-title">#{{idx+1}} {{ft.title}}</span>
@ -91,28 +91,25 @@
</template>
<script>
//import Draggable from 'vuedraggable'
import {containers as CONS, basicFields as BFS, advancedFields as AFS, customFields as CFS} from "./widgetsConfig"
import {formTemplates} from './templatesConfig'
import {addWindowResizeHandler} from "@/utils/util"
import {addWindowResizeHandler, generateId} from "@/utils/util"
import i18n from "@/utils/i18n"
import axios from 'axios'
import ftImg1 from '@/assets/ft-images/t1.png'
import ftImg2 from '@/assets/ft-images/t2.png'
import ftImg3 from '@/assets/ft-images/t3.png'
import ftImg4 from '@/assets/ft-images/t4.png'
import ftImg5 from '@/assets/ft-images/t5.png'
import ftImg6 from '@/assets/ft-images/t6.png'
import ftImg7 from '@/assets/ft-images/t7.png'
import ftImg8 from '@/assets/ft-images/t8.png'
import { generateId } from '../../../utils/util'
// import ftImg1 from '@/assets/ft-images/t1.png'
// import ftImg2 from '@/assets/ft-images/t2.png'
// import ftImg3 from '@/assets/ft-images/t3.png'
// import ftImg4 from '@/assets/ft-images/t4.png'
// import ftImg5 from '@/assets/ft-images/t5.png'
// import ftImg6 from '@/assets/ft-images/t6.png'
// import ftImg7 from '@/assets/ft-images/t7.png'
// import ftImg8 from '@/assets/ft-images/t8.png'
export default {
name: "FieldPanel",
mixins: [i18n],
components: {
//Draggable,
},
props: {
designer: Object,
@ -134,16 +131,16 @@ import { generateId } from '../../../utils/util'
customFields: [],
formTemplates: formTemplates,
ftImages: [
{imgUrl: ftImg1},
{imgUrl: ftImg2},
{imgUrl: ftImg3},
{imgUrl: ftImg4},
{imgUrl: ftImg5},
{imgUrl: ftImg6},
{imgUrl: ftImg7},
{imgUrl: ftImg8},
]
// ftImages: [
// {imgUrl: ftImg1},
// {imgUrl: ftImg2},
// {imgUrl: ftImg3},
// {imgUrl: ftImg4},
// {imgUrl: ftImg5},
// {imgUrl: ftImg6},
// {imgUrl: ftImg7},
// {imgUrl: ftImg8},
// ]
}
},
computed: {

View File

@ -1,56 +1,56 @@
export const formTemplates = [
{
title: '单列表单',
//imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t1.png',
imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t1.png',
jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json1.txt',
description: '表单模板详细说明...'
},
{
title: '多列表单',
//imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t2.png',
imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t2.png',
jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json2.txt',
description: '表单模板详细说明...'
},
{
title: '分组表单',
//imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t3.png',
imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t3.png',
jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json3.txt',
description: '表单模板详细说明...'
},
{
title: '标签页表单',
//imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t4.png',
imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t4.png',
jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json4.txt',
description: '表单模板详细说明...'
},
{
title: '主从表单',
//imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t5.png',
imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t5.png',
jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json5.txt',
description: '表单模板详细说明...'
},
{
title: '响应式表单',
//imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t6.png',
imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t6.png',
jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json6.txt',
description: '表单模板详细说明...'
},
{
title: '问卷调查表',
//imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t7.png',
imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t7.png',
jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json7.txt',
description: '表单模板详细说明...'
},
{
title: '固定表格表单',
//imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t8.png',
imgUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/t8.png',
jsonUrl: 'https://ks3-cn-beijing.ksyuncs.com/vform-static/form-samples/json8.txt',
description: '表单模板详细说明...'
},

View File

@ -899,17 +899,6 @@ export const advancedFields = [
},
},
// {
// type: 'slot',
// icon: 'slot-field',
// formItemFlag: false,
// options: {
// name: '',
// label: '',
// customClass: '', //自定义css类名
// }
// },
]
export const customFields = [

View File

@ -38,10 +38,10 @@
<el-row v-for="(subFormRowId, sfrIdx) in rowIdData" class="sub-form-row" :key="subFormRowId">
<div class="sub-form-action-column hide-label">
<div class="action-button-column">
<el-button :disabled="actionDisabled" circle icon="el-icon-circle-plus-outline" @click="insertSubFormRow(sfrIdx)"
:title="i18nt('render.hint.insertSubFormRow')"></el-button>
<el-button :disabled="actionDisabled" circle icon="el-icon-delete" @click="deleteSubFormRow(sfrIdx)"
:title="i18nt('render.hint.deleteSubFormRow')"></el-button>
<el-button :disabled="actionDisabled" circle @click="insertSubFormRow(sfrIdx)"
:title="i18nt('render.hint.insertSubFormRow')"><svg-icon icon-class="el-plus" /></el-button>
<el-button :disabled="actionDisabled" circle @click="deleteSubFormRow(sfrIdx)"
:title="i18nt('render.hint.deleteSubFormRow')"><svg-icon icon-class="el-delete" /></el-button>
<span v-if="widget.options.showRowNumber" class="row-number-span">#{{sfrIdx+1}}</span>
</div>
</div>
@ -374,7 +374,7 @@
}
:deep(.el-button) {
font-size: 18px;
font-size: 14px;
padding: 0;
background: #DCDFE6;
border: 4px solid #DCDFE6;

View File

@ -170,11 +170,13 @@
insertCustomStyleAndScriptNode() {
if (!!this.formConfig && !!this.formConfig.cssCode) {
insertCustomCssToHead(this.formConfig.cssCode, this.formId)
insertCustomCssToHead(this.formConfig.cssCode,
!!this.previewState ? '' : this.formId)
}
if (!!this.formConfig && !!this.formConfig.functions) {
insertGlobalFunctionsToHtml(this.formConfig.functions, this.formId)
insertGlobalFunctionsToHtml(this.formConfig.functions,
!!this.previewState ? '' : this.formId)
}
},

View File

@ -82,7 +82,7 @@ export const loadExtension = function (app) {
/* type属性映射已存在无须再注册故只需注册属性编辑器即可 */
app.component('alert-type-editor',
PEFactory.createSelectEditor('type', 'extension.setting.alertType',
{optionItems: typeOptions}))
{optionItems: typeOptions}))
PERegister.registerCPEditor(app, 'alert-description', 'alert-description-editor',
PEFactory.createInputTextEditor('description', 'extension.setting.description'))

View File

@ -319,6 +319,7 @@ export default {
formModelName: 'Model Name',
formRefName: 'Ref Name',
formRulesName: 'Rules Name',
syntaxCheckWarning: 'Syntax error in the javascript codes, please check again!',
}

View File

@ -319,6 +319,7 @@ export default {
formModelName: '数据对象名称',
formRefName: '引用名称',
formRulesName: '验证规则名称',
syntaxCheckWarning: 'JS代码存在语法错误请仔细检查',
}

View File

@ -8,7 +8,7 @@ export const DESIGNER_OPTIONS = {
}
export const VARIANT_FORM_VERSION = '3.0.5'
export const VARIANT_FORM_VERSION = '3.0.6'
//export const MOCK_CASE_URL = 'https://www.fastmock.site/mock/2de212e0dc4b8e0885fea44ab9f2e1d0/vform/'
export const MOCK_CASE_URL = 'https://ks3-cn-beijing.ksyuncs.com/vform-static/vcase/'

View File

@ -4,6 +4,7 @@ import vueJsx from '@vitejs/plugin-vue-jsx'
import viteSvgIcons from 'vite-plugin-svg-icons'
import { resolve } from 'path'
import commonjs from '@rollup/plugin-commonjs'
import visualizer from 'rollup-plugin-visualizer'
// https://vitejs.dev/config/
export default defineConfig({
@ -17,6 +18,9 @@ export default defineConfig({
commonjs({requireReturnsDefault: true}), /* requireReturnsDefault
解决打包后引入VForm出现的"Axios is not a constructor" */
//可视化Bundle
visualizer(),
viteSvgIcons({
// Specify the icon folder to be cached
iconDirs: [resolve(process.cwd(), 'src/icons/svg')],