Browse Source

build:调度添加驳回状态

snow 2 năm trước cách đây
mục cha
commit
32a584984c

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/0.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/app.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-elementUI.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
dist/static/js/chunk-libs.js


+ 27 - 0
src/components/flow-chart/config.js

@@ -0,0 +1,27 @@
+export const colors = {
+  //已完成节点
+  start:{
+    background:'#e5fff5',
+    border:'#a2e9d6'
+  },
+  //进行中节点
+  process:{
+    background:'#d1e9ff',
+    border:'#afcaff'
+  },
+  //未开始节点
+  end:{
+    background:'#e7faf0',
+    border:'rgb(19, 206, 102)'
+  }
+}
+
+//横向中间位置
+export const MIDDMLE_X = 750
+//横向间隔
+export const GAP_X = 90
+
+//纵向起始位置
+export const START_Y = 100
+//纵向间隔
+export const GAP_Y = 90

+ 3 - 0
src/components/flow-chart/index.js

@@ -0,0 +1,3 @@
+import FlowChart from "./index.vue";
+
+export default FlowChart

+ 127 - 0
src/components/flow-chart/index.vue

@@ -0,0 +1,127 @@
+<template>
+  <div class="container">
+    <div class="lf" ref="container" />
+    <legend-lf />
+  </div>
+</template>
+
+<script>
+import LegendLf from "./legend.vue";
+import LogicFlow from "@logicflow/core";
+import { generateProcessChart } from "./utils/genProceeChart";
+import processRequest from "@/apis/service/serviceParam/setActionProcess";
+import { StartTask, ProcessTask, NormalTask, Dashe } from "./tasks";
+import { Tooltip } from "./utils/tooltip";
+
+import "@logicflow/core/dist/style/index.css";
+import "./style.css";
+
+LogicFlow.use(Tooltip);
+export default {
+  props: {
+    orderCode: {
+      type: String,
+      default: ""
+    },
+    process_id: {
+      type: String,
+      default: ""
+    },
+    type:{
+      type:String,
+      default:'YJD'
+    }
+  },
+  data() {
+    return {
+      lf: null,
+      process: null,
+      record: null
+    };
+  },
+  components: {
+    LegendLf
+  },
+  mounted() {
+    this.createLf();
+  },
+  methods: {
+    createLf() {
+      this.lf = new LogicFlow({
+        container: this.$refs.container,
+        stopZoomGraph: true,
+        stopScrollGraph: true,
+        stopMoveGraph: true,
+        isSilentMode: true,
+        grid: false
+      });
+
+      this.lf.register(StartTask);
+      this.lf.register(ProcessTask);
+      this.lf.register(NormalTask);
+      this.lf.register(Dashe);
+    },
+    async getProcess() {
+      const result = await processRequest.list({ process_id: this.process_id });
+      this.process = result.data?.list;
+    },
+    async getRecord() {
+      const result = await processRequest.record({
+        orderCode: this.orderCode,
+        type: this.type
+      });
+      this.record = result.data;
+    },
+    initalData() {
+      this.getRecord();
+      this.getProcess();
+    },
+    createChartData() {
+      if (!this.process || !this.record || !this.lf) return;
+      this.lf.render(generateProcessChart(this.process, this.record));
+    }
+  },
+  watch: {
+    process: {
+      handler() {
+        this.createChartData();
+      },
+      deep: true
+    },
+    record: {
+      handler() {
+        this.createChartData();
+      },
+      deep: true
+    },
+    process_id: {
+      handler() {
+        this.process_id && this.getProcess();
+      },
+      immediate:true,
+      deep: true
+    },
+    orderCode: {
+      handler() {
+        console.log(this.orderCode)
+        this.orderCode && this.getRecord();
+      },
+      immediate:true,
+      deep: true
+    }
+  }
+};
+</script>
+
+
+<style scoped>
+.container {
+  width: 100%;
+  height: 650px;
+}
+
+.container > .lf {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 58 - 0
src/components/flow-chart/legend.vue

@@ -0,0 +1,58 @@
+<template>
+  <div class="legend__container">
+    <div class="legend___item">
+      <div
+        class="legend--color"
+        :style="{background:colors.start.background,border:`1px solid ${colors.start.border}`}"
+      />
+      <span>已办节点</span>
+    </div>
+
+    <div class="legend___item">
+      <div
+        class="legend--color"
+        :style="{background:colors.process.background,border:`1px solid ${colors.process.border}`}"
+      />
+      <span>进行中节点</span>
+    </div>
+
+    <div class="legend___item">
+      <div class="legend--color" :style="{background:'#fff',border:`1px solid #ccc`}" />
+      <span>未开始</span>
+    </div>
+  </div>
+</template>
+
+<script>
+import { colors } from "./config";
+export default {
+  data() {
+    return { colors };
+  }
+};
+</script>
+
+
+<style scoped>
+.legend__container {
+  width: 150px;
+  position: absolute;
+  left: 10px;
+  top: 10px;
+  padding: 10px;
+  box-sizing: border-box;
+  background: #fff;
+}
+
+.legend__container > .legend___item {
+  display: flex;
+  align-items: center;
+}
+
+.legend--color {
+  width: 15px;
+  height: 15px;
+  margin-right: 20px;
+  border-radius: 2px;
+}
+</style>

+ 48 - 0
src/components/flow-chart/style.css

@@ -0,0 +1,48 @@
+.process-wrapper {
+  height: 30px;
+  width: 100px;
+  background: repeating-linear-gradient(135deg, transparent, transparent 3px, rgb(175, 202, 255) 3px, rgb(175, 202, 255) 8px);
+  animation: shine 1s infinite linear;
+  overflow: hidden;
+}
+
+.content {
+  height: 28px;
+  background-color: rgb(209, 233, 255);
+  margin: 1px;
+}
+
+
+@keyframes shine {
+  0% {
+    background-position: -1px -1px;
+  }
+
+  100% {
+    background-position: -12px -12px;
+  }
+}
+
+
+.lf__tooltip {
+  background: #000;
+  color: #fff;
+  border-radius: 8px;
+  font-size: 12px;
+  position: relative;
+  padding: 5px 10px;
+}
+
+.lf__tooltip>.tooltip__arrow {
+  width: 10px;
+  height: 10px;
+  position: absolute;
+  left: -7px;
+  top: 50%;
+  background: #000;
+  transform: rotate(45deg) translateY(-50%);
+}
+
+.lf__tooltip p:not(:last-child) {
+  margin-bottom: 5px;
+}

+ 59 - 0
src/components/flow-chart/tasks/_dashe.js

@@ -0,0 +1,59 @@
+
+import { PolylineEdge, PolylineEdgeModel } from "@logicflow/core";
+
+class CustomEdgeModel extends PolylineEdgeModel {
+  // customTextPosition = true;
+  initEdgeData(data) {
+    super.initEdgeData(data);
+    this.customTextPosition = true;
+    this.zIndex = -1;
+  }
+  getEdgeStyle(){
+    const style = super.getEdgeStyle();
+    style.stroke = "#ccc"
+    style.strokeDasharray = "5 5";
+    style.strokeWidth = 1;
+    return style
+  }
+  getTextPosition() {
+    const position = super.getTextPosition();
+    const currentPositionList = this.points.split(" ");
+    const pointsList = [];
+    currentPositionList &&
+      currentPositionList.forEach((item) => {
+        const [x, y] = item.split(",");
+        pointsList.push({ x: Number(x), y: Number(y) });
+      });
+    if (pointsList.length > 1) {
+      let { x: x1, y: y1 } = pointsList[0];
+      let { x: x2, y: y2 } = pointsList[1];
+      let distence = 50;
+      // 垂直
+      if (x1 === x2) {
+        if (y2 < y1) {
+          // 上
+          distence = -50;
+        }
+        position.y = y1 + distence;
+        position.x = x1;
+      } else {
+        // 水平
+        if (x2 < x1) {
+          // 左
+          distence = -50;
+        }
+        position.x = x1 + distence;
+        position.y = y1 - 10;
+      }
+    }
+    return position;
+  }
+}
+
+class CustomEdge extends PolylineEdge {}
+
+export default {
+  type: "dashe-edge",
+  model: CustomEdgeModel,
+  view: CustomEdge
+};

+ 41 - 0
src/components/flow-chart/tasks/_normal.js

@@ -0,0 +1,41 @@
+import { RectNode, RectNodeModel } from "@logicflow/core"
+
+class NormalTaskModel extends RectNodeModel {
+  initNodeData(data){
+    super.initNodeData(data);
+    this.height = 30
+  }
+  getNodeStyle(){
+    const style = super.getNodeStyle();
+    style.fill  = '#fff';
+    style.strokeWidth = 1;
+    style.stroke = '#ccc';
+
+    return style
+  }
+  getDefaultAnchor() {
+    const { width, height, x, y, id } = this;
+    return [
+      {
+        x: x,
+        y: y + 15,
+        name: 'bottom',
+        id: `${id}_0`
+      },
+      {
+        x: x,
+        y: y,
+        name: 'top',
+        id: `${id}_0`
+      },
+    ]
+  }
+}
+
+class NormalTaskView extends RectNode {}
+
+export default {
+  type:'NormalTask',
+  model:NormalTaskModel,
+  view:NormalTaskView
+}

+ 51 - 0
src/components/flow-chart/tasks/_process.js

@@ -0,0 +1,51 @@
+import { HtmlNodeModel, HtmlNode } from "@logicflow/core"
+import { colors } from "./../config";
+
+class ProcessTaskModel extends HtmlNodeModel {
+  initNodeData(data){
+    super.initNodeData(data);
+    this.height = 30
+  }
+  getNodeStyle(){
+    const style = super.getNodeStyle();
+    style.fill  = colors.process.background;
+    style.strokeWidth = 1;
+    style.stroke = colors.process.border;
+
+    return style
+  }
+  getDefaultAnchor() {
+    const { x, y, id } = this;
+    return [
+      {
+        x: x,
+        y: y + 15,
+        name: 'bottom',
+        id: `${id}_0`
+      },
+      {
+        x: x,
+        y: y - 15,
+        name: 'top',
+        id: `${id}_0`
+      },
+    ]
+  }
+}
+
+class ProcessTaskView extends HtmlNode {
+  setHtml(rootEl) {
+    const el = document.createElement('div');
+    el.className = 'process-wrapper';
+    el.innerHTML = `<div class="content"></div>`
+    rootEl.innerHTML = '';
+    rootEl.appendChild(el);
+  }
+}
+
+
+export default {
+  type:'ProcessTask',
+  view:ProcessTaskView,
+  model:ProcessTaskModel
+}

+ 43 - 0
src/components/flow-chart/tasks/_start.js

@@ -0,0 +1,43 @@
+import { RectNode, RectNodeModel } from "@logicflow/core"
+import { colors } from "./../config";
+
+class StartTaskModel extends RectNodeModel {
+  initNodeData(data) {
+    super.initNodeData(data);
+    this.height = 30
+  }
+  getNodeStyle() {
+    const style = super.getNodeStyle();
+    style.fill = colors.start.background;
+    style.stroke = colors.start.border;
+    style.strokeWidth = 1
+    return style
+  }
+  getDefaultAnchor() {
+    const { x, y, id } = this;
+    return [
+      {
+        x: x,
+        y: y + 15,
+        name: 'bottom',
+        id: `${id}_0`
+      },
+      {
+        x: x,
+        y: y - 15,
+        name: 'top',
+        id: `${id}_0`
+      },
+    ]
+  }
+}
+
+class startTaskView extends RectNode {
+ }
+
+
+export default {
+  type: 'StartTask',
+  model: StartTaskModel,
+  view: startTaskView
+}

+ 4 - 0
src/components/flow-chart/tasks/index.js

@@ -0,0 +1,4 @@
+export { default as StartTask } from "./_start"
+export { default as ProcessTask } from "./_process"
+export { default as NormalTask } from "./_normal"
+export { default as Dashe } from "./_dashe"

+ 99 - 0
src/components/flow-chart/utils/genProceeChart.js

@@ -0,0 +1,99 @@
+import { GAP_X, GAP_Y, MIDDMLE_X, START_Y } from "../config"
+
+const map = new Map()
+map.set('1', 'StartTask')
+map.set('2', 'ProcessTask')
+map.set('3', 'InterruptTask')
+map.set('4', 'EndTask')
+
+function createNode(nodeRaw, level = 0, index = 0, max = 0) {
+  let x = 0;
+  const y = START_Y + level * GAP_Y
+  const _index = index + 1;
+  const middle = Math.ceil(max / 2);
+
+  if (_index === middle || max === 0) x = MIDDMLE_X;
+  if (_index > middle) x = MIDDMLE_X + (middle * GAP_X)
+  if (_index < middle) x = MIDDMLE_X - (middle * GAP_X)
+
+  return ({
+    id: nodeRaw.order_process,
+    text: nodeRaw.status_name,
+    type: 'NormalTask',
+    x,
+    y,
+  })
+}
+
+function createStartNode(source) {
+  const nodeRaw = source.find(({ action_type }) => action_type === '1');
+  const startNode = createNode(nodeRaw);
+
+  return {
+    startNode,
+    startNodeRaw: nodeRaw
+  }
+}
+
+function createEdge(sourceNodeId, targetNodeId) {
+  return ({
+    sourceNodeId,
+    targetNodeId,
+    type: "dashe-edge"
+  })
+}
+
+export function generateProcessChart(source, record) {
+  const processChart = {
+    nodes: [],
+    edges: []
+  }
+
+  //找到开始节点
+  const { startNode, startNodeRaw } = createStartNode(source);
+  processChart.nodes.push(startNode);
+
+  //根据开始节点找到其他的节点并转换
+  function transform(nodeRaw, level = 0, parent = 0) {
+    level++
+    const { next_actions } = nodeRaw;
+    //从原数据中找到下一个节点的数据
+    const nextActionNodeRaw = source.filter(({ status_name }) => next_actions.includes(status_name))
+    nextActionNodeRaw.map((raw, index) => {
+      const node = createNode(raw, level, index, nextActionNodeRaw.length)
+      const edge = createEdge(parent, raw.order_process);
+      if(processChart.nodes.filter(({text})=> text === node.text).length === 0) processChart.nodes.push(node)
+      processChart.edges.push(edge)
+      //存在下个节点 递归生成
+      if (raw.next_actions.length > 0) transform(raw, level, raw.order_process)
+    });
+  }
+
+  transform(startNodeRaw, 0, startNodeRaw.order_process)
+
+
+  console.log(record)
+
+  //根据审批记录连线
+  record.forEach((item, index) => {
+    const descIndex = processChart.nodes.findIndex(({ id }) => id === item.order_process);
+    if (descIndex >= 0) {
+      processChart.nodes[descIndex].type = index === record.length - 1 ? 'ProcessTask' : 'StartTask' 
+      processChart.nodes[descIndex].properties = {
+        name: item.action_name,
+        time: item.addtime
+      }
+    }
+
+    const sourceEdgeIdx = processChart.edges.findIndex(({ sourceNodeId, targetNodeId }) => {
+      return String(sourceNodeId) === String(record[index]?.order_process) && String(targetNodeId) === String(record[index + 1]?.order_process);
+    });
+    
+
+    if (sourceEdgeIdx >= 0) {
+      processChart.edges[sourceEdgeIdx].type = 'polyline'
+    }
+  })
+
+  return processChart
+}

+ 70 - 0
src/components/flow-chart/utils/tooltip.js

@@ -0,0 +1,70 @@
+export class Tooltip {
+  static pluginName = 'Tooltip'
+  __clickOver = false;
+
+  constructor({ lf }) {
+    this.lf = lf;
+    this.bindEvent();
+  }
+
+  render(_, toolOverlay) {
+    this.__toolOverlay = toolOverlay;
+  }
+
+  bindEvent() {
+    this.lf.on('node:click', ({ data }) => {
+      setTimeout(() => {
+        this._activeData = data;
+        this.createTootip();
+        this.showTooltip();
+        this.__clickOver = true;
+      }, 100)
+    })
+
+    document.addEventListener('click', this.onClickOutside.bind(this))
+  }
+
+  onClickOutside(event) {
+    if (this.__clickOver && !this.__tooltipDOM?.contains(event.target)) {
+      this.__clickOver = false;
+      this.__tooltipDOM?.remove();
+    }
+  }
+
+  createTootip() {
+    this.__tooltipDOM = document.createElement('div');
+  }
+
+  showTooltip() {
+    const { properties } = this._activeData;
+    if (!properties.time || !properties.name) return;
+
+    const [x, y] = this.getTootipPosition();
+    this.__tooltipDOM.className = 'lf__tooltip';
+
+    this.__tooltipDOM.innerHTML = `
+     <div class="tooltip__arrow"></div>
+     <p>审批人 : ${properties.name}</p>
+     <p>时间 : ${properties.time}</p>
+    `
+
+    this.__tooltipDOM.style.position = 'absolute';
+    this.__tooltipDOM.style.top = `${y}px`;
+    this.__tooltipDOM.style.left = `${x + 10}px`;
+    this.__toolOverlay.appendChild(this.__tooltipDOM);
+  }
+
+  getTootipPosition() {
+    const data = this._activeData;
+    const Model = this.lf?.graphModel.getElement(data.id);
+
+    let x, y;
+
+    if (Model?.BaseType === 'node') {
+      x = data.x + Model.width / 2;
+      y = data.y - Model.height + 5;
+    }
+
+    return this.lf?.graphModel.transformModel.CanvasPointToHtmlPoint([x, y])
+  }
+}

+ 21 - 20
src/views/stock/allot/detail.vue

@@ -2,7 +2,8 @@
   <div class="allotDetail pagePadding" v-loading="loading">
     <div style="width: 100%" v-if="powers.some((i) => i == '007')">
       <div class="detail-page-title">
-        <span>调拨编号:</span><span v-if="sitem">{{ sitem.allot_code }}</span>
+        <span>调拨编号:</span>
+        <span v-if="sitem">{{ sitem.allot_code }}</span>
         <el-button
           @click="statusConfirm('-1', '作废该条信息')"
           type="danger"
@@ -10,8 +11,7 @@
           class="fr"
           :size="'mini'"
           v-if="status !== '' && status !== '5' && powers.some((i) => i == '015')"
-          >作废该条信息</el-button
-        >
+        >作废该条信息</el-button>
       </div>
 
       <!-- <status-bar
@@ -19,7 +19,7 @@
         :newTime="newTime"
         :options="statusOptions"
         :status="status"
-      /> -->
+      />-->
       <el-tabs v-model="activeTabs">
         <el-tab-pane label="业务详情" name="1">
           <el-collapse v-model="activeNames" style="margin: -18px 0 0 0">
@@ -47,8 +47,7 @@
                   :size="'mini'"
                   @click="statusConfirm('1', '发起审核流程')"
                   v-if="status === '0' && ppowers.some((i) => i == '0')"
-                  >发起审核流程
-                </el-button>
+                >发起审核流程</el-button>
 
                 <el-button
                   @click="statusConfirm('0', '取消审核流程')"
@@ -56,8 +55,7 @@
                   class="fr"
                   :size="'mini'"
                   v-if="status === '1' && powers.some((i) => i == '014')"
-                  >取消审核流程</el-button
-                >
+                >取消审核流程</el-button>
               </div>
             </el-collapse-item>
             <el-collapse-item
@@ -136,22 +134,24 @@ export default {
   components: {
     addForm,
     GoStockAudit,
-    InspectionTable,
+    InspectionTable
   },
   computed: {
     powers() {
       const tran =
-        this.$store.getters.btnList.find((item) => item.menu_route == "allotDetail") ||
-        {};
+        this.$store.getters.btnList.find(
+          item => item.menu_route == "allotDetail"
+        ) || {};
       const { action } = tran ?? {};
       return action ?? [];
     },
     ppowers() {
       const tran =
-        this.$store.getters.roleProcess.find((i) => i.process_type === "DBD") || {};
+        this.$store.getters.roleProcess.find(i => i.process_type === "DBD") ||
+        {};
       const { action } = tran ?? {};
       return action ?? [];
-    },
+    }
   },
   data() {
     return {
@@ -170,6 +170,7 @@ export default {
         { value: "3", label: "入库方验货" },
         { value: "4", label: "验货审核" },
         { value: "5", label: "调拨完成" },
+        { value: "6", label: "调拨驳回" },
       ],
     };
   },
@@ -187,7 +188,7 @@ export default {
       await this.$confirm(`确定要${message}?`, {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
-        type: "warning",
+        type: "warning"
       })
         .then(async () => {
           if (status === "-1") {
@@ -209,7 +210,7 @@ export default {
       if (res && res.code === 0) {
         this.$notify.success({
           title: message + "成功!",
-          message: "",
+          message: ""
         });
 
         this.routeGoto("check", {});
@@ -224,14 +225,14 @@ export default {
       let model = {
         id: this.queryId,
         remark: remark || "",
-        status: status,
+        status: status
       };
       const res = await asyncRequest.status(model);
       this.loading = false;
       if (res && res.code === 0) {
         this.$notify.success({
           title: message + "成功!",
-          message: "",
+          message: ""
         });
         this.initData();
       } else if (res && res.code >= 100 && res.code <= 104) {
@@ -242,7 +243,7 @@ export default {
     },
     async examForm(e) {
       if (!this.loading) {
-        let type = e.state === "1" ? "2" : "0";
+        let type = e.state === "1" ? "2" : "6";
         await this.setStatus(type, "提交入库方审核", e.remark);
       }
     },
@@ -263,7 +264,7 @@ export default {
         this.$message.warning(res.message);
       }
       this.loading = false;
-    },
-  },
+    }
+  }
 };
 </script>

+ 2 - 1
src/views/stock/allot/index.vue

@@ -249,6 +249,7 @@ export default {
         { id: "3", label: "待入库方验货提交" },
         { id: "4", label: "待验货审核" },
         { id: "5", label: "调拨已完成" },
+        { id: "6", label: "调拨驳回" },
       ],
       statusList: statusList,
       options: ["按出库方筛选", "按入库方筛选"],
@@ -430,4 +431,4 @@ export default {
 .el-icon-arrow-down {
   font-size: 12px;
 }
-</style>
+</style>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác