yaowanxin
8 小时以前 00ca5a7d2c93420dc8696b3b3574885ad0bf3ff8
添加入库数量输入和合格状态选择功能,实现采购异常记录的添加和更新接口
已添加2个文件
468 ■■■■■ 文件已修改
src/api/procurementManagement/transferManagement.js 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/transferManagement/index.vue 434 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/transferManagement.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢
export function getPurchaseOrders(query) {
  return request({
    url: "/purchase/ledger/listPage",
    method: "get",
    params: query,
  });
}
//
export function confirmReceipt(query) {
    return request({
      url: "",
      method: "post",
      data: query,
    });
}
// å¢žæ·»é‡‡è´­å¼‚常记录
export function addPurchaseException(query) {
    return request({
      url: "/procurementExceptionRecord/add",
      method: "post",
      data: query,
    });
}
// ä¿®æ”¹é‡‡è´­å¼‚常记录
export function updatePurchaseException(query) {
    return request({
        url: "/procurementExceptionRecord/update",
        method: "post",
        data: query,
    });
}
src/views/procurementManagement/transferManagement/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,434 @@
<template>
  <div class="app-container">
    <!-- æœç´¢è¿‡æ»¤åŒº -->
    <el-form :model="searchForm" :inline="true">
      <el-form-item label="采购合同号">
        <el-input v-model="searchForm.purchaseContractNumber" placeholder="请输入" />
      </el-form-item>
      <el-form-item label="供应商">
        <el-input v-model="searchForm.supplierName" placeholder="请输入" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="resetSearch">重置</el-button>
      </el-form-item>
    </el-form>
    <!-- è¡¨æ ¼å±•示区 -->
    <el-table :data="orderList" border v-loading="loading" height="calc(100vh - 12em)">
      <!-- æ·»åŠ åºå·åˆ— -->
      <el-table-column align="center" label="序号" type="index" width="60" />
      <el-table-column prop="purchaseContractNumber" label="采购合同号" show-overflow-tooltip />
      <el-table-column prop="supplierName" label="供应商" show-overflow-tooltip />
      <el-table-column label="付款状态">
        <template #default="scope">
          <el-tag
            :type="getPaymentStatusType(scope.row.paymentStatus)"
            size="small"
          >
            {{ getPaymentStatusText(scope.row.paymentStatus) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="收货状态">
        <template #default="scope">
          <el-tag
            :type="getReceiptStatusType(scope.row.receiptStatus)"
            size="small"
          >
            {{ getReceiptStatusText(scope.row.receiptStatus) }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="receivedQuantity" label="已收货数量"/>
      <el-table-column prop="unreceivedQuantity" label="未收货数量"/>
      <el-table-column label="操作" width="200"  fixed="right" align="center">
        <template #default="scope">
          <el-button
            type="primary"
            size="small"
            @click="confirmReceipter(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"
    />
    <!-- ç¡®è®¤æ”¶è´§å¯¹è¯æ¡† -->
    <el-dialog v-model="receiptDialogVisible" title="确认收货" width="70%">
      <el-form :model="receiptForm" label-width="120px" ref="formRef">
        <el-form-item label="采购合同号">
          <el-input v-model="receiptForm.purchaseContractNumber" disabled />
        </el-form-item>
        <el-form-item label="异常原因">
          <el-input
            v-model="receiptForm.exceptionReason"
            type="textarea"
            placeholder="请输入异常原因(不合格时填写)"
          />
        </el-form-item>
        <el-table
            :data="productList"
            border
            v-loading="loadingProducts"
            @selection-change="handleSelectionChange"
        >
          <el-table-column align="center" type="selection" width="55" />
          <el-table-column
              align="center"
              label="序号"
              type="index"
              width="60"
          />
          <el-table-column label="产品大类" prop="productCategory" />
          <el-table-column label="规格型号" prop="specificationModel" />
          <el-table-column label="单位" prop="unit" width="70" />
          <el-table-column label="供应商" prop="supplierName" width="100" />
          <el-table-column label="采购数量" prop="quantity" width="100" />
          <el-table-column label="待入库数量" prop="quantity0" width="100" />
          <el-table-column label="本次入库数量" prop="quantityStock" width="150">
            <template #default="scope">
              <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="scope.row.quantityStock" />
            </template>
          </el-table-column>
<!--          åˆæ ¼æˆ–不合格-->
          <el-table-column label="是否合格" width="100">
            <template #default="scope">
              <el-select v-model="scope.row.isQualified" placeholder="请选择">
                <el-option label="合格" value="1" />
                <el-option label="不合格" value="2" />
              </el-select>
            </template>
          </el-table-column>
          <el-table-column label="税率(%)" prop="taxRate" width="120" />
          <el-table-column
              label="含税单价(元)"
              prop="taxInclusiveUnitPrice"
              :formatter="formattedNumber"
              width="150"
          />
          <el-table-column
              label="含税总价(元)"
              prop="taxInclusiveTotalPrice"
              :formatter="formattedNumber"
              width="150"
          />
          <el-table-column
              label="不含税总价(元)"
              prop="taxExclusiveTotalPrice"
              :formatter="formattedNumber"
              width="150"
          />
        </el-table>
      </el-form>
      <template #footer>
        <el-button @click="receiptDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="submitReceipt">确认收货</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import {ref, onMounted, getCurrentInstance} from 'vue'
import {
  getPurchaseOrders,
  confirmReceipt,
  addPurchaseException
} from '@/api/procurementManagement/transferManagement.js'
import {selectProductRecordListByPuechaserId, addSutockIn, updateStockIn} from "@/api/inventoryManagement/stockIn.js";
import useUserStore from "@/store/modules/user.js";
const userStore = useUserStore()
const { proxy } = getCurrentInstance()
// æ•°æ®å®šä¹‰
const orderList = ref([])
const receiptDialogVisible = ref(false)
const receiptForm = ref({
  purchaseContractNumber: '',
  exceptionReason: '',
  purchaseLedgerId: '',
})
const operationType = ref('')// æ“ä½œç±»åž‹: 'add' æˆ– 'edit'
const productList = ref([]);// äº§å“åˆ—表数据
const loadingProducts = ref(false);// äº§å“åŠ è½½çŠ¶æ€
const selectedRows = ref([]);
const loading = ref(false);
const total = ref(0); // æ€»è®°å½•æ•°
// æœç´¢è¡¨å•
const searchForm = ref({
  purchaseContractNumber: '',
  supplierName: '',
})
// åˆ†é¡µæ•°æ®
const page = reactive({
  current: 1,
  size: 100, // æ¯é¡µæ˜¾ç¤ºæ•°é‡
});
// åˆ†é¡µå˜åŒ–处理
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getReceiptOrders(); // é‡æ–°èŽ·å–æ•°æ®
};
// èŽ·å–è®¢å•åˆ—è¡¨
const getReceiptOrders = async () => {
  loading.value = true;
  try {
    const response = await getPurchaseOrders({
      ...searchForm.value,
      current: page.current,
      size: page.size
    });
    // ä½¿ç”¨ Promise.all å¤„理所有异步请求
    const processedOrders = await Promise.all(response.data.records.map(async (order) => {
      // ç­‰å¾…异步获取产品记录
      const productRes = await selectProductRecordListByPuechaserId({
        purchaseContractNumber: order.purchaseContractNumber
      });
      // ç¡®ä¿ productRes.data å­˜åœ¨
      if (productRes && productRes.data && Array.isArray(productRes.data)) {
        // è®¡ç®—总数量
        order.totalQuantity = productRes.data.reduce((acc, cur) => acc + (cur.quantity || 0), 0);
        // è®¡ç®—未收货数量
        order.unreceivedQuantity = productRes.data.reduce((acc, cur) => acc + (cur.quantity0 || 0), 0);
        // è®¡ç®—已收货数量
        order.receivedQuantity = order.totalQuantity - order.unreceivedQuantity;
        // ä¿®æ­£çŠ¶æ€åˆ¤æ–­é€»è¾‘ï¼ˆä½¿ç”¨ === è¿›è¡Œæ¯”较)
        if (order.unreceivedQuantity === 0) {
          order.paymentStatus = 1;
          order.receiptStatus = 1;
        } else if (order.receivedQuantity === 0) {
          order.paymentStatus = 3;
          order.receiptStatus = 3;
        } else {
          order.paymentStatus = 2;
          order.receiptStatus = 2;
        }
      } else {
        // å¦‚果没有产品记录,设置默认值
        order.totalQuantity = 0;
        order.unreceivedQuantity = 0;
        order.receivedQuantity = 0;
        order.receiptStatus = 3; // æœªå…¥åº“
      }
      return order;
    }));
    // æ­£ç¡®èµ‹å€¼ç»™ orderList
    orderList.value = processedOrders;
    total.value = response.data.total;
  } catch (error) {
    console.error('获取订单列表失败:', error);
    proxy.$modal.msgError('获取订单列表失败');
  } finally {
    loading.value = false;
  }
}
// ä»˜æ¬¾çŠ¶æ€æ˜¾ç¤ºå¤„ç†
const getPaymentStatusText = (status) => {
  const statusMap = { '1': '已付款', '2': '部分付款', '3': '未付款' }
  return statusMap[status] || '未知'
}
const getPaymentStatusType = (status) => {
  const typeMap = { '1': 'success', '2': 'warning', '3': 'danger' }
  return typeMap[status] || 'info'
}
// æ”¶è´§çŠ¶æ€å¤„ç†
const getReceiptStatusText = (status) => {
  const statusMap = { '1': '收货完成', '2': '部分入库', '3': '未入库' }
  return statusMap[status] || '未知'
}
const getReceiptStatusType = (status) => {
  const typeMap = { '1': 'success', '2': 'warning', '3': 'info' }
  return typeMap[status] || 'info'
}
const exceedsAddLimit = (product) => {
  const stock = Number(product?.quantityStock ?? 0);
  const waiting = Number(product?.quantity0 ?? 0);
  if (!Number.isFinite(stock) || !Number.isFinite(waiting)) {
    return false;
  }
  return stock > waiting;
};
const exceedsEditLimit = (product) => {
  const stock = Number(product?.quantityStock ?? 0);
  const waiting = Number(product?.quantity0 ?? 0);
  const original = Number(product?.originalQuantityStock ?? 0);
  if (!Number.isFinite(stock) || !Number.isFinite(waiting) || !Number.isFinite(original)) {
    return false;
  }
  return stock > waiting + original;
};
const updatePro = async () => {
  const target = selectedRows.value[0];
  const stock = Number(target?.quantityStock ?? 0);
  if (!Number.isFinite(stock) || stock <= 0) {
    proxy.$modal.msgWarning('请填写有效的入库数量');
    return;
  }
  if (exceedsEditLimit(target)) {
    proxy.$modal.msgError('本次入库数量不能超过原入库数量与待入库数量之和');
    return;
  }
  const stockInData = {
    id: selectedRows.value[0].recordId,
    quantityStock: Number(selectedRows.value[0].quantityStock),// ä½¿ç”¨æ–°æ ¼å¼åŒ–函数
  };
  await updateStockIn(stockInData)
  proxy.$modal.msgSuccess('修改入库成功')
  closeDia()
  getReceiptOrders() // åˆ·æ–°åˆ—表
}
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  // è¿‡æ»¤æŽ‰å­æ•°æ®
  selectedRows.value = selection.filter(item => item.id);
}
// æ‰“开弹框-确认收货
const confirmReceipter = (row) => {
  receiptForm.value = {
    purchaseContractNumber: row.purchaseContractNumber,
    purchaseLedgerId: row.id,
    exceptionReason: ''
  }
  selectedRows.value = []
  receiptDialogVisible.value = true
  fetchProductsByContract()
}
const fetchProductsByContract = async () =>
{
  try {
    loadingProducts.value = true
    // æ ¹æ®åˆåŒæŸ¥è¯¢äº§å“è®°å½•
    const productRes = await selectProductRecordListByPuechaserId({
      purchaseContractNumber: receiptForm.value.purchaseContractNumber
    });
    console.log('productRes:', productRes)
    operationType.value = 'add'
    if (!productRes.data || productRes.data.length === 0) {
      proxy.$modal.msgWarning('该合同下没有产品记录')
      productList.value = [];
      return
    }
    // å¤„理产品数据,添加本次入库数量字段
    productList.value = productRes.data.map(item => ({
      ...item,
      quantityStock: 0,
      originalQuantityStock: Number(item.quantityStock ?? item.inboundQuantity ?? 0),
    }))
    selectedRows.value = productList.value
  } catch (error) {
    console.error('查询产品记录失败:', error)
    proxy.$modal.msgError('查询产品记录失败')
    productList.value = [];
  } finally {
    loadingProducts.value = false
  }
}
// æäº¤æ”¶è´§ç¡®è®¤
const submitReceipt = async () => {
  if(operationType.value !== 'add'){
    await updatePro()
    return
  }
  try {
    await proxy.$refs.formRef.validate()
    // éªŒè¯å…¥åº“数量
    const invalidProducts = selectedRows.value.filter((product) => {
      const stock = Number(product?.quantityStock ?? 0);
      if (!Number.isFinite(stock) || stock <= 0) {
        return true;
      }
      return exceedsAddLimit(product);
    })
    if (invalidProducts.length > 0) {
      proxy.$modal.msgError('本次入库数量需大于0,且不能超过待入库数量')
      return
    }
    loading.value = true
    // å‡†å¤‡æäº¤æ•°æ® - ä¿®æ”¹ä¸ºåŽç«¯éœ€è¦çš„æ ¼å¼
    const stockInData = {
      // å…¥åº“单基本信息
      ...receiptForm.value,
      nickName: userStore.nickName,
      details: selectedRows.value.map(product => ({
        id: product.id,
        inboundQuantity: Number(product.quantityStock)
      })),
    };
    //如果产品合格
    if(productList.value.every(product => product.isQualified === '1')){
      await addSutockIn(stockInData)
      proxy.$modal.msgSuccess('确认收货,入库成功')
    }else{
       stockInData.details.forEach(item => {
        const ProcurementExceptionRecord = {
          purchaseContractNumber: receiptForm.value.purchaseContractNumber,
          purchaseLedgerId: receiptForm.value.purchaseLedgerId,
          exceptionNum: item.inboundQuantity,
          exceptionReason: receiptForm.value.exceptionReason
        }
        addPurchaseException(ProcurementExceptionRecord).then(response => {
          proxy.$modal.msgSuccess('产品不合格,采购异常记录成功')
        })
      })
    }
    closeDia()
    getReceiptOrders() // åˆ·æ–°åˆ—表
  } catch (error) {
    console.error('提交失败:', error)
    if (!error.errors) {
      proxy.$modal.msgError('操作失败,请重试')
    }
  } finally {
    loading.value = false
  }
}
// å…³é—­å¼¹æ¡†
const closeDia = () => {
  proxy.$refs.formRef.resetFields()
  receiptDialogVisible.value = false
}
// æœç´¢å’Œé‡ç½®
const search = () => {
  getReceiptOrders()
}
const resetSearch = () => {
  searchForm.value = {
    purchaseContractNumber: '',
    supplierName: '',
  }
  getReceiptOrders()
}
onMounted(() => {
  getReceiptOrders()
})
</script>