singleChoice.vue 10.7 KB
<!--
 * @Description: 
 * @Date: 2021-06-10 18:57:34
-->
<template>
  <div class="bi-single-choice" ref="bi-single-choice">
    <div
      :style="{
        display: isUseScale && scaleDomsInfo.items.length > 0 ? 'none' : ''
      }"
    >
      <slot></slot>
    </div>
    <template v-if="isUseScale">
      <div ref="print-area">
        <div
          class="print-item"
          v-for="(item, index) in scaleDomsInfo.items"
          :key="index"
          :style="{
            zoom: item.scale
          }"
        >
          <div
            class="bi-single-choice-info"
            v-if="item.topDom"
            v-html="item.topDom"
          ></div>
          <BiChartBlock
            v-for="domItem in item.chartConfigs"
            class="bi-single-choice_item"
            :showGuide="index === 0"
            :chartConfig="dealConfig(domItem, item.scale)"
            :key="domItem.baseInfo.id"
          >
            <BiBlank height="28" slot="top" usePrint></BiBlank>
            <BiBlank height="28" slot="bottom" usePrint></BiBlank>
          </BiChartBlock>
        </div>
      </div>
      <div
        style="position:absolute;z-index:-1;opacity: 0;left:0;top:0;"
        :style="{
          display: scaleDomsInfo.items.length > 0 ? 'none' : ''
        }"
      >
        <BiChartBlock
          v-for="(item, index) in copySingleChoice"
          ref="bi-single-choice_item"
          class="bi-single-choice_item"
          :style="{
            zIndex: guideStepShow(index, 3) ? 11 : ''
          }"
          :showGuide="index === 0"
          :chartConfig="item"
          :key="item.baseInfo.id"
        >
          <BiBlank height="28" slot="top" usePrint></BiBlank>
          <BiBlank height="28" slot="bottom" usePrint></BiBlank>
        </BiChartBlock>
      </div>
    </template>
    <template v-else>
      <vue-draggable
        class="bi-single-choice_group"
        :class="{ wrap: pageWrap }"
        handle=".bi-chart-title-darg"
        v-model="copySingleChoice"
        :disabled="disabled"
        chosen-class="chosen"
        force-fallback="true"
        :group="groupName"
        animation="500"
        touchStartThreshold="0"
        @start="onStart"
        @end="onEnd"
      >
        <transition-group
          v-for="(item, index) in copySingleChoice"
          :key="index"
        >
          <div
            :key="index"
            style="position:relative;"
            class="bi-single-choice_item_block"
          >
            <BiChartBlock
              ref="bi-single-choice_item"
              class="bi-single-choice_item"
              :style="{
                zIndex: guideStepShow(index, 3) ? 11 : ''
              }"
              :class="{ dragging: drag }"
              :showGuide="index === 0"
              :chartConfig="item"
              :key="item.baseInfo.id"
            >
              <BiBlank height="28" slot="top"></BiBlank>
              <BiBlank height="28" slot="bottom"></BiBlank>
            </BiChartBlock>
            <BiTips v-if="guide.use && index === 0"></BiTips>
          </div>
        </transition-group>
      </vue-draggable>
    </template>
  </div>
</template>

<script>
import BiBlank from '../commonComponents/blank.vue';
import BiChartBlock from '../commonComponents/chart-block.vue';
import BiTips from '../commonComponents/tips.vue';
import eventBus from '../eventBus/index';
import mixin from '../mixin/index';
import { getQueryVariable } from '../chart-type/common';

