nbcio-boot移植到若依ruoyi-nbcio平台里一formdesigner部分(二)

news/2024/7/10 0:29:13 标签: formdesigner, vue, ruoyi

接第一部分

1、在tools目录下建立formdesigner的index.vue,主要是获取参数,调用formdesigner组件,内容如下:

<template>
  <div>
    <form-designer ref="formDesigner" :queryId="routeQueryId" v-model="form.fdForm"></form-designer>
  </div>
</template>

<script>
export default {
  name: 'designerExapmle',
  data() {
    return {
      form: {
        fdForm: ''
      },
      routeQueryId: '',
    }
  },
  created() {
    this.routeQueryId = this.$route.query && this.$route.query.formId;
  },
  mounted() {
  },
}
</script>

<style>

</style>

2、组件里的formdesigner.vue主要是获取form信息,同时赋值,再调用designer组件,并传递相关参数,具体代码如下:

<template>
  <div class="container">
    <div class="left-board">
      <div class="d-logo-wrapper">
        <div class="d-logo">
          Form designer
        </div>
      </div>

      <el-scrollbar class="left-scrollbar">
        <!--左侧组件列表-->
        <div class="components-list">
          <div class="components-title">
            常用组件
          </div>
          <draggable
            class="components-draggable"
            :list="formItems"
            :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
            :clone="cloneComponent"
            draggable=".components-item"
            :sort="false"
            @start="onStart"
            @end="onEnd"
          >
            <div
              v-for="(element, index) in formItems" :key="index" class="components-item"
              @click="addComponent(element)"
            >
              <div class="components-body" :class="{ 'dynamicTable-tips': dynamicTableExist(element)}">
                <icon :code="element.compIcon" :text="element.compName"/>
              </div>
            </div>
          </draggable>
          <div class="components-title">
            布局组件
          </div>
          <draggable
            class="components-draggable"
            :list="layoutFormItems"
            :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
            :clone="cloneComponent"
            draggable=".components-item"
            :sort="false"
            @start="onStart"
            @end="onEnd"
          >
            <div
              v-for="(element, index) in layoutFormItems" :key="index" class="components-item"
              @click="addComponent(element)"
            >
              <div class="components-body">
                <icon :code="element.compIcon" :text="element.compName"/>
              </div>
            </div>
          </draggable>
          <div class="components-title">
            辅助组件
          </div>
          <draggable
            class="components-draggable"
            :list="assistFormItems"
            :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
            :clone="cloneComponent"
            draggable=".components-item"
            :sort="false"
            @start="onStart"
            @end="onEnd"
          >
            <div
              v-for="(element, index) in assistFormItems" :key="index" class="components-item"
              @click="addComponent(element)"
            >
              <div class="components-body">
                <icon :code="element.compIcon" :text="element.compName"/>
              </div>
            </div>
          </draggable>
        </div>
      </el-scrollbar>
    </div>
    <designer ref="designer" :queryId="routeQueryId" :list="designList" :formConfig="formConfig" :inform="inform" @clear="designList = []" @updateJSON="handlerUpdateJSON" :activeData="activeData"/>
  </div>
</template>
<script>
/**
 * 1.0版本
 */
import draggable from "vuedraggable";
import {formItems,assistFormItems,layoutFormItems} from "./custom/itemList";
import designer from "./designer";
import icon from "./icon";
import {getSimpleId,setTableId} from "./utils/IdGenerate";
import formConf from "./custom/formConf";
import {dynamicTableAllowedItems} from "./custom/formConf";
import {getForm, addForm, updateForm} from "@/api/workflow/form";

let tempActiveData;

