seaProcess.vue 6.68 KB
<template>
  <div class="app-seaProcess">
    <!-- 海运流程图 -->
    <el-scrollbar :vertical="true" viewClass="shipping-chart">
      <div v-for="(nodes,index) in seaBaseData" :key="index" class="chart-nodes">
        <div class="node-area">
          <div v-for="node in nodes" :key="node.title" @click="nodeClick(index, node)" class="node-div">
            <template v-if="!node.unNode">
              <img :src="getImgSrc(node)" alt="">
              <p>{{node.title}}</p>
            </template>
            <template v-else-if="node.unNode">
              <el-button type="primary" @click="nodeClick(index, node)" style="width:100px;">{{node.title}}</el-button>
            </template>
          </div>
        </div>
        <div class="arrow-area" v-if="index !== (seaBaseData.length-1)">
          <img src="@/assets/images/shipping/jt-start.png" alt="" v-if="index >= currIndex">
          <img src="@/assets/images/shipping/jt-end.png" alt="" v-if="index < currIndex">
        </div>
      </div>
    </el-scrollbar>

    <!-- 弹窗 -->
    <el-dialog custom-class="shipping-dialog" :title="dialogConfig.title" :visible.sync="dialogConfig.dialogVisible" :width="dialogConfig.width" :fullscreen="dialogConfig.fullscreen" :close-on-click-modal=false :modal-append-to-body=false append-to-body>
      <component v-bind:is="currentComponent" v-if="dialogConfig.dialogVisible" @closeDialog="closeDialog" v-bind="$attrs" :shipmentObj="shipmentObj" :currNode="currNode"></component>
    </el-dialog>
  </div>
</template>

<script>
import bookingWidget from "./nodePage/booking.vue";
import trailerWidget from "./nodePage/trailer.vue";
import preinstallWidget from "./nodePage/preinstall.vue";
import preinstallReviewWidget from "./nodePage/preinstallReview.vue";
import agentWidget from "./nodePage/agent.vue";
import cabinetWidget from "./nodePage/cabinet/index.vue";
import cusDeclarationWidget from "./nodePage/cusDeclaration.vue";
import shipWidget from "./nodePage/ship.vue";
import subMaterialWidget from "./nodePage/subMaterial.vue";
import bargeWidget from "./nodePage/barge.vue";
import departureWidget from "./nodePage/departure.vue";
import blCopyWidget from "./nodePage/blCopy.vue";
import clrDocumentWidget from "./nodePage/clrDocument.vue";
import arrivalWidget from "./nodePage/arrival.vue";
import cusClearanceWidget from "./nodePage/cusClearance.vue";
import unloadingWidget from "./nodePage/unloading/index.vue";
import settlementWidget from "./nodePage/settlement.vue";

/**
 * 海运流程图
 */
export default {
  name: "shippingChart",
  inheritAttrs: false,
  components: {
    bookingWidget,
    trailerWidget,
    preinstallWidget,
    agentWidget,
    cabinetWidget,
    cusDeclarationWidget,
    shipWidget,
    subMaterialWidget,
    bargeWidget,
    departureWidget,
    blCopyWidget,
    clrDocumentWidget,
    arrivalWidget,
    cusClearanceWidget,
    unloadingWidget,
    settlementWidget,
    preinstallReviewWidget,
  },
  props: {
    shipmentObj: Object,
    seaBaseData: Array,
  },
  data() {
    return {
      // 弹窗配置
      dialogConfig: {
        dialogVisible: false,
        title: "",
        width: "",
        fullscreen: false,
      },
      // 当前组件
      currentComponent: "",
      // 当前步骤节点坐标
      currIndex: 0,
      // 当前节点
      currNode: {},
    };
  },
  created() {},
  methods: {
    /** 关闭弹窗 */
    closeDialog(type) {
      this.$set(this.dialogConfig, "dialogVisible", false);
      if (type === "submit") {
        this.$emit("getBoxInfo");
      }
    },
    /** 节点点击 */
    nodeClick(currIndex, node) {
      if (currIndex > this.currIndex) {
        this.$message.error("请先完成上一步");
        return;
      }
      this.currNode = node;
      this.currentComponent = `${node.type}Widget`;
      this.$set(this.dialogConfig, "width", "500px");
      this.$set(this.dialogConfig, "title", node.title);
      this.$set(this.dialogConfig, "fullscreen", false);
      switch (node.type) {
        // 订舱
        case "booking":
        // 驳船
        case "barge":
        // 清关文件
        case "clrDocument":
          this.$set(this.dialogConfig, "width", "700px");
          break;
        // AGENT
        case "agent":
          this.$set(this.dialogConfig, "title", "代理商设置");
          break;
        // 预装
        case "preinstall":
          // 预装反审
          const status = this.shipmentObj[node.keyName];
          if ([23, 24].includes(status)) {
            this.currentComponent = `preinstallReviewWidget`;
            this.$set(this.dialogConfig, "width", "700px");
            this.$set(this.dialogConfig, "title", "预装反审");
          } else {
            this.$set(this.dialogConfig, "fullscreen", true);
            this.$set(this.dialogConfig, "title", "出货安排(预装)");
          }
          break;
      }
      this.$set(this.dialogConfig, "dialogVisible", true);
    },
    /* 获取图片路径 */
    getImgSrc(node) {
      return node.imgSrc[node.currStatus ?? "start"];
    },
  },
  watch: {
    /* 监听发货对象 */
    shipmentObj(val) {
      // 迭代每个节点
      for (let i = 0; i < this.seaBaseData.length; i++) {
        const nodes = this.seaBaseData[i];
        let nodeIndex = 0;
        for (let j = 0; j < nodes.length; j++) {
          const node = nodes[j];
          const { keyName, voName, status } = node;
          if (!keyName) continue;
          const { start, wait, end } = status;

          if (start.includes(val[keyName])) {
            node.currStatus = "start";
          }

          if (start.includes(val[keyName]) && val[voName]) {
            node.currStatus = "wait";
          }

          if (wait.includes(val[keyName])) {
            node.currStatus = "wait";
          }

          if (end.includes(val[keyName])) {
            node.currStatus = "end";
            // 已完成节点个数
            ++nodeIndex;
          }
        }
        // 如果相等标识改步骤已完成
        if (nodeIndex === nodes.length) {
          // 加1表示为已完成步骤后一步
          this.currIndex = i + 1;
        }
      }
    },
  },
};
</script>

<style lang="scss">
.app-seaProcess {
  .shipping-chart {
    width: max-content;
    display: flex;
    padding: 10px 0;
    .chart-nodes {
      display: flex;
      align-items: center;
      justify-content: center;
      .node-area {
        display: flex;
        flex-direction: column;
        align-items: center;

        .node-div {
          margin-top: 10px;
          cursor: pointer;
          p {
            margin-top: -10px;
            margin-bottom: 0px;
            text-align: center;
          }
        }
      }
      .arrow-area {
        margin: 0 10px;
      }
    }
  }
}
</style>