Files
LabelChange-server/batch_query-Old.html
2026-06-01 16:30:29 +08:00

5586 lines
292 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>批量查询接口测试</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<!-- SheetJS for Excel export -->
<script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
<!-- Label 预览模态框 -->
<div class="modal fade" id="labelPreviewModal" tabindex="-1" aria-labelledby="labelPreviewModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="labelPreviewModalLabel">Label 预览</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="labelPreviewContent"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
</head>
<body>
<div class="container mt-5">
<h1 class="text-center mb-5">批量查询换单数据</h1>
<!-- 环境选择 -->
<div class="mb-4">
<label for="environment" class="form-label">环境选择</label>
<select class="form-select" id="environment" style="max-width: 400px;">
<option value="local">本地环境 (http://localhost:5002)</option>
<option value="test" selected>测试环境 (http://172.232.21.79:5002)</option>
<option value="production">生产环境 (https://lr.tooexp.com)</option>
</select>
</div>
<!-- 标签页导航 -->
<ul class="nav nav-tabs" id="queryTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="label-replace-tab" data-bs-toggle="tab" data-bs-target="#label-replace" type="button" role="tab" aria-controls="label-replace" aria-selected="true">标签替换请求</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="label-scan-tab" data-bs-toggle="tab" data-bs-target="#label-scan" type="button" role="tab" aria-controls="label-scan" aria-selected="false">标签扫描记录</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="arrival-handover-tab" data-bs-toggle="tab" data-bs-target="#arrival-handover" type="button" role="tab" aria-controls="arrival-handover" aria-selected="false">到货交接单</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="shipping-handover-tab" data-bs-toggle="tab" data-bs-target="#shipping-handover" type="button" role="tab" aria-controls="shipping-handover" aria-selected="false">出货交接单</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="bag-tag-tab" data-bs-toggle="tab" data-bs-target="#bag-tag" type="button" role="tab" aria-controls="bag-tag" aria-selected="false">集包数据查询</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="order-log-tab" data-bs-toggle="tab" data-bs-target="#order-log" type="button" role="tab" aria-controls="order-log" aria-selected="false">订单日志查询</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="data-dashboard-tab" data-bs-toggle="tab" data-bs-target="#data-dashboard" type="button" role="tab" aria-controls="data-dashboard" aria-selected="false">数据看板</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="order-import-tab" data-bs-toggle="tab" data-bs-target="#order-import" type="button" role="tab" aria-controls="order-import" aria-selected="false">订单导入</button>
</li>
</ul>
<!-- 标签页内容 -->
<div class="tab-content" id="queryTabsContent">
<!-- 标签替换请求查询 -->
<div class="tab-pane fade show active" id="label-replace" role="tabpanel" aria-labelledby="label-replace-tab">
<div class="card mt-4">
<div class="card-header">
<h2 class="h4">标签替换请求查询</h2>
</div>
<div class="card-body">
<!-- 筛选表单 -->
<form id="labelReplaceForm" class="mb-4">
<div class="row g-3">
<div class="col-md-3">
<label for="billOfLadingNumber" class="form-label">提单号</label>
<input type="text" class="form-control" id="billOfLadingNumber" placeholder="请输入提单号">
</div>
<div class="col-md-3">
<label for="masterPackageNumber" class="form-label">大包号</label>
<input type="text" class="form-control" id="masterPackageNumber" placeholder="请输入大包号">
</div>
<div class="col-md-3">
<label for="referenceNumber" class="form-label">参考号</label>
<input type="text" class="form-control" id="referenceNumber" placeholder="请输入参考号">
</div>
<div class="col-md-3">
<label for="neutralWaybillNumber" class="form-label">中性面单单号</label>
<textarea class="form-control" id="neutralWaybillNumber" rows="3" placeholder="请输入中性面单单号,多个单号请换行分隔"></textarea>
</div>
<div class="col-md-3">
<label for="finalMileTrackingNumber" class="form-label">尾程跟踪单号</label>
<input type="text" class="form-control" id="finalMileTrackingNumber" placeholder="请输入尾程跟踪单号">
</div>
<div class="col-md-3">
<label for="replaceStatus" class="form-label">换单状态</label>
<select class="form-select" id="replaceStatus">
<option value="">全部</option>
<option value="Y">正常换单</option>
<option value="N">冻结换单</option>
</select>
</div>
<div class="col-md-3">
<label for="customerId" class="form-label">客户</label>
<select class="form-select" id="customerId">
<option value="">全部</option>
</select>
</div>
<div class="col-md-3">
<label for="startCreatedAt" class="form-label">创建时间开始</label>
<input type="datetime-local" class="form-control" id="startCreatedAt">
</div>
<div class="col-md-3">
<label for="endCreatedAt" class="form-label">创建时间结束</label>
<input type="datetime-local" class="form-control" id="endCreatedAt">
</div>
<div class="col-md-3">
<label for="startReplacedAt" class="form-label">换单完成时间开始</label>
<input type="datetime-local" class="form-control" id="startReplacedAt">
</div>
<div class="col-md-3">
<label for="endReplacedAt" class="form-label">换单完成时间结束</label>
<input type="datetime-local" class="form-control" id="endReplacedAt">
</div>
<div class="col-md-3">
<label for="sortBy" class="form-label">排序字段</label>
<select class="form-select" id="sortBy">
<option value="CreatedAt">创建时间</option>
<option value="Id">ID</option>
<option value="NeutralWaybillNumber">中性面单单号</option>
</select>
</div>
<div class="col-md-3">
<label for="sortOrder" class="form-label">排序顺序</label>
<select class="form-select" id="sortOrder">
<option value="desc">降序</option>
<option value="asc">升序</option>
</select>
</div>
<div class="col-md-3">
<label for="pageSize" class="form-label">每页记录数</label>
<select class="form-select" id="pageSize">
<option value="500">500</option>
<option value="1000">1000</option>
<option value="2000">2000</option>
<option value="custom">自定义</option>
</select>
</div>
<div class="col-md-3" id="customPageSizeContainer" style="display: none;">
<label for="customPageSize" class="form-label">自定义记录数</label>
<input type="number" class="form-control" id="customPageSize" placeholder="请输入记录数" min="1" max="10000">
</div>
<div class="col-md-6 d-flex align-items-end">
<button type="submit" class="btn btn-primary me-2">查询</button>
<button type="button" class="btn btn-secondary" id="resetLabelReplaceForm">重置</button>
</div>
</div>
</form>
<!-- 结果展示 -->
<div id="labelReplaceResult" class="mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="h5">查询结果</h3>
<div class="d-flex align-items-center">
<button type="button" class="btn btn-success me-2" id="exportExcelBtn">导出Excel</button>
<div id="labelReplacePaginationInfo" class="text-muted"></div>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>客户简称</th>
<th>提单号</th>
<th>大包号</th>
<th>中性面单单号</th>
<th>尾程跟踪单号</th>
<th>袋牌号</th>
<th>有无面单</th>
<th>换单状态</th>
<th>换单完成时间</th>
<th>标签推送时间</th>
<th>创建时间</th>
</tr>
</thead>
<tbody id="labelReplaceTableBody">
<tr>
<td colspan="12" class="text-center">请点击查询按钮获取数据</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页控件 -->
<nav id="labelReplacePagination" class="mt-3">
<ul class="pagination justify-content-center"></ul>
</nav>
</div>
</div>
</div>
</div>
<!-- 标签扫描记录查询 -->
<div class="tab-pane fade" id="label-scan" role="tabpanel" aria-labelledby="label-scan-tab">
<div class="card mt-4">
<div class="card-header">
<h2 class="h4">标签扫描记录查询</h2>
</div>
<div class="card-body">
<!-- 筛选表单 -->
<form id="labelScanForm" class="mb-4">
<div class="row g-3">
<div class="col-md-3">
<label for="scanCustomerId" class="form-label">客户</label>
<select class="form-select" id="scanCustomerId">
<option value="">全部</option>
</select>
</div>
<div class="col-md-3">
<label for="scanNeutralWaybillNumber" class="form-label">中性面单单号</label>
<input type="text" class="form-control" id="scanNeutralWaybillNumber" placeholder="请输入中性面单单号">
</div>
<div class="col-md-3">
<label for="scanFinalMileTrackingNumber" class="form-label">尾程跟踪单号</label>
<input type="text" class="form-control" id="scanFinalMileTrackingNumber" placeholder="请输入尾程跟踪单号">
</div>
<div class="col-md-3">
<label for="scanResult" class="form-label">扫描结果</label>
<select class="form-select" id="scanResult">
<option value="">全部</option>
<option value="0">已返回面单</option>
<option value="1">无面单数据</option>
<option value="2">无下单数据</option>
<option value="3">订单被冻结</option>
<option value="4">订单已销毁</option>
<option value="5">其他</option>
</select>
</div>
<div class="col-md-3">
<label for="scanStartCreatedAt" class="form-label">创建时间开始</label>
<input type="datetime-local" class="form-control" id="scanStartCreatedAt">
</div>
<div class="col-md-3">
<label for="scanEndCreatedAt" class="form-label">创建时间结束</label>
<input type="datetime-local" class="form-control" id="scanEndCreatedAt">
</div>
<div class="col-md-3">
<label for="scanSortBy" class="form-label">排序字段</label>
<select class="form-select" id="scanSortBy">
<option value="CreatedAt">创建时间</option>
<option value="Id">ID</option>
<option value="NeutralWaybillNumber">中性面单单号</option>
</select>
</div>
<div class="col-md-3">
<label for="scanSortOrder" class="form-label">排序顺序</label>
<select class="form-select" id="scanSortOrder">
<option value="desc">降序</option>
<option value="asc">升序</option>
</select>
</div>
<div class="col-md-3">
<label for="scanPageSize" class="form-label">每页记录数</label>
<select class="form-select" id="scanPageSize">
<option value="500">500</option>
<option value="1000">1000</option>
<option value="2000">2000</option>
<option value="custom">自定义</option>
</select>
</div>
<div class="col-md-3" id="customScanPageSizeContainer" style="display: none;">
<label for="customScanPageSize" class="form-label">自定义记录数</label>
<input type="number" class="form-control" id="customScanPageSize" placeholder="请输入记录数" min="1" max="10000">
</div>
<div class="col-md-6 d-flex align-items-end">
<button type="submit" class="btn btn-primary me-2">查询</button>
<button type="button" class="btn btn-secondary" id="resetLabelScanForm">重置</button>
</div>
</div>
</form>
<!-- 结果展示 -->
<div id="labelScanResult" class="mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="h5">查询结果</h3>
<div class="d-flex align-items-center">
<button type="button" class="btn btn-success me-2" id="exportScanExcelBtn">导出Excel</button>
<div id="labelScanPaginationInfo" class="text-muted"></div>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>客户简称</th>
<th>中性面单单号</th>
<th>尾程跟踪单号</th>
<th>扫描结果</th>
<th>描述</th>
<th>创建人</th>
<th>创建时间</th>
</tr>
</thead>
<tbody id="labelScanTableBody">
<tr>
<td colspan="10" class="text-center">请点击查询按钮获取数据</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页控件 -->
<nav id="labelScanPagination" class="mt-3">
<ul class="pagination justify-content-center"></ul>
</nav>
</div>
</div>
</div>
</div>
<!-- 到货交接单 -->
<div class="tab-pane fade" id="arrival-handover" role="tabpanel" aria-labelledby="arrival-handover-tab">
<div class="card mt-4">
<div class="card-header">
<h2 class="h4">到货交接单</h2>
</div>
<div class="card-body">
<!-- 功能操作区 -->
<div class="mb-4 p-3 border rounded bg-light">
<div class="row g-3">
<!-- 添加到货交接单 -->
<div class="col-md-8">
<h3 class="h5 mb-3">添加到货交接单</h3>
<!-- 图片上传表单 -->
<form id="uploadArrivalPODForm" action="" method="post" enctype="multipart/form-data" target="uploadFrame" style="display: none;">
<input type="file" id="addPOD" name="files" multiple accept="image/*">
<input type="hidden" name="type" value="arrival">
<input type="hidden" name="handoverNumber" id="arrivalHandoverNumberForUpload">
</form>
<form id="addArrivalHandoverForm" class="mb-4">
<div class="row g-3">
<div class="col-md-4">
<label for="addHandoverNumber" class="form-label">交接单号(头程物流跟踪号,多个请换行)</label>
<textarea class="form-control" id="addHandoverNumber" rows="3" placeholder="请输入交接单号,多个单号请换行分隔" required></textarea>
</div>
<div class="col-md-4">
<label for="addLogisticsProviderArrivalTime" class="form-label">头程物流商送达时间</label>
<input type="datetime-local" class="form-control" id="addLogisticsProviderArrivalTime" required>
</div>
<div class="col-md-4">
<label for="addReceiptTime" class="form-label">收货时间</label>
<input type="datetime-local" class="form-control" id="addReceiptTime" required>
</div>
<div class="col-md-6">
<label for="addPOD" class="form-label">POD图片上传</label>
<input type="file" class="form-control" id="addPOD" multiple accept="image/*">
<small class="form-text text-muted">支持上传多个图片文件</small>
</div>
<div class="col-md-6">
<label class="form-label">已上传图片</label>
<div id="uploadedArrivalPODs" class="mt-2 p-3 border border-dashed border-gray-300 rounded" style="min-height: 120px;">
<p class="text-muted text-center">点击或粘贴图片到此处</p>
</div>
</div>
<div class="col-md-6">
<label for="addRemarks" class="form-label">备注</label>
<textarea class="form-control" id="addRemarks" rows="2" placeholder="请输入备注"></textarea>
</div>
<div class="col-md-12">
<label for="timezone" class="form-label">时区选择</label>
<select class="form-select" id="timezone">
<option value="America/New_York" selected>美国纽约 (东部时间 UTC-5)</option>
<option value="America/Chicago">美国芝加哥 (中部时间 UTC-6)</option>
<option value="America/Denver">美国丹佛 (山地时间 UTC-7)</option>
<option value="America/Los_Angeles">美国洛杉矶 (太平洋时间 UTC-8)</option>
<option value="America/Anchorage">美国安克雷奇 (阿拉斯加时间 UTC-9)</option>
<option value="America/Honolulu">美国檀香山 (夏威夷时间 UTC-10)</option>
<option value="Asia/Shanghai">中国标准时间 (UTC+8)</option>
<option value="UTC">协调世界时 (UTC)</option>
</select>
</div>
<div class="col-md-12 d-flex justify-content-end">
<button type="submit" class="btn btn-primary">添加</button>
</div>
</div>
</form>
</div>
<!-- 查询到货交接单 -->
<div class="col-md-4">
<h3 class="h5 mb-3 p-2 bg-primary text-white rounded">查询条件</h3>
<form id="arrivalHandoverForm" class="mb-4 p-3 border rounded bg-light">
<div class="row g-3">
<div class="col-md-12">
<label for="handoverNumber" class="form-label">交接单号(多个请换行)</label>
<textarea class="form-control" id="handoverNumber" rows="3" placeholder="请输入交接单号,多个单号请换行分隔"></textarea>
</div>
<div class="col-md-6">
<label for="arrivalSortBy" class="form-label">排序字段</label>
<select class="form-select" id="arrivalSortBy">
<option value="CreatedAt">创建时间</option>
<option value="Id">ID</option>
<option value="HandoverNumber">交接单号</option>
</select>
</div>
<div class="col-md-6">
<label for="arrivalSortOrder" class="form-label">排序顺序</label>
<select class="form-select" id="arrivalSortOrder">
<option value="desc">降序</option>
<option value="asc">升序</option>
</select>
</div>
<div class="col-md-6">
<label for="arrivalPageSize" class="form-label">每页记录数</label>
<select class="form-select" id="arrivalPageSize">
<option value="500">500</option>
<option value="1000">1000</option>
<option value="2000">2000</option>
<option value="custom">自定义</option>
</select>
</div>
<div class="col-md-6" id="customArrivalPageSizeContainer" style="display: none;">
<label for="customArrivalPageSize" class="form-label">自定义记录数</label>
<input type="number" class="form-control" id="customArrivalPageSize" placeholder="请输入记录数" min="1" max="10000">
</div>
<div class="col-md-12 d-flex justify-content-end">
<button type="submit" class="btn btn-primary me-2">查询</button>
<button type="button" class="btn btn-secondary" id="resetArrivalHandoverForm">重置</button>
</div>
</div>
</form>
</div>
</div>
</div>
<!-- 结果展示 -->
<div id="arrivalHandoverResult" class="mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="h5">查询结果</h3>
<div class="d-flex align-items-center">
<button type="button" class="btn btn-danger me-2" id="deleteSelectedHandoverForms">删除选中</button>
<div id="arrivalHandoverPaginationInfo" class="text-muted"></div>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th><input type="checkbox" id="selectAllHandoverForms"></th>
<th>ID</th>
<th>客户简称</th>
<th>交接单号</th>
<th>头程物流商送达时间</th>
<th>收货时间</th>
<th>POD</th>
<th>备注</th>
<th>创建人</th>
<th>创建时间</th>
<th>时区</th>
<th>操作</th>
</tr>
</thead>
<tbody id="arrivalHandoverTableBody">
<tr>
<td colspan="11" class="text-center">请点击查询按钮获取数据</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页控件 -->
<nav id="arrivalHandoverPagination" class="mt-3">
<ul class="pagination justify-content-center"></ul>
</nav>
</div>
</div>
</div>
</div>
<!-- 出货交接单 -->
<div class="tab-pane fade" id="shipping-handover" role="tabpanel" aria-labelledby="shipping-handover-tab">
<div class="card mt-4">
<div class="card-header">
<h2 class="h4">出货交接单</h2>
</div>
<div class="card-body">
<!-- 功能操作区 -->
<div class="mb-4 p-3 border rounded bg-light">
<div class="row g-3">
<!-- 添加出货交接单 -->
<div class="col-md-8">
<h3 class="h5 mb-3">添加出货交接单</h3>
<!-- 图片上传表单 -->
<form id="uploadShippingPODForm" action="" method="post" enctype="multipart/form-data" target="uploadFrame" style="display: none;">
<input type="file" id="addShippingPOD" name="files" multiple accept="image/*">
<input type="hidden" name="type" value="shipping">
<input type="hidden" name="handoverNumber" id="shippingHandoverNumberForUpload">
</form>
<form id="addShippingHandoverForm" class="mb-4">
<div class="row g-3">
<div class="col-md-4">
<label for="addShippingHandoverNumber" class="form-label">交接单号</label>
<input type="text" class="form-control" id="addShippingHandoverNumber" placeholder="请输入交接单号,或留空自动生成">
</div>
<div class="col-md-4">
<label for="addChannel" class="form-label">渠道</label>
<select class="form-select" id="addChannel">
<option value="">请选择渠道</option>
<option value="UPS">UPS</option>
<option value="USPS">USPS</option>
<option value="GOFO">GOFO</option>
<option value="UNIUNI">UNIUNI</option>
<option value="SPEEDX">SPEEDX</option>
<option value="YWX">YWX</option>
<option value="SWIFTX">SWIFTX</option>
<option value="FEDEX">FEDEX</option>
</select>
</div>
<div class="col-md-4">
<label for="addDeliveryTime" class="form-label">交货时间</label>
<input type="datetime-local" class="form-control" id="addDeliveryTime">
</div>
<div class="col-md-6">
<label for="addShippingPOD" class="form-label">POD图片上传</label>
<input type="file" class="form-control" id="addShippingPOD" multiple accept="image/*">
<small class="form-text text-muted">支持上传多个图片文件</small>
</div>
<div class="col-md-6">
<label for="addShippingPODUrls" class="form-label">POD链接多个链接用逗号分隔</label>
<input type="text" class="form-control" id="addShippingPODUrls" placeholder="请输入S3链接多个链接用逗号分隔">
<small class="form-text text-muted">可以直接输入预生成的S3链接</small>
</div>
<div class="col-md-12">
<label class="form-label">已上传图片</label>
<div id="uploadedShippingPODs" class="mt-2 p-3 border border-dashed border-gray-300 rounded" style="min-height: 120px;">
<p class="text-muted text-center">点击或粘贴图片到此处</p>
</div>
</div>
<div class="col-md-6">
<label for="addShippingRemarks" class="form-label">备注</label>
<textarea class="form-control" id="addShippingRemarks" rows="2" placeholder="请输入备注"></textarea>
</div>
<div class="col-md-12">
<label for="shippingTimezone" class="form-label">时区选择</label>
<select class="form-select" id="shippingTimezone">
<option value="America/New_York" selected>美国纽约 (东部时间 UTC-5)</option>
<option value="America/Chicago">美国芝加哥 (中部时间 UTC-6)</option>
<option value="America/Denver">美国丹佛 (山地时间 UTC-7)</option>
<option value="America/Los_Angeles">美国洛杉矶 (太平洋时间 UTC-8)</option>
<option value="America/Anchorage">美国安克雷奇 (阿拉斯加时间 UTC-9)</option>
<option value="America/Honolulu">美国檀香山 (夏威夷时间 UTC-10)</option>
<option value="Asia/Shanghai">中国标准时间 (UTC+8)</option>
<option value="UTC">协调世界时 (UTC)</option>
</select>
</div>
<div class="col-md-12 d-flex justify-content-end">
<button type="button" class="btn btn-secondary me-2" id="generateShippingHandoverNumber">生成交接单号</button>
<button type="submit" class="btn btn-primary">添加</button>
</div>
</div>
</form>
</div>
<!-- 关联袋牌 -->
<div class="col-md-4">
<h3 class="h5 mb-3 p-2 bg-primary text-white rounded">关联袋牌</h3>
<form id="associateBagTagsForm" class="mb-4 p-3 border rounded bg-light">
<div class="row g-3">
<div class="col-md-12">
<label for="shippingHandoverFormId" class="form-label">出货交接单ID</label>
<input type="number" class="form-control" id="shippingHandoverFormId" placeholder="请输入出货交接单ID" required>
</div>
<div class="col-md-12">
<label for="bagTagNumbers" class="form-label">袋牌号(多个请换行)</label>
<textarea class="form-control" id="bagTagNumbers" rows="3" placeholder="请输入袋牌号,多个牌号请换行分隔" required></textarea>
</div>
<div class="col-md-12 d-flex justify-content-end">
<button type="submit" class="btn btn-primary">关联</button>
</div>
</div>
</form>
<!-- 查询关联袋牌 -->
<h3 class="h5 mb-3 p-2 bg-primary text-white rounded">查询关联袋牌</h3>
<form id="queryAssociatedBagTagsForm" class="mb-4 p-3 border rounded bg-light">
<div class="row g-3">
<div class="col-md-12">
<label for="queryShippingHandoverFormId" class="form-label">出货交接单ID</label>
<input type="number" class="form-control" id="queryShippingHandoverFormId" placeholder="请输入出货交接单ID" required>
</div>
<div class="col-md-12 d-flex justify-content-end">
<button type="submit" class="btn btn-primary">查询</button>
</div>
</div>
</form>
</div>
</div>
</div>
<!-- 查询出货交接单 -->
<div class="mb-4">
<h3 class="h5 mb-3 p-2 bg-primary text-white rounded">查询条件</h3>
<form id="shippingHandoverForm" class="mb-4 p-3 border rounded bg-light">
<div class="row g-3">
<div class="col-md-3">
<label for="shippingHandoverNumber" class="form-label">交接单号</label>
<input type="text" class="form-control" id="shippingHandoverNumber" placeholder="请输入交接单号">
</div>
<div class="col-md-3">
<label for="shippingChannel" class="form-label">渠道</label>
<select class="form-select" id="shippingChannel">
<option value="">全部</option>
<option value="UPS">UPS</option>
<option value="USPS">USPS</option>
<option value="GOFO">GOFO</option>
<option value="UNIUNI">UNIUNI</option>
<option value="SPEEDX">SPEEDX</option>
<option value="YWX">YWX</option>
<option value="SWIFTX">SWIFTX</option>
<option value="FEDEX">FEDEX</option>
</select>
</div>
<div class="col-md-3">
<label for="shippingCreator" class="form-label">创建人</label>
<input type="text" class="form-control" id="shippingCreator" placeholder="请输入创建人">
</div>
<div class="col-md-3">
<label for="startDeliveryTime" class="form-label">交货时间开始</label>
<input type="datetime-local" class="form-control" id="startDeliveryTime">
</div>
<div class="col-md-3">
<label for="endDeliveryTime" class="form-label">交货时间结束</label>
<input type="datetime-local" class="form-control" id="endDeliveryTime">
</div>
<div class="col-md-3">
<label for="shippingSortBy" class="form-label">排序字段</label>
<select class="form-select" id="shippingSortBy">
<option value="CreatedAt">创建时间</option>
<option value="Id">ID</option>
<option value="HandoverNumber">交接单号</option>
</select>
</div>
<div class="col-md-3">
<label for="shippingSortOrder" class="form-label">排序顺序</label>
<select class="form-select" id="shippingSortOrder">
<option value="desc">降序</option>
<option value="asc">升序</option>
</select>
</div>
<div class="col-md-3">
<label for="shippingPageSize" class="form-label">每页记录数</label>
<select class="form-select" id="shippingPageSize">
<option value="500">500</option>
<option value="1000">1000</option>
<option value="2000">2000</option>
<option value="custom">自定义</option>
</select>
</div>
<div class="col-md-3" id="customShippingPageSizeContainer" style="display: none;">
<label for="customShippingPageSize" class="form-label">自定义记录数</label>
<input type="number" class="form-control" id="customShippingPageSize" placeholder="请输入记录数" min="1" max="10000">
</div>
<div class="col-md-6 d-flex align-items-end">
<button type="submit" class="btn btn-primary me-2">查询</button>
<button type="button" class="btn btn-secondary" id="resetShippingHandoverForm">重置</button>
</div>
</div>
</form>
</div>
<!-- 结果展示 -->
<div id="shippingHandoverResult" class="mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="h5">查询结果</h3>
<div class="d-flex align-items-center">
<button type="button" class="btn btn-danger me-2" id="deleteSelectedShippingHandoverForms">删除选中</button>
<div id="shippingHandoverPaginationInfo" class="text-muted"></div>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th><input type="checkbox" id="selectAllShippingHandoverForms"></th>
<th>ID</th>
<th>交接单号</th>
<th>箱数</th>
<th>交货单量</th>
<th>交货渠道</th>
<th>交货时间</th>
<th>时区</th>
<th>POD</th>
<th>备注</th>
<th>创建人</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="shippingHandoverTableBody">
<tr>
<td colspan="13" class="text-center">请点击查询按钮获取数据</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页控件 -->
<nav id="shippingHandoverPagination" class="mt-3">
<ul class="pagination justify-content-center"></ul>
</nav>
</div>
</div>
</div>
</div>
<!-- 数据看板 -->
<div class="tab-pane fade" id="data-dashboard" role="tabpanel" aria-labelledby="data-dashboard-tab">
<div class="card mt-4">
<div class="card-header">
<h2 class="h4">数据看板</h2>
</div>
<div class="card-body">
<!-- 数据看板查询表单 -->
<form id="dashboardQueryForm" class="mb-4">
<div class="row g-3">
<div class="col-md-4">
<label for="arrivalNumber" class="form-label">交接单号</label>
<input type="text" class="form-control" id="arrivalNumber" placeholder="请输入交接单号">
</div>
<div class="col-md-4">
<label for="dashboardStartDate" class="form-label">开始日期</label>
<input type="date" class="form-control" id="dashboardStartDate">
</div>
<div class="col-md-4">
<label for="dashboardEndDate" class="form-label">结束日期</label>
<input type="date" class="form-control" id="dashboardEndDate">
</div>
<div class="col-md-4">
<label for="dashboardCustomerId" class="form-label">客户</label>
<select class="form-select" id="dashboardCustomerId">
<option value="">全部</option>
</select>
</div>
<div class="col-md-12 d-flex align-items-end">
<button type="submit" class="btn btn-primary me-2">查询</button>
<button type="button" class="btn btn-secondary me-2" id="resetDashboardForm">重置</button>
<button type="button" class="btn btn-warning" id="exportDailyStatsChineseBtn">导出运维监控</button>
</div>
</div>
</form>
<!-- 当天扫描后未下单数量 -->
<div class="mb-4 p-3 border rounded bg-info text-white">
<h3 class="h5 mb-2">当天扫描后未下单数量</h3>
<div class="row">
<div class="col-md-4">
<p><strong>未下单数量:</strong><span id="todayUnorderedCount" class="text-white">0</span></p>
</div>
<div class="col-md-4">
<p><strong>扫描总数:</strong><span id="todayScanTotal" class="text-white">0</span></p>
</div>
<div class="col-md-4">
<p><strong>统计日期:</strong><span id="todayDate" class="text-white"></span></p>
</div>
</div>
</div>
<!-- 结果展示 -->
<div id="dataDashboardResult" class="mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="h5">查询结果</h3>
<div class="d-flex align-items-center">
<button type="button" class="btn btn-success me-2" id="exportDashboardExcelBtn">导出Excel</button>
<div id="dataDashboardPaginationInfo" class="text-muted"></div>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>客户简称</th>
<th>已有标签率</th>
<th>未换单完成数量</th>
<th>提单号</th>
<th>大箱号</th>
<th>到货订单数量</th>
<th>换单完成数量</th>
<th>无标签数据数量</th>
<th>到货时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="dataDashboardTableBody">
<tr>
<td colspan="10" class="text-center">请点击查询按钮获取数据</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页控件 -->
<nav id="dataDashboardPagination" class="mt-3">
<ul class="pagination justify-content-center"></ul>
</nav>
</div>
</div>
</div>
</div>
<!-- 订单导入 -->
<div class="tab-pane fade" id="order-import" role="tabpanel" aria-labelledby="order-import-tab">
<div class="card mt-4">
<div class="card-header">
<h2 class="h4">订单导入</h2>
</div>
<div class="card-body">
<!-- 导入表单 -->
<form id="orderImportForm" class="mb-4">
<div class="row g-3">
<div class="col-md-4">
<label for="importCustomerId" class="form-label">客户选择</label>
<select class="form-select" id="importCustomerId" required>
<option value="">请选择客户</option>
</select>
</div>
<div class="col-md-4">
<label for="labelFilenameMapping" class="form-label">标签文件名映射为:</label>
<select class="form-select" id="labelFilenameMapping" required>
<option value="none"></option>
<option value="neutralWaybill">中性面单单号</option>
<option value="finalMileTracking">尾程单号</option>
</select>
</div>
<div class="col-md-4">
<label for="excelFile" class="form-label">Excel文件</label>
<input type="file" class="form-control" id="excelFile" accept=".xlsx,.xls" required>
<small class="form-text text-muted">支持.xlsx和.xls格式</small>
<div class="mt-2">
<button type="button" class="btn btn-sm btn-outline-secondary" id="downloadTemplateBtn">下载模板</button>
</div>
</div>
<div class="col-md-12">
<label class="form-label">Excel列要求</label>
<div class="p-3 border rounded bg-light">
<p>Excel文件必须包含以下列</p>
<ul>
<li><strong>BillOfLadingNumber</strong> - 提单号(支持纯数字格式)</li>
<li><strong>MasterPackageNumber</strong> - 大包号(支持纯数字格式)</li>
<li><strong>NeutralWaybillNumber</strong> - 中性面单单号(必填)</li>
<li><strong>FinalMileTrackingNumber</strong> - 尾程单号</li>
<li><strong>Label</strong> - 标签内容可选会根据选择的映射生成URL</li>
</ul>
</div>
</div>
<div class="col-md-12 d-flex justify-content-end">
<button type="submit" class="btn btn-primary">导入订单</button>
<button type="button" class="btn btn-secondary ms-2" id="resetOrderImportForm">重置</button>
</div>
</div>
</form>
<!-- 进度显示 -->
<div id="importProgress" class="mb-4" style="display: none;">
<div class="card">
<div class="card-header">
<h3 class="h5">导入进度</h3>
</div>
<div class="card-body">
<div class="progress mb-3">
<div class="progress-bar" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="row">
<div class="col-md-4">
<p><strong>总订单数:</strong><span id="totalOrders">0</span></p>
</div>
<div class="col-md-4">
<p><strong>已处理:</strong><span id="processedOrders">0</span></p>
</div>
<div class="col-md-4">
<p><strong>进度:</strong><span id="progressPercentage">0%</span></p>
</div>
</div>
<div id="importStatus" class="mt-2"></div>
</div>
</div>
</div>
<!-- 结果展示 -->
<div id="importResult" class="mt-4" style="display: none;">
<div class="card">
<div class="card-header">
<h3 class="h5">导入结果</h3>
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-md-3">
<p><strong>总订单数:</strong><span id="resultTotalCount">0</span></p>
</div>
<div class="col-md-3">
<p><strong>成功:</strong><span id="resultSuccessCount" class="text-success">0</span></p>
</div>
<div class="col-md-3">
<p><strong>失败:</strong><span id="resultFailedCount" class="text-danger">0</span></p>
</div>
<div class="col-md-3">
<p><strong>成功率:</strong><span id="resultSuccessRate">0%</span></p>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>提单号</th>
<th>大包号</th>
<th>中性面单单号</th>
<th>尾程单号</th>
<th>状态</th>
<th>消息</th>
<th>标签</th>
</tr>
</thead>
<tbody id="importResultTableBody">
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 面单文件上传 -->
<!-- 订单日志查询 -->
<div class="tab-pane fade" id="order-log" role="tabpanel" aria-labelledby="order-log-tab">
<div class="card mt-4">
<div class="card-header">
<h2 class="h4">订单日志查询</h2>
</div>
<div class="card-body">
<!-- 筛选表单 -->
<form id="orderLogForm" class="mb-4">
<div class="row g-3">
<div class="col-md-6">
<label for="neutralWaybillNumber" class="form-label">中性面单单号</label>
<input type="text" class="form-control" id="orderLogNeutralWaybillNumber" placeholder="请输入中性面单单号">
</div>
<div class="col-md-6">
<label for="finalMileTrackingNumber" class="form-label">尾程单号</label>
<input type="text" class="form-control" id="orderLogFinalMileTrackingNumber" placeholder="请输入尾程单号">
</div>
<div class="col-md-6">
<label for="orderLogSortBy" class="form-label">排序字段</label>
<select class="form-select" id="orderLogSortBy">
<option value="CreatedAt">创建时间</option>
<option value="Id">ID</option>
</select>
</div>
<div class="col-md-6">
<label for="orderLogSortOrder" class="form-label">排序顺序</label>
<select class="form-select" id="orderLogSortOrder">
<option value="desc">降序</option>
<option value="asc">升序</option>
</select>
</div>
<div class="col-md-12 d-flex align-items-end">
<button type="submit" class="btn btn-primary me-2">查询</button>
<button type="button" class="btn btn-secondary" id="resetOrderLogForm">重置</button>
</div>
</div>
</form>
<!-- 结果展示 -->
<div id="orderLogResult" class="mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="h5">查询结果</h3>
<div class="d-flex align-items-center">
<button type="button" class="btn btn-success me-2" id="exportOrderLogExcelBtn">导出Excel</button>
<div id="orderLogPaginationInfo" class="text-muted"></div>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>中性面单单号</th>
<th>尾程单号</th>
<th>操作类型</th>
<th>操作详情</th>
<th>操作人</th>
<th>操作时间</th>
</tr>
</thead>
<tbody id="orderLogTableBody">
<tr>
<td colspan="7" class="text-center">请点击查询按钮获取数据</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页控件 -->
<nav id="orderLogPagination" class="mt-3">
<ul class="pagination justify-content-center"></ul>
</nav>
</div>
</div>
</div>
</div>
<!-- 集包数据查询 -->
<div class="tab-pane fade" id="bag-tag" role="tabpanel" aria-labelledby="bag-tag-tab">
<div class="card mt-4">
<div class="card-header">
<h2 class="h4">集包数据查询</h2>
</div>
<div class="card-body">
<!-- 筛选表单 -->
<form id="bagTagForm" class="mb-4">
<div class="row g-3">
<div class="col-md-3">
<label for="bagTagNumber" class="form-label">袋牌号码</label>
<input type="text" class="form-control" id="bagTagNumber" placeholder="请输入袋牌号码">
</div>
<div class="col-md-3">
<label for="bagTagChannel" class="form-label">渠道</label>
<select class="form-select" id="bagTagChannel">
<option value="">全部</option>
<option value="UPS">UPS</option>
<option value="USPS">USPS</option>
<option value="GOFO">GOFO</option>
<option value="UNIUNI">UNIUNI</option>
<option value="SPEEDX">SPEEDX</option>
<option value="YWX">YWX</option>
<option value="SWIFTX">SWIFTX</option>
<option value="FEDEX">FEDEX</option>
</select>
</div>
<div class="col-md-3">
<label for="bagTagStatus" class="form-label">状态</label>
<select class="form-select" id="bagTagStatus">
<option value="">全部</option>
<option value="Generated">已生成</option>
<option value="Opened">已打开</option>
<option value="Closed">已关闭</option>
</select>
</div>
<div class="col-md-3">
<label for="bagTagCreator" class="form-label">创建人</label>
<input type="text" class="form-control" id="bagTagCreator" placeholder="请输入创建人">
</div>
<div class="col-md-3">
<label for="bagTagStartCreatedAt" class="form-label">创建时间开始</label>
<input type="datetime-local" class="form-control" id="bagTagStartCreatedAt">
</div>
<div class="col-md-3">
<label for="bagTagEndCreatedAt" class="form-label">创建时间结束</label>
<input type="datetime-local" class="form-control" id="bagTagEndCreatedAt">
</div>
<div class="col-md-3">
<label for="bagTagSortBy" class="form-label">排序字段</label>
<select class="form-select" id="bagTagSortBy">
<option value="CreatedAt">创建时间</option>
<option value="Id">ID</option>
<option value="TagNumber">袋牌号码</option>
</select>
</div>
<div class="col-md-3">
<label for="bagTagSortOrder" class="form-label">排序顺序</label>
<select class="form-select" id="bagTagSortOrder">
<option value="desc">降序</option>
<option value="asc">升序</option>
</select>
</div>
<div class="col-md-3">
<label for="bagTagPageSize" class="form-label">每页记录数</label>
<select class="form-select" id="bagTagPageSize">
<option value="500">500</option>
<option value="1000">1000</option>
<option value="2000">2000</option>
<option value="custom">自定义</option>
</select>
</div>
<div class="col-md-3" id="customBagTagPageSizeContainer" style="display: none;">
<label for="customBagTagPageSize" class="form-label">自定义记录数</label>
<input type="number" class="form-control" id="customBagTagPageSize" placeholder="请输入记录数" min="1" max="10000">
</div>
<div class="col-md-6 d-flex align-items-end">
<button type="submit" class="btn btn-primary me-2">查询</button>
<button type="button" class="btn btn-secondary" id="resetBagTagForm">重置</button>
</div>
</div>
</form>
<!-- 结果展示 -->
<div id="bagTagResult" class="mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="h5">查询结果</h3>
<div class="d-flex align-items-center">
<button type="button" class="btn btn-success me-2" id="exportBagTagExcelBtn">导出Excel</button>
<div id="bagTagPaginationInfo" class="text-muted"></div>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>袋牌号码</th>
<th>渠道</th>
<th>状态</th>
<th>创建人</th>
<th>创建时间</th>
<th>打开时间</th>
<th>关闭时间</th>
<th>关联运单数量</th>
<th>操作</th>
</tr>
</thead>
<tbody id="bagTagTableBody">
<tr>
<td colspan="10" class="text-center">请点击查询按钮获取数据</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页控件 -->
<nav id="bagTagPagination" class="mt-3">
<ul class="pagination justify-content-center"></ul>
</nav>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 气泡弹窗 -->
<div id="bubbleNotification" class="fixed inset-0 flex items-center justify-center z-50 pointer-events-none" style="display: none;">
<div class="bg-white rounded-lg shadow-lg p-6 max-w-md mx-auto text-center">
<div class="text-green-500 mb-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<h3 class="text-lg font-medium text-gray-900 mb-2">操作完成</h3>
<p class="text-gray-600" id="bubbleMessage">共找到 0 条记录</p>
</div>
</div>
<!-- 编辑出货交接单模态框 -->
<div class="modal fade" id="editShippingHandoverModal" tabindex="-1" aria-labelledby="editShippingHandoverModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editShippingHandoverModalLabel">编辑出货交接单</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="editShippingHandoverForm">
<input type="hidden" id="editId">
<div class="mb-3">
<label for="editDeliveryTime" class="form-label">交货时间</label>
<input type="datetime-local" class="form-control" id="editDeliveryTime">
</div>
<div class="mb-3">
<label for="editTimezone" class="form-label">时区</label>
<select class="form-select" id="editTimezone">
<option value="America/New_York">美国纽约 (东部时间 UTC-5)</option>
<option value="America/Chicago">美国芝加哥 (中部时间 UTC-6)</option>
<option value="America/Denver">美国丹佛 (山地时间 UTC-7)</option>
<option value="America/Los_Angeles">美国洛杉矶 (太平洋时间 UTC-8)</option>
<option value="America/Anchorage">美国安克雷奇 (阿拉斯加时间 UTC-9)</option>
<option value="America/Honolulu">美国檀香山 (夏威夷时间 UTC-10)</option>
<option value="Asia/Shanghai">中国标准时间 (UTC+8)</option>
<option value="UTC">协调世界时 (UTC)</option>
</select>
</div>
<div class="mb-3">
<label for="editShippingPOD" class="form-label">POD图片上传</label>
<input type="file" class="form-control" id="editShippingPOD" multiple accept="image/*">
<small class="form-text text-muted">支持上传多个图片文件</small>
</div>
<div class="mb-3">
<label for="editShippingPODUrls" class="form-label">POD链接多个链接用逗号分隔</label>
<input type="text" class="form-control" id="editShippingPODUrls" placeholder="请输入S3链接多个链接用逗号分隔">
<small class="form-text text-muted">可以直接输入预生成的S3链接</small>
</div>
<div class="mb-3">
<label class="form-label">已上传图片</label>
<div id="editUploadedShippingPODs" class="mt-2 p-3 border border-dashed border-gray-300 rounded" style="min-height: 120px;">
<p class="text-muted text-center">点击或粘贴图片到此处</p>
</div>
</div>
<div class="mb-3">
<label for="editRemarks" class="form-label">备注</label>
<textarea class="form-control" id="editRemarks" rows="3"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="saveEditBtn">保存</button>
</div>
</div>
</div>
</div>
<!-- 隐藏的iframe用于表单提交 -->
<iframe name="uploadFrame" id="uploadFrame" style="display: none;"></iframe>
<!-- 编辑到货交接单模态框 -->
<div class="modal fade" id="editArrivalHandoverModal" tabindex="-1" aria-labelledby="editArrivalHandoverModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editArrivalHandoverModalLabel">编辑到货交接单</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="editArrivalHandoverForm">
<input type="hidden" id="editArrivalId">
<input type="hidden" id="editArrivalHandoverNumber">
<div class="mb-3">
<label for="editLogisticsProviderArrivalTime" class="form-label">头程物流商送达时间</label>
<input type="datetime-local" class="form-control" id="editLogisticsProviderArrivalTime">
</div>
<div class="mb-3">
<label for="editReceiptTime" class="form-label">收货时间</label>
<input type="datetime-local" class="form-control" id="editReceiptTime">
</div>
<div class="mb-3">
<label for="editArrivalPODUpload" class="form-label">POD图片上传</label>
<input type="file" class="form-control" id="editArrivalPODUpload" multiple accept="image/*">
<small class="form-text text-muted">支持上传多个图片文件</small>
</div>
<div class="mb-3">
<label for="editArrivalPOD" class="form-label">POD链接多个链接用逗号分隔</label>
<input type="text" class="form-control" id="editArrivalPOD" placeholder="请输入S3链接多个链接用逗号分隔">
<small class="form-text text-muted">可以直接输入预生成的S3链接</small>
</div>
<div class="mb-3">
<label class="form-label">已上传图片</label>
<div id="editUploadedArrivalPODs" class="mt-2 p-3 border border-dashed border-gray-300 rounded" style="min-height: 120px;">
<p class="text-muted text-center">点击或粘贴图片到此处</p>
</div>
</div>
<div class="mb-3">
<label for="editArrivalTimezone" class="form-label">时区</label>
<select class="form-select" id="editArrivalTimezone">
<option value="America/New_York">美国纽约 (东部时间 UTC-5)</option>
<option value="America/Chicago">美国芝加哥 (中部时间 UTC-6)</option>
<option value="America/Denver">美国丹佛 (山地时间 UTC-7)</option>
<option value="America/Los_Angeles">美国洛杉矶 (太平洋时间 UTC-8)</option>
<option value="America/Anchorage">美国安克雷奇 (阿拉斯加时间 UTC-9)</option>
<option value="America/Honolulu">美国檀香山 (夏威夷时间 UTC-10)</option>
<option value="Asia/Shanghai">中国标准时间 (UTC+8)</option>
<option value="UTC">协调世界时 (UTC)</option>
</select>
</div>
<div class="mb-3">
<label for="editArrivalRemarks" class="form-label">备注</label>
<textarea class="form-control" id="editArrivalRemarks" rows="3"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="saveArrivalEditBtn">保存</button>
</div>
</div>
</div>
</div>
<!-- POD 预览模态框 -->
<div class="modal fade" id="podPreviewModal" tabindex="-1" aria-labelledby="podPreviewModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="podPreviewModalLabel">POD 预览</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="podPreviewContent"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<style>
/* 气泡弹窗样式 */
.fixed {
position: fixed;
}
.inset-0 {
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.flex {
display: flex;
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.z-50 {
z-index: 50;
}
.pointer-events-none {
pointer-events: none;
}
.bg-white {
background-color: white;
}
.rounded-lg {
border-radius: 0.5rem;
}
.shadow-lg {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.p-6 {
padding: 1.5rem;
}
.max-w-md {
max-width: 28rem;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
}
.text-center {
text-align: center;
}
.text-green-500 {
color: #10b981;
}
.mb-2 {
margin-bottom: 0.5rem;
}
.h-12 {
height: 3rem;
}
.w-12 {
width: 3rem;
}
.text-lg {
font-size: 1.125rem;
}
.font-medium {
font-weight: 500;
}
.text-gray-900 {
color: #111827;
}
.text-gray-600 {
color: #4b5563;
}
/* 表格样式优化 */
.table {
table-layout: auto;
width: 100%;
}
.table th,
.table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.table-responsive {
overflow-x: auto;
}
.cursor-pointer {
cursor: pointer;
}
.cursor-pointer:hover {
text-decoration: underline;
}
</style>
<script>
// 环境配置
const environments = {
local: 'http://localhost:5002',
test: 'http://172.232.21.79:5002',
production: 'https://lr.tooexp.com'
};
// 获取当前环境的基础URL
function getBaseUrl() {
const env = $('#environment').val();
return environments[env] || environments.test;
}
// 显示气泡弹窗
function showBubbleNotification(message) {
const bubble = $('#bubbleNotification');
const bubbleMessage = $('#bubbleMessage');
bubbleMessage.text(message);
bubble.css('display', 'flex');
// 2秒后自动隐藏
setTimeout(() => {
bubble.css('display', 'none');
}, 2000);
}
// JSONP 回调函数
function jsonpCallback(response) {
// 这个函数会被后端返回的 JavaScript 代码调用
console.log('JSONP response:', response);
}
// 客户列表回调函数
function customerListCallback(response) {
if (response.status === 'ok') {
// 填充标签替换请求的客户下拉框
const customerSelect = $('#customerId');
customerSelect.empty();
customerSelect.append('<option value="">全部</option>');
// 填充标签扫描记录的客户下拉框
const scanCustomerSelect = $('#scanCustomerId');
scanCustomerSelect.empty();
scanCustomerSelect.append('<option value="">全部</option>');
scanCustomerSelect.append('<option value="0">无客户</option>');
// 填充订单导入的客户下拉框
const importCustomerSelect = $('#importCustomerId');
importCustomerSelect.empty();
importCustomerSelect.append('<option value="">请选择客户</option>');
// 填充数据看板的客户下拉框
const dashboardCustomerSelect = $('#dashboardCustomerId');
dashboardCustomerSelect.empty();
dashboardCustomerSelect.append('<option value="">全部</option>');
response.data.forEach(customer => {
customerSelect.append(`<option value="${customer.Id}">${customer.CustomerCode}</option>`);
scanCustomerSelect.append(`<option value="${customer.Id}">${customer.CustomerCode}</option>`);
importCustomerSelect.append(`<option value="${customer.Id}">${customer.CustomerCode}</option>`);
dashboardCustomerSelect.append(`<option value="${customer.Id}">${customer.CustomerCode}</option>`);
});
}
}
// 生成出货交接单号回调函数
function generateShippingHandoverNumberCallback(response) {
console.log('Generate shipping handover number response:', response);
if (response && response.code === 0 && response.data) {
$('#addShippingHandoverNumber').val(response.data);
showBubbleNotification('成功生成交接单号');
} else {
showBubbleNotification('生成失败: ' + (response ? response.message : '未知错误'));
}
}
// 获取客户列表
function loadCustomerList() {
const url = getBaseUrl() + '/api/Label/customers';
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'customerListCallback',
success: function(response) {
console.log('Customer list loaded:', response);
},
error: function(xhr, status, error) {
console.error('Failed to load customer list:', error);
}
});
}
// 页面加载完成后获取客户列表
$(document).ready(function() {
loadCustomerList();
// 环境切换时重新加载客户列表
$('#environment').change(function() {
loadCustomerList();
showBubbleNotification('环境已切换,正在加载对应环境的客户列表...');
});
// 订单日志查询表单提交
$('#orderLogForm').submit(function(e) {
e.preventDefault();
queryOrderLog();
});
// 重置订单日志查询表单
$('#resetOrderLogForm').click(function() {
$('#orderLogNeutralWaybillNumber').val('');
$('#orderLogFinalMileTrackingNumber').val('');
$('#orderLogSortBy').val('CreatedAt');
$('#orderLogSortOrder').val('desc');
});
// 导出订单日志Excel
$('#exportOrderLogExcelBtn').click(function() {
exportOrderLogToExcel();
});
// 提单号预报表单提交
// 数据看板表单提交
$('#dashboardQueryForm').submit(function(e) {
e.preventDefault();
queryDashboard();
});
// 重置数据看板表单
$('#resetDashboardForm').click(function() {
$('#arrivalNumber').val('');
$('#dashboardStartDate').val('');
$('#dashboardEndDate').val('');
$('#dashboardCustomerId').val('');
});
// 导出数据看板Excel
$('#exportDashboardExcelBtn').click(function() {
exportDashboardToExcel();
});
// 导出运维监控数据Excel
$('#exportDailyStatsChineseBtn').click(function() {
exportDailyStatsChineseToExcel();
});
// 加载当天扫描后未下单数量
loadTodayUnorderedCount();
});
// 生成GUID与后端一致
function generateGuid() {
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// 订单日志查询
function queryOrderLog() {
const neutralWaybillNumber = $('#orderLogNeutralWaybillNumber').val().trim();
const finalMileTrackingNumber = $('#orderLogFinalMileTrackingNumber').val().trim();
const sortBy = $('#orderLogSortBy').val();
const sortOrder = $('#orderLogSortOrder').val();
if (!neutralWaybillNumber && !finalMileTrackingNumber) {
showBubbleNotification('请至少输入中性面单单号或尾程单号');
return;
}
const baseUrl = getBaseUrl();
const url = baseUrl + '/api/order-log/query';
$.ajax({
url: url,
type: 'GET',
data: {
neutralWaybillNumber: neutralWaybillNumber,
finalMileTrackingNumber: finalMileTrackingNumber,
sortBy: sortBy,
sortOrder: sortOrder
},
dataType: 'jsonp',
jsonp: 'callback',
success: function(response) {
console.log('Order log query response:', response);
if (response && response.code === 0) {
displayOrderLogResult(response.data);
showBubbleNotification(`共找到 ${response.data.length} 条订单日志记录`);
} else {
showBubbleNotification('查询失败: ' + (response ? response.message : '未知错误'));
$('#orderLogTableBody').html('<tr><td colspan="7" class="text-center">查询失败</td></tr>');
}
},
error: function(xhr, status, error) {
console.error('Failed to query order log:', error);
showBubbleNotification('查询失败: ' + error);
$('#orderLogTableBody').html('<tr><td colspan="7" class="text-center">查询失败</td></tr>');
}
});
}
// 展示订单日志查询结果
function displayOrderLogResult(data) {
const tableBody = $('#orderLogTableBody');
tableBody.empty();
if (!data || data.length === 0) {
tableBody.html('<tr><td colspan="7" class="text-center">无数据</td></tr>');
return;
}
data.forEach(item => {
const row = $('<tr></tr>');
row.append(`<td>${item.Id || ''}</td>`);
row.append(`<td>${item.NeutralWaybillNumber || ''}</td>`);
row.append(`<td>${item.FinalMileTrackingNumber || ''}</td>`);
row.append(`<td>${item.OperationType || ''}</td>`);
row.append(`<td>${item.OperationDetails || ''}</td>`);
row.append(`<td>${item.Operator || ''}</td>`);
row.append(`<td>${item.CreatedAt || ''}</td>`);
tableBody.append(row);
});
}
// 导出订单日志到Excel
function exportOrderLogToExcel() {
const neutralWaybillNumber = $('#orderLogNeutralWaybillNumber').val().trim();
const finalMileTrackingNumber = $('#orderLogFinalMileTrackingNumber').val().trim();
const sortBy = $('#orderLogSortBy').val();
const sortOrder = $('#orderLogSortOrder').val();
if (!neutralWaybillNumber && !finalMileTrackingNumber) {
showBubbleNotification('请至少输入中性面单单号或尾程单号');
return;
}
const baseUrl = getBaseUrl();
const url = baseUrl + '/api/order-log/export';
// 构建导出URL
let exportUrl = url + '?';
if (neutralWaybillNumber) exportUrl += `neutralWaybillNumber=${encodeURIComponent(neutralWaybillNumber)}&`;
if (finalMileTrackingNumber) exportUrl += `finalMileTrackingNumber=${encodeURIComponent(finalMileTrackingNumber)}&`;
exportUrl += `sortBy=${encodeURIComponent(sortBy)}&sortOrder=${encodeURIComponent(sortOrder)}`;
// 打开导出链接
window.open(exportUrl, '_blank');
}
// 预生成S3链接
function generateS3Url(type, handoverNumber, fileName, uniqueId) {
const endpoint = 'https://pod.us-ord-1.linodeobjects.com';
const yearMonth = new Date().toISOString().slice(0, 7).replace('-', '');
let prefix = '';
if (type === 'arrival') {
prefix = `arrivalhandover/${yearMonth}/`;
} else if (type === 'shipping') {
prefix = `shippinghandover/${yearMonth}/`;
} else {
prefix = 'pod/';
}
const objectKey = `${prefix}${handoverNumber}_${uniqueId}_${fileName}`;
return `${endpoint}/${objectKey}`;
}
// 传统表单提交上传文件
function uploadFilesWithForm(files, type, handoverNumber, uniqueIds) {
let formId, handoverNumberInputId;
if (type === 'arrival') {
formId = 'uploadArrivalPODForm';
handoverNumberInputId = 'arrivalHandoverNumberForUpload';
} else if (type === 'shipping') {
formId = 'uploadShippingPODForm';
handoverNumberInputId = 'shippingHandoverNumberForUpload';
} else {
return false;
}
// 获取当前环境的基础URL
const baseUrl = getBaseUrl();
// 设置表单的action属性
document.getElementById(formId).action = baseUrl + '/api/upload';
// 设置交接单号
$('#' + handoverNumberInputId).val(handoverNumber);
// 为每个文件添加唯一ID到表单
const form = document.getElementById(formId);
// 移除旧的uniqueIds输入
const oldInputs = form.querySelectorAll('input[name="uniqueIds"]');
oldInputs.forEach(input => input.remove());
// 移除旧的文件输入
const oldFileInput = form.querySelector('input[type="file"]');
if (oldFileInput) {
oldFileInput.remove();
}
// 添加新的文件输入
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.name = 'files';
fileInput.multiple = true;
fileInput.accept = 'image/*';
fileInput.id = type === 'arrival' ? 'addPOD' : 'addShippingPOD';
form.appendChild(fileInput);
// 复制文件到新的文件输入
const dataTransfer = new DataTransfer();
for (let i = 0; i < files.length; i++) {
dataTransfer.items.add(files[i]);
}
fileInput.files = dataTransfer.files;
// 添加新的uniqueIds输入
for (let i = 0; i < files.length; i++) {
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'uniqueIds';
// 使用传入的uniqueId或生成新的
input.value = uniqueIds && uniqueIds[i] ? uniqueIds[i] : generateGuid();
form.appendChild(input);
}
// 提交表单
form.submit();
return true;
}
// 数据看板查询
function queryDashboard() {
const arrivalNumber = $('#arrivalNumber').val().trim();
const startDate = $('#dashboardStartDate').val();
const endDate = $('#dashboardEndDate').val();
const customerId = $('#dashboardCustomerId').val();
const baseUrl = getBaseUrl();
const url = baseUrl + '/api/dashboard/query';
$.ajax({
url: url,
type: 'GET',
data: {
arrivalNumber: arrivalNumber,
startDate: startDate,
endDate: endDate,
customerId: customerId
},
dataType: 'jsonp',
jsonp: 'callback',
success: function(response) {
console.log('Dashboard query response:', response);
if (response && response.code === 0) {
displayDataDashboardResult(response.data);
loadTodayUnorderedCount();
showBubbleNotification(`共找到 ${response.data.length} 条记录`);
} else {
showBubbleNotification('查询失败: ' + (response ? response.message : '未知错误'));
$('#dataDashboardTableBody').html('<tr><td colspan="10" class="text-center">查询失败</td></tr>');
}
},
error: function(xhr, status, error) {
console.error('Failed to query dashboard:', error);
showBubbleNotification('查询失败: ' + error);
$('#dataDashboardTableBody').html('<tr><td colspan="10" class="text-center">查询失败</td></tr>');
}
});
}
// 展示数据看板查询结果
function displayDataDashboardResult(data) {
const tableBody = $('#dataDashboardTableBody');
tableBody.empty();
if (!data || data.length === 0) {
tableBody.html('<tr><td colspan="10" class="text-center">无数据</td></tr>');
return;
}
data.forEach(item => {
const row = $('<tr></tr>');
row.append(`<td>${item.CustomerCode || ''}</td>`);
row.append(`<td>${item.LabelRate || '0%'}</td>`);
row.append(`<td>${item.ReplacePendingCount || 0}</td>`);
row.append(`<td>${item.BillOfLadingNumber || ''}</td>`);
row.append(`<td>${item.MasterPackageNumber || ''}</td>`);
row.append(`<td>${item.ArrivalOrderCount || 0}</td>`);
row.append(`<td>${item.ReplaceCompletedCount || 0}</td>`);
row.append(`<td>${item.NoLabelDataCount || 0}</td>`);
const arrivalTime = item.ArrivalTime ? item.ArrivalTime.replace('T', ' ') : '';
row.append(`<td>${arrivalTime}</td>`);
row.append(`<td><button class="btn btn-sm btn-primary viewDetails" data-arrival="${item.ArrivalNumber || ''}">查看详情</button></td>`);
tableBody.append(row);
});
$('.viewDetails').click(function() {
const arrival = $(this).data('arrival');
showBubbleNotification(`查看交接单 ${arrival} 的详情`);
});
}
// 加载当天扫描后未下单数量
function loadTodayUnorderedCount() {
const baseUrl = getBaseUrl();
const url = baseUrl + '/api/dashboard/today-unordered';
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
success: function(response) {
console.log('Today unordered count response:', response);
if (response && response.code === 0) {
const data = response.data;
$('#todayUnorderedCount').text(data.unorderedCount || 0);
$('#todayScanTotal').text(data.totalCount || 0);
$('#todayDate').text(data.date || '');
}
},
error: function(xhr, status, error) {
console.error('Failed to load today unordered count:', error);
}
});
}
// 导出数据看板到Excel
function exportDashboardToExcel() {
let dashboardType, billOfLadingNumber, masterPackageNumber, startDate, endDate, customerId;
// 检测当前激活的标签页
if ($('#bill-of-lading-tab').hasClass('active')) {
// 提单号预报
dashboardType = 'billOfLading';
billOfLadingNumber = $('#billOfLadingNumber').val().trim();
startDate = $('#billOfLadingStartDate').val();
endDate = $('#billOfLadingEndDate').val();
customerId = $('#billOfLadingCustomerId').val();
masterPackageNumber = '';
} else if ($('#master-package-tab').hasClass('active')) {
// 大箱号预报
dashboardType = 'masterPackage';
masterPackageNumber = $('#masterPackageNumber').val().trim();
startDate = $('#masterPackageStartDate').val();
endDate = $('#masterPackageEndDate').val();
customerId = $('#masterPackageCustomerId').val();
billOfLadingNumber = '';
} else {
// 默认提单号预报
dashboardType = 'billOfLading';
billOfLadingNumber = $('#billOfLadingNumber').val().trim();
startDate = $('#billOfLadingStartDate').val();
endDate = $('#billOfLadingEndDate').val();
customerId = $('#billOfLadingCustomerId').val();
masterPackageNumber = '';
}
const baseUrl = getBaseUrl();
const url = baseUrl + '/api/dashboard/export';
// 构建导出URL
let exportUrl = url + '?';
exportUrl += `type=${encodeURIComponent(dashboardType)}&`;
if (billOfLadingNumber) exportUrl += `billOfLadingNumber=${encodeURIComponent(billOfLadingNumber)}&`;
if (masterPackageNumber) exportUrl += `masterPackageNumber=${encodeURIComponent(masterPackageNumber)}&`;
if (startDate) exportUrl += `startDate=${encodeURIComponent(startDate)}&`;
if (endDate) exportUrl += `endDate=${encodeURIComponent(endDate)}&`;
if (customerId) exportUrl += `customerId=${encodeURIComponent(customerId)}`;
// 打开导出链接
window.open(exportUrl, '_blank');
}
// 导出运维监控数据Excel
function exportDailyStatsChineseToExcel() {
const baseUrl = getBaseUrl();
const url = baseUrl + '/api/dashboard/daily-stats-chinese/export-excel';
// 打开导出链接
window.open(url, '_blank');
}
// 显示已上传的图片
function displayUploadedImages(containerId, imageUrls) {
const container = $('#' + containerId);
container.empty();
imageUrls.forEach(url => {
const imgDiv = $('<div class="d-inline-block mr-2 mb-2" style="position: relative;"></div>');
const img = $('<img src="' + url + '" style="width: 100px; height: 100px; object-fit: cover; border: 1px solid #ddd; border-radius: 4px;">');
const removeBtn = $('<button type="button" class="btn btn-sm btn-danger" style="position: absolute; top: -5px; right: -5px; border-radius: 50%; width: 20px; height: 20px; padding: 0; display: flex; align-items: center; justify-content: center;">×</button>');
removeBtn.click(function() {
imgDiv.remove();
});
imgDiv.append(img);
imgDiv.append(removeBtn);
container.append(imgDiv);
});
}
// 初始化图片粘贴和点击功能
function initImagePaste() {
// 为到货交接单POD区域添加粘贴事件
$('#uploadedArrivalPODs').on('paste', function(e) {
handlePaste(e, 'addPOD', 'uploadedArrivalPODs', function(imageUrls) {
// 处理上传后的图片URL
console.log('Arrival POD images uploaded:', imageUrls);
// 将S3 URL添加到POD链接输入框
if (imageUrls && imageUrls.length > 0) {
const currentUrls = $('#editArrivalPOD').val().trim();
const newUrls = currentUrls ? currentUrls + ',' + imageUrls.join(',') : imageUrls.join(',');
$('#editArrivalPOD').val(newUrls);
}
});
});
// 为到货交接单POD区域添加点击事件
$('#uploadedArrivalPODs').on('click', function() {
$('#addPOD').click();
});
// 为出货交接单POD区域添加粘贴事件
$('#uploadedShippingPODs').on('paste', function(e) {
handlePaste(e, 'addShippingPOD', 'uploadedShippingPODs', function(imageUrls) {
// 处理上传后的图片URL
console.log('Shipping POD images uploaded:', imageUrls);
// 将S3 URL添加到POD链接输入框
if (imageUrls && imageUrls.length > 0) {
const currentUrls = $('#addShippingPODUrls').val().trim();
const newUrls = currentUrls ? currentUrls + ',' + imageUrls.join(',') : imageUrls.join(',');
$('#addShippingPODUrls').val(newUrls);
}
});
});
// 为出货交接单POD区域添加点击事件
$('#uploadedShippingPODs').on('click', function() {
$('#addShippingPOD').click();
});
// 为编辑到货交接单POD区域添加粘贴事件
$('#editUploadedArrivalPODs').on('paste', function(e) {
handlePaste(e, 'editArrivalPODUpload', 'editUploadedArrivalPODs', function(imageUrls) {
// 处理上传后的图片URL
console.log('Edit Arrival POD images uploaded:', imageUrls);
// 将S3 URL添加到POD链接输入框
if (imageUrls && imageUrls.length > 0) {
const currentUrls = $('#editArrivalPOD').val().trim();
const newUrls = currentUrls ? currentUrls + ',' + imageUrls.join(',') : imageUrls.join(',');
$('#editArrivalPOD').val(newUrls);
}
});
});
// 为编辑到货交接单POD区域添加点击事件
$('#editUploadedArrivalPODs').on('click', function(e) {
// 只有当点击的是空白区域时才触发文件选择器
if (e.target === this) {
$('#editArrivalPODUpload').click();
}
});
// 为编辑出货交接单POD区域添加粘贴事件
$('#editUploadedShippingPODs').on('paste', function(e) {
handlePaste(e, 'editShippingPOD', 'editUploadedShippingPODs', function(imageUrls) {
// 处理上传后的图片URL
console.log('Edit Shipping POD images uploaded:', imageUrls);
// 将S3 URL添加到POD链接输入框
if (imageUrls && imageUrls.length > 0) {
const currentUrls = $('#editShippingPODUrls').val().trim();
const newUrls = currentUrls ? currentUrls + ',' + imageUrls.join(',') : imageUrls.join(',');
$('#editShippingPODUrls').val(newUrls);
}
});
});
// 为编辑出货交接单POD区域添加点击事件
$('#editUploadedShippingPODs').on('click', function(e) {
// 只有当点击的是空白区域时才触发文件选择器
if (e.target === this) {
$('#editShippingPOD').click();
}
});
}
// 处理粘贴事件
function handlePaste(e, fileInputId, containerId, callback) {
e.preventDefault(); // 阻止默认粘贴行为,避免打开文件管理
const items = e.originalEvent.clipboardData.items;
const files = [];
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf('image') !== -1) {
const file = items[i].getAsFile();
if (file) {
files.push(file);
}
}
}
if (files.length > 0) {
// 将粘贴的文件添加到文件输入控件
const fileInput = document.getElementById(fileInputId);
const dataTransfer = new DataTransfer();
// 保留原有文件
if (fileInput.files) {
for (let i = 0; i < fileInput.files.length; i++) {
dataTransfer.items.add(fileInput.files[i]);
}
}
// 添加新粘贴的文件
files.forEach(file => {
dataTransfer.items.add(file);
});
fileInput.files = dataTransfer.files;
// 显示预览图片(本地预览,不上传)
files.forEach(file => {
const reader = new FileReader();
reader.onload = function(e) {
const imgDiv = $('<div class="d-inline-block mr-2 mb-2" style="position: relative;"></div>');
const img = $('<img src="' + e.target.result + '" style="width: 100px; height: 100px; object-fit: cover; border: 1px solid #ddd; border-radius: 4px;">');
const removeBtn = $('<button type="button" class="btn btn-sm btn-danger" style="position: absolute; top: -5px; right: -5px; border-radius: 50%; width: 20px; height: 20px; padding: 0; display: flex; align-items: center; justify-content: center;">×</button>');
removeBtn.click(function() {
imgDiv.remove();
// 从文件输入控件中移除对应的文件
removeFileFromInput(fileInput, file);
});
imgDiv.append(img);
imgDiv.append(removeBtn);
$('#' + containerId).append(imgDiv);
};
reader.readAsDataURL(file);
});
}
}
// 从文件输入控件中移除指定文件
function removeFileFromInput(fileInput, fileToRemove) {
const dataTransfer = new DataTransfer();
for (let i = 0; i < fileInput.files.length; i++) {
const file = fileInput.files[i];
// 通过文件名和大小来匹配文件
if (file.name !== fileToRemove.name || file.size !== fileToRemove.size) {
dataTransfer.items.add(file);
}
}
fileInput.files = dataTransfer.files;
}
$(document).ready(function() {
loadCustomerList();
// 初始化图片粘贴功能
initImagePaste();
// POD 预览按钮点击事件
$(document).on('click', '.preview-pod-btn', function() {
const pod = $(this).data('pod');
const previewContent = $('#podPreviewContent');
// 清空预览内容
previewContent.empty();
// 检查 POD 是否包含多个链接(逗号分隔)
const podItems = pod.split(',').map(item => item.trim());
if (podItems.length > 1) {
// 多个 POD 链接,显示为图片列表
const gallery = $('<div class="row"></div>');
podItems.forEach(item => {
if (item) {
if (item.startsWith('http')) {
// 图片链接
const col = $('<div class="col-md-6 mb-3"></div>');
const img = $('<img>').attr('src', item).addClass('img-fluid rounded').css('max-height', '300px');
col.append(img);
gallery.append(col);
} else {
// 文本内容
const col = $('<div class="col-md-12 mb-3"></div>');
const p = $('<p>').text(item).addClass('border p-3 rounded bg-light');
col.append(p);
gallery.append(col);
}
}
});
previewContent.append(gallery);
} else if (podItems.length === 1 && podItems[0]) {
const item = podItems[0];
if (item.startsWith('http')) {
// 单个图片链接
const img = $('<img>').attr('src', item).addClass('img-fluid rounded').css('max-height', '500px');
previewContent.append(img);
} else {
// 单个文本内容
const p = $('<p>').text(item).addClass('border p-3 rounded bg-light');
previewContent.append(p);
}
} else {
// 空 POD
previewContent.append('<p class="text-muted">无 POD 内容</p>');
}
// 显示模态框
$('#podPreviewModal').modal('show');
});
// 保存编辑按钮点击事件
$('#saveEditBtn').click(function() {
saveShippingHandoverEdit();
});
// 保存到货交接单编辑按钮点击事件
$('#saveArrivalEditBtn').click(function() {
saveArrivalHandoverEdit();
});
// 为文件选择器添加变化事件,显示预览图片
$('#addPOD').change(function(e) {
const files = e.target.files;
const containerId = 'uploadedArrivalPODs';
if (files.length > 0) {
// 清空容器
$('#' + containerId).empty();
// 显示预览图片
for (let i = 0; i < files.length; i++) {
const file = files[i];
const reader = new FileReader();
reader.onload = function(e) {
const imgDiv = $('<div class="d-inline-block mr-2 mb-2" style="position: relative;"></div>');
const img = $('<img src="' + e.target.result + '" style="width: 100px; height: 100px; object-fit: cover; border: 1px solid #ddd; border-radius: 4px;">');
const removeBtn = $('<button type="button" class="btn btn-sm btn-danger" style="position: absolute; top: -5px; right: -5px; border-radius: 50%; width: 20px; height: 20px; padding: 0; display: flex; align-items: center; justify-content: center;">×</button>');
removeBtn.click(function() {
imgDiv.remove();
// 从文件输入控件中移除对应的文件
removeFileFromInput(e.target, file);
});
imgDiv.append(img);
imgDiv.append(removeBtn);
$('#' + containerId).append(imgDiv);
};
reader.readAsDataURL(file);
}
}
});
// 为出货交接单的文件选择器添加变化事件
$('#addShippingPOD').change(function(e) {
const files = e.target.files;
const containerId = 'uploadedShippingPODs';
if (files.length > 0) {
// 清空容器
$('#' + containerId).empty();
// 显示预览图片
for (let i = 0; i < files.length; i++) {
const file = files[i];
const reader = new FileReader();
reader.onload = function(e) {
const imgDiv = $('<div class="d-inline-block mr-2 mb-2" style="position: relative;"></div>');
const img = $('<img src="' + e.target.result + '" style="width: 100px; height: 100px; object-fit: cover; border: 1px solid #ddd; border-radius: 4px;">');
const removeBtn = $('<button type="button" class="btn btn-sm btn-danger" style="position: absolute; top: -5px; right: -5px; border-radius: 50%; width: 20px; height: 20px; padding: 0; display: flex; align-items: center; justify-content: center;">×</button>');
removeBtn.click(function() {
imgDiv.remove();
// 从文件输入控件中移除对应的文件
removeFileFromInput(e.target, file);
});
imgDiv.append(img);
imgDiv.append(removeBtn);
$('#' + containerId).append(imgDiv);
};
reader.readAsDataURL(file);
}
}
});
// 为编辑到货交接单的文件选择器添加变化事件
$('#editArrivalPODUpload').change(function(e) {
const files = e.target.files;
const containerId = 'editUploadedArrivalPODs';
if (files.length > 0) {
// 清空容器
$('#' + containerId).empty();
// 显示预览图片
for (let i = 0; i < files.length; i++) {
const file = files[i];
const reader = new FileReader();
reader.onload = function(e) {
const imgDiv = $('<div class="d-inline-block mr-2 mb-2" style="position: relative;"></div>');
const img = $('<img src="' + e.target.result + '" style="width: 100px; height: 100px; object-fit: cover; border: 1px solid #ddd; border-radius: 4px;">');
const removeBtn = $('<button type="button" class="btn btn-sm btn-danger" style="position: absolute; top: -5px; right: -5px; border-radius: 50%; width: 20px; height: 20px; padding: 0; display: flex; align-items: center; justify-content: center;">×</button>');
removeBtn.click(function() {
imgDiv.remove();
// 从文件输入控件中移除对应的文件
removeFileFromInput(e.target, file);
// 更新POD链接输入框
updateEditArrivalPODUrls();
});
imgDiv.append(img);
imgDiv.append(removeBtn);
$('#' + containerId).append(imgDiv);
};
reader.readAsDataURL(file);
}
}
});
// 为编辑出货交接单的文件选择器添加变化事件
$('#editShippingPOD').change(function(e) {
const files = e.target.files;
const containerId = 'editUploadedShippingPODs';
if (files.length > 0) {
// 清空容器
$('#' + containerId).empty();
// 显示预览图片
for (let i = 0; i < files.length; i++) {
const file = files[i];
const reader = new FileReader();
reader.onload = function(e) {
const imgDiv = $('<div class="d-inline-block mr-2 mb-2" style="position: relative;"></div>');
const img = $('<img src="' + e.target.result + '" style="width: 100px; height: 100px; object-fit: cover; border: 1px solid #ddd; border-radius: 4px;">');
const removeBtn = $('<button type="button" class="btn btn-sm btn-danger" style="position: absolute; top: -5px; right: -5px; border-radius: 50%; width: 20px; height: 20px; padding: 0; display: flex; align-items: center; justify-content: center;">×</button>');
removeBtn.click(function() {
imgDiv.remove();
// 从文件输入控件中移除对应的文件
removeFileFromInput(e.target, file);
// 更新POD链接输入框
updateEditShippingPODUrls();
});
imgDiv.append(img);
imgDiv.append(removeBtn);
$('#' + containerId).append(imgDiv);
};
reader.readAsDataURL(file);
}
}
});
// 监听每页记录数选择变化
$('#pageSize').change(function() {
if ($(this).val() === 'custom') {
$('#customPageSizeContainer').show();
} else {
$('#customPageSizeContainer').hide();
}
});
// 监听扫描记录查询每页记录数选择变化
$('#scanPageSize').change(function() {
if ($(this).val() === 'custom') {
$('#customScanPageSizeContainer').show();
} else {
$('#customScanPageSizeContainer').hide();
}
});
// 监听到货交接单查询每页记录数选择变化
$('#arrivalPageSize').change(function() {
if ($(this).val() === 'custom') {
$('#customArrivalPageSizeContainer').show();
} else {
$('#customArrivalPageSizeContainer').hide();
}
});
// 监听出货交接单查询每页记录数选择变化
$('#shippingPageSize').change(function() {
if ($(this).val() === 'custom') {
$('#customShippingPageSizeContainer').show();
} else {
$('#customShippingPageSizeContainer').hide();
}
});
// 添加到货交接单表单提交
$('#addArrivalHandoverForm').submit(function(e) {
e.preventDefault();
const handoverNumbers = $('#addHandoverNumber').val().trim().split('\n').filter(hn => hn.trim() !== '');
const logisticsProviderArrivalTime = $('#addLogisticsProviderArrivalTime').val();
const receiptTime = $('#addReceiptTime').val();
const files = $('#addPOD')[0].files;
const remarks = $('#addRemarks').val().trim();
const timezone = $('#timezone').val();
if (handoverNumbers.length === 0) {
showBubbleNotification('请输入至少一个交接单号');
return;
}
// 处理每个交接单号
handoverNumbers.forEach(handoverNumber => {
let pod = '';
let uniqueIds = [];
// 如果有文件上传预生成S3链接
if (files.length > 0) {
// 预生成S3链接
const preGeneratedUrls = [];
uniqueIds = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
const uniqueId = generateGuid();
uniqueIds.push(uniqueId);
const preGeneratedUrl = generateS3Url('arrival', handoverNumber, file.name, uniqueId);
preGeneratedUrls.push(preGeneratedUrl);
}
// 将预生成的链接添加到POD链接输入框
pod = preGeneratedUrls.join(',');
}
// 先处理到货交接单添加不带POD
processArrivalHandoverForm(handoverNumber, logisticsProviderArrivalTime, receiptTime, pod, remarks, timezone, function() {
// 成功创建到货交接单后上传图片
if (files.length > 0) {
// 上传图片完成后再更新POD字段
setTimeout(function() {
uploadFilesWithForm(files, 'arrival', handoverNumber, uniqueIds);
}, 1000); // 延迟1秒确保图片上传完成
}
});
});
});
// 处理单个到货交接单添加
function processArrivalHandoverForm(handoverNumber, logisticsProviderArrivalTime, receiptTime, pod, remarks, timezone, callback) {
const url = getBaseUrl() + '/api/arrival-handover/create';
// 构建请求数据
const data = {
HandoverNumber: handoverNumber,
LogisticsProviderArrivalTime: logisticsProviderArrivalTime,
ReceiptTime: receiptTime,
Remarks: remarks,
Creator: 'system',
TimeZone: timezone
};
// 只有当 POD 不为空时才传递
if (pod && pod.trim() !== '') {
data.POD = pod;
}
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'createArrivalHandoverCallback',
data: data,
success: function(response) {
if (response.code === 0) {
showBubbleNotification('成功添加到货交接单');
// 清空表单
$('#addArrivalHandoverForm')[0].reset();
$('#uploadedArrivalPODs').empty();
// 重新查询
$('#arrivalHandoverForm').submit();
// 执行回调函数
if (typeof callback === 'function') {
callback();
}
} else {
showBubbleNotification('添加失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
// 处理到货交接单批量添加
function processArrivalHandoverForms(handoverNumbers, logisticsProviderArrivalTime, receiptTime, pod, remarks, timezone, callback) {
// 批量添加到货交接单
const promises = handoverNumbers.map(async (handoverNumber) => {
const url = getBaseUrl() + '/api/arrival-handover/create';
// 构建请求数据
const data = {
HandoverNumber: handoverNumber,
LogisticsProviderArrivalTime: logisticsProviderArrivalTime,
ReceiptTime: receiptTime,
Remarks: remarks,
Creator: 'system',
TimeZone: timezone
};
// 只有当 POD 不为空时才传递
if (pod && pod.trim() !== '') {
data.POD = pod;
}
return new Promise((resolve, reject) => {
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'createArrivalHandoverCallback',
data: data,
success: function(response) {
resolve(response);
},
error: function(xhr, status, error) {
reject(error);
}
});
});
});
Promise.all(promises)
.then(results => {
showBubbleNotification(`成功添加 ${handoverNumbers.length} 个到货交接单`);
// 清空表单
$('#addArrivalHandoverForm')[0].reset();
$('#uploadedArrivalPODs').empty();
// 重新查询
$('#arrivalHandoverForm').submit();
// 执行回调函数
if (typeof callback === 'function') {
callback();
}
})
.catch(error => {
showBubbleNotification('添加失败: ' + error);
});
}
// 创建到货交接单回调函数
function createArrivalHandoverCallback(response) {
// 回调函数处理
}
// 查询到货交接单表单提交
$('#arrivalHandoverForm').submit(function(e) {
e.preventDefault();
const page = 1;
const pageSize = $('#arrivalPageSize').val() === 'custom' ? $('#customArrivalPageSize').val() : $('#arrivalPageSize').val();
const sortBy = $('#arrivalSortBy').val();
const sortOrder = $('#arrivalSortOrder').val();
const handoverNumber = $('#handoverNumber').val().trim().replace(/\s+/g, ','); // 将多行输入转换为逗号分隔的字符串
const url = getBaseUrl() + '/api/arrival-handover/list';
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'getArrivalHandoverListCallback',
data: {
page: page,
pageSize: pageSize,
sortBy: sortBy,
sortOrder: sortOrder,
handoverNumber: handoverNumber
},
success: function(response) {
if (response.code === 0) {
renderArrivalHandoverTable(response.data.forms);
// 渲染分页
showBubbleNotification('共找到 ' + response.data.totalCount + ' 条记录');
} else {
showBubbleNotification('查询失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
});
// 获取到货交接单列表回调函数
function getArrivalHandoverListCallback(response) {
if (response.code === 0) {
renderArrivalHandoverTable(response.data.forms);
// 渲染分页
showBubbleNotification('共找到 ' + response.data.totalCount + ' 条记录');
} else {
showBubbleNotification('查询失败: ' + response.message);
}
}
// 重置到货交接单表单
$('#resetArrivalHandoverForm').click(function() {
$('#arrivalHandoverForm')[0].reset();
});
// 全选/取消全选到货交接单
$('#selectAllHandoverForms').change(function() {
const isChecked = $(this).prop('checked');
$('.handover-form-checkbox').prop('checked', isChecked);
});
// 批量删除到货交接单
$('#deleteSelectedHandoverForms').click(function() {
const selectedIds = [];
$('.handover-form-checkbox:checked').each(function() {
selectedIds.push($(this).data('id'));
});
if (selectedIds.length === 0) {
showBubbleNotification('请选择要删除的到货交接单');
return;
}
if (confirm('确定要删除选中的到货交接单吗?')) {
selectedIds.forEach(id => {
const url = getBaseUrl() + '/api/arrival-handover/delete/' + id;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'deleteArrivalHandoverCallback',
success: function(response) {
if (response.code === 0) {
showBubbleNotification('删除成功');
// 重新查询
$('#arrivalHandoverForm').submit();
} else {
showBubbleNotification('删除失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
});
}
});
// 删除到货交接单回调函数
function deleteArrivalHandoverCallback(response) {
if (response.code === 0) {
showBubbleNotification('删除成功');
// 重新查询
$('#arrivalHandoverForm').submit();
} else {
showBubbleNotification('删除失败: ' + response.message);
}
}
// 添加出货交接单表单提交
$('#addShippingHandoverForm').submit(function(e) {
e.preventDefault();
let handoverNumber = $('#addShippingHandoverNumber').val().trim();
const channel = $('#addChannel').val();
const deliveryTime = $('#addDeliveryTime').val();
const files = $('#addShippingPOD')[0].files;
const podUrls = $('#addShippingPODUrls').val().trim();
const remarks = $('#addShippingRemarks').val().trim();
const timezone = $('#shippingTimezone').val();
// 验证渠道是否选择
if (!channel) {
showBubbleNotification('请选择渠道');
return;
}
// 生成交接单号(如果未提供)
if (!handoverNumber) {
$.ajax({
url: getBaseUrl() + '/api/shipping-handover/generate-number',
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'generateShippingHandoverNumberCallback',
data: { channel: channel },
success: function(response) {
if (response.code === 0) {
handoverNumber = response.data;
$('#addShippingHandoverNumber').val(handoverNumber);
processFormWithHandoverNumber(handoverNumber, channel, deliveryTime, files, podUrls, remarks, timezone);
} else {
showBubbleNotification('生成交接单号失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('生成交接单号失败: ' + error);
}
});
} else {
processFormWithHandoverNumber(handoverNumber, channel, deliveryTime, files, podUrls, remarks, timezone);
}
});
// 处理表单提交(带交接单号)
function processFormWithHandoverNumber(handoverNumber, channel, deliveryTime, files, podUrls, remarks, timezone) {
// 优先使用直接输入的POD链接
let pod = podUrls || '';
let uniqueIds = [];
// 如果有文件上传预生成S3链接
if (files.length > 0 && !pod) {
// 预生成S3链接
const preGeneratedUrls = [];
uniqueIds = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
const uniqueId = generateGuid();
uniqueIds.push(uniqueId);
const preGeneratedUrl = generateS3Url('shipping', handoverNumber, file.name, uniqueId);
preGeneratedUrls.push(preGeneratedUrl);
}
// 将预生成的链接添加到POD链接输入框
pod = preGeneratedUrls.join(',');
$('#addShippingPODUrls').val(pod);
}
// 先处理出货交接单添加不带POD
processShippingHandoverForm(handoverNumber, channel, deliveryTime, '', remarks, timezone, function() {
// 成功创建出货交接单后上传图片
if (files.length > 0) {
// 上传图片完成后再更新POD字段
setTimeout(function() {
uploadFilesWithForm(files, 'shipping', handoverNumber, uniqueIds);
// 上传完成后更新POD字段
if (pod) {
updateShippingHandoverFormPOD(handoverNumber, pod);
}
}, 1000); // 延迟1秒确保图片上传完成
} else if (pod) {
// 没有文件上传但有POD链接直接更新
updateShippingHandoverFormPOD(handoverNumber, pod);
}
});
}
// 生成对象键
function generateObjectKey(handoverNumber, uniqueId, fileName, type) {
const yearMonth = new Date().toISOString().slice(0, 7).replace('-', '');
let prefix = '';
if (type === 'arrival') {
prefix = `arrivalhandover/${yearMonth}/`;
} else if (type === 'shipping') {
prefix = `shippinghandover/${yearMonth}/`;
} else {
prefix = 'pod/';
}
return `${prefix}${handoverNumber}_${uniqueId}_${fileName}`;
}
// 处理出货交接单添加
function processShippingHandoverForm(handoverNumber, channel, deliveryTime, pod, remarks, timezone, callback) {
const url = getBaseUrl() + '/api/shipping-handover/create';
// 构建请求数据,只传递非空字段
const data = {
HandoverNumber: handoverNumber,
Channel: channel,
DeliveryTime: deliveryTime,
Creator: 'system',
TimeZone: timezone
};
// 只有当 POD 不为空时才传递
if (pod && pod.trim() !== '') {
data.POD = pod;
}
// 只有当 Remarks 不为空时才传递
if (remarks && remarks.trim() !== '') {
data.Remarks = remarks;
}
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'createShippingHandoverCallback',
data: data,
success: function(response) {
if (response.code === 0) {
showBubbleNotification('成功添加出货交接单');
// 清空表单
$('#addShippingHandoverForm')[0].reset();
$('#uploadedShippingPODs').empty();
// 重新查询
$('#shippingHandoverForm').submit();
// 执行回调函数
if (typeof callback === 'function') {
callback();
}
} else {
showBubbleNotification('添加失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
// 更新出货交接单POD字段
function updateShippingHandoverFormPOD(handoverNumber, podLinks, callback) {
const url = getBaseUrl() + '/api/shipping-handover/update-pod';
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'updateShippingHandoverFormPODCallback',
data: {
handoverNumber: handoverNumber,
podLinks: podLinks
},
success: function(response) {
if (typeof callback === 'function') {
callback();
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
// 更新出货交接单POD回调函数
function updateShippingHandoverFormPODCallback(response) {
if (response.code === 0) {
showBubbleNotification('成功更新POD字段');
// 重新查询
$('#shippingHandoverForm').submit();
} else {
showBubbleNotification('更新POD失败: ' + response.message);
}
}
// 更新到货交接单POD字段
function updateArrivalHandoverFormPOD(handoverNumber, podLinks, callback) {
// 先获取到货交接单ID
const getUrl = getBaseUrl() + '/api/arrival-handover/get-by-number/' + handoverNumber;
$.ajax({
url: getUrl,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'getArrivalHandoverFormByNumberCallback',
success: function(response) {
if (response.code === 0 && response.data) {
const formId = response.data.id;
// 更新POD字段
const updateUrl = getBaseUrl() + '/api/arrival-handover/update/' + formId;
$.ajax({
url: updateUrl,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'updateArrivalHandoverFormCallback',
data: {
POD: podLinks
},
success: function(response) {
if (typeof callback === 'function') {
callback();
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
} else {
showBubbleNotification('获取到货交接单失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
// 获取到货交接单回调函数
function getArrivalHandoverFormByNumberCallback(response) {
// 回调函数处理
}
// 更新到货交接单回调函数
function updateArrivalHandoverFormCallback(response) {
if (response.code === 0) {
showBubbleNotification('成功更新到货交接单');
// 重新查询
$('#arrivalHandoverForm').submit();
} else {
showBubbleNotification('更新失败: ' + response.message);
}
}
// 创建出货交接单回调函数
function createShippingHandoverCallback(response) {
if (response.code === 0) {
showBubbleNotification('成功添加出货交接单');
// 清空表单
$('#addShippingHandoverForm')[0].reset();
$('#uploadedShippingPODs').empty();
// 重新查询
$('#shippingHandoverForm').submit();
} else {
showBubbleNotification('添加失败: ' + response.message);
}
}
// 生成出货交接单号
$('#generateShippingHandoverNumber').click(function() {
const channel = $('#addChannel').val();
if (!channel) {
showBubbleNotification('请先选择渠道');
return;
}
const url = getBaseUrl() + '/api/shipping-handover/generate-number';
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'generateShippingHandoverNumberCallback',
data: {
channel: channel
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
});
// 查询出货交接单表单提交
$('#shippingHandoverForm').submit(function(e) {
e.preventDefault();
const page = 1;
const pageSize = $('#shippingPageSize').val() === 'custom' ? $('#customShippingPageSize').val() : $('#shippingPageSize').val();
const sortBy = $('#shippingSortBy').val();
const sortOrder = $('#shippingSortOrder').val();
const handoverNumber = $('#shippingHandoverNumber').val().trim();
const channel = $('#shippingChannel').val();
const creator = $('#shippingCreator').val().trim();
const startDeliveryTime = $('#startDeliveryTime').val();
const endDeliveryTime = $('#endDeliveryTime').val();
const url = getBaseUrl() + '/api/shipping-handover/list';
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'getShippingHandoverListCallback',
data: {
page: page,
pageSize: pageSize,
sortBy: sortBy,
sortOrder: sortOrder,
handoverNumber: handoverNumber,
channel: channel,
creator: creator,
startDeliveryTime: startDeliveryTime,
endDeliveryTime: endDeliveryTime
},
success: function(response) {
if (response.code === 0) {
renderShippingHandoverTable(response.data.forms);
// 渲染分页
showBubbleNotification('共找到 ' + response.data.totalCount + ' 条记录');
} else {
showBubbleNotification('查询失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
});
// 获取出货交接单列表回调函数
function getShippingHandoverListCallback(response) {
if (response.code === 0) {
renderShippingHandoverTable(response.data.forms);
// 渲染分页
showBubbleNotification('共找到 ' + response.data.totalCount + ' 条记录');
} else {
showBubbleNotification('查询失败: ' + response.message);
}
}
// 重置出货交接单表单
$('#resetShippingHandoverForm').click(function() {
$('#shippingHandoverForm')[0].reset();
});
// 全选/取消全选出货交接单
$('#selectAllShippingHandoverForms').change(function() {
const isChecked = $(this).prop('checked');
$('.shipping-handover-form-checkbox').prop('checked', isChecked);
});
// 批量删除出货交接单
$('#deleteSelectedShippingHandoverForms').click(function() {
const selectedIds = [];
$('.shipping-handover-form-checkbox:checked').each(function() {
selectedIds.push($(this).data('id'));
});
if (selectedIds.length === 0) {
showBubbleNotification('请选择要删除的出货交接单');
return;
}
if (confirm('确定要删除选中的出货交接单吗?')) {
selectedIds.forEach(id => {
const url = getBaseUrl() + '/api/shipping-handover/delete/' + id;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'deleteShippingHandoverCallback',
success: function(response) {
if (response.code === 0) {
showBubbleNotification('删除成功');
// 重新查询
$('#shippingHandoverForm').submit();
} else {
showBubbleNotification('删除失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
});
}
});
// 删除出货交接单回调函数
function deleteShippingHandoverCallback(response) {
if (response.code === 0) {
showBubbleNotification('删除成功');
// 重新查询
$('#shippingHandoverForm').submit();
} else {
showBubbleNotification('删除失败: ' + response.message);
}
}
// 关联袋牌表单提交
$('#associateBagTagsForm').submit(function(e) {
e.preventDefault();
const shippingHandoverFormId = $('#shippingHandoverFormId').val();
const bagTagNumbers = $('#bagTagNumbers').val().trim().split('\n').filter(tag => tag.trim() !== '');
if (!shippingHandoverFormId) {
showBubbleNotification('请输入出货交接单ID');
return;
}
if (bagTagNumbers.length === 0) {
showBubbleNotification('请输入至少一个袋牌号');
return;
}
// 先获取出货交接单的详情,包括渠道信息
const shippingHandoverUrl = getBaseUrl() + '/api/shipping-handover/get/' + shippingHandoverFormId;
$.ajax({
url: shippingHandoverUrl,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
success: function(shippingHandoverResponse) {
if (shippingHandoverResponse.code === 0) {
const shippingHandoverChannel = shippingHandoverResponse.data.Channel;
// 验证所有袋牌的渠道是否与出货交接单的渠道一致
let allChannelsMatch = true;
let mismatchedBagTags = [];
// 遍历袋牌号码,验证渠道
let validatedBagTags = 0;
let existingBagTags = [];
bagTagNumbers.forEach(bagTagNumber => {
const bagTagUrl = getBaseUrl() + '/api/bagtag/' + bagTagNumber;
$.ajax({
url: bagTagUrl,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
success: function(bagTagResponse) {
validatedBagTags++;
if (bagTagResponse.code === 0) {
const bagTagChannel = bagTagResponse.data.ChannelName;
const bagTagStatus = bagTagResponse.data.Status;
if (bagTagChannel !== shippingHandoverChannel) {
allChannelsMatch = false;
mismatchedBagTags.push(bagTagNumber + ' (渠道不一致)');
} else {
existingBagTags.push(bagTagNumber);
}
} else {
allChannelsMatch = false;
mismatchedBagTags.push(bagTagNumber + ' (袋牌不存在)');
}
// 当所有袋牌都验证完成后
if (validatedBagTags === bagTagNumbers.length) {
if (allChannelsMatch) {
// 所有袋牌渠道都匹配,执行关联操作
const associateUrl = getBaseUrl() + '/api/shipping-handover/bag-tag/associate-by-number/' + shippingHandoverFormId;
$.ajax({
url: associateUrl,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'associateBagTagsCallback',
data: {
bagTagNumbers: existingBagTags.join(',')
},
success: function(response) {
if (response.code === 0) {
showBubbleNotification(`成功关联 ${existingBagTags.length} 个袋牌`);
// 清空表单
$('#associateBagTagsForm')[0].reset();
} else {
showBubbleNotification('关联失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
} else {
// 有袋牌渠道不匹配或不存在,显示错误信息
showBubbleNotification('关联失败: ' + mismatchedBagTags.join(', '));
}
}
},
error: function(xhr, status, error) {
validatedBagTags++;
allChannelsMatch = false;
mismatchedBagTags.push(bagTagNumber + ' (获取袋牌信息失败)');
// 当所有袋牌都验证完成后
if (validatedBagTags === bagTagNumbers.length) {
showBubbleNotification('关联失败: ' + mismatchedBagTags.join(', '));
}
}
});
});
} else {
showBubbleNotification('获取出货交接单详情失败: ' + shippingHandoverResponse.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('获取出货交接单详情失败: ' + error);
}
});
});
// 关联袋牌回调函数
function associateBagTagsCallback(response) {
if (response.code === 0) {
showBubbleNotification(`成功关联袋牌`);
// 清空表单
$('#associateBagTagsForm')[0].reset();
} else {
showBubbleNotification('关联失败: ' + response.message);
}
}
// 查询关联袋牌表单提交
$('#queryAssociatedBagTagsForm').submit(function(e) {
e.preventDefault();
const shippingHandoverFormId = $('#queryShippingHandoverFormId').val();
if (!shippingHandoverFormId) {
showBubbleNotification('请输入出货交接单ID');
return;
}
const url = getBaseUrl() + '/api/shipping-handover/bag-tag/list/' + shippingHandoverFormId;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'queryAssociatedBagTagsCallback',
success: function(response) {
if (response.code === 0) {
showBubbleNotification(`共找到 ${response.data.length} 个关联袋牌`);
// 显示袋牌列表
alert('关联袋牌列表:\n' + response.data.map(tag => tag.TagNumber).join('\n'));
} else {
showBubbleNotification('查询失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
});
// 查询关联袋牌回调函数
function queryAssociatedBagTagsCallback(response) {
if (response.code === 0) {
showBubbleNotification(`共找到 ${response.data.length} 个关联袋牌`);
// 显示袋牌列表
alert('关联袋牌列表:\n' + response.data.map(tag => tag.TagNumber).join('\n'));
} else {
showBubbleNotification('查询失败: ' + response.message);
}
}
// 查询袋牌回调函数(用于表格中的查询袋牌按钮)
function queryBagTagsCallback(response) {
// 此回调函数在 ajax 调用中直接处理响应,不需要在这里重复处理
}
});
// 渲染到货交接单表格
function renderArrivalHandoverTable(forms) {
const tableBody = $('#arrivalHandoverTableBody');
tableBody.empty();
if (forms && forms.length > 0) {
forms.forEach(form => {
const row = $('<tr></tr>');
row.append(`<td><input type="checkbox" class="handover-form-checkbox" data-id="${form.Id}"></td>`);
row.append(`<td>${form.Id}</td>`);
// 添加客户简称列,初始显示加载中
const customerCell = $('<td>加载中...</td>');
row.append(customerCell);
row.append(`<td>${form.HandoverNumber}</td>`);
row.append(`<td>${form.LogisticsProviderArrivalTime ? new Date(form.LogisticsProviderArrivalTime).toLocaleString() : '-'}</td>`);
row.append(`<td>${form.ReceiptTime ? new Date(form.ReceiptTime).toLocaleString() : '-'}</td>`);
row.append(`<td>${form.POD && form.POD.trim() !== '' ? '<span class="text-success">有并支持查看预览</span> <button class="btn btn-sm btn-info ml-2 preview-pod-btn" data-pod="' + form.POD + '">预览</button>' : '无'}</td>`);
row.append(`<td>${form.Remarks || '-'}</td>`);
row.append(`<td>${form.Creator}</td>`);
row.append(`<td>${new Date(form.CreatedAt).toLocaleString()}</td>`);
row.append(`<td>${form.TimeZone || '-'}</td>`);
row.append(`<td class="d-flex flex-wrap gap-1">
<button class="btn btn-sm btn-primary arrival-edit-btn" data-id="${form.Id}">编辑</button>
<button class="btn btn-sm btn-danger arrival-delete-btn" data-id="${form.Id}">删除</button>
</td>`);
tableBody.append(row);
// 异步获取客户简称
fetchCustomerAbbreviation(form.HandoverNumber, customerCell);
});
// 添加事件处理程序
$('.arrival-edit-btn').click(function() {
const id = $(this).data('id');
editArrivalHandoverForm(id);
});
$('.arrival-delete-btn').click(function() {
const id = $(this).data('id');
if (confirm('确定要删除到货交接单 ID: ' + id + ' 吗?')) {
const url = getBaseUrl() + '/api/arrival-handover/delete/' + id;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'deleteArrivalHandoverCallback',
success: function(response) {
if (response.code === 0) {
showBubbleNotification('删除成功');
// 重新查询
$('#arrivalHandoverForm').submit();
} else {
showBubbleNotification('删除失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
});
} else {
tableBody.append('<tr><td colspan="12" class="text-center">暂无数据</td></tr>');
}
}
// 获取客户简称
function fetchCustomerAbbreviation(handoverNumber, cell) {
const baseUrl = getBaseUrl();
// 先尝试通过BillOfLadingNumber查询
let url = baseUrl + '/api/Label/label-replace/batch?page=1&pageSize=1&billOfLadingNumber=' + handoverNumber;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
success: function(response) {
if (response.status === 'ok' && response.data && response.data.length > 0) {
// 找到记录获取CustomerCode
const customerCode = response.data[0].CustomerCode;
if (customerCode) {
cell.text(customerCode);
} else {
// 尝试通过MasterPackageNumber查询
fetchByMasterPackageNumber(handoverNumber, cell);
}
} else {
// 尝试通过MasterPackageNumber查询
fetchByMasterPackageNumber(handoverNumber, cell);
}
},
error: function() {
// 尝试通过MasterPackageNumber查询
fetchByMasterPackageNumber(handoverNumber, cell);
}
});
}
// 通过MasterPackageNumber查询
function fetchByMasterPackageNumber(handoverNumber, cell) {
const baseUrl = getBaseUrl();
const url = baseUrl + '/api/Label/label-replace/batch?page=1&pageSize=1&masterPackageNumber=' + handoverNumber;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
success: function(response) {
if (response.status === 'ok' && response.data && response.data.length > 0) {
// 找到记录获取CustomerCode
const customerCode = response.data[0].CustomerCode;
if (customerCode) {
cell.text(customerCode);
} else {
cell.text('-');
}
} else {
cell.text('-');
}
},
error: function() {
cell.text('-');
}
});
}
// 渲染出货交接单表格
function renderShippingHandoverTable(forms) {
const tableBody = $('#shippingHandoverTableBody');
tableBody.empty();
if (forms && forms.length > 0) {
forms.forEach(form => {
// 创建行元素
const row = $('<tr></tr>');
row.append(`<td><input type="checkbox" class="shipping-handover-form-checkbox" data-id="${form.Id}"></td>`);
row.append(`<td>${form.Id}</td>`);
row.append(`<td>${form.HandoverNumber}</td>`);
// 添加箱数和交货单量的占位符
const boxCountCell = $('<td>加载中...</td>');
const orderCountCell = $('<td>加载中...</td>');
row.append(boxCountCell);
row.append(orderCountCell);
row.append(`<td>${form.Channel}</td>`);
row.append(`<td>${form.DeliveryTime ? new Date(form.DeliveryTime).toLocaleString() : '-'}</td>`);
row.append(`<td>${form.TimeZone || '-'}</td>`);
row.append(`<td>${form.POD ? '<span class="text-success">有并支持查看预览</span> <button class="btn btn-sm btn-info ml-2 preview-pod-btn" data-pod="' + form.POD + '">预览</button>' : '无'}</td>`);
row.append(`<td>${form.Remarks || '-'}</td>`);
row.append(`<td>${form.Creator}</td>`);
row.append(`<td>${new Date(form.CreatedAt).toLocaleString()}</td>`);
row.append(`<td class="d-flex flex-wrap gap-1">
<button class="btn btn-sm btn-primary edit-btn" data-id="${form.Id}">编辑</button>
<button class="btn btn-sm btn-danger delete-btn" data-id="${form.Id}">删除</button>
<button class="btn btn-sm btn-success query-bag-tags-btn" data-id="${form.Id}">查询袋牌</button>
</td>`);
tableBody.append(row);
// 加载箱数和交货单量
loadBagTagAndPackageCount(form.Id, boxCountCell, orderCountCell);
});
// 添加事件处理程序
$('.edit-btn').click(function() {
const id = $(this).data('id');
editShippingHandoverForm(id);
});
$('.delete-btn').click(function() {
const id = $(this).data('id');
if (confirm('确定要删除出货交接单 ID: ' + id + ' 吗?')) {
const url = getBaseUrl() + '/api/shipping-handover/delete/' + id;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'deleteShippingHandoverCallback',
success: function(response) {
if (response.code === 0) {
showBubbleNotification('删除成功');
// 重新查询
$('#shippingHandoverForm').submit();
} else {
showBubbleNotification('删除失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
});
$('.query-bag-tags-btn').click(function() {
const id = $(this).data('id');
const row = $(this).closest('tr');
const bagTagRow = row.next('.bag-tag-detail-row');
if (bagTagRow.length > 0) {
// 切换袋牌明细行的显示状态
bagTagRow.toggle();
$(this).text(bagTagRow.is(':visible') ? '收起袋牌' : '查询袋牌');
} else {
// 加载袋牌数据并创建明细行
const url = getBaseUrl() + '/api/shipping-handover/bag-tag/list/' + id;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'queryBagTagsCallback',
success: function(response) {
if (response.code === 0) {
const bagTags = response.data;
if (bagTags && bagTags.length > 0) {
// 创建袋牌明细行
const newBagTagRow = $('<tr class="bag-tag-detail-row"></tr>');
newBagTagRow.append(`<td colspan="12">
<div class="p-3 bg-light rounded">
<h6 class="mb-2">交接单 ID: ${id} 关联的袋牌</h6>
<div class="table-responsive">
<table class="table table-sm table-striped">
<thead>
<tr>
<th>袋牌号码</th>
<th>小包数量</th>
<th>状态</th>
<th>创建人</th>
<th>创建时间</th>
<th>打开时间</th>
<th>关闭时间</th>
</tr>
</thead>
<tbody>
${bagTags.map(tag => `
<tr>
<td>${tag.TagNumber || '-'}</td>
<td>${tag.WaybillCount || 0}</td>
<td>${tag.Status || '-'}</td>
<td>${tag.Creator || '-'}</td>
<td>${tag.CreatedAt ? new Date(tag.CreatedAt).toLocaleString() : '-'}</td>
<td>${tag.OpenedAt ? new Date(tag.OpenedAt).toLocaleString() : '-'}</td>
<td>${tag.ClosedAt ? new Date(tag.ClosedAt).toLocaleString() : '-'}</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
</div>
</td>`);
row.after(newBagTagRow);
// 显示明细行
newBagTagRow.show();
// 更新按钮文本
$('.query-bag-tags-btn[data-id="' + id + '"]').text('收起袋牌');
} else {
showBubbleNotification('该交接单未关联任何袋牌');
}
} else {
showBubbleNotification('查询袋牌失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
});
} else {
tableBody.append('<tr><td colspan="12" class="text-center">暂无数据</td></tr>');
}
}
// 并发请求控制
const requestQueue = {
queue: [],
processing: 0,
maxConcurrent: 3, // 最多同时处理3个请求
add: function(task) {
this.queue.push(task);
this.process();
},
process: function() {
if (this.queue.length > 0 && this.processing < this.maxConcurrent) {
this.processing++;
const task = this.queue.shift();
task().then(() => {
this.processing--;
this.process();
}).catch(() => {
this.processing--;
this.process();
});
}
}
};
// 加载袋牌数量和包裹数量
function loadBagTagAndPackageCount(shippingHandoverFormId, boxCountCell, orderCountCell) {
const task = function() {
return new Promise((resolve, reject) => {
const url = getBaseUrl() + '/api/shipping-handover/bag-tag/count/' + shippingHandoverFormId;
// 使用 JSONP 请求,与其他 API 调用保持一致
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'countBagTagsCallback',
timeout: 10000, // 添加10秒超时
success: function(response) {
console.log('袋牌和包裹数量响应:', response);
if (response && response.code === 0) {
const bagTagCount = response.data ? response.data.bagTagCount || 0 : 0;
const packageCount = response.data ? response.data.packageCount || 0 : 0;
boxCountCell.text(bagTagCount);
orderCountCell.text(packageCount);
} else {
boxCountCell.text('0');
orderCountCell.text('0');
}
resolve();
},
error: function(xhr, status, error) {
console.error('加载袋牌和包裹数量失败:', error, status);
boxCountCell.text('0');
orderCountCell.text('0');
resolve(); // 即使失败也继续处理队列
}
});
});
};
// 将任务添加到队列
requestQueue.add(task);
}
// 袋牌和包裹数量统计回调函数
function countBagTagsCallback(response) {
// 此回调函数在 ajax 调用中直接处理响应,不需要在这里重复处理
}
// 编辑出货交接单
function editShippingHandoverForm(id) {
const url = getBaseUrl() + '/api/shipping-handover/get/' + id;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'getShippingHandoverDetailCallback',
success: function(response) {
if (response.code === 0) {
const form = response.data;
$('#editId').val(form.Id);
// 转换时间格式为datetime-local所需的格式
if (form.DeliveryTime) {
const deliveryTime = new Date(form.DeliveryTime);
$('#editDeliveryTime').val(deliveryTime.toISOString().slice(0, 16));
} else {
$('#editDeliveryTime').val('');
}
$('#editTimezone').val(form.TimeZone || 'America/New_York');
$('#editShippingPODUrls').val(form.POD || '');
$('#editRemarks').val(form.Remarks || '');
// 显示已上传的POD图片
const editUploadedShippingPODs = $('#editUploadedShippingPODs');
editUploadedShippingPODs.empty();
if (form.POD) {
const podItems = form.POD.split(',').map(item => item.trim());
podItems.forEach(item => {
if (item && item.startsWith('http')) {
const imgDiv = $('<div class="d-inline-block mr-2 mb-2" style="position: relative;"></div>');
const img = $('<img src="' + item + '" style="width: 100px; height: 100px; object-fit: cover; border: 1px solid #ddd; border-radius: 4px;">');
const removeBtn = $('<button type="button" class="btn btn-sm btn-danger" style="position: absolute; top: -5px; right: -5px; border-radius: 50%; width: 20px; height: 20px; padding: 0; display: flex; align-items: center; justify-content: center;">×</button>');
removeBtn.click(function() {
imgDiv.remove();
// 更新POD链接输入框
updateEditShippingPODUrls();
// 确保预览模态框中的图片也被移除
$('#podPreviewContent').empty();
});
imgDiv.append(img);
imgDiv.append(removeBtn);
editUploadedShippingPODs.append(imgDiv);
}
});
}
// 如果没有已上传的图片,显示提示信息
if (editUploadedShippingPODs.children().length === 0) {
editUploadedShippingPODs.append('<p class="text-muted text-center">点击或粘贴图片到此处</p>');
}
$('#editShippingHandoverModal').modal('show');
} else {
showBubbleNotification('获取详情失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
// 获取出货交接单详情回调函数
function getShippingHandoverDetailCallback(response) {
// 此回调函数在 ajax 调用中直接处理响应,不需要在这里重复处理
}
// 更新编辑出货交接单的POD链接输入框
function updateEditShippingPODUrls() {
const editUploadedShippingPODs = $('#editUploadedShippingPODs');
const podUrls = [];
// 从已上传的图片中获取链接
editUploadedShippingPODs.find('img').each(function() {
podUrls.push($(this).attr('src'));
});
// 从输入框中获取其他链接(只保留非图片链接)
const inputUrls = $('#editShippingPODUrls').val().split(',').map(item => item.trim()).filter(item => item && !item.startsWith('http'));
// 合并并去重
const allUrls = [...new Set([...podUrls, ...inputUrls])];
// 更新输入框
$('#editShippingPODUrls').val(allUrls.join(','));
}
// 更新编辑到货交接单的POD链接输入框
function updateEditArrivalPODUrls() {
const editUploadedArrivalPODs = $('#editUploadedArrivalPODs');
const podUrls = [];
// 从已上传的图片中获取链接
editUploadedArrivalPODs.find('img').each(function() {
podUrls.push($(this).attr('src'));
});
// 从输入框中获取其他链接(只保留非图片链接)
const inputUrls = $('#editArrivalPOD').val().split(',').map(item => item.trim()).filter(item => item && !item.startsWith('http'));
// 合并并去重
const allUrls = [...new Set([...podUrls, ...inputUrls])];
// 更新输入框
$('#editArrivalPOD').val(allUrls.join(','));
}
// 保存编辑
function saveShippingHandoverEdit() {
const id = $('#editId').val();
const deliveryTime = $('#editDeliveryTime').val();
const pod = $('#editShippingPODUrls').val().trim();
const remarks = $('#editRemarks').val().trim();
const timezone = $('#editTimezone').val();
// 先上传图片
const files = $('#editShippingPOD')[0].files;
if (files.length > 0) {
const handoverNumber = 'EDIT_' + id;
const uniqueIds = [];
const imageUrls = [];
// 预生成S3链接
for (let i = 0; i < files.length; i++) {
const file = files[i];
const uniqueId = generateGuid();
uniqueIds.push(uniqueId);
const imageUrl = generateS3Url('shipping', handoverNumber, file.name, uniqueId);
imageUrls.push(imageUrl);
}
// 上传图片
uploadFilesWithForm(files, 'shipping', handoverNumber, uniqueIds);
// 延迟更新POD确保图片上传完成
setTimeout(function() {
// 合并已有的POD链接和新上传的图片链接
const existingPod = pod ? pod + ',' : '';
const newPod = existingPod + imageUrls.join(',');
updateShippingHandoverFormPOD(id, newPod, function() {
// 保存其他字段
saveShippingHandoverFields(id, deliveryTime, newPod, remarks, timezone);
});
}, 2000);
} else {
// 没有新图片,直接保存
saveShippingHandoverFields(id, deliveryTime, pod, remarks, timezone);
}
}
// 保存出货交接单字段
function saveShippingHandoverFields(id, deliveryTime, pod, remarks, timezone) {
const url = getBaseUrl() + '/api/shipping-handover/update/' + id;
// 构建请求数据
const data = {
DeliveryTime: deliveryTime,
TimeZone: timezone,
POD: pod || '' // 总是传递 POD 字段,为空时传递空字符串
};
// 只有当 Remarks 不为空时才传递
if (remarks && remarks.trim() !== '') {
data.Remarks = remarks;
}
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'updateShippingHandoverCallback',
data: data,
success: function(response) {
if (response.code === 0) {
showBubbleNotification('更新成功');
$('#editShippingHandoverModal').modal('hide');
// 重新查询
$('#shippingHandoverForm').submit();
} else {
showBubbleNotification('更新失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
// 更新出货交接单回调函数
function updateShippingHandoverCallback(response) {
if (response.code === 0) {
showBubbleNotification('更新成功');
$('#editShippingHandoverModal').modal('hide');
// 重新查询
$('#shippingHandoverForm').submit();
} else {
showBubbleNotification('更新失败: ' + response.message);
}
}
// 编辑到货交接单
function editArrivalHandoverForm(id) {
const url = getBaseUrl() + '/api/arrival-handover/get/' + id;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'getArrivalHandoverDetailCallback',
success: function(response) {
if (response.code === 0) {
const form = response.data;
$('#editArrivalId').val(form.Id);
$('#editArrivalHandoverNumber').val(form.HandoverNumber);
// 直接使用数据库中的时间值,不进行时区转换
// 假设数据库中存储的时间格式已经是YYYY-MM-DDTHH:MM格式
if (form.LogisticsProviderArrivalTime) {
// 确保时间格式为datetime-local所需的格式
let timeStr = form.LogisticsProviderArrivalTime;
// 如果时间字符串包含秒,去掉秒部分
if (timeStr.includes(':')) {
const parts = timeStr.split('T');
if (parts.length === 2) {
const timeParts = parts[1].split(':');
if (timeParts.length >= 2) {
timeStr = parts[0] + 'T' + timeParts[0] + ':' + timeParts[1];
}
}
}
$('#editLogisticsProviderArrivalTime').val(timeStr);
} else {
$('#editLogisticsProviderArrivalTime').val('');
}
if (form.ReceiptTime) {
// 确保时间格式为datetime-local所需的格式
let timeStr = form.ReceiptTime;
// 如果时间字符串包含秒,去掉秒部分
if (timeStr.includes(':')) {
const parts = timeStr.split('T');
if (parts.length === 2) {
const timeParts = parts[1].split(':');
if (timeParts.length >= 2) {
timeStr = parts[0] + 'T' + timeParts[0] + ':' + timeParts[1];
}
}
}
$('#editReceiptTime').val(timeStr);
} else {
$('#editReceiptTime').val('');
}
$('#editArrivalPOD').val(form.POD || '');
$('#editArrivalTimezone').val(form.TimeZone || 'America/New_York');
$('#editArrivalRemarks').val(form.Remarks || '');
// 显示已上传的POD图片
const editUploadedArrivalPODs = $('#editUploadedArrivalPODs');
editUploadedArrivalPODs.empty();
if (form.POD) {
const podItems = form.POD.split(',').map(item => item.trim());
podItems.forEach(item => {
if (item && item.startsWith('http')) {
const imgDiv = $('<div class="d-inline-block mr-2 mb-2" style="position: relative;"></div>');
const img = $('<img src="' + item + '" style="width: 100px; height: 100px; object-fit: cover; border: 1px solid #ddd; border-radius: 4px;">');
const removeBtn = $('<button type="button" class="btn btn-sm btn-danger" style="position: absolute; top: -5px; right: -5px; border-radius: 50%; width: 20px; height: 20px; padding: 0; display: flex; align-items: center; justify-content: center;">×</button>');
removeBtn.click(function() {
imgDiv.remove();
// 更新POD链接输入框
updateEditArrivalPODUrls();
// 确保预览模态框中的图片也被移除
$('#podPreviewContent').empty();
// 如果没有图片了清空POD输入框
if (editUploadedArrivalPODs.children().length === 0) {
editUploadedArrivalPODs.append('<p class="text-muted text-center">点击或粘贴图片到此处</p>');
$('#editArrivalPOD').val('');
}
});
imgDiv.append(img);
imgDiv.append(removeBtn);
editUploadedArrivalPODs.append(imgDiv);
}
});
}
// 如果没有已上传的图片,显示提示信息
if (editUploadedArrivalPODs.children().length === 0) {
editUploadedArrivalPODs.append('<p class="text-muted text-center">点击或粘贴图片到此处</p>');
$('#editArrivalPOD').val('');
}
$('#editArrivalHandoverModal').modal('show');
} else {
showBubbleNotification('获取详情失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
// 获取到货交接单详情回调函数
function getArrivalHandoverDetailCallback(response) {
// 此回调函数在 ajax 调用中直接处理响应,不需要在这里重复处理
}
// 保存到货交接单编辑
function saveArrivalHandoverEdit() {
const id = $('#editArrivalId').val();
const logisticsProviderArrivalTime = $('#editLogisticsProviderArrivalTime').val();
const receiptTime = $('#editReceiptTime').val();
const remarks = $('#editArrivalRemarks').val().trim();
const timezone = $('#editArrivalTimezone').val();
// 检查是否有图片预览如果没有清空POD
const editUploadedArrivalPODs = $('#editUploadedArrivalPODs');
const hasImages = editUploadedArrivalPODs.find('img').length > 0;
// 先上传图片
const files = $('#editArrivalPODUpload')[0].files;
if (files.length > 0) {
const handoverNumber = $('#editArrivalHandoverNumber').val() || 'EDIT_ARRIVAL_' + id;
const uniqueIds = [];
const imageUrls = [];
// 预生成S3链接
for (let i = 0; i < files.length; i++) {
const file = files[i];
const uniqueId = generateGuid();
uniqueIds.push(uniqueId);
const imageUrl = generateS3Url('arrival', handoverNumber, file.name, uniqueId);
imageUrls.push(imageUrl);
}
// 上传图片
uploadFilesWithForm(files, 'arrival', handoverNumber, uniqueIds);
// 延迟更新,确保图片上传完成
setTimeout(function() {
// 合并已有的POD链接和新上传的图片链接
let newPod = imageUrls.join(',');
// 直接保存所有字段包括POD
saveArrivalHandoverFields(id, logisticsProviderArrivalTime, receiptTime, newPod, remarks, timezone);
}, 2000);
} else {
// 没有新图片,直接保存
// 明确检查是否有图片如果没有强制清空POD
const finalPod = hasImages ? $('#editArrivalPOD').val().trim() : '';
// 确保POD字段被正确传递
console.log('Saving arrival handover with POD:', finalPod);
saveArrivalHandoverFields(id, logisticsProviderArrivalTime, receiptTime, finalPod, remarks, timezone);
}
}
// 保存到货交接单字段
function saveArrivalHandoverFields(id, logisticsProviderArrivalTime, receiptTime, pod, remarks, timezone) {
const url = getBaseUrl() + '/api/arrival-handover/update/' + id;
// 构建请求数据
const data = {
TimeZone: timezone
};
// 只有当值不为空时才传递
if (logisticsProviderArrivalTime) {
data.LogisticsProviderArrivalTime = logisticsProviderArrivalTime;
}
if (receiptTime) {
data.ReceiptTime = receiptTime;
}
if (remarks) {
data.Remarks = remarks;
}
// 总是传递 POD 字段,当为空时传递 null
data.POD = pod && pod.trim() !== '' ? pod : null;
// 确保POD字段被正确传递
console.log('Sending POD to server:', data.POD);
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'updateArrivalHandoverCallback',
data: data,
success: function(response) {
if (response.code === 0) {
showBubbleNotification('更新成功');
$('#editArrivalHandoverModal').modal('hide');
// 重新查询
$('#arrivalHandoverForm').submit();
} else {
showBubbleNotification('更新失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
// 更新到货交接单回调函数
function updateArrivalHandoverCallback(response) {
if (response.code === 0) {
showBubbleNotification('更新成功');
$('#editArrivalHandoverModal').modal('hide');
// 重新查询
$('#arrivalHandoverForm').submit();
} else {
showBubbleNotification('更新失败: ' + response.message);
}
}
// 时区选择变化
$('#timezone').change(function() {
// 可以在这里添加时区变化的处理逻辑
showBubbleNotification('时区已更新');
});
// 监听集包数据查询每页记录数选择变化
$('#bagTagPageSize').change(function() {
if ($(this).val() === 'custom') {
$('#customBagTagPageSizeContainer').show();
} else {
$('#customBagTagPageSizeContainer').hide();
}
});
// 集包数据查询表单提交
$('#bagTagForm').submit(function(e) {
e.preventDefault();
const page = 1;
const pageSize = getBagTagPageSize();
const sortBy = $('#bagTagSortBy').val();
const sortOrder = $('#bagTagSortOrder').val();
const tagNumber = $('#bagTagNumber').val();
const channel = $('#bagTagChannel').val();
const status = $('#bagTagStatus').val();
const creator = $('#bagTagCreator').val();
const bagTagStartCreatedAt = $('#bagTagStartCreatedAt').val();
const bagTagEndCreatedAt = $('#bagTagEndCreatedAt').val();
const url = getBaseUrl() + '/api/bagtag/batch?page=' + page + '&pageSize=' + pageSize + '&sortBy=' + sortBy + '&sortOrder=' + sortOrder + '&tagNumber=' + tagNumber + '&channel=' + channel + '&status=' + status + '&creator=' + creator + '&startCreatedAt=' + bagTagStartCreatedAt + '&endCreatedAt=' + bagTagEndCreatedAt;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'jsonpCallback',
success: function(response) {
if (response.status === 'ok') {
renderBagTagTable(response.data);
renderPagination('bagTag', response.page, response.pageSize, response.totalPages, response.totalCount);
showBubbleNotification('共找到 ' + response.totalCount + ' 条记录');
} else {
showBubbleNotification('查询失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
});
// 重置集包数据查询表单
$('#resetBagTagForm').click(function() {
$('#bagTagForm')[0].reset();
$('#customBagTagPageSizeContainer').hide();
});
// 集包数据导出Excel
$('#exportBagTagExcelBtn').click(function() {
// 检查是否有数据
const bagTagData = window.bagTagData;
if (!bagTagData || bagTagData.length === 0) {
showBubbleNotification('没有数据可导出');
return;
}
showBubbleNotification('正在准备导出数据,请稍候...');
// 获取当前查询参数
const sortBy = $('#bagTagSortBy').val();
const sortOrder = $('#bagTagSortOrder').val();
const tagNumber = $('#bagTagNumber').val();
const channel = $('#bagTagChannel').val();
const status = $('#bagTagStatus').val();
const creator = $('#bagTagCreator').val();
const bagTagStartCreatedAt = $('#bagTagStartCreatedAt').val();
const bagTagEndCreatedAt = $('#bagTagEndCreatedAt').val();
// 封装JSONP请求为Promise
function jsonpRequest(url) {
return new Promise((resolve, reject) => {
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
success: resolve,
error: reject
});
});
}
// 获取所有袋牌数据
async function getAllBagTagData() {
try {
// 首先获取第一页数据和总页数
const firstPageUrl = getBaseUrl() + '/api/bagtag/batch?page=1&pageSize=100&sortBy=' + sortBy + '&sortOrder=' + sortOrder + '&tagNumber=' + tagNumber + '&channel=' + channel + '&status=' + status + '&creator=' + creator + '&startCreatedAt=' + bagTagStartCreatedAt + '&endCreatedAt=' + bagTagEndCreatedAt;
const firstPageResponse = await jsonpRequest(firstPageUrl);
if (firstPageResponse.status !== 'ok') {
throw new Error('获取第一页数据失败: ' + (firstPageResponse.message || '未知错误'));
}
const totalPages = firstPageResponse.totalPages;
const allBagTagData = [...firstPageResponse.data];
// 获取剩余页的数据
for (let page = 2; page <= totalPages; page++) {
const pageUrl = getBaseUrl() + '/api/bagtag/batch?page=' + page + '&pageSize=100&sortBy=' + sortBy + '&sortOrder=' + sortOrder + '&tagNumber=' + tagNumber + '&channel=' + channel + '&status=' + status + '&creator=' + creator + '&startCreatedAt=' + bagTagStartCreatedAt + '&endCreatedAt=' + bagTagEndCreatedAt;
const pageResponse = await jsonpRequest(pageUrl);
if (pageResponse.status === 'ok') {
allBagTagData.push(...pageResponse.data);
} else {
console.warn('获取第 ' + page + ' 页数据失败,跳过该页');
}
}
return allBagTagData;
} catch (error) {
console.error('获取袋牌数据失败:', error);
throw error;
}
}
// 获取单个袋牌的运单数据
async function getWaybillsForBagTag(bagTag) {
try {
if (bagTag.waybillCount <= 0) {
return [];
}
const url = getBaseUrl() + '/api/bagtag/' + bagTag.tagNumber + '/waybills';
const response = await jsonpRequest(url);
if (response.code === 0 && response.data) {
return response.data;
} else {
console.warn('获取袋牌 ' + bagTag.tagNumber + ' 的运单数据失败:', response.message);
return [];
}
} catch (error) {
console.error('获取袋牌 ' + bagTag.tagNumber + ' 的运单数据失败:', error);
return [];
}
}
// 主导出逻辑
async function exportData() {
try {
// 获取所有袋牌数据
const allBagTagData = await getAllBagTagData();
if (allBagTagData.length === 0) {
showBubbleNotification('没有数据可导出');
return;
}
// 准备袋牌信息数据
const bagTagSheetData = allBagTagData.map(item => {
return {
'袋牌号码': item.tagNumber || '-',
'渠道': item.channelName || '-',
'状态': item.status || '-',
'创建人': item.creator || '-',
'创建时间': item.createdAt ? new Date(item.createdAt).toLocaleString() : '-',
'打开时间': item.openedAt ? new Date(item.openedAt).toLocaleString() : '-',
'关闭时间': item.closedAt ? new Date(item.closedAt).toLocaleString() : '-',
'关联运单数量': item.waybillCount || 0
};
});
// 准备小包明细数据
const waybillSheetData = [];
// 逐个获取每个袋牌的运单数据
for (const bagTag of allBagTagData) {
const waybills = await getWaybillsForBagTag(bagTag);
// 添加运单数据到导出列表
waybills.forEach(w => {
waybillSheetData.push({
'袋牌号码': bagTag.tagNumber || '-',
'尾程跟踪单号': w.FinalMileTrackingNumber || '-',
'中性面单号': w.NeutralWaybillNumber || '-',
'换单完成时间': w.ReplaceCompletedTime ? new Date(w.ReplaceCompletedTime).toLocaleString() : '-',
'提单号': w.BillOfLadingNumber || '-',
'客户简称': w.CustomerAbbreviation || '-',
'创建人': w.Creator || '-',
'创建时间': w.CreatedAt ? new Date(w.CreatedAt).toLocaleString() : '-',
'备注': w.Remark || '-'
});
});
}
// 验证数据一致性
const expectedWaybillCount = bagTagSheetData.reduce((total, item) => total + (item['关联运单数量'] || 0), 0);
const actualWaybillCount = waybillSheetData.length;
console.log('验证数据一致性:');
console.log('预期运单数量:', expectedWaybillCount);
console.log('实际运单数量:', actualWaybillCount);
if (expectedWaybillCount !== actualWaybillCount) {
console.warn('运单数量不一致,可能存在数据缺失');
showBubbleNotification('警告: 运单数量可能存在不一致,导出数据可能不完整');
}
// 导出Excel
exportExcel([
{
sheetName: '袋牌信息',
data: bagTagSheetData
},
{
sheetName: '小包明细',
data: waybillSheetData
}
], '集包数据');
showBubbleNotification('导出完成');
} catch (error) {
console.error('导出失败:', error);
showBubbleNotification('导出失败: ' + (error.message || '未知错误'));
}
}
// 开始导出过程
exportData();
});
// 获取实际的页大小
function getPageSize() {
const pageSize = $('#pageSize').val();
if (pageSize === 'custom') {
const customSize = $('#customPageSize').val();
return customSize || 500;
}
return pageSize;
}
// 获取扫描记录查询的实际页大小
function getScanPageSize() {
const pageSize = $('#scanPageSize').val();
if (pageSize === 'custom') {
const customSize = $('#customScanPageSize').val();
return customSize || 500;
}
return pageSize;
}
// 获得到货批次查询的实际页大小
function getArrivalPageSize() {
const pageSize = $('#arrivalPageSize').val();
if (pageSize === 'custom') {
const customSize = $('#customArrivalPageSize').val();
return customSize || 500;
}
return pageSize;
}
// 获取集包数据查询的实际页大小
function getBagTagPageSize() {
const pageSize = $('#bagTagPageSize').val();
if (pageSize === 'custom') {
const customSize = $('#customBagTagPageSize').val();
return customSize || 500;
}
return pageSize;
}
// 结果映射
const scanResultMap = {
0: '已返回面单',
1: '无面单数据',
2: '无下单数据',
3: '订单被冻结',
4: '订单已销毁',
5: '其他'
};
// 标签替换请求查询
$('#labelReplaceForm').submit(function(e) {
e.preventDefault();
const page = 1;
const pageSize = getPageSize();
const sortBy = $('#sortBy').val();
const sortOrder = $('#sortOrder').val();
const billOfLadingNumber = $('#billOfLadingNumber').val();
const masterPackageNumber = $('#masterPackageNumber').val();
const referenceNumber = $('#referenceNumber').val();
const neutralWaybillNumber = $('#neutralWaybillNumber').val().trim().replace(/\s+/g, ','); // 将多行输入转换为逗号分隔的字符串
const finalMileTrackingNumber = $('#finalMileTrackingNumber').val();
const replaceStatus = $('#replaceStatus').val();
const customerId = $('#customerId').val();
const startCreatedAt = $('#startCreatedAt').val();
const endCreatedAt = $('#endCreatedAt').val();
const startReplacedAt = $('#startReplacedAt').val();
const endReplacedAt = $('#endReplacedAt').val();
const url = getBaseUrl() + '/api/Label/label-replace/batch?page=' + page + '&pageSize=' + pageSize + '&sortBy=' + sortBy + '&sortOrder=' + sortOrder + '&billOfLadingNumber=' + billOfLadingNumber + '&masterPackageNumber=' + masterPackageNumber + '&referenceNumber=' + referenceNumber + '&neutralWaybillNumber=' + neutralWaybillNumber + '&finalMileTrackingNumber=' + finalMileTrackingNumber + '&replaceStatus=' + replaceStatus + '&customerId=' + customerId + '&startCreatedAt=' + startCreatedAt + '&endCreatedAt=' + endCreatedAt + '&startReplacedAt=' + startReplacedAt + '&endReplacedAt=' + endReplacedAt;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'jsonpCallback',
success: function(response) {
if (response.status === 'ok') {
renderLabelReplaceTable(response.data);
renderPagination('labelReplace', response.page, response.pageSize, response.totalPages, response.totalCount);
// 显示气泡弹窗
showBubbleNotification('共找到 ' + response.totalCount + ' 条记录');
} else {
showBubbleNotification('查询失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
});
// 标签扫描记录查询
$('#labelScanForm').submit(function(e) {
e.preventDefault();
const page = 1;
const pageSize = getScanPageSize();
const sortBy = $('#scanSortBy').val();
const sortOrder = $('#scanSortOrder').val();
const customerId = $('#scanCustomerId').val();
const neutralWaybillNumber = $('#scanNeutralWaybillNumber').val();
const finalMileTrackingNumber = $('#scanFinalMileTrackingNumber').val();
const result = $('#scanResult').val();
const scanStartCreatedAt = $('#scanStartCreatedAt').val();
const scanEndCreatedAt = $('#scanEndCreatedAt').val();
const url = getBaseUrl() + '/api/Label/label-scan/batch?page=' + page + '&pageSize=' + pageSize + '&sortBy=' + sortBy + '&sortOrder=' + sortOrder + '&customerId=' + customerId + '&neutralWaybillNumber=' + neutralWaybillNumber + '&finalMileTrackingNumber=' + finalMileTrackingNumber + '&result=' + result + '&startCreatedAt=' + scanStartCreatedAt + '&endCreatedAt=' + scanEndCreatedAt;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'jsonpCallback',
success: function(response) {
if (response.status === 'ok') {
renderLabelScanTable(response.data);
renderPagination('labelScan', response.page, response.pageSize, response.totalPages, response.totalCount);
// 显示气泡弹窗
showBubbleNotification('共找到 ' + response.totalCount + ' 条记录');
} else {
showBubbleNotification('查询失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
});
// 渲染标签替换请求表格
function renderLabelReplaceTable(data) {
const tbody = $('#labelReplaceTableBody');
tbody.empty();
if (data.length === 0) {
tbody.append('<tr><td colspan="12" class="text-center">暂无数据</td></tr>');
return;
}
data.forEach(item => {
const row = $('<tr></tr>');
row.append(`<td>${item.Id || '-'}</td>`);
row.append(`<td>${item.CustomerCode || '-'}</td>`);
row.append(`<td>${item.BillOfLadingNumber || '-'}</td>`);
row.append(`<td>${item.MasterPackageNumber || '-'}</td>`);
row.append(`<td>${item.NeutralWaybillNumber || '-'}</td>`);
row.append(`<td>${item.FinalMileTrackingNumber || '-'}</td>`);
row.append(`<td>${item.BagTagNumber || '-'}</td>`);
// 有无面单字段 - 根据 Label 字段判断
const hasLabel = item.Label && item.Label.trim() !== '';
if (hasLabel) {
// 检查是否为 URL 资源
if (item.Label.startsWith('http://') || item.Label.startsWith('https://')) {
const encodedUrl = encodeURIComponent(item.Label);
row.append(`<td><span class="text-success cursor-pointer" data-url="${encodedUrl}">有</span></td>`);
} else {
// 非 URL 资源,显示原数据
row.append(`<td><span class="text-success cursor-pointer" data-content="${item.Label}">有</span></td>`);
}
} else {
row.append(`<td><span class="text-muted cursor-pointer" data-content="无">无</span></td>`);
}
row.append(`<td>${item.ReplaceStatus === 'Y' ? '正常换单' : '冻结换单'}</td>`);
row.append(`<td>${item.ReplacedAt ? new Date(item.ReplacedAt).toLocaleString() : '-'}</td>`);
row.append(`<td>${item.LabelRetrievedAt ? new Date(item.LabelRetrievedAt).toLocaleString() : '-'}</td>`);
row.append(`<td>${item.CreatedAt ? new Date(item.CreatedAt).toLocaleString() : '-'}</td>`);
tbody.append(row);
});
// 添加点击预览事件(使用事件委托,确保动态生成的元素也能触发)
$('#labelReplaceTableBody').on('click', '.cursor-pointer', function() {
// 检查是否有 data-url 属性URL 资源)
if ($(this).data('url')) {
const encodedUrl = $(this).data('url');
if (encodedUrl) {
const url = decodeURIComponent(encodedUrl);
// 直接打开 URL 资源
window.open(url, '_blank');
}
}
// 检查是否有 data-content 属性(非 URL 资源)
else if ($(this).data('content')) {
const content = $(this).data('content');
if (content) {
// 显示原数据
$('#labelPreviewContent').html(`<p class="border p-3 rounded bg-light">${content}</p>`);
$('#labelPreviewModal').modal('show');
}
}
});
}
// 渲染标签扫描记录表格
function renderLabelScanTable(data) {
const tbody = $('#labelScanTableBody');
tbody.empty();
if (data.length === 0) {
tbody.append('<tr><td colspan="8" class="text-center">暂无数据</td></tr>');
return;
}
data.forEach(item => {
const row = $('<tr></tr>');
row.append(`<td>${item.Id || '-'}</td>`);
row.append(`<td>${item.CustomerCode || '-'}</td>`);
row.append(`<td>${item.NeutralWaybillNumber || '-'}</td>`);
row.append(`<td>${item.FinalMileTrackingNumber || '-'}</td>`);
row.append(`<td>${scanResultMap[item.Result] || item.Result || '-'}</td>`);
row.append(`<td>${item.Description || '-'}</td>`);
row.append(`<td>${item.CreatedBy || '-'}</td>`);
row.append(`<td>${item.CreatedAt ? new Date(item.CreatedAt).toLocaleString() : '-'}</td>`);
tbody.append(row);
});
}
// 渲染到货批次表格
function renderArrivalBatchTable(data) {
const tbody = $('#arrivalBatchTableBody');
tbody.empty();
if (data.length === 0) {
tbody.append('<tr><td colspan="8" class="text-center">暂无数据</td></tr>');
return;
}
data.forEach(item => {
const row = $('<tr></tr>');
// 转换时间格式为datetime-local所需的格式
let logisticsDeliveryTime = '';
let warehouseReceiptTime = '';
if (item.LogisticsDeliveryTime) {
const logisticsTime = new Date(item.LogisticsDeliveryTime);
logisticsDeliveryTime = logisticsTime.toISOString().slice(0, 16);
}
if (item.WarehouseReceiptTime) {
const warehouseTime = new Date(item.WarehouseReceiptTime);
warehouseReceiptTime = warehouseTime.toISOString().slice(0, 16);
}
row.append(`<td><input type="checkbox" class="batch-checkbox" data-id="${item.Id}"></td>`);
row.append(`<td>${item.Id || '-'}</td>`);
row.append(`<td><input type="text" class="form-control" data-field="TrackingNumber" data-id="${item.Id}" value="${item.TrackingNumber || ''}"></td>`);
row.append(`<td><input type="datetime-local" class="form-control" data-field="LogisticsDeliveryTime" data-id="${item.Id}" value="${logisticsDeliveryTime}"></td>`);
row.append(`<td><input type="datetime-local" class="form-control" data-field="WarehouseReceiptTime" data-id="${item.Id}" value="${warehouseReceiptTime}"></td>`);
row.append(`<td>${item.CreatedAt ? new Date(item.CreatedAt).toLocaleString() : '-'}</td>`);
row.append(`<td>${item.UpdatedAt ? new Date(item.UpdatedAt).toLocaleString() : '-'}</td>`);
row.append(`<td>
<button class="btn btn-sm btn-success me-1" onclick="saveBatchEdit(${item.Id})">保存</button>
<button class="btn btn-sm btn-danger" onclick="deleteArrivalBatch(${item.Id})">删除</button>
</td>`);
tbody.append(row);
});
// 绑定输入框变化事件
$('.form-control[data-field]').change(function() {
const id = $(this).data('id');
const field = $(this).data('field');
const value = $(this).val();
// 可以在这里添加实时验证或其他处理
});
}
// 渲染集包数据表格
function renderBagTagTable(data) {
const tbody = $('#bagTagTableBody');
tbody.empty();
// 存储数据到全局变量,用于导出
window.bagTagData = data;
if (data.length === 0) {
tbody.append('<tr><td colspan="10" class="text-center">暂无数据</td></tr>');
return;
}
data.forEach(item => {
// 主行
const row = $('<tr class="bag-tag-row"></tr>');
row.append(`<td>${item.id || '-'}</td>`);
row.append(`<td>${item.tagNumber || '-'}</td>`);
row.append(`<td>${item.channelName || '-'}</td>`);
row.append(`<td>${item.status || '-'}</td>`);
row.append(`<td>${item.creator || '-'}</td>`);
row.append(`<td>${item.createdAt ? new Date(item.createdAt).toLocaleString() : '-'}</td>`);
row.append(`<td>${item.openedAt ? new Date(item.openedAt).toLocaleString() : '-'}</td>`);
row.append(`<td>${item.closedAt ? new Date(item.closedAt).toLocaleString() : '-'}</td>`);
row.append(`<td>${item.waybillCount || 0}</td>`);
row.append(`<td><button class="btn btn-sm btn-primary view-waybills" data-tag-number="${item.tagNumber}">${item.waybillCount > 0 ? '查看运单' : '无运单'}</button></td>`);
tbody.append(row);
// 运单明细行(默认隐藏,动态加载)
const waybillRow = $('<tr class="waybill-detail-row" style="display: none;"></tr>');
waybillRow.append(`<td colspan="10">
<div class="p-3 bg-light rounded">
<h6 class="mb-2">袋牌 ${item.tagNumber} 的运单明细</h6>
<div class="table-responsive" id="waybill-content-${item.tagNumber}">
<div class="text-center p-3">加载中...</div>
</div>
</div>
</td>`);
tbody.append(waybillRow);
});
// 绑定查看运单按钮事件
$('.view-waybills').click(function() {
const tagNumber = $(this).data('tag-number');
const row = $(this).closest('.bag-tag-row');
const waybillRow = row.next('.waybill-detail-row');
if (waybillRow.length > 0) {
if (waybillRow.is(':visible')) {
waybillRow.hide();
$(this).text('查看运单');
} else {
waybillRow.show();
$(this).text('收起运单');
// 动态加载运单明细
const contentDiv = $(`#waybill-content-${tagNumber}`);
// 检查是否已经有缓存数据
const bagTagItem = window.bagTagData.find(item => item.tagNumber === tagNumber);
if (bagTagItem && bagTagItem.waybills) {
// 使用缓存数据
const waybills = bagTagItem.waybills;
if (waybills.length > 0) {
let html = `
<table class="table table-sm table-striped">
<thead>
<tr>
<th>尾程跟踪单号</th>
<th>创建人</th>
<th>创建时间</th>
<th>备注</th>
</tr>
</thead>
<tbody>
${waybills.map(w => `
<tr>
<td>${w.finalMileTrackingNumber || '-'}</td>
<td>${w.creator || '-'}</td>
<td>${w.createdAt ? new Date(w.createdAt).toLocaleString() : '-'}</td>
<td>${w.remark || '-'}</td>
</tr>
`).join('')}
</tbody>
</table>
`;
contentDiv.html(html);
} else {
contentDiv.html('<div class="text-center p-3">无运单数据</div>');
}
} else {
// 首次加载,从服务器获取数据
contentDiv.html('<div class="text-center p-3">加载中...</div>');
const url = getBaseUrl() + '/api/bagtag/' + tagNumber + '/waybills';
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'jsonpCallback',
success: function(response) {
if (response.code === 0 && response.data) {
const waybills = response.data;
// 转换数据格式并缓存
const formattedWaybills = waybills.map(w => ({
finalMileTrackingNumber: w.FinalMileTrackingNumber,
neutralWaybillNumber: w.NeutralWaybillNumber,
replaceCompletedTime: w.ReplaceCompletedTime,
billOfLadingNumber: w.BillOfLadingNumber,
customerAbbreviation: w.CustomerAbbreviation,
creator: w.Creator,
createdAt: w.CreatedAt,
remark: w.Remark
}));
// 存储到bagTagData中
if (bagTagItem) {
bagTagItem.waybills = formattedWaybills;
}
if (waybills.length > 0) {
let html = `
<table class="table table-sm table-striped">
<thead>
<tr>
<th>尾程跟踪单号</th>
<th>创建人</th>
<th>创建时间</th>
<th>备注</th>
</tr>
</thead>
<tbody>
${waybills.map(w => `
<tr>
<td>${w.FinalMileTrackingNumber || '-'}</td>
<td>${w.Creator || '-'}</td>
<td>${w.CreatedAt ? new Date(w.CreatedAt).toLocaleString() : '-'}</td>
<td>${w.Remark || '-'}</td>
</tr>
`).join('')}
</tbody>
</table>
`;
contentDiv.html(html);
} else {
contentDiv.html('<div class="text-center p-3">无运单数据</div>');
}
} else {
contentDiv.html('<div class="text-center p-3 text-danger">加载失败: ' + (response.message || '未知错误') + '</div>');
}
},
error: function(xhr, status, error) {
contentDiv.html('<div class="text-center p-3 text-danger">请求失败: ' + error + '</div>');
}
});
}
}
} else {
showBubbleNotification(`袋牌 ${tagNumber} 无关联运单`);
}
});
}
// 保存编辑
function saveBatchEdit(id) {
const trackingNumber = $(`input[data-field="TrackingNumber"][data-id="${id}"]`).val();
const logisticsDeliveryTime = $(`input[data-field="LogisticsDeliveryTime"][data-id="${id}"]`).val();
const warehouseReceiptTime = $(`input[data-field="WarehouseReceiptTime"][data-id="${id}"]`).val();
const timezone = $('#timezone').val();
const url = getBaseUrl() + '/api/arrival-batch/' + id;
$.ajax({
url: url,
type: 'PUT',
data: JSON.stringify({
trackingNumber: trackingNumber,
logisticsDeliveryTime: logisticsDeliveryTime,
warehouseReceiptTime: warehouseReceiptTime,
timezone: timezone
}),
contentType: 'application/json',
success: function(response) {
if (response.status === 'ok') {
showBubbleNotification('到货批次更新成功');
// 重新查询
$('#arrivalBatchForm').submit();
} else {
showBubbleNotification('更新失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
// 编辑到货批次
function editArrivalBatch(id, trackingNumber, logisticsDeliveryTime, warehouseReceiptTime) {
$('#editBatchId').val(id);
$('#editTrackingNumber').val(trackingNumber);
// 转换时间格式为datetime-local所需的格式
if (logisticsDeliveryTime) {
const logisticsTime = new Date(logisticsDeliveryTime);
$('#editLogisticsDeliveryTime').val(logisticsTime.toISOString().slice(0, 16));
}
if (warehouseReceiptTime) {
const warehouseTime = new Date(warehouseReceiptTime);
$('#editWarehouseReceiptTime').val(warehouseTime.toISOString().slice(0, 16));
}
$('#editArrivalBatchModal').modal('show');
}
// 删除到货批次
function deleteArrivalBatch(id) {
if (confirm('确定要删除这个到货批次吗?')) {
const url = getBaseUrl() + '/api/arrival-batch/' + id;
$.ajax({
url: url,
type: 'DELETE',
success: function(response) {
if (response.status === 'ok') {
showBubbleNotification('到货批次删除成功');
// 重新查询
$('#arrivalBatchForm').submit();
} else {
showBubbleNotification('删除失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('请求失败: ' + error);
}
});
}
}
// 渲染分页控件
function renderPagination(prefix, currentPage, pageSize, totalPages, totalCount) {
const pagination = $(`#${prefix}Pagination`);
const paginationInfo = $(`#${prefix}PaginationInfo`);
paginationInfo.text(`${totalCount} 条记录,第 ${currentPage} / ${totalPages}`);
pagination.empty();
// 上一页
const prevLi = $('<li class="page-item"></li>');
const prevLink = $('<a class="page-link" href="#">上一页</a>');
if (currentPage === 1) {
prevLi.addClass('disabled');
} else {
prevLink.click(function(e) {
e.preventDefault();
loadPage(prefix, currentPage - 1);
});
}
prevLi.append(prevLink);
pagination.append(prevLi);
// 页码
if (totalPages <= 7) {
// 总页数较少,显示所有页码
for (let i = 1; i <= totalPages; i++) {
const li = $('<li class="page-item"></li>');
const link = $('<a class="page-link" href="#">' + i + '</a>');
if (i === currentPage) {
li.addClass('active');
} else {
link.click(function(e) {
e.preventDefault();
loadPage(prefix, i);
});
}
li.append(link);
pagination.append(li);
}
} else {
// 总页数较多,显示部分页码
// 显示第一页
const firstLi = $('<li class="page-item"></li>');
const firstLink = $('<a class="page-link" href="#">1</a>');
if (currentPage === 1) {
firstLi.addClass('active');
} else {
firstLink.click(function(e) {
e.preventDefault();
loadPage(prefix, 1);
});
}
firstLi.append(firstLink);
pagination.append(firstLi);
// 显示省略号
if (currentPage > 4) {
const ellipsis1 = $('<li class="page-item disabled"><a class="page-link" href="#">...</a></li>');
pagination.append(ellipsis1);
}
// 显示当前页附近的页码
const startPage = Math.max(2, currentPage - 2);
const endPage = Math.min(totalPages - 1, currentPage + 2);
for (let i = startPage; i <= endPage; i++) {
const li = $('<li class="page-item"></li>');
const link = $('<a class="page-link" href="#">' + i + '</a>');
if (i === currentPage) {
li.addClass('active');
} else {
link.click(function(e) {
e.preventDefault();
loadPage(prefix, i);
});
}
li.append(link);
pagination.append(li);
}
// 显示省略号
if (currentPage < totalPages - 3) {
const ellipsis2 = $('<li class="page-item disabled"><a class="page-link" href="#">...</a></li>');
pagination.append(ellipsis2);
}
// 显示最后一页
const lastLi = $('<li class="page-item"></li>');
const lastLink = $('<a class="page-link" href="#">' + totalPages + '</a>');
if (currentPage === totalPages) {
lastLi.addClass('active');
} else {
lastLink.click(function(e) {
e.preventDefault();
loadPage(prefix, totalPages);
});
}
lastLi.append(lastLink);
pagination.append(lastLi);
}
// 下一页
const nextLi = $('<li class="page-item"></li>');
const nextLink = $('<a class="page-link" href="#">下一页</a>');
if (currentPage === totalPages) {
nextLi.addClass('disabled');
} else {
nextLink.click(function(e) {
e.preventDefault();
loadPage(prefix, currentPage + 1);
});
}
nextLi.append(nextLink);
pagination.append(nextLi);
}
// 加载指定页码
function loadPage(prefix, page) {
if (prefix === 'labelReplace') {
const pageSize = getPageSize();
const sortBy = $('#sortBy').val();
const sortOrder = $('#sortOrder').val();
const billOfLadingNumber = $('#billOfLadingNumber').val();
const masterPackageNumber = $('#masterPackageNumber').val();
const referenceNumber = $('#referenceNumber').val();
const neutralWaybillNumber = $('#neutralWaybillNumber').val().trim().replace(/\s+/g, ','); // 将多行输入转换为逗号分隔的字符串
const finalMileTrackingNumber = $('#finalMileTrackingNumber').val();
const replaceStatus = $('#replaceStatus').val();
const customerId = $('#customerId').val();
const url = getBaseUrl() + '/api/Label/label-replace/batch?page=' + page + '&pageSize=' + pageSize + '&sortBy=' + sortBy + '&sortOrder=' + sortOrder + '&billOfLadingNumber=' + billOfLadingNumber + '&masterPackageNumber=' + masterPackageNumber + '&referenceNumber=' + referenceNumber + '&neutralWaybillNumber=' + neutralWaybillNumber + '&finalMileTrackingNumber=' + finalMileTrackingNumber + '&replaceStatus=' + replaceStatus + '&customerId=' + customerId;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'jsonpCallback',
success: function(response) {
if (response.status === 'ok') {
renderLabelReplaceTable(response.data);
renderPagination('labelReplace', response.page, response.pageSize, response.totalPages, response.totalCount);
// 显示通知
$('#resultCount').text(response.totalCount);
const toast = new bootstrap.Toast($('#queryNotification'));
toast.show();
} else {
alert('查询失败: ' + response.message);
}
},
error: function(xhr, status, error) {
alert('请求失败: ' + error);
}
});
} else if (prefix === 'labelScan') {
const pageSize = getScanPageSize();
const sortBy = $('#scanSortBy').val();
const sortOrder = $('#scanSortOrder').val();
const customerId = $('#scanCustomerId').val();
const neutralWaybillNumber = $('#scanNeutralWaybillNumber').val();
const finalMileTrackingNumber = $('#scanFinalMileTrackingNumber').val();
const result = $('#scanResult').val();
const url = getBaseUrl() + '/api/Label/label-scan/batch?page=' + page + '&pageSize=' + pageSize + '&sortBy=' + sortBy + '&sortOrder=' + sortOrder + '&customerId=' + customerId + '&neutralWaybillNumber=' + neutralWaybillNumber + '&finalMileTrackingNumber=' + finalMileTrackingNumber + '&result=' + result;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'jsonpCallback',
success: function(response) {
if (response.status === 'ok') {
renderLabelScanTable(response.data);
renderPagination('labelScan', response.page, response.pageSize, response.totalPages, response.totalCount);
// 显示通知
$('#resultCount').text(response.totalCount);
const toast = new bootstrap.Toast($('#queryNotification'));
toast.show();
} else {
alert('查询失败: ' + response.message);
}
},
error: function(xhr, status, error) {
alert('请求失败: ' + error);
}
});
} else if (prefix === 'arrivalBatch') {
const pageSize = getArrivalPageSize();
const sortBy = $('#arrivalSortBy').val();
const sortOrder = $('#arrivalSortOrder').val();
const trackingNumber = $('#trackingNumber').val().trim().replace(/\s+/g, ','); // 将多行输入转换为逗号分隔的字符串
const url = getBaseUrl() + '/api/arrival-batch/batch?page=' + page + '&pageSize=' + pageSize + '&sortBy=' + sortBy + '&sortOrder=' + sortOrder + '&trackingNumber=' + trackingNumber;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: 'jsonpCallback',
success: function(response) {
if (response.status === 'ok') {
renderArrivalBatchTable(response.data);
renderPagination('arrivalBatch', response.page, response.pageSize, response.totalPages, response.totalCount);
} else {
alert('查询失败: ' + response.message);
}
},
error: function(xhr, status, error) {
alert('请求失败: ' + error);
}
});
}
}
// 重置标签替换请求表单
$('#resetLabelReplaceForm').click(function() {
$('#labelReplaceForm')[0].reset();
});
// 重置标签扫描记录表单
$('#resetLabelScanForm').click(function() {
$('#labelScanForm')[0].reset();
});
// 导出标签替换请求Excel
$('#exportExcelBtn').click(function() {
const billOfLadingNumber = $('#billOfLadingNumber').val();
const masterPackageNumber = $('#masterPackageNumber').val();
const referenceNumber = $('#referenceNumber').val();
const neutralWaybillNumber = $('#neutralWaybillNumber').val().trim().replace(/\s+/g, ','); // 将多行输入转换为逗号分隔的字符串
const finalMileTrackingNumber = $('#finalMileTrackingNumber').val();
const replaceStatus = $('#replaceStatus').val();
const customerId = $('#customerId').val();
const startCreatedAt = $('#startCreatedAt').val();
const endCreatedAt = $('#endCreatedAt').val();
const url = getBaseUrl() + '/api/Label/label-replace/export-excel?billOfLadingNumber=' + billOfLadingNumber + '&masterPackageNumber=' + masterPackageNumber + '&referenceNumber=' + referenceNumber + '&neutralWaybillNumber=' + neutralWaybillNumber + '&finalMileTrackingNumber=' + finalMileTrackingNumber + '&replaceStatus=' + replaceStatus + '&customerId=' + customerId + '&startCreatedAt=' + startCreatedAt + '&endCreatedAt=' + endCreatedAt;
// 打开新窗口下载Excel文件
window.open(url, '_blank');
});
// 导出标签扫描记录Excel
$('#exportScanExcelBtn').click(function() {
const customerId = $('#scanCustomerId').val();
const neutralWaybillNumber = $('#scanNeutralWaybillNumber').val();
const finalMileTrackingNumber = $('#scanFinalMileTrackingNumber').val();
const result = $('#scanResult').val();
const url = getBaseUrl() + '/api/Label/label-scan/export-excel?customerId=' + customerId + '&neutralWaybillNumber=' + neutralWaybillNumber + '&finalMileTrackingNumber=' + finalMileTrackingNumber + '&result=' + result;
// 打开新窗口下载Excel文件
window.open(url, '_blank');
});
// 导出Excel函数
function exportExcel(sheets, fileName) {
// 获取当前时间并格式化
const now = new Date();
const timeStr = now.getFullYear() + '-' +
(now.getMonth() + 1).toString().padStart(2, '0') + '-' +
now.getDate().toString().padStart(2, '0') + ' ' +
now.getHours().toString().padStart(2, '0') + '-' +
now.getMinutes().toString().padStart(2, '0') + '-' +
now.getSeconds().toString().padStart(2, '0');
// 创建一个新的工作簿
const wb = XLSX.utils.book_new();
// 为每个sheet添加数据
sheets.forEach(sheet => {
// 将JSON数据转换为工作表
const ws = XLSX.utils.json_to_sheet(sheet.data);
// 将工作表添加到工作簿
XLSX.utils.book_append_sheet(wb, ws, sheet.sheetName);
});
// 导出Excel文件文件名包含导出时间
XLSX.writeFile(wb, fileName + ' ' + timeStr + '.xlsx');
}
// 编辑出货交接单
$('.edit-btn').click(function() {
const id = $(this).data('id');
// 获取出货交接单详情
const url = getBaseUrl() + '/api/shipping-handover/get/' + id;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
success: function(response) {
if (response.code === 0) {
const form = response.data;
// 填充编辑表单
$('#editFormId').val(form.Id);
$('#editDeliveryTime').val(form.DeliveryTime ? new Date(form.DeliveryTime).toISOString().slice(0, 16) : '');
$('#editTimezone').val(form.TimeZone || 'America/New_York');
$('#editRemarks').val(form.Remarks || '');
// 显示模态框
$('#editShippingHandoverModal').modal('show');
} else {
showBubbleNotification('获取出货交接单详情失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('获取出货交接单详情失败: ' + error);
}
});
});
// 保存编辑
$('#saveEditBtn').click(function() {
const id = $('#editFormId').val();
const deliveryTime = $('#editDeliveryTime').val();
const remarks = $('#editRemarks').val();
const timezone = $('#editTimezone').val();
// 发送更新请求
const url = getBaseUrl() + '/api/shipping-handover/update/' + id;
$.ajax({
url: url,
type: 'GET',
dataType: 'jsonp',
jsonp: 'callback',
data: {
DeliveryTime: deliveryTime,
Remarks: remarks,
TimeZone: timezone
},
success: function(response) {
if (response.code === 0) {
showBubbleNotification('编辑成功');
// 关闭模态框
$('#editShippingHandoverModal').modal('hide');
// 重新查询数据
$('#shippingHandoverForm').submit();
} else {
showBubbleNotification('编辑失败: ' + response.message);
}
},
error: function(xhr, status, error) {
showBubbleNotification('编辑失败: ' + error);
}
});
});
</script>
<!-- 编辑出货交接单模态框 -->
<div class="modal fade" id="editShippingHandoverModal" tabindex="-1" aria-labelledby="editShippingHandoverModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editShippingHandoverModalLabel">编辑出货交接单</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="editShippingHandoverForm">
<input type="hidden" id="editFormId">
<div class="mb-3">
<label for="editDeliveryTime" class="form-label">交货时间</label>
<input type="datetime-local" class="form-control" id="editDeliveryTime">
</div>
<div class="mb-3">
<label for="editTimezone" class="form-label">时区</label>
<select class="form-select" id="editTimezone">
<option value="America/New_York">美国纽约 (东部时间 UTC-5)</option>
<option value="America/Chicago">美国芝加哥 (中部时间 UTC-6)</option>
<option value="America/Denver">美国丹佛 (山地时间 UTC-7)</option>
<option value="America/Los_Angeles">美国洛杉矶 (太平洋时间 UTC-8)</option>
<option value="America/Anchorage">美国安克雷奇 (阿拉斯加时间 UTC-9)</option>
<option value="America/Honolulu">美国檀香山 (夏威夷时间 UTC-10)</option>
<option value="Asia/Shanghai">中国标准时间 (UTC+8)</option>
<option value="UTC">协调世界时 (UTC)</option>
</select>
</div>
<div class="mb-3">
<label for="editRemarks" class="form-label">备注</label>
<textarea class="form-control" id="editRemarks" rows="3"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" id="saveEditBtn">保存</button>
</div>
</div>
</div>
<!-- 订单导入脚本 -->
<script>
$(document).ready(function() {
// 初始化客户选择
initCustomerSelect();
// 订单导入表单提交
$('#orderImportForm').submit(function(e) {
e.preventDefault();
importOrders();
});
// 重置按钮
$('#resetOrderImportForm').click(function() {
$('#orderImportForm')[0].reset();
$('#importProgress').hide();
$('#importResult').hide();
});
// 下载模板按钮
$('#downloadTemplateBtn').click(function() {
downloadExcelTemplate();
});
// 客户选择变更事件
$('#importCustomerId').change(function() {
const customerId = $(this).val();
const customerCode = $(this).find('option:selected').text();
if (customerId) {
getCustomerApiKey(customerId, customerCode);
} else {
customerInfo = {
id: '',
code: '',
apiKey: ''
};
}
});
});
// 存储客户信息
let customerInfo = {
id: '',
code: '',
apiKey: ''
};
// 获取客户API密钥
function getCustomerApiKey(customerId, customerCode) {
// 存储客户代码
customerInfo.id = customerId;
customerInfo.code = customerCode;
const environment = $('#environment').val();
let apiUrl = '';
switch (environment) {
case 'local':
apiUrl = 'http://localhost:5002/api/Tag/customer-api';
break;
case 'test':
apiUrl = 'http://172.232.21.79:5002/api/Tag/customer-api';
break;
case 'production':
apiUrl = 'https://lr.tooexp.com/api/Tag/customer-api';
break;
default:
apiUrl = 'http://172.232.21.79:5002/api/Tag/customer-api';
}
// 使用JSONP进行跨域请求
const callbackName = 'customerApiCallback_' + Date.now();
window[callbackName] = function(response) {
if (response.status === 'ok' && response.data) {
customerInfo.apiKey = response.data.ApiKey;
console.log('Customer API key retrieved successfully');
} else {
customerInfo.apiKey = '';
console.error('Failed to retrieve customer API key:', response.message);
}
delete window[callbackName];
};
// 使用jQuery的JSONP请求
$.ajax({
url: apiUrl,
type: 'GET',
data: {
customerId: customerId
},
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: callbackName,
success: function(response) {
console.log('Customer API response:', response);
},
error: function(xhr, status, error) {
console.error('Failed to get customer API key:', error);
customerInfo.apiKey = '';
}
});
}
// 初始化客户选择
function initCustomerSelect() {
// 调用现有的加载客户列表函数
loadCustomerList();
}
// 导入订单
function importOrders() {
const customerId = $('#importCustomerId').val();
const labelMapping = $('#labelFilenameMapping').val();
const fileInput = $('#excelFile')[0];
if (!customerId) {
alert('请选择客户');
return;
}
if (!fileInput.files || fileInput.files.length === 0) {
alert('请选择Excel文件');
return;
}
const file = fileInput.files[0];
const reader = new FileReader();
reader.onload = function(e) {
try {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const jsonData = XLSX.utils.sheet_to_json(worksheet);
if (jsonData.length === 0) {
alert('Excel文件中没有数据');
return;
}
// 处理订单数据
const orders = processOrders(jsonData, labelMapping);
// 显示进度条
showProgress(orders.length);
// 调用API导入订单
importOrdersToApi(orders);
} catch (error) {
alert('解析Excel文件失败: ' + error.message);
}
};
reader.onerror = function() {
alert('读取文件失败');
};
reader.readAsArrayBuffer(file);
}
// 处理订单数据
function processOrders(jsonData, labelMapping) {
const orders = [];
const fixedDate = '20260302';
const maxUrlLength = 2048; // URL最大长度限制
jsonData.forEach(row => {
const order = {
BillOfLadingNumber: row.BillOfLadingNumber || null,
MasterPackageNumber: row.MasterPackageNumber || null,
NeutralWaybillNumber: row.NeutralWaybillNumber || '',
FinalMileTrackingNumber: row.FinalMileTrackingNumber || null,
Label: row.Label || null,
ReplaceStatus: 'Y'
};
// 生成标签URL
if (!order.Label && labelMapping !== 'none') {
let filename = '';
if (labelMapping === 'neutralWaybill' && order.NeutralWaybillNumber) {
filename = order.NeutralWaybillNumber;
} else if (labelMapping === 'finalMileTracking' && order.FinalMileTrackingNumber) {
filename = order.FinalMileTrackingNumber;
}
if (filename) {
// 生成URL
let url = `http://172.232.21.79/api-lable/pdf/${fixedDate}/${filename}.pdf`;
// 检查URL有效性和长度
if (isValidUrl(url) && url.length <= maxUrlLength) {
order.Label = url;
}
}
}
orders.push(order);
});
return orders;
}
// 验证URL有效性
function isValidUrl(url) {
try {
new URL(url);
return true;
} catch (error) {
return false;
}
}
// 显示进度条
function showProgress(total) {
$('#importProgress').show();
$('#importResult').hide();
$('#totalOrders').text(total);
$('#processedOrders').text('0');
$('#progressPercentage').text('0%');
$('.progress-bar').css('width', '0%').attr('aria-valuenow', '0');
$('#importStatus').text('准备导入...');
}
// 更新进度
function updateProgress(processed, total) {
const percentage = Math.round((processed / total) * 100);
$('#processedOrders').text(processed);
$('#progressPercentage').text(percentage + '%');
$('.progress-bar').css('width', percentage + '%').attr('aria-valuenow', percentage);
$('#importStatus').text(`正在导入... ${processed}/${total}`);
}
// 调用API导入订单
function importOrdersToApi(orders) {
// 使用从customer_apis表获取的API密钥
const apiKey = customerInfo.apiKey;
const customerCode = customerInfo.code;
// 验证API密钥和客户代码
if (!apiKey || !customerCode) {
// 尝试重新获取API密钥
const customerId = $('#importCustomerId').val();
const selectedCustomerCode = $('#importCustomerId').find('option:selected').text();
if (customerId) {
// 同步获取API密钥
$.ajax({
url: getApiUrlForCustomerApi(),
type: 'GET',
data: {
customerId: customerId
},
dataType: 'jsonp',
jsonp: 'callback',
async: false,
success: function(response) {
if (response.status === 'ok' && response.data) {
customerInfo.apiKey = response.data.ApiKey;
customerInfo.code = selectedCustomerCode;
customerInfo.id = customerId;
console.log('Customer API key retrieved successfully');
} else {
customerInfo.apiKey = '';
console.error('Failed to retrieve customer API key:', response.message);
}
},
error: function(xhr, status, error) {
console.error('Failed to get customer API key:', error);
customerInfo.apiKey = '';
}
});
// 再次检查
if (!customerInfo.apiKey || !customerInfo.code) {
alert('无法获取客户API密钥或客户代码请重新选择客户');
return;
}
} else {
alert('请选择客户');
return;
}
}
const environment = $('#environment').val();
let apiUrl = '';
switch (environment) {
case 'local':
apiUrl = 'http://localhost:5002/api/tag/order-import';
break;
case 'test':
apiUrl = 'http://172.232.21.79:5002/api/tag/order-import';
break;
case 'production':
apiUrl = 'https://lr.tooexp.com/api/tag/order-import';
break;
default:
apiUrl = 'http://172.232.21.79:5002/api/tag/order-import';
}
// 分批处理订单每批5个减少URL长度
const batchSize = 5;
const batches = [];
for (let i = 0; i < orders.length; i += batchSize) {
batches.push(orders.slice(i, i + batchSize));
}
// 存储所有批次的结果
const allResults = {
Status: 'ok',
TotalCount: 0,
SuccessCount: 0,
FailedCount: 0,
Results: []
};
let processedBatches = 0;
let processedOrders = 0;
const totalBatches = batches.length;
// 处理每个批次
batches.forEach(function(batch, batchIndex) {
// 使用JSONP进行跨域请求
const callbackName = 'jsonpCallback_' + Date.now() + '_' + batchIndex;
window[callbackName] = function(response) {
// 处理批次响应
if (response.Status === 'ok') {
allResults.TotalCount += response.TotalCount;
allResults.SuccessCount += response.SuccessCount;
allResults.FailedCount += response.FailedCount;
allResults.Results = allResults.Results.concat(response.Results);
}
processedBatches++;
processedOrders += batch.length;
// 更新进度
updateProgress(processedOrders, orders.length);
// 检查是否所有批次都已处理完成
if (processedBatches === totalBatches) {
displayImportResult(allResults);
}
delete window[callbackName];
};
// 构建请求数据
const requestData = {
Orders: batch
};
// 序列化数据
const dataString = JSON.stringify(requestData);
// 使用jQuery的JSONP请求
$.ajax({
url: apiUrl,
type: 'GET',
data: {
data: dataString,
customerCode: customerCode,
apiKey: apiKey
},
dataType: 'jsonp',
jsonp: 'callback',
jsonpCallback: callbackName,
success: function(response) {
console.log('Batch import response:', response);
},
error: function(xhr, status, error) {
console.error('Failed to import batch:', error);
// 处理错误情况
allResults.Status = 'error';
allResults.Results.push({
BillOfLadingNumber: '',
MasterPackageNumber: '',
NeutralWaybillNumber: '',
FinalMileTrackingNumber: '',
Status: 'error',
Message: '导入失败: ' + error,
Label: ''
});
processedBatches++;
processedOrders += batch.length;
// 更新进度
updateProgress(processedOrders, orders.length);
// 检查是否所有批次都已处理完成
if (processedBatches === totalBatches) {
displayImportResult(allResults);
}
}
});
});
}
// 显示导入结果
function displayImportResult(response) {
$('#importProgress').hide();
$('#importResult').show();
if (response.Status === 'ok') {
$('#resultTotalCount').text(response.TotalCount);
$('#resultSuccessCount').text(response.SuccessCount);
$('#resultFailedCount').text(response.FailedCount);
const successRate = response.TotalCount > 0
? Math.round((response.SuccessCount / response.TotalCount) * 100)
: 0;
$('#resultSuccessRate').text(successRate + '%');
// 填充结果表格
const tbody = $('#importResultTableBody');
tbody.empty();
response.Results.forEach(item => {
const row = $('<tr></tr>');
row.append(`<td>${item.BillOfLadingNumber || '-'}</td>`);
row.append(`<td>${item.MasterPackageNumber || '-'}</td>`);
row.append(`<td>${item.NeutralWaybillNumber || '-'}</td>`);
row.append(`<td>${item.FinalMileTrackingNumber || '-'}</td>`);
const statusCell = $('<td></td>');
if (item.Status === 'ok') {
statusCell.addClass('text-success').text('成功');
} else {
statusCell.addClass('text-danger').text('失败');
}
row.append(statusCell);
row.append(`<td>${item.Message || '-'}</td>`);
row.append(`<td>${item.Label || '-'}</td>`);
tbody.append(row);
});
} else {
alert('导入失败: ' + (response.Message || response.message || '未知错误'));
}
}
// 获取客户API的URL
function getApiUrlForCustomerApi() {
const environment = $('#environment').val();
let apiUrl = '';
switch (environment) {
case 'local':
apiUrl = 'http://localhost:5002/api/Tag/customer-api';
break;
case 'test':
apiUrl = 'http://172.232.21.79:5002/api/Tag/customer-api';
break;
case 'production':
apiUrl = 'https://lr.tooexp.com/api/Tag/customer-api';
break;
default:
apiUrl = 'http://172.232.21.79:5002/api/Tag/customer-api';
}
return apiUrl;
}
// 下载Excel模板
function downloadExcelTemplate() {
// 创建工作簿
const wb = XLSX.utils.book_new();
// 创建工作表数据
const headers = [
'BillOfLadingNumber', // 提单号
'MasterPackageNumber', // 大包号
'NeutralWaybillNumber', // 中性面单单号(必填)
'FinalMileTrackingNumber', // 尾程单号
'Label' // 标签内容(可选)
];
// 创建工作表
const ws = XLSX.utils.aoa_to_sheet([headers]);
// 添加工作表到工作簿
XLSX.utils.book_append_sheet(wb, ws, '订单模板');
// 生成Excel文件并下载
XLSX.writeFile(wb, '订单导入模板.xlsx');
}
</script>
</div>
</body>
</html>