WidgetGridLayout.vue 11.3 KB
<template>
  <div class="widget-form-item" @click.stop="handleSelectWidget(index)">
    <div
      class="drag-widget"
      title="拖拽"
      v-if="selectWidgetItem.key == element.key"
    >
      <i class="icon-drag"></i>
    </div>
    <div class="widget-view-action" v-if="selectWidgetItem.key == element.key">
      <i
        class="icon-fuzhi1 copy-icon"
        title="复制布局"
        @click.stop="handleWidgetClone(index)"
      ></i>
      <i
        class="icon-fuzhineirong copy-icon"
        title="复制布局+字段"
        @click.stop="handleWidgetFieldClone(index)"
      ></i>
      <i
        class="icon-application-delete del-icon"
        title="删除"
        @click.stop="handleWidgetDelete(index)"
      ></i>
    </div>
    <!-- 栅格标题 -->
    <div>
      <div
        v-if="element.options.gridDesc && !element.options.hideLabel"
        class="widget-title"
        :style="{
          'background-color': element.options.gridDescBagColor,
          color: element.options.gridDescColor,
          'text-align': element.options.gridDescJustify,
          'font-weight': element.options.gridDescBold
        }"
      >
        {{ element.options.gridDesc_zh || element.options.gridDesc }}
      </div>
      <el-row
        class="widget-col"
        :style="{
          padding:
            element.options.gridDesc && !element.options.hideLabel
              ? '55px 5px 15px'
              : '15px 5px'
        }"
        v-if="element && element.key"
        type="flex"
        :class="{active: selectWidgetItem.key == element.key}"
        :gutter="element.options.gutter ? Number(element.options.gutter) : 0"
        :justify="element.options.justify"
        :align="element.options.align"
      >
        <el-col
          v-for="(col, colIndex) in element.columns"
          :key="colIndex"
          :span="col.span ? col.span : 0"
        >
          <draggable
            v-model="col.list"
            :no-transition-on-drag="true"
            v-bind="{
              group: 'form',
              ghostClass: 'ghost',
              animation: 200,

              handle: '.drag-widget'
            }"
            @start="handleMoveStart"
            @add="handleWidgetColAdd($event, element, colIndex)"
          >
            <transition-group name="fade" tag="div" class="widget-col-list">
              <widget-form-item
                v-for="(el, i) in col.list.filter(c => c.key)"
                :key="el.key"
                :element="el"
                :select.sync="selectWidgetItem"
                :index="i"
                :selectWidgetList.sync="selectWidgetList"
                :data.sync="col"
              ></widget-form-item>
            </transition-group>
          </draggable>
        </el-col>
      </el-row>
    </div>
  </div>
