Browse Source

装箱改造

asd26269546 1 year ago
parent
commit
cefa144047

+ 875 - 0
src/views/salesMange/shipmentMange/packing/index copy.vue

@@ -0,0 +1,875 @@
+<template>
+  <div class="tenant">
+    <!-- <Banner /> -->
+    <div class="content">
+      <byTable
+        :source="sourceList.data"
+        :pagination="sourceList.pagination"
+        :config="config"
+        :loading="loading"
+        highlight-current-row
+        :selectConfig="selectConfig"
+        :table-events="{
+          //element talbe事件都能传
+          select: selectRow,
+          'select-all': selectRow,
+        }"
+        :action-list="[
+          {
+            text: '出货',
+            disabled: selectData.length === 0,
+            action: () => openModalOne(),
+          },
+          {
+            text: '产品装箱',
+            action: () => openModal(),
+          },
+        ]"
+        @get-list="getList">
+        <template #code="{ item }">
+          <div>
+            <div v-for="(item, index) in getData(item.codeAPName, 'code')" :key="index">
+              {{ item }}
+            </div>
+          </div>
+        </template>
+        <template #productName="{ item }">
+          <div>
+            <div v-for="(item, index) in getData(item.codeAPName, 'productName')" :key="index">
+              {{ item }}
+            </div>
+          </div>
+        </template>
+        <template #netWeight="{ item }">
+          <div>
+            <div v-for="(i, index) in item.dataJsonListCopy" :key="index">
+              {{ i.netWeight + " kg" }}
+            </div>
+          </div>
+        </template>
+        <template #roughWeight="{ item }">
+          <div>
+            <div v-for="(i, index) in item.dataJsonListCopy" :key="index">
+              {{ i.roughWeight + " kg" }}
+            </div>
+          </div>
+        </template>
+        <template #boxLong="{ item }">
+          <div>
+            <div v-for="(i, index) in item.dataJsonListCopy" :key="index">
+              {{ i.boxLong + " cm" }}
+            </div>
+          </div>
+        </template>
+        <template #boxWide="{ item }">
+          <div>
+            <div v-for="(i, index) in item.dataJsonListCopy" :key="index">
+              {{ i.boxWide + " cm" }}
+            </div>
+          </div>
+        </template>
+        <template #boxHigh="{ item }">
+          <div>
+            <div v-for="(i, index) in item.dataJsonListCopy" :key="index">
+              {{ i.boxHigh + " cm" }}
+            </div>
+          </div>
+        </template>
+        <template #bomVolume="{ item }">
+          <div>
+            <div v-for="(i, index) in item.dataJsonListCopy" :key="index">
+              {{ i.bomVolume + " m³" }}
+            </div>
+          </div>
+        </template>
+      </byTable>
+    </div>
+    <el-dialog title="产品装箱" v-model="dialogVisible" width="80%" v-loading="loading">
+      <el-form :model="formData.data" :rules="rules" ref="formDom" label-position="top">
+        <el-row :gutter="10">
+          <el-col :span="8">
+            <el-form-item label="客户名称" prop="customerId">
+              <el-select v-model="formData.data.customerId" placeholder="请选择" @change="handleChangeCustomer" filterable style="width: 100%">
+                <el-option v-for="item in customerList" :label="item.name" :value="item.id"> </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="选择合同" prop="contractIds">
+          <el-select v-model="formData.data.contractIds" placeholder="请选择" @change="handleChangeContract" filterable style="width: 100%" multiple>
+            <el-option v-for="item in contractData" :label="item.code" :value="item.id"> </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="合同明细" prop="contractProductData">
+          <el-table :data="formData.data.contractProductData" @select="handleSelectProduct" @select-all="handleSelectProduct" ref="tableDom">
+            <el-table-column type="selection" label="" width="50" />
+            <el-table-column prop="contractCode" label="合同编码" width="160" />
+            <el-table-column prop="productName" label="产品名称" min-width="180" />
+            <el-table-column prop="productSpec" label="规格型号" min-width="140" />
+            <el-table-column prop="cpQuantity" label="合同数量" width="140" />
+            <el-table-column prop="waitQuantity" label="待装箱数量" width="140" />
+            <el-table-column prop="quantity" label="装箱数量" width="160">
+              <template #default="{ row, $index }">
+                <el-form-item :prop="'contractProductData.' + $index + '.quantity'" :inline-message="true">
+                  <el-input-number v-model="row.quantity" :precision="4" :controls="false" :min="0" onmousewheel="return false;" />
+                </el-form-item>
+              </template>
+            </el-table-column>
+          </el-table>
+          <el-button type="primary" style="margin-top: 10px; width: 100%" @click="handleClickPacking"> 装箱 </el-button>
+        </el-form-item>
+        <el-form-item label="装箱明细" prop="packDetailList">
+          <div class="box" v-for="(item, index) in formData.data.packDetailList" :key="index">
+            <div ref="" style="position: relative">
+              <span>箱规</span>
+              <el-button type="primary" style="position: absolute; right: 0px; top: 0px" @click="clickDelete(index)" text>删除</el-button>
+            </div>
+            <el-row :gutter="10">
+              <el-col :span="5">
+                <el-form-item label="箱数" :prop="'packDetailList.' + index + '.packQuantity'" :rules="rules.packQuantity">
+                  <el-input-number
+                    v-model="item.packQuantity"
+                    :precision="0"
+                    :controls="false"
+                    :min="1"
+                    placeholder="请输入"
+                    onmousewheel="return false;"
+                    @change="(val) => handleChangePackQuantity(val, index)" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="5">
+                <el-form-item label="净重(kg)" :prop="'packDetailList.' + index + '.netWeight'" :rules="rules.netWeight">
+                  <el-input-number v-model="item.netWeight" :precision="2" :controls="false" :min="0" placeholder="请输入" onmousewheel="return false;" />
+                </el-form-item>
+              </el-col>
+
+              <el-col :span="5">
+                <el-form-item label="毛重(kg)" :prop="'packDetailList.' + index + '.roughWeight'" :rules="rules.roughWeight">
+                  <el-input-number v-model="item.roughWeight" :precision="2" :controls="false" :min="0" placeholder="请输入" onmousewheel="return false;" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="9">
+                <el-row>
+                  <el-form-item label="尺寸(cm³)" required>
+                    <el-col :span="1"></el-col>
+                    <el-col :span="7">
+                      <el-form-item label="" :prop="'packDetailList.' + index + '.boxLong'" :rules="rules.boxLong">
+                        <el-input-number
+                          v-model="item.boxLong"
+                          placeholder="长"
+                          :precision="2"
+                          :controls="false"
+                          :min="0"
+                          onmousewheel="return false;"></el-input-number>
+                      </el-form-item>
+                    </el-col>
+                    <el-col :span="1" style="text-align: center"> * </el-col>
+                    <el-col :span="7">
+                      <el-form-item label="" :prop="'packDetailList.' + index + '.boxWide'" :rules="rules.boxWide">
+                        <el-input-number
+                          v-model="item.boxWide"
+                          placeholder="宽"
+                          :precision="2"
+                          :controls="false"
+                          :min="0"
+                          onmousewheel="return false;"></el-input-number>
+                      </el-form-item>
+                    </el-col>
+                    <el-col :span="1" style="text-align: center"> * </el-col>
+                    <el-col :span="7">
+                      <el-form-item label="" :prop="'packDetailList.' + index + '.boxHigh'" :rules="rules.boxHigh">
+                        <el-input-number
+                          v-model="item.boxHigh"
+                          placeholder="高"
+                          :precision="2"
+                          :controls="false"
+                          :min="0"
+                          onmousewheel="return false;"></el-input-number>
+                      </el-form-item>
+                    </el-col>
+                  </el-form-item>
+                </el-row>
+              </el-col>
+            </el-row>
+            <div class="line"></div>
+            <el-form-item label="关联合同产品">
+              <div class="flex-box">
+                <div class="item" v-for="(product, j) in item.packDetailProductList" :key="j">
+                  <div>合同编码:{{ product.contractCode }}</div>
+                  <div>产品名称:{{ product.productName }}</div>
+                  <div>每箱数量:{{ product.quantity }}</div>
+                </div>
+              </div>
+            </el-form-item>
+            <div class="bottom-arrow" v-show="!item.isShow" @click="item.isShow = !item.isShow">
+              <span style="margin-right: 5px"> 自定义装箱明细</span>
+              <el-icon><ArrowDownBold /></el-icon>
+            </div>
+            <div class="bottom-arrow" v-show="item.isShow" @click="item.isShow = !item.isShow">
+              <span style="margin-right: 5px"> 收起</span>
+              <el-icon><ArrowUpBold /></el-icon>
+            </div>
+            <el-form-item prop="packDetailGoodsList" v-show="item.isShow">
+              <el-button type="primary" style="margin-bottom: 10px" @click="handleCustomPush(index)"> 添加行 </el-button>
+              <el-table :data="item.packDetailGoodsList">
+                <el-table-column label="货物描述">
+                  <template #default="{ row, $index }">
+                    <el-form-item :prop="['packDetailList', index, 'packDetailGoodsList', $index, 'remark']" :rules="rules.remark" :inline-message="true">
+                      <el-input v-model="row.remark" placeholder="请输入" />
+                    </el-form-item>
+                  </template>
+                </el-table-column>
+                <el-table-column label="单位" width="150">
+                  <template #default="{ row, $index }">
+                    <el-form-item :prop="['packDetailList', index, 'packDetailGoodsList', $index, 'unit']" :rules="rules.unit" :inline-message="true">
+                      <el-input v-model="row.unit" placeholder="请输入" />
+                    </el-form-item>
+                  </template>
+                </el-table-column>
+                <el-table-column label="数量" width="150">
+                  <template #default="{ row, $index }">
+                    <el-form-item
+                      :prop="['packDetailList', index, 'packDetailGoodsList', $index, 'quantity']"
+                      :rules="rules.quantityOne"
+                      :inline-message="true">
+                      <el-input-number v-model="row.quantity" :precision="4" :controls="false" :min="0" onmousewheel="return false;" />
+                    </el-form-item>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="zip" label="操作" width="100">
+                  <template #default="{ $index }">
+                    <el-button type="primary" link @click="handleCustomRemove(index, $index)">删除</el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </el-form-item>
+          </div>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="handleClose" size="large">取 消</el-button>
+        <el-button type="primary" @click="submitForm()" size="large" :loading="submitLoading"> 确 定 </el-button>
+      </template>
+    </el-dialog>
+    <el-dialog title="合并出货" v-model="dialogVisibleOne" width="400" v-loading="loadingOne">
+      <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.dataOne" :rules="rules" ref="byform"> </byForm>
+      <template #footer>
+        <el-button @click="dialogVisibleOne = false" size="large">取 消</el-button>
+        <el-button type="primary" @click="submitFormOne()" size="large" :loading="submitLoading"> 确 定 </el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+/* eslint-disable vue/no-unused-components */
+import { ElMessage, ElMessageBox } from "element-plus";
+import byTable from "@/components/byTable/index";
+import byForm from "@/components/byForm/index";
+import FileUpload from "@/components/FileUpload/index";
+import { computed, defineComponent, ref } from "vue";
+import { getToken } from "@/utils/auth";
+
+const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传文件服务器地址
+const headers = ref({ Authorization: "Bearer " + getToken() });
+const uploadData = ref({});
+const loading = ref(false);
+const loadingOne = ref(false);
+
+const submitLoading = ref(false);
+const sourceList = ref({
+  data: [],
+  pagination: {
+    total: 3,
+    pageNum: 1,
+    pageSize: 10,
+    status: "",
+  },
+});
+let dialogVisible = ref(false);
+let dialogVisibleOne = ref(false);
+
+let modalType = ref("add");
+let fileList = ref([]);
+let rules = ref({
+  contractIds: [{ required: true, message: "请选择合同", trigger: "change" }],
+  packQuantity: [{ required: true, message: "请输入箱数", trigger: "blur" }],
+  netWeight: [{ required: true, message: "请输入净重", trigger: "blur" }],
+  roughWeight: [{ required: true, message: "请输入毛重", trigger: "blur" }],
+  boxLong: [{ required: true, message: "请输入长", trigger: "blur" }],
+  boxWide: [{ required: true, message: "请输入宽", trigger: "blur" }],
+  boxHigh: [{ required: true, message: "请输入高", trigger: "blur" }],
+  quantity: [{ required: true, message: "请输入装箱数量", trigger: "blur" }],
+  quantityOne: [{ required: true, message: "请输入数量", trigger: "blur" }],
+  unit: [{ required: true, message: "请输入单位", trigger: "blur" }],
+  remark: [{ required: true, message: "请输入货物描述", trigger: "blur" }],
+
+  contractId: [{ required: true, message: "请选择主合同", trigger: "change" }],
+});
+
+const { proxy } = getCurrentInstance();
+const selectConfig = reactive([
+  {
+    label: "出货状态",
+    prop: "shipmentStatus",
+    data: [
+      {
+        label: "未出货",
+        value: "0",
+      },
+      {
+        label: "已出货",
+        value: "1",
+      },
+    ],
+  },
+]);
+const config = computed(() => {
+  return [
+    {
+      type: "selection",
+      attrs: {
+        checkAtt: "isCheck",
+      },
+    },
+    {
+      attrs: {
+        label: "合同号",
+        prop: "codeAPName",
+        slot: "code",
+      },
+    },
+    {
+      attrs: {
+        label: "产品名称",
+        prop: "codeAPName",
+        slot: "productName",
+      },
+    },
+
+    {
+      attrs: {
+        label: "总箱数",
+        prop: "packQuantity",
+        width: 90,
+      },
+    },
+    {
+      attrs: {
+        label: "净重",
+        slot: "netWeight",
+        width: 90,
+      },
+    },
+    {
+      attrs: {
+        label: "毛重",
+        slot: "roughWeight",
+        width: 90,
+      },
+    },
+    {
+      attrs: {
+        label: "长",
+        slot: "boxLong",
+        width: 90,
+      },
+    },
+
+    {
+      attrs: {
+        label: "宽",
+        slot: "boxWide",
+        width: 90,
+      },
+    },
+    {
+      attrs: {
+        label: "高",
+        slot: "boxHigh",
+        width: 90,
+      },
+    },
+    {
+      attrs: {
+        label: "体积",
+        slot: "bomVolume",
+        width: 90,
+      },
+    },
+    {
+      attrs: {
+        label: "总净重",
+        prop: "netWeight",
+        width: 120,
+      },
+      render(netWeight) {
+        return netWeight + " kg";
+      },
+    },
+    {
+      attrs: {
+        label: "总毛重",
+        prop: "roughWeight",
+        width: 120,
+      },
+      render(roughWeight) {
+        return roughWeight + " kg";
+      },
+    },
+    {
+      attrs: {
+        label: "总体积",
+        prop: "bomVolume",
+        width: 120,
+      },
+      render(bomVolume) {
+        return bomVolume + " m³";
+      },
+    },
+    {
+      attrs: {
+        label: "出货状态",
+        prop: "shipmentStatus",
+        width: 90,
+      },
+      render(status) {
+        return status == 1 ? "已出货" : status == 0 ? "未出货" : "";
+      },
+    },
+    {
+      attrs: {
+        label: "出货时间",
+        prop: "shipmentTime",
+        width: 155,
+      },
+      render(shipmentTime) {
+        if (shipmentTime) {
+          return shipmentTime.slice(5, 10);
+        } else {
+          return "";
+        }
+      },
+    },
+    {
+      attrs: {
+        label: "操作",
+        width: "90",
+        align: "center",
+      },
+      // 渲染 el-button,一般用在最后一列。
+      renderHTML(row) {
+        return [
+          {
+            attrs: {
+              label: "删除",
+              type: "primary",
+              text: true,
+              disabled: false,
+            },
+            el: "button",
+            click() {
+              ElMessageBox.confirm("此操作将永久作废该数据, 是否继续?", "提示", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning",
+              }).then(() => {
+                // 删除
+                proxy
+                  .post("/pack/delete", {
+                    id: row.packId,
+                  })
+                  .then((res) => {
+                    ElMessage({
+                      message: "作废成功",
+                      type: "success",
+                    });
+                    getList();
+                  });
+              });
+            },
+          },
+        ];
+      },
+    },
+  ];
+});
+const formDom = ref(null);
+let formData = reactive({
+  data: {},
+  dataOne: {},
+});
+const formOption = reactive({
+  inline: true,
+  labelWidth: 100,
+  itemWidth: 100,
+  rules: [],
+});
+const byform = ref(null);
+const treeData = ref([]);
+const formConfig = reactive([
+  {
+    type: "select",
+    prop: "contractId",
+    label: "主合同",
+    required: true,
+    data: [],
+  },
+]);
+
+const getList = async (req) => {
+  selectData.value = [];
+  sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
+  loading.value = true;
+  proxy.post("/packDetail/page", sourceList.value.pagination).then((res) => {
+    for (let i = 0; i < res.rows.length; i++) {
+      const e = res.rows[i];
+      e.isCheck = e.shipmentStatus == 1 ? false : true;
+      let arr = [];
+      let newArr = [];
+      arr = e.dataJsonList.split("_");
+      for (let j = 0; j < arr.length; j++) {
+        const jele = arr[j];
+        const jarr = jele.split(",");
+        const obj = {
+          bomVolume: jarr[0],
+          boxLong: jarr[1],
+          boxWide: jarr[2],
+          boxHigh: jarr[3],
+          roughWeight: jarr[4],
+          netWeight: jarr[5],
+        };
+        let createArr = new Array(Number(jarr[6])).fill(obj);
+        newArr = [...newArr, ...createArr];
+      }
+      e.dataJsonListCopy = newArr;
+    }
+    sourceList.value.data = res.rows;
+    sourceList.value.pagination.total = res.total;
+    loading.value = false;
+  });
+};
+
+const openModal = () => {
+  modalType.value = "add";
+  formData.data = {
+    packDetailList: [],
+    contractIds: [],
+  };
+  dialogVisible.value = true;
+  handleChangeCustomer("");
+};
+
+const openModalOne = () => {
+  formData.dataOne = {
+    ids: [],
+    contractId: "",
+  };
+  let ids = []; //合同id
+  let idsOne = []; //包装id
+  const list = selectData.value;
+  for (let i = 0; i < list.length; i++) {
+    const e = list[i];
+    ids = [...ids, ...e.contractIds.split(",")];
+    idsOne = [...idsOne, ...e.ids.split(",")];
+  }
+  formData.dataOne.ids = idsOne;
+  proxy.post(`/contract/getByIds`, ids).then((res) => {
+    formConfig[0].data = res.map((x) => ({
+      label: x.code,
+      value: x.id,
+    }));
+    dialogVisibleOne.value = true;
+  });
+};
+
+const submitForm = () => {
+  formDom.value.validate((vaild) => {
+    if (vaild) {
+      if (!formData.data.packDetailList.length > 0) {
+        return ElMessage({
+          message: "请添加装箱明细!",
+          type: "info",
+        });
+      }
+      submitLoading.value = true;
+      loadingOne.value = true;
+      for (let i = 0; i < formData.data.packDetailList.length; i++) {
+        const e = formData.data.packDetailList[i];
+        e.bomVolume = (e.boxLong * e.boxWide * e.boxHigh) / 1000000;
+      }
+      formData.data.contractIds = formData.data.contractIds.join(",");
+      proxy.post("/pack/" + modalType.value, formData.data).then(
+        (res) => {
+          ElMessage({
+            message: modalType.value == "add" ? "添加成功" : "编辑成功",
+            type: "success",
+          });
+          dialogVisible.value = false;
+          submitLoading.value = false;
+          loadingOne.value = false;
+          getList();
+        },
+        (err) => {
+          submitLoading.value = false;
+          loading.value = false;
+        }
+      );
+    }
+  });
+};
+const table = ref(null);
+const submitFormOne = () => {
+  byform.value.handleSubmit((valid) => {
+    loading.value = true;
+    submitLoading.value = true;
+    proxy.post("/packDetail/shipment", formData.dataOne).then(
+      (res) => {
+        ElMessage({
+          message: "出货成功",
+          type: "success",
+        });
+        dialogVisibleOne.value = false;
+        submitLoading.value = false;
+        loading.value = false;
+        getList();
+        selectData.value = [];
+      },
+      (err) => {
+        submitLoading.value = false;
+        loading.value = false;
+      }
+    );
+  });
+};
+
+const selectData = ref([]);
+const selectRow = (data) => {
+  selectData.value = data;
+};
+const selectProductData = ref([]);
+const handleSelectProduct = (data) => {
+  selectProductData.value = data;
+};
+const tableDom = ref(null);
+const handleClickPacking = () => {
+  if (selectProductData.value.length > 0) {
+    const list = selectProductData.value;
+    for (let i = 0; i < list.length; i++) {
+      const e = list[i];
+      if (!e.quantity) {
+        return ElMessage({
+          message: "请输入装箱数量",
+          type: "info",
+        });
+      }
+    }
+    for (let i = 0; i < list.length; i++) {
+      const e = list[i];
+      for (let j = 0; j < formData.data.contractProductData.length; j++) {
+        const jele = formData.data.contractProductData[j];
+        if (e.id === jele.id && e.quantity > Number(jele.waitQuantity)) {
+          return ElMessage({
+            message: "装箱数量不可大于袋装箱数量",
+            type: "info",
+          });
+        }
+      }
+    }
+    const packDetailProductList = list.map((x) => ({
+      contractCode: x.contractCode,
+      contractId: x.contractId,
+      contractProductId: x.id,
+      quantity: x.quantity,
+      productId: x.productId,
+      productName: x.productName,
+    }));
+    const customerId = formData.data.customerId ? formData.data.customerId : "";
+    const contractIds = formData.data.contractIds ? formData.data.contractIds.join(",") : "";
+    let item = {
+      customerId: customerId,
+      contractIds: contractIds,
+      packQuantity: 1,
+      netWeight: null,
+      roughWeight: null,
+      boxLong: null,
+      boxWide: null,
+      boxHigh: null,
+      bomVolume: "",
+      remark: "",
+      packDetailGoodsList: [],
+      packDetailProductList: packDetailProductList,
+      isShow: false,
+    };
+    formData.data.packDetailList.push(item);
+    handleChangePackQuantity(item.packQuantity, formData.data.packDetailList.length - 1);
+    tableDom.value.clearSelection();
+    selectProductData.value = [];
+    table.value.clearSelection();
+  } else {
+    return ElMessage({
+      message: "请选择产品 !",
+      type: "info",
+    });
+  }
+};
+
+const handleChangePackQuantity = (val, index) => {
+  const obj = {};
+  for (let i = 0; i < formData.data.contractProductData.length; i++) {
+    const e = formData.data.contractProductData[i];
+    obj[e.contractId + "_" + e.productId + ""] = (Number(e.cpQuantity) - Number(e.sumPackQuantity)).toFixed(2);
+  }
+  // 计算数量 即装箱数量 * 箱数 新增字段放在最外层
+  for (let i = 0; i < formData.data.packDetailList.length; i++) {
+    const ele = formData.data.packDetailList[i];
+    for (let j = 0; j < ele.packDetailProductList.length; j++) {
+      const jele = ele.packDetailProductList[j];
+      ele[jele.contractId + "_" + jele.productId + ""] = (Number(ele.packQuantity) * jele.quantity).toFixed(2);
+    }
+  }
+  // 计算新的待装箱数量
+  for (let i = 0; i < formData.data.packDetailList.length; i++) {
+    const e = formData.data.packDetailList[i];
+    for (const key in obj) {
+      if (e.hasOwnProperty(key)) {
+        obj[key] = (obj[key] - e[key]).toFixed(2);
+        if (obj[key] < 0) {
+          e.packQuantity = null;
+          handleChangePackQuantity(null, index);
+          return ElMessage({
+            message: "装箱数量 * 箱数不可大于待装箱数量",
+            type: "info",
+          });
+        }
+      }
+    }
+  }
+  // 赋值
+  for (let i = 0; i < formData.data.contractProductData.length; i++) {
+    const e = formData.data.contractProductData[i];
+    for (const key in obj) {
+      if (e.contractId + "_" + e.productId + "" === key) {
+        e.waitQuantity = obj[key];
+      }
+    }
+  }
+  // }
+};
+
+const handleCustomPush = (index) => {
+  formData.data.packDetailList[index].packDetailGoodsList.push({
+    unit: "",
+    quantity: "",
+    remark: "",
+  });
+};
+
+const handleCustomRemove = (index, sonIndex) => {
+  formData.data.packDetailList[index].packDetailGoodsList.splice(sonIndex, 1);
+};
+const customerList = ref([]);
+const getSelectData = () => {
+  proxy.post("/customer/page", { pageNum: 1, pageSize: 999 }).then((res) => {
+    customerList.value = res.rows.map((item) => {
+      return {
+        ...item,
+        label: item.name,
+        value: item.id,
+      };
+    });
+  });
+};
+const contractData = ref([]);
+const handleChangeCustomer = (val) => {
+  proxy.get(`/contract/getNoPackContractByCustomerId?customerId=${val}`).then((res) => {
+    contractData.value = res.data;
+    formData.data.contractIds = [];
+  });
+};
+const handleChangeContract = (val) => {
+  const customerId = formData.data.customerId ? formData.data.customerId : "";
+  proxy.get(`/contractProduct/getNoPackContractProductById?customerId=${customerId}&contractIds=${val}`).then((res) => {
+    formData.data.contractProductData = res.data.map((x) => ({
+      ...x,
+      waitQuantity: (Number(x.cpQuantity) - Number(x.sumPackQuantity)).toFixed(2),
+      quantity: null,
+    }));
+    handleChangePackQuantity();
+  });
+};
+
+const getData = (data, type) => {
+  if (!data) return [];
+  const arr = data.split(",");
+  if (arr && arr.length > 0) {
+    const arrOne = [];
+    for (let i = 0; i < arr.length; i++) {
+      const e = arr[i];
+      if (type === "code") {
+        arrOne.push(e.split("_")[0]);
+      } else if (type === "productName") {
+        arrOne.push(e.split("_")[1]);
+      }
+    }
+    return arrOne;
+  }
+  return [];
+};
+
+const handleClose = () => {
+  dialogVisible.value = false;
+  selectProductData.value = [];
+};
+getSelectData();
+getList();
+const clickDelete = (index) => {
+  formData.data.packDetailList.splice(index, 1);
+  handleChangePackQuantity();
+};
+</script>
+
+<style lang="scss" scoped>
+.tenant {
+  padding: 20px;
+}
+:deep(.el-collapse-item__header) {
+  background-color: #fde6c8;
+  border: none;
+}
+:deep(.el-collapse-item__wrap) {
+  background-color: #fde6c8;
+  border: none;
+}
+
+.box {
+  padding: 15px;
+  background: #fde6c8;
+  border: 1px solid #7fb5e3;
+  margin-bottom: 10px;
+  width: 100%;
+  .flex-box {
+    width: 100%;
+    display: flex;
+    flex-wrap: wrap;
+    .item {
+      width: 50%;
+      margin-bottom: 10px;
+      div {
+        line-height: 22px;
+      }
+    }
+  }
+  .line {
+    width: 100%;
+    height: 1px;
+    background: #7fb5e3;
+    margin: 20px 0;
+  }
+  .bottom-arrow {
+    text-align: center;
+    cursor: pointer;
+    color: #0084ff;
+  }
+}
+</style>

