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