<template> <div class="app-seaProcess"> <!-- 海运流程图 --> <el-scrollbar :vertical="true" viewClass="shipping-chart"> <div v-for="(nodes,index) in processData" :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"> <div> <img :src="getImgSrc(node)" alt="" :width="width" :height="height"> <p>{{node.title}}</p> </div> </div> </div> <div class="arrow-area" v-if="index !== (processData.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" v-on="$listeners" :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 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 twoWayTakeoffWidget from "./nodePage/twoWayTakeoff.vue"; import twoWayArrivalWidget from "./nodePage/twoWayArrival.vue"; import unloadingWidget from "./nodePage/unloading/index.vue"; import settlementWidget from "./nodePage/settlement.vue"; import reviewWidget from "./nodePage/review.vue"; import tallyWidget from "./nodePage/tally/index.vue"; /** * 海运流程图 */ export default { name: "shippingChart", inheritAttrs: false, components: { bookingWidget, trailerWidget, preinstallWidget, agentWidget, cabinetWidget, cusDeclarationWidget, shipWidget, subMaterialWidget, bargeWidget, departureWidget, blCopyWidget, clrDocumentWidget, arrivalWidget, cusClearanceWidget, twoWayTakeoffWidget, twoWayArrivalWidget, unloadingWidget, settlementWidget, reviewWidget, tallyWidget, }, props: { shipmentObj: Object, seaBaseData: Array, width: { type: String, default: "76px", }, height: { type: String, default: "76px", }, }, data() { return { // 弹窗配置 dialogConfig: { dialogVisible: false, title: "", width: "", fullscreen: false, }, // 当前组件 currentComponent: "", // 当前步骤节点坐标 currIndex: 0, // 当前节点 currNode: {}, // 数据 processData: this.seaBaseData, }; }, created() {}, /* computed: { isShowAgent() { return (type) => { if (type === "agent") { const { preInstallInfo } = this.shipmentObj; const user = this.$store.state.user; if (preInstallInfo && preInstallInfo.noticeUser === user.id) return true; return false; } return true; }; }, }, */ 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(this.$t("请先完成上一步")); 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", this.$t("代理商设置")); break; // 理货 case "tally": this.$set(this.dialogConfig, "fullscreen", true); break; // 预装 case "preinstall": // 预装反审 const preStatus = this.shipmentObj[node.keyName]; if ([25].includes(preStatus)) { this.currentComponent = `reviewWidget`; this.$set(this.dialogConfig, "width", "700px"); this.$set(this.dialogConfig, "title", this.$t("预装反审")); } else { this.$set(this.dialogConfig, "fullscreen", true); this.$set(this.dialogConfig, "title", this.$t("出货安排(预装)")); } // 装柜 case "cabinet": // 装柜反审 const cabStatus = this.shipmentObj[node.keyName]; if ([47].includes(cabStatus)) { this.currentComponent = `reviewWidget`; this.$set(this.dialogConfig, "width", "700px"); this.$set(this.dialogConfig, "title", this.$t("装柜反审")); } break; // 卸柜 case "unloading": // 卸柜反审 const unStatus = this.shipmentObj[node.keyName]; if ([186].includes(unStatus)) { this.currentComponent = `reviewWidget`; this.$set(this.dialogConfig, "width", "700px"); this.$set(this.dialogConfig, "title", this.$t("卸柜反审")); } break; } this.$set(this.dialogConfig, "dialogVisible", true); }, /* 获取图片路径 */ getImgSrc(node) { return node.imgSrc[node.currStatus ?? "start"]; }, }, watch: { /* 监听发货对象 */ shipmentObj(val) { let newNodes = [], finish = 0; // 迭代每个节点 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, type } = node; // agent if (!keyName && type === "agent") { if (val[voName]) { // 已完成agent节点 node.currStatus = "end"; ++nodeIndex; } 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"; // 判断是否存在异常未处理 if ( (type === "cusDeclaration" && val.customsHasAbnormal) || (type === "departure" && val.shippingHasAbnormal) || (type === "arrival" && val.arrivalHasAbnormal) ) { continue; } // 报关 if (type === "cusDeclaration") { const { dcCustomsStatus, dcCheckStatus } = val; // 查验状态并且是退场/部分退场 if (dcCustomsStatus === 3 && [1, 2].includes(dcCheckStatus)) { // 只有审核通过并且已处理才算完成 if (val.checkExamineStatus === 2 && val.checkDealStatus === 1) { // 已完成节点个数 ++nodeIndex; } else { continue; } } } // 已完成节点个数 ++nodeIndex; } } // 如果相等标识该步骤已完成 if (nodeIndex === nodes.length) { // 加1表示为已完成步骤后一步 finish = finish + 1; } newNodes.push(nodes); } this.currIndex = finish; this.processData = newNodes; }, }, }; </script> <style lang="scss"> .app-seaProcess { .shipping-chart { display: flex; padding: 10px 10px; min-width: 1300px; width: max-content; .chart-nodes { display: flex; align-items: center; justify-content: center; .node-area { display: flex; flex-direction: column; align-items: center; .node-div { text-align: center; margin-top: 10px; cursor: pointer; p { margin-top: -10px; margin-bottom: 0px; text-align: center; } } } .arrow-area { margin: 0 6px; } } } } </style>