huminmin
9 小时以前 f02160e1f583f063dc01499634311ef981cfe894
src/views/inventoryManagement/stockManagement/index.vue
@@ -1,659 +1,33 @@
<template>
  <div class="app-container">
    <el-tabs v-model="activeTab"
             @tab-change="handleTabChange">
      <el-tab-pane label="成品库存"
                   name="production">
        <div class="search_form">
          <div>
            <span class="search_title ml10">入库日期:</span>
            <el-date-picker v-model="searchForm.timeStr"
                            type="date"
                            placeholder="请选择日期"
                            value-format="YYYY-MM-DD"
                            format="YYYY-MM-DD"
                            clearable
                            @change="handleQuery" />
            <span class="search_title ml10">产品大类:</span>
            <el-input v-model="searchForm.productCategory"
                      style="width: 240px"
                      placeholder="请输入"
                      clearable />
            <el-button type="primary"
                       @click="handleQuery"
                       style="margin-left: 10px">搜索</el-button>
          </div>
          <div>
            <el-button @click="handleOut">导出</el-button>
            <!--            <el-button type="danger" plain @click="handleDelete">删除</el-button>-->
          </div>
        </div>
        <div class="table_list">
          <el-table :data="tableData"
                    border
                    v-loading="tableLoading"
                    @selection-change="handleSelectionChange"
                    :expand-row-keys="expandedRowKeys"
                    :row-key="row => row.id"
                    show-summary
                    style="width: 100%"
                    :row-class-name="tableRowClassName"
                    :summary-method="summarizeMainTable"
                    height="calc(100vh - 18.5em)">
            <el-table-column align="center"
                             type="selection"
                             width="55" />
            <el-table-column align="center"
                             label="序号"
                             type="index"
                             width="60" />
            <el-table-column label="入库日期"
                             prop="createTime"
                             width="120">
              <template #default="scope">
                {{ parseTime(scope.row.createTime, '{y}-{m}-{d}') || '-' }}
              </template>
            </el-table-column>
            <el-table-column label="产品名称"
                             prop="productName"
                             width="180"
                             show-overflow-tooltip />
            <el-table-column label="产品规格"
                             prop="model"
                             show-overflow-tooltip />
            <el-table-column label="单位"
                             prop="unit"
                             width="80"
                             show-overflow-tooltip />
            <el-table-column label="已出库数量"
                             prop="outboundNum"
                             show-overflow-tooltip />
            <el-table-column label="剩余库存"
                             prop="stockQuantity"
                             show-overflow-tooltip />
            <!-- <el-table-column fixed="right" label="操作" min-width="60" align="center">
              <template #default="scope">
                <el-button link type="primary" size="small" @click="openForm('edit', scope.row);">编辑</el-button>
              </template>
            </el-table-column> -->
          </el-table>
          <pagination v-show="total > 0"
                      :total="total"
                      layout="total, sizes, prev, pager, next, jumper"
                      :page="page.current"
                      :limit="page.size"
                      @pagination="paginationChange" />
        </div>
      </el-tab-pane>
      <el-tab-pane label="原料库存"
                   name="purchase">
        <div class="search_form">
          <div>
            <span class="search_title ml10">入库日期:</span>
            <el-date-picker v-model="searchForm.timeStr"
                            type="date"
                            placeholder="请选择日期"
                            value-format="YYYY-MM-DD"
                            format="YYYY-MM-DD"
                            clearable
                            @change="handleQuery" />
            <span class="search_title ml10">产品大类:</span>
            <el-input v-model="searchForm.productCategory"
                      style="width: 240px"
                      placeholder="请输入"
                      clearable />
            <el-button type="primary"
                       @click="handleQuery"
                       style="margin-left: 10px">搜索</el-button>
          </div>
          <div>
            <el-button @click="handleOut">导出</el-button>
            <el-button type="danger"
                       plain
                       @click="handleFrozen">冻结</el-button>
            <el-button type="success"
                       plain
                       @click="handleThaw">解冻</el-button>
            <!--           <el-button type="danger" plain @click="handleDelete">删除</el-button>-->
          </div>
        </div>
        <div class="table_list">
          <el-table :data="tableData"
                    border
                    v-loading="tableLoading"
                    @selection-change="handleSelectionChange"
                    :expand-row-keys="expandedRowKeys"
                    :row-key="row => row.id"
                    show-summary
                    style="width: 100%"
                    :row-class-name="tableRowClassName"
                    :summary-method="summarizeMainTable"
                    height="calc(100vh - 18.5em)">
            <el-table-column align="center"
                             type="selection"
                             width="55" />
            <el-table-column align="center"
                             label="序号"
                             type="index"
                             width="60" />
            <el-table-column label="入库日期"
                             prop="createTime"
                             width="120"
                             show-overflow-tooltip>
              <template #default="scope">
                {{ parseTime(scope.row.createTime, '{y}-{m}-{d}') || '-' }}
              </template>
            </el-table-column>
            <el-table-column label="采购合同号"
                             prop="purchaseContractNumber"
                             width="180"
                             show-overflow-tooltip />
            <el-table-column label="产品大类"
                             prop="productCategory"
                             show-overflow-tooltip />
            <el-table-column label="规格型号"
                             prop="specificationModel"
                             show-overflow-tooltip />
            <el-table-column label="单位"
                             prop="unit"
                             width="80"
                             show-overflow-tooltip />
            <el-table-column label="已出库数量"
                             prop="totalInboundNum"
                             show-overflow-tooltip />
            <el-table-column label="剩余库存"
                             prop="inboundNum0"
                             show-overflow-tooltip />
            <el-table-column label="含税单价(元)"
                             prop="taxInclusiveUnitPrice"
                             width="150"></el-table-column>
            <el-table-column label="含税总价(元)"
                             prop="taxInclusiveTotalPrice"
                             width="150"></el-table-column>
            <el-table-column label="状态"
                             align="center"
                             prop="isFrozen"
                             width="100">
              <template #default="scope">
                <el-tag :type="scope.row.isFrozen ? 'danger' : 'success'">
                  {{ scope.row.isFrozen ? '已冻结' : '正常' }}
                </el-tag>
              </template>
            </el-table-column>
          </el-table>
          <pagination v-show="total > 0"
                      :total="total"
                      layout="total, sizes, prev, pager, next, jumper"
                      :page="page.current"
                      :limit="page.size"
                      @pagination="paginationChange" />
        </div>
    <el-tabs v-model="activeTab" @tab-change="handleTabChange">
      <el-tab-pane v-for="tab in tabs"
                   :label="tab.label"
                   :name="tab.name"
                   :key="tab.name">
        <component :is="tab.name === 'qualified' ? QualifiedRecord : UnqualifiedRecord" />
      </el-tab-pane>
    </el-tabs>
    <!-- 成品库存弹框 -->
    <FormDiaProduction v-model:dialogFormVisible="productionDialogVisible"
                       :operationType="operationType"
                       :formData="form"
                       @submit="submitForm"
                       @close="closeDia" />
    <!-- 原料库存弹框 -->
    <FormDiaPurchase v-model:dialogFormVisible="purchaseDialogVisible"
                     :operationType="operationType"
                     :formData="form"
                     @submit="submitForm"
                     @close="closeDia" />
  </div>