</template>
<script>
import {mapState, mapMutations} from 'vuex'
import Draggable from 'vuedraggable'
import WidgetFormItem from '@/components/form/WidgetFormItem.vue'
import controlsApi from '@/api/controlsConfig.js'
import deepmerge from 'deepmerge'
import updateSelectControl from '@/mixins/updateSelectControl.js'
export default {
  name: 'widget-grid-layout',
  components: {Draggable, WidgetFormItem},
  mixins: [updateSelectControl],
  props: ['element', 'select', 'index', 'data', 'selectWidgetList'],
  data() {
    return {
      noBindModelArr: [
        'text',
        'immediate-single',
        'immediate-textarea',
        'flowChart',
        'approvalHistory',
        'opinion',
        'big-title',
        'small-title',
        'simple-text',
        'explain',
        'dataView',
        'formTable',
        'QRcode',
        'iframe',
        'image',
        'customChart',
        'button'
      ]
    }
  },
  computed: {
    ...mapState('form', ['selectWidget'])
  },
  methods: {
    ...mapMutations({
      setSelectWidget: 'form/setSelectWidget' // 设置当前选中控件
    }),

    handleMoveStart: function(evt) {
      // 新增控件时  将控件属性切断联系
      evt.item._underlying_vm_ = deepmerge({}, evt.item._underlying_vm_, {
        clone: true
      })
      const key =
        Date.parse(new Date()) + '_' + Math.ceil(Math.random() * 99999)
      evt.item._underlying_vm_.key = key

      evt.item._data_vm_ = deepmerge({}, this.data.list, {
        clone: true
      })
      evt.item._p_vm_ = this.data
    },
    handleSelectWidget(index) {
      this.setSelectWidget(this.data.list[index])
    },
    handleAddBack($event, columns, newIndex) {
      columns.list.splice(newIndex, 1)
      if ($event.item._p_vm_) {
        $event.item._p_vm_.list = $event.item._data_vm_
      }
    },
    handleWidgetColAdd($event, row, colIndex) {
      const newIndex = $event.newIndex
      const oldIndex = $event.oldIndex
      const item = $event.item
      if (row.parentNodeType) {
        let text = ''
        if (row.parentNodeType == 'sub') {
          text = '子表'
        } else if (row.parentNodeType == 'sun') {
          text = '孙表'
        }
        if (item._underlying_vm_.ctrlType == 'QRcode') {
          this.$message.warning(text + '不允许存在二维码')
          this.handleAddBack($event, row.columns[colIndex], newIndex)
          return false
        }
        if (item._underlying_vm_.ctrlType == 'milepost') {
          this.$message.warning(text + '不允许存在里程碑')
          this.handleAddBack($event, row.columns[colIndex], newIndex)
          return false
        }
        if (item._underlying_vm_.ctrlType == 'processForecast') {
          this.$message.warning(text + '不允许存在审批预测')
          this.handleAddBack($event, row.columns[colIndex], newIndex)
          return false
        }
        if (item._underlying_vm_.ctrlType == 'customChart') {
          this.$message.warning(text + '不允许存在图表')
          this.handleAddBack($event, row.columns[colIndex], newIndex)
          return false
        }
        if (item._underlying_vm_.ctrlType == 'table') {
          this.$message.warning(text + '不允许存在表格布局')
          this.handleAddBack($event, row.columns[colIndex], newIndex)
          return false
        }
        if (['amap','tianditu'].includes(item._underlying_vm_.ctrlType)) {
          this.$message.warning(text + '不允许存在地图')
          this.handleAddBack($event, row.columns[colIndex], newIndex)
          return false
        }
        if (item._underlying_vm_.ctrlType == 'related-process') {
          this.$message.warning(text + '不允许存在相关流程')
          this.handleAddBack($event, row.columns[colIndex], newIndex)
          return false
        }
        if (item._underlying_vm_.ctrlType === 'dataView') {
          this.$message.warning(text + '不允许存在数据列表')
          this.handleAddBack($event, row.columns[colIndex], newIndex)
          return false
        }
        if (item._underlying_vm_.ctrlType === 'formTable') {
          this.$message.warning(text + '不允许存在表单列表')
          this.handleAddBack($event, row.columns[colIndex], newIndex)
          return false
        }
      }
      // 防止布局元素的嵌套拖拽
      if (
        item.className.indexOf('data-grid') >= 0 ||
        item.innerText == '分页符'
      ) {
        // 如果是列表中拖拽的元素需要还原到原来位置
        item.tagName === 'DIV' &&
          this.data.list.splice(
            oldIndex,
            0,
            row.columns[colIndex].list[newIndex]
          )

        this.handleAddBack($event, row.columns[colIndex], newIndex)
        if (item.innerText == '分页符') {
          this.$message.warning('栅格布局中不允许再拖入分页布局')
        }
        return false
      }
      if (
        !controlsApi.handleLayoutComponents(
          this,
          row,
          row.columns[colIndex].list,
          newIndex
        )
      ) {
        this.handleAddBack($event, row.columns[colIndex], newIndex)
        return false
      }
      if (row.columns[colIndex].list[newIndex]) {
        let params = row.columns[colIndex].list[newIndex]
        params.parentNodeType = row.parentNodeType
        params.boSubEntity = row.boSubEntity
        this.setSelectWidget(params)
      }
    },
    handleWidgetDelete(index) {
      if (this.data.list.length - 1 === index) {
        if (index === 0) {
          this.setSelectWidget({options: {validateType: ''}})
        } else {
          this.setSelectWidget(this.data.list[index - 1])
        }
      } else {
        this.setSelectWidget(this.data.list[index + 1])
      }

      this.$nextTick(() => {
        this.data.list.splice(index, 1)
      })
    },
    //复制布局+字段
    handleWidgetFieldClone(index) {
      let cloneData = deepmerge({}, this.data.list[index], {clone: true})

      cloneData.key =
        Date.parse(new Date()) + '_' + Math.ceil(Math.random() * 99999)
      const hasMap = cloneData.columns
        .map(item => item.list.some(it => ['amap','tianditu'].includes(it.ctrlType)))
        .filter(result => Boolean(result))
      if (hasMap && hasMap.length > 0) {
        this.$message.warning(
          '表单中只能存在一个地图控件,当前地图控件将不能复制'
        )
      }
      cloneData.columns.forEach(v => {
        v.list.forEach(t => {
          t.key =
            Date.parse(new Date()) + '_' + Math.ceil(Math.random() * 99999)
          // 复制组件时 如果是无属性组件
          if (
            this.noBindModelArr.includes(t.ctrlType) ||
            (t.options && t.options.noBindModel)
          ) {
            t.name = 'c_' + t.key
            if (t.boDefAlias) {
              t.fieldPath = t.boDefAlias + '.' + t.name
            }
          }
        })
      })
      const currentColumns = cloneData.columns.map(item => {
        return {
          ...item,
          list: item.list.filter(it => !['amap','tianditu'].includes(it.ctrlType))
        }
      })
      this.data.list.splice(index + 1, 0, {
        ...cloneData,
        columns: currentColumns
      })
      this.$nextTick(() => {
        this.setSelectWidget(this.data.list[index + 1])
      })
    },
    //复制布局
    handleWidgetClone(index) {
      let cloneData = deepmerge({}, this.data.list[index], {clone: true})

      cloneData.key =
        Date.parse(new Date()) + '_' + Math.ceil(Math.random() * 99999)
      cloneData.columns.forEach(v => {
        v.list = []
      })
      this.data.list.splice(index + 1, 0, cloneData)

      this.$nextTick(() => {
        this.setSelectWidget(this.data.list[index + 1])
      })
    }
  }
}
</script>
<style lang="scss" scoped>
@import '@/assets/css/form-editor.scss';

.widget-col {
  padding-bottom: 0;
  // padding: 15px 5px;
  padding: 55px 5px 15px;
}

.widget-col.active {
  outline: 2px solid $--form-design-active-color;
}

.el-col {
  min-height: 50px;
}

.widget-col-list {
  min-height: 50px;
  border: 1px solid #ededed;
}

div.widget-view-action {
  background: $--form-design-active-color;
  .copy-icon {
    color: #fff;
    &:first-child {
      padding: 0 10px;
    }
  }
}

div.widget-view-action i.del-icon {
  margin: 0 10px;
  color: #fff;
}

div.drag-widget {
  background: $--form-design-active-color;
}

div.drag-widget i.icon-drag {
  color: #fff;
}
.widget-title {

  padding: 0px 16px;
  border: 1px solid #ededed;
  background-color: #f9f9f9;
  height: 40px;
  line-height: 40px;
  font-size: 16px;
  margin: 0px 5px -40px 5px;
  border-bottom: 0;
  padding-top: -11px;
  position: relative;
  top: 15px;

}
</style>