export default {
  name:"formDesigner",
  components:{
    draggable
    ,icon,
    designer
  },
  data() {
    return {
      formItems:formItems,
      assistFormItems:assistFormItems,
      layoutFormItems:layoutFormItems,
      designList:[],
      activeData:{},
      formConfig:formConf,
      routeQueryId:'',
      inform:[],
    }
  },
  props:{
    value:{
      type:String,
      default:''
    },
    queryId:{
      type:String,
      default:''
    }
  },
  created() {// add by nbacheng 2023-09-10
    const that = this;
    const id =  that.queryId;
    console.log("formDesigner mounted queryId",that.queryId);
    if (id) {
      getForm(id).then(res =>{
        console.log("getForm res=",res);
        const content = JSON.parse(res.data.content);
        that.formConfig = content.config;
        that.designList = content.list;
        that.inform = res.data;
      })
    }
  },
  mounted() {

  },
  methods: {
    addComponent(element){

    },
    cloneComponent(origin){
      const clone = JSON.parse(JSON.stringify(origin))
      if (!clone.layout) clone.layout = 'colItem'
      if (clone.layout === 'colItem'||clone.layout === 'dynamicItem') {
        let uId = "fd_"+getSimpleId();
        clone.id = uId;
        clone._id = uId;
        tempActiveData = clone;
      }else if (clone.layout === 'rowItem'){
        let uId = "row_"+getSimpleId();
        clone.id = uId;
        clone._id = uId;
        tempActiveData = clone;
      }else if(clone.layout === 'tableItem'){
        let uId = "table_"+getSimpleId();
        clone.id = uId;
        clone._id = uId;
        //增加td默认的id
        setTableId(clone);
        tempActiveData = clone;
      }
      this.$refs.designer.activeItem = tempActiveData;
    },
    onStart(obj){

    },
    onEnd(obj){
      if(obj.from !== obj.to){
        this.activeData = tempActiveData;
        this.$refs.designer.activeItem = this.activeData;
        if(obj.to.className.indexOf('row-drag')<0){
          this.designList.splice(obj.newIndex,0,this.activeData);
        }
      }else{
        this.$refs.designer.activeItem = {};
      }

    },
    getFormData(){
      return this.formData;
    },
    handlerUpdateJSON(json){
      const jsonObject = JSON.parse(json);
      this.designList = [];
      this.designList = this.designList.concat(jsonObject.list);
      this.formConfig = Object.assign({}, jsonObject.config);
      this.$refs['designer'].changeFormConfig(this.formConfig);
    }
  },
  computed:{
    formData:function(){
      const list = this.designList;
      const config = this.formConfig;
      let formData = {};
      formData.list = list;
      formData.config = config;
      console.log("formDesigner formData=",formData);
      return JSON.stringify(formData);
        //this.$emit('input',JSON.stringify(formData));
    },
    dynamicTableExist(){
      return function(element){
        return  this.formConfig.dynamicTableAllowed
            &&this.designList.filter(item=>item.compType === 'dynamicTable').length>0
            &&dynamicTableAllowedItems.includes(element.compType);
      }
    }
  },
  watch:{
    value(newVal){
      if(newVal !==''){
        const formData = JSON.parse(newVal);
        this.designList= formData.list;
        this.formConfig = formData.config;
      }
    }
  }
}

</script>
<style scoped>
.container{
  padding:0px
}
.dynamicTable-tips{
  border:1px solid#F08080
}
</style>

3、组件里的designer.vue主要增加一个保存按钮与相关方法,具体代码如下:

