dengrui 1 місяць тому
батько
коміт
ed11fdc2ac

+ 236 - 141
src/views/pro-steps/components/duomeiticaiji.vue

@@ -1,111 +1,150 @@
 <template>
-  <el-scrollbar style="width: 100%; height: 100%; padding: 20px 0">
-    <div class="media-container">
-      <CameraUpload
-        @reset-select="clickReset"
-        @upload-finish="finish"
-        @delete-all="clickDeleteAll"
-        @camera-ohos="camera_ohos"
-        @select-ohos="select_ohos"
+  <div class="body">
+    <div class="itemRow">
+      <el-scrollbar @click.stop style="height: calc(100vh - 260px)">
+        <div
+          :class="selectItem === true ? 'itembox itemSelect' : 'itembox'"
+          @click="toCamera"
+        >
+          <svg-icon icon-class="paizhao" size="130" />
+        </div>
+        <div
+          :class="selectItem === index ? 'itembox itemSelect' : 'itembox'"
+          @click.stop="toShowImg(index)"
+          v-for="(item, index) in medias"
+        >
+          <el-image
+            :src="getImgurl(item)"
+            :zoom-rate="1"
+            class="imgBox"
+            fit="cover"
+          />
+        </div>
+      </el-scrollbar>
+    </div>
+    <div class="view" id="show">
+      <!-- 展示图片或者照相 -->
+      <video
+        id="video"
+        v-if="selectItem === true"
+        height="100%"
+        width="100%"
+        autoplay="autoplay"
+      ></video>
+      <el-image
+        v-if="selectItem !== true && selectItem !== null"
+        :initial-index="selectItem"
+        :max-scale="7"
+        :min-scale="0.2"
+        :preview-src-list="urlList"
+        :src="getImgurl(medias[selectItem])"
+        :zoom-rate="1"
+        style="width: 100%; height: 100%"
+        fit="cover"
       />
-      <div
-        v-for="(item, index) in medias.filter((item: any) => item.filePath)"
-        :key="index"
-        class="media-item"
-        @click="item.isSelected = !item.isSelected"
-      >
-        <!--        <img :src="getImgurl(item)" alt="" class="img-box" object-fit="cover" />-->
-        <el-image
-          :initial-index="index"
-          :max-scale="7"
-          :min-scale="0.2"
-          :preview-src-list="urlList"
-          :src="getImgurl(item)"
-          :zoom-rate="1.2"
-          class="img-box"
-          fit="cover"
-        />
-        <div class="checkB-border"></div>
-        <i-ep-delete
-          v-show="item.isSelected"
-          class="check"
-          color="#ff4d4f"
-          size="20px"
-        />
+      <canvas
+        v-show="false"
+        id="canvas"
+        style="height: 100%; width: 100%"
+      ></canvas>
+    </div>
+    <div
+      class="itemRow"
+      style="
+        display: flex;
+        flex-direction: column;
+        justify-content: space-between;
+      "
+    >
+      <div class="operate">
+        <el-button
+          v-if="selectItem === true"
+          style="width: 100%"
+          type="primary"
+          @click="takePhoto"
+          >拍照</el-button
+        >
+
+        <div class="flashlightBox" v-if="selectItem === true">
+          <div style="margin-top: 5px">闪光灯:</div>
+
+          <el-switch
+            v-model="flashlight"
+            class="mt-2"
+            inline-prompt
+            style="
+              --el-switch-on-color: #13ce66;
+              --el-switch-off-color: #ff4949;
+            "
+            :active-icon="Check"
+            :inactive-icon="Close"
+          />
+        </div>
+      </div>
+      <div class="operate">
+        <el-button style="width: 100%" type="primary">提交</el-button>
       </div>
     </div>
-  </el-scrollbar>
+  </div>
 </template>
 
-<script lang="ts" setup>
+<script setup>
+defineOptions({
+  name: "duomeiticaiji",
+});
 import { useProcessStore } from "@/store";
 import { addMedia, deleteMedias, pageMedias } from "@/api/prosteps/medias";
-
-import CameraUpload from "@/components/Upload/CameraUpload.vue";
-
+import { Check, Close } from "@element-plus/icons-vue";
+import { uploadFileApi } from "@/api/file";
 const proStore = useProcessStore();