+ 324 - 7
src/views/salesMange/shipmentMange/packing/index.vue

@@ -84,7 +84,131 @@
         </template>
       </byTable>
     </div>
-    <el-dialog title="产品装箱" v-model="dialogVisible" width="80%" v-loading="loading">
+    <el-dialog title="产品装箱" v-model="dtlModalType" width="80%" v-loading="loading" @close="dtlModalClose">
+      <el-row :gutter="10">
+        <el-col :span="8">
+          <div class="common-title">箱规</div>
+          <el-form :model="boxFormData" :rules="rules" ref="formDom" label-position="top">
+            <el-form-item label="尺寸(cm³)" required>
+              <el-col :span="7">
+                <el-form-item label="" :prop="'boxLong'" :rules="rules.boxLong">
+                  <el-input-number
+                    v-model="boxFormData.boxLong"
+                    placeholder="长"
+                    :precision="2"
+                    :controls="false"
+                    :min="0"
+                    onmousewheel="return false;"></el-input-number>
+                </el-form-item>
+              </el-col>
+              <el-col :span="1" style="text-align: center"> * </el-col>
+              <el-col :span="7">
+                <el-form-item label="" :prop="'boxWide'" :rules="rules.boxWide">
+                  <el-input-number
+                    v-model="boxFormData.boxWide"
+                    placeholder="宽"
+                    :precision="2"
+                    :controls="false"
+                    :min="0"
+                    onmousewheel="return false;"></el-input-number>
+                </el-form-item>
+              </el-col>
+              <el-col :span="1" style="text-align: center"> * </el-col>
+              <el-col :span="7">
+                <el-form-item label="" :prop="'boxHigh'" :rules="rules.boxHigh">
+                  <el-input-number
+                    v-model="boxFormData.boxHigh"
+                    placeholder="高"
+                    :precision="2"
+                    :controls="false"
+                    :min="0"
+                    onmousewheel="return false;"></el-input-number>
+                </el-form-item>
+              </el-col>
+            </el-form-item>
+            <el-form-item label="体积" required>
+              <el-input-number
+                v-model="boxFormData.bomVolume"
+                placeholder="请输入"
+                :precision="4"
+                :controls="false"
+                :min="0"
+                disabled
+                onmousewheel="return false;"></el-input-number>
+            </el-form-item>
+            <el-form-item label="净重(kg)" :prop="'netWeight'" :rules="rules.netWeight">
+              <el-input-number
+                v-model="boxFormData.netWeight"
+                :precision="2"
+                :controls="false"
+                :min="0"
+                placeholder="请输入"
+                onmousewheel="return false;"></el-input-number>
+            </el-form-item>
+            <el-form-item label="毛重(kg)" :prop="'roughWeight'" :rules="rules.roughWeight">
+              <el-input-number
+                v-model="boxFormData.roughWeight"
+                :precision="2"
+                :controls="false"
+                :min="0"
+                placeholder="请输入"
+                onmousewheel="return false;"></el-input-number>
+            </el-form-item>
+            <el-form-item label="总箱数" :prop="'packQuantity'" :rules="rules.packQuantity">
+              <el-input-number
+                v-model="boxFormData.packQuantity"
+                :precision="0"
+                :controls="false"
+                :min="1"
+                placeholder="请输入"
+                onmousewheel="return false;"></el-input-number>
+            </el-form-item>
+          </el-form>
+        </el-col>
+        <el-col :span="16">
+          <!-- 添加行 -->
+          <div class="add-box" style="margin-bottom: 20px;">
+            <el-button type="primary" @click="packDetailProductListPush(boxIndex)"> 添加行 </el-button>
+            <el-button type="primary" @click="packDetailProductListPush(boxIndex)"> 自定义装箱 </el-button>
+          </div>
+          <el-table :data="boxFormData.packDetailProductList" @select="handleSelectProduct" @select-all="handleSelectProduct" ref="tableDom">
+              <el-table-column prop="productName" label="产品名称" min-width="180">
+                <template #default="{ row, $index }">
+                  <!-- 选择产品 -->
+                    <el-form-item 
+                      prop="mathId"  
+                      style="margin-bottom:0px" :inline-message="true">
+                      <el-select
+                        :model-value="boxFormData.packDetailProductList[$index].mathId" 
+                        placeholder="请选择" 
+                        @change="(e) => selectProduct(e,$index)" 
+                        filterable style="width: 100%"
+                        >
+                        <el-option v-for="item in formData.data.contractProductData" :disabled='item.disabled' :label="item.productName" :value="item.mathId"> </el-option>
+                      </el-select>
+                    </el-form-item>
+                  
+                </template>
+              </el-table-column>
+              <el-table-column prop="productSpec" label="规格型号" min-width="140" />
+              <el-table-column prop="cpQuantity" label="合同数量" width="140" />
+              <el-table-column prop="waitQuantity" label="待装箱数量" width="140" />
+              <el-table-column prop="quantity" label="装箱数量" width="160">
+                <template #default="{ row, $index }">
+                   
+                    <el-form-item prop="quantity" :inline-message="true">
+                      <el-input-number :max="row.waitQuantity" v-model="boxFormData.packDetailProductList[$index].quantity" :precision="4" :controls="false" :min="0" onmousewheel="return false;" />
+                    </el-form-item>
+                </template>
+              </el-table-column>
+          </el-table>
+        </el-col>
+      </el-row>
+      <template #footer>
+        <el-button type="primary" @click="submitBox()" size="large" :loading="submitLoading"> 确 定 </el-button>
+      </template>
+    </el-dialog>
+    <el-dialog title="产品装箱" v-model="dialogVisible" width="600" v-loading="loading">
       <el-form :model="formData.data" :rules="rules" ref="formDom" label-position="top">
         <el-row :gutter="10">
           <el-col :span="8">
