<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-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></div>
|
<div>
|
<el-button type="primary"
|
@click="openForm('add')">
|
新增台账
|
</el-button>
|
<el-button @click="handleOut">导出</el-button>
|
<el-button type="danger"
|
plain
|
@click="handleDelete">删除</el-button>
|
<el-button type="primary"
|
plain
|
@click="handlePrint">打印</el-button>
|
</div>
|
</div>
|
<el-table :data="tableData"
|
border
|
v-loading="tableLoading"
|
@selection-change="handleSelectionChange"
|
:expand-row-keys="expandedRowKeys"
|
:row-key="(row) => row.id"
|
show-summary
|
style="width: 100%"
|
:summary-method="summarizeMainTable"
|
@expand-change="expandChange"
|
height="calc(100vh - 21em)">
|
<el-table-column align="center"
|
type="selection"
|
width="55" />
|
<el-table-column type="expand">
|
<template #default="props">
|
<el-table :data="props.row.children"
|
border
|
show-summary
|
:summary-method="summarizeChildrenTable">
|
<el-table-column align="center"
|
label="序号"
|
type="index"
|
width="60" />
|
<el-table-column label="产品大类"
|
prop="productCategory" />
|
<el-table-column label="规格型号"
|
prop="specificationModel" />
|
<el-table-column label="单位"
|
prop="unit" />
|
<el-table-column label="生产状态"
|
width="100px"
|
align="center">
|
<template #default="scope">
|
<el-tag v-if="scope.row.productionStatus === '已完成'"
|
type="success">已完成</el-tag>
|
<el-tag v-if="scope.row.productionStatus === '生产中'"
|
type="warning">生产中</el-tag>
|
<el-tag v-if="scope.row.productionStatus === '未开始'"
|
type="danger">未开始</el-tag>
|
<el-tag v-if="!scope.row.productionStatus"
|
type="info">暂无状态</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="产品状态"
|
width="100px"
|
align="center">
|
<template #default="scope">
|
<el-tag v-if="scope.row.approveStatus === 0"
|
type="info">未出库</el-tag>
|
<el-tag v-if="scope.row.approveStatus === 1"
|
type="success">已出库</el-tag>
|
<el-tag v-if="scope.row.approveStatus === 2"
|
type="warning">审核中</el-tag>
|
<el-tag v-if="scope.row.approveStatus === 3"
|
type="success">审核成功</el-tag>
|
<el-tag v-if="scope.row.approveStatus === 4"
|
type="danger">审核失败</el-tag>
|
</template>
|
</el-table-column>
|
<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 :disabled="scope.row.approveStatus!==1"
|
link
|
type="primary"
|
size="small"
|
@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="customerContractNo"
|
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="shippingCarNumber"
|
width="120"
|
show-overflow-tooltip>
|
<template #default="scope">
|
<div>
|
<div v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</div>
|
<el-tag v-else
|
type="warning">未发货</el-tag>
|
</div>
|
</template>
|
</el-table-column>
|
<el-table-column label="发货日期"
|
prop="shippingDate"
|
width="120"
|
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 fixed="right"
|
label="操作"
|
min-width="100"
|
align="center">
|
<template #default="scope">
|
<el-button link
|
type="primary"
|
size="small"
|
@click="openForm('edit', scope.row)">编辑</el-button>
|
<!-- <el-button link type="primary" size="small" @click="openForm('view', scope.row)">详情</el-button>-->
|
<el-button link
|
type="primary"
|
size="small"
|
@click="downLoadFile(scope.row)">附件</el-button>
|
<!-- <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">发货</el-button>-->
|
</template>
|
</el-table-column>
|
</el-table>
|
<pagination v-show="total > 0"
|
:total="total"
|
layout="total, sizes, prev, pager, next, jumper"
|
:page="page.current"
|
:limit="page.size"
|
@pagination="paginationChange" />
|
</div>
|
<el-dialog v-model="dialogFormVisible"
|
:title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'"
|
width="70%"
|
@close="closeDia">
|
<el-form :model="form"
|
label-width="140px"
|
label-position="top"
|
:rules="rules"
|
ref="formRef">
|
<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"
|
filterable
|
default-first-option
|
:reserve-keyword="false"
|
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'"
|
filterable>
|
<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="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-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="付款方式">
|
<el-input v-model="form.paymentMethod"
|
placeholder="请输入"
|
clearable
|
:disabled="operationType === 'view'" />
|
</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'" />
|
<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="speculativeTradingName" />-->
|
<el-table-column label="单位"
|
prop="unit" />
|
<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"
|
@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="remark">
|
<el-input v-model="form.remark"
|
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="remark">
|
<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>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary"
|
@click="submitForm">确认</el-button>
|
<el-button @click="closeDia">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
<el-dialog v-model="productFormVisible"
|
:title="productOperationType === 'add' ? '新增产品' : '编辑产品'"
|
width="40%"
|
@close="closeProductDia">
|
<el-form :model="productForm"
|
label-width="140px"
|
label-position="top"
|
:rules="productRules"
|
ref="productFormRef">
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="产品大类:"
|
prop="productCategory">
|
<!-- <el-select v-model="productForm.productCategory" placeholder="请选择" clearable>
|
<el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/>
|
</el-select> -->
|
<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-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="规格型号:"
|
prop="productModelId">
|
<el-select v-model="productForm.productModelId"
|
placeholder="请选择"
|
clearable
|
@change="getProductModel"
|
filterable>
|
<el-option v-for="item in modelOptions"
|
:key="item.id"
|
:label="item.model"
|
:value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<!-- <el-row :gutter="30">-->
|
<!-- <el-col :span="24">-->
|
<!-- <el-form-item label="绑定机器:">-->
|
<!-- <el-input v-model="productForm.speculativeTradingName" placeholder="请先选择规格型号" clearable disabled />-->
|
<!-- </el-form-item>-->
|
<!-- </el-col>-->
|
<!-- </el-row>-->
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="单位:"
|
prop="unit">
|
<el-input v-model="productForm.unit"
|
placeholder="请输入"
|
clearable />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="税率(%):"
|
prop="taxRate">
|
<el-select v-model="productForm.taxRate"
|
placeholder="请选择"
|
clearable
|
@change="calculateFromTaxRate">
|
<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-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<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="12">
|
<el-form-item label="数量:"
|
prop="quantity">
|
<el-input-number :step="0.1"
|
:min="0"
|
v-model="productForm.quantity"
|
placeholder="请输入"
|
clearable
|
:precision="2"
|
@change="calculateFromQuantity"
|
style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="含税总价(元):"
|
prop="taxInclusiveTotalPrice">
|
<el-input v-model="productForm.taxInclusiveTotalPrice"
|
placeholder="请输入"
|
clearable
|
@change="calculateFromTotalPrice" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="不含税总价(元):"
|
prop="taxExclusiveTotalPrice">
|
<el-input v-model="productForm.taxExclusiveTotalPrice"
|
placeholder="请输入"
|
clearable
|
@change="calculateFromExclusiveTotalPrice" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="12">
|
<el-form-item label="发票类型:"
|
prop="invoiceType">
|
<el-select v-model="productForm.invoiceType"
|
placeholder="请选择"
|
clearable>
|
<el-option label="增普票"
|
value="增普票" />
|
<el-option label="增专票"
|
value="增专票" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary"
|
@click="submitProduct">确认</el-button>
|
<el-button @click="closeProductDia">取消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
<!-- 打印预览弹窗 -->
|
<el-dialog v-model="printPreviewVisible"
|
title="打印预览"
|
width="90%"
|
:close-on-click-modal="false"
|
class="print-preview-dialog">
|
<div class="print-preview-container">
|
<div class="print-preview-header">
|
<el-button type="primary"
|
@click="executePrint">执行打印</el-button>
|
<el-button @click="printPreviewVisible = false">关闭预览</el-button>
|
</div>
|
<div class="print-preview-content">
|
<div v-if="printData.length === 0"
|
style="text-align: center; padding: 50px; color: #999;">
|
暂无打印数据
|
</div>
|
<div v-else
|
style="text-align: center; padding: 10px; color: #666; font-size: 14px; background: #e8f4fd; margin-bottom: 10px;">
|
共 {{ printData.length }} 条数据待打印
|
</div>
|
<div v-for="(item, index) in printData"
|
:key="index"
|
class="print-page">
|
<div class="delivery-note">
|
<div class="header">
|
<div class="company-name">{{ currentFactoryName }}</div>
|
<div class="document-title">零售发货单</div>
|
</div>
|
<div class="info-section">
|
<div class="info-row">
|
<div>
|
<span class="label">发货日期:</span>
|
<span class="value">{{ formatDate(item.createTime) }}</span>
|
</div>
|
<div>
|
<span class="label">发货车牌号:</span>
|
<span class="value">{{ item.shippingCarNumber }}</span>
|
</div>
|
</div>
|
<div class="info-row">
|
<div>
|
<span class="label">客户名称:</span>
|
<span class="value">{{ item.customerName || '张爱有' }}</span>
|
</div>
|
<span class="label">单号:</span>
|
<span class="value">{{ item.salesContractNo }}</span>
|
</div>
|
</div>
|
<div class="table-section">
|
<table class="product-table">
|
<thead>
|
<tr>
|
<th>产品名称</th>
|
<th>规格型号</th>
|
<th>单位</th>
|
<th>单价</th>
|
<th>零售数量</th>
|
<th>零售金额</th>
|
</tr>
|
</thead>
|
<tbody>
|
<tr v-for="product in item.products"
|
:key="product.id">
|
<td>{{ product.productCategory || '' }}</td>
|
<td>{{ product.specificationModel || '' }}</td>
|
<td>{{ product.unit || '' }}</td>
|
<td>{{ product.taxInclusiveUnitPrice || '0' }}</td>
|
<td>{{ product.quantity || '0' }}</td>
|
<td>{{ product.taxInclusiveTotalPrice || '0' }}</td>
|
</tr>
|
<tr v-if="!item.products || item.products.length === 0">
|
<td colspan="6"
|
style="text-align: center; color: #999;">暂无产品数据</td>
|
</tr>
|
</tbody>
|
<tfoot>
|
<tr>
|
<td class="label">合计</td>
|
<td class="total-value"></td>
|
<td class="total-value"></td>
|
<td class="total-value"></td>
|
<td class="total-value">{{ getTotalQuantity(item.products) }}</td>
|
<td class="total-value">{{ getTotalAmount(item.products) }}</td>
|
</tr>
|
</tfoot>
|
</table>
|
</div>
|
<div class="footer-section">
|
<div class="footer-row">
|
<div class="footer-item">
|
<span class="label">收货电话:</span>
|
<span class="value"></span>
|
</div>
|
<div class="footer-item">
|
<span class="label">收货人:</span>
|
<span class="value"></span>
|
</div>
|
<div class="footer-item address-item">
|
<span class="label">收货地址:</span>
|
<span class="value address-value"></span>
|
</div>
|
</div>
|
<div class="footer-row">
|
<div class="footer-item">
|
<span class="label">操作员:</span>
|
<span class="value">{{ userStore.nickName || '撕开前' }}</span>
|
</div>
|
<div class="footer-item">
|
<span class="label">打印日期:</span>
|
<span class="value">{{ formatDateTime(new Date()) }}</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</el-dialog>
|
<!-- 发货弹框 -->
|
<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="shippingDate">
|
<el-date-picker style="width: 100%"
|
v-model="deliveryForm.shippingDate"
|
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="24">
|
<el-form-item label="发货车牌号:"
|
prop="shippingCarNumber">
|
<el-input v-model="deliveryForm.shippingCarNumber"
|
placeholder="请输入发货车牌号"
|
clearable />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="30">
|
<el-col :span="24">
|
<el-form-item label="审批人:"
|
prop="approverId">
|
<el-select v-model="deliveryForm.approverId"
|
placeholder="请选择审批人"
|
clearable
|
:disabled="operationType === 'view'">
|
<el-option v-for="item in userList"
|
:key="item.userId"
|
:label="item.nickName"
|
:value="item.userId" />
|
</el-select>
|
</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>
|
<FileList ref="fileListRef" />
|
</div>
|
</template>
|
|
<script setup>
|
import { getToken } from "@/utils/auth";
|
import pagination from "@/components/PIMTable/Pagination.vue";
|
import { onMounted, ref } from "vue";
|
import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
import useUserStore from "@/store/modules/user";
|
import { userListNoPage } from "@/api/system/user.js";
|
import FileList from "./fileList.vue";
|
import {
|
ledgerListPage,
|
productList,
|
customerList,
|
addOrUpdateSalesLedger,
|
getSalesLedgerWithProducts,
|
delLedger,
|
addOrUpdateSalesLedgerProduct,
|
delProduct,
|
delLedgerFile,
|
getProductInventory,
|
} from "@/api/salesManagement/salesLedger.js";
|
import { modelList, productTreeList } from "@/api/basicData/product.js";
|
import useFormData from "@/hooks/useFormData.js";
|
import dayjs from "dayjs";
|
|
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 operationType = ref("");
|
const dialogFormVisible = ref(false);
|
const data = reactive({
|
searchForm: {
|
customerName: "", // 客户名称
|
salesContractNo: "", // 销售合同编号
|
entryDate: null, // 录入日期
|
entryDateStart: undefined,
|
entryDateEnd: undefined,
|
},
|
form: {
|
salesContractNo: "",
|
salesman: "",
|
customerContractNo: "",
|
customerId: "",
|
projectName: "",
|
entryPerson: "",
|
entryDate: "",
|
maintenanceTime: "",
|
productData: [],
|
executionDate: "",
|
},
|
rules: {
|
salesman: [{ required: true, message: "请选择", trigger: "change" }],
|
customerContractNo: [
|
{ required: true, message: "请输入", trigger: "blur" },
|
],
|
customerId: [{ required: true, message: "请选择", trigger: "change" }],
|
projectName: [{ required: true, message: "请输入", trigger: "blur" }],
|
entryPerson: [{ required: true, message: "请选择", trigger: "change" }],
|
entryDate: [{ 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: "",
|
unit: "",
|
quantity: "",
|
taxInclusiveUnitPrice: "",
|
taxRate: "",
|
taxInclusiveTotalPrice: "",
|
taxExclusiveTotalPrice: "",
|
invoiceType: "",
|
speculativeTradingName: "",
|
},
|
productRules: {
|
productCategory: [{ required: true, message: "请选择", trigger: "change" }],
|
productModelId: [{ required: true, message: "请选择", trigger: "change" }],
|
specificationModel: [
|
{ required: true, message: "请选择", trigger: "change" },
|
],
|
unit: [{ 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 printPreviewVisible = ref(false);
|
const printData = ref([]);
|
|
// 发货相关
|
const deliveryFormVisible = ref(false);
|
const currentDeliveryRow = ref(null);
|
const deliveryFormData = reactive({
|
deliveryForm: {
|
shippingDate: "",
|
shippingCarNumber: "",
|
},
|
deliveryRules: {
|
shippingDate: [
|
{ required: true, message: "请选择发货日期", trigger: "change" },
|
],
|
shippingCarNumber: [
|
{ required: true, message: "请输入发货车牌号", trigger: "blur" },
|
],
|
approverId: [
|
{
|
required: true,
|
message: "",
|
},
|
],
|
},
|
});
|
const { deliveryForm, deliveryRules } = toRefs(deliveryFormData);
|
|
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 = async () => {
|
let userLists = await userListNoPage();
|
userList.value = userLists.data;
|
tableLoading.value = true;
|
const { entryDate, ...rest } = searchForm;
|
ledgerListPage({ ...rest, ...page })
|
.then(res => {
|
tableLoading.value = false;
|
tableData.value = res.records;
|
tableData.value.map(item => {
|
item.children = [];
|
});
|
total.value = res.total;
|
})
|
.catch(() => {
|
tableLoading.value = false;
|
});
|
};
|
const currentFactoryName = ref("");
|
const getcurrentFactoryName = async () => {
|
let res = await userStore.getInfo();
|
currentFactoryName.value = res.user.currentFactoryName;
|
};
|
// 获取产品大类tree数据
|
const getProductOptions = () => {
|
productTreeList().then(res => {
|
productOptions.value = convertIdToValue(res);
|
});
|
};
|
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 => {
|
console.log("value", value);
|
const index = modelOptions.value.findIndex(item => item.id === value);
|
if (index !== -1) {
|
productForm.value.specificationModel = modelOptions.value[index].model;
|
productForm.value.unit = modelOptions.value[index].unit;
|
// productForm.value.speculativeTradingName = modelOptions.value[index].speculativeTradingName || "";
|
} else {
|
productForm.value.specificationModel = null;
|
productForm.value.unit = null;
|
productForm.value.speculativeTradingName = "";
|
}
|
};
|
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;
|
});
|
}
|
// 表格选择数据
|
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 => {
|
const rowKey = row.id;
|
const isExpanded = expandedRowKeys.value.includes(rowKey);
|
|
if (isExpanded) {
|
// 当前行已展开 -> 收起
|
expandedRowKeys.value = [];
|
return;
|
}
|
|
// 展开当前行前,先收起其它行
|
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 = [rowKey];
|
});
|
} catch (error) {
|
console.log(error);
|
}
|
};
|
// 主表合计方法
|
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 = [];
|
let userLists = await userListNoPage();
|
userList.value = userLists.data;
|
customerList().then(res => {
|
customerOption.value = res;
|
});
|
form.value.entryPerson = userStore.id;
|
if (type !== "add") {
|
currentId.value = row.id;
|
getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
|
form.value = { ...res };
|
form.value.entryPerson = Number(res.entryPerson);
|
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;
|
};
|
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 = (type, row, index) => {
|
productOperationType.value = type;
|
productForm.value = {};
|
proxy.resetForm("productFormRef");
|
if (type === "edit") {
|
productForm.value = { ...row };
|
productIndex.value = index;
|
}
|
productFormVisible.value = true;
|
getProductOptions();
|
};
|
// 提交产品表单
|
const submitProduct = () => {
|
proxy.$refs["productFormRef"].validate(valid => {
|
if (valid) {
|
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;
|
}
|
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;
|
};
|
// 导出
|
const handleOut = () => {
|
ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
proxy.download("/sales/ledger/export", {}, "销售台账.xlsx");
|
})
|
.catch(() => {
|
proxy.$modal.msg("已取消");
|
});
|
};
|
// 删除
|
const handleDelete = () => {
|
let ids = [];
|
if (selectedRows.value.length > 0) {
|
ids = selectedRows.value.map(item => item.id);
|
} else {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
delLedger(ids).then(res => {
|
proxy.$modal.msgSuccess("删除成功");
|
getList();
|
});
|
})
|
.catch(() => {
|
proxy.$modal.msg("已取消");
|
});
|
};
|
|
// 打印功能
|
const handlePrint = async () => {
|
if (selectedRows.value.length === 0) {
|
proxy.$modal.msgWarning("请选择要打印的数据");
|
return;
|
}
|
|
// 显示加载状态
|
proxy.$modal.loading("正在获取产品数据,请稍候...");
|
|
try {
|
// 为每个选中的销售台账记录查询对应的产品数据
|
const printDataWithProducts = [];
|
|
for (const row of selectedRows.value) {
|
try {
|
// 调用productList接口查询产品数据
|
const productRes = await productList({
|
salesLedgerId: row.id,
|
type: 1,
|
});
|
|
// 将产品数据整合到销售台账记录中
|
const rowWithProducts = {
|
...row,
|
products: productRes.data || [],
|
};
|
|
printDataWithProducts.push(rowWithProducts);
|
} catch (error) {
|
console.error(`获取销售台账 ${row.id} 的产品数据失败:`, error);
|
// 即使某个记录的产品数据获取失败,也要包含该记录
|
printDataWithProducts.push({
|
...row,
|
products: [],
|
});
|
}
|
}
|
|
printData.value = printDataWithProducts;
|
console.log("打印数据(包含产品):", printData.value);
|
printPreviewVisible.value = true;
|
} catch (error) {
|
console.error("获取产品数据失败:", error);
|
proxy.$modal.msgError("获取产品数据失败,请重试");
|
} finally {
|
proxy.$modal.closeLoading();
|
}
|
};
|
// 执行打印
|
const executePrint = () => {
|
console.log("开始执行打印,数据条数:", printData.value.length);
|
console.log("打印数据:", printData.value);
|
|
// 创建一个新的打印窗口
|
const printWindow = window.open("", "_blank", "width=800,height=600");
|
|
// 构建打印内容
|
let printContent = `
|
<!DOCTYPE html>
|
<html>
|
<head>
|
<meta charset="UTF-8">
|
<title>打印预览</title>
|
<style>
|
body {
|
margin: 0;
|
padding: 0;
|
font-family: "SimSun", serif;
|
background: white;
|
}
|
.print-page {
|
width: 200mm;
|
height: 75mm;
|
padding: 10mm;
|
padding-left: 20mm;
|
background: white;
|
box-sizing: border-box;
|
page-break-after: always;
|
page-break-inside: avoid;
|
}
|
.print-page:last-child {
|
page-break-after: avoid;
|
}
|
.delivery-note {
|
width: 100%;
|
height: 100%;
|
font-size: 12px;
|
line-height: 1.2;
|
display: flex;
|
flex-direction: column;
|
color: #000;
|
}
|
.header {
|
text-align: center;
|
margin-bottom: 8px;
|
}
|
.company-name {
|
font-size: 18px;
|
font-weight: bold;
|
margin-bottom: 4px;
|
}
|
.document-title {
|
font-size: 16px;
|
font-weight: bold;
|
}
|
.info-section {
|
margin-bottom: 8px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
}
|
.info-row {
|
line-height: 20px;
|
}
|
.label {
|
font-weight: bold;
|
width: 60px;
|
font-size: 12px;
|
}
|
.value {
|
margin-right: 20px;
|
min-width: 80px;
|
font-size: 12px;
|
}
|
.table-section {
|
margin-bottom: 40px;
|
// flex: 0.6;
|
}
|
.product-table {
|
width: 100%;
|
border-collapse: collapse;
|
border: 1px solid #000;
|
}
|
.product-table th, .product-table td {
|
border: 1px solid #000;
|
padding: 6px;
|
text-align: center;
|
font-size: 12px;
|
line-height: 1.4;
|
}
|
.product-table th {
|
font-weight: bold;
|
}
|
.total-value {
|
font-weight: bold;
|
}
|
.footer-section {
|
margin-top: auto;
|
}
|
.footer-row {
|
display: flex;
|
margin-bottom: 3px;
|
line-height: 22px;
|
justify-content: space-between;
|
}
|
.footer-item {
|
display: flex;
|
margin-right: 20px;
|
}
|
.footer-item .label {
|
font-weight: bold;
|
width: 80px;
|
font-size: 12px;
|
}
|
.footer-item .value {
|
min-width: 80px;
|
font-size: 12px;
|
}
|
.address-item .address-value {
|
min-width: 200px;
|
}
|
@media print {
|
body {
|
margin: 0;
|
padding: 0;
|
}
|
.print-page {
|
margin: 0;
|
padding: 10mm;
|
/* padding-left: 20mm; */
|
page-break-inside: avoid;
|
page-break-after: always;
|
}
|
.print-page:last-child {
|
page-break-after: avoid;
|
}
|
}
|
</style>
|
</head>
|
<body>
|
`;
|
|
// 为每条数据生成打印页面
|
printData.value.forEach((item, index) => {
|
printContent += `
|
<div class="print-page">
|
<div class="delivery-note">
|
<div class="header">
|
<div class="company-name">${
|
currentFactoryName.value
|
}</div>
|
<div class="document-title">零售发货单</div>
|
</div>
|
|
<div class="info-section">
|
<div class="info-row">
|
<div>
|
<span class="label">发货日期:</span>
|
<span class="value">${formatDate(
|
item.createTime
|
)}</span>
|
</div>
|
<div>
|
<span class="label">客户名称:</span>
|
<span class="value">${
|
item.customerName || "张爱有"
|
}</span>
|
</div>
|
</div>
|
<div class="info-row">
|
<span class="label">单号:</span>
|
<span class="value">${
|
item.salesContractNo || ""
|
}</span>
|
</div>
|
</div>
|
|
<div class="table-section">
|
<table class="product-table">
|
<thead>
|
<tr>
|
<th>产品名称</th>
|
<th>规格型号</th>
|
<th>单位</th>
|
<th>单价</th>
|
<th>零售数量</th>
|
<th>零售金额</th>
|
</tr>
|
</thead>
|
<tbody>
|
${
|
item.products &&
|
item.products.length > 0
|
? item.products
|
.map(
|
product => `
|
<tr>
|
<td>${
|
product.productCategory || ""
|
}</td>
|
<td>${
|
product.specificationModel || ""
|
}</td>
|
<td>${product.unit || ""}</td>
|
<td>${
|
product.taxInclusiveUnitPrice ||
|
"0"
|
}</td>
|
<td>${
|
product.quantity || "0"
|
}</td>
|
<td>${
|
product.taxInclusiveTotalPrice ||
|
"0"
|
}</td>
|
</tr>
|
`
|
)
|
.join("")
|
: '<tr><td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td></tr>'
|
}
|
</tbody>
|
<tfoot>
|
<tr>
|
<td class="label">合计</td>
|
<td class="total-value"></td>
|
<td class="total-value"></td>
|
<td class="total-value"></td>
|
<td class="total-value">${getTotalQuantityForPrint(
|
item.products
|
)}</td>
|
<td class="total-value">${getTotalAmountForPrint(
|
item.products
|
)}</td>
|
</tr>
|
</tfoot>
|
</table>
|
</div>
|
|
<div class="footer-section">
|
<div class="footer-row">
|
<div class="footer-item">
|
<span class="label">收货电话:</span>
|
<span class="value"></span>
|
</div>
|
<div class="footer-item">
|
<span class="label">收货人:</span>
|
<span class="value"></span>
|
</div>
|
<div class="footer-item address-item">
|
<span class="label">收货地址:</span>
|
<span class="value address-value"></span>
|
</div>
|
</div>
|
<div class="footer-row">
|
<div class="footer-item">
|
<span class="label">操作员:</span>
|
<span class="value">${
|
userStore.nickName || "撕开前"
|
}</span>
|
</div>
|
<div class="footer-item">
|
<span class="label">打印日期:</span>
|
<span class="value">${formatDateTime(
|
new Date()
|
)}</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
`;
|
});
|
|
printContent += `
|
</body>
|
</html>
|
`;
|
|
// 写入内容到新窗口
|
printWindow.document.write(printContent);
|
printWindow.document.close();
|
|
// 等待内容加载完成后打印
|
printWindow.onload = () => {
|
setTimeout(() => {
|
printWindow.print();
|
printWindow.close();
|
printPreviewVisible.value = false;
|
}, 500);
|
};
|
};
|
// 格式化日期
|
const formatDate = dateString => {
|
if (!dateString) return getCurrentDate();
|
const date = new Date(dateString);
|
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 formatDateTime = date => {
|
const year = date.getFullYear();
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
const day = String(date.getDate()).padStart(2, "0");
|
const hours = String(date.getHours()).padStart(2, "0");
|
const minutes = String(date.getMinutes()).padStart(2, "0");
|
const seconds = String(date.getSeconds()).padStart(2, "0");
|
return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
|
};
|
// 获取当前日期并格式化为 YYYY-MM-DD
|
function getCurrentDate() {
|
const today = new Date();
|
const year = today.getFullYear();
|
const month = String(today.getMonth() + 1).padStart(2, "0"); // 月份从0开始
|
const day = String(today.getDate()).padStart(2, "0");
|
return `${year}-${month}-${day}`;
|
}
|
|
// 计算产品总数量
|
const getTotalQuantity = products => {
|
if (!products || products.length === 0) return "0";
|
const total = products.reduce((sum, product) => {
|
return sum + (parseFloat(product.quantity) || 0);
|
}, 0);
|
return total.toFixed(2);
|
};
|
|
// 计算产品总金额
|
const getTotalAmount = products => {
|
if (!products || products.length === 0) return "0";
|
const total = products.reduce((sum, product) => {
|
return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
|
}, 0);
|
return total.toFixed(2);
|
};
|
|
// 用于打印的计算函数
|
const getTotalQuantityForPrint = products => {
|
if (!products || products.length === 0) return "0";
|
const total = products.reduce((sum, product) => {
|
return sum + (parseFloat(product.quantity) || 0);
|
}, 0);
|
return total.toFixed(2);
|
};
|
|
const getTotalAmountForPrint = products => {
|
if (!products || products.length === 0) return "0";
|
const total = products.reduce((sum, product) => {
|
return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0);
|
}, 0);
|
return total.toFixed(2);
|
};
|
|
const mathNum = () => {
|
console.log("productForm.value", productForm.value);
|
if (!productForm.value.taxInclusiveUnitPrice) {
|
return;
|
}
|
if (!productForm.value.quantity) {
|
return;
|
}
|
// 含税总价计算
|
productForm.value.taxInclusiveTotalPrice =
|
proxy.calculateTaxIncludeTotalPrice(
|
productForm.value.taxInclusiveUnitPrice,
|
productForm.value.quantity
|
);
|
if (productForm.value.taxRate) {
|
// 不含税总价计算
|
productForm.value.taxExclusiveTotalPrice =
|
proxy.calculateTaxExclusiveTotalPrice(
|
productForm.value.taxInclusiveTotalPrice,
|
productForm.value.taxRate
|
);
|
}
|
};
|
|
// 根据含税总价计算含税单价和数量
|
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;
|
|
// 计算含税单价 = 含税总价 / 数量
|
productForm.value.taxInclusiveUnitPrice = (totalPrice / 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);
|
|
// 计算含税单价 = 含税总价 / 数量
|
productForm.value.taxInclusiveUnitPrice = (
|
inclusiveTotalPrice / 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);
|
|
if (!quantity || quantity <= 0 || !unitPrice) {
|
return;
|
}
|
|
isCalculating.value = true;
|
|
// 计算含税总价
|
productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2);
|
|
// 如果有税率,计算不含税总价
|
if (productForm.value.taxRate) {
|
productForm.value.taxExclusiveTotalPrice =
|
proxy.calculateTaxExclusiveTotalPrice(
|
productForm.value.taxInclusiveTotalPrice,
|
productForm.value.taxRate
|
);
|
}
|
|
isCalculating.value = false;
|
};
|
|
// 根据含税单价变化计算总价
|
const calculateFromUnitPrice = () => {
|
if (!productForm.value.taxRate) {
|
proxy.$modal.msgWarning("请先选择税率");
|
return;
|
}
|
if (isCalculating.value) return;
|
|
const quantity = parseFloat(productForm.value.quantity);
|
const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice);
|
|
if (!quantity || quantity <= 0 || !unitPrice) {
|
return;
|
}
|
|
isCalculating.value = true;
|
|
// 计算含税总价
|
productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).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 fileListRef = ref(null);
|
const downLoadFile = row => {
|
getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
|
fileListRef.value.open(res.salesLedgerFiles);
|
});
|
};
|
|
// 打开发货弹框
|
const openDeliveryForm = row => {
|
currentDeliveryRow.value = row;
|
deliveryForm.value = {
|
shippingDate: "", // 移除默认值设置
|
shippingCarNumber: "",
|
};
|
deliveryFormVisible.value = true;
|
};
|
|
// 提交发货表单
|
const submitDelivery = () => {
|
proxy.$refs["deliveryFormRef"].validate(valid => {
|
if (valid) {
|
addShippingInfo({
|
approverId: deliveryForm.value.approverId,
|
salesLedgerId: currentDeliveryRow.value.salesLedgerId,
|
salesLedgerProductId: currentDeliveryRow.value.id,
|
shippingDate: deliveryForm.value.shippingDate,
|
shippingCarNumber: deliveryForm.value.shippingCarNumber,
|
})
|
.then(() => {
|
proxy.$modal.msgSuccess("发货成功");
|
closeDeliveryDia();
|
getList();
|
})
|
.catch(() => {
|
proxy.$modal.msgError("发货失败,请重试");
|
});
|
}
|
});
|
};
|
|
// 关闭发货弹框
|
const closeDeliveryDia = () => {
|
proxy.resetForm("deliveryFormRef");
|
deliveryFormVisible.value = false;
|
currentDeliveryRow.value = null;
|
};
|
|
onMounted(() => {
|
// 设置录入日期范围默认值为当天
|
const today = dayjs().format("YYYY-MM-DD");
|
searchForm.entryDate = [today, today];
|
// 设置范围日期字段的起始和结束时间
|
searchForm.entryDateStart = today;
|
searchForm.entryDateEnd = today;
|
getList();
|
getcurrentFactoryName();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.ml-10 {
|
margin-left: 10px;
|
}
|
|
.table_list {
|
margin-top: unset;
|
}
|
|
.actions {
|
display: flex;
|
justify-content: space-between;
|
margin-bottom: 10px;
|
}
|
.print-preview-dialog {
|
.el-dialog__body {
|
padding: 0;
|
max-height: 80vh;
|
overflow-y: auto;
|
}
|
}
|
|
.print-preview-container {
|
.print-preview-header {
|
padding: 15px;
|
border-bottom: 1px solid #e4e7ed;
|
text-align: center;
|
|
.el-button {
|
margin: 0 10px;
|
}
|
}
|
|
.print-preview-content {
|
padding: 20px;
|
background-color: #f5f5f5;
|
min-height: 400px;
|
}
|
}
|
|
.print-page {
|
width: 220mm;
|
height: 90mm;
|
padding: 10mm;
|
margin: 0 auto;
|
background: white;
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
margin-bottom: 10px;
|
box-sizing: border-box;
|
}
|
|
.delivery-note {
|
width: 100%;
|
height: 100%;
|
font-family: "SimSun", serif;
|
font-size: 10px;
|
line-height: 1.2;
|
display: flex;
|
flex-direction: column;
|
}
|
|
.header {
|
text-align: center;
|
margin-bottom: 8px;
|
|
.company-name {
|
font-size: 18px;
|
font-weight: bold;
|
margin-bottom: 4px;
|
}
|
|
.document-title {
|
font-size: 16px;
|
font-weight: bold;
|
}
|
}
|
|
.info-section {
|
margin-bottom: 8px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
|
.info-row {
|
line-height: 20px;
|
|
.label {
|
font-weight: bold;
|
width: 60px;
|
font-size: 14px;
|
}
|
|
.value {
|
margin-right: 20px;
|
min-width: 80px;
|
font-size: 14px;
|
}
|
}
|
}
|
|
.table-section {
|
margin-bottom: 4px;
|
flex: 1;
|
|
.product-table {
|
width: 100%;
|
border-collapse: collapse;
|
border: 1px solid #000;
|
|
th,
|
td {
|
border: 1px solid #000;
|
padding: 6px;
|
text-align: center;
|
font-size: 14px;
|
line-height: 1.4;
|
}
|
|
th {
|
font-weight: bold;
|
}
|
|
.total-label {
|
text-align: right;
|
font-weight: bold;
|
}
|
|
.total-value {
|
font-weight: bold;
|
}
|
}
|
}
|
|
.footer-section {
|
.footer-row {
|
display: flex;
|
margin-bottom: 3px;
|
line-height: 20px;
|
justify-content: space-between;
|
|
.footer-item {
|
display: flex;
|
margin-right: 20px;
|
|
.label {
|
font-weight: bold;
|
width: 80px;
|
font-size: 14px;
|
}
|
|
.value {
|
min-width: 80px;
|
font-size: 14px;
|
}
|
|
&.address-item {
|
.address-value {
|
min-width: 200px;
|
}
|
}
|
}
|
}
|
}
|
|
@media print {
|
.app-container {
|
display: none;
|
}
|
|
.print-page {
|
box-shadow: none;
|
margin: 0;
|
padding: 10mm;
|
padding-left: 20mm;
|
page-break-inside: avoid;
|
page-break-after: always;
|
}
|
.print-page:last-child {
|
page-break-after: avoid;
|
}
|
}
|
</style>
|