<template>
  <!--中间面板-->
  <div class="center-board" >
    <div class="action-bar">
      <el-button icon="el-icon-plus" type="text" @click="save">
        保存
      </el-button>
      <el-button icon="el-icon-view" type="text" @click="preview">
        预览
      </el-button>
      <el-button icon="el-icon-view" type="text" @click="view">
        查看
      </el-button>
      <el-button icon="el-icon-tickets" type="text" @click="viewJSON">
        JSON
      </el-button>
      <el-button icon="el-icon-s-tools" type="text" @click="setting">
        设置
      </el-button>
      <el-button class="delete-btn" icon="el-icon-delete-solid" type="text" @click="clear">
        清空
      </el-button>
      <el-button icon="el-icon-question" type="text" @click="help">
        帮助
      </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'"
                class="design-form"
        >
          <draggable
                  class="drawing-board center-board-row"
                  :list="list"
                  :animation="100"
                  group="componentsGroup"
          >
            <template v-for="element in list">
              <el-row
                      :gutter="element.gutter"
                      class="drawing-item"
              >
                <design-item
                        :model="element"
                        :activeItem="activeItem"
                        @rowItemRollBack="handlerRollBack"
                        @onActiveItemChange="handlerActiveItemChange"
                        @copyItem="handlerItemCopy"
                        @deleteItem="handlerItemDelete"
                />
              </el-row>
            </template>
          </draggable>
          <div v-show="infoShow" class="empty-info">
            <el-empty description="从左侧拖拽添加控件"></el-empty>
          </div>
        </el-form>
      </el-row>
    </el-scrollbar>
    <config-panel :activeItem="activeItem" :itemList="list" :formConf="formConf"/>
    <!-- 设计器配置弹出框 -->
    <el-dialog  :visible.sync="formConfVisible" width="50%" top="30px" :center="true">
      <el-tabs v-model="activeName">
        <el-tab-pane label="表单配置" name="formConf">
          <el-form ref="formConf" :model="formConf" label-width="100px">
            <el-form-item label="表单名">
              <el-input class="input" v-model="formConf.formRef"></el-input>
            </el-form-item>
            <el-form-item label="表单模型">
              <el-input class="input" v-model="formConf.formModel"></el-input>
            </el-form-item>
            <el-form-item label="校验模型">
              <el-input class="input" v-model="formConf.formRules"></el-input>
            </el-form-item>
            <el-form-item label="表单尺寸">
              <el-radio-group v-model="formConf.size">
                <el-radio-button label="medium">中等</el-radio-button>
                <el-radio-button label="small">较小</el-radio-button>
                <el-radio-button label="mini">迷你</el-radio-button>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="标签对齐">
              <el-radio-group v-model="formConf.labelPosition">
                <el-radio-button label="right">右对齐</el-radio-button>
                <el-radio-button label="left">左对齐</el-radio-button>
                <el-radio-button label="top">顶部对齐</el-radio-button>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="标签宽度">
              <el-input-number v-model="formConf.labelWidth"  :min="60" :max="140"></el-input-number>
            </el-form-item>
            <el-form-item label="栅格间隔">
              <el-input-number v-model="formConf.gutter"  :min="0" :max="30"></el-input-number>
            </el-form-item>
            <el-form-item label="动态表格支持组件高亮显示">
              <el-switch v-model="formConfig.dynamicTableAllowed"></el-switch>
            </el-form-item>
            <el-form-item label="禁用表单">
              <el-switch v-model="formConf.disabled"></el-switch>
            </el-form-item>
            <el-form-item label="表单样式表">
              <css-codemirror ref="cssCodemirror"  :formConf="formConf"></css-codemirror>
            </el-form-item>
          </el-form>
        </el-tab-pane>
        <!-- <el-tab-pane label="提交前" name="fourth">开发中...</el-tab-pane> -->
      </el-tabs>
      <span slot="footer" class="dialog-footer">
            <el-button type="primary" @click="handlerSaveFormConf">确 定</el-button>
        </span>
    </el-dialog>
    <el-dialog :visible.sync="previewVisible" width="70%" title="预览">
      <preview :itemList="itemList"  :formConf="formConf" v-if="previewVisible"/>
    </el-dialog>
    <el-dialog :visible.sync="JSONVisible" width="70%" title="JSON" center :close-on-click-modal="false">
      <codemirror v-model="viewCode" :options="options"/>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="handlerSetJson()">确 定</el-button>
      </span>
    </el-dialog>
    <!--表单配置详情  add by nbacheng 2022-09-05-->
    <el-dialog :title="formTitle" :visible.sync="formOpen" width="500px" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="表单名称" prop="formName">
          <el-input v-model="form.formName" placeholder="请输入表单名称" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" placeholder="请输入备注" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
  import draggable from "vuedraggable";
  import configPanel from './configPanel'
  import designItem from './designItem'
  import {getSimpleId} from "./utils/IdGenerate";
  import { isLayout, isTable, inTable,jsonClone } from "./utils/index";
  import formConf from "./custom/formConf";
  import preview from "./preview";
  import {codemirror} from 'vue-codemirror';
  // 核心样式
  import 'codemirror/lib/codemirror.css';
  // 引入主题后还需要在 options 中指定主题才会生效
  import 'codemirror/theme/dracula.css';
  import 'codemirror/mode/javascript/javascript'
  import cssCodemirror from '../components/custom/css/cssCodemirror'
  import {addForm, updateForm} from "@/api/workflow/form";

  export default {
    name:"designer",
    components:{
      draggable,
      configPanel,
      designItem,
      preview,
      codemirror,
      cssCodemirror
    },
    props:{
      list: {
        type: Array,
        default:[]
      },
      formConfig:{
      type:Object,
      default:formConf
      },
      inform: {
        type:Array,
        default:[]
      },
      queryId: {
        type:String,
        default:''
      }
    },
    provide(){
      return{
        getContext:this
      }
    },
    data() {
      return {
        formConf:formConf,
        activeItem:{},
        lastActiveItem:{},
        formConfVisible:false,
        previewVisible:false,
        JSONVisible:false,
        itemList:[],
        activeName:'formConf',
        editorCode:'',
        viewCode:'',
         formOpen: false,
         formTitle: "",
         // 表单参数
         form: {
           formId: null,
           formName: null,
           content: null,
           remark: null
         },
         // 表单校验
         rules: {},
        // 默认配置
        options: {
          tabSize: 2, // 缩进格式
          theme: 'dracula', // 主题,对应主题库 JS 需要提前引入
          lineNumbers: true, // 显示行号
          line: true,
          styleActiveLine: true, // 高亮选中行
          hintOptions: {
            completeSingle: true // 当匹配只有一项的时候是否自动补全
          }
        }
      }
    },
    mounted() {
    },
    methods: {
    save(){// add by nbacheng 2022-09-05
      console.log("save inform=",this.inform);
      if (this.inform.formId) {
        this.form.formId = this.inform.formId;
        this.form.formName = this.inform.formName;
        this.form.remark = this.inform.remark;
      }
      /** 表单保存基本信息 */
       this.formData = {
         list: this.list,
         config: this.formConf
       }
       console.log("save this.formData=",this.formData);
       this.form.content = JSON.stringify(this.formData);
       this.formOpen = true;
       if (this.inform.formId) {
         this.formTitle = "修改表单";
       }
       else {
         this.formTitle = "添加表单";
       }
       console.log("save form=",this.form);
    },
      changeFormConfig(formConfig){
        this.formConf = formConfig;
      },
      preview(){
        const clone = JSON.parse(JSON.stringify(this.list))
        this.itemList = clone;
        this.previewVisible= true;
      },
      viewJSON(){
        this.viewCode = this.code;
        this.JSONVisible = true;
      },
      // 表单重置
    reset() {
      this.form = {
        formId: null,
        formName: null,
        content: null,
        remark: null
      };
      this.resetForm("form");
    },
    // 取消按钮
    cancel() {
      this.formOpen = false;
      this.reset();
    },
    /** 保存表单信息 */
    submitForm(){
      this.$refs["form"].validate(valid => {
        if (valid) {
          if (this.form.formId != null) {
            updateForm(this.form).then(response => {
              this.$message.success("修改成功");
            });
          } else {
            addForm(this.form).then(response => {
              this.$message.success("新增成功");
            });
          }
          this.list = []
          this.idGlobal = 100
          this.formOpen = false;
          // 关闭当前标签页并返回上个页面
          this.$store.dispatch("tagsView/delView", this.$route);
          this.$router.go(-1)
        }
      });
    },
      view(){
        localStorage.setItem("formValue",this.code);
        window.open('#/view');
      },
      setting(){
        this.formConfVisible = true;
      },
      clear(){
        this.$confirm('此操作将清空整个表单,是否继续?').then(() => {
          this.$emit('clear');
        })
      },
      help(){
        window.open('https://gitee.com/wurong19870715/formDesigner')
      },
      handlerActiveItemChange(obj){
        this.lastActiveItem = this.activeItem;
        this.activeItem = obj;
      },
      handlerItemCopy(origin,parent){
        if(isLayout(origin)){ //row
          const clone = jsonClone(origin);
          const uId = "row_"+getSimpleId();
          console.log(uId);
          clone.id = uId;
          clone._id = uId;
          clone.columns.map((column)=>{
            let itemList = [];
            column.list.map((item)=>{
              const cloneItem = jsonClone(item);
              const uId = "fd_"+getSimpleId();
              cloneItem.id = uId;
              cloneItem._id = uId;
              itemList.push(cloneItem);
            })
            column.list = [];
            column.list = itemList;
          })
          this.list.push(clone);
          this.handlerActiveItemChange(clone);
        }else if(isTable(origin)){  //表格布局
          const clone = jsonClone(origin);
          const uId = "table_"+getSimpleId();
          clone.id = uId;
          clone._id = uId;
          clone.layoutArray.map((tr)=>{
            tr.map(td=>{
              let itemList = [];
              td.id=getSimpleId();
              td.columns.map((item,i)=>{
                const cloneItem = jsonClone(item);
                const uId = "fd_"+getSimpleId();
                cloneItem.id = uId;
                cloneItem._id = uId;
                itemList.push(cloneItem);
              })
              td.columns = [];
              td.columns = itemList;
            });
          })
          this.list.push(clone);
          this.handlerActiveItemChange(clone);
        }else{  //如果是普通组件,需要判断他是否再布局组件下。
          if(parent){
            if (inTable(parent)) { //增加表格组件的支持
              if (parent.columns.some(item => item.id === origin.id)) {
                const clone = jsonClone(origin);
                const uId = "fd_" + getSimpleId();
                clone.id = uId;
                clone._id = uId;
                parent.columns.push(clone);
                this.handlerActiveItemChange(clone);
              }
            } else {
              parent.columns.map((column) => {
                if (column.list.some(item => item.id === origin.id)) {
                  const clone = jsonClone(origin);
                  const uId = "fd_" + getSimpleId();
                  clone.id = uId;
                  clone._id = uId;
                  column.list.push(clone);
                  this.handlerActiveItemChange(clone);
                }
              })
            }

          }else{
            const clone = jsonClone(origin);
            const uId = "fd_"+getSimpleId();
            clone.id = uId;
            clone._id = uId;
            this.list.push(clone);
            this.handlerActiveItemChange(clone);
          }
        }
      },
      handlerItemDelete(origin,parent){
        if (isLayout(origin) || isTable(origin)){ //如果是布局组件,则直接删除
          const index = this.list.findIndex(item=>item.id === origin.id);
          this.list.splice(index,1);
        }else{  //如果不是布局组件,则先判断是不是再布局内部,如果不是,则直接删除就可以,如果是,则要在布局内部删除
          if(parent){
            if (inTable(parent)){ //增加表格组件的支持
              const colIndex = parent.columns.findIndex(item => item.id === origin.id);
              if (colIndex > -1) {
                parent.columns.splice(colIndex, 1);
              }
            }else{
              parent.columns.map((column) => {
                const colIndex = column.list.findIndex(item => item.id === origin.id);
                if (colIndex > -1) {
                  column.list.splice(colIndex, 1);
                }
              })
            }

          }else{
            const index = this.list.findIndex(item=>item.id === origin.id);
            this.list.splice(index,1);

          }
        }
      },
      handlerSaveFormConf(){
        this.$refs.cssCodemirror.setClassStyle()
        this.formConfVisible = false
      },
      handlerRollBack(rowItem,oldIndex){  //还原
        this.list.splice(oldIndex,0,rowItem);
      },
      handlerSetJson(){
        this.$emit('updateJSON',this.viewCode);
        this.JSONVisible = false;
      },
    },
    computed:{
      infoShow() {
        return this.list.length<1;
      },
      code() {
        let json = {};
        json.config = this.formConf;
        json.list = this.list;
        return JSON.stringify(json,null,4);
      }
    },
    watch: {
      activeItem (newValue,oldValue) {
        this.lastActiveItem = oldValue;
      }
    }
  }