@@ -100,6 +224,17 @@
             <el-option v-for="item in contractData" :label="item.code" :value="item.id"> </el-option>
           </el-select>
         </el-form-item>
+        <div class="box-icon-warp">
+          <div class="box-content"  v-for="(i,index) in formData.data.packDetailList"  :key="i.id" @click="openDtlUpdata(index)">
+            <div class="box-icon">
+              <i class="iconfont icon-iconm_daick"></i>
+            </div>
+            <div class="box-text"> * {{i.packQuantity}}</div>
+          </div>
+          <div class="add-box">
+            <i class="iconfont icon-iconm_tianjia1" @click="openDtlModal"></i>
+          </div>
+        </div>
         <el-form-item label="合同明细" prop="contractProductData">
           <el-table :data="formData.data.contractProductData" @select="handleSelectProduct" @select-all="handleSelectProduct" ref="tableDom">
             <el-table-column type="selection" label="" width="50" />
@@ -270,12 +405,10 @@ import FileUpload from "@/components/FileUpload/index";
 import { computed, defineComponent, ref } from "vue";
 import { getToken } from "@/utils/auth";
 
-const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传文件服务器地址
-const headers = ref({ Authorization: "Bearer " + getToken() });
-const uploadData = ref({});
+
 const loading = ref(false);
 const loadingOne = ref(false);