export default {
  name: 'bi-single-choice',
  mixins: [mixin],
  components: {
    BiBlank,
    BiTips,
    BiChartBlock,
    'vue-draggable':
      this.isPrint || getQueryVariable('print') == 1
        ? {
            template: '<div><slot></slot></div>'
          }
        : require('vuedraggable')
  },
  props: {
    singleChoice: {
      type: Array,
      default: () => []
    },
    pageWrap: Boolean,
    disabled: Boolean
  },
  data() {
    return {
      drag: false,
      groupName: `single-choice-chart-${parseInt(
        Math.random() * new Date().getTime()
      )}`,
      copySingleChoice: [],
      scaleDomsInfo: {
        items: []
      }
    };
  },
  computed: {
    guideStepShow() {
      return (index, step) =>
        index === 0 && this.guide.use && this.guide.step == step;
    }
  },
  methods: {
    dealConfig(config, zoom) {
      const _config = JSON.parse(JSON.stringify(config));
      // _config.chart._width = _config.chart.width * zoom;
      // _config.chart._height = _config.chart.height * zoom;
      // _config.chart.width /= zoom;
      // _config.chart.height /= zoom;
      _config.chart.zoom = zoom || 1;
      return _config;
    },
    onStart() {
      this.drag = true;
      document
        .getElementsByClassName('xrk-components-bi')[0]
        .parentElement.parentElement.parentElement.scrollTo(
          0,
          this.$refs['bi-single-choice'].offsetTop
        );
    },
    onEnd() {
      this.drag = false;
      this.$emit('sort', this.copySingleChoice);
    },
    getPageSize() {
      const topDom = (this.$slots.default || [{}])[0].elm || {
        offsetHeight: 0
      };
      const domArr = [
        {
          $el: topDom
        },
        ...(this.$refs['bi-single-choice_item'] || []).map(item => {
          let height = 0;
          item.pervPage = item.$children.reduce((pre, { $el }) => {
            const { offsetHeight } = $el;
            if ($el.className != 'bi-blank' && !this.Bi.isPrint) {
              height += offsetHeight;
            }
            if (height >= 1697) {
              pre += 1;
              height = offsetHeight;
            }
            return pre;
          }, 0);
          return item;
        })
      ];
      const pageSizeInfo = {
        pervHeight: 0,
        pervPage: 0,
        height: 0,
        page: this.pageWrap ? 0 : 1
      };
      const catalogueInfoArr = [];
      domArr.forEach(({ $el, title, pervPage = 0 }, index) => {
        const offsetHeight = $el.offsetHeight - (this.Bi.isPrint ? 0 : 56);
        pageSizeInfo.height += offsetHeight;
        if (this.pageWrap) {
          if (index == 1) {
            // 遍历到第二个时,如果存在顶部标题,则将两个高度相加(汇总标题和表格不做强制分页)
            pageSizeInfo.pervHeight = offsetHeight + topDom.offsetHeight;
            if (offsetHeight + topDom.offsetHeight > 1697) {
              pageSizeInfo.page += 1;
            }
          } else {
            pageSizeInfo.page += pageSizeInfo.pervPage + 1;
            pageSizeInfo.pervPage = pervPage;
          }
        } else if (pageSizeInfo.height >= 1697) {
          pageSizeInfo.page += 1;
          pageSizeInfo.height = offsetHeight;
        }
        catalogueInfoArr.push({
          name: (title || {}).name,
          page: pageSizeInfo.page
        });
      });
      console.log(111, pageSizeInfo.page, catalogueInfoArr);
      this.$emit('page', {
        pageSize: pageSizeInfo.page,
        info: catalogueInfoArr
      });
    },
    dealDomForScale() {
      const topDom = (this.$slots.default || [{}])[0].elm || {
        offsetHeight: 0
      };
      const baseHeight = 1697;
      const baseScale = 1.1;
      const cScale = height => {
        return Math.min(baseHeight / height, 1);
      };
      const newDom = (this.$refs['bi-single-choice_item'] || []).reduce(
        (pre, cur) => {
          const { $el } = cur;
          const { offsetHeight } = $el;
          const domUsePage = parseInt(offsetHeight / (baseHeight * baseScale));
          if (pre.height + offsetHeight < baseHeight * baseScale) {
            // 当前dom高度加上历史高度 小于 A4纸高度的1.15倍
            if (pre.height === 0) {
              // 第一项
              pre.items.push({
                allHeight: offsetHeight,
                scale: cScale(offsetHeight),
                chartConfigs: [cur.chartConfig]
              });
            } else {
              const lastItem = pre.items[pre.items.length - 1];
              lastItem.allHeight += offsetHeight;
              lastItem.scale = cScale(lastItem.allHeight);
              lastItem.chartConfigs.push(cur.chartConfig);
            }
            pre.height += offsetHeight;
          } else {
            pre.totalPage += Math.max(domUsePage, 1);
            pre.height = offsetHeight;
            pre.items.push({
              allHeight: offsetHeight,
              scale: domUsePage === 0 ? cScale(offsetHeight) : 1,
              chartConfigs: [cur.chartConfig]
            });
          }
          pre.catalogueInfoArr.push({
            name: (cur.chartConfig.title || {}).name,
            page: pre.totalPage - domUsePage
          });
          return pre;
        },
        {
          height: topDom.offsetHeight,
          totalPage: 1,
          items:
            topDom.offsetHeight === 0
              ? []
              : [
                  {
                    allHeight: topDom.offsetHeight,
                    scale: cScale(topDom.offsetHeight),
                    topDom: topDom.innerHTML,
                    chartConfigs: []
                  }
                ],
          catalogueInfoArr: []
        }
      );
      this.scaleDomsInfo = newDom;
      this.$emit('page', {
        pageSize: newDom.totalPage,
        info: newDom.catalogueInfoArr
      });
      console.log(newDom);
      // this.$refs['print-area'].innerHTML = 'xxxx';
    }
  },
  mounted() {
    eventBus.$on('addStep', () => {
      this.guide.step += 1;
    });
    eventBus.$on('hideGuide', () => {
      this.guide.use = false;
    });
    // this.dealDomForScale();
  },
  watch: {
    singleChoice: {
      handler(v) {
        this.copySingleChoice = v;
        this.$nextTick(this.dealDomForScale);
      },
      deep: true,
      immediate: true
    }
  }
};
</script>

<style lang="scss" scoped>
.print-item {
  page-break-before: always;
  transform-origin: 0 0;
  overflow: hidden;
  // &:first-child {
  //   page-break-before: auto;
  //   page-break-inside: avoid;
  // }
}
.bi-single-choice {
  // page-break-before: always;
  &_group {
    & > span {
      display: block;
      margin-top: 8px;
      page-break-inside: avoid;
      // & + span {
      // }
      &.chosen {
        border: 2px solid #016cd6;
        z-index: 9;
        position: relative;
      }
      &.sortable-fallback {
        height: 150px !important;
        overflow: hidden;
      }
    }
    &.wrap {
      & > span {
        & + span {
          // page-break-before: always;
        }
      }
    }
  }
  &_item {
    padding: 0 28px;
    border-radius: 4px;
    border: 1px solid #f4f4f4;
    box-shadow: 0px 3px 6px rgba(27, 39, 64, 0.04);
    background-color: #fff;
    &_block {
      page-break-inside: avoid;
      // margin-top: 8px;
    }
    &.dragging {
      height: 140px;
      overflow: hidden;
    }
  }
}
</style>