variant-form/src/components/form-designer/toolbar-panel/index.vue

498 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="toolbar-container">
<div class="left-toolbar">
<el-button type="text" :disabled="undoDisabled" :title="i18nt('designer.toolbar.undoHint')" @click="undoHistory">
<svg-icon icon-class="undo" /></el-button>
<el-button type="text" :disabled="redoDisabled" :title="i18nt('designer.toolbar.redoHint')" @click="redoHistory">
<svg-icon icon-class="redo" /></el-button>
<el-button-group style="margin-left: 20px">
<el-button :type="layoutType === 'PC' ? 'info': ''" @click="changeLayoutType('PC')">
{{i18nt('designer.toolbar.pcLayout')}}</el-button>
<el-button :type="layoutType === 'H5' ? 'info': ''" @click="changeLayoutType('H5')">
{{i18nt('designer.toolbar.mobileLayout')}}</el-button>
</el-button-group>
</div>
<div class="right-toolbar">
<el-button type="text" @click="clearFormWidget"><i class="el-icon-delete" />{{i18nt('designer.toolbar.clear')}}</el-button>
<el-button type="text" @click="previewForm"><i class="el-icon-view" />{{i18nt('designer.toolbar.preview')}}</el-button>
<el-button type="text" @click="importJson">{{i18nt('designer.toolbar.importJson')}}</el-button>
<el-button type="text" @click="exportJson">{{i18nt('designer.toolbar.exportJson')}}</el-button>
<el-button type="text" @click="exportCode">{{i18nt('designer.toolbar.exportCode')}}</el-button>
<el-button type="text" @click="generateSFC"><svg-icon icon-class="vue-sfc" />{{i18nt('designer.toolbar.generateSFC')}}</el-button>
</div>
<el-dialog :title="i18nt('designer.toolbar.preview')" :visible.sync="showPreviewDialogFlag" v-if="showPreviewDialogFlag"
:show-close="true" :close-on-click-modal="false" :close-on-press-escape="false" center v-dialog-drag
:destroy-on-close="true" class="small-padding-dialog" width="75%" :fullscreen="layoutType === 'H5'">
<div>
<div class="form-render-wrapper" :class="[layoutType === 'H5' ? 'h5-layout' : '']">
<VFormRender ref="preForm" :form-json="formJson" :form-data="testFormData"
@appendButtonClick="testOnAppendButtonClick" @buttonClick="testOnButtonClick"
@formChange="handleFormChange"></VFormRender>
</div>
</div>
<code-editor v-model="testFunc" style="display: none"></code-editor>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="getFormData">{{i18nt('designer.hint.getFormData')}}</el-button>
<el-button type="primary" @click="resetForm">{{i18nt('designer.hint.resetForm')}}</el-button>
<el-button type="primary" @click="setFormDisabled">{{i18nt('designer.hint.disableForm')}}</el-button>
<el-button type="primary" @click="setFormEnabled">{{i18nt('designer.hint.enableForm')}}</el-button>
<el-button type="" @click="showPreviewDialogFlag = false">{{i18nt('designer.hint.closePreview')}}</el-button>
</div>
</el-dialog>
<el-dialog :title="i18nt('designer.toolbar.importJson')" :visible.sync="showImportJsonDialogFlag"
v-if="showImportJsonDialogFlag" :show-close="true" class="small-padding-dialog" center v-dialog-drag
:close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
<el-alert type="info" :title="i18nt('designer.hint.importJsonHint')" show-icon class="alert-padding"></el-alert>
<code-editor :mode="'json'" :readonly="false" v-model="importTemplate"></code-editor>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="doJsonImport">
{{i18nt('designer.hint.import')}}</el-button>
<el-button @click="showImportJsonDialogFlag = false">
{{i18nt('designer.hint.cancel')}}</el-button>
</div>
</el-dialog>
<el-dialog :title="i18nt('designer.toolbar.exportJson')" :visible.sync="showExportJsonDialogFlag"
v-if="showExportJsonDialogFlag" :show-close="true" class="small-padding-dialog" center v-dialog-drag
:close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
<code-editor :mode="'json'" :readonly="true" v-model="jsonContent"></code-editor>
<div slot="footer" class="dialog-footer">
<el-button type="primary" class="copy-json-btn" :data-clipboard-text="jsonRawContent" @click="copyFormJson">
{{i18nt('designer.hint.copyJson')}}</el-button>
<el-button @click="saveFormJson">{{i18nt('designer.hint.saveFormJson')}}</el-button>
<el-button type="" @click="showExportJsonDialogFlag = false">
{{i18nt('designer.hint.closePreview')}}</el-button>
</div>
</el-dialog>
<el-dialog :title="i18nt('designer.toolbar.exportCode')" :visible.sync="showExportCodeDialogFlag"
v-if="showExportCodeDialogFlag" :show-close="true" class="small-padding-dialog" center v-dialog-drag
width="65%" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
<el-tabs type="border-card" class="no-box-shadow no-padding" v-model="activeCodeTab">
<el-tab-pane label="Vue" name="vue">
<code-editor :mode="'html'" :readonly="true" v-model="vueCode" :user-worker="false"></code-editor>
</el-tab-pane>
<el-tab-pane label="HTML" name="html">
<code-editor :mode="'html'" :readonly="true" v-model="htmlCode" :user-worker="false"></code-editor>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button type="primary" class="copy-vue-btn" :data-clipboard-text="vueCode" @click="copyVueCode">
{{i18nt('designer.hint.copyVueCode')}}</el-button>
<el-button type="primary" class="copy-html-btn" :data-clipboard-text="htmlCode" @click="copyHtmlCode">
{{i18nt('designer.hint.copyHtmlCode')}}</el-button>
<el-button @click="saveVueCode">{{i18nt('designer.hint.saveVueCode')}}</el-button>
<el-button @click="saveHtmlCode">{{i18nt('designer.hint.saveHtmlCode')}}</el-button>
<el-button type="" @click="showExportCodeDialogFlag = false">
{{i18nt('designer.hint.closePreview')}}</el-button>
</div>
</el-dialog>
<el-dialog :title="i18nt('designer.hint.exportFormData')" :visible.sync="showFormDataDialogFlag"
v-if="showFormDataDialogFlag" :show-close="true" class="dialog-title-light-bg" center v-dialog-drag
:close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true"
:append-to-body="true">
<div style="border: 1px solid #DCDFE6">
<code-editor :mode="'json'" :readonly="true" v-model="formDataJson"></code-editor>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" class="copy-form-data-json-btn" :data-clipboard-text="formDataRawJson" @click="copyFormDataJson">
{{i18nt('designer.hint.copyFormData')}}</el-button>
<el-button @click="saveFormData">{{i18nt('designer.hint.saveFormData')}}</el-button>
<el-button type="" @click="showFormDataDialogFlag = false">
{{i18nt('designer.hint.closePreview')}}</el-button>
</div>
</el-dialog>
<el-dialog :title="i18nt('designer.toolbar.generateSFC')" :visible.sync="showExportSFCDialogFlag"
v-if="showExportSFCDialogFlag" :show-close="true" class="small-padding-dialog" center v-dialog-drag
width="65%" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="true">
<el-tabs type="border-card" class="no-box-shadow no-padding" v-model="activeSFCTab">
<el-tab-pane label="Vue2" name="vue2">
<code-editor :mode="'html'" :readonly="true" v-model="sfcCode" :user-worker="false"></code-editor>
</el-tab-pane>
<el-tab-pane label="Vue3" name="vue3">
<code-editor :mode="'html'" :readonly="true" v-model="sfcCodeV3" :user-worker="false"></code-editor>
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button type="primary" class="copy-vue2-sfc-btn" :data-clipboard-text="sfcCode" @click="copyV2SFC">
{{i18nt('designer.hint.copyVue2SFC')}}</el-button>
<el-button type="primary" class="copy-vue3-sfc-btn" :data-clipboard-text="sfcCodeV3" @click="copyV3SFC">
{{i18nt('designer.hint.copyVue3SFC')}}</el-button>
<el-button @click="saveV2SFC">{{i18nt('designer.hint.saveVue2SFC')}}</el-button>
<el-button @click="saveV3SFC">{{i18nt('designer.hint.saveVue3SFC')}}</el-button>
<el-button type="" @click="showExportSFCDialogFlag = false">
{{i18nt('designer.hint.closePreview')}}</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import VFormRender from '@/components/form-render/index'
import CodeEditor from '@/components/code-editor/index'
import Clipboard from 'clipboard'
import {deepClone, copyToClipboard, generateId, getQueryParam} 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 { saveAs } from 'file-saver'
export default {
name: "ToolbarPanel",
mixins: [i18n],
components: {
VFormRender,
CodeEditor,
Clipboard,
},
props: {
designer: Object
},
data() {
return {
showPreviewDialogFlag: false,
showImportJsonDialogFlag: false,
showExportJsonDialogFlag: false,
showExportCodeDialogFlag: false,
showFormDataDialogFlag: false,
showExportSFCDialogFlag: false,
testFunc: '',
importTemplate: '',
jsonContent: '',
jsonRawContent: '',
formDataJson: '',
formDataRawJson: '',
vueCode: '',
htmlCode: '',
sfcCode: '',
sfcCodeV3: '',
activeCodeTab: 'vue',
activeSFCTab: 'vue2',
testFormData: {
// 'userName': '666888',
// 'productItems': [
// {'pName': 'iPhone12', 'pNum': 10},
// {'pName': 'P50', 'pNum': 16},
// ]
},
}
},
computed: {
formJson() {
return {
widgetList: this.designer.widgetList,
formConfig: this.designer.formConfig
}
},
undoDisabled() {
return !this.designer.undoEnabled()
},
redoDisabled() {
return !this.designer.redoEnabled()
},
layoutType() {
return this.designer.getLayoutType()
},
},
methods: {
undoHistory() {
this.designer.undoHistoryStep()
},
redoHistory() {
this.designer.redoHistoryStep()
},
changeLayoutType(newType) {
this.designer.changeLayoutType(newType)
},
clearFormWidget() {
this.designer.clearDesigner()
},
previewForm() {
this.showPreviewDialogFlag = true
},
saveAsFile(fileContent, defaultFileName) {
this.$prompt(this.i18nt('designer.hint.fileNameForSave'), this.i18nt('designer.hint.saveFileTitle'), {
inputValue: defaultFileName,
closeOnClickModal: false,
inputPlaceholder: this.i18nt('designer.hint.fileNameInputPlaceholder')
}).then(({ value }) => {
if (!value) {
value = defaultFileName
}
if (getQueryParam('vscode') == 1) {
this.vsSaveFile(value, fileContent)
return
}
const fileBlob = new Blob([fileContent], { type: 'text/plain;charset=utf-8' })
saveAs(fileBlob ,value)
}).catch(() => {
//
})
},
vsSaveFile(fileName, fileContent) {
const msgObj = {
cmd: 'writeFile',
data: {
fileName,
code: fileContent
}
}
window.parent.postMessage(msgObj, '*')
},
importJson() {
this.importTemplate = JSON.stringify(this.designer.getImportTemplate(), null, ' ')
this.showImportJsonDialogFlag = true
},
doJsonImport() {
try {
let importObj = JSON.parse(this.importTemplate)
this.designer.loadFormJson(importObj)
this.showImportJsonDialogFlag = false
this.$message.success(this.i18nt('designer.hint.importJsonSuccess'))
this.designer.emitHistoryChange()
this.designer.emitEvent('form-json-imported', [])
} catch(ex) {
this.$message.error(ex + '')
}
},
exportJson() {
let widgetList = deepClone(this.designer.widgetList)
let formConfig = deepClone(this.designer.formConfig)
this.jsonContent = JSON.stringify({widgetList, formConfig}, null, ' ')
this.jsonRawContent = JSON.stringify({widgetList, formConfig})
this.showExportJsonDialogFlag = true
},
copyFormJson(e) {
copyToClipboard(this.jsonRawContent, e,
this.$message,
this.i18nt('designer.hint.copyJsonSuccess'),
this.i18nt('designer.hint.copyJsonFail')
)
},
saveFormJson() {
this.saveAsFile(this.jsonContent, `vform${generateId()}.json`)
},
exportCode() {
this.vueCode = generateCode(this.formJson)
this.htmlCode = generateCode(this.formJson, 'html')
this.showExportCodeDialogFlag = true
},
copyVueCode(e) {
copyToClipboard(this.vueCode, e,
this.$message,
this.i18nt('designer.hint.copyVueCodeSuccess'),
this.i18nt('designer.hint.copyVueCodeFail')
)
},
copyHtmlCode(e) {
copyToClipboard(this.htmlCode, e,
this.$message,
this.i18nt('designer.hint.copyHtmlCodeSuccess'),
this.i18nt('designer.hint.copyHtmlCodeFail')
)
},
saveVueCode() {
this.saveAsFile(this.vueCode, `vform${generateId()}.vue`)
},
saveHtmlCode() {
this.saveAsFile(this.htmlCode, `vform${generateId()}.html`)
},
generateSFC() {
loadBeautifier(beautifier => {
this.sfcCode = genSFC(this.designer.formConfig, this.designer.widgetList, beautifier)
this.sfcCodeV3 = genSFC(this.designer.formConfig, this.designer.widgetList, beautifier, true)
this.showExportSFCDialogFlag = true
})
},
copyV2SFC(e) {
copyToClipboard(this.sfcCode, e,
this.$message,
this.i18nt('designer.hint.copySFCSuccess'),
this.i18nt('designer.hint.copySFCFail')
)
},
copyV3SFC(e) {
copyToClipboard(this.sfcCodeV3, e,
this.$message,
this.i18nt('designer.hint.copySFCSuccess'),
this.i18nt('designer.hint.copySFCFail')
)
},
saveV2SFC() {
this.saveAsFile(this.sfcCode, `vformV2-${generateId()}.vue`)
},
saveV3SFC() {
this.saveAsFile(this.sfcCodeV3, `vformV3-${generateId()}.vue`)
},
getFormData() {
this.$refs['preForm'].getFormData().then(formData => {
this.formDataJson = JSON.stringify(formData, null, ' ')
this.formDataRawJson = JSON.stringify(formData)
this.showFormDataDialogFlag = true
}).catch(error => {
this.$message.error(error)
})
},
copyFormDataJson(e) {
copyToClipboard(this.formDataRawJson, e,
this.$message,
this.i18nt('designer.hint.copyJsonSuccess'),
this.i18nt('designer.hint.copyJsonFail')
)
},
saveFormData() {
this.saveAsFile(this.htmlCode, `formData${generateId()}.json`)
},
resetForm() {
this.$refs['preForm'].resetForm()
},
setFormDisabled() {
this.$refs['preForm'].disableForm()
},
setFormEnabled() {
this.$refs['preForm'].enableForm()
},
handleFormChange(fieldName, newValue, oldValue, formModel) {
console.log('---formChange start---')
console.log('fieldName', fieldName)
console.log('newValue', newValue)
console.log('oldValue', oldValue)
console.log('formModel', formModel)
console.log('---formChange end---')
},
testOnAppendButtonClick(clickedWidget) {
console.log('test', clickedWidget)
},
testOnButtonClick(button) {
console.log('test', button)
},
}
}
</script>
<style lang="scss" scoped>
div.toolbar-container {
}
.left-toolbar {
float: left;
font-size: 16px;
}
.right-toolbar {
float: right;
::v-deep .el-button--text {
font-size: 14px !important;
}
}
.el-button i {
margin-right: 3px;
}
.small-padding-dialog {
::v-deep .el-dialog__header {
//padding-top: 3px;
//padding-bottom: 3px;
background: #f1f2f3;
}
::v-deep .el-dialog__body {
padding: 12px 15px 12px 15px;
.el-alert.alert-padding {
padding: 0 10px;
}
}
::v-deep .ace-container {
border: 1px solid #DCDFE6;
}
}
.dialog-title-light-bg {
::v-deep .el-dialog__header {
background: #f1f2f3;
}
}
.no-box-shadow {
box-shadow: none;
}
.no-padding.el-tabs--border-card {
::v-deep .el-tabs__content {
padding: 0;
}
}
.form-render-wrapper {
//height: calc(100vh - 142px);
all: revert !important; /* 防止表单继承el-dialog等外部样式未生效原因不明 */
}
.form-render-wrapper.h5-layout {
margin: 0 auto;
width: 420px;
border-radius: 15px;
//border-width: 10px;
box-shadow: 0 0 1px 10px #495060;
height: calc(100vh - 142px);
}
</style>