<template> <div class="container"> <div class="center-board"> <!-- <el-scrollbar class="center-scrollbar"> --> <el-row class="center-board-row"> <el-form :size="formConf.size" :label-position="formConf.labelPosition" :disabled="formConf.disabled" :label-width="formConf.labelWidth + 'px'" ref="myfrom"> <!-- <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup"> --> <draggable-item v-for="(element, index) in drawingList" :key="element.renderKey" :drawing-list="drawingList" :element="element" :index="index" :active-id="activeId" :form-conf="formConf" @activeItem="activeFormItem" @copyItem="drawingItemCopy" @deleteItem="drawingItemDelete" ref="draggableitem" /> <!-- </draggable> --> </el-form> </el-row> <!-- </el-scrollbar> --> </div> </div> </template> <script> import draggable from 'vuedraggable' import beautifier from 'js-beautify' import ClipboardJS from 'clipboard' import render from '@/utils/generator/render' import RightPanel from './RightPanel' import { inputComponents, selectComponents, layoutComponents, formConf } from '@/utils/generator/config' import { beautifierConf, titleCase } from '@/utils/index' import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html' import { makeUpJs } from '@/utils/generator/js' import { makeUpCss } from '@/utils/generator/css' import drawingDefault from '@/utils/generator/drawingDefault' import logo from '@/assets/logo/logo.png' import CodeTypeDialog from './CodeTypeDialog' import DraggableItem from './DraggableItem' import { templateInfo } from "@/api/onlineDeclartion/declarationManagement" import { getAllList } from "@/api/system/dict/data"; import { getToken } from '@/utils/auth' import { Upload } from 'element-ui' let oldActiveId let tempActiveData export default { components: { draggable, render, RightPanel, CodeTypeDialog, DraggableItem }, dicts: ['bms_responsibility_unit', 'bms_level'], data() { let validateTime = (rule, value, callback) => { if (new Date(value[1]) < new Date()) { callback(new Error('选择结束时间需大于当前时间')) } else { callback() } } return { logo, idGlobal: 100, formConf, inputComponents, selectComponents, layoutComponents, labelWidth: 100, drawingList: "", drawingData: {}, activeId: drawingDefault[0].formId, drawerVisible: false, formData: {}, dialogVisible: false, generateConf: null, showFileName: false, activeData: drawingDefault[0], options: [], // 表单参数 dialogForm: {}, projectBigType: undefined, projectMiddleType: undefined, projectSmallType: undefined, createTemplate: true, } }, created() { // 防止 firefox 下 拖拽 会新打卡一个选项卡 document.body.ondrop = event => { event.preventDefault() event.stopPropagation() } }, watch: { // eslint-disable-next-line func-names 'activeData.label': function (val, oldVal) { if ( this.activeData.placeholder === undefined || !this.activeData.tag || oldActiveId !== this.activeId ) { return } this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val }, activeId: { handler(val) { oldActiveId = val }, immediate: true } }, mounted() { // 1. 在created中订阅 // 2. 回调函数需要写成箭头函数 // this.$bus.$on('事件名', 事件回调函数) // this.$bus.$on('Myuploadfn', msg => { // console.log(777,msg) // }) const clipboard = new ClipboardJS('#copyNode', { text: trigger => { const codeStr = this.generateCode() this.$notify({ title: '成功', message: '代码已复制到剪切板,可粘贴。', type: 'success' }) return codeStr } }) clipboard.on('error', e => { this.$message.error('代码复制失败') }) this.getDataList(); }, methods: { jsonOpen(templateJson){ let list = [] list = JSON.parse(templateJson).fields // console.log(list); list.forEach(item => { if (item.tag == "el-upload") { console.log(item); item.action = process.env.VUE_APP_BASE_API + item.action + ""; item.headers.Authorization = 'Bearer ' + getToken() } }) this.drawingList = list }, activeFormItem() { console.log("activeFormItem"); }, drawingItemCopy() { console.log("drawingItemCopy"); }, drawingItemDelete() { console.log("drawingItemDelete"); }, getDataList() { getAllList({ dictType: "project_categories" }).then(res => { res.data.map(item => { let obj = {}; obj.value = item.dictValue; obj.label = item.dictLabel; obj.dict = item.remark; this.options.push(obj); }) }) }, // 项目分类选择 changeProjectClassify(valId) { if (valId) { this.projectBigType = valId[0] this.projectMiddleType = valId[1] this.projectSmallType = valId[2] } }, // 模板有效期选择 changeDateRange(val) { // console.log('val: ', val); this.dialogForm.useStart = val[0] this.dialogForm.useEnd = val[1] }, // 取消按钮 cancel() { this.createTemplate = false; this.reset(); }, // 表单重置 reset() { this.dialogForm = { responsibilityUnit: undefined, templateName: undefined, level: undefined, projectClassify: [], reportTime: [], }; this.projectBigType = undefined this.projectMiddleType = undefined this.projectSmallType = undefined this.resetForm("form"); }, /** 提交按钮 */ submitForm: function () { this.$refs["form"].validate(valid => { if (valid) { this.createTemplate = false; } }); }, activeFormItem(element) { this.activeData = element this.activeId = element.formId }, onEnd(obj, a) { if (obj.from !== obj.to) { this.activeData = tempActiveData this.activeId = this.idGlobal } }, addComponent(item) { const clone = this.cloneComponent(item) this.drawingList.push(clone) this.activeFormItem(clone) }, cloneComponent(origin) { const clone = JSON.parse(JSON.stringify(origin)) clone.formId = ++this.idGlobal clone.span = formConf.span clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件 if (!clone.layout) clone.layout = 'colFormItem' if (clone.layout === 'colFormItem') { clone.vModel = `field${this.idGlobal}` clone.placeholder !== undefined && (clone.placeholder += clone.label) tempActiveData = clone } else if (clone.layout === 'rowFormItem') { delete clone.label clone.componentName = `row${this.idGlobal}` clone.gutter = this.formConf.gutter tempActiveData = clone } return tempActiveData }, AssembleFormData() { this.formData = { fields: JSON.parse(JSON.stringify(this.drawingList)), ...this.formConf } }, generate(data) { const func = this[`exec${titleCase(this.operationType)}`] this.generateConf = data func && func(data) }, execRun(data) { this.AssembleFormData() this.drawerVisible = true }, execDownload(data) { const codeStr = this.generateCode() const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' }) this.$download.saveAs(blob, data.fileName) }, execCopy(data) { document.getElementById('copyNode').click() }, empty() { this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then( () => { this.drawingList = [] } ) }, drawingItemCopy(item, parent) { let clone = JSON.parse(JSON.stringify(item)) clone = this.createIdAndKey(clone) parent.push(clone) this.activeFormItem(clone) }, createIdAndKey(item) { item.formId = ++this.idGlobal item.renderKey = +new Date() if (item.layout === 'colFormItem') { item.vModel = `field${this.idGlobal}` } else if (item.layout === 'rowFormItem') { item.componentName = `row${this.idGlobal}` } if (Array.isArray(item.children)) { item.children = item.children.map(childItem => this.createIdAndKey(childItem)) } return item }, drawingItemDelete(index, parent) { parent.splice(index, 1) this.$nextTick(() => { const len = this.drawingList.length if (len) { this.activeFormItem(this.drawingList[len - 1]) } }) }, generateCode() { const { type } = this.generateConf this.AssembleFormData() const script = vueScript(makeUpJs(this.formData, type)) const html = vueTemplate(makeUpHtml(this.formData, type)) const css = cssStyle(makeUpCss(this.formData)) return beautifier.html(html + script + css, beautifierConf.html) }, showJson() { this.AssembleFormData() // 级别,责任单位,模板使用有效期开始时间,模板使用有效期结束时间,模板名称 console.log(this.formData); localStorage.setItem("myJSON", JSON.stringify(this.formData)) const { level, responsibilityUnit, useStart, useEnd, templateName } = this.dialogForm; if (level && responsibilityUnit && useStart && useEnd && templateName) { // templateInfo({level, responsibilityUnit, templateName, useStart, useEnd, projectBigType:this.projectBigType, projectMiddleType:this.projectMiddleType, projectSmallType:this.projectSmallType,templateJson: JSON.stringify(this.formData)}).then(res=>{ // if(res.code == 200) { // this.$router.push({ // name: 'Template', // params: {code:200}, // }) // } // }) } else { // this.createTemplate = true; } }, download() { this.dialogVisible = true this.showFileName = true this.operationType = 'download' }, run() { this.dialogVisible = true this.showFileName = false this.operationType = 'run' }, copy() { this.dialogVisible = true this.showFileName = false this.operationType = 'copy' }, tagChange(newTag) { newTag = this.cloneComponent(newTag) newTag.vModel = this.activeData.vModel newTag.formId = this.activeId newTag.span = this.activeData.span delete this.activeData.tag delete this.activeData.tagIcon delete this.activeData.document Object.keys(newTag).forEach(key => { if (this.activeData[key] !== undefined && typeof this.activeData[key] === typeof newTag[key]) { newTag[key] = this.activeData[key] } }) this.activeData = newTag this.updateDrawingList(newTag, this.drawingList) }, updateDrawingList(newTag, list) { const index = list.findIndex(item => item.formId === this.activeId) if (index > -1) { list.splice(index, 1, newTag) } else { list.forEach(item => { if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children) }) } } }, } </script> <style lang='scss'> ::v-deep .el-form { .el-form-item__content { .el-upload-list { .el-upload-list__item{ transition: none !important; } } } } .editor-tabs { background: #121315; .el-tabs__header { margin: 0; border-bottom-color: #121315; .el-tabs__nav { border-color: #121315; } } .el-tabs__item { height: 32px; line-height: 32px; color: #888a8e; border-left: 1px solid #121315 !important; background: #363636; margin-right: 5px; user-select: none; } .el-tabs__item.is-active { background: #1e1e1e; border-bottom-color: #1e1e1e !important; color: #fff; } .el-icon-edit { color: #f1fa8c; } .el-icon-document { color: #a95812; } } // home .right-scrollbar { .el-scrollbar__view { padding: 12px 18px 15px 15px; } } .left-scrollbar .el-scrollbar__wrap { box-sizing: border-box; overflow-x: hidden !important; margin-bottom: 0 !important; } .center-tabs { .el-tabs__header { margin-bottom: 0 !important; } .el-tabs__item { width: 50%; text-align: center; } .el-tabs__nav { width: 100%; } } .reg-item { padding: 12px 6px; background: #f8f8f8; position: relative; border-radius: 4px; .close-btn { position: absolute; right: -6px; top: -6px; display: block; width: 16px; height: 16px; line-height: 16px; background: rgba(0, 0, 0, 0.2); border-radius: 50%; color: #fff; text-align: center; z-index: 1; cursor: pointer; font-size: 12px; &:hover { background: rgba(210, 23, 23, 0.5) } } &+.reg-item { margin-top: 18px; } } .action-bar { & .el-button+.el-button { margin-left: 15px; } & i { font-size: 20px; vertical-align: middle; position: relative; top: -1px; } } .custom-tree-node { width: 100%; font-size: 14px; .node-operation { float: right; } i[class*="el-icon"]+i[class*="el-icon"] { margin-left: 6px; } .el-icon-plus { color: #409EFF; } .el-icon-delete { color: #157a0c; } } .left-scrollbar .el-scrollbar__view { overflow-x: hidden; } .el-rate { display: inline-block; vertical-align: text-top; } .el-upload__tip { line-height: 1.2; } $selectedColor: #f6f7ff; $lighterBlue: #409EFF; .container { position: relative; width: 100%; min-height: 50vh; } .components-list { padding: 8px; box-sizing: border-box; height: 100%; .components-item { display: inline-block; width: 48%; margin: 1%; transition: transform 0ms !important; } } .components-draggable { padding-bottom: 20px; } .components-title { font-size: 14px; color: #222; margin: 6px 2px; .svg-icon { color: #666; font-size: 18px; } } .components-body { padding: 8px 10px; background: $selectedColor; font-size: 12px; cursor: move; border: 1px dashed $selectedColor; border-radius: 3px; .svg-icon { color: #777; font-size: 15px; } &:hover { border: 1px dashed #787be8; color: #787be8; .svg-icon { color: #787be8; } } } .left-board { width: 260px; position: absolute; left: 0; top: 0; height: 100%; } .left-scrollbar { height: calc(100% - 42px); overflow: hidden; } .center-scrollbar { width: 100%; height: calc(100% - 42px); overflow: hidden; border-left: 1px solid #f1e8e8; border-right: 1px solid #f1e8e8; box-sizing: border-box; } .center-board { height: 100%; width: auto; box-sizing: border-box; } .empty-info { position: absolute; top: 46%; left: 0; right: 0; text-align: center; font-size: 18px; color: #ccb1ea; letter-spacing: 4px; } .action-bar { position: relative; height: 42px; text-align: right; padding: 0 15px; box-sizing: border-box; ; border: 1px solid #f1e8e8; border-top: none; border-left: none; .delete-btn { color: #F56C6C; } } .logo-wrapper { position: relative; height: 42px; background: #fff; border-bottom: 1px solid #f1e8e8; box-sizing: border-box; } .logo { position: absolute; left: 12px; top: 6px; line-height: 30px; color: #00afff; font-weight: 600; font-size: 17px; white-space: nowrap; >img { width: 30px; height: 30px; vertical-align: top; } .github { display: inline-block; vertical-align: sub; margin-left: 15px; >img { height: 22px; } } } .center-board-row { padding: 12px 12px 15px 12px; box-sizing: border-box; &>.el-form { // 69 = 12+15+42 height: calc(100% - 69px); } } .drawing-board { height: 100%; position: relative; .components-body { padding: 0; margin: 0; font-size: 0; } .sortable-ghost { position: relative; display: block; overflow: hidden; &::before { content: " "; position: absolute; left: 0; right: 0; top: 0; height: 3px; background: rgb(89, 89, 223); z-index: 2; } } .components-item.sortable-ghost { width: 100%; height: 60px; background-color: $selectedColor; } .active-from-item { &>.el-form-item { background: $selectedColor; border-radius: 6px; } &>.drawing-item-copy, &>.drawing-item-delete { display: initial; } &>.component-name { color: $lighterBlue; } } .el-form-item { margin-bottom: 15px; } } .drawing-item { position: relative; cursor: move; &.unfocus-bordered:not(.activeFromItem)>div:first-child { border: 1px dashed #ccc; } .el-form-item { padding: 12px 10px; } } .drawing-row-item { position: relative; cursor: move; box-sizing: border-box; border: 1px dashed #ccc; border-radius: 3px; padding: 0 2px; margin-bottom: 15px; .drawing-row-item { margin-bottom: 2px; } .el-col { margin-top: 22px; } .el-form-item { margin-bottom: 0; } .drag-wrapper { min-height: 80px; } &.active-from-item { border: 1px dashed $lighterBlue; } .component-name { position: absolute; top: 0; left: 0; font-size: 12px; color: #bbb; display: inline-block; padding: 0 6px; } } .drawing-item, .drawing-row-item { &:hover { &>.el-form-item { background: $selectedColor; border-radius: 6px; } &>.drawing-item-copy, &>.drawing-item-delete { display: initial; } } &>.drawing-item-copy, &>.drawing-item-delete { display: none; position: absolute; top: -10px; width: 22px; height: 22px; line-height: 22px; text-align: center; border-radius: 50%; font-size: 12px; border: 1px solid; cursor: pointer; z-index: 1; } &>.drawing-item-copy { right: 56px; border-color: $lighterBlue; color: $lighterBlue; background: #fff; &:hover { background: $lighterBlue; color: #fff; } } &>.drawing-item-delete { right: 24px; border-color: #F56C6C; color: #F56C6C; background: #fff; &:hover { background: #F56C6C; color: #fff; } } } </style>