-const medias = ref<any>([]);
-const urlList = ref<string[]>([]);
-
-defineOptions({
-  name: "Wuliaocaiji",
-});
-
-const input = ref("");
-
-const finish = (value: string) => {
-  addMedia({
-    filePath: value,
-    operationMediaId: proStore.odersData.operationId,
-    processId: proStore.scanInfo.id,
-    seqNo: proStore.scanInfo.seqNo,
-  }).then((res) => {
-    getListData();
-    ElMessage.success("上传成功");
-  });
+const toShowImg = (index) => {
+  console.log(index);
+  selectItem.value = index;
 };
-
-onMounted(() => {
-  getListData();
-});
-
-const getListData = () => {
-  pageMedias(
-    proStore.odersData.operationId,
-    proStore.scanInfo.id,
-    proStore.scanInfo.seqNo
-  ).then((res: any) => {
-    medias.value = res.data.records || [];
-    urlList.value = res.data.records.map((item: any) => {
-      return import.meta.env.VITE_APP_UPLOAD_URL + item.filePath;
-    });
-  });
-};
-
-const getImgurl = (item: any) => {
+//true为切换到视频流 其余则为切换展示图片
+const selectItem = ref(null);
+const flashlight = ref(false);
+const medias = ref([]);
+const urlList = ref([]);
+const getImgurl = (item) => {
   let url = import.meta.env.VITE_APP_UPLOAD_URL + item.filePath;
   return url;
 };
-
-const clickReset = () => {
-  // medias.value.forEach((item: any) => {
-  //   item.isSelected = false;
-  // });
-  getListData();
+//切换视频流
+const toCamera = () => {
+  if (selectItem.value != true) {
+    selectItem.value = true;
+    ElMessage.success("切换到拍照模式");
+    openMedia();
+  }
 };
-
-const clickDeleteAll = () => {
-  let ids = medias.value
-    .filter((item: any) => item.isSelected)
-    .map((item: any) => item.id);
-
-  ids &&
-    ids.length > 0 &&
-    deleteMedias(ids).then(() => {
-      getListData();
+let mediaStreamTrack = null; // 视频对象(全局)
+let video;
+const openMedia = async () => {
+  if (window.openHarmonyBridge && window.openHarmonyBridge.startCamera) {
+    camera_ohos();
+  } else {
+    nextTick(() => {
+      let show = document.getElementById("show");
+      let constraints = {
+        video: { width: show.clientWidth, height: show.clientHeight },
+        audio: false,
+      };
+      //获得video摄像头
+      video = document.getElementById("video");
+      navigator.mediaDevices
+        .getUserMedia(constraints)
+        .then(async (mediaStream) => {
+          mediaStreamTrack = mediaStream.getVideoTracks();
+          video.srcObject = mediaStream;
+          video.play();
+        })
+        .catch((error) => {
+          ElMessage.error("没有找到设备,或者没有权限");
+        });
     });
+  }
 };
-
 const select_ohos = () => {
   let p = {
     token: localStorage.getItem("token"),
@@ -139,61 +178,117 @@ const camera_ohos = () => {
     window.openHarmonyBridge.startCamera(JSON.stringify(p));
   }
 };
+// 拍照
+function takePhoto() {
+  //获得Canvas对象
+  let video = document.getElementById("video");
+  let canvas = document.getElementById("canvas");
+  let show = document.getElementById("show");
+  canvas.width = show.clientWidth; // 实际渲染像素
+  canvas.height = show.clientHeight; // 实际渲染像素
+  let ctx = canvas.getContext("2d");
+  ctx.imageSmoothingEnabled = false; //关闭抗锯齿
+  ctx.drawImage(video, 0, 0, show.clientWidth, show.clientHeight);
+  let base64Data = document.getElementById("canvas").toDataURL();
+  let blob = dataURItoBlob(base64Data);
+  let file = new File([blob], `photo.png`, { type: "image/png" });
+  uploadFileApi(file).then((res) => {
+    finish(res.data.fileUrl);
+  });
+}
+function dataURItoBlob(base64Data) {
+  var byteString;
+  if (base64Data.split(",")[0].indexOf("base64") >= 0)
+    byteString = atob(base64Data.split(",")[1]);
+  else byteString = unescape(base64Data.split(",")[1]);
+  var mimeString = base64Data.split(",")[0].split(":")[1].split(";")[0];
+  var ia = new Uint8Array(byteString.length);
+  for (var i = 0; i < byteString.length; i++) {
+    ia[i] = byteString.charCodeAt(i);
+  }
+  return new Blob([ia], { type: mimeString });
+}
+const finish = (value) => {
+  addMedia({
+    filePath: value,
+    operationMediaId: proStore.odersData.operationId,
+    processId: proStore.scanInfo.id,
+    seqNo: proStore.scanInfo.seqNo,
+  }).then((res) => {
+    getListData();
+    ElMessage.success("上传成功");
+  });
+};
+// 关闭摄像头
+function closeMedia() {
+  let stream = document.getElementById("video").srcObject;
+  if (stream) {
+    let tracks = stream.getTracks();
+    tracks?.forEach(function (track) {
+      track.stop();
+    });
+  }
+  document.getElementById("video").srcObject = null;
+}
+const getListData = () => {
+  pageMedias(
+    proStore.odersData.operationId,
+    proStore.scanInfo.id,
+    proStore.scanInfo.seqNo
+  ).then((res) => {
+    medias.value = res.data.records || [];
+    urlList.value = res.data.records.map((item) => {
+      return import.meta.env.VITE_APP_UPLOAD_URL + item.filePath;
+    });
+  });
+};
 
-// window.addEventListener("message", (event) => {
-//   const data = JSON.parse(event.data);
-//   if (data.fullUrl && data.messageKey && data.messageKey === "refreshView") {
-//     getListData();
-//   }
-// });
+onMounted(() => {
+  getListData();
+});
 </script>
 
 <style lang="scss" scoped>
-.media-container {
+.body {
   width: 100%;
-  display: grid;
-  /*行间距*/
-  //grid-row-gap: 24px;
-  ///*列间距*/
-  //grid-column-gap: 24px;
-  /*每3行有2个行间距,所以每个格子的宽高都要减去(24*2) / 3 */
-  //grid-template-columns: repeat(4, calc(33.33% - 16px));
-  //grid-template-rows: repeat(4, calc(33.33% - 16px));
-  //grid-template-columns: 1fr 1fr 1fr 1fr;
-  grid-template-columns: repeat(auto-fit, 300px);
-  grid-auto-rows: 300px;
-  grid-gap: 24px; /* 设置元素之间的间距 */
-  overflow-y: auto;
-}
-
-.media-item {
-  width: 292px;
-  height: 292px;
-  flex-shrink: 0;
-  margin-bottom: 49px;
-  border: 1px solid #ccc;
-  border-radius: 16px 16px 16px 16px;
-  overflow: hidden;
-  position: relative;
-
-  .img-box {
-    width: 292px;
-    height: 292px;
+  height: calc(100vh - 240px);
+  border: 1px solid;
+  display: flex;
+  .itemRow {
+    width: 180px;
+    background-color: #d5dade;
+    padding: 20px;
+    .itembox {
+      width: 140px;
+      height: 140px;
+      border-radius: 10px;
+      background-color: #f2f2f2;
+      margin-bottom: 20px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      overflow: hidden;
+      .imgBox {
+        width: 140px;
+        height: 140px;
+      }
+    }
+    .itemSelect {
+      border: 1px solid greenyellow;
+      box-sizing: border-box;
+    }
+    .operate {
+      margin: 10px 0;
+      .flashlightBox {
+        height: 40px;
+        display: flex;
+        align-items: center;
+        justify-content: start;
+      }
+    }
   }
-
-  .checkB-border {
-    position: absolute;
-    top: 20px;
-    right: 20px;
-    width: 40px;
-    height: 40px;
-    border: 2px solid #1482f0;
-  }
-
-  .check {
-    position: absolute;
-    top: 30px;
-    right: 30px;
+  .view {
+    flex: 1;
   }
 }
 </style>

+ 202 - 113
src/views/pro-steps/components/wuliaocaiji.vue

@@ -2,62 +2,44 @@
   <div class="scanCode">
     <ScanCodeInput v-model="scanCode" @keyup.enter="enterfnc" />
   </div>
-  <div v-if="opCompentDataList.length < 1" class="showCodeBody">
-    <div class="codeBox">
-      <img
-        src="@/assets/icons/shaoma.svg"
-        style="width: 134px; height: 134px"
-      />
-      <div class="codeText">扫码物料码添加物料</div>
+  <div class="materialInfoBody">
+    <el-scrollbar @click.stop style="height: calc(100vh - 360px)">
+      <el-table
+        :data="tableData"
+        border
+        style="width: 100%; height: calc(100vh - 360px)"
+      >
+        <el-table-column label="序号" type="index" width="120" align="center" />
+        <el-table-column prop="materialModel" label="物料规格" align="center" />
+        <el-table-column prop="materialName" label="物料名称" align="center" />
+        <el-table-column prop="needNum" label="需求数量" align="center" />
+        <el-table-column prop="scanNum" label="扫码确认数量" align="center" />
+        <el-table-column prop="materialArray" label="物料编号" width="400">
+          <template #default="scope">
+            <el-tag
+              v-for="(tag, index) in scope.row.materialArray"
+              :key="tag.label"
+              closable
+              style="margin-right: 5px"
+              @close="handleClose(scope.$index, index)"
+            >
+              {{ tag.label }}&nbsp;{{ tag.num }}
+            </el-tag>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-scrollbar>
+    <div class="btns">
+      <el-button type="primary">提交</el-button>
     </div>
   </div>
-  <div v-else class="materialInfoBody">
-    <div
-      v-for="(item, index) in opCompentDataList"
-      :class="[
-        item.needNum - item.realNum <= 0
-          ? 'infoMsg infoMsgImg blueBgClass'
-          : 'infoMsg whiteBgClass',
-      ]"
-      :key="index"
-      @click="toXQPop(item)"
-    >
-      <div class="leftMsg">
-        <div class="nameMsg">{{ item.itemName }}</div>
-        <div class="describe">{{ item.itemCode }}</div>
-        <div class="describe">{{ item.itemModel }}</div>
-        <div class="describe">需求:{{ Number(item.needNum) }}</div>
-      </div>
-      <div v-if="item.needNum - item.realNum != 0" class="rightMsg">
-        <div class="sum">
-          {{
-            Number(item.needNum) - Number(item.realNum) < 0
-              ? 0
-              : Number(item.needNum) - Number(item.realNum)
-          }}
-        </div>
-        <div class="describe">还需采集</div>
-      </div>
-      <svg-icon class="svgStyle" icon-class="jiaobiao" size="25" />
-    </div>
-  </div>
-  <xiangqingPopUp
-    v-model="showXQ"
-    :showInfo="showInfo"
-    :showInfoData="showInfoData"
-  />
-  <caijiRightPopUp
-    ref="caijiRef"
-    v-model="showCJ"
-    :seqNo="scanCode"
-    @submit="submit"
-  />
 </template>
 
 <script setup>
+defineOptions({
+  name: "Wuliaocaiji",
+});
 import ScanCodeInput from "@/components/ScanCodeInput/index.vue";
-import caijiRightPopUp from "../popUpView/caijiRightPopUp.vue";
-import xiangqingPopUp from "../popUpView/xiangqingPopUp.vue";
 import {
   getInfo,
   itemRecordAdd,
@@ -65,10 +47,171 @@ import {
   searchMaterial,
 } from "@/api/prosteps/wuliaocaiji";
 import { useProcessStore } from "@/store";
-
-defineOptions({
-  name: "Wuliaocaiji",
-});
+const handleClose = (index1, index2) => {
+  tableData.value[index1].materialArray.splice(index2, 1);
+};
+const tableData = ref([
+  {
+    materialModel: "SG-8",
+    materialName: "盖片",
+    needNum: 20,
+    scanNum: 13,
+    materialArray: [
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+    ],
+  },
+  {
+    materialModel: "SG-8",
+    materialName: "盖片",
+    needNum: 20,
+    scanNum: 13,
+    materialArray: [
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+    ],
+  },
+  {
+    materialModel: "SG-8",
+    materialName: "盖片",
+    needNum: 20,
+    scanNum: 13,
+    materialArray: [
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+    ],
+  },
+  {
+    materialModel: "SG-8",
+    materialName: "盖片",
+    needNum: 20,
+    scanNum: 13,
+    materialArray: [
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+    ],
+  },
+  {
+    materialModel: "SG-8",
+    materialName: "盖片",
+    needNum: 20,
+    scanNum: 13,
+    materialArray: [
+      {
+        label: "SN001",
+        num: 12,
+      },
+      {
+        label: "SN002",
+        num: 8,
+      },
+    ],
+  },
+]);
 const caijiRef = ref(null);
 const store = useProcessStore();
 const scanCode = ref("");
@@ -166,67 +309,13 @@ onMounted(() => {
 
 .materialInfoBody {
   width: 100%;
-  margin-top: $p10;
-  display: grid;
-  gap: 20px;
-  grid-template-columns: 1fr 1fr;
-  color: var(--ohos-text);
-
-  .infoMsgImg {
-    background-image: url("@/assets/images/caijiwancheng.png");
-    background-position: right top;
-    background-repeat: no-repeat;
-    background-size: 100px 100px;
-  }
-
-  .blueBgClass {
-    background-color: #64bb5c;
-  }
-
-  .whiteBgClass {
-    background-color: var(--ohos-box-bg);
-  }
-
-  .infoMsg {
-    height: 190px;
-    color: var(--ohos-text);
-    border-radius: 16px;
-    background-color: #d5dade;
+  height: calc(100vh - 360px);
+  margin-top: 10px;
+  .btns {
+    height: 50px;
     display: flex;
-    padding: $p20;
-    justify-content: space-between;
     align-items: center;
-    position: relative;
-
-    .svgStyle {
-      position: absolute;
-      bottom: 0;
-      right: 0;
-      color: var(--ohos-text);
-    }
-
-    .describe {
-      font-size: $f20;
-      color: $font-default-60;
-      line-height: 30px;
-      color: var(--ohos-text);
-    }
-
-    .leftMsg {
-      .nameMsg {
-        font-size: $f24;
-        font-weight: $Medium;
-      }
-    }
-
-    .rightMsg {
-      .sum {
-        font-size: $f38;
-        font-weight: bold;
-        line-height: 38px;
-        text-align: right;
-      }
-    }
+    justify-content: end;
   }
 }
 :deep(.el-input__wrapper) {

+ 195 - 1
src/views/pro-steps/index.vue

@@ -288,7 +288,11 @@
               >
             </div>
             <div style="display: flex">
-              <el-button type="primary" @click="" style="width: 50%"
+              <el-button
+                type="primary"
+                @click="popStatus8 = true"
+                style="width: 50%"
+                :disabled="true"
                 >流程单据</el-button
               >
               <el-button
@@ -1157,6 +1161,139 @@
         </div>
       </div>
     </div>
+    <!-- 流程单据 -->
+    <div class="midPopUp" v-if="popStatus8" @click.stop="popStatus8 = false">
+      <div class="popView">
+        <div
+          class="hang"
+          style="
+            text-align: center;
+            font-size: 26px;
+            font-weight: 600;
+            width: 100%;
+            display: flex;
+            justify-content: space-between;
+          "
+        >
+          <div>流程模板</div>
+
+          <el-button
+            type="primary"
+            style="width: 80px; float: right; margin-right: 10px !important"
+            @click="toCreateTemplate"
+          >
+            新建
+          </el-button>
+        </div>
+        <el-divider
+          content-position="center"
+          style="border-color: black !important"
+        ></el-divider>
+        <el-scrollbar @click.stop style="height: calc(100vh - 260px)">
+          <div
+            style="
+              width: 100%;
+              display: grid;
+              gap: 20px;
+              padding: 20px;
+              grid-template-columns: repeat(3, 1fr);
+            "
+          >
+            <div
+              :class="
+                index == selectIndexData5 && templateType == 1
+                  ? 'selcetedMaterialInfoBoxTemplate materialInfoBoxTemplate'
+                  : 'materialInfoBoxTemplate'
+              "
+              @click="
+                templateType = 1;
+                selectIndexData5 = index;
+              "
+              v-for="(item, index) in tableData5"
+            >
+              <div class="productitleText">模板名称: {{ item.name }}</div>
+              <div class="productitleText">创建时间:{{ item.date }}</div>
+              <div class="productitleText">创建人员:{{ item.user }}</div>
+            </div>
+          </div>
+        </el-scrollbar>
+        <div
+          class="hang"
+          style="
+            text-align: center;
+            font-size: 26px;
+            font-weight: 600;
+            width: 100%;
+            display: flex;
+            justify-content: space-between;
+          "
+        >
+          <div>待处理流程</div>
+
+          <el-button
+            type="primary"
+            style="width: 80px; float: right; margin-right: 10px !important"
+            @click="toCreateTemplate"
+          >
+            打开
+          </el-button>
+        </div>
+        <el-divider
+          content-position="center"
+          style="border-color: black !important"
+        ></el-divider>
+        <el-scrollbar @click.stop style="height: calc(100vh - 260px)">
+          <div
+            style="
+              width: 100%;
+              display: grid;
+              gap: 20px;
+              padding: 20px;
+              grid-template-columns: repeat(3, 1fr);
+            "
+          >
+            <div
+              :class="
+                index == selectIndexData5 && templateType == 2
+                  ? 'selcetedMaterialInfoBox materialInfoBox'
+                  : 'materialInfoBox'
+              "
+              @click="
+                templateType = 2;
+                selectIndexData5 = index;
+              "
+              v-for="(item, index) in tableData5"
+            >
+              <div class="productitleText">模板名称: {{ item.name }}</div>
+              <div class="productitleText">创建时间:{{ item.date }}</div>
+              <div class="productitleText">创建人员:{{ item.user }}</div>
+              <div class="productitleText">当前阶段:{{ item.stage }}</div>
+            </div>
+          </div>
+        </el-scrollbar>
+        <!-- <div class="btns" @click.stop style="margin-top: 10px">
+          <el-button
+            type="primary"
+            @click="
+              popStatus6 = false;
+              fileType = null;
+              selectIndexData4 = null;
+            "
+            style="width: 80px; float: right"
+            >取消</el-button
+          >
+
+          <el-button
+            type="success"
+            style="width: 80px; float: right; margin-right: 10px !important"
+            @click="toTemplate"
+            :disabled="selectIndexData5 == null"
+          >
+            打开
+          </el-button>
+        </div> -->
+      </div>
+    </div>
   </div>
 </template>
 
@@ -1353,6 +1490,42 @@ const tableData4 = ref([
   },
 ]);
 const selectIndexData3 = ref(null);
+//流程模板
+const templateType = ref(null);
+const selectIndexData5 = ref(null);
+const tableData5 = ref([
+  {
+    name: "委外",
+    date: "2025-05-06 12:21:32",
+    user: "admin",
+    stage: "A阶段",
+  },
+  {
+    name: "测试",
+    date: "2025-05-06 12:21:32",
+    user: "admin",
+    stage: "C阶段",
+  },
+  {
+    name: "返工",
+    date: "2025-05-06 12:21:32",
+    user: "admin",
+    stage: "D阶段",
+  },
+  {
+    name: "报故",
+    date: "2025-05-06 12:21:32",
+    user: "admin",
+    stage: "E阶段",
+  },
+  {
+    name: "检验",
+    date: "2025-05-06 12:21:32",
+    user: "admin",
+    stage: "F阶段",
+  },
+]);
+const toTemplate = () => {};
 //true为展示所有
 const opShowAllStatus = ref(false);
 const opValue = ref("1");
@@ -1442,6 +1615,8 @@ const popStatus6 = ref(null);
 //文件类型 0图纸资料 1作业指导书
 const fileType = ref(null);
 const popStatus7 = ref(null);
+// 单据
+const popStatus8 = ref(null);
 const callMaterialsNum1 = ref("");
 const callMaterialsNum2 = ref("");
 const openPop = async () => {
@@ -1686,6 +1861,25 @@ watch(
   background-position: right top;
   background-repeat: no-repeat;
 }
+.materialInfoBoxTemplate {
+  height: 160px;
+  font-size: 18px;
+  background-color: #02a7f0;
+  border-radius: 16px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  .productitleText {
+    font-size: 20px;
+    font-weight: 600;
+  }
+}
+.selcetedMaterialInfoBoxTemplate {
+  background-color: #ffffff70;
+  background-position: right top;
+  background-repeat: no-repeat;
+}
 .selectOpBox {
   height: 100px;
   margin-bottom: 10px;