|
|
|
|
|
<template>
|
|
|
|
|
|
<div class="p-2">
|
|
|
|
|
|
<!-- 审批按钮组件 -->
|
|
|
|
|
|
<el-card shadow="never" style="margin-top: 0">
|
|
|
|
|
|
<approvalButton
|
|
|
|
|
|
@submitForm="submitForm"
|
|
|
|
|
|
@approvalVerifyOpen="approvalVerifyOpen"
|
|
|
|
|
|
@handleApprovalRecord="handleApprovalRecord"
|
|
|
|
|
|
:buttonLoading="buttonLoading"
|
|
|
|
|
|
:id="form.shippingBillId"
|
|
|
|
|
|
:status="form.flowStatus"
|
|
|
|
|
|
:pageType="routeParams.type"
|
|
|
|
|
|
:mode="false"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 全部到货确认区块:查看/审批页都展示,仅到货确认节点允许申请人录入 -->
|
|
|
|
|
|
<el-card
|
|
|
|
|
|
v-if="showArrivalConfirmSection"
|
|
|
|
|
|
shadow="never"
|
|
|
|
|
|
style="margin-top: 10px"
|
|
|
|
|
|
:style="isArrivalConfirmApprover ? 'border: 1px solid #e6a23c' : ''"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div style="text-align: left; font-weight: bold; font-size: 16px" :style="isArrivalConfirmApprover ? 'color: #e6a23c' : ''">
|
|
|
|
|
|
<el-icon v-if="isArrivalConfirmApprover" style="margin-right: 6px"><Warning /></el-icon>全部到货确认
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<el-form v-if="isArrivalConfirmApprover" :model="arrivalConfirmForm" label-width="120px" ref="arrivalConfirmFormRef">
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="全部到货标识" prop="isAllReceiving" :rules="[{ required: true, message: '请选择全部到货标识', trigger: 'change' }]">
|
|
|
|
|
|
<el-radio-group v-model="arrivalConfirmForm.isAllReceiving">
|
|
|
|
|
|
<el-radio-button v-for="dict in is_all_receiving" :key="dict.value" :label="dict.value">
|
|
|
|
|
|
{{ dict.label }}
|
|
|
|
|
|
</el-radio-button>
|
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-form-item
|
|
|
|
|
|
label="收货单附件"
|
|
|
|
|
|
prop="arrivalReceiptOssId"
|
|
|
|
|
|
:rules="[{ required: arrivalConfirmForm.isAllReceiving === '0', message: '全部到货必须上传收货单', trigger: 'change' }]"
|
|
|
|
|
|
>
|
|
|
|
|
|
<fileUpload v-model="arrivalConfirmForm.arrivalReceiptOssId" :limit="5" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
<el-form v-else :model="form" label-width="120px" disabled>
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="全部到货标识">
|
|
|
|
|
|
<dict-tag :options="is_all_receiving" :value="form.isAllReceiving" />
|
|
|
|
|
|
<span v-if="!form.isAllReceiving">-</span>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="到货确认时间">
|
|
|
|
|
|
<span>{{ proxy?.parseTime(form.arrivalConfirmTime, '{y}-{m}-{d} {h}:{i}:{s}') || '-' }}</span>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="到货确认人">
|
|
|
|
|
|
<span>{{ form.arrivalConfirmByName || '-' }}</span>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-form-item label="收货单附件">
|
|
|
|
|
|
<fileUpload v-model="form.arrivalReceiptOssId" :limit="5" disabled />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 基本信息区域 -->
|
|
|
|
|
|
<el-card shadow="never" style="margin-top: 0">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div style="text-align: left; font-weight: bold; font-size: 18px">基本信息</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<el-form ref="shippingBillFormRef" :model="form" :loading="buttonLoading" :disabled="mainFormDisabled" :rules="rules" label-width="120px">
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="发货单号" prop="shippingCode">
|
|
|
|
|
|
<el-input v-model="form.shippingCode" placeholder="由系统自动生成" disabled />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="发货类型" prop="shippingType">
|
|
|
|
|
|
<el-select v-model="form.shippingType" placeholder="请选择发货类型" style="width: 100%" @change="handleShippingTypeChange">
|
|
|
|
|
|
<el-option v-for="dict in shipping_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="发货方式" prop="shippingMode">
|
|
|
|
|
|
<el-select v-model="form.shippingMode" placeholder="请选择发货方式" style="width: 100%">
|
|
|
|
|
|
<el-option v-for="dict in shipping_mode" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="绑定类型" prop="bindType">
|
|
|
|
|
|
<el-radio-group v-model="form.bindType">
|
|
|
|
|
|
<el-radio-button label="1">按项目</el-radio-button>
|
|
|
|
|
|
<el-radio-button label="2">按合同</el-radio-button>
|
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12" v-if="form.bindType === '1'">
|
|
|
|
|
|
<el-form-item label="项目" prop="projectId">
|
|
|
|
|
|
<el-input v-model="selectedProjectName" placeholder="请选择项目" readonly>
|
|
|
|
|
|
<template #suffix>
|
|
|
|
|
|
<el-icon style="cursor: pointer" @click="openProjectSelect">
|
|
|
|
|
|
<Search />
|
|
|
|
|
|
</el-icon>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12" v-if="form.bindType === '1'">
|
|
|
|
|
|
<el-form-item label="项目编号" prop="projectCode">
|
|
|
|
|
|
<el-input v-model="form.projectCode" disabled placeholder="自动带入" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12" v-if="form.bindType === '2'">
|
|
|
|
|
|
<el-form-item label="合同" prop="contractId">
|
|
|
|
|
|
<el-input v-model="selectedContractName" placeholder="请选择合同" readonly>
|
|
|
|
|
|
<template #suffix>
|
|
|
|
|
|
<el-icon style="cursor: pointer" @click="openContractSelect">
|
|
|
|
|
|
<Search />
|
|
|
|
|
|
</el-icon>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-input>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12" v-if="form.bindType === '2'">
|
|
|
|
|
|
<el-form-item label="合同编号" prop="contractCode">
|
|
|
|
|
|
<el-input v-model="form.contractCode" disabled placeholder="自动带入" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12" v-if="form.bindType === '2' && selectedSapOrderCode">
|
|
|
|
|
|
<el-form-item label="SAP订单号">
|
|
|
|
|
|
<el-input v-model="selectedSapOrderCode" disabled placeholder="自动带入" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="客户" prop="customerId">
|
|
|
|
|
|
<el-select v-model="form.customerId" placeholder="请选择客户" filterable style="width: 100%" @change="handleCustomerChange">
|
|
|
|
|
|
<el-option v-for="item in customerList" :key="item.customerId" :label="item.customerName" :value="item.customerId" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="客户联系人" prop="customerContactId">
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
v-model="form.customerContactId"
|
|
|
|
|
|
placeholder="请先选择客户"
|
|
|
|
|
|
filterable
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
@change="handleCustomerContactChange"
|
|
|
|
|
|
:disabled="!form.customerId"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-option v-for="item in customerContactList" :key="item.contactId" :label="item.contactName" :value="item.contactId" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="收货联系人" prop="receiverName">
|
|
|
|
|
|
<el-input v-model="form.receiverName" placeholder="请输入收货联系人" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="收货联系电话" prop="receiverPhone">
|
|
|
|
|
|
<el-input v-model="form.receiverPhone" placeholder="请输入收货联系电话" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="收货地址" prop="shippingAddress">
|
|
|
|
|
|
<el-input v-model="form.shippingAddress" placeholder="请输入收货地址" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="发货日期" prop="shippingTime">
|
|
|
|
|
|
<el-date-picker
|
|
|
|
|
|
v-model="form.shippingTime"
|
|
|
|
|
|
type="date"
|
|
|
|
|
|
format="YYYY-MM-DD"
|
|
|
|
|
|
value-format="YYYY-MM-DD"
|
|
|
|
|
|
placeholder="请选择发货日期"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="计划到货时间" prop="planArrivalTime">
|
|
|
|
|
|
<el-date-picker
|
|
|
|
|
|
v-model="form.planArrivalTime"
|
|
|
|
|
|
type="date"
|
|
|
|
|
|
value-format="YYYY-MM-DD"
|
|
|
|
|
|
placeholder="请选择计划到货时间"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12" v-if="form.shippingMode === '2'">
|
|
|
|
|
|
<el-form-item label="供应商" prop="supplierId">
|
|
|
|
|
|
<el-select v-model="form.supplierId" placeholder="请选择供应商" filterable style="width: 100%" @change="handleSupplierChange">
|
|
|
|
|
|
<el-option v-for="item in supplierList" :key="item.supplierId" :label="item.supplierName" :value="item.supplierId" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12" v-if="form.shippingMode === '1'">
|
|
|
|
|
|
<el-form-item label="发货仓库" prop="warehouseId">
|
|
|
|
|
|
<el-select v-model="form.warehouseId" placeholder="请选择仓库" filterable style="width: 100%" @change="handleWarehouseChange">
|
|
|
|
|
|
<el-option v-for="item in warehouseList" :key="item.warehouseId" :label="item.warehouseName" :value="item.warehouseId" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-form-item label="发货说明" prop="directions">
|
|
|
|
|
|
<el-input v-model="form.directions" type="textarea" placeholder="请输入发货说明" :rows="2" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
<el-form v-if="isArrivalConfirmApprover" ref="copyManagerFormRef" :model="form" label-width="120px">
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="抄送人员" prop="tManagerId" :rules="copyManagerRules">
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
v-model="form.tManagerId"
|
|
|
|
|
|
placeholder="请选择抄送人员"
|
|
|
|
|
|
:disabled="copyManagerDisabled"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
filterable
|
|
|
|
|
|
multiple
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 物流信息区域 -->
|
|
|
|
|
|
<!-- <el-card shadow="never" style="margin-top: 0">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<div style="text-align: left; font-weight: bold; font-size: 18px">物流信息</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<el-form :model="form" :disabled="routeParams.type === 'view' || routeParams.type === 'approval'" label-width="120px">
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="物流公司" prop="logisticsCompany">
|
|
|
|
|
|
<el-input v-model="form.logisticsCompany" placeholder="请输入物流公司" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="运单号" prop="trackingNo">
|
|
|
|
|
|
<el-input v-model="form.trackingNo" placeholder="请输入运单号" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
|
<el-form-item label="物流联系电话" prop="logisticsPhone">
|
|
|
|
|
|
<el-input v-model="form.logisticsPhone" placeholder="请输入物流联系电话" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</el-card>-->
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 发货明细区域 -->
|
|
|
|
|
|
<el-card shadow="never" style="margin-top: 0">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<el-row :gutter="10" type="flex" align="middle">
|
|
|
|
|
|
<el-col :span="1.5">
|
|
|
|
|
|
<span style="font-weight: bold; font-size: 18px">发货明细</span>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="3">
|
|
|
|
|
|
<!-- 物料来源切换 -->
|
|
|
|
|
|
<el-radio-group v-model="materialSourceType" size="small" @change="handleMaterialSourceChange" :disabled="detailFormDisabled">
|
|
|
|
|
|
<el-radio-button value="1">ERP物料</el-radio-button>
|
|
|
|
|
|
<el-radio-button value="2">WMS物料</el-radio-button>
|
|
|
|
|
|
</el-radio-group>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
<el-col :span="1.5">
|
|
|
|
|
|
<el-button type="primary" icon="Plus" @click="handleAddDetail" v-if="canEditDetailFields"> 新增物料 </el-button>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table :data="detailsList" v-loading="buttonLoading" border>
|
|
|
|
|
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
|
|
|
<el-table-column label="物料编码" align="center" prop="materialCode" min-width="120" />
|
|
|
|
|
|
<el-table-column label="物料名称" align="center" prop="materialName" min-width="150" />
|
|
|
|
|
|
<el-table-column label="规格型号" align="center" prop="materielSpecification" min-width="120" />
|
|
|
|
|
|
<el-table-column label="批次号" align="center" prop="batchNumber" width="120" />
|
|
|
|
|
|
<el-table-column label="发货数量" align="center" prop="shippingStockAmount" width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.shippingStockAmount"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:precision="2"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
@change="calculateTotalPrice(scope.row)"
|
|
|
|
|
|
:disabled="detailFormDisabled"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="单位" align="center" prop="unitName" width="80" />
|
|
|
|
|
|
<el-table-column label="单价" align="center" prop="unitPrice" width="100">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input-number
|
|
|
|
|
|
v-model="scope.row.unitPrice"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:precision="2"
|
|
|
|
|
|
:controls="false"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
:disabled="detailFormDisabled"
|
|
|
|
|
|
@change="calculateTotalPrice(scope.row)"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="总价" align="center" prop="totalPrice" width="100">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ scope.row.totalPrice ? Number(scope.row.totalPrice).toFixed(2) : '0.00' }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="备注" align="center" prop="remark" min-width="120">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-input v-model="scope.row.remark" placeholder="备注" size="small" :disabled="detailFormDisabled" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="操作" align="center" width="80" fixed="right" v-if="canEditDetailFields">
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
<el-button link type="danger" icon="Delete" @click="handleDeleteDetail(scope.$index)">删除</el-button>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ERP物料选择对话框 -->
|
|
|
|
|
|
<MaterialSelect ref="materialSelectRef" :multiple="true" @confirm-call-back="erpMaterialSelectCallBack" />
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 项目选择对话框 -->
|
|
|
|
|
|
<ProjectSelect ref="projectSelectRef" :multiple="false" @confirm-call-back="projectInfoSelectCallBack" />
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 合同选择对话框 -->
|
|
|
|
|
|
<el-dialog title="选择合同" v-model="contractDialog.visible" width="900px" append-to-body>
|
|
|
|
|
|
<el-form :model="contractQueryParams" :inline="true" label-width="100px">
|
|
|
|
|
|
<el-form-item label="合同编号">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="contractQueryParams.contractCode"
|
|
|
|
|
|
placeholder="请输入合同编号"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
style="width: 200px"
|
|
|
|
|
|
@keyup.enter="getContractList"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="合同名称">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="contractQueryParams.contractName"
|
|
|
|
|
|
placeholder="请输入合同名称"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
style="width: 200px"
|
|
|
|
|
|
@keyup.enter="getContractList"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item>
|
|
|
|
|
|
<el-button type="primary" icon="Search" @click="getContractList">搜索</el-button>
|
|
|
|
|
|
<el-button icon="Refresh" @click="resetContractQuery">重置</el-button>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
ref="contractTableRef"
|
|
|
|
|
|
v-loading="contractLoading"
|
|
|
|
|
|
:data="contractList"
|
|
|
|
|
|
border
|
|
|
|
|
|
@row-click="handleContractRowClick"
|
|
|
|
|
|
@select="handleContractSelect"
|
|
|
|
|
|
max-height="400"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column type="selection" width="55" align="center" />
|
|
|
|
|
|
<el-table-column label="合同编号" align="center" prop="contractCode" min-width="120" />
|
|
|
|
|
|
<el-table-column label="合同名称" align="center" prop="contractName" min-width="180" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column label="合同总价" align="center" prop="totalPrice" min-width="120" />
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
<pagination
|
|
|
|
|
|
v-show="contractTotal > 0"
|
|
|
|
|
|
:total="contractTotal"
|
|
|
|
|
|
v-model:page="contractQueryParams.pageNum"
|
|
|
|
|
|
v-model:limit="contractQueryParams.pageSize"
|
|
|
|
|
|
@pagination="getContractList"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<div class="dialog-footer">
|
|
|
|
|
|
<el-button type="primary" @click="submitContractSelect">确 定</el-button>
|
|
|
|
|
|
<el-button @click="contractDialog.visible = false">取 消</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- WMS物料选择对话框 -->
|
|
|
|
|
|
<el-dialog title="选择WMS物料" v-model="wmsMaterialDialog.visible" width="900px" append-to-body>
|
|
|
|
|
|
<el-form :model="wmsMaterialQueryParams" :inline="true" label-width="100px">
|
|
|
|
|
|
<el-form-item label="物料编码">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="wmsMaterialQueryParams.productCode"
|
|
|
|
|
|
placeholder="请输入物料编码"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
style="width: 180px"
|
|
|
|
|
|
@keyup.enter="getWmsMaterialList"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="物料名称">
|
|
|
|
|
|
<el-input
|
|
|
|
|
|
v-model="wmsMaterialQueryParams.productName"
|
|
|
|
|
|
placeholder="请输入物料名称"
|
|
|
|
|
|
clearable
|
|
|
|
|
|
style="width: 180px"
|
|
|
|
|
|
@keyup.enter="getWmsMaterialList"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="仓库">
|
|
|
|
|
|
<el-select v-model="wmsMaterialQueryParams.warehouseId" placeholder="请选择仓库" clearable style="width: 180px">
|
|
|
|
|
|
<el-option v-for="item in warehouseList" :key="item.warehouseId" :label="item.warehouseName" :value="item.warehouseId" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item>
|
|
|
|
|
|
<el-button type="primary" icon="Search" @click="getWmsMaterialList">搜索</el-button>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
ref="wmsMaterialTableRef"
|
|
|
|
|
|
:data="wmsMaterialList"
|
|
|
|
|
|
v-loading="wmsMaterialLoading"
|
|
|
|
|
|
border
|
|
|
|
|
|
@selection-change="handleWmsMaterialSelectionChange"
|
|
|
|
|
|
>
|
|
|
|
|
|
<el-table-column type="selection" width="55" align="center" />
|
|
|
|
|
|
<el-table-column label="物料编码" align="center" prop="productCode" min-width="120" />
|
|
|
|
|
|
<el-table-column label="物料名称" align="center" prop="productName" min-width="150" />
|
|
|
|
|
|
<el-table-column label="规格型号" align="center" prop="productSpe" min-width="120" />
|
|
|
|
|
|
<el-table-column label="仓库" align="center" prop="warehouseName" width="100" />
|
|
|
|
|
|
<el-table-column label="批次号" align="center" prop="batchNumber" width="120" />
|
|
|
|
|
|
<el-table-column label="库存数量" align="center" prop="inventoryAmount" width="100" />
|
|
|
|
|
|
<el-table-column label="单价" align="center" prop="unitPrice" width="80" />
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
<pagination
|
|
|
|
|
|
v-show="wmsMaterialTotal > 0"
|
|
|
|
|
|
:total="wmsMaterialTotal"
|
|
|
|
|
|
v-model:page="wmsMaterialQueryParams.pageNum"
|
|
|
|
|
|
v-model:limit="wmsMaterialQueryParams.pageSize"
|
|
|
|
|
|
@pagination="getWmsMaterialList"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<template #footer>
|
|
|
|
|
|
<div class="dialog-footer">
|
|
|
|
|
|
<el-button type="primary" @click="confirmWmsMaterialSelect">确 定</el-button>
|
|
|
|
|
|
<el-button @click="wmsMaterialDialog.visible = false">取 消</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 提交审批组件 -->
|
|
|
|
|
|
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
|
|
|
|
|
<!-- 审批记录 -->
|
|
|
|
|
|
<approvalRecord ref="approvalRecordRef" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup name="WmsShippingBillEdit" lang="ts">
|
|
|
|
|
|
import { addWmsShippingBill, getWmsShippingBill, shippingBillSubmitAndFlowStart, updateWmsShippingBill } from '@/api/wms/wmsShippingBill';
|
|
|
|
|
|
import { WmsShippingBillForm } from '@/api/wms/wmsShippingBill/types';
|
|
|
|
|
|
import { useUserStore } from '@/store/modules/user';
|
|
|
|
|
|
import { getTask } from '@/api/workflow/task';
|
|
|
|
|
|
import type { FlowTaskVO } from '@/api/workflow/task/types';
|
|
|
|
|
|
import { WmsShippingDetailsForm } from '@/api/wms/wmsShippingDetails/types';
|
|
|
|
|
|
import { listInventoryDetails } from '@/api/wms/inventoryDetails';
|
|
|
|
|
|
import { InventoryDetailsQuery, InventoryDetailsVO } from '@/api/wms/inventoryDetails/types';
|
|
|
|
|
|
import { getWmsWarehouseInfoList } from '@/api/wms/warehouseInfo';
|
|
|
|
|
|
import { getCrmCustomerInfoList } from '@/api/oa/crm/customerInfo';
|
|
|
|
|
|
import { getCrmCustomerContactList } from '@/api/oa/crm/customerContact';
|
|
|
|
|
|
import type { CustomerContactVO } from '@/api/oa/crm/customerContact/types';
|
|
|
|
|
|
import { getCrmSupplierInfoList } from '@/api/oa/crm/crmSupplierInfo';
|
|
|
|
|
|
import { listUser } from '@/api/system/user';
|
|
|
|
|
|
import type { UserQuery } from '@/api/system/user/types';
|
|
|
|
|
|
import { getContractOrder } from '@/api/oa/erp/contractOrder';
|
|
|
|
|
|
import MaterialSelect from '@/components/MaterialSelect/index.vue';
|
|
|
|
|
|
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
|
|
|
|
|
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
|
|
|
|
|
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
|
|
|
|
|
import ProjectSelect from '@/components/ProjectSelect/index.vue';
|
|
|
|
|
|
import type { ProjectInfoVO } from '@/api/oa/erp/projectInfo/types';
|
|
|
|
|
|
import { getProjectInfo } from '@/api/oa/erp/projectInfo';
|
|
|
|
|
|
import { getContractInfo, listContractInfo } from '@/api/oa/erp/contractInfo';
|
|
|
|
|
|
import type { ContractInfoQuery, ContractInfoVO } from '@/api/oa/erp/contractInfo/types';
|
|
|
|
|
|
import type { ContractOrderPurchaseMaterialVO } from '@/api/oa/erp/contractOrder/types';
|
|
|
|
|
|
import { FlowCodeEnum } from '@/enums/OAEnum';
|
|
|
|
|
|
import { Search, Warning } from '@element-plus/icons-vue';
|
|
|
|
|
|
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
const userStore = useUserStore();
|
|
|
|
|
|
|
|
|
|
|
|
// 路由参数
|
|
|
|
|
|
const routeParams = ref<Record<string, any>>({});
|
|
|
|
|
|
|
|
|
|
|
|
// 字典
|
|
|
|
|
|
const { shipping_mode, shipping_bill_status, material_source_type, shipping_type, is_all_receiving } = toRefs<any>(
|
|
|
|
|
|
proxy?.useDict('shipping_mode', 'shipping_bill_status', 'material_source_type', 'shipping_type', 'is_all_receiving')
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const buttonLoading = ref(false);
|
|
|
|
|
|
const shippingBillFormRef = ref<ElFormInstance>();
|
|
|
|
|
|
const arrivalConfirmFormRef = ref<ElFormInstance>();
|
|
|
|
|
|
const copyManagerFormRef = ref<ElFormInstance>();
|
|
|
|
|
|
|
|
|
|
|
|
type ArrivalConfirmFormModel = {
|
|
|
|
|
|
shippingBillId: string | number;
|
|
|
|
|
|
isAllReceiving: string;
|
|
|
|
|
|
arrivalReceiptOssId: string;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 到货确认表单数据
|
|
|
|
|
|
const arrivalConfirmForm = ref<ArrivalConfirmFormModel>({
|
|
|
|
|
|
shippingBillId: '',
|
|
|
|
|
|
isAllReceiving: '0',
|
|
|
|
|
|
arrivalReceiptOssId: ''
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => arrivalConfirmForm.value.isAllReceiving,
|
|
|
|
|
|
() => {
|
|
|
|
|
|
arrivalConfirmFormRef.value?.clearValidate(['arrivalReceiptOssId']);
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const currentTask = ref<FlowTaskVO | null>(null);
|
|
|
|
|
|
|
|
|
|
|
|
const isArrivalConfirmTask = computed(() => currentTask.value?.nodeCode === 'arrival-confirm');
|
|
|
|
|
|
|
|
|
|
|
|
const isCurrentTaskBusinessMatched = computed(() => {
|
|
|
|
|
|
const taskBusinessId = String(currentTask.value?.businessId || '').trim();
|
|
|
|
|
|
const shippingBillId = String(form.value.shippingBillId || '').trim();
|
|
|
|
|
|
if (!taskBusinessId) {
|
|
|
|
|
|
// 部分任务接口场景可能不回 businessId,前端不能因为缺少辅助字段把到货确认入口误隐藏
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return taskBusinessId === shippingBillId;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 是否显示到货确认区块:审批模式 + 到货确认节点 + 当前用户是申请人
|
|
|
|
|
|
const isArrivalConfirmApprover = computed(() => {
|
|
|
|
|
|
return (
|
|
|
|
|
|
routeParams.value.type === 'approval' &&
|
|
|
|
|
|
String(form.value.needArrivalConfirm || '') === '1' &&
|
|
|
|
|
|
isArrivalConfirmTask.value &&
|
|
|
|
|
|
isCurrentTaskBusinessMatched.value &&
|
|
|
|
|
|
String(userStore.userId || '') === String(form.value.createBy || '')
|
|
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const showArrivalConfirmSection = computed(() => {
|
|
|
|
|
|
const hasArrivalConfirmData =
|
|
|
|
|
|
String(form.value.needArrivalConfirm || '') === '1' ||
|
|
|
|
|
|
!!form.value.isAllReceiving ||
|
|
|
|
|
|
!!form.value.arrivalConfirmTime ||
|
|
|
|
|
|
!!form.value.arrivalConfirmByName ||
|
|
|
|
|
|
!!form.value.arrivalReceiptOssId;
|
|
|
|
|
|
if (isViewMode.value) {
|
|
|
|
|
|
return hasArrivalConfirmData;
|
|
|
|
|
|
}
|
|
|
|
|
|
return isArrivalConfirmApprover.value;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const isViewMode = computed(() => routeParams.value.type === 'view');
|
|
|
|
|
|
|
|
|
|
|
|
const isDraftFlowStatus = computed(() => {
|
|
|
|
|
|
if (!form.value.shippingBillId) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return String(form.value.flowStatus || '') === 'draft';
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const canEditBusinessFields = computed(() => {
|
|
|
|
|
|
// 基础信息与明细仅允许草稿态维护,审批中任何节点都不能通过编辑页修改这些业务字段
|
|
|
|
|
|
return !isViewMode.value && routeParams.value.type !== 'approval' && isDraftFlowStatus.value;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const mainFormDisabled = computed(() => !canEditBusinessFields.value);
|
|
|
|
|
|
|
|
|
|
|
|
const canEditDetailFields = computed(() => canEditBusinessFields.value);
|
|
|
|
|
|
|
|
|
|
|
|
const detailFormDisabled = computed(() => !canEditDetailFields.value);
|
|
|
|
|
|
|
|
|
|
|
|
const validateCopyManager = (rule: any, value: unknown, callback: (error?: Error) => void) => {
|
|
|
|
|
|
if (!isArrivalConfirmApprover.value) {
|
|
|
|
|
|
callback();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const selectedIds = toWorkflowUserIdArray(value);
|
|
|
|
|
|
if (!selectedIds || selectedIds.length === 0) {
|
|
|
|
|
|
callback(new Error('请选择抄送人员'));
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
callback();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const copyManagerRules = [{ validator: validateCopyManager, trigger: 'change' }];
|
|
|
|
|
|
|
|
|
|
|
|
const canEditCopyManager = computed(() => {
|
|
|
|
|
|
if (isViewMode.value) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 抄送人员仅在到货确认节点由申请人选择
|
|
|
|
|
|
return isArrivalConfirmApprover.value;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const copyManagerDisabled = computed(() => !canEditCopyManager.value);
|
|
|
|
|
|
|
|
|
|
|
|
// 审批相关组件引用
|
|
|
|
|
|
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
|
|
|
|
|
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
|
|
|
|
|
|
|
|
|
|
|
// 任务变量
|
|
|
|
|
|
const taskVariables = ref<Record<string, any>>({});
|
|
|
|
|
|
|
|
|
|
|
|
// 物料来源类型(1-ERP物料,2-WMS物料),新建空白单据时默认使用WMS物料
|
|
|
|
|
|
const materialSourceType = ref('2');
|
|
|
|
|
|
|
|
|
|
|
|
// 下拉数据源
|
|
|
|
|
|
const userList = ref<any[]>([]);
|
|
|
|
|
|
const customerList = ref<any[]>([]);
|
|
|
|
|
|
const supplierList = ref<any[]>([]);
|
|
|
|
|
|
const warehouseList = ref<any[]>([]);
|
|
|
|
|
|
const customerContactList = ref<CustomerContactVO[]>([]); // 客户联系人列表
|
|
|
|
|
|
|
|
|
|
|
|
// 项目选择
|
|
|
|
|
|
const selectedProjectName = ref<string>('');
|
|
|
|
|
|
const projectSelectRef = ref<InstanceType<typeof ProjectSelect>>();
|
|
|
|
|
|
|
|
|
|
|
|
// 合同选择
|
|
|
|
|
|
const selectedContractName = ref<string>('');
|
|
|
|
|
|
const selectedSapOrderCode = ref<string>(''); // SAP订单号(来自合同)
|
|
|
|
|
|
const contractTableRef = ref();
|
|
|
|
|
|
const contractDialog = reactive({ visible: false });
|
|
|
|
|
|
const contractLoading = ref(false);
|
|
|
|
|
|
const contractList = ref<ContractInfoVO[]>([]);
|
|
|
|
|
|
const contractTotal = ref(0);
|
|
|
|
|
|
const contractQueryParams = ref<ContractInfoQuery>({
|
|
|
|
|
|
pageNum: 1,
|
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
|
contractStatus: '3'
|
|
|
|
|
|
});
|
|
|
|
|
|
const selectedContract = ref<ContractInfoVO | null>(null);
|
|
|
|
|
|
|
|
|
|
|
|
// 发货明细列表
|
|
|
|
|
|
const detailsList = ref<WmsShippingDetailsForm[]>([]);
|
|
|
|
|
|
|
|
|
|
|
|
// ERP物料选择组件引用
|
|
|
|
|
|
const materialSelectRef = ref();
|
|
|
|
|
|
|
|
|
|
|
|
// WMS物料选择对话框
|
|
|
|
|
|
const wmsMaterialDialog = reactive({ visible: false });
|
|
|
|
|
|
const wmsMaterialLoading = ref(false);
|
|
|
|
|
|
const wmsMaterialList = ref<InventoryDetailsVO[]>([]);
|
|
|
|
|
|
const wmsMaterialTotal = ref(0);
|
|
|
|
|
|
const selectedWmsMaterials = ref<InventoryDetailsVO[]>([]);
|
|
|
|
|
|
const wmsMaterialQueryParams = ref<InventoryDetailsQuery>({
|
|
|
|
|
|
pageNum: 1,
|
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
|
productCode: undefined,
|
|
|
|
|
|
productName: undefined,
|
|
|
|
|
|
warehouseId: undefined
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const getTodayDateString = () => {
|
|
|
|
|
|
const date = new Date();
|
|
|
|
|
|
const year = date.getFullYear();
|
|
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
|
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
|
|
|
|
return `${year}-${month}-${day}`;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 表单初始数据
|
|
|
|
|
|
const initFormData: WmsShippingBillForm = {
|
|
|
|
|
|
shippingBillId: undefined,
|
|
|
|
|
|
shippingCode: undefined,
|
|
|
|
|
|
shippingType: undefined,
|
|
|
|
|
|
shippingMode: '1', // 默认公司仓库发货
|
|
|
|
|
|
bindType: '1',
|
|
|
|
|
|
projectId: undefined,
|
|
|
|
|
|
projectCode: undefined,
|
|
|
|
|
|
projectName: undefined,
|
|
|
|
|
|
customerId: undefined,
|
|
|
|
|
|
customerContactId: undefined,
|
|
|
|
|
|
customerName: undefined,
|
|
|
|
|
|
shippingAddress: undefined,
|
|
|
|
|
|
receiverName: undefined,
|
|
|
|
|
|
receiverPhone: undefined,
|
|
|
|
|
|
supplierId: undefined,
|
|
|
|
|
|
supplier: undefined,
|
|
|
|
|
|
contactUser: undefined,
|
|
|
|
|
|
contactNumber: undefined,
|
|
|
|
|
|
logisticsCompany: undefined,
|
|
|
|
|
|
trackingNo: undefined,
|
|
|
|
|
|
logisticsPhone: undefined,
|
|
|
|
|
|
directions: undefined,
|
|
|
|
|
|
planArrivalTime: undefined,
|
|
|
|
|
|
shippingTime: getTodayDateString(),
|
|
|
|
|
|
warehouseId: undefined,
|
|
|
|
|
|
warehouseName: undefined,
|
|
|
|
|
|
outStockBillStatus: '1', // 默认暂存
|
|
|
|
|
|
flowStatus: 'draft',
|
|
|
|
|
|
needArrivalConfirm: undefined,
|
|
|
|
|
|
isAllReceiving: undefined,
|
|
|
|
|
|
arrivalReceiptOssId: undefined,
|
|
|
|
|
|
arrivalConfirmTime: undefined,
|
|
|
|
|
|
arrivalConfirmBy: undefined,
|
|
|
|
|
|
arrivalConfirmByName: undefined,
|
|
|
|
|
|
remark: undefined,
|
|
|
|
|
|
createBy: undefined,
|
|
|
|
|
|
createTime: undefined,
|
|
|
|
|
|
detailsList: []
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const validateProjectOrContract = (rule: any, value: any, callback: any) => {
|
|
|
|
|
|
if (form.value.bindType === '1' && !form.value.projectId) {
|
|
|
|
|
|
callback(new Error('项目不能为空'));
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
callback();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const validateContractWhenBind = (rule: any, value: any, callback: any) => {
|
|
|
|
|
|
if (form.value.bindType === '2' && !form.value.contractId) {
|
|
|
|
|
|
callback(new Error('合同不能为空'));
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
callback();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const data = reactive<{ form: WmsShippingBillForm; rules: any }>({
|
|
|
|
|
|
form: { ...initFormData },
|
|
|
|
|
|
rules: {
|
|
|
|
|
|
shippingMode: [{ required: true, message: '发货方式不能为空', trigger: 'change' }],
|
|
|
|
|
|
bindType: [{ required: true, message: '绑定类型不能为空', trigger: 'change' }],
|
|
|
|
|
|
projectId: [{ validator: validateProjectOrContract, trigger: 'change' }],
|
|
|
|
|
|
contractId: [{ validator: validateContractWhenBind, trigger: 'change' }],
|
|
|
|
|
|
customerId: [{ required: true, message: '客户不能为空', trigger: 'change' }]
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const { form, rules } = toRefs(data);
|
|
|
|
|
|
|
|
|
|
|
|
const syncMaterialSourceTypeByDetails = () => {
|
|
|
|
|
|
if (!detailsList.value.length) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const hasErpMaterial = detailsList.value.some((item) => item.materialSourceType === '1');
|
|
|
|
|
|
const hasWmsMaterial = detailsList.value.some((item) => item.materialSourceType === '2');
|
|
|
|
|
|
// 项目自动生成的发货草稿物料属于 ERP 物料,页面回显后默认切到 ERP,
|
|
|
|
|
|
// 用户继续点“新增物料”时才能沿用当前草稿的物料语义,而不是误切回 WMS 选料
|
|
|
|
|
|
if (hasErpMaterial && !hasWmsMaterial) {
|
|
|
|
|
|
materialSourceType.value = '1';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!hasErpMaterial && hasWmsMaterial) {
|
|
|
|
|
|
materialSourceType.value = '2';
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toNumberOrDefault = (value: unknown, defaultValue = 0) => {
|
|
|
|
|
|
const result = Number(value);
|
|
|
|
|
|
return Number.isFinite(result) ? result : defaultValue;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const normalizeWorkflowUserIds = (value: unknown): string | undefined => {
|
|
|
|
|
|
if (Array.isArray(value)) {
|
|
|
|
|
|
const ids = value.map((item) => String(item ?? '').trim()).filter((item) => item.length > 0);
|
|
|
|
|
|
return ids.length > 0 ? ids.join(',') : undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (value === undefined || value === null) {
|
|
|
|
|
|
return undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
const text = String(value).trim();
|
|
|
|
|
|
return text.length > 0 ? text : undefined;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toWorkflowUserIdArray = (value: unknown): (string | number)[] | undefined => {
|
|
|
|
|
|
const text = normalizeWorkflowUserIds(value);
|
|
|
|
|
|
if (!text) {
|
|
|
|
|
|
return undefined;
|
|
|
|
|
|
}
|
|
|
|
|
|
return text
|
|
|
|
|
|
.split(',')
|
|
|
|
|
|
.map((id) => id.trim())
|
|
|
|
|
|
.filter((id) => id.length > 0);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const buildFlowCopyVariables = async (submitData: WmsShippingBillForm) => {
|
|
|
|
|
|
let tManagerId = normalizeWorkflowUserIds((submitData as any).tManagerId);
|
|
|
|
|
|
const bindType = submitData.bindType;
|
|
|
|
|
|
|
|
|
|
|
|
// 先使用页面已有口径(合同负责人/项目抄送人),避免每次都发起远程查询
|
|
|
|
|
|
if (!tManagerId && bindType === '2') {
|
|
|
|
|
|
tManagerId = normalizeWorkflowUserIds((submitData as any).contractManagerId);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!tManagerId && bindType === '1') {
|
|
|
|
|
|
tManagerId = normalizeWorkflowUserIds((submitData as any).peopleId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 绑定合同时优先取合同负责人作为流程抄送人,保证流程变量完整
|
|
|
|
|
|
// 统一归一为 tManagerId,流程节点只关心当前业务口径下的实际抄送人
|
|
|
|
|
|
if (bindType === '2' && !tManagerId && submitData.contractId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const contractRes = await getContractInfo(submitData.contractId);
|
|
|
|
|
|
tManagerId = normalizeWorkflowUserIds((contractRes.data as any)?.contractManagerId);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载合同负责人失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 绑定项目时兜底取项目负责人,防止流程变量缺失
|
|
|
|
|
|
if (bindType === '1' && !tManagerId && submitData.projectId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const projectRes = await getProjectInfo(submitData.projectId);
|
|
|
|
|
|
tManagerId = normalizeWorkflowUserIds((projectRes.data as any)?.peopleId);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载抄送人员失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return { tManagerId };
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const prepareTaskVariables = async () => {
|
|
|
|
|
|
if (!isArrivalConfirmApprover.value) {
|
|
|
|
|
|
taskVariables.value = {};
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
const valid = await copyManagerFormRef.value?.validate().catch(() => false);
|
|
|
|
|
|
if (!valid) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
const tManagerId = normalizeWorkflowUserIds((form.value as any).tManagerId);
|
|
|
|
|
|
if (!tManagerId) {
|
|
|
|
|
|
proxy?.$modal.msgError('请选择抄送人员');
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 抄送人员不落库,只在到货确认节点审批时作为流程变量传递
|
|
|
|
|
|
taskVariables.value = { tManagerId };
|
|
|
|
|
|
return true;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const syncCopyManagerSelection = async () => {
|
|
|
|
|
|
const current = normalizeWorkflowUserIds((form.value as any).tManagerId);
|
|
|
|
|
|
if (current) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const { tManagerId } = await buildFlowCopyVariables(form.value as WmsShippingBillForm);
|
|
|
|
|
|
if (tManagerId) {
|
|
|
|
|
|
// 编辑历史单据时回显抄送人员,保持与 orderActivate 一样“可见可改”
|
|
|
|
|
|
(form.value as any).tManagerId = toWorkflowUserIdArray(tManagerId);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const getContractList = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
contractLoading.value = true;
|
|
|
|
|
|
const res = await listContractInfo(contractQueryParams.value);
|
|
|
|
|
|
contractList.value = res.rows || [];
|
|
|
|
|
|
contractTotal.value = (res.total as number) || contractList.value.length;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('查询合同列表失败:', error);
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
contractLoading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const resetContractQuery = () => {
|
|
|
|
|
|
contractQueryParams.value.contractCode = undefined;
|
|
|
|
|
|
contractQueryParams.value.contractName = undefined;
|
|
|
|
|
|
contractQueryParams.value.pageNum = 1;
|
|
|
|
|
|
getContractList();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleContractRowClick = (row: ContractInfoVO) => {
|
|
|
|
|
|
selectedContract.value = row;
|
|
|
|
|
|
// 同步选中状态到选择框
|
|
|
|
|
|
if (contractTableRef.value) {
|
|
|
|
|
|
contractTableRef.value.clearSelection();
|
|
|
|
|
|
contractTableRef.value.toggleRowSelection(row, true);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 合同选择框点击事件 - 实现单选 */
|
|
|
|
|
|
const handleContractSelect = (selection: any[], row: any) => {
|
|
|
|
|
|
if (contractTableRef.value) {
|
|
|
|
|
|
contractTableRef.value.clearSelection();
|
|
|
|
|
|
if (selection.length > 0) {
|
|
|
|
|
|
contractTableRef.value.toggleRowSelection(row, true);
|
|
|
|
|
|
selectedContract.value = row;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
selectedContract.value = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const submitContractSelect = () => {
|
|
|
|
|
|
if (selectedContract.value) {
|
|
|
|
|
|
applyContractInfoToForm(selectedContract.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
contractDialog.visible = false;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const applyProjectInfoToForm = (project: Partial<ProjectInfoVO> & Record<string, any>) => {
|
|
|
|
|
|
form.value.bindType = '1';
|
|
|
|
|
|
form.value.projectId = project.projectId;
|
|
|
|
|
|
form.value.projectCode = project.projectCode || '';
|
|
|
|
|
|
form.value.projectName = project.projectName || '';
|
|
|
|
|
|
selectedProjectName.value = project.projectName || '';
|
|
|
|
|
|
const peopleId = normalizeWorkflowUserIds(project.peopleId);
|
|
|
|
|
|
(form.value as any).peopleId = peopleId;
|
|
|
|
|
|
(form.value as any).tManagerId = toWorkflowUserIdArray(peopleId);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const syncCustomerById = async (customerId?: string | number) => {
|
|
|
|
|
|
if (!customerId) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
form.value.customerId = customerId;
|
|
|
|
|
|
await handleCustomerChange(customerId);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const applyContractInfoToForm = (contract: ContractInfoVO) => {
|
|
|
|
|
|
form.value.bindType = '2';
|
|
|
|
|
|
form.value.contractId = contract.contractId as any;
|
|
|
|
|
|
form.value.contractCode = contract.contractCode || '';
|
|
|
|
|
|
form.value.contractName = contract.contractName || '';
|
|
|
|
|
|
selectedContractName.value = contract.contractName || '';
|
|
|
|
|
|
selectedSapOrderCode.value = (contract as any).orderContractCode || '';
|
|
|
|
|
|
const contractManagerId = normalizeWorkflowUserIds((contract as any).contractManagerId);
|
|
|
|
|
|
(form.value as any).contractManagerId = contractManagerId;
|
|
|
|
|
|
(form.value as any).tManagerId = toWorkflowUserIdArray(contractManagerId);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const mapContractMaterialToShippingDetail = (material: ContractOrderPurchaseMaterialVO | Record<string, any>): WmsShippingDetailsForm => {
|
|
|
|
|
|
const rawMaterial = material as Record<string, any>;
|
|
|
|
|
|
const shippingStockAmount = toNumberOrDefault(rawMaterial.amount ?? rawMaterial.contractAmount, 0);
|
|
|
|
|
|
const unitPrice = toNumberOrDefault(rawMaterial.includingPrice ?? rawMaterial.beforePrice, 0);
|
|
|
|
|
|
return {
|
|
|
|
|
|
shippingDetailsId: undefined,
|
|
|
|
|
|
shippingBillId: form.value.shippingBillId,
|
|
|
|
|
|
materialSourceType: '1',
|
|
|
|
|
|
erpMaterialId: rawMaterial.materialId,
|
|
|
|
|
|
wmsMaterialId: undefined,
|
|
|
|
|
|
sourceDetailType: 'CONTRACT_DETAIL',
|
|
|
|
|
|
sourceDetailId: rawMaterial.contractMaterialId,
|
|
|
|
|
|
warehouseId: undefined,
|
|
|
|
|
|
materielId: rawMaterial.materialId,
|
|
|
|
|
|
materialCode: rawMaterial.materialCode,
|
|
|
|
|
|
materialName: rawMaterial.saleMaterialName || rawMaterial.materialName || rawMaterial.productName,
|
|
|
|
|
|
materielSpecification: rawMaterial.specificationDescription,
|
|
|
|
|
|
batchNumber: undefined,
|
|
|
|
|
|
unitPrice,
|
|
|
|
|
|
shippingStockAmount,
|
|
|
|
|
|
unitId: rawMaterial.unitId,
|
|
|
|
|
|
unitName: rawMaterial.unitName,
|
|
|
|
|
|
totalPrice: unitPrice * shippingStockAmount,
|
|
|
|
|
|
remark: rawMaterial.remark
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const initShippingDetailsFromContract = (contractMaterialList: ContractOrderPurchaseMaterialVO[] | any[]) => {
|
|
|
|
|
|
detailsList.value = (contractMaterialList || []).map((item) => mapContractMaterialToShippingDetail(item));
|
|
|
|
|
|
materialSourceType.value = '1';
|
|
|
|
|
|
syncMaterialSourceTypeByDetails();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const initFromContractSource = async (contractId: string | number, projectId?: string | number) => {
|
|
|
|
|
|
const [contractRes, projectRes] = await Promise.all([
|
|
|
|
|
|
getContractInfo(contractId),
|
|
|
|
|
|
projectId
|
|
|
|
|
|
? getContractOrder(projectId).catch((error) => {
|
|
|
|
|
|
console.error('加载合同订单项目数据失败:', error);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
})
|
|
|
|
|
|
: Promise.resolve(null)
|
|
|
|
|
|
]);
|
|
|
|
|
|
const contract = contractRes.data;
|
|
|
|
|
|
applyContractInfoToForm(contract);
|
|
|
|
|
|
await syncCustomerById((contract as any).finalCustomerId ?? (contract as any).oneCustomerId);
|
|
|
|
|
|
if (projectRes?.data) {
|
|
|
|
|
|
applyProjectInfoToForm(projectRes.data as any);
|
|
|
|
|
|
form.value.bindType = '2';
|
|
|
|
|
|
}
|
|
|
|
|
|
initShippingDetailsFromContract((contract as any)?.contractMaterialList || []);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const initFromProjectSource = async (projectId: string | number) => {
|
|
|
|
|
|
const projectRes = await getProjectInfo(projectId);
|
|
|
|
|
|
const project = projectRes.data as any;
|
|
|
|
|
|
applyProjectInfoToForm(project);
|
|
|
|
|
|
await syncCustomerById(project.customerId ?? project.finalCustomerId);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const initFormByRouteSource = async () => {
|
|
|
|
|
|
if (routeParams.value.type !== 'add') {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const source = String(routeParams.value.source || '').trim();
|
|
|
|
|
|
const bindType = String(routeParams.value.bindType || '').trim();
|
|
|
|
|
|
const contractId = routeParams.value.contractId as string | number | undefined;
|
|
|
|
|
|
const projectId = routeParams.value.projectId as string | number | undefined;
|
|
|
|
|
|
if ((source === 'orderLedger' || bindType === '2') && contractId) {
|
|
|
|
|
|
await initFromContractSource(contractId, projectId);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (bindType === '1' && projectId) {
|
|
|
|
|
|
await initFromProjectSource(projectId);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 打开项目选择弹窗 */
|
|
|
|
|
|
const openProjectSelect = () => {
|
|
|
|
|
|
if (!canEditBusinessFields.value) return;
|
|
|
|
|
|
projectSelectRef.value?.open();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 打开合同选择弹窗 */
|
|
|
|
|
|
const openContractSelect = () => {
|
|
|
|
|
|
if (!canEditBusinessFields.value) return;
|
|
|
|
|
|
contractDialog.visible = true;
|
|
|
|
|
|
contractQueryParams.value.pageNum = 1;
|
|
|
|
|
|
getContractList();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 项目选择回调 */
|
|
|
|
|
|
const projectInfoSelectCallBack = (data: ProjectInfoVO[]) => {
|
|
|
|
|
|
if (data && data.length > 0) {
|
|
|
|
|
|
const project = data[0] as ProjectInfoVO & Record<string, any>;
|
|
|
|
|
|
applyProjectInfoToForm(project);
|
|
|
|
|
|
// 如果项目有关联客户,自动带入
|
|
|
|
|
|
if (project.customerId) {
|
|
|
|
|
|
form.value.customerId = project.customerId;
|
|
|
|
|
|
handleCustomerChange(project.customerId);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 客户选择变化 - 加载对应的客户联系人列表 */
|
|
|
|
|
|
const handleCustomerChange = async (customerId: any) => {
|
|
|
|
|
|
const customer = customerList.value.find((c: any) => c.customerId === customerId);
|
|
|
|
|
|
if (customer) {
|
|
|
|
|
|
form.value.customerName = customer.customerName;
|
|
|
|
|
|
// 默认使用CRM客户的详细地址作为收货地址,用户仍可在界面上手动修改
|
|
|
|
|
|
form.value.shippingAddress = customer.detailedAddress;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 清空已选联系人和相关信息
|
|
|
|
|
|
form.value.customerContactId = undefined;
|
|
|
|
|
|
form.value.receiverName = undefined;
|
|
|
|
|
|
form.value.receiverPhone = undefined;
|
|
|
|
|
|
customerContactList.value = [];
|
|
|
|
|
|
// 加载客户联系人列表
|
|
|
|
|
|
if (customerId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await getCrmCustomerContactList({ customerId });
|
|
|
|
|
|
customerContactList.value = res.data || [];
|
|
|
|
|
|
// 默认选择首要联系人(firstFlag='1'或1),若无则选择第一个
|
|
|
|
|
|
let defaultContact = customerContactList.value.find((c: CustomerContactVO) => c.firstFlag === '1' || c.firstFlag === (1 as any));
|
|
|
|
|
|
if (!defaultContact && customerContactList.value.length > 0) {
|
|
|
|
|
|
defaultContact = customerContactList.value[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
if (defaultContact) {
|
|
|
|
|
|
form.value.customerContactId = defaultContact.contactId;
|
|
|
|
|
|
// 带出收货联系人信息
|
|
|
|
|
|
form.value.receiverName = defaultContact.contactName;
|
|
|
|
|
|
form.value.receiverPhone = defaultContact.phoneNumber;
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载客户联系人列表失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 客户联系人选择变化 - 自动带出姓名和电话 */
|
|
|
|
|
|
const handleCustomerContactChange = (contactId: any) => {
|
|
|
|
|
|
const contact = customerContactList.value.find((c: CustomerContactVO) => c.contactId === contactId);
|
|
|
|
|
|
if (contact) {
|
|
|
|
|
|
form.value.receiverName = contact.contactName;
|
|
|
|
|
|
form.value.receiverPhone = contact.phoneNumber;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 供应商选择变化 */
|
|
|
|
|
|
const handleSupplierChange = (supplierId: any) => {
|
|
|
|
|
|
const supplier = supplierList.value.find((s) => s.supplierId === supplierId);
|
|
|
|
|
|
if (supplier) {
|
|
|
|
|
|
form.value.supplier = supplier.supplierName;
|
|
|
|
|
|
form.value.contactUser = supplier.contactPerson;
|
|
|
|
|
|
form.value.contactNumber = supplier.contactPhone;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 仓库选择变化 */
|
|
|
|
|
|
const handleWarehouseChange = (warehouseId: any) => {
|
|
|
|
|
|
const warehouse = warehouseList.value.find((w) => w.warehouseId === warehouseId);
|
|
|
|
|
|
if (warehouse) {
|
|
|
|
|
|
form.value.warehouseName = warehouse.warehouseName;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 发货类型变化 - 联动需到货确认标识 */
|
|
|
|
|
|
const handleShippingTypeChange = (val: any) => {
|
|
|
|
|
|
if (val === '1') {
|
|
|
|
|
|
form.value.needArrivalConfirm = '1';
|
|
|
|
|
|
} else if (val === '2' || val === '3') {
|
|
|
|
|
|
form.value.needArrivalConfirm = '0';
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 监听发货类型,确保逻辑一致性 */
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => form.value.shippingType,
|
|
|
|
|
|
(val) => {
|
|
|
|
|
|
handleShippingTypeChange(val);
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/** 物料来源切换 */
|
|
|
|
|
|
const handleMaterialSourceChange = () => {
|
|
|
|
|
|
// 切换物料来源时,可以选择是否清空已选物料
|
|
|
|
|
|
// 这里暂不清空,允许混合选择
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 新增物料 */
|
|
|
|
|
|
const handleAddDetail = () => {
|
|
|
|
|
|
if (!canEditDetailFields.value) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (materialSourceType.value === '1') {
|
|
|
|
|
|
// ERP物料选择
|
|
|
|
|
|
materialSelectRef.value?.open();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// WMS物料选择
|
|
|
|
|
|
wmsMaterialDialog.visible = true;
|
|
|
|
|
|
getWmsMaterialList();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** ERP物料选择回调 */
|
|
|
|
|
|
const erpMaterialSelectCallBack = (materials: any[]) => {
|
|
|
|
|
|
if (materials && materials.length > 0) {
|
|
|
|
|
|
materials.forEach((material) => {
|
|
|
|
|
|
// 检查是否已存在
|
|
|
|
|
|
const exists = detailsList.value.some((d) => d.materialSourceType === '1' && d.erpMaterialId === material.materialId);
|
|
|
|
|
|
if (!exists) {
|
|
|
|
|
|
detailsList.value.push({
|
|
|
|
|
|
shippingDetailsId: undefined,
|
|
|
|
|
|
shippingBillId: form.value.shippingBillId,
|
|
|
|
|
|
materialSourceType: '1', // ERP物料
|
|
|
|
|
|
erpMaterialId: material.materialId,
|
|
|
|
|
|
// 项目自动生成的 ERP 草稿明细同时带有 erpMaterialId 与 materielId,
|
|
|
|
|
|
// 手动新增 ERP 物料时保持同一口径,后续保存、回显和扩展处理才不会出现字段缺失
|
|
|
|
|
|
materielId: material.materialId,
|
|
|
|
|
|
wmsMaterialId: undefined,
|
|
|
|
|
|
materialCode: material.materialCode,
|
|
|
|
|
|
materialName: material.materialName,
|
|
|
|
|
|
materielSpecification: material.materialModel,
|
|
|
|
|
|
batchNumber: undefined,
|
|
|
|
|
|
unitPrice: material.purchasePrice || 0,
|
|
|
|
|
|
shippingStockAmount: 1,
|
|
|
|
|
|
unitId: material.unitId,
|
|
|
|
|
|
unitName: material.unitName,
|
|
|
|
|
|
totalPrice: material.purchasePrice || 0,
|
|
|
|
|
|
remark: material.remark
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
syncMaterialSourceTypeByDetails();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 获取WMS物料列表 */
|
|
|
|
|
|
const getWmsMaterialList = async () => {
|
|
|
|
|
|
wmsMaterialLoading.value = true;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await listInventoryDetails(wmsMaterialQueryParams.value);
|
|
|
|
|
|
wmsMaterialList.value = res.rows;
|
|
|
|
|
|
wmsMaterialTotal.value = res.total;
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
wmsMaterialLoading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** WMS物料选择变化 */
|
|
|
|
|
|
const handleWmsMaterialSelectionChange = (selection: InventoryDetailsVO[]) => {
|
|
|
|
|
|
selectedWmsMaterials.value = selection;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 确认WMS物料选择 */
|
|
|
|
|
|
const confirmWmsMaterialSelect = () => {
|
|
|
|
|
|
if (selectedWmsMaterials.value.length > 0) {
|
|
|
|
|
|
selectedWmsMaterials.value.forEach((material) => {
|
|
|
|
|
|
// 检查是否已存在
|
|
|
|
|
|
const exists = detailsList.value.some((d) => d.materialSourceType === '2' && d.wmsMaterialId === material.inventoryDetailsId);
|
|
|
|
|
|
if (!exists) {
|
|
|
|
|
|
detailsList.value.push({
|
|
|
|
|
|
shippingDetailsId: undefined,
|
|
|
|
|
|
shippingBillId: form.value.shippingBillId,
|
|
|
|
|
|
materialSourceType: '2', // WMS物料
|
|
|
|
|
|
erpMaterialId: undefined,
|
|
|
|
|
|
wmsMaterialId: material.inventoryDetailsId,
|
|
|
|
|
|
warehouseId: material.warehouseId,
|
|
|
|
|
|
materielId: material.materielId,
|
|
|
|
|
|
materialCode: material.productCode,
|
|
|
|
|
|
materialName: material.productName,
|
|
|
|
|
|
materielSpecification: material.productSpe,
|
|
|
|
|
|
batchNumber: material.batchNumber,
|
|
|
|
|
|
unitPrice: material.unitPrice || 0,
|
|
|
|
|
|
shippingStockAmount: 1,
|
|
|
|
|
|
unitId: material.unitId,
|
|
|
|
|
|
unitName: material.unitName,
|
|
|
|
|
|
totalPrice: material.unitPrice || 0,
|
|
|
|
|
|
remark: undefined
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
wmsMaterialDialog.visible = false;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 删除明细 */
|
|
|
|
|
|
const handleDeleteDetail = (index: number) => {
|
|
|
|
|
|
if (!canEditDetailFields.value) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
detailsList.value.splice(index, 1);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 计算总价 */
|
|
|
|
|
|
const calculateTotalPrice = (row: WmsShippingDetailsForm) => {
|
|
|
|
|
|
row.totalPrice = (row.unitPrice || 0) * (row.shippingStockAmount || 0);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 提交表单 */
|
|
|
|
|
|
const submitForm = async (status: string, mode: boolean) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await shippingBillFormRef.value?.validate();
|
|
|
|
|
|
buttonLoading.value = true;
|
|
|
|
|
|
|
|
|
|
|
|
// 将明细列表设置到表单
|
|
|
|
|
|
form.value.detailsList = detailsList.value;
|
|
|
|
|
|
|
|
|
|
|
|
// 准备提交数据
|
|
|
|
|
|
const submitData = { ...form.value };
|
|
|
|
|
|
// shippingStatus 已弃用,前端不再继续回写旧状态字段。
|
|
|
|
|
|
delete submitData.shippingStatus;
|
|
|
|
|
|
|
|
|
|
|
|
if (status !== 'draft') {
|
|
|
|
|
|
// 提交流程:设置流程编码与变量,驱动审批流
|
|
|
|
|
|
// 提交审批 - 后端发起流程模式
|
|
|
|
|
|
submitData.flowCode = FlowCodeEnum.SHIPPING_BILL_CODE;
|
|
|
|
|
|
// 流程变量
|
|
|
|
|
|
submitData.variables = {
|
|
|
|
|
|
shippingBillId: submitData.shippingBillId,
|
|
|
|
|
|
shippingCode: submitData.shippingCode,
|
|
|
|
|
|
projectName: submitData.projectName,
|
|
|
|
|
|
customerName: submitData.customerName
|
|
|
|
|
|
};
|
|
|
|
|
|
// 流程实例业务扩展字段
|
|
|
|
|
|
submitData.bizExt = {
|
|
|
|
|
|
businessTitle: '发货单审批',
|
|
|
|
|
|
businessCode: submitData.shippingCode
|
|
|
|
|
|
};
|
|
|
|
|
|
submitData.outStockBillStatus = '2'; // 审批中
|
|
|
|
|
|
submitData.flowStatus = 'waiting';
|
|
|
|
|
|
|
|
|
|
|
|
// 调用提交审批接口
|
|
|
|
|
|
const res = await shippingBillSubmitAndFlowStart(submitData);
|
|
|
|
|
|
form.value = res.data;
|
|
|
|
|
|
proxy?.$modal.msgSuccess('提交成功');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 暂存仅做草稿保存,不触发流程
|
|
|
|
|
|
// 暂存
|
|
|
|
|
|
submitData.outStockBillStatus = '1';
|
|
|
|
|
|
submitData.flowStatus = 'draft';
|
|
|
|
|
|
if (submitData.shippingBillId) {
|
|
|
|
|
|
await updateWmsShippingBill(submitData);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
await addWmsShippingBill(submitData);
|
|
|
|
|
|
}
|
|
|
|
|
|
proxy?.$modal.msgSuccess('暂存成功');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
proxy?.$tab.closePage();
|
|
|
|
|
|
router.go(-1);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('提交失败:', error);
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
buttonLoading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 加载下拉数据 */
|
|
|
|
|
|
const loadSelectOptions = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const userQuery: UserQuery = { pageNum: 1, pageSize: 9999 };
|
|
|
|
|
|
const [userRes, customerRes, supplierRes, warehouseRes] = await Promise.all([
|
|
|
|
|
|
listUser(userQuery),
|
|
|
|
|
|
getCrmCustomerInfoList(null),
|
|
|
|
|
|
getCrmSupplierInfoList(null),
|
|
|
|
|
|
getWmsWarehouseInfoList(null)
|
|
|
|
|
|
]);
|
|
|
|
|
|
userList.value = userRes.rows || [];
|
|
|
|
|
|
customerList.value = customerRes.data || [];
|
|
|
|
|
|
supplierList.value = supplierRes.data || [];
|
|
|
|
|
|
warehouseList.value = warehouseRes.data || [];
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载下拉数据失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 加载表单数据 */
|
|
|
|
|
|
const loadFormData = async (id: string | number) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await getWmsShippingBill(id);
|
|
|
|
|
|
Object.assign(form.value, res.data);
|
|
|
|
|
|
await syncCopyManagerSelection();
|
|
|
|
|
|
arrivalConfirmForm.value.shippingBillId = res.data.shippingBillId;
|
|
|
|
|
|
arrivalConfirmForm.value.isAllReceiving = res.data.isAllReceiving || '0';
|
|
|
|
|
|
arrivalConfirmForm.value.arrivalReceiptOssId = res.data.arrivalReceiptOssId || '';
|
|
|
|
|
|
selectedProjectName.value = form.value.projectName || '';
|
|
|
|
|
|
selectedContractName.value = form.value.contractName || '';
|
|
|
|
|
|
// SAP订单号(来自后端联查合同表)
|
|
|
|
|
|
selectedSapOrderCode.value = (res.data as any).orderContractCode || '';
|
|
|
|
|
|
|
|
|
|
|
|
// 加载明细列表
|
|
|
|
|
|
if (res.data.itemsVo && res.data.itemsVo.length > 0) {
|
|
|
|
|
|
detailsList.value = res.data.itemsVo.map((item: any) => ({
|
|
|
|
|
|
shippingDetailsId: item.shippingDetailsId,
|
|
|
|
|
|
shippingBillId: item.shippingBillId,
|
|
|
|
|
|
materialSourceType: item.materialSourceType,
|
|
|
|
|
|
erpMaterialId: item.erpMaterialId,
|
|
|
|
|
|
wmsMaterialId: item.wmsMaterialId,
|
|
|
|
|
|
warehouseId: item.warehouseId,
|
|
|
|
|
|
materielId: item.materielId,
|
|
|
|
|
|
materialCode: item.materialCode,
|
|
|
|
|
|
materialName: item.materialName,
|
|
|
|
|
|
materielSpecification: item.materielSpecification,
|
|
|
|
|
|
batchNumber: item.batchNumber,
|
|
|
|
|
|
unitPrice: item.unitPrice,
|
|
|
|
|
|
shippingStockAmount: item.shippingStockAmount,
|
|
|
|
|
|
unitId: item.unitId,
|
|
|
|
|
|
unitName: item.unitName,
|
|
|
|
|
|
totalPrice: item.totalPrice,
|
|
|
|
|
|
remark: item.remark
|
|
|
|
|
|
}));
|
|
|
|
|
|
syncMaterialSourceTypeByDetails();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 编辑模式下:如果有客户ID,加载客户联系人列表
|
|
|
|
|
|
if (form.value.customerId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const contactRes = await getCrmCustomerContactList({ customerId: form.value.customerId });
|
|
|
|
|
|
customerContactList.value = contactRes.data || [];
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载客户联系人列表失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载表单数据失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const loadCurrentTask = async () => {
|
|
|
|
|
|
if (routeParams.value.type !== 'approval' || !routeParams.value.taskId) {
|
|
|
|
|
|
currentTask.value = null;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await getTask(String(routeParams.value.taskId));
|
|
|
|
|
|
currentTask.value = res.data;
|
|
|
|
|
|
return !!currentTask.value;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
currentTask.value = null;
|
|
|
|
|
|
console.error('加载当前审批任务失败:', error);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 审批记录
|
|
|
|
|
|
const handleApprovalRecord = () => {
|
|
|
|
|
|
approvalRecordRef.value?.init(form.value.shippingBillId);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 提交回调
|
|
|
|
|
|
const submitCallback = async () => {
|
|
|
|
|
|
if (isArrivalConfirmApprover.value) {
|
|
|
|
|
|
const valid = await arrivalConfirmFormRef.value?.validate().catch(() => false);
|
|
|
|
|
|
if (!valid) return;
|
|
|
|
|
|
const saveData: WmsShippingBillForm = {
|
|
|
|
|
|
shippingBillId: form.value.shippingBillId,
|
|
|
|
|
|
projectId: form.value.projectId,
|
|
|
|
|
|
contractId: form.value.contractId,
|
|
|
|
|
|
isAllReceiving: arrivalConfirmForm.value.isAllReceiving,
|
|
|
|
|
|
arrivalReceiptOssId: arrivalConfirmForm.value.arrivalReceiptOssId
|
|
|
|
|
|
};
|
|
|
|
|
|
await updateWmsShippingBill(saveData);
|
|
|
|
|
|
form.value.isAllReceiving = saveData.isAllReceiving;
|
|
|
|
|
|
form.value.arrivalReceiptOssId = saveData.arrivalReceiptOssId;
|
|
|
|
|
|
}
|
|
|
|
|
|
await proxy?.$tab.closePage(route);
|
|
|
|
|
|
router.go(-1);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 审批(到货确认节点先校验,再打开审批弹窗)
|
|
|
|
|
|
const approvalVerifyOpen = async () => {
|
|
|
|
|
|
if (routeParams.value.type === 'approval' && routeParams.value.taskId) {
|
|
|
|
|
|
const taskLoaded = await loadCurrentTask();
|
|
|
|
|
|
if (!taskLoaded || !currentTask.value) {
|
|
|
|
|
|
proxy?.$modal.msgError('当前任务信息加载失败,请刷新后重试');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isArrivalConfirmApprover.value) {
|
|
|
|
|
|
// 到货确认节点:先校验到货确认表单,业务字段在 submitCallback 中统一存储
|
|
|
|
|
|
const valid = await arrivalConfirmFormRef.value?.validate().catch(() => false);
|
|
|
|
|
|
if (!valid) return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const prepared = await prepareTaskVariables();
|
|
|
|
|
|
if (!prepared) return;
|
|
|
|
|
|
await submitVerifyRef.value?.openDialog(routeParams.value.taskId);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
|
nextTick(async () => {
|
|
|
|
|
|
routeParams.value = route.query;
|
|
|
|
|
|
// 页面初始化先展示加载态,防止首屏空白
|
|
|
|
|
|
proxy?.$modal.loading('正在加载数据,请稍后...');
|
|
|
|
|
|
|
|
|
|
|
|
await loadSelectOptions();
|
|
|
|
|
|
|
|
|
|
|
|
const id = routeParams.value.id as string | number;
|
|
|
|
|
|
if (id && (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval')) {
|
|
|
|
|
|
// 编辑/查看/审批场景加载后端数据,避免覆盖草稿
|
|
|
|
|
|
await loadFormData(id);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
await initFormByRouteSource();
|
|
|
|
|
|
}
|
|
|
|
|
|
await loadCurrentTask();
|
|
|
|
|
|
|
|
|
|
|
|
proxy?.$modal.closeLoading();
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.card-title {
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|