-
+const dtlModalType = ref(false);
 const submitLoading = ref(false);
 const sourceList = ref({
   data: [],
@@ -286,6 +419,148 @@ const sourceList = ref({
     status: "",
   },
 });
+
+const openDtlUpdata = (index) => {
+  boxIndex.value = index;
+  dtlModalType.value = true;
+};
+
+let boxFormData = ref({
+  packQuantity: null,
+  netWeight: null,
+  roughWeight: null,
+  boxLong: null,
+  boxWide: null,
+  boxHigh: null,
+  packDetailGoodsList: [],
+  packDetailProductList: [],
+  bomVolume: null,
+  //生成唯一id
+  id: Math.random().toString(36).substr(2),
+});
+
+const openDtlModal = () => {
+  boxFormData.value = {
+    packQuantity: null,
+    netWeight: null,
+    roughWeight: null,
+    boxLong: null,
+    boxWide: null,
+    boxHigh: null,
+    packDetailGoodsList: [],
+    packDetailProductList: [],
+    bomVolume: null,
+    //生成唯一id
+    id: Math.random().toString(36).substr(2),
+  };
+  boxIndex.value = formData.data.packDetailList.length - 1;
+  dtlModalType.value = true;
+
+};
+
+const dtlModalClose = () => {
+  dtlModalType.value = false;
+  //如果关闭删除本条数据
+  formData.data.packDetailList.splice(boxIndex.value, 1);
+  boxIndex.value = 0
+  console.log(formData.data.packDetailList)
+};
+
+const boxIndex = ref(0);
+
+const packDetailProductListPush = (index) => {
+  boxFormData.value.packDetailProductList.push({
+    contractId: null,
+    productName: null,
+    contractProductId: null,
+    quantity: null,
+    productId: null,
+    productModel: null,
+    remark:null,
+  });
+};
+
+const submitBox = () => {
+  formDom.value.validate((vaild) => {
+    if (vaild) {
+      if(boxFormData.value.packDetailProductList.length == 0){
+        ElMessage.error("请添加产品");
+        return;
+      }
+      for (let i = 0; i < boxFormData.value.packDetailProductList.length; i++) {
+        const item = boxFormData.value.packDetailProductList[j];
+        if (item.quantity == null) {
+          ElMessage.error("请填写装箱数量");
+          return;
+        }
+        if (item.productId == null) {
+            ElMessage.error("请填写选择产品");
+            return;
+        }
+      }
+      dtlModalType.value = false;
+      formData.data.packDetailList[boxIndex.value] = {
+        packQuantity: boxFormData.value.packQuantity,
+        netWeight: boxFormData.value.netWeight,
+        roughWeight: boxFormData.value.roughWeight,
+        boxLong: boxFormData.value.boxLong,
+        boxWide: boxFormData.value.boxWide,
+        boxHigh: boxFormData.value.boxHigh,
+        packDetailGoodsList: boxFormData.value.packDetailGoodsList,
+        packDetailProductList: boxFormData.value.packDetailProductList,
+        bomVolume: boxFormData.value.bomVolume,
+        id: boxFormData.value.id,
+      };
+    }
+  })
+  console.log(formData.data.packDetailList[boxIndex.value])
+  
+};
+
+const dtlformData = reactive({
+  data: {
+    customerId:null,
+    contractIds:null,
+    packQuantity:null,
+    netWeight:null,
+    roughWeight:null,
+    boxLong:null,
+    boxWide:null,
+    boxHigh:null,
+    remark:null,
+    packDetailGoodsList:[],
+    packDetailProductList:[],
+    bomVolume:null,
+  },
+});
+
+const selectProduct = (val,index) => {
+  let msg  = {...formData.data.contractProductData.find((item) => item.mathId == val)}
+  //根据val 禁用相应的下拉数据
+  console.log(msg,index)
+  boxFormData.value.packDetailProductList[index] = {
+    productId: msg.productId,
+    productName: msg.productName,
+    productSpec: msg.productSpec,
+    contractCode: msg.contractCode,
+    contractProductId: msg.contractProductId,
+    cpQuantity: msg.cpQuantity,
+    waitQuantity: msg.waitQuantity,
+    quantity: null,
+    mathId: msg.mathId,
+  }
+  formData.data.contractProductData.forEach((item) => {
+    item.disabled = false
+    boxFormData.value.packDetailProductList.forEach((item1) => {
+      if(item.mathId == item1.mathId){
+        item.disabled = true
+      }
+    })
+  });
+  console.log(formData.data.packDetailList)
+};
+
+
 let dialogVisible = ref(false);
 let dialogVisibleOne = ref(false);
 
@@ -303,8 +578,9 @@ let rules = ref({
   quantityOne: [{ required: true, message: "请输入数量", trigger: "blur" }],
   unit: [{ required: true, message: "请输入单位", trigger: "blur" }],
   remark: [{ required: true, message: "请输入货物描述", trigger: "blur" }],
-
+  productId: [{ required: true, message: "请选择产品", trigger: "change" }],
   contractId: [{ required: true, message: "请选择主合同", trigger: "change" }],
+  mathId: [{ required: true, message: "请选择产品", trigger: "change" }],
 });
 
 const { proxy } = getCurrentInstance();
@@ -582,7 +858,7 @@ const openModalOne = () => {
     dialogVisibleOne.value = true;
   });
 };
