Bläddra i källkod

Merge branch '生产工单'

lxf 1 år sedan
förälder
incheckning
26b4c961ed

+ 2 - 0
package.json

@@ -40,6 +40,7 @@
     "jquery": "^3.7.0",
     "js-cookie": "3.0.1",
     "js-table2excel": "^1.1.2",
+    "jsbarcode": "^3.11.5",
     "jsencrypt": "3.3.1",
     "jspdf": "^2.5.1",
     "lossless-json": "^2.0.8",
@@ -48,6 +49,7 @@
     "pinia": "2.0.22",
     "pinia-plugin-persist": "^1.0.0",
     "pubsub-js": "^1.9.4",
+    "qrcodejs2-fix": "0.0.1",
     "sortablejs": "^1.15.0",
     "typescript": "^5.0.4",
     "vue": "3.2.45",

+ 28 - 0
src/components/CycleBarcode/index.vue

@@ -0,0 +1,28 @@
+<template>
+  <div>
+    <img :id="'barcode' + index" style="max-width: 100%" />
+  </div>
+</template>
+
+<script setup>
+import JsBarcode from "jsbarcode";
+const props = defineProps({
+  value: {
+    type: String,
+    default: "",
+  },
+  index: {
+    type: Number,
+  },
+});
+onMounted(() => {
+  JsBarcode("#barcode" + props.index, String(props.value), {
+    format: "CODE128",
+    lineColor: "#000",
+    background: "white",
+    width: 1.6,
+    height: 50,
+    displayValue: true,
+  });
+});
+</script>

+ 37 - 1
src/utils/util.js

@@ -442,7 +442,7 @@ export function downloadFile(fileStream, fileName) {
   URL.revokeObjectURL(url);
 }
 