</template>
<script setup>
  import pagination from "@/components/PIMTable/Pagination.vue";
  import { ref, reactive, toRefs, onMounted, getCurrentInstance } from "vue";
  import { ElMessageBox } from "element-plus";
  import useUserStore from "@/store/modules/user";
  import { userListNoPageByTenantId } from "@/api/system/user.js";
  import { productTreeList, modelList } from "@/api/basicData/product.js";
  import {
    getStockManagePage,
    getStockManagePageByProduction,
    delStockManage, getStockManageProduction,
    frozenQuality,
    thawQuality,
  } from "@/api/inventoryManagement/stockManage.js";
  import {
    updateManagement,
    updateManagementByCustom,
    updateStockIn,
  } from "@/api/inventoryManagement/stockIn.js";
import QualifiedRecord from "@/views/inventoryManagement/stockManagement/Qualified.vue";
import UnqualifiedRecord from "@/views/inventoryManagement/stockManagement/Unqualified.vue";
  // 导入两个独立的弹框组件
  import FormDiaProduction from "./components/FormDiaProduction.vue";
  import FormDiaPurchase from "./components/FormDiaPurchase.vue";
  const userStore = useUserStore();
  const { proxy } = getCurrentInstance();
  const tableData = ref([]);
  const productData = ref([]);
  const selectedRows = ref([]);
  const userList = ref([]);
  const productList = ref([]);
  const productModelList = ref([]);
  // const customerOption = ref([])
  const tableLoading = ref(false);
  const page = reactive({
    current: 1,
    size: 100,
  });
  const total = ref(0);
  const fileList = ref([]);
  const loading = ref(false);
  // 用户信息表单弹框数据
  const operationType = ref("");
  const activeTab = ref("production");
  // 弹框显示状态
  const productionDialogVisible = ref(false);
  const purchaseDialogVisible = ref(false);
  const data = reactive({
    searchForm: {
      // supplierName: '',
      productCategory: "",
      customerName: "",
      timeStr: "",
    },
    form: {
      supplierId: null,
      // supplierName: '',
      productId: null,
      productName: "",
      userId: userStore.userId,
      nickName: "",
      productModelId: null,
      model: "",
      unit: "",
      productrecordId: null,
      unitPrice: "", // 添加成品库存的单价字段
      taxInclusiveUnitPrice: "",
      taxInclusiveTotalPrice: "",
      taxRate: "",
      taxExclusiveTotalPrice: "",
      inboundTime: "",
      inboundBatch: "",
      stockQuantity: "",
      boundTime: "",
      warnNum: "", // 新增最低库存字段
      salesLedgerProductId: null,
    },
    rules: {
      // supplierName: [{ required: true, message: '请输入供应商名称', trigger: 'blur' }],
      productCategory: [
        { required: true, message: "请选择产品大类", trigger: "change" },
      ],
      specificationModel: [
        { required: true, message: "请输入规格型号", trigger: "blur" },
      ],
      unit: [{ required: true, message: "请输入单位", trigger: "blur" }],
      stockQuantity: [
        { required: true, message: "请输入出库数量", trigger: "blur" },
      ],
      unitPrice: [{ required: true, message: "请输入单价", trigger: "blur" }], // 添加成品库存单价的验证规则
      taxInclusiveUnitPrice: [
        { required: true, message: "请输入含税单价", trigger: "blur" },
      ],
      taxInclusiveTotalPrice: [
        { required: true, message: "请输入含税总价", trigger: "blur" },
      ],
      taxRate: [{ required: true, message: "请输入税率", trigger: "blur" }],
      taxExclusiveTotalPrice: [
        { required: true, message: "请输入不含税总价", trigger: "blur" },
      ],
      boundTime: [
        { required: true, message: "请选择库存时间", trigger: "change" },
      ],
      inboundTime: [
        { required: true, message: "请选择入库时间", trigger: "change" },
      ],
      inboundPerson: [
        { required: true, message: "请选择出库人", trigger: "change" },
      ],
      warnNum: [{ required: true, message: "请输入最低库存", trigger: "blur" }],
    },
  });
  const { searchForm, form, rules } = toRefs(data);
  // 查询列表
  /** 搜索按钮操作 */
  const handleQuery = () => {
    page.current = 1;
    getList();
  };
  const paginationChange = obj => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  };
  const buildQueryParams = () => {
    const params = {
      ...page,
      timeStr: searchForm.value.timeStr,
    };
    params.productCategory = searchForm.value.productCategory;
    if (activeTab.value === "production") {
      params.customerName = searchForm.value.customerName;
    } else {
      // params.supplierName = searchForm.value.supplierName
    }
    return params;
  };
  const getList = () => {
    tableLoading.value = true;
    const params = buildQueryParams();
    const apiCall =
      activeTab.value === "production"
        ? getStockManageProduction(params)
        : getStockManagePage(params);
    apiCall
      .then(res => {
        tableLoading.value = false;
        tableData.value = res.data.records;
        // 为表格数据自动计算总价
        // tableData.value = tableData.value.map(item => {
        //   // 计算剩余库存
        //   const stockQuantity = parseFloat(item.inboundNum) || 0;
        //   const outboundQuantity = parseFloat(item.totalInboundNum) || 0;
        //   const remainingStock = Math.max(stockQuantity - outboundQuantity, 0);
        //
        //   // 根据标签页类型计算总价
        //   if (activeTab.value === "production") {
        //     // 成品库存:总价 = 单价 × 剩余库存
        //     const unitPrice = parseFloat(item.unitPrice) || 0;
        //     item.totalPrice = (unitPrice * remainingStock).toFixed(2);
        //   } else if (activeTab.value === "purchase") {
        //     // 原料库存:含税总价 = 含税单价 × 剩余库存
        //     const taxInclusiveUnitPrice =
        //       parseFloat(item.taxInclusiveUnitPrice) || 0;
        //     item.taxInclusiveTotalPrice = (
        //       taxInclusiveUnitPrice * remainingStock
        //     ).toFixed(2);
        //   }
        //
        //   return item;
        // });
        total.value = res.data.total;
        // 数据加载完成后检查库存
        // checkStockAndCreatePurchase();
      })
      .catch(() => {
        tableLoading.value = false;
      });
  };
  // 切换 tab
  const handleTabChange = () => {
    page.current = 1;
    // searchForm.value.supplierName = ''
    searchForm.value.customerName = "";
    searchForm.value.timeStr = "";
    selectedRows.value = [];
    searchForm.value.productCategory = "";
    getList();
  };
  // 表格选择数据
  const handleSelectionChange = selection => {
    // 过滤掉子数据
    selectedRows.value = selection.filter(item => item.id);
    console.log("selection", selectedRows.value);
  };
  const expandedRowKeys = ref([]);
  // 主表合计方法
  const summarizeMainTable = param => {
    return proxy.summarizeTable(param, [
      "contractAmount",
      "taxInclusiveTotalPrice",
      "taxExclusiveTotalPrice",
    ]);
  };
  // 表格行类名
  const tableRowClassName = ({ row }) => {
    const stock = Number(row?.inboundNum0 ?? 0);
    const warn = Number(row?.warnNum ?? 0);
    if (!Number.isFinite(stock) || !Number.isFinite(warn)) {
      return "";
    }
    return stock < warn ? "row-low-stock" : "";
  };
  // 打开弹框
  const openForm = async (type, row) => {
    operationType.value = type;
    form.value = {};
    productData.value = [];
    let userLists = await userListNoPageByTenantId();
    userList.value = userLists.data;
    if (type === "edit") {
      form.value = { ...row };
      productTreeList().then(res => {
        productList.value = res;
        productList.value.forEach(i => {
          if (i.label === row.productCategory) {
            modelList({ id: i.id }).then(res => {
              productModelList.value = res;
            });
          }
        });
      });
    }
    form.value.entryDate = getCurrentDate(); // 设置默认录入日期为当前日期
    // 根据当前标签页显示对应的弹框
    if (activeTab.value === "production") {
      productionDialogVisible.value = true;
    } else if (activeTab.value === "purchase") {
      purchaseDialogVisible.value = true;
    }
  };
  // 提交表单
  const submitForm = submittedData => {
    console.log("子组件提交的数据:", submittedData);
    // 使用子组件提交的数据,而不是父组件的form对象
    const submitData = { ...submittedData };
    // 根据当前标签页移除对应的总价字段
    if (activeTab.value === "production") {
      // 成品库存:移除总价字段
      delete submitData.totalPrice;
    } else if (activeTab.value === "purchase") {
      // 原料库存:移除含税总价字段
      delete submitData.taxInclusiveTotalPrice;
    }
    // 移除其他可能的总价字段
    delete submitData.taxExclusiveTotalPrice;
    console.log("提交给后端的数据(已移除总价字段):", submitData);
    // 根据当前标签页调用不同的提交接口
    let apiCall;
    if (activeTab.value === "production") {
      // 成品库存使用 updateManagement 接口
      apiCall = updateManagement(submitData);
    } else {
      // 原料库存使用 updateManagementByCustom 接口
      apiCall = updateManagementByCustom(submitData);
    }
    apiCall
      .then(res => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
        getList();
        // 提交后检查库存并尝试创建请购单
        // checkStockAndCreatePurchase();
      })
      .catch(error => {
        console.error("提交失败:", error);
        proxy.$modal.msgError("提交失败,请重试");
      });
  };
  // 检查库存并创建请购单
  // const checkStockAndCreatePurchase = async () => {
  //   const stockList = tableData.value;
  //   // handList()
  //   for (const item of stockList) {
  //     if (item.inboundNum0 < item.warnNum) {
  //       try {
  //             const stockInData = {
  //                id: item.id,
  //                quantityStock: item.warnNum + item.totalInboundNum,// 使用新格式化函数
  //             };
  //             loading.value = true
  //             await updateStockIn(stockInData)
  //             proxy.$modal.msgSuccess(`产品 ${item.productCategory} 修改入库成功`)
  //             loading.value = false
  //       } catch (error) {
  //         proxy.$modal.msgError(`产品 ${item.productCategory} 生成请购单失败,请手动处理`);
  //
  //       }
  //     }
  //   }
  // };
  // 关闭弹框
  const closeDia = () => {
    proxy.resetForm("formRef");
    productionDialogVisible.value = false;
    purchaseDialogVisible.value = false;
  };
  // 导出
  const handleOut = () => {
    ElMessageBox.confirm("是否确认导出?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        const exportParams = buildQueryParams();
        // 根据不同的 tab 类型调用不同的导出接口
        let exportUrl = "/stockin/exportCopy";
        if (activeTab.value === "production") {
          exportUrl = "/stockin/exportCopyOne";
        }
        proxy.download(exportUrl, exportParams, "库存信息.xlsx");
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
  // 冻结
  const handleFrozen = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
      ids = selectedRows.value.map(item => item.id);
    } else {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    ElMessageBox.confirm("选中的内容将被标记为不合格产品并冻结,是否确认?", "警告", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        frozenQuality(ids).then(res => {
          proxy.$modal.msgSuccess("操作成功");
          getList();
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
  // 解冻
  const handleThaw = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
      ids = selectedRows.value.map(item => item.id);
    } else {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    ElMessageBox.confirm("选中的内容将被解冻,是否确认?", "提示", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "success",
    })
      .then(() => {
        thawQuality(ids).then(res => {
          proxy.$modal.msgSuccess("操作成功");
          getList();
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
  // 删除
  const handleDelete = () => {
    let ids = [];
    if (selectedRows.value.length > 0) {
      ids = selectedRows.value.map(item => item.id);
    } else {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        delStockManage({ ids: ids }).then(res => {
          proxy.$modal.msgSuccess("删除成功");
          getList();
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
  // 获取当前日期并格式化为 YYYY-MM-DD
  function getCurrentDate() {
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0"); // 月份从0开始
    const day = String(today.getDate()).padStart(2, "0");
    return `${year}-${month}-${day}`;
const activeTab = ref('qualified')
const tabs = ref([
  {
    label: '合格库存',
    name: 'qualified'
  },
  {
    label: '不合格库存',
    name: 'unqualified'
  }
  onMounted(() => {
    getList();
    // checkStockAndCreatePurchase();
    // 每小时检查一次库存
    // const intervalId = setInterval(checkStockAndCreatePurchase, 60 * 60 * 1000);
])
    // onUnmounted(() => {
    //   // 组件卸载时清除定时器
    //   clearInterval(intervalId);
    // });
  });
const handleTabChange = (tabName) => {
  activeTab.value = tabName;
}
</script>
<style scoped lang="scss">
  :deep(.row-low-stock td) {
    background-color: #fde2e2;
    color: #c45656;
  }
  :deep(.row-low-stock:hover > td) {
    background-color: #fcd4d4;
  }
</style>