You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1472 lines
56 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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>