</script>
<style  scoped>
  .el-rate{
    display:inline-block;
  }
  .center-scrollbar >>> .el-scrollbar__bar.is-horizontal {
    display: none;
  }
  .center-scrollbar >>> .el-scrollbar__wrap{
    overflow-x: hidden;
  }
  .empty-info >>> .el-empty__description p{
    color: #ccb1ea;
    font-size:16px;
  }
  .drawing-board >>> .el-radio.is-bordered+.el-radio.is-bordered{
    margin-left:0px;
  }
  .drawing-board >>> .el-checkbox.is-bordered+.el-checkbox.is-bordered{
    margin-left:0px;
  }
</style>
<style lang="scss">
  @import "./style/designer.scss";
</style>
<style>
  @import "./style/designer.css";
</style>


http://www.niftyadmin.cn/n/5016540.html

相关文章

记录vite下使用require报错和解决办法

前情提要 我们现在项目用的是vite4react18开发的项目、但是最近公司有个睿智的人让我把webpack中的bpmn组件迁移过来、结果就出现问题啦&#xff1a;因为webpack是commonjs规范、但是vite不是、好像是es吧、可想而知各种报错 废话不多说啦 直接上代码&#xff1a; 注释是之前c…

rrweb入门

rrweb 背景 rrweb 是 record and replay the web&#xff0c;是当下很流行的一个录制屏幕的开源库。与我们传统认知的录屏方式&#xff08;如 WebRTC&#xff09;不同的是&#xff0c;rrweb 录制的不是真正的视频流&#xff0c;而是一个记录页面 DOM 变化的 JSON 数组&#x…

