498 lines
18 KiB
Vue
498 lines
18 KiB
Vue
<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>
|