From 64d172717748c383a5c88348037354bffd60f966 Mon Sep 17 00:00:00 2001 From: gaoluyang <2820782392@qq.com> Date: 星期二, 27 五月 2025 17:52:03 +0800 Subject: [PATCH] 页面样式修改 --- src/views/tool/build/index.vue | 653 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 653 insertions(+), 0 deletions(-) diff --git a/src/views/tool/build/index.vue b/src/views/tool/build/index.vue new file mode 100644 index 0000000..e630740 --- /dev/null +++ b/src/views/tool/build/index.vue @@ -0,0 +1,653 @@ +<template> + <div class="container"> + <div class="left-board"> + <div class="logo-wrapper"> + <div class="logo"> + <img :src="logo" alt="logo"> Form Generator + </div> + </div> + <el-scrollbar class="left-scrollbar"> + <div class="components-list"> + <div class="components-title"> + <svg-icon icon-class="component" />杈撳叆鍨嬬粍浠� + </div> + <draggable class="components-draggable" :list="inputComponents" + :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent" + draggable=".components-item" :sort="false" @end="onEnd" item-key="label"> + <template #item="{ element, index }"> + <div :key="index" class="components-item" @click="addComponent(element)"> + <div class="components-body"> + <svg-icon :icon-class="element.tagIcon" /> + {{ element.label }} + </div> + </div> + </template> + </draggable> + <div class="components-title"> + <svg-icon icon-class="component" />閫夋嫨鍨嬬粍浠� + </div> + <draggable class="components-draggable" :list="selectComponents" + :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent" + draggable=".components-item" :sort="false" @end="onEnd" item-key="label"> + <template #item="{ element, index }"> + <div :key="index" class="components-item" @click="addComponent(element)"> + <div class="components-body"> + <svg-icon :icon-class="element.tagIcon" /> + {{ element.label }} + </div> + </div> + </template> + </draggable> + <div class="components-title"> + <svg-icon icon-class="component" /> 甯冨眬鍨嬬粍浠� + </div> + <draggable class="components-draggable" :list="layoutComponents" + :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent" + draggable=".components-item" :sort="false" @end="onEnd" item-key="label"> + <template #item="{ element, index }"> + <div :key="index" class="components-item" @click="addComponent(element)"> + <div class="components-body"> + <svg-icon :icon-class="element.tagIcon" /> + {{ element.label }} + </div> + </div> + </template> + </draggable> + </div> + </el-scrollbar> + </div> + <div class="center-board"> + <div class="action-bar"> + <el-button icon="Download" type="primary" text @click="download"> + 瀵煎嚭vue鏂囦欢 + </el-button> + <el-button class="copy-btn-main" icon="DocumentCopy" type="primary" text @click="copy"> + 澶嶅埗浠g爜 + </el-button> + <el-button class="delete-btn" icon="Delete" text @click="empty" type="danger"> + 娓呯┖ + </el-button> + </div> + <el-scrollbar class="center-scrollbar"> + <el-row class="center-board-row" :gutter="formConf.gutter"> + <el-form :size="formConf.size" :label-position="formConf.labelPosition" :disabled="formConf.disabled" + :label-width="formConf.labelWidth + 'px'"> + <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup" + item-key="label"> + <template #item="{ element, index }"> + <draggable-item :key="element.renderKey" :drawing-list="drawingList" :element="element" :index="index" + :active-id="activeId" :form-conf="formConf" @activeItem="activeFormItem" @copyItem="drawingItemCopy" + @deleteItem="drawingItemDelete" /> + </template> + </draggable> + <div v-show="!drawingList.length" class="empty-info"> + 浠庡乏渚ф嫋鍏ユ垨鐐归�夌粍浠惰繘琛岃〃鍗曡璁� + </div> + </el-form> + </el-row> + </el-scrollbar> + </div> + <right-panel :active-data="activeData" :form-conf="formConf" :show-field="!!drawingList.length" + @tag-change="tagChange" /> + + <code-type-dialog v-model="dialogVisible" title="閫夋嫨鐢熸垚绫诲瀷" :showFileName="showFileName" @confirm="generate" /> + <input id="copyNode" type="hidden"> + </div> +</template> + +<script setup> +import draggable from "vuedraggable/dist/vuedraggable.common" +import ClipboardJS from 'clipboard' +import beautifier from 'js-beautify' +import logo from '@/assets/logo/logo.png' +import { inputComponents, selectComponents, layoutComponents, formConf as formConfData } from '@/utils/generator/config' +import { beautifierConf } from '@/utils/index' +import drawingDefalut from '@/utils/generator/drawingDefalut' +import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html' +import { makeUpJs } from '@/utils/generator/js' +import { makeUpCss } from '@/utils/generator/css' +import Download from '@/plugins/download' +import { ElNotification } from 'element-plus' +import DraggableItem from './DraggableItem' +import RightPanel from './RightPanel' +import CodeTypeDialog from './CodeTypeDialog' +import { onMounted, watch } from 'vue' + +const drawingList = ref(drawingDefalut) +const { proxy } = getCurrentInstance() +const dialogVisible = ref(false) +const showFileName = ref(false) +const operationType = ref('') +const idGlobal = ref(100) +const activeData = ref(drawingDefalut[0]) +const activeId = ref(drawingDefalut[0].formId) +const generateConf = ref(null) +const formData = ref({}) +const formConf = ref(formConfData) +let oldActiveId +let tempActiveData + +function activeFormItem(element) { + activeData.value = element + activeId.value = element.formId +} +function copy() { + dialogVisible.value = true + showFileName.value = false + operationType.value = 'copy' +} +function download() { + dialogVisible.value = true + showFileName.value = true + operationType.value = 'download' +} +function empty() { + proxy.$modal.confirm('纭畾瑕佹竻绌烘墍鏈夌粍浠跺悧锛�', '鎻愮ず', { type: 'warning' }).then(() => { + idGlobal.value = 100 + drawingList.value = [] + } + ) +} + +function onEnd(obj, a) { + if (obj.from !== obj.to) { + activeData.value = tempActiveData + activeId.value = idGlobal.value + } +} + +function addComponent(item) { + const clone = cloneComponent(item) + drawingList.value.push(clone) + activeFormItem(clone) +} + +function cloneComponent(origin) { + const clone = JSON.parse(JSON.stringify(origin)) + clone.formId = ++idGlobal.value + clone.span = formConf.value.span + clone.renderKey = +new Date() // 鏀瑰彉renderKey鍚庡彲浠ュ疄鐜板己鍒舵洿鏂扮粍浠� + if (!clone.layout) clone.layout = 'colFormItem' + if (clone.layout === 'colFormItem') { + clone.vModel = `field${idGlobal.value}` + clone.placeholder !== undefined && (clone.placeholder += clone.label) + tempActiveData = clone + } else if (clone.layout === 'rowFormItem') { + delete clone.label + clone.componentName = `row${idGlobal.value}` + clone.gutter = formConf.value.gutter + tempActiveData = clone + } + return tempActiveData +} + +function drawingItemCopy(item, parent) { + let clone = JSON.parse(JSON.stringify(item)) + clone = createIdAndKey(clone) + parent.push(clone) + activeFormItem(clone) +} + + +function createIdAndKey(item) { + item.formId = ++idGlobal.value + item.renderKey = +new Date() + if (item.layout === 'colFormItem') { + item.vModel = `field${idGlobal.value}` + } else if (item.layout === 'rowFormItem') { + item.componentName = `row${idGlobal.value}` + } + if (Array.isArray(item.children)) { + item.children = item.children.map(childItem => createIdAndKey(childItem)) + } + return item +} + +function drawingItemDelete(index, parent) { + parent.splice(index, 1) + nextTick(() => { + const len = drawingList.value.length + if (len) { + activeFormItem(drawingList.value[len - 1]) + } + }) +} + +function tagChange(newTag) { + newTag = cloneComponent(newTag) + newTag.vModel = activeData.value.vModel + newTag.formId = activeId.value + newTag.span = activeData.value.span + delete activeData.value.tag + delete activeData.value.tagIcon + delete activeData.value.document + Object.keys(newTag).forEach(key => { + if (activeData.value[key] !== undefined + && typeof activeData.value[key] === typeof newTag[key]) { + newTag[key] = activeData.value[key] + } + }) + activeData.value = newTag + updateDrawingList(newTag, drawingList.value) +} + + +function updateDrawingList(newTag, list) { + const index = list.findIndex(item => item.formId === activeId.value) + if (index > -1) { + list.splice(index, 1, newTag) + } else { + list.forEach(item => { + if (Array.isArray(item.children)) updateDrawingList(newTag, item.children) + }) + } +} +function generate(data) { + generateConf.value = data + nextTick(() => { + switch (operationType.value) { + case 'copy': + execCopy(data) + break + case 'download': + execDownload(data) + break + default: + break + } + }) +} + +function execDownload(data) { + const codeStr = generateCode() + const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' }) + Download.saveAs(blob, data.fileName) +} + +function execCopy(data) { + document.getElementById('copyNode').click() +} +function AssembleFormData() { + formData.value = { fields: JSON.parse(JSON.stringify(drawingList.value)), ...formConf.value } +} +function generateCode() { + const { type } = generateConf.value + AssembleFormData() + const script = vueScript(makeUpJs(formData.value, type)) + const html = vueTemplate(makeUpHtml(formData.value, type)) + const css = cssStyle(makeUpCss(formData.value)) + return beautifier.html(html + script + css, beautifierConf.html) +} +watch(() => activeData.value.label, (val, oldVal) => { + if ( + activeData.value.placeholder === undefined + || !activeData.value.tag + || oldActiveId !== activeId.value + ) { + return + } + activeData.value.placeholder = activeData.value.placeholder.replace(oldVal, '') + val +}) +watch(activeId, (val) => { + oldActiveId = val +}, { immediate: true }) + +onMounted(() => { + const clipboard = new ClipboardJS('#copyNode', { + text: trigger => { + const codeStr = generateCode() + ElNotification({ title: '鎴愬姛', message: '浠g爜宸插鍒跺埌鍓垏鏉匡紝鍙矘璐淬��', type: 'success' }) + return codeStr + } + }) + clipboard.on('error', e => { + proxy.$modal.msgError('浠g爜澶嶅埗澶辫触') + }) +}) +</script> + +<style lang='scss'> +$lighterBlue: #409EFF; + +.container { + position: relative; + width: 100%; + background-color: var(--el-bg-color-overlay); + height: calc(100vh - 50px - 40px); + overflow: hidden; + + .left-board { + width: 260px; + position: absolute; + left: 0; + top: 0; + height: calc(100vh - 50px - 40px); + + .logo-wrapper { + position: relative; + height: 42px; + border-bottom: 1px solid var(--el-border-color-extra-light); + 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; + } + } + } + } + + .left-scrollbar { + .el-scrollbar__wrap { + box-sizing: border-box; + overflow-x: hidden !important; + margin-bottom: 0 !important; + + .components-list { + padding: 8px; + box-sizing: border-box; + height: 100%; + + .components-title { + font-size: 14px; + // color: #222; + margin: 6px 2px; + + .svg-icon { + // color: #666; + font-size: 18px; + margin-right: 5px; + } + } + + .components-draggable { + padding-bottom: 20px; + + .components-item { + display: inline-block; + width: 48%; + margin: 1%; + transition: transform 0ms !important; + + .components-body { + padding: 8px 10px; + background: var(--el-border-color-extra-light); + font-size: 12px; + cursor: move; + border: 1px dashed var(--el-border-color-extra-light); + border-radius: 3px; + + .svg-icon { + // color: #777; + font-size: 15px; + margin-right: 5px; + } + + &:hover { + border: 1px dashed #787be8; + color: #787be8; + + .svg-icon { + color: #787be8; + } + } + } + } + } + + + } + } + } + } + + .center-board { + height: calc(100vh - 50px - 40px); + width: auto; + margin: 0 350px 0 260px; + box-sizing: border-box; + + .action-bar { + position: relative; + height: 42px; + padding: 0 15px; + box-sizing: border-box; + ; + border: 1px solid var(--el-border-color-extra-light); + border-top: none; + border-left: none; + display: flex; + align-items: center; + justify-content: flex-end; + + u .delete-btn { + color: #F56C6C; + } + } + + .center-scrollbar { + height: calc(100vh - 50px - 40px - 42px); + overflow: hidden; + border-left: 1px solid var(--el-border-color-extra-light); + border-right: 1px solid var(--el-border-color-extra-light); + box-sizing: border-box; + + .el-scrollbar__view { + overflow-x: hidden; + } + + .center-board-row { + padding: 12px 12px 15px 12px; + box-sizing: border-box; + + &>.el-form { + // 69 = 12+15+42 + height: calc(100vh - 50px - 40px - 69px); + flex: 1; + + .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: var(--el-border-color-extra-light); + } + + .active-from-item { + &>.el-form-item { + background: var(--el-border-color-extra-light); + border-radius: 6px; + } + + &>.drawing-item-copy, + &>.drawing-item-delete { + display: initial; + } + + &>.component-name { + color: $lighterBlue; + } + + .el-input__wrapper { + box-shadow: 0 0 0 1px var(--el-input-hover-border-color) inset; + } + } + + .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; + flex: 1; + display: flex; + flex-wrap: wrap; + } + + &.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: var(--el-border-color-extra-light); + 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; + } + } + } + + .empty-info { + position: absolute; + top: 46%; + left: 0; + right: 0; + text-align: center; + font-size: 18px; + color: #ccb1ea; + letter-spacing: 4px; + } + + } + } + } + } +} +</style> -- Gitblit v1.9.3