JavaScript设计模式(五)——发布订阅模式、桥接模式、组合模式

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

【力扣周赛】第 360 场周赛(贪心 ⭐树上倍增)

文章目录 竞赛链接Q1&#xff1a;8015. 距离原点最远的点&#xff08;贪心&#xff09;Q2&#xff1a;8022. 找出美丽数组的最小和&#xff08;贪心&#xff09;Q3&#xff1a;2835. 使子序列的和等于目标的最少操作次数&#xff08;贪心&#xff09;思路竞赛时丑陋代码&#x…

“内存炸弹”DDOS拒绝服务攻击

Windows平台演示 最早的内存炸弹是 zip 炸弹&#xff0c;也称为死亡 zip&#xff0c;它是一种恶意计算机文件&#xff0c;旨在使读取该文件的程序崩溃或瘫痪。zip 炸弹不会劫持程序的操作&#xff0c;而是利用解压缩压缩文件所需的时间、磁盘空间或内存。 zip 炸弹的一个示例…

SpringBoot结合MyBatis实现多数据源配置

SpringBoot结合MyBatis实现多数据源配置 一、前提条件 1.1、环境准备 SpringBoot框架实现多数据源操作&#xff0c;首先需要搭建Mybatis的运行环境。 由于是多数据源&#xff0c;也就是要有多个数据库&#xff0c;所以&#xff0c;我们创建两个测试数据库&#xff0c;分别是…

vue学习之内容渲染

内容渲染 创建 demo2.html,内容如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</…

堆相关例子-最大线段重合问题

问题描述 给定很多线段&#xff0c;每个线段都有两个数[start, end]&#xff0c; 表示线段开始位置和结束位置&#xff0c;左右都是闭区间 规定&#xff1a; 1&#xff09;线段的开始和结束位置一定都是整数值 2&#xff09;线段重合区域的长度必须>1 返回线段最多重合…