<template>
|
<div class="app-container">
|
<div class="search_form">
|
<el-form :model="searchForm" :inline="true">
|
<el-form-item label="客户名称:">
|
<el-input v-model="searchForm.customerName" placeholder="请输入" clearable prefix-icon="Search"
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="销售合同号:">
|
<el-input v-model="searchForm.salesContractNo" placeholder="请输入" clearable prefix-icon="Search"
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="项目名称:">
|
<el-input v-model="searchForm.projectName" placeholder="请输入" clearable prefix-icon="Search"
|
@change="handleQuery" />
|
</el-form-item>
|
<el-form-item label="录入日期:">
|
<el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange"
|
placeholder="请选择" clearable @change="changeDaterange" />
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="handleQuery"> 搜索 </el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
<div class="table_list">
|
<div class="actions">
|
<div>
|
<OtherAmountMaintenanceButton />
|
<ProcessFlowMaintenanceButton />
|
</div>
|
<ProcessFlowConfigSelectDialog
|
v-model:visible="processFlowSelectDialogVisible"
|
:default-route-id="processFlowSelectDefaultRouteId"
|
:bound-route-name="processFlowSelectBoundRouteName"
|
@confirm="handleProcessFlowSelectConfirm"
|
/>
|
<el-space wrap>
|
<el-button type="primary" @click="openForm('add')">新增台账</el-button>
|
<el-button type="primary" @click="handleBulkDelivery">发货</el-button>
|
<el-button type="primary" plain @click="handleImport">导入</el-button>
|
<el-button @click="handleOut">导出</el-button>
|
|
<el-button type="danger" plain @click="handleDelete">删除</el-button>
|
|
<el-dropdown @command="handlePrintCommand">
|
<el-button type="primary" plain>
|
打印单据<el-icon class="el-icon--right">
|
<ArrowDown />
|
</el-icon>
|
</el-button>
|
<template #dropdown>
|
<el-dropdown-menu>
|
<el-dropdown-item command="finishedProcessCard">生产流程卡(成品)</el-dropdown-item>
|
<el-dropdown-item command="salesOrder">销售订单</el-dropdown-item>
|
<el-dropdown-item command="salesDeliveryNote">销售发货单</el-dropdown-item>
|
</el-dropdown-menu>
|
</template>
|
</el-dropdown>
|
<el-button type="primary" plain @click="handlePrintLabel">打印标签</el-button>
|
</el-space>
|
</div>
|
<el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
|
:expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" :row-class-name="tableRowClassName" show-summary style="width: 100%"
|
:summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 18.5em)">
|
<el-table-column align="center" type="selection" width="55" fixed="left"/>
|
<el-table-column type="expand" width="60" fixed="left">
|
<template #default="props">
|
<el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable">
|
<el-table-column align="center" label="序号" type="index"/>
|
<el-table-column label="楼层编号" prop="floorCode" min-width="100" show-overflow-tooltip />
|
<el-table-column label="产品大类" prop="productCategory" />
|
<el-table-column label="规格型号" prop="specificationModel" />
|
<el-table-column label="厚度" prop="thickness" min-width="90">
|
<template #default="scope">
|
{{ scope.row.thickness ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="宽(mm)" prop="width" min-width="80">
|
<template #default="scope">
|
{{ scope.row.width ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="高(mm)" prop="height" min-width="80">
|
<template #default="scope">
|
{{ scope.row.height ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="周长(cm)" prop="perimeter" min-width="90">
|
<template #default="scope">
|
{{ scope.row.perimeter ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="总面积(cm²)" prop="actualTotalArea" min-width="100">
|
<template #default="scope">
|
{{ scope.row.actualTotalArea ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="加工要求" prop="processRequirement" min-width="120"
|
show-overflow-tooltip />
|
<el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
|
<el-table-column label="重箱" prop="heavyBox" min-width="80">
|
<template #default="scope">
|
{{ scope.row.heavyBox ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="产品状态"
|
width="100px"
|
align="center">
|
<template #default="scope">
|
|
<el-tag v-if="scope.row.approveStatus === 1 && (!scope.row.shippingDate || !scope.row.shippingCarNumber)"
|
type="success">充足</el-tag>
|
<el-tag v-else-if="scope.row.approveStatus === 0 && (scope.row.shippingDate || scope.row.shippingCarNumber)"
|
type="success">已出库</el-tag>
|
<el-tag v-else type="danger">不足</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="发货状态" width="140" align="center">
|
<template #default="scope">
|
<el-tag :type="getShippingStatusType(scope.row)" size="small">
|
{{ getShippingStatusText(scope.row) }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="快递公司" prop="expressCompany" show-overflow-tooltip />
|
<el-table-column label="快递单号" prop="expressNumber" show-overflow-tooltip />
|
<el-table-column label="发货车牌" minWidth="100px" align="center">
|
<template #default="scope">
|
<div>
|
<el-tag type="success" v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</el-tag>
|
<el-tag v-else type="info">-</el-tag>
|
</div>
|
</template>
|
</el-table-column>
|
<el-table-column label="发货日期"
|
minWidth="100px"
|
align="center">
|
<template #default="scope">
|
<div>
|
<div v-if="scope.row.shippingDate">{{ scope.row.shippingDate }}</div>
|
<el-tag v-else
|
type="info">-</el-tag>
|
</div>
|
</template>
|
</el-table-column>
|
<el-table-column label="数量" prop="quantity" />
|
<el-table-column label="税率(%)" prop="taxRate" />
|
<el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
|
<el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
|
<el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
|
<!--操作-->
|
<!-- <el-table-column Width="60px" label="操作" align="center">
|
<template #default="scope">
|
<el-button
|
link
|
type="primary"
|
:disabled="!canShip(scope.row)"
|
@click="openDeliveryForm(scope.row)">
|
发货
|
</el-button>
|
</template>
|
</el-table-column> -->
|
</el-table>
|
</template>
|
</el-table-column>
|
<el-table-column align="center" label="序号" type="index" width="60" />
|
<el-table-column label="销售合同号" prop="salesContractNo" width="180" show-overflow-tooltip />
|
<el-table-column label="客户名称" prop="customerName" width="300" show-overflow-tooltip />
|
<el-table-column label="业务员" prop="salesman" width="100" show-overflow-tooltip />
|
<el-table-column label="项目名称" prop="projectName" width="180" show-overflow-tooltip />
|
<el-table-column label="付款方式" prop="paymentMethod" show-overflow-tooltip />
|
<el-table-column label="合同金额(元)" prop="contractAmount" width="220" show-overflow-tooltip
|
:formatter="formattedNumber" />
|
<el-table-column label="录入人" prop="entryPersonName" width="100" show-overflow-tooltip />
|
<el-table-column label="录入日期" prop="entryDate" width="120" show-overflow-tooltip />
|
<el-table-column label="签订日期" prop="executionDate" width="120" show-overflow-tooltip />
|
<el-table-column label="交付日期" prop="deliveryDate" width="120" show-overflow-tooltip />
|
<el-table-column label="备注" prop="remarks" width="200" show-overflow-tooltip />
|
<el-table-column fixed="right" label="操作" width="200" align="center">
|
<template #default="scope">
|
<el-button link type="primary" @click="openForm('edit', scope.row)" :disabled="!scope.row.isEdit">编辑</el-button>
|
<el-button link type="primary" @click="openProcessFlowSelect(scope.row)" :disabled="!scope.row.isEdit">工艺路线</el-button>
|
<el-button link type="primary" @click="downLoadFile(scope.row)">附件</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
<pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper"
|
:page="page.current" :limit="page.size" @pagination="paginationChange" />
|
</div>
|
<FormDialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'" :width="'70%'"
|
:operation-type="operationType" @close="closeDia" @confirm="submitForm" @cancel="closeDia">
|
<el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef">
|
<!-- 报价单导入入口:放在表单顶部,选择后反显客户/业务员等 -->
|
<el-row v-if="operationType === 'add'" style="margin-bottom: 10px;">
|
<el-col :span="24" style="text-align: right;">
|
<el-button type="primary" plain @click="openQuotationDialog">
|
从销售报价导入
|
</el-button>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="销售合同号:" prop="salesContractNo">
|
<el-input v-model="form.salesContractNo" placeholder="自动生成" clearable disabled />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="业务员:" prop="salesman">
|
<el-select v-model="form.salesman" placeholder="请选择" clearable :disabled="operationType === 'view'">
|
<el-option v-for="item in userList" :key="item.nickName" :label="item.nickName"
|
:value="item.nickName" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="客户名称:" prop="customerId">
|
<el-select v-model="form.customerId" placeholder="请选择" clearable :disabled="operationType === 'view'">
|
<el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id">
|
{{
|
item.customerName + "——" + item.taxpayerIdentificationNumber
|
}}
|
</el-option>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="项目名称:" prop="projectName">
|
<el-input v-model="form.projectName" placeholder="请输入" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="签订日期:" prop="executionDate">
|
<el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD" type="date" placeholder="请选择" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="付款方式">
|
<el-input v-model="form.paymentMethod" placeholder="请输入" clearable :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="录入人:" prop="entryPerson">
|
<el-select v-model="form.entryPerson"
|
filterable
|
default-first-option
|
:reserve-keyword="false" placeholder="请选择" clearable @change="changs">
|
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="录入日期:" prop="entryDate">
|
<el-date-picker style="width: 100%" v-model="form.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
|
type="date" placeholder="请选择" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="交货日期:" prop="entryDate">
|
<el-date-picker style="width: 100%" v-model="form.deliveryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD"
|
type="date" placeholder="请选择" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row>
|
<el-form-item label="产品信息:" prop="entryDate">
|
<el-button v-if="operationType !== 'view'" type="primary" @click="openProductForm('add')">添加</el-button>
|
<el-button v-if="operationType !== 'view'" plain type="danger" @click="deleteProduct" >删除</el-button>
|
</el-form-item>
|
</el-row>
|
<el-table :data="productData" border @selection-change="productSelected" show-summary
|
:summary-method="summarizeMainTable">
|
<el-table-column align="center" type="selection" width="55" v-if="operationType !== 'view'"
|
:selectable="(row) => !isProductShipped(row)" />
|
<el-table-column align="center" label="序号" type="index" width="60" />
|
<el-table-column label="产品大类" prop="productCategory" />
|
<el-table-column label="规格型号" prop="specificationModel" />
|
<el-table-column label="厚度" prop="thickness" min-width="90">
|
<template #default="scope">
|
{{ scope.row.thickness ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="宽(mm)" prop="width" min-width="80">
|
<template #default="scope">
|
{{ scope.row.width ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="高(mm)" prop="height" min-width="80">
|
<template #default="scope">
|
{{ scope.row.height ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="面积(m²)" prop="actualTotalArea" min-width="100">
|
<template #default="scope">
|
{{ scope.row.actualTotalArea ?? "" }}
|
</template>
|
</el-table-column>
|
<el-table-column label="数量" prop="quantity" />
|
<el-table-column label="税率(%)" prop="taxRate" />
|
<el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
|
<el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
|
<el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
|
<el-table-column fixed="right" label="操作" min-width="60" align="center" v-if="operationType !== 'view'">
|
<template #default="scope">
|
<el-button link type="primary" size="small"
|
:disabled="isProductShipped(scope.row)"
|
@click="openProductForm('edit', scope.row,scope.$index)">编辑</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="备注:" prop="remarks">
|
<el-input v-model="form.remarks" placeholder="请输入" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="客户备注:" prop="customerRemarks">
|
<el-input
|
v-model="form.customerRemarks"
|
placeholder="请输入"
|
clearable
|
type="textarea"
|
:rows="2"
|
:disabled="operationType === 'view'"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="附件材料:" prop="salesLedgerFiles">
|
<el-upload v-model:file-list="fileList" :action="upload.url" multiple ref="fileUpload" auto-upload
|
:headers="upload.headers" :before-upload="handleBeforeUpload" :on-error="handleUploadError"
|
:on-success="handleUploadSuccess" :on-remove="handleRemove">
|
<el-button type="primary" v-if="operationType !== 'view'">上传</el-button>
|
<template #tip v-if="operationType !== 'view'">
|
<div class="el-upload__tip">
|
文件格式支持
|
doc,docx,xls,xlsx,ppt,pptx,pdf,txt,xml,jpg,jpeg,png,gif,bmp,rar,zip,7z
|
</div>
|
</template>
|
</el-upload>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
</FormDialog>
|
|
<!-- 从报价单导入(仅审批通过) -->
|
<el-dialog
|
v-model="quotationDialogVisible"
|
title="选择审批通过的销售报价单"
|
width="80%"
|
:close-on-click-modal="false"
|
>
|
<div style="margin-bottom: 12px; display:flex; gap: 12px; align-items:center;">
|
<el-input
|
v-model="quotationSearchForm.quotationNo"
|
placeholder="请输入报价单号"
|
clearable
|
style="max-width: 260px;"
|
@change="fetchQuotationList"
|
/>
|
<el-input
|
v-model="quotationSearchForm.customer"
|
placeholder="请输入客户名称"
|
clearable
|
style="max-width: 260px;"
|
@change="fetchQuotationList"
|
/>
|
<el-button type="primary" @click="fetchQuotationList">搜索</el-button>
|
<el-button @click="resetQuotationSearch">重置</el-button>
|
</div>
|
|
<el-table
|
:data="quotationList"
|
border
|
stripe
|
v-loading="quotationLoading"
|
height="420px"
|
>
|
<el-table-column align="center" label="序号" type="index" width="60" />
|
<el-table-column prop="quotationNo" label="报价单号" width="180" show-overflow-tooltip />
|
<el-table-column prop="customer" label="客户名称" min-width="220" show-overflow-tooltip />
|
<el-table-column prop="salesperson" label="业务员" width="120" show-overflow-tooltip />
|
<el-table-column prop="quotationDate" label="报价日期" width="140" />
|
<el-table-column prop="status" label="审批状态" width="120" align="center" />
|
<el-table-column prop="totalAmount" label="报价金额(元)" width="160" align="right">
|
<template #default="scope">
|
{{ Number(scope.row.totalAmount ?? 0).toFixed(2) }}
|
</template>
|
</el-table-column>
|
<el-table-column fixed="right" label="操作" width="120" align="center">
|
<template #default="scope">
|
<el-button type="primary" link @click="applyQuotation(scope.row)">选择</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<pagination
|
v-show="quotationPage.total > 0"
|
:total="quotationPage.total"
|
layout="total, sizes, prev, pager, next, jumper"
|
:page="quotationPage.current"
|
:limit="quotationPage.size"
|
@pagination="quotationPaginationChange"
|
/>
|
|
<template #footer>
|
<el-button @click="quotationDialogVisible = false">关闭</el-button>
|
</template>
|
</el-dialog>
|
<FormDialog
|
v-model="productFormVisible"
|
:title="productOperationType === 'add' ? '新增产品' : '编辑产品'"
|
:width="'60%'"
|
:operation-type="productOperationType"
|
@close="closeProductDia"
|
@confirm="submitProduct"
|
@cancel="closeProductDia">
|
<el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef">
|
<!-- 每行三个:产品大类/规格型号/单位 -->
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="产品大类:" prop="productCategory">
|
<el-tree-select
|
v-model="productForm.productCategory"
|
placeholder="请选择"
|
clearable
|
check-strictly
|
@change="getModels"
|
:data="productOptions"
|
:render-after-expand="false"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="规格型号:" prop="productModelId">
|
<el-select
|
v-model="productForm.productModelId"
|
placeholder="请选择"
|
clearable
|
@change="getProductModel"
|
filterable
|
style="width: 100%"
|
>
|
<el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="厚度:" prop="thickness">
|
<el-input-number
|
v-model="productForm.thickness"
|
:min="0"
|
:step="0.000000000000001"
|
:precision="15"
|
style="width: 100%;"
|
placeholder="请输入"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<!-- 每行三个:税率/含税单价/数量 -->
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="税率(%):" prop="taxRate">
|
<el-select v-model="productForm.taxRate" placeholder="请选择" clearable @change="calculateFromTaxRate" style="width: 100%">
|
<el-option label="1" value="1" />
|
<el-option label="6" value="6" />
|
<el-option label="13" value="13" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice">
|
<el-input-number
|
:step="0.01"
|
:min="0"
|
v-model="productForm.taxInclusiveUnitPrice"
|
style="width: 100%"
|
:precision="2"
|
placeholder="请输入"
|
clearable
|
@change="calculateFromUnitPrice"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="数量:" prop="quantity">
|
<el-input-number
|
:step="0.1"
|
:min="0"
|
v-model="productForm.quantity"
|
placeholder="请输入"
|
clearable
|
:precision="2"
|
@change="() => { calculateFromQuantity(); recalcAreaTotals(); }"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<!-- 每行三个:含税总价/不含税总价/发票类型 -->
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice">
|
<el-input v-model="productForm.taxInclusiveTotalPrice" placeholder="请输入" clearable @change="calculateFromTotalPrice" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="不含税总价(元):" prop="taxExclusiveTotalPrice">
|
<el-input v-model="productForm.taxExclusiveTotalPrice" placeholder="请输入" clearable @change="calculateFromExclusiveTotalPrice" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="发票类型:" prop="invoiceType">
|
<el-select v-model="productForm.invoiceType" placeholder="请选择" clearable style="width: 100%">
|
<el-option label="增普票" value="增普票" />
|
<el-option label="增专票" value="增专票" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<!-- 每行三个:宽/高/实际单片面积 -->
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="宽(mm):" prop="width">
|
<el-input-number
|
v-model="productForm.width"
|
:min="0"
|
:step="1"
|
:precision="2"
|
style="width: 100%"
|
placeholder="请输入宽(mm)"
|
clearable
|
@change="recalcAreaFromWidthHeight"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="高(mm):" prop="height">
|
<el-input-number
|
v-model="productForm.height"
|
:min="0"
|
:step="1"
|
:precision="2"
|
style="width: 100%"
|
placeholder="请输入高(mm)"
|
clearable
|
@change="recalcAreaFromWidthHeight"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="周长(cm):" prop="perimeter">
|
<el-input-number
|
v-model="productForm.perimeter"
|
:min="0"
|
:step="0.01"
|
:precision="2"
|
style="width: 100%"
|
placeholder="请输入"
|
clearable
|
:disabled="true"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<!-- 每行三个:实际单片面积/实际总面积/结算单片面积 -->
|
<el-row :gutter="30">
|
<el-col :span="8">
|
<el-form-item label="实际单片面积(㎡):" prop="actualPieceArea">
|
<el-input-number
|
v-model="productForm.actualPieceArea"
|
:min="0"
|
:step="0.00001"
|
:precision="5"
|
style="width: 100%"
|
placeholder="请输入"
|
clearable
|
@change="recalcAreaTotals"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="实际总面积(㎡):" prop="actualTotalArea">
|
<el-input-number
|
v-model="productForm.actualTotalArea"
|
:min="0"
|
:step="0.00001"
|
:precision="5"
|
style="width: 100%"
|
placeholder="请输入"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="结算单片面积(㎡):" prop="settlePieceArea">
|
<el-input-number
|
v-model="productForm.settlePieceArea"
|
:min="0"
|
:step="0.00001"
|
:precision="5"
|
style="width: 100%"
|
placeholder="请输入"
|
clearable
|
@change="() => { recalcAreaTotals(); calculateFromUnitPrice(true); }"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="结算总面积(㎡):" prop="settleTotalArea">
|
<el-input-number
|
v-model="productForm.settleTotalArea"
|
:min="0"
|
:step="0.00001"
|
:precision="5"
|
style="width: 100%"
|
placeholder="请输入"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="结算总面积(㎡):" prop="settleTotalArea">
|
<el-input-number
|
v-model="productForm.settleTotalArea"
|
:min="0"
|
:step="0.00001"
|
:precision="5"
|
style="width: 100%"
|
placeholder="请输入"
|
clearable
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="8">
|
<el-form-item label="重箱:" prop="heavyBox">
|
<el-input v-model="productForm.heavyBox" placeholder="请输入" clearable @change="calculateFromExclusiveTotalPrice" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="楼层编号:" prop="floorCode">
|
<el-input v-model="productForm.floorCode" placeholder="请输入楼层编号" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<!-- 其他金额(占满一行:等同于 3 列网格的整行) -->
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="加工要求:" prop="processRequirement">
|
<el-input v-model="productForm.processRequirement" placeholder="请输入加工要求" clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="备注:" prop="remark">
|
<el-input v-model="productForm.remark" placeholder="请输入备注" clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item>
|
<template #label>
|
<div style="display:flex; align-items:center; gap: 12px; width: 100%;">
|
<div style="font-weight: 600; color: #303133;">其他金额:</div>
|
<div style="color:#909399; font-size: 13px; flex: 1;">
|
已选择 {{ productForm?.salesProductProcessList?.length || 0 }} 项
|
</div>
|
<el-button
|
v-if="operationType !== 'view'"
|
type="primary"
|
plain
|
size="small"
|
@click="startAddOtherAmount"
|
>
|
新增
|
</el-button>
|
</div>
|
</template>
|
|
<div style="display:flex; flex-direction:column; gap: 12px;">
|
<div v-if="Array.isArray(productForm?.salesProductProcessList) && productForm.salesProductProcessList.length > 0"
|
style="display:flex; flex-wrap:wrap; gap: 12px; align-items:flex-start;"
|
>
|
<div
|
v-for="(item, index) in productForm.salesProductProcessList"
|
:key="String(item.id) + '_' + index"
|
style="display:flex; gap: 10px; align-items:center; padding: 10px 12px; border: 1px solid #ebeef5; border-radius: 8px; box-sizing:border-box; min-width: 0;"
|
:style="getOtherAmountCardFlexStyle()"
|
>
|
<div style="flex: 1; min-width: 0;">
|
<el-tag type="info" style="width: 100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
|
{{ item.processName }}
|
</el-tag>
|
</div>
|
<div style="flex: 1;">
|
<el-input-number
|
v-model="item.quantity"
|
:min="0"
|
:step="1"
|
:precision="0"
|
style="width: 100%;"
|
placeholder="请输入数量"
|
:disabled="operationType === 'view'"
|
@change="calculateFromUnitPrice(true)"
|
/>
|
</div>
|
<el-button
|
v-if="operationType !== 'view'"
|
type="danger"
|
link
|
size="small"
|
@click="removeOtherAmountAt(index)"
|
>
|
删除
|
</el-button>
|
</div>
|
</div>
|
|
<div v-else style="color:#909399; font-size: 13px;">
|
暂无其他金额
|
</div>
|
</div>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
</FormDialog>
|
<!-- 其他金额:新增弹框 -->
|
<el-dialog
|
v-model="otherAmountAddDialogVisible"
|
title="新增其他金额"
|
width="520px"
|
:close-on-click-modal="false"
|
>
|
<div style="padding: 4px 0 10px;">
|
<div style="font-size: 14px; color: #606266; margin-bottom: 10px;">
|
请选择要新增的其他金额项目
|
</div>
|
<el-select
|
v-model="otherAmountAddId"
|
filterable
|
clearable
|
placeholder="请选择其他金额项目"
|
style="width: 100%;"
|
:disabled="operationType === 'view'"
|
>
|
<el-option
|
v-for="item in otherAmountSelectOptions"
|
:key="item.id"
|
:label="item.processName"
|
:value="item.id"
|
/>
|
</el-select>
|
</div>
|
<template #footer>
|
<el-button @click="cancelAddOtherAmount">取消</el-button>
|
<el-button
|
type="primary"
|
@click="confirmAddOtherAmount"
|
:disabled="operationType === 'view' || otherAmountAddId === null || otherAmountAddId === undefined || otherAmountAddId === ''"
|
>
|
确认添加
|
</el-button>
|
</template>
|
</el-dialog>
|
|
<!-- 导入弹窗 -->
|
<FormDialog
|
v-model="importUpload.open"
|
:title="importUpload.title"
|
:width="'600px'"
|
@close="importUpload.open = false"
|
@confirm="submitImportFile"
|
@cancel="importUpload.open = false"
|
>
|
<el-upload
|
ref="importUploadRef"
|
:limit="1"
|
accept=".xlsx,.xls"
|
:action="importUpload.url"
|
:headers="importUpload.headers"
|
:before-upload="importUpload.beforeUpload"
|
:on-success="importUpload.onSuccess"
|
:on-error="importUpload.onError"
|
:on-progress="importUpload.onProgress"
|
:on-change="importUpload.onChange"
|
:auto-upload="false"
|
drag
|
>
|
<i class="el-icon-upload"></i>
|
<div class="el-upload__text">
|
将文件拖到此处,或<em>点击上传</em>
|
</div>
|
<template #tip>
|
<div class="el-upload__tip">
|
仅支持 xls/xlsx,大小不超过 10MB。
|
<el-button link type="primary" @click="downloadTemplate">下载导入模板</el-button>
|
</div>
|
</template>
|
</el-upload>
|
</FormDialog>
|
<!-- 附件列表弹窗 -->
|
<FileListDialog
|
ref="fileListRef"
|
v-model="fileListDialogVisible"
|
title="附件列表"
|
/>
|
<!-- 发货弹框 -->
|
<el-dialog
|
v-model="deliveryFormVisible"
|
title="发货信息"
|
width="40%"
|
@close="closeDeliveryDia"
|
>
|
<el-form :model="deliveryForm" label-width="120px" label-position="top" :rules="deliveryRules" ref="deliveryFormRef">
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="发货类型:" prop="type">
|
<el-select
|
v-model="deliveryForm.type"
|
placeholder="请选择发货类型"
|
style="width: 100%"
|
>
|
<el-option label="货车" value="货车" />
|
<el-option label="快递" value="快递" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<!-- 审批人选择(仿协同审批里的审批人节点选择) -->
|
<el-row>
|
<el-col :span="24">
|
<el-form-item>
|
<template #label>
|
<span>审批人选择:</span>
|
<el-button type="primary" @click="addApproverNode" style="margin-left: 8px;">新增节点</el-button>
|
</template>
|
<div style="display: flex; align-items: flex-end; flex-wrap: wrap;">
|
<div
|
v-for="(node, index) in approverNodes"
|
:key="node.id"
|
style="margin-right: 20px; text-align: center; margin-bottom: 10px;"
|
>
|
<div>
|
<span>审批人</span>
|
→
|
</div>
|
<el-select
|
v-model="node.userId"
|
placeholder="选择人员"
|
filterable
|
style="width: 140px; margin-bottom: 8px;"
|
>
|
<el-option
|
v-for="user in userList"
|
:key="user.userId"
|
:label="user.nickName"
|
:value="user.userId"
|
/>
|
</el-select>
|
<div>
|
<el-button
|
type="danger"
|
@click="removeApproverNode(index)"
|
v-if="approverNodes.length > 1"
|
>删除</el-button>
|
</div>
|
</div>
|
</div>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" @click="submitDelivery">确认发货</el-button>
|
<el-button @click="closeDeliveryDia">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
|
</div>
|
</template>
|
|
<script setup>
|
import { getToken } from "@/utils/auth";
|
import pagination from "@/components/PIMTable/Pagination.vue";
|
import {onMounted, ref, getCurrentInstance} from "vue";
|
import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
|
import { ElMessageBox, ElMessage } from "element-plus";
|
import { ArrowDown } from "@element-plus/icons-vue";
|
import useUserStore from "@/store/modules/user";
|
import { userListNoPage } from "@/api/system/user.js";
|
import FileListDialog from '@/components/Dialog/FileListDialog.vue';
|
import FormDialog from '@/components/Dialog/FormDialog.vue';
|
import OtherAmountMaintenanceButton from "./components/OtherAmountMaintenanceButton.vue";
|
import ProcessFlowMaintenanceButton from "./components/ProcessFlowMaintenanceButton.vue";
|
import ProcessFlowConfigSelectDialog from "./components/ProcessFlowConfigSelectDialog.vue";
|
import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
|
import {
|
ledgerListPage,
|
productList,
|
customerList,
|
addOrUpdateSalesLedger,
|
getSalesLedgerWithProducts,
|
delLedger,
|
addOrUpdateSalesLedgerProduct,
|
delProduct,
|
delLedgerFile,
|
getProductInventory,
|
salesLedgerProductProcessList,
|
saleProcessBind,
|
getSaleProcessBindInfo,
|
getProcessCard,
|
getSalesOrder,
|
getSalesInvoices,
|
getSalesLabel,
|
} from "@/api/salesManagement/salesLedger.js";
|
import { modelList, productTreeList } from "@/api/basicData/product.js";
|
import useFormData from "@/hooks/useFormData.js";
|
import dayjs from "dayjs";
|
import { getCurrentDate } from "@/utils/index.js";
|
import { printFinishedProcessCard } from "./components/processCardPrint.js";
|
import { printSalesOrder } from "./components/salesOrderPrint.js";
|
import { printSalesDeliveryNote } from "./components/salesDeliveryPrint.js";
|
import { printSalesLabel } from "./components/salesLabelPrint.js";
|
// import { salesLedgerProductSetProcessFlowConfig } from "@/api/salesManagement/salesProcessFlowConfig.js";
|
|
const userStore = useUserStore();
|
const { proxy } = getCurrentInstance();
|
const tableData = ref([]);
|
const productData = ref([]);
|
const selectedRows = ref([]);
|
const productSelectedRows = ref([]);
|
const userList = ref([]);
|
const customerOption = ref([]);
|
const productOptions = ref([]);
|
const modelOptions = ref([]);
|
const tableLoading = ref(false);
|
const page = reactive({
|
current: 1,
|
size: 100,
|
});
|
const total = ref(0);
|
const fileList = ref([]);
|
|
// 工艺路线配置选择弹窗(绑定到台账产品)
|
const processFlowSelectDialogVisible = ref(false);
|
const processFlowSelectLedgerRow = ref(null);
|
const processFlowSelectDefaultRouteId = ref(null);
|
const processFlowSelectBoundRouteId = ref(null);
|
const processFlowSelectBoundRouteName = ref("");
|
|
// 用户信息表单弹框数据
|
const operationType = ref("");
|
const dialogFormVisible = ref(false);
|
const data = reactive({
|
searchForm: {
|
customerName: "", // 客户名称
|
salesContractNo: "", // 销售合同编号
|
entryDate: null, // 录入日期
|
entryDateStart: undefined,
|
entryDateEnd: undefined,
|
},
|
form: {
|
salesContractNo: "",
|
salesman: "",
|
customerId: "",
|
entryPerson: "",
|
entryDate: "",
|
deliveryDate: "",
|
maintenanceTime: "",
|
productData: [],
|
executionDate: "",
|
},
|
rules: {
|
salesman: [{ required: true, message: "请选择", trigger: "change" }],
|
customerId: [{ required: true, message: "请选择", trigger: "change" }],
|
entryPerson: [{ required: true, message: "请选择", trigger: "change" }],
|
entryDate: [{ required: true, message: "请选择", trigger: "change" }],
|
deliveryDate: [{ required: true, message: "请选择", trigger: "change" }],
|
executionDate: [{ required: true, message: "请选择", trigger: "change" }],
|
},
|
});
|
const { form, rules } = toRefs(data);
|
const { form: searchForm } = useFormData(data.searchForm);
|
// 产品表单弹框数据
|
const productFormVisible = ref(false);
|
const productOperationType = ref("");
|
const currentId = ref("");
|
const productFormData = reactive({
|
productForm: {
|
productCategory: "",
|
specificationModel: "",
|
thickness:null,
|
quantity: "",
|
taxInclusiveUnitPrice: "",
|
taxRate: "",
|
taxInclusiveTotalPrice: "",
|
taxExclusiveTotalPrice: "",
|
invoiceType: "",
|
// 新增:尺寸/面积/加工与其他金额
|
width: 0, // 宽(mm)
|
height: 0, // 高(mm)
|
perimeter: 0, // 周长(cm) = (宽+高)*2,宽高为 mm
|
// 面积字段(㎡)
|
actualPieceArea: 0, // 实际单片面积(㎡)
|
actualTotalArea: 0, // 实际总面积(㎡)
|
settlePieceArea: 0, // 结算单片面积(㎡)
|
settleTotalArea: 0, // 结算总面积(㎡)
|
processRequirement: "", // 加工要求
|
remark: "", // 备注
|
salesProductProcessList: [], // 其他金额:[{id, processName, quantity}]
|
processFlowConfigId: null, // 工艺流程配置绑定
|
floorCode: "", // 楼层编号
|
},
|
productRules: {
|
productCategory: [{ required: true, message: "请选择", trigger: "change" }],
|
productModelId: [{ required: true, message: "请选择", trigger: "change" }],
|
specificationModel: [
|
{ required: true, message: "请选择", trigger: "change" },
|
],
|
thickness: [{ required: true, message: "请输入", trigger: "blur" }],
|
quantity: [{ required: true, message: "请输入", trigger: "blur" }],
|
taxInclusiveUnitPrice: [
|
{ required: true, message: "请输入", trigger: "blur" },
|
],
|
taxRate: [{ required: true, message: "请选择", trigger: "change" }],
|
taxInclusiveTotalPrice: [
|
{ required: true, message: "请输入", trigger: "blur" },
|
],
|
taxExclusiveTotalPrice: [
|
{ required: true, message: "请输入", trigger: "blur" },
|
],
|
invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
|
},
|
});
|
const { productForm, productRules } = toRefs(productFormData);
|
// 防止循环计算的标志
|
const isCalculating = ref(false);
|
const upload = reactive({
|
// 上传的地址
|
url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
|
// 设置上传的请求头部
|
headers: { Authorization: "Bearer " + getToken() },
|
});
|
// 报价单导入相关
|
const quotationDialogVisible = ref(false);
|
const quotationLoading = ref(false);
|
const quotationList = ref([]);
|
const quotationSearchForm = reactive({
|
quotationNo: "",
|
customer: "",
|
});
|
// 报价单弹框分页
|
const quotationPage = reactive({
|
current: 1,
|
size: 10,
|
total: 0,
|
});
|
const selectedQuotation = ref(null);
|
|
// 发货相关
|
const deliveryFormVisible = ref(false);
|
const currentDeliveryRows = ref([]);
|
const deliveryFormData = reactive({
|
deliveryForm: {
|
type: "货车", // 货车, 快递
|
},
|
deliveryRules: {
|
type: [
|
{ required: true, message: "请选择发货类型", trigger: "change" }
|
]
|
},
|
});
|
const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
|
|
// 产品弹框:其他金额多选下拉(基于“其他金额维护”查询接口)
|
const otherAmountSelectOptions = ref([]); // [{id, processName}]
|
const otherAmountSelectOptionsLoading = ref(false);
|
|
const fetchOtherAmountSelectOptions = async (force = false) => {
|
if (!force && otherAmountSelectOptions.value.length > 0) return;
|
otherAmountSelectOptionsLoading.value = true;
|
try {
|
const params = {
|
current: 1,
|
// 下拉框尽量一次性拉全,避免多次分页影响选择体验
|
size: 1000,
|
};
|
const res = await salesLedgerProductProcessList(params);
|
const records = res?.records ?? res?.data?.records ?? [];
|
|
otherAmountSelectOptions.value = records.map((item) => ({
|
id: item.id,
|
processName: item.processName ?? "",
|
unitPrice: item.unitPrice ?? 0,
|
}));
|
} finally {
|
otherAmountSelectOptionsLoading.value = false;
|
}
|
};
|
|
const normalizeOtherAmountsFromRow = (row) => {
|
if (!row) return [];
|
const raw =
|
row.other_amounts ??
|
row.otherAmounts ??
|
row.otherAmountProjects ??
|
row.otherAmountList ??
|
row.salesProductProcessList ??
|
[];
|
|
if (!Array.isArray(raw)) return [];
|
if (raw.length === 0) return [];
|
|
// 情况1:后端直接返回 [{id, processName}...]
|
if (typeof raw[0] === "object") {
|
return raw
|
.map((it) => {
|
const id = it?.id ?? it?.processId ?? it?.otherAmountId ?? null;
|
const quantity =
|
Number(
|
it?.quantity ??
|
it?.processQuantity ??
|
it?.otherQuantity ??
|
it?.process_quantity ??
|
it?.other_amount_quantity
|
) || 0;
|
return {
|
id,
|
processName: it?.processName ?? "",
|
quantity,
|
};
|
})
|
.filter((it) => it.id !== null && it.id !== undefined && it.id !== "");
|
}
|
|
// 情况2:后端只返回 ids: [1,2,3]
|
return raw
|
.map((id) => ({
|
id,
|
processName: "",
|
quantity: 0,
|
}))
|
.filter((it) => it.id !== null && it.id !== undefined && it.id !== "");
|
};
|
|
const mergeOtherAmountOptionsBySelection = (selected) => {
|
const list = Array.isArray(selected) ? selected : [];
|
for (const s of list) {
|
const exists = otherAmountSelectOptions.value.some((o) => String(o.id) === String(s.id));
|
if (!exists) {
|
otherAmountSelectOptions.value.push({
|
id: s.id,
|
processName: s.processName ?? "",
|
});
|
}
|
}
|
};
|
|
const fillOtherAmountProcessName = (selected) => {
|
const list = Array.isArray(selected) ? selected : [];
|
return list.map((s) => {
|
const opt = otherAmountSelectOptions.value.find((o) => String(o.id) === String(s.id));
|
return {
|
id: s.id,
|
processName: opt?.processName ?? s.processName ?? "",
|
unitPrice: opt?.unitPrice ?? s.unitPrice ?? 0,
|
quantity: Number(s.quantity ?? 0) || 0,
|
};
|
});
|
};
|
|
// “其他金额”卡片布局:只有一条时占满整行;>=2时两列排布
|
const getOtherAmountCardFlexStyle = () => {
|
const list = productForm.value?.salesProductProcessList;
|
const len = Array.isArray(list) ? list.length : 0;
|
if (len === 1) {
|
return { flex: "0 0 100%", maxWidth: "100%", width: "100%" };
|
}
|
return {
|
flex: "0 0 calc(50% - 6px)",
|
maxWidth: "calc(50% - 6px)",
|
width: "calc(50% - 6px)",
|
};
|
};
|
|
// 其他金额:点击“新增”后在弹窗里选择一个项目
|
const otherAmountAddDialogVisible = ref(false);
|
const otherAmountAddId = ref(null);
|
|
const startAddOtherAmount = () => {
|
if (operationType.value === "view") return;
|
otherAmountAddDialogVisible.value = true;
|
otherAmountAddId.value = null;
|
// 通常 openProductForm 已经拉过 options,这里兜底
|
if (otherAmountSelectOptions.value.length === 0) {
|
fetchOtherAmountSelectOptions(true);
|
}
|
};
|
|
const cancelAddOtherAmount = () => {
|
otherAmountAddDialogVisible.value = false;
|
otherAmountAddId.value = null;
|
};
|
|
const handleOtherAmountSelected = (id) => {
|
const selectedId = id ?? otherAmountAddId.value;
|
if (selectedId === null || selectedId === undefined || selectedId === "") return;
|
const opt = otherAmountSelectOptions.value.find((o) => String(o.id) === String(selectedId));
|
if (!opt) return;
|
|
const exists = (productForm.value?.salesProductProcessList ?? []).some(
|
(it) => String(it?.id) === String(opt.id)
|
);
|
if (exists) {
|
proxy.$modal.msgWarning("该其他金额项目已添加");
|
return;
|
}
|
|
productForm.value.salesProductProcessList.push({
|
id: opt.id,
|
processName: opt.processName,
|
unitPrice: opt.unitPrice ?? 0,
|
quantity: 0,
|
});
|
calculateFromUnitPrice(true);
|
|
// 选择完成后关闭弹窗,下一次可再次点击“新增”继续添加
|
otherAmountAddDialogVisible.value = false;
|
otherAmountAddId.value = null;
|
};
|
|
const confirmAddOtherAmount = () => {
|
handleOtherAmountSelected(otherAmountAddId.value);
|
};
|
|
const removeOtherAmountAt = (index) => {
|
if (operationType.value === "view") return;
|
if (!Array.isArray(productForm.value?.salesProductProcessList)) return;
|
productForm.value.salesProductProcessList.splice(index, 1);
|
calculateFromUnitPrice(true);
|
};
|
|
// 发货审批人节点(仿协同审批 infoFormDia.vue)
|
const approverNodes = ref([{ id: 1, userId: null }]);
|
let nextApproverId = 2;
|
const addApproverNode = () => {
|
approverNodes.value.push({ id: nextApproverId++, userId: null });
|
};
|
const removeApproverNode = (index) => {
|
approverNodes.value.splice(index, 1);
|
};
|
|
// 导入相关
|
const importUploadRef = ref(null);
|
const importUpload = reactive({
|
title: "导入销售台账",
|
open: false,
|
url: import.meta.env.VITE_APP_BASE_API + "/sales/ledger/import",
|
headers: { Authorization: "Bearer " + getToken() },
|
isUploading: false,
|
beforeUpload: (file) => {
|
const isExcel = file.name.endsWith('.xlsx') || file.name.endsWith('.xls');
|
const isLt10M = file.size / 1024 / 1024 < 10;
|
if (!isExcel) {
|
proxy.$modal.msgError("上传文件只能是 xlsx/xls 格式!");
|
return false;
|
}
|
if (!isLt10M) {
|
proxy.$modal.msgError("上传文件大小不能超过 10MB!");
|
return false;
|
}
|
return true;
|
},
|
onChange: (file, fileList) => {
|
console.log('文件状态改变', file, fileList);
|
},
|
onProgress: (event, file, fileList) => {
|
console.log('上传中...', event.percent);
|
},
|
onSuccess: (response, file, fileList) => {
|
console.log('上传成功', response, file, fileList);
|
importUpload.isUploading = false;
|
if (response.code === 200) {
|
proxy.$modal.msgSuccess("导入成功");
|
importUpload.open = false;
|
if (importUploadRef.value) {
|
importUploadRef.value.clearFiles();
|
}
|
getList();
|
} else {
|
proxy.$modal.msgError(response.msg || "导入失败");
|
}
|
},
|
onError: (error, file, fileList) => {
|
console.error('上传失败', error, file, fileList);
|
importUpload.isUploading = false;
|
proxy.$modal.msgError("导入失败,请重试");
|
},
|
});
|
|
const changeDaterange = (value) => {
|
if (value) {
|
searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD");
|
searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
|
} else {
|
searchForm.entryDateStart = undefined;
|
searchForm.entryDateEnd = undefined;
|
}
|
handleQuery();
|
};
|
|
// 查询列表
|
/** 搜索按钮操作 */
|
const handleQuery = () => {
|
// 只有在点击搜索按钮时才重置页码到第一页
|
// 避免表单字段change事件干扰分页
|
if (arguments.length === 0) {
|
page.current = 1;
|
}
|
expandedRowKeys.value = [];
|
getList();
|
};
|
const paginationChange = (obj) => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
const getList = () => {
|
tableLoading.value = true;
|
const { entryDate, ...rest } = searchForm;
|
// 将范围日期字段传递给后端
|
const params = { ...rest, ...page };
|
// 移除录入日期的默认值设置,只保留范围日期字段
|
delete params.entryDate;
|
return ledgerListPage(params)
|
.then((res) => {
|
tableLoading.value = false;
|
tableData.value = res.records;
|
tableData.value.map((item) => {
|
item.children = [];
|
});
|
total.value = res.total;
|
return res;
|
})
|
.catch(() => {
|
tableLoading.value = false;
|
});
|
};
|
|
// 打开“工艺路线配置”选择弹窗(必须显式选择)
|
const openProcessFlowSelect = async (ledgerRow) => {
|
if (!ledgerRow) return;
|
if (!ledgerRow.isEdit) return;
|
|
processFlowSelectLedgerRow.value = ledgerRow;
|
processFlowSelectDefaultRouteId.value = null;
|
processFlowSelectBoundRouteId.value = null;
|
processFlowSelectBoundRouteName.value = "";
|
|
try {
|
const res = await getSaleProcessBindInfo(ledgerRow.id);
|
const info = res?.data ?? res ?? {};
|
const boundId =
|
info?.processRouteId ??
|
info?.routeId ??
|
info?.id ??
|
null;
|
const boundName =
|
info?.processRouteName ??
|
info?.routeName ??
|
info?.name ??
|
"";
|
processFlowSelectBoundRouteId.value = boundId;
|
processFlowSelectBoundRouteName.value = boundName;
|
processFlowSelectDefaultRouteId.value = boundId;
|
} catch (e) {
|
// 查询失败时按未绑定处理,不阻塞弹窗
|
processFlowSelectBoundRouteId.value = null;
|
processFlowSelectBoundRouteName.value = "";
|
processFlowSelectDefaultRouteId.value = null;
|
}
|
|
processFlowSelectDialogVisible.value = true;
|
};
|
|
// 绑定工艺路线到当前台账数据
|
const handleProcessFlowSelectConfirm = async (routeId) => {
|
const ledgerRow = processFlowSelectLedgerRow.value;
|
if (!ledgerRow?.id) return;
|
|
const finalRouteId = routeId ?? null;
|
if (!finalRouteId) return;
|
|
const oldRouteId = processFlowSelectBoundRouteId.value;
|
if (oldRouteId !== null && oldRouteId !== undefined && oldRouteId !== "" && String(oldRouteId) !== String(finalRouteId)) {
|
try {
|
await ElMessageBox.confirm(
|
"该订单已绑定工艺路线,是否确定更换?",
|
"提示",
|
{
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning",
|
}
|
);
|
} catch {
|
return;
|
}
|
}
|
|
proxy?.$modal?.loading?.("正在绑定工艺路线,请稍候...");
|
try {
|
await saleProcessBind({
|
salesLedgerId: ledgerRow.id,
|
processRouteId: finalRouteId,
|
});
|
|
proxy?.$modal?.msgSuccess?.("工艺路线绑定成功");
|
processFlowSelectDialogVisible.value = false;
|
// 绑定后刷新列表,确保操作列再次点击能回显绑定
|
await getList();
|
} catch (e) {
|
proxy?.$modal?.msgError?.("绑定失败,请稍后重试");
|
} finally {
|
proxy?.$modal?.closeLoading?.();
|
}
|
};
|
|
// 获取产品大类tree数据
|
const getProductOptions = () => {
|
// 返回 Promise,便于在编辑产品时等待加载完成
|
return productTreeList().then((res) => {
|
productOptions.value = convertIdToValue(res);
|
return productOptions.value;
|
});
|
};
|
const formattedNumber = (row, column, cellValue) => {
|
return parseFloat(cellValue).toFixed(2);
|
};
|
// 获取tree子数据
|
const getModels = (value) => {
|
productForm.value.productCategory = findNodeById(productOptions.value, value);
|
modelList({ id: value }).then((res) => {
|
modelOptions.value = res;
|
});
|
};
|
const getProductModel = (value) => {
|
const index = modelOptions.value.findIndex((item) => item.id === value);
|
if (index !== -1) {
|
productForm.value.specificationModel = modelOptions.value[index].model;
|
} else {
|
productForm.value.specificationModel = null;
|
}
|
};
|
const findNodeById = (nodes, productId) => {
|
for (let i = 0; i < nodes.length; i++) {
|
if (nodes[i].value === productId) {
|
return nodes[i].label; // 找到节点,返回该节点
|
}
|
if (nodes[i].children && nodes[i].children.length > 0) {
|
const foundNode = findNodeById(nodes[i].children, productId);
|
if (foundNode) {
|
return foundNode; // 在子节点中找到,返回该节点
|
}
|
}
|
}
|
return null; // 没有找到节点,返回null
|
};
|
function convertIdToValue(data) {
|
return data.map((item) => {
|
const { id, children, ...rest } = item;
|
const newItem = {
|
...rest,
|
value: id, // 将 id 改为 value
|
};
|
if (children && children.length > 0) {
|
newItem.children = convertIdToValue(children);
|
}
|
|
return newItem;
|
});
|
}
|
// 根据名称反查产品大类 id,便于仅存名称时的反显
|
function findNodeIdByLabel(nodes, label) {
|
if (!label) return null;
|
for (let i = 0; i < nodes.length; i++) {
|
const node = nodes[i];
|
if (node.label === label) return node.value;
|
if (node.children && node.children.length > 0) {
|
const found = findNodeIdByLabel(node.children, label);
|
if (found !== null && found !== undefined) return found;
|
}
|
}
|
return null;
|
}
|
// 表格选择数据
|
const handleSelectionChange = (selection) => {
|
// 过滤掉子数据
|
selectedRows.value = selection.filter((item) => item.children !== undefined);
|
console.log("selection", selectedRows.value);
|
};
|
const productSelected = (selectedRows) => {
|
productSelectedRows.value = selectedRows;
|
};
|
const expandedRowKeys = ref([]);
|
// 展开行
|
const expandChange = (row, expandedRows) => {
|
if (expandedRows.length > 0) {
|
expandedRowKeys.value = [];
|
try {
|
productList({ salesLedgerId: row.id, type: 1 }).then((res) => {
|
const index = tableData.value.findIndex((item) => item.id === row.id);
|
if (index > -1) {
|
tableData.value[index].children = res.data;
|
}
|
expandedRowKeys.value.push(row.id);
|
});
|
} catch (error) {
|
console.log(error);
|
}
|
} else {
|
expandedRowKeys.value = [];
|
}
|
};
|
|
// 添加表行类名方法
|
const tableRowClassName = ({ row }) => {
|
if (!row.deliveryDate) return '';
|
if (row.isFh) return '';
|
|
const diff = row.deliveryDaysDiff;
|
if (diff === 15) {
|
return 'yellow';
|
} else if (diff === 10) {
|
return 'pink';
|
} else if (diff === 2) {
|
return 'purple';
|
} else if (diff < 2) {
|
return 'red';
|
}
|
};
|
// 主表合计方法
|
const summarizeMainTable = (param) => {
|
return proxy.summarizeTable(param, [
|
"contractAmount",
|
"taxInclusiveTotalPrice",
|
"taxExclusiveTotalPrice",
|
]);
|
};
|
// 子表合计方法
|
const summarizeChildrenTable = (param) => {
|
return proxy.summarizeTable(param, [
|
"taxInclusiveUnitPrice",
|
"taxInclusiveTotalPrice",
|
"taxExclusiveTotalPrice",
|
]);
|
};
|
// 打开弹框
|
const openForm = async (type, row) => {
|
operationType.value = type;
|
form.value = {};
|
productData.value = [];
|
selectedQuotation.value = null;
|
let userLists = await userListNoPage();
|
userList.value = userLists.data;
|
customerList().then((res) => {
|
customerOption.value = res;
|
});
|
form.value.entryPerson = userStore.id;
|
if (type === "add") {
|
// 新增时设置录入日期为当天
|
form.value.entryDate = getCurrentDate();
|
// 签订日期默认为当天
|
form.value.executionDate = getCurrentDate();
|
form.value.customerRemarks = "";
|
} else {
|
currentId.value = row.id;
|
getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
|
form.value = { ...res };
|
form.value.entryPerson = Number(res.entryPerson);
|
// 字段名兼容:后端可能返回 customer_remarks
|
form.value.customerRemarks = res?.customerRemarks ?? res?.customer_remarks ?? "";
|
productData.value = form.value.productData;
|
fileList.value = form.value.salesLedgerFiles;
|
});
|
}
|
// let userAll = await userStore.getInfo()
|
// userList.value.forEach(element => {
|
// if(userAll.user.nickName === element.nickName && userAll.user.userName === element.userName) {
|
// form.value.entryPerson = userAll.user.userId // 设置默认业务员为当前用户
|
// }
|
// });
|
form.value.entryDate = getCurrentDate(); // 设置默认录入日期为当前日期
|
dialogFormVisible.value = true;
|
};
|
|
// 打开报价单选择弹窗(仅审批通过)
|
const openQuotationDialog = async () => {
|
if (operationType.value === "view") return;
|
quotationDialogVisible.value = true;
|
// 打开弹窗时重置分页到第一页
|
quotationPage.current = 1;
|
// 先确保客户列表已加载,便于后续回填 customerId
|
if (!customerOption.value || customerOption.value.length === 0) {
|
try {
|
const res = await customerList();
|
customerOption.value = res;
|
} catch (e) {
|
// ignore,允许用户后续手动选择客户
|
}
|
}
|
await fetchQuotationList();
|
};
|
|
const fetchQuotationList = async () => {
|
quotationLoading.value = true;
|
try {
|
const params = {
|
// 后端分页字段:current / size
|
current: quotationPage.current,
|
size: quotationPage.size,
|
...quotationSearchForm,
|
status: "通过",
|
};
|
const res = await getQuotationList(params);
|
quotationList.value = res?.data?.records || [];
|
quotationPage.total = res?.data?.total || 0;
|
} finally {
|
quotationLoading.value = false;
|
}
|
};
|
|
const resetQuotationSearch = async () => {
|
quotationSearchForm.quotationNo = "";
|
quotationSearchForm.customer = "";
|
quotationPage.current = 1;
|
await fetchQuotationList();
|
};
|
|
// 报价单弹框分页切换
|
const quotationPaginationChange = (obj) => {
|
quotationPage.current = obj.page;
|
quotationPage.size = obj.limit;
|
fetchQuotationList();
|
};
|
|
// 选中报价单后回填到台账表单
|
const applyQuotation = (row) => {
|
if (!row) return;
|
selectedQuotation.value = row;
|
|
// 业务员
|
form.value.salesman = (row.salesperson || "").trim();
|
|
// 客户名称 -> customerId
|
const qCustomerName = String(row.customer || "").trim();
|
const customer = (customerOption.value || []).find((c) => {
|
const name = String(c.customerName || "").trim();
|
return name === qCustomerName || name.includes(qCustomerName) || qCustomerName.includes(name);
|
});
|
if (customer?.id) {
|
form.value.customerId = customer.id;
|
} else {
|
// 如果找不到,保留原值(允许用户手动选择/不打断已有输入)
|
form.value.customerId = form.value.customerId || "";
|
}
|
|
// 产品信息映射:报价 products -> 台账 productData
|
const products = Array.isArray(row.products) ? row.products : [];
|
productData.value = products.map((p) => {
|
const quantity = Number(p.quantity ?? 0) || 0;
|
const unitPrice = Number(p.unitPrice ?? 0) || 0;
|
const settlePieceArea = Number(p.settlePieceArea ?? 0) || 1;
|
const taxRate = "13"; // 默认 13%,便于直接提交(如需可在产品中自行修改)
|
const taxInclusiveTotalPrice = (unitPrice * settlePieceArea * quantity).toFixed(2);
|
const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(taxInclusiveTotalPrice, taxRate);
|
return {
|
// 台账字段
|
productCategory: p.product || p.productName || "",
|
specificationModel: p.specification || "",
|
thickness: p.thickness,
|
quantity: quantity,
|
taxRate: taxRate,
|
taxInclusiveUnitPrice: unitPrice.toFixed(2),
|
taxInclusiveTotalPrice: taxInclusiveTotalPrice,
|
taxExclusiveTotalPrice: taxExclusiveTotalPrice,
|
invoiceType: "增普票",
|
// 新增:默认值(避免后续提交时字段缺失)
|
width: 0,
|
height: 0,
|
actualPieceArea: 0,
|
actualTotalArea: 0,
|
settlePieceArea: 0,
|
settleTotalArea: 0,
|
processRequirement: "",
|
floorCode: "",
|
remark: "",
|
salesProductProcessList: [],
|
};
|
});
|
|
quotationDialogVisible.value = false;
|
};
|
function changs(val) {
|
console.log(val);
|
}
|
// 上传前校检
|
function handleBeforeUpload(file) {
|
// 校检文件大小
|
// if (file.size > 1024 * 1024 * 10) {
|
// proxy.$modal.msgError("上传文件大小不能超过10MB!");
|
// return false;
|
// }
|
proxy.$modal.loading("正在上传文件,请稍候...");
|
return true;
|
}
|
// 上传失败
|
function handleUploadError(err) {
|
proxy.$modal.msgError("上传文件失败");
|
proxy.$modal.closeLoading();
|
}
|
// 上传成功回调
|
function handleUploadSuccess(res, file, uploadFiles) {
|
proxy.$modal.closeLoading();
|
if (res.code === 200) {
|
file.tempId = res.data.tempId;
|
proxy.$modal.msgSuccess("上传成功");
|
} else {
|
proxy.$modal.msgError(res.msg);
|
proxy.$refs.fileUpload.handleRemove(file);
|
}
|
}
|
// 移除文件
|
function handleRemove(file) {
|
if (operationType.value === "edit") {
|
let ids = [];
|
ids.push(file.id);
|
delLedgerFile(ids).then((res) => {
|
proxy.$modal.msgSuccess("删除成功");
|
});
|
}
|
}
|
// 提交表单
|
const submitForm = () => {
|
proxy.$refs["formRef"].validate((valid) => {
|
if (valid) {
|
console.log('productData.value--', productData.value)
|
if (productData.value !== null && productData.value.length > 0) {
|
form.value.productData = proxy.HaveJson(productData.value);
|
} else {
|
proxy.$modal.msgWarning("请添加产品信息");
|
return;
|
}
|
let tempFileIds = [];
|
if (fileList.value !== null && fileList.value.length > 0) {
|
tempFileIds = fileList.value.map((item) => item.tempId);
|
}
|
form.value.tempFileIds = tempFileIds;
|
form.value.type = 1;
|
addOrUpdateSalesLedger(form.value).then((res) => {
|
proxy.$modal.msgSuccess("提交成功");
|
closeDia();
|
getList();
|
});
|
}
|
});
|
};
|
// 关闭弹框
|
const closeDia = () => {
|
proxy.resetForm("formRef");
|
dialogFormVisible.value = false;
|
};
|
|
const productIndex = ref(0);
|
// 打开产品弹框
|
const openProductForm = async (type, row, index) => {
|
// 编辑时检查产品是否已发货或审核通过
|
if (type === "edit" && isProductShipped(row)) {
|
proxy.$modal.msgWarning("已发货或审核通过的产品不能编辑");
|
return;
|
}
|
|
productOperationType.value = type;
|
productForm.value = {};
|
proxy.resetForm("productFormRef");
|
// 确保多选项默认是数组,避免 el-select multiple 报错
|
productForm.value.salesProductProcessList = [];
|
otherAmountAddDialogVisible.value = false;
|
otherAmountAddId.value = null;
|
if (type === "edit") {
|
productForm.value = { ...row };
|
|
// 字段命名兼容:优先驼峰(如 actualPieceArea),兼容后端可能返回下划线(如 actual_piece_area)
|
productForm.value.actualPieceArea = row?.actualPieceArea ?? row?.actual_piece_area ?? 0;
|
productForm.value.actualTotalArea = row?.actualTotalArea ?? row?.actual_total_area ?? 0;
|
productForm.value.settlePieceArea = row?.settlePieceArea ?? row?.settle_piece_area ?? 0;
|
productForm.value.settleTotalArea = row?.settleTotalArea ?? row?.settle_total_area ?? 0;
|
|
// 加工要求/备注兼容:后端可能使用其它命名
|
productForm.value.processRequirement =
|
row?.processRequirement ?? row?.process_requirement ?? "";
|
productForm.value.remark = row?.remark ?? row?.remarks ?? "";
|
productForm.value.floorCode = row?.floorCode ?? row?.floor_code ?? "";
|
// 工艺流程配置绑定字段(后续由后端确认字段名)
|
productForm.value.processFlowConfigId =
|
row?.processFlowConfigId ?? row?.process_flow_config_id ?? null;
|
|
// 周长回显(如后端返回;最终仍以公式计算为准)
|
productForm.value.perimeter =
|
row?.perimeter ?? row?.heavyBoxPerimeter ?? row?.heavyboxPerimeter ?? 0;
|
|
// 后端直接返回 thickness
|
productForm.value.thickness = row?.thickness;
|
|
productForm.value.salesProductProcessList = normalizeOtherAmountsFromRow(row);
|
productIndex.value = index;
|
// 编辑时根据产品大类名称反查 tree 节点 id,并加载规格型号列表
|
try {
|
const options = productOptions.value && productOptions.value.length > 0
|
? productOptions.value
|
: await getProductOptions();
|
const categoryId = findNodeIdByLabel(options, productForm.value.productCategory);
|
if (categoryId) {
|
const models = await modelList({ id: categoryId });
|
modelOptions.value = models || [];
|
// 根据当前规格型号名称反查并设置 productModelId,便于下拉框显示已选值
|
const currentModel = (modelOptions.value || []).find(
|
(m) => m.model === productForm.value.specificationModel
|
);
|
if (currentModel) {
|
productForm.value.productModelId = currentModel.id;
|
}
|
}
|
} catch (e) {
|
// 加载失败时保持可编辑,不中断弹窗
|
console.error("加载产品规格型号失败", e);
|
}
|
|
// 根据当前宽高重新计算周长与面积
|
recalcPerimeterFromWidthHeight();
|
recalcAreaFromWidthHeight();
|
|
// 回显“其他金额”多选:先拉取下拉选项,再补齐 processName
|
await fetchOtherAmountSelectOptions(true);
|
mergeOtherAmountOptionsBySelection(productForm.value.salesProductProcessList);
|
productForm.value.salesProductProcessList = fillOtherAmountProcessName(productForm.value.salesProductProcessList);
|
} else {
|
getProductOptions()
|
// 新增时下拉选项加载一次即可
|
fetchOtherAmountSelectOptions(true);
|
}
|
productFormVisible.value = true;
|
};
|
// 提交产品表单
|
const submitProduct = () => {
|
proxy.$refs["productFormRef"].validate((valid) => {
|
if (valid) {
|
// 厚度保留 15 位小数,避免由于浮点计算/输入导致精度偏差
|
if (productForm.value.thickness !== null && productForm.value.thickness !== undefined) {
|
productForm.value.thickness = Number(Number(productForm.value.thickness).toFixed(15));
|
}
|
|
// 面积/总计字段在提交前兜底计算一次
|
recalcAreaTotals();
|
// 其他金额只提交 {id, processName, quantity}(后端字段:salesProductProcessList)
|
productForm.value.salesProductProcessList = (Array.isArray(productForm.value.salesProductProcessList)
|
? productForm.value.salesProductProcessList
|
: []
|
)
|
.map((it) => ({
|
id: it?.id,
|
processName: it?.processName ?? "",
|
unitPrice: Number(it?.unitPrice ?? 0) || 0,
|
quantity: Number(it?.quantity ?? 0) || 0,
|
}))
|
.filter((it) => it.id !== null && it.id !== undefined && it.id !== "");
|
|
if (operationType.value === "edit") {
|
submitProductEdit();
|
} else {
|
if(productOperationType.value === "add"){
|
productData.value.push({ ...productForm.value });
|
}else{
|
productData.value[productIndex.value] = { ...productForm.value }
|
}
|
closeProductDia();
|
}
|
}
|
});
|
};
|
const submitProductEdit = () => {
|
productForm.value.salesLedgerId = currentId.value;
|
productForm.value.type = 1
|
addOrUpdateSalesLedgerProduct(productForm.value).then((res) => {
|
proxy.$modal.msgSuccess("提交成功");
|
closeProductDia();
|
getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then((res) => {
|
productData.value = res.productData;
|
});
|
});
|
};
|
// 删除产品
|
const deleteProduct = () => {
|
if (productSelectedRows.value.length === 0) {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
|
// 检查是否有已发货或审核通过的产品
|
const shippedProducts = productSelectedRows.value.filter(row => isProductShipped(row));
|
if (shippedProducts.length > 0) {
|
proxy.$modal.msgWarning("已发货或审核通过的产品不能删除");
|
return;
|
}
|
|
if (operationType.value === "add") {
|
productSelectedRows.value.forEach((selectedRow) => {
|
const index = productData.value.findIndex(
|
(product) => product.id === selectedRow.id
|
);
|
if (index !== -1) {
|
productData.value.splice(index, 1);
|
}
|
});
|
} else {
|
let ids = [];
|
if (productSelectedRows.value.length > 0) {
|
ids = productSelectedRows.value.map((item) => item.id);
|
}
|
ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
delProduct(ids).then((res) => {
|
proxy.$modal.msgSuccess("删除成功");
|
closeProductDia();
|
getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then(
|
(res) => {
|
productData.value = res.productData;
|
}
|
);
|
});
|
})
|
.catch(() => {
|
proxy.$modal.msg("已取消");
|
});
|
}
|
};
|
// 关闭产品弹框
|
const closeProductDia = () => {
|
proxy.resetForm("productFormRef");
|
productFormVisible.value = false;
|
otherAmountAddDialogVisible.value = false;
|
otherAmountAddId.value = null;
|
};
|
// 导入
|
const handleImport = () => {
|
importUpload.title = "导入销售台账";
|
importUpload.open = true;
|
if (importUploadRef.value) {
|
importUploadRef.value.clearFiles();
|
}
|
};
|
|
// 下载导入模板
|
const downloadTemplate = () => {
|
proxy.download("/sales/ledger/exportTemplate", {}, "销售台账导入模板.xlsx");
|
};
|
|
// 提交导入文件
|
const submitImportFile = () => {
|
importUpload.isUploading = true;
|
proxy.$refs["importUploadRef"].submit();
|
};
|
|
// 导出
|
const handleOut = () => {
|
ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
proxy.download("/sales/ledger/export", {}, "销售台账.xlsx");
|
})
|
.catch(() => {
|
proxy.$modal.msg("已取消");
|
});
|
};
|
/** 判断单个产品是否已发货(根据shippingStatus判断,已发货或审核通过不可编辑和删除) */
|
const isProductShipped = (product) => {
|
if (!product) return false;
|
const status = String(product.shippingStatus || "").trim();
|
// 如果发货状态是"已发货"或"审核通过",则不可编辑和删除
|
return status === "已发货" || status === "审核通过";
|
};
|
|
/** 判断销售订单下是否存在已发货/发货完成的产品(不可删除) */
|
const hasShippedProducts = (products) => {
|
if (!products || !products.length) return false;
|
return products.some((p) => {
|
const status = String(p.shippingStatus || "").trim();
|
// 有发货日期或车牌号视为已发货
|
if (p.shippingDate || p.shippingCarNumber) return true;
|
// 已进行发货、发货完成、已发货 均不可删除
|
return status === "已进行发货" || status === "发货完成" || status === "已发货";
|
});
|
};
|
|
// 删除
|
const handleDelete = async () => {
|
if (selectedRows.value.length === 0) {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
const ids = selectedRows.value.map((item) => item.id);
|
|
// 检查是否有已进行发货或发货完成的销售订单,若有则不允许删除
|
const cannotDeleteNames = [];
|
for (const row of selectedRows.value) {
|
let products = row.children && row.children.length > 0 ? row.children : null;
|
if (!products) {
|
try {
|
const res = await productList({ salesLedgerId: row.id, type: 1 });
|
products = res.data || [];
|
} catch {
|
products = [];
|
}
|
}
|
if (hasShippedProducts(products)) {
|
cannotDeleteNames.push(row.salesContractNo || `ID:${row.id}`);
|
}
|
}
|
if (cannotDeleteNames.length > 0) {
|
proxy.$modal.msgWarning("已进行发货或发货完成的销售订单不能删除:" + cannotDeleteNames.join("、"));
|
return;
|
}
|
|
ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
delLedger(ids).then((res) => {
|
proxy.$modal.msgSuccess("删除成功");
|
getList();
|
});
|
})
|
.catch(() => {
|
proxy.$modal.msg("已取消");
|
});
|
};
|
|
const handlePrintCommand = async (command) => {
|
if (command !== "finishedProcessCard" && command !== "salesOrder" && command !== "salesDeliveryNote") return;
|
if (command === "salesDeliveryNote") {
|
if (selectedRows.value.length === 0) {
|
proxy.$modal.msgWarning("请至少选择一条销售台账数据进行打印");
|
return;
|
}
|
const customerNames = Array.from(
|
new Set(selectedRows.value.map((item) => String(item?.customerName ?? "").trim()))
|
);
|
if (customerNames.length > 1) {
|
proxy.$modal.msgWarning("仅支持相同客户名称的销售台账合并发货打印");
|
return;
|
}
|
} else if (selectedRows.value.length !== 1) {
|
proxy.$modal.msgWarning("请选择一条销售台账数据进行打印");
|
return;
|
}
|
|
const selectedRow = selectedRows.value[0];
|
const selectedId = selectedRow?.id;
|
if (command === "salesDeliveryNote") {
|
const selectedIds = selectedRows.value
|
.map((item) => item?.id)
|
.filter((id) => id !== null && id !== undefined && id !== "");
|
if (selectedIds.length !== selectedRows.value.length) {
|
proxy.$modal.msgWarning("当前选择数据存在缺少ID的记录,无法打印");
|
return;
|
}
|
const loadingText =
|
command === "salesOrder"
|
? "正在获取销售订单数据,请稍候..."
|
: command === "salesDeliveryNote"
|
? "正在获取销售发货单数据,请稍候..."
|
: "正在获取生产流程卡数据,请稍候...";
|
proxy.$modal.loading(loadingText);
|
try {
|
const res = await getSalesInvoices(selectedIds);
|
const salesInvoiceData = res?.data ?? {};
|
printSalesDeliveryNote(salesInvoiceData, selectedRow);
|
} catch (error) {
|
console.error("打印销售发货单失败:", error);
|
proxy.$modal.msgError("打印失败,请稍后重试");
|
} finally {
|
proxy.$modal.closeLoading();
|
}
|
return;
|
}
|
if (!selectedId) {
|
proxy.$modal.msgWarning("当前选择数据缺少ID,无法打印");
|
return;
|
}
|
|
const loadingText =
|
command === "salesOrder"
|
? "正在获取销售订单数据,请稍候..."
|
: command === "salesDeliveryNote"
|
? "正在获取销售发货单数据,请稍候..."
|
: "正在获取生产流程卡数据,请稍候...";
|
proxy.$modal.loading(loadingText);
|
try {
|
if (command === "salesOrder") {
|
const res = await getSalesOrder(selectedId);
|
const salesOrderData = res?.data ?? {};
|
printSalesOrder(salesOrderData);
|
} else {
|
const res = await getProcessCard(selectedId);
|
const processCardData = res?.data ?? {};
|
printFinishedProcessCard(processCardData);
|
}
|
} catch (error) {
|
console.error(
|
command === "salesOrder"
|
? "打印销售订单失败:"
|
: command === "salesDeliveryNote"
|
? "打印销售发货单失败:"
|
: "打印生产流程卡失败:",
|
error
|
);
|
proxy.$modal.msgError("打印失败,请稍后重试");
|
} finally {
|
proxy.$modal.closeLoading();
|
}
|
};
|
|
const handlePrintLabel = async () => {
|
if (selectedRows.value.length !== 1) {
|
proxy.$modal.msgWarning("请选择一条销售台账数据进行标签打印");
|
return;
|
}
|
|
const selectedId = selectedRows.value[0]?.id;
|
if (!selectedId) {
|
proxy.$modal.msgWarning("当前选择数据缺少ID,无法打印标签");
|
return;
|
}
|
|
proxy.$modal.loading("正在获取标签数据,请稍候...");
|
try {
|
const res = await getSalesLabel(selectedId);
|
const labelList = res?.data ?? [];
|
if (!Array.isArray(labelList) || labelList.length === 0) {
|
proxy.$modal.msgWarning("暂无可打印标签数据");
|
return;
|
}
|
printSalesLabel(labelList);
|
} catch (error) {
|
console.error("打印标签失败:", error);
|
proxy.$modal.msgError("打印标签失败,请稍后重试");
|
} finally {
|
proxy.$modal.closeLoading();
|
}
|
};
|
|
const mathNum = () => {
|
console.log("productForm.value", productForm.value);
|
if (!productForm.value.taxInclusiveUnitPrice) {
|
return;
|
}
|
if (!productForm.value.quantity) {
|
return;
|
}
|
const settlePieceArea = parseFloat(productForm.value.settlePieceArea) || 1;
|
// 含税总价计算 = 单价 * 结算面积 * 数量 + 其他金额总和
|
const basePrice = proxy.calculateTaxIncludeTotalPrice(
|
productForm.value.taxInclusiveUnitPrice * settlePieceArea,
|
productForm.value.quantity
|
);
|
const otherAmountTotal = (productForm.value.salesProductProcessList || []).reduce((total, item) => {
|
return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
|
}, 0);
|
productForm.value.taxInclusiveTotalPrice = (parseFloat(basePrice) + otherAmountTotal).toFixed(2);
|
if (productForm.value.taxRate) {
|
// 不含税总价计算
|
productForm.value.taxExclusiveTotalPrice =
|
proxy.calculateTaxExclusiveTotalPrice(
|
productForm.value.taxInclusiveTotalPrice,
|
productForm.value.taxRate
|
);
|
}
|
};
|
|
// 新增:尺寸(宽高)与面积(单片/总计)联动
|
const recalcAreaTotals = () => {
|
const qty = Number(productForm.value.quantity ?? 0) || 0;
|
const actualPiece = Number(productForm.value.actualPieceArea ?? 0) || 0;
|
const settlePiece = Number(productForm.value.settlePieceArea ?? 0) || 0;
|
|
productForm.value.actualTotalArea = Number((actualPiece * qty).toFixed(5));
|
productForm.value.settleTotalArea = Number((settlePiece * qty).toFixed(5));
|
};
|
|
// 新增:周长(cm)(重箱heavyBox周长)
|
// width/height 单位为 mm,因此周长(cm)需要除以 10
|
const recalcPerimeterFromWidthHeight = () => {
|
const width = Number(productForm.value.width ?? 0) || 0;
|
const height = Number(productForm.value.height ?? 0) || 0;
|
|
if (width <= 0 || height <= 0) {
|
productForm.value.perimeter = 0;
|
return;
|
}
|
|
// 周长 = (宽 + 高) * 2,单位从 mm 转为 cm:/10
|
productForm.value.perimeter = Number((((width + height) * 2) / 10).toFixed(2));
|
};
|
|
const recalcAreaFromWidthHeight = () => {
|
const width = Number(productForm.value.width ?? 0) || 0;
|
const height = Number(productForm.value.height ?? 0) || 0;
|
|
if (width <= 0 || height <= 0) {
|
// 宽高为空/为0时,把单片面积与总面积置为0
|
productForm.value.actualPieceArea = 0;
|
productForm.value.actualTotalArea = 0;
|
productForm.value.perimeter = 0;
|
|
// 只有在结算单片面积也为空/为0时,才同步置0,避免覆盖用户手动填写
|
const settlePiece = Number(productForm.value.settlePieceArea ?? 0) || 0;
|
if (!settlePiece) {
|
productForm.value.settlePieceArea = 0;
|
}
|
productForm.value.settleTotalArea = Number(
|
((Number(productForm.value.settlePieceArea ?? 0) || 0) * (Number(productForm.value.quantity ?? 0) || 0)).toFixed(5)
|
);
|
return;
|
}
|
|
const computedPieceArea = (width * height) / 1e6; // mm*mm -> ㎡
|
const computed = Number(computedPieceArea.toFixed(5));
|
|
productForm.value.actualPieceArea = computed;
|
productForm.value.settlePieceArea = computed;
|
|
recalcPerimeterFromWidthHeight();
|
recalcAreaTotals();
|
// 面积更新后,重新计算含税总价 = 单价 * 结算面积 * 数量
|
calculateFromUnitPrice(true);
|
};
|
|
// 根据含税总价计算含税单价和数量
|
const calculateFromTotalPrice = () => {
|
if (isCalculating.value) return;
|
|
const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
|
const quantity = parseFloat(productForm.value.quantity);
|
|
if (!totalPrice || !quantity || quantity <= 0) {
|
return;
|
}
|
|
isCalculating.value = true;
|
|
// 计算含税单价 = (含税总价 - 其他金额总和) / 数量
|
const otherAmountTotal = (productForm.value.salesProductProcessList || []).reduce((total, item) => {
|
return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
|
}, 0);
|
const basePrice = totalPrice - otherAmountTotal;
|
productForm.value.taxInclusiveUnitPrice = (basePrice / quantity).toFixed(2);
|
|
// 如果有税率,计算不含税总价
|
if (productForm.value.taxRate) {
|
productForm.value.taxExclusiveTotalPrice =
|
proxy.calculateTaxExclusiveTotalPrice(
|
totalPrice,
|
productForm.value.taxRate
|
);
|
}
|
|
isCalculating.value = false;
|
};
|
|
// 根据不含税总价计算含税单价和数量
|
const calculateFromExclusiveTotalPrice = () => {
|
if (!productForm.value.taxRate) {
|
proxy.$modal.msgWarning("请先选择税率");
|
return;
|
}
|
if (isCalculating.value) return;
|
|
const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice);
|
const quantity = parseFloat(productForm.value.quantity);
|
const taxRate = parseFloat(productForm.value.taxRate);
|
|
if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) {
|
return;
|
}
|
|
isCalculating.value = true;
|
|
// 先计算含税总价 = 不含税总价 / (1 - 税率/100)
|
const taxRateDecimal = taxRate / 100;
|
const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal);
|
productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2);
|
|
// 计算含税单价 = (含税总价 - 其他金额总和) / 数量
|
const otherAmountTotal = (productForm.value.salesProductProcessList || []).reduce((total, item) => {
|
return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
|
}, 0);
|
const basePrice = inclusiveTotalPrice - otherAmountTotal;
|
productForm.value.taxInclusiveUnitPrice = (basePrice / quantity).toFixed(2);
|
|
isCalculating.value = false;
|
};
|
|
// 根据数量变化计算总价
|
const calculateFromQuantity = () => {
|
if (!productForm.value.taxRate) {
|
proxy.$modal.msgWarning("请先选择税率");
|
return;
|
}
|
if (isCalculating.value) return;
|
|
const quantity = parseFloat(productForm.value.quantity);
|
const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
|
const settlePieceArea = parseFloat(productForm.value.settlePieceArea) || 1;
|
|
if (!quantity || quantity <= 0 || !unitPrice) {
|
return;
|
}
|
|
isCalculating.value = true;
|
|
// 计算含税总价 = 单价 * 结算面积 * 数量 + 其他金额总和
|
const basePrice = unitPrice * settlePieceArea * quantity;
|
const otherAmountTotal = (productForm.value.salesProductProcessList || []).reduce((total, item) => {
|
return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
|
}, 0);
|
productForm.value.taxInclusiveTotalPrice = (basePrice + otherAmountTotal).toFixed(2);
|
|
// 如果有税率,计算不含税总价
|
if (productForm.value.taxRate) {
|
productForm.value.taxExclusiveTotalPrice =
|
proxy.calculateTaxExclusiveTotalPrice(
|
productForm.value.taxInclusiveTotalPrice,
|
productForm.value.taxRate
|
);
|
}
|
|
isCalculating.value = false;
|
};
|
|
// 根据含税单价变化计算总价
|
const calculateFromUnitPrice = (silent = false) => {
|
if (!productForm.value.taxRate) {
|
if (!silent) proxy.$modal.msgWarning("请先选择税率");
|
return;
|
}
|
if (isCalculating.value) return;
|
|
const quantity = parseFloat(productForm.value.quantity);
|
const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
|
const settlePieceArea = parseFloat(productForm.value.settlePieceArea) || 1;
|
|
if (!quantity || quantity <= 0 || !unitPrice) {
|
return;
|
}
|
|
isCalculating.value = true;
|
|
// 计算含税总价 = 单价 * 结算面积 * 数量 + 其他金额总和
|
const basePrice = unitPrice * settlePieceArea * quantity;
|
const otherAmountTotal = (productForm.value.salesProductProcessList || []).reduce((total, item) => {
|
return total + (Number(item.unitPrice) || 0) * (Number(item.quantity) || 0);
|
}, 0);
|
productForm.value.taxInclusiveTotalPrice = (basePrice + otherAmountTotal).toFixed(2);
|
|
// 如果有税率,计算不含税总价
|
if (productForm.value.taxRate) {
|
productForm.value.taxExclusiveTotalPrice =
|
proxy.calculateTaxExclusiveTotalPrice(
|
productForm.value.taxInclusiveTotalPrice,
|
productForm.value.taxRate
|
);
|
}
|
|
isCalculating.value = false;
|
};
|
|
// 根据税率变化计算不含税总价
|
const calculateFromTaxRate = () => {
|
if (!productForm.value.taxRate) {
|
proxy.$modal.msgWarning("请先选择税率");
|
return;
|
}
|
if (isCalculating.value) return;
|
|
const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice);
|
const taxRate = parseFloat(productForm.value.taxRate);
|
|
if (!inclusiveTotalPrice || !taxRate) {
|
return;
|
}
|
|
isCalculating.value = true;
|
|
// 计算不含税总价
|
productForm.value.taxExclusiveTotalPrice =
|
proxy.calculateTaxExclusiveTotalPrice(
|
inclusiveTotalPrice,
|
taxRate
|
);
|
|
isCalculating.value = false;
|
};
|
/**
|
* 获取发货状态文本
|
* @param row 行数据
|
*/
|
const getShippingStatusText = (row) => {
|
// 如果已发货(有发货日期或车牌号),显示"已发货"
|
if (row.shippingDate || row.shippingCarNumber) {
|
return '已发货';
|
}
|
|
// 获取发货状态字段
|
const status = row.shippingStatus;
|
|
// 如果状态为空或未定义,默认为"待发货"
|
if (status === null || status === undefined || status === '') {
|
return '待发货';
|
}
|
|
// 状态是字符串
|
const statusStr = String(status).trim();
|
const statusTextMap = {
|
'待发货': '待发货',
|
'待审核': '待审核',
|
'审核中': '审核中',
|
'审核拒绝': '审核拒绝',
|
'审核通过': '审核通过',
|
'已发货': '已发货'
|
};
|
return statusTextMap[statusStr] || '待发货';
|
};
|
|
/**
|
* 获取发货状态标签类型(颜色)
|
* @param row 行数据
|
*/
|
const getShippingStatusType = (row) => {
|
// 如果已发货(有发货日期或车牌号),显示绿色
|
if (row.shippingDate || row.shippingCarNumber) {
|
return 'success';
|
}
|
|
// 获取发货状态字段
|
const status = row.shippingStatus;
|
|
// 如果状态为空或未定义,默认为灰色(待发货)
|
if (status === null || status === undefined || status === '') {
|
return 'info';
|
}
|
|
// 状态是字符串
|
const statusStr = String(status).trim();
|
const typeTextMap = {
|
'待发货': 'info',
|
'待审核': 'info',
|
'审核中': 'warning',
|
'审核拒绝': 'danger',
|
'审核通过': 'success',
|
'已发货': 'success'
|
};
|
return typeTextMap[statusStr] || 'info';
|
};
|
|
/**
|
* 判断是否可以发货
|
* 只有在产品状态是充足,发货状态是待发货和审核拒绝的时候才可以发货
|
* @param row 行数据
|
*/
|
const canShip = (row) => {
|
// 产品状态必须是充足(approveStatus === 1)
|
if (row.approveStatus !== 1) {
|
return false;
|
}
|
|
// 获取发货状态
|
const shippingStatus = row.shippingStatus;
|
|
// 如果已发货(有发货日期或车牌号),不能再次发货
|
if (row.shippingDate || row.shippingCarNumber) {
|
return false;
|
}
|
|
// 发货状态必须是"待发货"或"审核拒绝"
|
const statusStr = shippingStatus ? String(shippingStatus).trim() : '';
|
return statusStr === '待发货' || statusStr === '审核拒绝';
|
};
|
|
const handleBulkDelivery = async () => {
|
if (selectedRows.value.length === 0) {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
|
const customerNames = selectedRows.value.map((r) => String(r.customerName || "").trim());
|
const uniqueCustomers = Array.from(new Set(customerNames));
|
|
// 客户名称不一致不允许发货
|
if (uniqueCustomers.length > 1) {
|
proxy.$modal.msgWarning("客户名称不一致,不允许发货");
|
return;
|
}
|
|
// 多条且客户一致:二次确认
|
if (selectedRows.value.length > 1) {
|
try {
|
await ElMessageBox.confirm("是否确认合并发货?", "合并发货", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
});
|
} catch (e) {
|
proxy.$modal.msg("已取消");
|
return;
|
}
|
}
|
|
proxy.$modal.loading("正在获取产品数据,请稍候...");
|
try {
|
const targets = [];
|
for (const ledger of selectedRows.value) {
|
let products = [];
|
try {
|
const res = await productList({ salesLedgerId: ledger.id, type: 1 });
|
products = res?.data || [];
|
} catch {
|
products = [];
|
}
|
|
for (const product of products) {
|
if (!canShip(product)) continue;
|
targets.push({
|
...product,
|
salesLedgerId: product.salesLedgerId || ledger.id,
|
});
|
}
|
}
|
|
if (targets.length === 0) {
|
proxy.$modal.msgWarning("没有可发货的数据");
|
return;
|
}
|
|
currentDeliveryRows.value = targets;
|
deliveryForm.value = { type: "货车" };
|
// 重置审批人节点(默认一个空节点)
|
approverNodes.value = [{ id: 1, userId: null }];
|
nextApproverId = 2;
|
deliveryFormVisible.value = true;
|
} finally {
|
proxy.$modal.closeLoading();
|
}
|
};
|
|
/**
|
* 下载文件
|
*
|
* @param row 下载文件的相关信息对象
|
*/
|
const fileListRef = ref(null)
|
const fileListDialogVisible = ref(false)
|
const downLoadFile = (row) => {
|
getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => {
|
if (fileListRef.value) {
|
fileListRef.value.open(res.salesLedgerFiles)
|
}
|
});
|
}
|
|
// 打开发货弹框
|
const openDeliveryForm = (row) => {
|
// 检查是否可以发货
|
if (!canShip(row)) {
|
proxy.$modal.msgWarning("只有在产品状态是充足,发货状态是待发货或审核拒绝的时候才可以发货");
|
return;
|
}
|
|
currentDeliveryRows.value = [row];
|
deliveryForm.value = {
|
type: "货车",
|
};
|
// 重置审批人节点(默认一个空节点)
|
approverNodes.value = [{ id: 1, userId: null }];
|
nextApproverId = 2;
|
deliveryFormVisible.value = true;
|
};
|
|
// 提交发货表单
|
const submitDelivery = () => {
|
proxy.$refs["deliveryFormRef"].validate((valid) => {
|
if (valid) {
|
// 审批人必填校验(所有节点都要选人)
|
const hasEmptyApprover = approverNodes.value.some(node => !node.userId);
|
if (hasEmptyApprover) {
|
proxy.$modal.msgError("请为所有审批节点选择审批人!");
|
return;
|
}
|
const approveUserIds = approverNodes.value.map(node => node.userId).join(",");
|
// 保存当前展开的行ID,以便发货后重新加载子表格数据
|
const currentExpandedKeys = [...expandedRowKeys.value];
|
|
const targets = currentDeliveryRows.value || [];
|
if (targets.length === 0) {
|
proxy.$modal.msgWarning("未选择可发货的数据");
|
return;
|
}
|
|
// 依次发货(避免并发下库存扣减/状态更新互相影响)
|
const run = async () => {
|
for (const item of targets) {
|
const salesLedgerId = item.salesLedgerId;
|
if (!salesLedgerId) continue;
|
await addShippingInfo({
|
salesLedgerId,
|
salesLedgerProductId: item.id,
|
type: deliveryForm.value.type,
|
approveUserIds,
|
});
|
}
|
};
|
|
run()
|
.then(() => {
|
proxy.$modal.msgSuccess("发货成功");
|
closeDeliveryDia();
|
// 刷新主表数据
|
getList().then(() => {
|
// 如果之前有展开的行,重新加载这些行的子表格数据
|
if (currentExpandedKeys.length > 0) {
|
const loadPromises = currentExpandedKeys.map((ledgerId) => {
|
return productList({ salesLedgerId: ledgerId, type: 1 }).then((res) => {
|
const index = tableData.value.findIndex((item) => item.id === ledgerId);
|
if (index > -1) {
|
tableData.value[index].children = res.data;
|
}
|
});
|
});
|
Promise.all(loadPromises).then(() => {
|
expandedRowKeys.value = currentExpandedKeys;
|
});
|
}
|
});
|
})
|
.catch(() => {
|
proxy.$modal.msgError("发货失败,请稍后重试");
|
});
|
}
|
});
|
};
|
|
// 关闭发货弹框
|
const closeDeliveryDia = () => {
|
proxy.resetForm("deliveryFormRef");
|
deliveryFormVisible.value = false;
|
currentDeliveryRows.value = [];
|
};
|
const currentFactoryName = ref("");
|
const getCurrentFactoryName = async () => {
|
let res = await userStore.getInfo();
|
currentFactoryName.value = res.user.currentFactoryName;
|
};
|
onMounted(() => {
|
getList();
|
userListNoPage().then(res => {
|
userList.value = res.data;
|
})
|
getCurrentFactoryName();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.ml-10 {
|
margin-left: 10px;
|
}
|
|
::v-deep .yellow {
|
background-color: #FAF0DE;
|
}
|
|
::v-deep .pink {
|
background-color: #FAE1DE;
|
}
|
|
::v-deep .red {
|
background-color: #FAE1DE;
|
}
|
|
::v-deep .purple{
|
background-color: #F4DEFA;
|
}
|
|
.other-amount-select {
|
/* 多选标签区域强制单行,不让输入框随标签换行而拉高高度 */
|
:deep .el-select__tags {
|
display: flex;
|
flex-wrap: nowrap !important;
|
white-space: nowrap;
|
overflow: hidden;
|
max-height: 32px;
|
}
|
}
|
|
.table_list {
|
margin-top: unset;
|
}
|
|
.actions {
|
display: flex;
|
justify-content: space-between;
|
margin-bottom: 10px;
|
}
|
</style>
|