瀏覽代碼

表单组布局功能,初步搭建

lph 1 年之前
父節點
當前提交
a41e9ad9c6

+ 1 - 1
zkqy-ui/src/assets/js/kFormDesign.js

@@ -575,7 +575,7 @@ let tempData = [
         "icon": "icon-fengexian",
         "options": {
           "orientation": "left",
-          "noFormItem": true
+          "noFormItem": true,
         },
         "key": "",
         "model": ""

+ 1 - 1
zkqy-ui/src/views/system/bpmnPro/index.vue

@@ -251,7 +251,7 @@ export default {
     processTypeOption() {
       let tenantProfession = this.user.tenant.tenantProfession;
 
-      let isMES = tenantProfession.includes("MES");
+      let isMES = tenantProfession?.includes("MES");
       if (isMES) {
         //mes
         this.processTypeOptions = this.dict.type.bpm_type;

+ 168 - 0
zkqy-ui/src/views/system/formGroupMange/component/CenterArea.vue

@@ -0,0 +1,168 @@
+<template>
+  <div class="center-area">
+    <p class="hint-text" v-show="data.list.length === 0">
+      <a-empty description="从左侧选择控件添加" />
+    </p>
+
+    <draggable
+      v-show="data.list.length !== 0"
+      tag="div"
+      class="draggable-box"
+      v-bind="{
+        group: 'form-draggable',
+        ghostClass: 'moving',
+        animation: 180,
+        handle: '.drag-move',
+      }"
+      v-model="data.list"
+      @add="deepClone"
+      @start="dragStart($event, data.list)"
+    >
+      <transition-group tag="div" name="list" class="list-main">
+        <LayoutItem
+          v-for="(item, index) in data.list"
+          :key="index"
+          class="drag-move"
+          :record="item"
+          :selectItem.sync="selectItem"
+          @handleColAdd="handleColAdd"
+          @dragStart="dragStart"
+          @handleSelectItem="handleSelectItem"
+          @handleDelete="handleDelete"
+          @handleShowRightMenu="handleShowRightMenu"
+        />
+      </transition-group>
+    </draggable>
+  </div>
+</template>
+
+<script>
+import LayoutItem from "./LayoutItem.vue";
+import draggable from "vuedraggable";
+export default {
+  name: "CenterArea",
+  props: ["selectItem", "data"],
+  components: { LayoutItem, draggable },
+  data() {
+    return {};
+  },
+  computed: {},
+  methods: {
+    // 递归 删除已选择
+    handleDelete(ele) {
+      console.log("删除的元素", ele);
+      // 删除已选择
+      const traverse = (array) => {
+        array = array.filter((element, index) => {
+          if (["grid", "tabs", "selectInputList"].includes(element.type)) {
+            // 栅格布局
+            element.columns.forEach((item) => {
+              item.list = traverse(item.list);
+            });
+          }
+          if (element.type === "card" || element.type === "batch") {
+            // 卡片布局
+            element.list = traverse(element.list);
+          }
+          if (element.type === "table") {
+            // 表格布局
+            element.trs.forEach((item) => {
+              item.tds.forEach((val) => {
+                val.list = traverse(val.list);
+              });
+            });
+          }
+          if (element.key !== ele.key) {
+            return true;
+          } else {
+            if (array.length === 1) {
+              this.handleSelectItem({ key: "" });
+            } else if (array.length - 1 > index) {
+              this.handleSelectItem(array[index + 1]);
+            } else {
+              this.handleSelectItem(array[index - 1]);
+            }
+            return false;
+          }
+        });
+        return array;
+      };
+
+      this.data.list = traverse(this.data.list);
+    },
+    deepClone(evt) {
+      const newIndex = evt.newIndex;
+      // json深拷贝一次
+      const listString = JSON.stringify(this.data.list);
+      this.data.list = JSON.parse(listString);
+      // 删除icon及compoent属性
+      delete this.data.list[newIndex].icon;
+      delete this.data.list[newIndex].component;
+      this.$emit("setCurrentTarget", this.data.list[newIndex]);
+    },
+    dragStart(e, list) {
+      this.$emit("setCurrentTarget", list[e.oldIndex]);
+    },
+    handleSelectItem(item) {
+      this.$emit("setCurrentTarget", item);
+    },
+    handleShowRightMenu() {},
+    handleColAdd(evt, columns, isCopy = false) {
+      // 重置或者生成key值
+      const newIndex = evt.newIndex;
+      const key = columns[newIndex].type + "_" + new Date().getTime();
+      if (columns[newIndex].key === "" || isCopy) {
+        this.$set(columns, newIndex, {
+          ...columns[newIndex],
+          key,
+          model: key,
+        });
+        if (this.noModel.includes(columns[newIndex].type)) {
+          // 删除不需要的model属性
+          delete columns[newIndex].model;
+        }
+        if (typeof columns[newIndex].options !== "undefined") {
+          // 深拷贝options
+          const optionsStr = JSON.stringify(columns[newIndex].options);
+          columns[newIndex].options = JSON.parse(optionsStr);
+        }
+        if (typeof columns[newIndex].rules !== "undefined") {
+          // 深拷贝rules
+          const rulesStr = JSON.stringify(columns[newIndex].rules);
+          columns[newIndex].rules = JSON.parse(rulesStr);
+        }
+        if (typeof columns[newIndex].list !== "undefined") {
+          // 深拷贝list
+          columns[newIndex].list = [];
+        }
+        if (typeof columns[newIndex].columns !== "undefined") {
+          // 深拷贝columns
+          const columnsStr = JSON.stringify(columns[newIndex].columns);
+          columns[newIndex].columns = JSON.parse(columnsStr);
+          // 复制时,清空数据
+          columns[newIndex].columns.forEach((item) => {
+            item.list = [];
+          });
+        }
+        if (columns[newIndex].type === "table") {
+          // 深拷贝trs
+          const trsStr = JSON.stringify(columns[newIndex].trs);
+          columns[newIndex].trs = JSON.parse(trsStr);
+          // 复制时,清空数据
+          columns[newIndex].trs.forEach((item) => {
+            item.tds.forEach((val) => {
+              val.list = [];
+            });
+          });
+        }
+      }
+      // 深拷贝数据
+      const listString = JSON.stringify(columns[newIndex]);
+      columns[newIndex] = JSON.parse(listString);
+      this.$emit("handleSetSelectItem", columns[newIndex]);
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss"></style>

+ 71 - 0
zkqy-ui/src/views/system/formGroupMange/component/DragPosition.vue

@@ -0,0 +1,71 @@
+<template>
+  <div class="main-wrap">
+    <div class="drag-position">
+      <!-- 左侧面板区域 start-->
+      <LetfPanel
+        :formList="formList"
+        @handleClick="panelClickHandler"
+      ></LetfPanel>
+      <!-- 左侧面板区域 end-->
+      <!-- 中间拖拽区域 start-->
+      <div class="drag-wrap">
+        <CenterArea
+          :data="layoutData"
+          :selectItem="selectItem"
+          @setCurrentTarget="setCurrentTarget"
+          ref="centerAreaRef"
+        ></CenterArea>
+      </div>
+      <!-- 中间拖拽区域 end-->
+    </div>
+  </div>
+</template>
+
+<script>
+import { formList } from "./tempJson.js";
+
+import LetfPanel from "./LetfPanel.vue";
+import CenterArea from "./CenterArea.vue";
+export default {
+  name: "DragPosition",
+  props: [],
+  components: { LetfPanel, CenterArea },
+  data() {
+    return {
+      layoutData: {
+        list: [],
+      },
+      mainList: [], //拖拽区域数据
+      selectItem: null, //当前拖拽对象
+    };
+  },
+  computed: {
+    formList() {
+      return formList;
+    },
+  },
+  methods: {
+    panelClickHandler(item) {
+      this.selectItem = item;
+      this.mainList.push(item);
+      this.layoutData.list.push(item);
+      console.log(this.mainList);
+    },
+    setCurrentTarget(item) {
+      console.log("this.selectItem", item);
+      this.selectItem = item;
+      console.log("layoutData", this.layoutData);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.drag-position {
+  display: flex;
+  .drag-wrap {
+    padding: 10px;
+    flex: 1;
+  }
+}
+</style>

+ 33 - 0
zkqy-ui/src/views/system/formGroupMange/component/FormCard.vue

@@ -0,0 +1,33 @@
+<template>
+  <div class="card-wrap">
+    <i class="el-icon-c-scale-to-original mr10"></i>
+    <span>{{ record.title }}</span>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "FormCard",
+  props: ["record"],
+  components: {},
+  data() {
+    return {};
+  },
+  computed: {},
+  methods: {},
+};
+</script>
+
+<style scoped lang="scss">
+.card-wrap {
+  width: 100%;
+  padding: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.card-wrap:hover {
+  background: #f5f7fa;
+  color: lightblue;
+}
+</style>

+ 186 - 0
zkqy-ui/src/views/system/formGroupMange/component/LayoutItem.vue

@@ -0,0 +1,186 @@
+<template>
+  <div class="layout-width">
+    <template v-if="record.type == 'tabs'">
+      <div
+        class="grid-box"
+        :class="{ active: record.key === selectItem.key }"
+        @click.stop="handleSelectItem(record)"
+      >
+        <el-tabs value="1">
+          <el-tab-pane
+            v-for="(tabItem, index) in record.columns"
+            :key="index"
+            :label="tabItem.label"
+            :name="tabItem.value"
+          >
+            <div class="grid-box-content">
+              <draggable
+                tag="div"
+                class="draggable-box"
+                v-bind="{
+                  group: 'form-draggable',
+                  ghostClass: 'moving',
+                  animation: 180,
+                  handle: '.drag-move',
+                }"
+                v-model="tabItem.list"
+                @start="$emit('dragStart', $event, tabItem.list)"
+                @add="$emit('handleColAdd', $event, tabItem.list)"
+              >
+                <!-- @start="$emit('dragStart', $event, tabItem.list)"
+                @add="$emit('handleColAdd', $event, tabItem.list)" -->
+                <transition-group tag="div" name="list" class="list-main">
+                  <LayoutItem
+                    class="drag-move"
+                    v-for="(item, index) in tabItem.list"
+                    :key="index"
+                    :selectItem.sync="selectItem"
+                    :record="item"
+                    @handleDelete="handleDelete"
+                  />
+                </transition-group>
+              </draggable>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+        <div
+          class="delete"
+          :class="record.key === selectItem.key ? 'active' : 'unactivated'"
+          @click.stop="deleHandle(record)"
+        >
+          <i class="el-icon-delete"></i>
+        </div>
+      </div>
+    </template>
+    <template v-else-if="record.type == 'grid'">
+      <!-- 栅格布局 -->
+      <div
+        class="grid-box"
+        :class="{ active: record.key === selectItem.key }"
+        @click.stop="handleSelectItem(record)"
+      >
+        <el-row class="grid-row" :gutter="record.options.gutter">
+          <el-col
+            class="grid-col"
+            v-for="(colItem, idnex) in record.columns"
+            :key="idnex"
+            :span="colItem.span || 0"
+          >
+            <div class="grid-box-content">
+              <draggable
+                tag="div"
+                class="draggable-box"
+                v-bind="{
+                  group: 'form-draggable',
+                  ghostClass: 'moving',
+                  animation: 180,
+                  handle: '.drag-move',
+                }"
+                v-model="colItem.list"
+                @start="$emit('dragStart', $event, colItem.list)"
+                @add="$emit('handleColAdd', $event, colItem.list)"
+              >
+                <transition-group tag="div" name="list" class="list-main">
+                  <LayoutItem
+                    class="drag-move"
+                    v-for="(item, index) in colItem.list"
+                    :key="index"
+                    :selectItem.sync="selectItem"
+                    :record="item"
+                    @handleDelete="handleDelete"
+                  />
+                </transition-group>
+              </draggable>
+            </div>
+          </el-col>
+        </el-row>
+        <div
+          class="delete"
+          :class="record.key === selectItem.key ? 'active' : 'unactivated'"
+          @click.stop="deleHandle(record)"
+        >
+          <i class="el-icon-delete"></i>
+        </div>
+      </div>
+    </template>
+    <template v-else-if="record.type == 'divider'">
+      <!-- 分割线 -->
+      <div
+        class="grid-box"
+        style="width: 100%"
+        :class="{ active: record.key === selectItem.key }"
+        @click.stop="handleSelectItem(record)"
+      >
+        <el-divider :content-position="record.options.orientation">{{
+          record.options.title || ""
+        }}</el-divider>
+      </div>
+    </template>
+    <template v-else-if="record.type == 'form'">
+      <form-card :record="record"></form-card>
+      <!-- <div
+          class="copy"
+          :class="record.key === selectItem.key ? 'active' : 'unactivated'"
+          @click.stop="$emit('handleCopy')"
+        >
+          <a-icon type="copy" />
+        </div> -->
+      <div
+        class="delete"
+        :class="record.key === selectItem.key ? 'active' : 'unactivated'"
+        @click.stop="deleHandle(record)"
+      >
+        <i class="el-icon-delete"></i>
+      </div>
+    </template>
+  </div>
+</template>
+
+<script>
+import FormCard from "./FormCard.vue";
+import draggable from "vuedraggable";
+export default {
+  name: "LayoutItem",
+  props: ["record", "selectItem"],
+  components: { FormCard, draggable },
+  data() {
+    return {};
+  },
+  computed: {},
+  methods: {
+    // 删除
+    deleHandle(record) {
+      console.log("dele", record);
+      this.$emit("handleDelete", record);
+    },
+    handleSelectItem(record) {
+      this.$emit("handleSelectItem", record);
+    },
+    handleDelete(record) {
+      this.$emit("handleDelete", record);
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.grid-box-content {
+  min-height: 60px !important;
+  min-width: 50px !important;
+  border: 1px dashed #ccc;
+  background: #fff;
+}
+.layout-width {
+  position: relative;
+  .delete {
+    position: absolute;
+    top: 0;
+    right: 0;
+    width: 30px;
+    height: 30px;
+    line-height: 30px;
+    text-align: center;
+    color: #ee88e5;
+  }
+}
+</style>

+ 143 - 0
zkqy-ui/src/views/system/formGroupMange/component/LetfPanel.vue

@@ -0,0 +1,143 @@
+<template>
+  <div class="left-panel-wrap">
+    <el-menu default-active="2" class="el-menu-vertical-demo">
+      <el-submenu index="1">
+        <template slot="title">
+          <i class="el-icon-tickets"></i>
+          <span>表单</span>
+        </template>
+        <draggable
+          :value="panelList"
+          v-bind="{
+            group: { name: 'form-draggable', pull: 'clone', put: false },
+            sort: false,
+            animation: 180,
+            ghostClass: 'moving',
+          }"
+        >
+          <el-menu-item
+            @click="handleClick(item)"
+            v-for="item in panelList"
+            :key="item.title"
+            >{{ item.title }}</el-menu-item
+          >
+        </draggable>
+      </el-submenu>
+      <el-submenu index="2">
+        <template slot="title">
+          <i class="el-icon-s-grid"></i>
+          <span>布局控件</span>
+        </template>
+        <draggable
+          :value="panelList"
+          v-bind="{
+            group: { name: 'form-draggable', pull: 'clone', put: false },
+            sort: false,
+            animation: 180,
+            ghostClass: 'moving',
+          }"
+        >
+          <el-menu-item
+            @click="handleClick(item)"
+            v-for="item in layoutList"
+            :key="item.label"
+            >{{ item.label }}</el-menu-item
+          >
+        </draggable>
+      </el-submenu>
+    </el-menu>
+  </div>
+</template>
+
+<script>
+import draggable from "vuedraggable";
+export default {
+  name: "LetfPanel",
+  props: ["formList"],
+  components: { draggable },
+  data() {
+    return {
+      layoutList: [
+        {
+          label: "标签页布局",
+          type: "tabs",
+          options: {
+            tabBarGutter: null,
+            type: "line",
+            tabPosition: "top",
+            size: "default",
+            noFormItem: true,
+            animated: true,
+          },
+          columns: [
+            {
+              value: "1",
+              label: "选项1",
+              list: [],
+            },
+            {
+              value: "2",
+              label: "选项2",
+              list: [],
+            },
+          ],
+          key: "",
+          model: "",
+        },
+        {
+          type: "grid",
+          label: "栅格布局",
+          icon: "icon-zhage",
+          columns: [
+            {
+              span: 12,
+              list: [],
+            },
+            {
+              span: 12,
+              list: [],
+            },
+          ],
+          options: {
+            noFormItem: true,
+            gutter: 0,
+          },
+          key: "",
+          model: "",
+        },
+        {
+          type: "divider",
+          label: "分割线",
+          icon: "icon-fengexian",
+          options: {
+            orientation: "left",
+            noFormItem: true,
+            title: "提示信息",
+          },
+          key: "",
+          model: "",
+        },
+      ],
+    };
+  },
+  computed: {
+    panelList() {
+      let list = this.formList.map((item) => {
+        item.type = "form";
+        item.title = item.dfName;
+        return item;
+      });
+      return list;
+    },
+  },
+  methods: {
+    handleClick(item) {
+      console.log(item);
+      item.key = item.type + "_" + new Date().getTime();
+      this.$emit("handleClick", item);
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss"></style>

文件差異過大導致無法顯示
+ 5 - 0
zkqy-ui/src/views/system/formGroupMange/component/tempJson.js


+ 22 - 2
zkqy-ui/src/views/system/formGroupMange/index.vue

@@ -158,6 +158,15 @@
                   >修改
                 </el-button></el-dropdown-item
               >
+              <el-dropdown-item
+                ><el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-edit"
+                  @click="handlePosition(scope.row)"
+                  >设置布局
+                </el-button></el-dropdown-item
+              >
               <el-dropdown-item>
                 <el-button
                   size="mini"
@@ -549,7 +558,10 @@
         </span>
       </template>
     </el-dialog>
-    <!-- 新增条件弹窗 -->
+    <!-- 布局弹窗 -->
+    <el-dialog title="布局" :visible.sync="layoutShow" fullscreen>
+      <DragPosition></DragPosition>
+    </el-dialog>
   </div>
 </template>
 
@@ -570,11 +582,12 @@ import {
   getListName,
   dragTablePreview,
 } from "@/api/dragform/form.js";
+import DragPosition from "./component/DragPosition.vue";
 
 export default {
   name: "formRelateMange",
   props: [],
-  components: {},
+  components: { DragPosition },
   data() {
     return {
       // 弹窗相关数据
@@ -670,6 +683,9 @@ export default {
       ],
       conditionTableShow: true,
       // end
+      // 布局数据  start
+      layoutShow: false,
+      // 布局数据  end
     };
   },
   computed: {
@@ -684,6 +700,10 @@ export default {
     this.getList();
   },
   methods: {
+    // 布局回调
+    handlePosition(row) {
+      this.layoutShow = true;
+    },
     //条件编辑确认回调
     conditionConfirmHandler() {
       if (this.flag == "query") {

部分文件因文件數量過多而無法顯示