-
+const packDetailProductListDom = ref(null);
 const submitForm = () => {
   formDom.value.validate((vaild) => {
     if (vaild) {
@@ -794,6 +1070,8 @@ const handleChangeContract = (val) => {
       ...x,
       waitQuantity: (Number(x.cpQuantity) - Number(x.sumPackQuantity)).toFixed(2),
       quantity: null,
+      mathId: Math.random().toString(36).substr(2),
+      disabled: false,
     }));
     handleChangePackQuantity();
   });
@@ -842,6 +1120,45 @@ const clickDelete = (index) => {
   border: none;
 }
 
+.box-icon-warp{
+  width: 100%;
+  display: flex;
+  .add-box{
+    width: 33.33%;
+    height: 100px;
+    border-radius: 50%;
+    display: flex;
+    justify-content: center;
+    i{
+      display: block;
+      width: 100px;
+      height: 100px;
+      border:1px solid #dcdcdc;
+      text-align: center;
+      line-height: 100px;
+      cursor: pointer;
+    }
+  }
+  .box-content{
+    width: 33.33%;
+    height: 100px;
+    border-radius: 50%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    .box-icon{
+      i{
+        font-size: 60px;
+      }
+      color: #f5a623;
+    }
+    .box-text{
+      font-size: 20px;
+      color: #f5a623;
+    }
+  }
+}
+
 .box {
   padding: 15px;
   background: #fde6c8;