<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>运单智能工作台 · 批量查询与轨迹解析</title>
<!-- Google Font & Font Awesome -->
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,[email protected],400;14..32,500;14..32,600;14..32,700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #f3f6fc;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
color: #1a2c3e;
padding: 32px 24px;
}
/* 主容器 */
.dashboard {
max-width: 1600px;
margin: 0 auto;
}
/* 头部 */
.header {
margin-bottom: 28px;
}
.header h1 {
font-size: 1.9rem;
font-weight: 700;
letter-spacing: -0.02em;
background: linear-gradient(135deg, #1f3a6b, #2b4c7c);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
display: inline-flex;
align-items: center;
gap: 12px;
}
.header p {
color: #5a6e8a;
margin-top: 8px;
font-size: 0.9rem;
}
/* 卡片样式 */
.card {
background: #ffffff;
border-radius: 28px;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.02), 0 1px 2px rgba(0, 0, 0, 0.03);
border: 1px solid #e9eff5;
overflow: hidden;
transition: all 0.2s;
}
/* 平台切换条 */
.platform-switch {
display: flex;
gap: 12px;
background: #ffffff;
border-radius: 48px;
padding: 6px;
width: fit-content;
border: 1px solid #e2ecf5;
margin-bottom: 28px;
background: #f9fbfe;
}
.platform-btn {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 28px;
border-radius: 40px;
font-weight: 600;
font-size: 0.9rem;
border: none;
background: transparent;
cursor: pointer;
transition: 0.2s;
color: #4c6280;
}
.platform-btn i {
font-size: 1.1rem;
}
.platform-btn.active {
background: #1e4a76;
color: white;
box-shadow: 0 2px 8px rgba(30,74,118,0.2);
}
/* 双栏布局 */
.two-col {
display: flex;
gap: 28px;
flex-wrap: wrap;
}
.col-left {
flex: 2.2;
min-width: 320px;
}
.col-right {
flex: 1.3;
min-width: 300px;
}
/* 表格区域 */
.table-wrapper {
overflow-x: auto;
border-radius: 24px;
}
.track-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
}
.track-table th {
text-align: left;
padding: 16px 18px;
background: #fbfdff;
border-bottom: 1px solid #eef2f8;
font-weight: 600;
color: #2c3f66;
}
.track-table td {
padding: 14px 18px;
border-bottom: 1px solid #f0f4fa;
vertical-align: middle;
}
.track-table tr:last-child td {
border-bottom: none;
}
.checkbox-cell {
width: 42px;
text-align: center;
}
.track-code {
font-family: 'SF Mono', 'Menlo', monospace;
font-weight: 500;
font-size: 0.8rem;
letter-spacing: -0.2px;
color: #1e3a5f;
word-break: break-all;
}
.status-badge {
display: inline-flex;
align-items: center;
gap: 6px;
background: #f0f4f9;
padding: 4px 12px;
border-radius: 30px;
font-size: 0.7rem;
font-weight: 500;
color: #4c5a72;
}
.status-valid {
background: #e6f4ea;
color: #1f7840;
}
.status-invalid {
background: #fee9e6;
color: #bc3f2e;
}
.action-icons i {
margin: 0 6px;
cursor: pointer;
color: #8c9bb0;
transition: 0.1s;
}
.action-icons i:hover {
color: #1e4a76;
}
/* 右侧卡片 */
.right-card {
padding: 22px;
}
.section-title {
font-weight: 600;
font-size: 0.9rem;
margin-bottom: 16px;
display: flex;
align-items: center;
gap: 8px;
color: #1f3a6b;
}
textarea {
width: 100%;
border: 1px solid #dfe7ef;
border-radius: 20px;
padding: 14px;
font-family: 'SF Mono', monospace;
font-size: 0.8rem;
resize: vertical;
background: #fefefe;
transition: 0.2s;
}
textarea:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59,130,246,0.1);
}
.preview-link {
background: #f8fafd;
border-radius: 20px;
padding: 14px;
margin: 16px 0;
font-family: monospace;
font-size: 0.7rem;
word-break: break-all;
border: 1px solid #eaf0f6;
color: #2c6280;
}
.btn-group {
display: flex;
gap: 12px;
flex-wrap: wrap;
margin-top: 16px;
}
.btn {
border: none;
padding: 8px 20px;
border-radius: 40px;
font-weight: 500;
font-size: 0.8rem;
cursor: pointer;
transition: 0.2s;
display: inline-flex;
align-items: center;
gap: 8px;
background: #f0f4f9;
color: #2c4b6e;
}
.btn-primary {
background: #1e4a76;
color: white;
}
.btn-primary:hover {
background: #0f3860;
transform: translateY(-1px);
}
.btn-outline {
border: 1px solid #cddfef;
background: white;
}
.btn-outline:hover {
background: #f8fafd;
}
.badge-count {
background: #eef2fa;
padding: 4px 12px;
border-radius: 40px;
font-size: 0.7rem;
}
.footer-note {
margin-top: 28px;
text-align: center;
font-size: 0.7rem;
color: #7b8ea8;
}
i.fa, i.far, i.fas {
pointer-events: none;
}
.limit-hint {
font-size: 0.7rem;
color: #7085a3;
margin-left: 8px;
}
.clear-invalid-area {
margin-top: 24px;
border-top: 1px solid #ecf3fa;
padding-top: 20px;
}
.list-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 20px;
background: linear-gradient(180deg, #fafdff 0%, #f4f8fd 100%);
border-bottom: 1px solid #e8eef6;
}
.list-toolbar-actions {
display: inline-flex;
align-items: center;
gap: 10px;
}
.btn-ghost {
background: #ffffff;
border: 1px solid #d6e3f0;
color: #385675;
}
.btn-ghost:hover {
background: #f5f9fe;
}
.source-switch {
display: inline-flex;
gap: 8px;
background: #f6f9fe;
border: 1px solid #dfe8f4;
border-radius: 999px;
padding: 4px;
margin-bottom: 12px;
}
.source-btn {
border: none;
background: transparent;
color: #5d7391;
border-radius: 999px;
padding: 7px 14px;
font-size: 0.75rem;
font-weight: 600;
display: inline-flex;
align-items: center;
gap: 6px;
cursor: pointer;
transition: all 0.2s ease;
}
.source-btn.active {
background: #1e4a76;
color: #fff;
box-shadow: 0 2px 8px rgba(30,74,118,0.2);
}
</style>
</head>
<body>
<div class="dashboard">
<div class="header">
<h1><i class="fas fa-chalkboard-user"></i> 运单智能工作台</h1>
<p>批量勾选 · 自动拼接链接 · 粘贴轨迹结果自动识别无效单号</p>
</div>
<!-- 平台切换 -->
<div class="platform-switch">
<button id="aftershipBtn" class="platform-btn active"><i class="fas fa-ship"></i> AfterShip <span class="limit-hint">≤20个/次</span></button>
<button id="track17Btn" class="platform-btn"><i class="fas fa-globe"></i> 17TRACK <span class="limit-hint">≤40个/次</span></button>
</div>
<div class="two-col">
<!-- 左侧:运单表格 -->
<div class="col-left">
<div class="card">
<div class="list-toolbar">
<div id="selectionStats" class="badge-count">已选中 0 个运单</div>
<div class="list-toolbar-actions">
<button id="clearSelectionBtn" class="btn btn-ghost"><i class="fas fa-times"></i> 清空勾选</button>
</div>
</div>
<div class="table-wrapper">
<table class="track-table" id="trackTable">
<thead>
<tr><th class="checkbox-cell"><input type="checkbox" id="selectAllChk"></th>
<th>运单号</th>
<th>状态</th>
</tr>
</thead>
<tbody id="tableBody">
<!-- 动态加载用户提供的跟踪号 -->
</tbody>
</table>
</div>
</div>
</div>
<!-- 右侧:操作面板 -->
<div class="col-right">
<div class="card right-card">
<div class="section-title"><i class="fas fa-link"></i> 实时拼接链接预览</div>
<div id="linkPreview" class="preview-link">未勾选任何运单号</div>
<div class="btn-group">
<button id="copyLinkBtn" class="btn btn-outline"><i class="fas fa-copy"></i> 复制链接</button>
<button id="openQueryBtn" class="btn btn-primary"><i class="fas fa-external-link-alt"></i> 打开查询页面</button>
</div>
<div class="section-title" style="margin-top: 28px;"><i class="fas fa-keyboard"></i> 自定义导入/查询运单</div>
<textarea id="customInput" rows="3" placeholder="每行一个运单号,支持批量粘贴 例如: 00340434624219076481 9C9089I947047"></textarea>
<div class="btn-group">
<button id="customAftershipBtn" class="btn btn-outline"><i class="fas fa-ship"></i> AfterShip查询</button>
<button id="custom17trackBtn" class="btn btn-outline"><i class="fas fa-globe"></i> 17TRACK查询</button>
<button id="importListBtn" class="btn btn-outline"><i class="fas fa-upload"></i> 导入列表</button>
<button id="clearCustomBtn" class="btn">清空输入框</button>
</div>
<!-- 重点:粘贴轨迹结果自动识别无效单号 -->
<div class="clear-invalid-area">
<div class="section-title"><i class="fas fa-clipboard-list"></i> 粘贴轨迹结果信息 · 自动更新订单跟进数据</div>
<div class="source-switch">
<button id="parseAftershipBtn" class="source-btn active"><i class="fas fa-ship"></i> AfterShip</button>
<button id="parse17trackBtn" class="source-btn"><i class="fas fa-globe"></i> 17TRACK</button>
</div>
<textarea id="trackResultInput" rows="4" placeholder="从 AfterShip / 17TRACK 等网站复制轨迹内容粘贴至此 系统将自动识别未出现或查询失败的运单号,标记为「无轨迹」"></textarea>
<div class="btn-group">
<button id="parseInvalidBtn" class="btn btn-primary"><i class="fas fa-filter"></i> 自动更新订单跟进数据</button>
<button id="removeInvalidBtn" class="btn btn-outline"><i class="fas fa-trash-alt"></i> 一键清除所有无效单号</button>
</div>
<p style="font-size:0.7rem; margin-top:12px; color:#6c819e;"><i class="fas fa-info-circle"></i> 系统会检测粘贴文本中是否包含每个运单号,未出现则标记为“无轨迹”。支持中英文“未找到/not found”等关键词增强识别。</p>
</div>
</div>
</div>
</div>
<div class="footer-note">
<i class="fas fa-mouse-pointer"></i> 勾选运单 → 自动生成链接 → 点击打开即可批量查询 (AfterShip上限20,17track上限40)
· 已查看状态会保留,支持单独查询/重新查询
</div>
</div>
<script>
// ---------- 用户提供的跟踪号列表(去重保留,共106个)----------
const rawTrackingNumbers = [
"00340434624219076481", "9C9089I947047", "36CNN5006486", "00340434624219163280", "Q10206795102B7020",
"00340434727198173995", "00340434630522121473", "00340434624219163730", "367314227280", "00340434624219075835",
"0082800082809767093642", "GFUS01039547921728", "00340434624219077723", "9261290278833819876414", "IW933354425GB",
"00340434624219163105", "9C1824J119920", "9261290306531784191724", "JJD0002210781528399", "00340434624219163242",
"GFUS01039382823363", "JT20260685125566", "LM130599395CN", "0082800082809767061685", "00340434624219164751",
"IW933353699GB", "00340435060715475509", "00340435060715475370", "9C1823J654129", "9C1823J683855",
"ND699220730BR", "ND703686851BR", "ND699838385BR", "ND697216613BR", "ND697057355BR",
"JT20260635016625", "JJD0002210781642874", "JJD0002210781662221", "IW933736407GB", "9C1823J781829",
"9C1823J538123", "JJD0002210781756807", "Q19350032772L4843", "1041106541518610193005", "9C1823J744993",
"1041106541518510110904", "9C1823J800746", "9261290278833819699655", "CNB29753480", "0082800082809766765042",
"CNB29760473", "9C1823J962203", "CNB29760451", "0079350082809753939782", "0082800082809767127564",
"9C1824J170573", "9C1824J136137", "00340435060716616826", "00340435060716619896", "00340435060716620090",
"00340435060716648032", "0079350082809754879087", "0079350082809755047937", "6031126660807", "0079350082809754251383",
"9C1824J171034", "0079350082809755559827", "9C1824J002369", "RELRLYTVR4WK", "6031126118552",
"420332069261290376144360060346", "6A05435128978", "9C1824J121504", "00340434727199596298", "9C1824J163995",
"9C1824J186786", "9C1824J223527", "00340433911300245118", "889863095941", "0079350082809755165515",
"H1022620542143701024", "0079350082809755438536", "H1022620542041401044", "0082800082809767197424", "0079350082809754995181"
];
// 去重保留顺序
const uniqueNumbers = [];
const seen = new Set();
for (let num of rawTrackingNumbers) {
if (!seen.has(num)) {
seen.add(num);
uniqueNumbers.push(num);
}
}
// 构建数据模型:status: 'pending' / 'viewed' / 'invalid'
let trackingItems = uniqueNumbers.map((code, idx) => ({
id: idx,
trackingNumber: code,
status: 'pending', // pending, viewed, invalid
lastViewTime: null
}));
// 平台与限制
let currentPlatform = 'aftership'; // 'aftership' or 'seventrack'
const LIMIT = { aftership: 20, seventrack: 40 };
// DOM 元素
const tbody = document.getElementById('tableBody');
const selectAllChk = document.getElementById('selectAllChk');
const selectionStatsSpan = document.getElementById('selectionStats');
const linkPreviewDiv = document.getElementById('linkPreview');
const copyLinkBtn = document.getElementById('copyLinkBtn');
const openQueryBtn = document.getElementById('openQueryBtn');
const aftershipBtn = document.getElementById('aftershipBtn');
const track17Btn = document.getElementById('track17Btn');
const clearSelectionBtn = document.getElementById('clearSelectionBtn');
const customInput = document.getElementById('customInput');
const customAftershipBtn = document.getElementById('customAftershipBtn');
const custom17trackBtn = document.getElementById('custom17trackBtn');
const importListBtn = document.getElementById('importListBtn');
const clearCustomBtn = document.getElementById('clearCustomBtn');
const parseInvalidBtn = document.getElementById('parseInvalidBtn');
const removeInvalidBtn = document.getElementById('removeInvalidBtn');
const trackResultInput = document.getElementById('trackResultInput');
const parseAftershipBtn = document.getElementById('parseAftershipBtn');
const parse17trackBtn = document.getElementById('parse17trackBtn');
let parseSource = 'aftership';
// 辅助: 获取当前勾选的运单号数组
function getSelectedNumbers() {
const checkboxes = document.querySelectorAll('.row-checkbox:checked');
return Array.from(checkboxes).map(cb => cb.getAttribute('data-tn'));
}
// 生成查询URL
function buildQueryUrl(selectedNumbers) {
if (!selectedNumbers.length) return null;
const limit = LIMIT[currentPlatform];
const limited = selectedNumbers.slice(0, limit);
if (currentPlatform === 'aftership') {
return "https://www.aftership.com/track?t=" + limited.join(',');
} else {
return "https://www.17track.net/en/track?nums=" + limited.join(',');
}
}
// 更新预览和统计
function updatePreviewAndStats() {
const selected = getSelectedNumbers();
const total = selected.length;
const limit = LIMIT[currentPlatform];
if (total === 0) {
linkPreviewDiv.innerHTML = '<span style="color:#99aec9;">未勾选任何运单号</span>';
selectionStatsSpan.innerText = `已选中 0 个运单`;
return;
}
const used = Math.min(total, limit);
const overflowMsg = total > limit ? ` (仅前${limit}个生效)` : '';
const url = buildQueryUrl(selected);
if (url) {
linkPreviewDiv.innerHTML = `<span style="word-break:break-all;">${escapeHtml(url)}</span>`;
} else {
linkPreviewDiv.innerHTML = '生成链接失败';
}
selectionStatsSpan.innerText = `已选中 ${total} 个运单${overflowMsg}`;
}
function escapeHtml(str) {
return str.replace(/[&<>]/g, function(m) {
if (m === '&') return '&';
if (m === '<') return '<';
if (m === '>') return '>';
return m;
});
}
// 渲染表格 (保留当前勾选)
function renderTable() {
const beforeSelected = getSelectedNumbers();
tbody.innerHTML = '';
trackingItems.forEach(item => {
const row = tbody.insertRow();
// 复选框
const chkTd = row.insertCell(0);
chkTd.className = 'checkbox-cell';
const chk = document.createElement('input');
chk.type = 'checkbox';
chk.className = 'row-checkbox';
chk.setAttribute('data-tn', item.trackingNumber);
if (beforeSelected.includes(item.trackingNumber)) chk.checked = true;
chk.addEventListener('change', () => {
updatePreviewAndStats();
updateSelectAllState();
});
chkTd.appendChild(chk);
// 运单号
const codeCell = row.insertCell(1);
codeCell.className = 'track-code';
codeCell.innerText = item.trackingNumber;
// 状态
const statusCell = row.insertCell(2);
const statusSpan = document.createElement('span');
statusSpan.className = `status-badge ${item.status === 'invalid' ? 'status-invalid' : (item.status === 'viewed' ? 'status-valid' : '')}`;
if (item.status === 'pending') {
statusSpan.innerHTML = '<i class="far fa-clock"></i> 未查看';
} else if (item.status === 'viewed') {
statusSpan.innerHTML = '<i class="fas fa-check-circle"></i> 已查看';
} else {
statusSpan.innerHTML = '<i class="fas fa-ban"></i> 无轨迹';
}
statusCell.appendChild(statusSpan);
});
updatePreviewAndStats();
updateSelectAllState();
}
// 打开单个运单并标记为已查看
function openSingle(trackingNumber) {
const url = buildQueryUrl([trackingNumber]);
if (url) {
window.open(url, '_blank', 'noopener,noreferrer');
const item = trackingItems.find(i => i.trackingNumber === trackingNumber);
if (item && item.status !== 'invalid') {
item.status = 'viewed';
item.lastViewTime = new Date().toLocaleString();
renderTable();
}
} else {
alert('链接无效');
}
}
// 批量打开(使用当前勾选,自动遵守上限)
function batchOpen() {
let selected = getSelectedNumbers();
if (selected.length === 0) {
alert('请至少勾选一个运单号');
return;
}
const limit = LIMIT[currentPlatform];
if (selected.length > limit) {
if (!confirm(`当前平台最多同时查询 ${limit} 个单号,你勾选了 ${selected.length} 个,将只查询前 ${limit} 个,是否继续?`)) {
return;
}
selected = selected.slice(0, limit);
}
const url = buildQueryUrl(selected);
if (url) {
window.open(url, '_blank', 'noopener,noreferrer');
// 标记这些单号为已查看
selected.forEach(tn => {
const item = trackingItems.find(i => i.trackingNumber === tn);
if (item && item.status !== 'invalid') {
item.status = 'viewed';
item.lastViewTime = new Date().toLocaleString();
}
});
renderTable();
} else {
alert('生成链接失败');
}
}
// 全选逻辑
function updateSelectAllState() {
const all = document.querySelectorAll('.row-checkbox');
const checked = document.querySelectorAll('.row-checkbox:checked');
if (all.length === 0) return;
const targetCount = Math.min(all.length, LIMIT[currentPlatform]);
selectAllChk.checked = checked.length === targetCount;
selectAllChk.indeterminate = checked.length > 0 && checked.length < targetCount;
}
function handleSelectAll() {
const isChecked = selectAllChk.checked;
const all = Array.from(document.querySelectorAll('.row-checkbox'));
const targetCount = Math.min(all.length, LIMIT[currentPlatform]);
all.forEach((cb, idx) => {
cb.checked = isChecked ? idx < targetCount : false;
});
updatePreviewAndStats();
updateSelectAllState();
}
function clearSelection() {
document.querySelectorAll('.row-checkbox').forEach(cb => cb.checked = false);
updatePreviewAndStats();
updateSelectAllState();
}
function queryFromText(platform) {
const raw = customInput.value;
if (!raw.trim()) return alert('请在文本框输入运单号');
const numbers = raw.split(/[,\n\r\s]+/).map(s => s.trim()).filter(Boolean);
const dedup = [];
const seenInInput = new Set();
for (let n of numbers) {
if (!seenInInput.has(n)) {
seenInInput.add(n);
dedup.push(n);
}
}
if (dedup.length === 0) return alert('未识别到有效运单号');
const limit = LIMIT[platform];
let finalNums = dedup;
if (dedup.length > limit) {
if (!confirm(`当前平台最多同时查询 ${limit} 个单号,你输入了 ${dedup.length} 个,将只查询前 ${limit} 个,是否继续?`)) {
return;
}
finalNums = dedup.slice(0, limit);
}
const url = platform === 'aftership'
? "https://www.aftership.com/track?t=" + finalNums.join(',')
: "https://www.17track.net/en/track?nums=" + finalNums.join(',');
window.open(url, '_blank', 'noopener,noreferrer');
}
function importToListFromText() {
const raw = customInput.value;
if (!raw.trim()) return alert('请在文本框输入运单号');
const numbers = raw.split(/[,\n\r\s]+/).map(s => s.trim()).filter(Boolean);
const dedup = [];
const seenInInput = new Set();
for (let n of numbers) {
if (!seenInInput.has(n)) {
seenInInput.add(n);
dedup.push(n);
}
}
const existingSet = new Set(trackingItems.map(i => i.trackingNumber));
const appendList = [];
for (let n of dedup) {
if (!existingSet.has(n)) {
existingSet.add(n);
appendList.push(n);
}
}
if (appendList.length === 0) {
alert('没有新增运单号可导入');
return;
}
appendList.forEach((code, idx) => {
trackingItems.push({
id: trackingItems.length + idx,
trackingNumber: code,
status: 'pending',
lastViewTime: null
});
});
renderTable();
alert(`已导入 ${appendList.length} 个运单号,当前共 ${trackingItems.length} 个`);
}
function setParseSource(source) {
parseSource = source;
if (source === 'aftership') {
parseAftershipBtn.classList.add('active');
parse17trackBtn.classList.remove('active');
trackResultInput.placeholder = "从 AfterShip 复制轨迹内容粘贴至此\n系统将自动识别未出现或查询失败的运单号,标记为「无轨迹」";
} else {
parse17trackBtn.classList.add('active');
parseAftershipBtn.classList.remove('active');
trackResultInput.placeholder = "从 17TRACK 复制轨迹内容粘贴至此\n系统将自动识别未出现或查询失败的运单号,标记为「无轨迹」";
}
}
// 重点:解析粘贴的轨迹结果,自动标记无效单号
function parseAndMarkInvalid() {
const text = trackResultInput.value;
if (!text.trim()) {
alert('请粘贴轨迹查询结果文本');
return;
}
const lowerText = text.toLowerCase();
// 将当前所有未被标记为无效的单号取出来
const activeItems = trackingItems.filter(item => item.status !== 'invalid');
if (activeItems.length === 0) {
alert('当前没有活跃单号(全部已无效)');
return;
}
const notFound = [];
for (let item of activeItems) {
const tn = item.trackingNumber;
// 检查原始文本是否包含完整运单号(不区分大小写)
if (!lowerText.includes(tn.toLowerCase())) {
notFound.push(tn);
}
}
if (notFound.length === 0) {
alert('所有活跃单号均在粘贴文本中出现,无需标记无效');
return;
}
// 标记为 invalid
let changed = 0;
trackingItems.forEach(item => {
if (notFound.includes(item.trackingNumber) && item.status !== 'invalid') {
item.status = 'invalid';
item.lastViewTime = null;
changed++;
}
});
if (changed > 0) {
renderTable();
const sourceName = parseSource === 'aftership' ? 'AfterShip' : '17TRACK';
alert(`已按 ${sourceName} 结果标记 ${changed} 个未出现轨迹的单号为「无轨迹」`);
} else {
alert('没有新的无效单号可标记');
}
}
function removeAllInvalid() {
const newList = trackingItems.filter(item => item.status !== 'invalid');
if (newList.length === trackingItems.length) {
alert('没有无效单号需要清除');
return;
}
const removedCount = trackingItems.length - newList.length;
trackingItems = newList;
renderTable();
alert(`已清除 ${removedCount} 个无效单号,当前剩余 ${trackingItems.length} 个`);
}
// 复制链接
function copyLink() {
const selected = getSelectedNumbers();
if (selected.length === 0) return alert('请勾选运单号');
const url = buildQueryUrl(selected);
if (url) {
navigator.clipboard.writeText(url).then(() => {
const original = copyLinkBtn.innerHTML;
copyLinkBtn.innerHTML = '<i class="fas fa-check"></i> 已复制';
setTimeout(() => copyLinkBtn.innerHTML = original, 1500);
}).catch(() => alert('复制失败'));
} else {
alert('链接无效');
}
}
// 切换平台
function setPlatform(platform) {
currentPlatform = platform;
if (platform === 'aftership') {
aftershipBtn.classList.add('active');
track17Btn.classList.remove('active');
} else {
track17Btn.classList.add('active');
aftershipBtn.classList.remove('active');
}
updatePreviewAndStats();
}
// 事件绑定
selectAllChk.addEventListener('change', handleSelectAll);
clearSelectionBtn.addEventListener('click', clearSelection);
copyLinkBtn.addEventListener('click', copyLink);
openQueryBtn.addEventListener('click', batchOpen);
aftershipBtn.addEventListener('click', () => setPlatform('aftership'));
track17Btn.addEventListener('click', () => setPlatform('seventrack'));
customAftershipBtn.addEventListener('click', () => queryFromText('aftership'));
custom17trackBtn.addEventListener('click', () => queryFromText('seventrack'));
importListBtn.addEventListener('click', importToListFromText);
clearCustomBtn.addEventListener('click', () => { customInput.value = ''; });
parseAftershipBtn.addEventListener('click', () => setParseSource('aftership'));
parse17trackBtn.addEventListener('click', () => setParseSource('seventrack'));
parseInvalidBtn.addEventListener('click', parseAndMarkInvalid);
removeInvalidBtn.addEventListener('click', removeAllInvalid);
// 监听复选框变化 (动态)
document.addEventListener('change', (e) => {
if (e.target.classList && e.target.classList.contains('row-checkbox')) {
updatePreviewAndStats();
updateSelectAllState();
}
});
// 初始化渲染
renderTable();
setPlatform('aftership');
setParseSource('aftership');
</script>
</body>
</html>
index.html
md
README.md
index.html