-// 深冻结 
+// 深冻结
 export function deepFreeze(obj) {
   // 获取所有属性
   var propNames = Object.getOwnPropertyNames(obj);
@@ -457,3 +457,39 @@ export function deepFreeze(obj) {
   // 冻结自身
   return Object.freeze(obj);
 }
+
+// 日期格式化
+export function dateFormat(date, format) {
+  format = format || "yyyy-MM-dd hh:mm:ss";
+  if (date !== "Invalid Date") {
+    let o = {
+      "M+": date.getMonth() + 1, //month
+      "d+": date.getDate(), //day
+      "h+": date.getHours(), //hour
+      "m+": date.getMinutes(), //minute
+      "s+": date.getSeconds(), //second
+      "q+": Math.floor((date.getMonth() + 3) / 3), //quarter
+      S: date.getMilliseconds(), //millisecond
+    };
+    if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
+    for (let k in o)
+      if (new RegExp("(" + k + ")").test(format)) format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
+    return format;
+  }
+  return "";
+}
+
+// 获取近几天日期
+export function getNearDays(num) {
+  // 如果包括今天,如需获取当前日期的近7天,days应该为6
+  let oneDay = 24 * 60 * 60 * 1000;
+  let beginTime = new Date(Date.now() - num * oneDay); //当前时间为结束时间
+  beginTime = dateFormat(beginTime, "yyyy-MM-dd");
+  let endTime = new Date(Date.now() + num * oneDay);
+  endTime = dateFormat(endTime, "yyyy-MM-dd");
+  const days = {
+    beginTime,
+    endTime,
+  };
+  return days;
+}

+ 396 - 0
src/views/production/schedule/production-work-order/index.vue

@@ -0,0 +1,396 @@
+<template>
+  <el-card class="box-card">
+    <byTable
+      :source="sourceList.data"
+      :pagination="sourceList.pagination"
+      :config="config"
+      :loading="loading"
+      :searchConfig="searchConfig"
+      highlight-current-row
+      :table-events="{
+        select: selectRow,
+        'select-all': selectRow,
+      }"
+      :action-list="[
+        {
+          text: '打印生产面单',
+          action: () => clickSelectPrint(),
+        },
+      ]"
+      @get-list="getList"
+      @clickReset="clickReset"
+      @changeRadioGroup="changeRadioGroup">
+      <template #code="{ item }">
+        <div>
+          <a style="color: #409eff; cursor: pointer; word-break: break-all" @click="clickCode(item)">{{ item.code }}</a>
+        </div>
+      </template>
+      <template #address="{ item }">
+        <div>{{ item.province }}, {{ item.city }}, {{ item.county }}, {{ item.detailedAddress }}</div>
+      </template>
+    </byTable>
+    <div style="display: none">
+      <div style="width: 250px" id="printMe">
+        <div v-for="(item, index) in QRcodeList" :key="index">
+          <div style="height: 442px; padding-top: 2px; overflow: hidden; position: relative">
+            <div style="border-bottom: 1px solid #000; display: flex; align-items: center; justify-content: center">
+              <CycleBarcode :value="item.orderWlnCode || item.orderCode" :index="index" style="max-width: 100%"></CycleBarcode>
+            </div>
+            <div style="display: flex; align-items: center; justify-content: center">
+              <div style="width: 150px; height: 150px; margin-top: 8px" :id="'print' + index" :ref="'print' + index">
+                <img src="" alt="" style="vertical-align: middle; height: 100%; width: 100%" />
+              </div>
+            </div>
+            <div style="text-align: center; font-size: 18px; font-weight: 700; padding: 4px 0; border-bottom: 1px solid #000">{{ item.completeTime }}</div>
+            <div style="word-break: break-all; padding: 2px">SKU品号:{{ item.skuSpecCode }}</div>
+            <div style="word-break: break-all; padding: 2px">SKU品名:{{ item.skuSpecName }}</div>
+            <div style="word-break: break-all; padding: 2px">BOM品号:{{ item.bomSpecCode }}</div>
+            <div style="word-break: break-all; padding: 2px">BOM品名:{{ item.bomSpecName }}</div>
+            <div v-if="item.orderWlnCode" class="one">
+              <div class="two">
+                <div class="three">万里牛</div>
+              </div>
+            </div>
+          </div>
+          <div style="page-break-after: always"></div>
+        </div>
+      </div>
+      <el-button type="primary" style="display: none" v-print="printObj" id="printBtnMini"></el-button>
+    </div>
+  </el-card>
+</template>
+
+<script setup>
+import byTable from "/src/components/byTable/index";
+import { getNearDays } from "/src/utils/util";
+import QRCode from "qrcodejs2-fix";
+import { ElMessage } from "element-plus";
+import CycleBarcode from "/src/components/CycleBarcode";
+
+const { proxy } = getCurrentInstance();
+const sourceList = ref({
+  data: [],
+  pagination: {
+    total: 0,
+    pageNum: 1,
+    pageSize: 10,
+    orderCode: "",
+    orderWlnCode: "",
+    skuSpecCode: "",
+    skuSpecName: "",
+    bomSpecCode: "",
+    bomSpecName: "",
+    productionWorkOrderCode: "",
+    beginTime: "",
+    endTime: "",
+    type: 3,
+  },
+});
+const loading = ref(false);
+const searchConfig = computed(() => {
+  return [
+    {
+      type: "input",
+      prop: "orderCode",
+      label: "订单号",
+    },
+    {
+      type: "input",
+      prop: "orderWlnCode",
+      label: "万里牛单号",
+    },
+    {
+      type: "input",
+      prop: "skuSpecCode",
+      label: "SKU品号",
+    },
+    {
+      type: "input",
+      prop: "skuSpecName",
+      label: "SKU品名",
+    },
+    {
+      type: "input",
+      prop: "bomSpecCode",
+      label: "BOM品号",
+    },
+    {
+      type: "input",
+      prop: "bomSpecName",
+      label: "BOM品名",
+    },
+    {
+      type: "input",
+      prop: "productionWorkOrderCode",
+      label: "工单号",
+    },
+    {
+      type: "radio-group",
+      prop: "type",
+      label: "交期",
+      data: [
+        {
+          dictKey: 1,
+          dictValue: "近3天",
+        },
+        {
+          dictKey: 3,
+          dictValue: "近7天",
+        },
+        {
+          dictKey: 15,
+          dictValue: "近31天",
+        },
+      ],
+    },
+    {
+      type: "date",
+      propList: ["beginTime", "endTime"],
+      label: "日期",
+    },
+  ];
+});
+const config = computed(() => {
+  return [
+    {
+      type: "selection",
+      attrs: {
+        checkAtt: "isCheck",
+      },
+    },
+    {
+      attrs: {
+        label: "订单号",
+        prop: "orderCode",
+        width: 180,
+      },
+    },
+    {
+      attrs: {
+        label: "万里牛单号",
+        prop: "orderWlnCode",
+        width: 150,
+      },
+    },
+    {
+      attrs: {
+        label: "SKU品号",
+        prop: "skuSpecCode",
+        width: 140,
+      },
+    },
+    {
+      attrs: {
+        label: "SKU品名",
+        prop: "skuSpecName",
+        "min-width": 220,
+      },
+    },
+    {
+      attrs: {
+        label: "BOM品号",
+        prop: "bomSpecCode",
+        width: 140,
+      },
+    },
+    {
+      attrs: {
+        label: "BOM品名",
+        prop: "bomSpecName",
+        "min-width": 280,
+      },
+    },
+    {
+      attrs: {
+        label: "生产状态",
+        prop: "status",
+        width: 100,
+      },
+      render(val) {
+        if (val == 0) {
+          return "待投产";
+        }
+      },
+    },
+    // {
+    //   attrs: {
+    //     label: "工艺路线",
+    //     prop: "departmentName",
+    //     width: 120,
+    //   },
+    // },
+    // {
+    //   attrs: {
+    //     label: "投产时间",
+    //     prop: "departmentName",
+    //     width: 160,
+    //     align: "center",
+    //     fixed: "right",
+    //   },
+    // },
+    {
+      attrs: {
+        label: "完成时间",
+        prop: "completeTime",
+        width: 160,
+        align: "center",
+        fixed: "right",
+      },
+    },
+    // {
+    //   attrs: {
+    //     label: "生产用时",
+    //     prop: "departmentName",
+    //     width: 160,
+    //     align: "center",
+    //     fixed: "right",
+    //   },
+    // },
+    {
+      attrs: {
+        label: "操作",
+        width: 120,
+        align: "center",
+        fixed: "right",
+      },
+      renderHTML(row) {
+        return [
+          {
+            attrs: {
+              label: "打印生产面单",
+              type: "primary",
+              text: true,
+            },
+            el: "button",
+            click() {
+              clickPrint([row]);
+            },
+          },
+        ];
+      },
+    },
+  ];
+});
+const getList = async (req, status) => {
+  if (status) {
+    sourceList.value.pagination = {
+      pageNum: sourceList.value.pagination.pageNum,
+      pageSize: sourceList.value.pagination.pageSize,
+      type: 3,
+      beginTime: getNearDays(3).beginTime,
+      endTime: getNearDays(3).endTime,
+    };
+  } else {
+    sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
+  }
+  loading.value = true;
+  proxy.post("/productionWorkOrder/page", sourceList.value.pagination).then((res) => {
+    if (res.rows && res.rows.length > 0) {
+      sourceList.value.data = res.rows.map((item) => {
+        return {
+          ...item,
+          isCheck: true,
+        };
+      });
+    } else {
+      sourceList.value.data = [];
+    }
+    sourceList.value.pagination.total = res.total;
+    setTimeout(() => {
+      loading.value = false;
+    }, 200);
+  });
+};
+getList({ beginTime: getNearDays(3).beginTime, endTime: getNearDays(3).endTime });
+const clickReset = () => {
+  getList("", true);
+};
+const changeRadioGroup = () => {
+  getList({ beginTime: getNearDays(sourceList.value.pagination.type).beginTime, endTime: getNearDays(sourceList.value.pagination.type).endTime });
+};
+const clickCode = (row) => {
+  proxy.$router.replace({
+    path: "/addOrder",
+    query: {
+      detailId: row.id,
+      text: "订单详情",
+      random: proxy.random(),
+      orderInquiry: true,
+    },
+  });
+};
+const printObj = ref({
+  id: "printMe",
+  popTitle: "",
+  extraCss: "https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css",
+  extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>',
+});
+const selectData = ref([]);
+const selectRow = (data) => {
+  selectData.value = data;
+};
+const QRcodeList = ref([]);
+const clickPrint = (list) => {
+  QRcodeList.value = list;
+  nextTick(() => {
+    for (let i = 0; i < QRcodeList.value.length; i++) {
+      proxy.$refs["print" + i][0].innerHTML = ""; //清除二维码方法一
+      let text = QRcodeList.value[i].skuSpecCode;
+      new QRCode(proxy.$refs["print" + i][0], {
+        text: text, //页面地址 ,如果页面需要参数传递请注意哈希模式#
+        width: 150,
+        height: 150,
+        colorDark: "#000000",
+        colorLight: "#ffffff",
+        correctLevel: QRCode.CorrectLevel.H,
+      });
+    }
+    nextTick(() => {
+      const btn = document.getElementById("printBtnMini");
+      btn.click();
+    });
+  });
+};
+const clickSelectPrint = () => {
+  if (selectData.value && selectData.value.length > 0) {
+    clickPrint(selectData.value);
+  } else {
+    return ElMessage("请选择需要打印的工单");
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+:deep(.el-dialog) {
+  margin-top: 10px !important;
+  margin-bottom: 10px !important;
+}
+.one {
+  position: absolute;
+  right: 10px;
+  top: 320px;
+  width: 70px;
+  height: 70px;
+  z-index: 99;
+  line-height: 80px;
+  text-align: center;
+  border-radius: 50%;
+  border: 1px solid #000;
+  .two {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    width: 60px;
+    height: 60px;
+    line-height: 60px;
+    text-align: center;
+    border-radius: 50%;
+    border: 1px dashed #000;
+    .three {
+      rotate: -45deg;
+      font-size: 14px;
+    }
+  }
+}
+</style>