// ==UserScript== // @name 单一窗口-内河运费自动化扣减 // @namespace // // @version 1.27 // @description 监听航次号变化并执行扣减操作,从外部JSON加载扣减标准,解析集装箱表格,自动计算扣减,支持用户修改扣减金额和币制 // @match https://swapp.singlewindow.cn/* // @match https://www.singlewindow.sd.cn/* // @grant GM_addStyle // @grant GM_xmlhttpRequest // @connect linjun.dpdns.org // ==/UserScript== (function () { "use strict"; // 扣减配置URL const DEDUCTION_CONFIG_URL = "https://linjun.dpdns.org/dl/neihev2.json"; // 添加自定义样式 GM_addStyle(` /* 科技风格弹窗样式 - 不影响页面原有样式 */ #customModal, #confirmModal, #otherRateConfirmModal, #otherMarkConfirmModal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.7); z-index: 10000; justify-content: center; align-items: center; } #customModal .modal-content, #confirmModal .modal-content, #otherRateConfirmModal .modal-content, #otherMarkConfirmModal .modal-content { position: relative; width: auto; max-width: 90%; padding: 25px; background: rgba(20, 25, 40, 0.95); border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.3), 0 0 0 1px rgba(100, 150, 255, 0.2), 0 0 20px rgba(100, 150, 255, 0.1); overflow: hidden; border: 1px solid rgba(100, 150, 255, 0.3); color: #e0e0e0; font-family: 'Segoe UI', system-ui, sans-serif; font-size: 14px; } #customModal .modal-header, #confirmModal .modal-header, #otherRateConfirmModal .modal-header, #otherMarkConfirmModal .modal-header { border-bottom: 1px solid rgba(100, 150, 255, 0.3); padding-bottom: 15px; margin-bottom: 20px; position: relative; } #customModal .modal-header::after, #confirmModal .modal-header::after, #otherRateConfirmModal .modal-header::after, #otherMarkConfirmModal .modal-header::after { content: ''; position: absolute; bottom: -1px; left: 0; width: 100%; height: 1px; background: linear-gradient(90deg, transparent, #5d8fff, transparent); } #customModal .modal-title, #confirmModal .modal-title, #otherRateConfirmModal .modal-title, #otherMarkConfirmModal .modal-title { font-size: 18px; font-weight: 600; color: #ffffff; margin: 0; text-align: center; text-shadow: 0 0 10px rgba(100, 150, 255, 0.5); } #customModal .modal-notice { margin-bottom: 20px; padding: 15px; background: rgba(255, 193, 7, 0.1); border: 1px solid rgba(255, 193, 7, 0.3); border-radius: 6px; color: #ffc107; font-size: 13px; line-height: 1.4; } #customModal .modal-body { margin-bottom: 25px; line-height: 1.5; display: flex; gap: 20px; align-items: stretch; } #confirmModal .modal-body, #otherRateConfirmModal .modal-body, #otherMarkConfirmModal .modal-body { margin-bottom: 25px; line-height: 1.5; } .deduction-details { background: rgba(30, 35, 50, 0.5); border-radius: 8px; padding: 15px; border: 1px solid rgba(100, 150, 255, 0.2); flex: 1 1 50%; max-height: 300px; overflow-y: auto; width: 100%; min-width: 0; box-sizing: border-box; display: flex; flex-direction: column; } .yellow-confirm-notice { background: rgba(255, 193, 7, 0.1) !important; border: 1px solid rgba(255, 193, 7, 0.3) !important; border-radius: 6px !important; color: #ffc107 !important; padding: 15px !important; margin: 10px 0 !important; font-weight: bold !important; } .calculation-form { background: rgba(30, 35, 50, 0.5); border-radius: 8px; padding: 15px; border: 1px solid rgba(100, 150, 255, 0.2); flex: 1 1 50%; width: 100%; min-width: 0; box-sizing: border-box; display: flex; flex-direction: column; } .deduction-item { display: flex; justify-content: space-between; margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid rgba(100, 150, 255, 0.1); } .deduction-item:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; } .deduction-total { font-weight: bold; color: #5d8fff; margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(100, 150, 255, 0.3); display: flex; justify-content: space-between; align-items: center; } .amount-input { background: rgba(40, 45, 60, 0.8); border: 1px solid rgba(100, 150, 255, 0.3); border-radius: 4px; color: #ffffff; padding: 5px 10px; width: 120px; text-align: right; font-size: 14px; -moz-appearance: textfield; } .amount-input::-webkit-outer-spin-button, .amount-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } .amount-input:focus { outline: none; border-color: #5d8fff; box-shadow: 0 0 5px rgba(93, 143, 255, 0.5); } .currency-display { color: #b0b0b0; font-size: 14px; min-width: 60px; } .form-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .form-row:last-child { margin-bottom: 0; } .form-label { font-weight: 600; color: #b0b0b0; min-width: 100px; } .form-value { display: flex; align-items: center; gap: 10px; } .final-result { background: rgba(40, 45, 60, 0.8); border-radius: 6px; padding: 10px; margin-top: 10px; border: 1px solid rgba(100, 150, 255, 0.3); font-weight: bold; color: #5d8fff; } #customModal .modal-footer, #confirmModal .modal-footer, #otherRateConfirmModal .modal-footer, #otherMarkConfirmModal .modal-footer { display: flex; justify-content: center; gap: 12px; } #customModal .btn, #confirmModal .btn, #otherRateConfirmModal .btn, #otherMarkConfirmModal .btn { padding: 12px 24px; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 600; border: none; min-height: 42px; min-width: 120px; display: flex; align-items: center; justify-content: center; white-space: nowrap; transition: all 0.3s ease; position: relative; overflow: hidden; } #customModal .btn::before, #confirmModal .btn::before, #otherRateConfirmModal .btn::before, #otherMarkConfirmModal .btn::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); transition: left 0.5s; } #customModal .btn:hover::before, #confirmModal .btn:hover::before, #otherRateConfirmModal .btn:hover::before, #otherMarkConfirmModal .btn:hover::before { left: 100%; } #customModal .btn-primary, #confirmModal .btn-primary, #otherRateConfirmModal .btn-primary, #otherMarkConfirmModal .btn-primary { background: linear-gradient(135deg, #4776E6, #8E54E9); color: white; box-shadow: 0 4px 15px rgba(71, 118, 230, 0.4); } #customModal .btn-primary:hover, #confirmModal .btn-primary:hover, #otherRateConfirmModal .btn-primary:hover, #otherMarkConfirmModal .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(71, 118, 230, 0.6); } #customModal .btn-secondary, #confirmModal .btn-secondary, #otherRateConfirmModal .btn-secondary, #otherMarkConfirmModal .btn-secondary { background: rgba(60, 65, 80, 0.9); color: #b0b0b0; border: 1px solid rgba(100, 150, 255, 0.3); } #customModal .btn-secondary:hover, #confirmModal .btn-secondary:hover, #otherRateConfirmModal .btn-secondary:hover, #otherMarkConfirmModal .btn-secondary:hover { background: rgba(70, 75, 90, 0.9); color: #ffffff; transform: translateY(-2px); } #confirmModal .modal-body, #otherRateConfirmModal .modal-body, #otherMarkConfirmModal .modal-body { text-align: center; font-size: 14px; padding: 10px 0; } @media (max-width: 900px) { #customModal .modal-content, #confirmModal .modal-content, #otherRateConfirmModal .modal-content, #otherMarkConfirmModal .modal-content { width: 95%; margin: 20px; padding: 20px; } #customModal .modal-body { flex-direction: column; } #customModal .modal-footer, #confirmModal .modal-footer, #otherRateConfirmModal .modal-footer, #otherMarkConfirmModal .modal-footer { flex-direction: column; } #customModal .btn, #confirmModal .btn, #otherRateConfirmModal .btn, #otherMarkConfirmModal .btn { min-width: 100%; } .form-row { flex-direction: column; align-items: flex-start; gap: 5px; } .form-value { width: 100%; justify-content: space-between; } .deduction-details, .calculation-form { flex-basis: auto; min-width: auto; } } `); // Toast函数 function Toast(message, type, duration) { if (!document.getElementById("tech-toast-styles")) { const style = document.createElement("style"); style.id = "tech-toast-styles"; style.textContent = `.tech-toast-container{position:fixed;top:30px;right:30px;z-index:10000;display:flex;flex-direction:column;gap:15px}.tech-toast{position:relative;min-width:300px;padding:18px 25px;background:rgba(15,20,35,0.95);border-radius:12px;box-shadow:0 5px 20px rgba(0,0,0,0.3),0 0 0 1px rgba(100,120,255,0.2),0 0 15px rgba(100,150,255,0.3);overflow:hidden;transform:translateX(120%);opacity:0;transition:transform 0.4s cubic-bezier(0.175,0.885,0.32,1.275),opacity 0.3s ease;display:flex;align-items:center;gap:15px}.tech-toast.show{transform:translateX(0);opacity:1}.tech-toast.hide{transform:translateX(120%);opacity:0}.toast-icon{width:40px;height:40px;display:flex;align-items:center;justify-content:center;border-radius:50%;flex-shrink:0;font-weight:bold;font-size:1.2rem}.success .toast-icon{background:rgba(46,204,113,0.15);color:#2ecc71}.error .toast-icon{background:rgba(231,76,60,0.15);color:#e74c3c}.warning .toast-icon{background:rgba(241,196,15,0.15);color:#f1c40f}.info .toast-icon{background:rgba(52,152,219,0.15);color:#3498db}.toast-content{flex:1;text-align:left}.toast-title{font-weight:600;font-size:1.1rem;margin-bottom:5px;color:#e0e0e0}.toast-message{font-size:14px;color:#a0b0c0;line-height:1.4}.progress-bar{position:absolute;bottom:0;left:0;height:4px;background:linear-gradient(90deg,#4776E6,#8E54E9);width:100%;transform-origin:left}.glow-effect{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:12px;box-shadow:inset 0 0 15px rgba(100,150,255,0.3);pointer-events:none;z-index:-1}.holographic-line{position:absolute;bottom:0;left:0;width:100%;height:1px;background:linear-gradient(90deg,transparent,#5d8fff,transparent);opacity:0.7}@media (max-width:600px){.tech-toast-container{top:20px;right:20px;left:20px}.tech-toast{min-width:auto;width:100%;padding:15px 20px}}`; document.head.appendChild(style); } let container = document.querySelector(".tech-toast-container"); if (!container) { container = document.createElement("div"); container.className = "tech-toast-container"; document.body.appendChild(container); } const toast = document.createElement("div"); toast.className = `tech-toast ${type}`; const icons = { success: "✓", error: "✕✕", warning: "⚠", info: "i" }; const titles = { success: "操作成功", error: "发生错误", warning: "警告", info: "信息", }; toast.innerHTML = `
${icons[type]}
${titles[type]}
${message}
`; container.appendChild(toast); setTimeout(() => { toast.classList.add("show"); const progressBar = toast.querySelector(".progress-bar"); progressBar.style.transform = "scaleX(0)"; progressBar.style.transition = `transform ${duration}ms linear`; setTimeout(() => (progressBar.style.transform = "scaleX(1)"), 10); setTimeout(() => { toast.classList.remove("show"); toast.classList.add("hide"); setTimeout(() => toast.remove(), 500); }, duration); }, 10); } // 设置隐藏元素值 function setHiddenFieldValues() { // 设置otherCurr为"CNY" const otherCurrInput = document.getElementById("otherCurr"); if (otherCurrInput) { otherCurrInput.value = "CNY"; } // 设置otherMark为"3" const otherMarkInput = document.getElementById("otherMark"); if (otherMarkInput) { otherMarkInput.value = "3"; } // 设置otherCurrName为"人民币" const otherCurrNameInput = document.getElementById("otherCurrName"); if (otherCurrNameInput) { otherCurrNameInput.value = "人民币"; } // 设置otherMarkName为"总价" const otherMarkNameInput = document.getElementById("otherMarkName"); if (otherMarkNameInput) { otherMarkNameInput.value = "总价"; } } // 触发原生decDelare函数 function triggerNativeDecDelare() { const decDelare = document.getElementById("decDelare"); if (decDelare) { const clickEvent = new MouseEvent("click", { view: window, bubbles: true, cancelable: true, }); decDelare.dispatchEvent(clickEvent); if (typeof decDelare.onclick === "function") { decDelare.onclick(); } } } // 触发原生addHeadBtn函数 function triggerNativeAddHeadBtn() { const addHeadBtn = document.getElementById("addHeadBtn"); if (addHeadBtn) { const clickEvent = new MouseEvent("click", { view: window, bubbles: true, cancelable: true, }); addHeadBtn.dispatchEvent(clickEvent); if (typeof addHeadBtn.onclick === "function") { addHeadBtn.onclick(); } } } // 从外部JSON加载扣减标准 function loadDeductionConfig() { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: DEDUCTION_CONFIG_URL, onload: function (response) { try { let responseText = response.responseText.trim(); if (responseText.charCodeAt(0) === 0xfeff) { responseText = responseText.substring(1); } const config = JSON.parse(responseText); console.log(config); if (Array.isArray(config) && config.length > 0) { resolve(config); } else { reject(new Error("扣减配置格式不正确,应为非空数组")); } } catch (error) { reject(new Error("解析扣减配置JSON失败: " + error.message)); } }, onerror: function (error) { reject(new Error("加载扣减配置失败: " + error.statusText)); }, }); }); } // 解析集装箱表格,统计各种类型的集装箱数量 function parseContainerTable() { const table = document.getElementById("decContainerTable"); if (!table) { Toast("未找到集装箱表格", "error", 3000); return null; } const rows = table.querySelectorAll("tbody tr"); if (rows.length === 0) { Toast("集装箱表格为空,请确认已正确录入集装箱信息", "error", 3000); return null; } const containerStats = {}; rows.forEach((row) => { const cells = row.querySelectorAll("td"); if (cells.length >= 3) { const containerType = cells[2].textContent.trim(); if (containerType) { if (!containerStats[containerType]) { containerStats[containerType] = 0; } containerStats[containerType]++; } } }); return containerStats; } // 获取港口名称 function getPortName() { const iEPortName = document.getElementById("iEPortName"); return iEPortName ? iEPortName.value.trim() : null; } // 获取目的港名称 function getDestPortName() { const customMasterName = document.getElementById("customMasterName"); return customMasterName ? customMasterName.value.trim() : null; } // 获取进口日期 function getImportDate() { const iEDate = document.getElementById("iEDate"); return iEDate ? iEDate.value.trim() : null; } // 日期格式转换和比较 function parseDate(dateStr) { if (!dateStr) return null; const parts = dateStr.split(/[/-]/); if (parts.length === 3) { const year = parseInt(parts[0]); const month = parseInt(parts[1]) - 1; const day = parseInt(parts[2]); return new Date(year, month, day); } if (dateStr.length === 8 && /^\d{8}$/.test(dateStr)) { const year = parseInt(dateStr.substring(0, 4)); const month = parseInt(dateStr.substring(4, 6)) - 1; const day = parseInt(dateStr.substring(6, 8)); return new Date(year, month, day); } return null; } // 检查日期是否在范围内 function isDateInRange(dateStr, beginDateStr, endDateStr) { const date = parseDate(dateStr); const beginDate = parseDate(beginDateStr); const endDate = parseDate(endDateStr); if (!date || !beginDate || !endDate) return true; return date >= beginDate && date <= endDate; } // 获取杂费原值和币制 function getOtherRateInfo() { const otherRateInput = document.getElementById("otherRate"); const otherCurrNameInput = document.getElementById("otherCurrName"); return { originalRate: otherRateInput ? parseFloat(otherRateInput.value) || 0 : 0, currency: otherCurrNameInput ? otherCurrNameInput.value.trim() : "人民币", rateElement: otherRateInput, currencyElement: otherCurrNameInput, }; } // 检查杂费名称是否为空 function isOtherMarkNameEmpty() { const otherMarkNameInput = document.getElementById("otherMarkName"); return otherMarkNameInput && !otherMarkNameInput.value.trim(); } // 计算扣减金额 function calculateDeduction(containerStats, deductionConfig) { if (!containerStats || !deductionConfig) { return { total: 0, details: [], portMatch: false }; } const portName = getPortName(); if (!portName) { Toast("未找到港口名称,请确认已正确录入港口信息", "error", 3000); return { total: 0, details: [], portMatch: false }; } const destPortName = getDestPortName(); if (!destPortName) { Toast("未找到目的港名称,请确认已正确录入目的港信息", "error", 3000); return { total: 0, details: [], portMatch: false }; } const importDate = getImportDate(); if (!importDate) { Toast("未找到进口日期,请确认已正确录入进口日期", "error", 3000); return { total: 0, details: [], portMatch: false }; } const matchedPortConfigs = deductionConfig.filter((item) => { console.log(item); const entryMatch = item.entryport === portName; const destMatch = Array.isArray(item.destport) ? item.destport.includes(destPortName) : item.destport === destPortName; const dateMatch = isDateInRange( importDate, item.begin_date, item.end_date ); return entryMatch && destMatch && dateMatch; }); if (matchedPortConfigs.length === 0) { Toast( `进境口岸"${portName}"或申报口岸"${destPortName}"或进口日期"${importDate}"无扣减参数,请联系税管科`, "error", 5000 ); return { total: 0, details: [], portMatch: false, portName: portName, destPortName: destPortName, }; } let totalDeduction = 0; const deductionDetails = []; Object.keys(containerStats).forEach((containerType) => { const count = containerStats[containerType]; const matchedConfig = matchedPortConfigs.find((item) => { const typeMatch = containerType.includes(item.type) || item.type.includes(containerType); return typeMatch; }); if (matchedConfig) { const deduction = matchedConfig.price * count; totalDeduction += deduction; deductionDetails.push({ type: containerType, count: count, price: matchedConfig.price, deduction: deduction, port: portName, destPort: destPortName, }); } else { const defaultPrice = 1350; const deduction = defaultPrice * count; totalDeduction += deduction; deductionDetails.push({ type: containerType, count: count, price: defaultPrice, deduction: deduction, note: "(使用默认价格)", port: portName, destPort: destPortName, }); } }); return { total: totalDeduction, details: deductionDetails, port: portName, destPort: destPortName, importDate: importDate, portMatch: true, }; } // 生成扣减详情HTML function generateDeductionDetailsHTML(deductionResult) { if (!deductionResult || deductionResult.details.length === 0) { if (deductionResult && !deductionResult.portMatch) { return `
进境口岸"${deductionResult.portName}"或申报口岸"${deductionResult.destPortName}"无扣减参数,请联系税管科
`; } return '
未检测到可扣减的集装箱
'; } let html = '
'; html += `
进境口岸:${deductionResult.port}
申报口岸:${deductionResult.destPort}
进口日期:${deductionResult.importDate}
`; deductionResult.details.forEach((detail) => { html += `
${detail.type} ${detail.count}箱 × ${detail.price}元 = ${ detail.deduction }元 ${detail.note || ""}
`; }); html += `
总计扣减金额
元人民币
`; return html; } // 生成计算表单HTML function generateCalculationFormHTML(otherRateInfo, deductionAmount) { const finalRate = otherRateInfo.originalRate - deductionAmount; return `
杂费原值:
${ otherRateInfo.currency }
扣减金额:
元人民币
最终杂费:
人民币
最终结果:${finalRate.toFixed(2)} 人民币
`; } // 创建自定义弹窗 function createModals() { const modalHTML = `
`; document.body.insertAdjacentHTML("beforeend", modalHTML); } // 检查条件并触发功能 function checkConditionsAndTrigger(deductionConfig) { const cusVoyageNoInput = document.getElementById("cusVoyageNo"); const cusTrafModeNameInput = document.getElementById("cusTrafModeName"); if (!cusVoyageNoInput || !cusTrafModeNameInput) { return false; } const voyageValue = cusVoyageNoInput.value; const trafModeValue = cusTrafModeNameInput.value; if (voyageValue.includes("@") && trafModeValue === "水路运输") { Toast("检测到内支线水路运输,触发扣减功能", "info", 5000); // 设置隐藏元素值 setHiddenFieldValues(); // 检查otherMarkName是否为空 if (isOtherMarkNameEmpty()) { const otherMarkConfirmModal = document.getElementById( "otherMarkConfirmModal" ); if (otherMarkConfirmModal) { otherMarkConfirmModal.style.display = "flex"; } return true; } const containerStats = parseContainerTable(); if (!containerStats) { return false; } const deductionResult = calculateDeduction( containerStats, deductionConfig ); if (!deductionResult.portMatch) { return; } const otherRateInfo = getOtherRateInfo(); const customModal = document.getElementById("customModal"); if (customModal) { const modalNotice = document.getElementById("modalNotice"); if (modalNotice) { modalNotice.innerHTML = `
提示:因插件无法获取内支线目的港,以申报港口默认作为目的港扣减,下方扣减金额支持手工调整
`; } const deductionDetailsElement = document.getElementById("deductionDetails"); if (deductionDetailsElement) { deductionDetailsElement.innerHTML = generateDeductionDetailsHTML(deductionResult); } const calculationFormElement = document.getElementById("calculationForm"); if (calculationFormElement) { calculationFormElement.innerHTML = generateCalculationFormHTML( otherRateInfo, deductionResult.total ); } const totalDeductionInput = document.getElementById( "totalDeductionInput" ); const deductionAmountInput = document.getElementById( "deductionAmountInput" ); const originalRateInput = document.getElementById("originalRateInput"); const finalRateInput = document.getElementById("finalRateInput"); if ( totalDeductionInput && deductionAmountInput && originalRateInput && finalRateInput ) { deductionAmountInput.value = totalDeductionInput.value; const updateCalculation = () => { deductionAmountInput.value = totalDeductionInput.value; const originalRate = parseFloat(originalRateInput.value) || 0; const deductionAmount = parseFloat(totalDeductionInput.value) || 0; const finalRate = originalRate - deductionAmount; finalRateInput.value = finalRate.toFixed(2); const finalResultElement = document.querySelector(".final-result"); if (finalResultElement) { finalResultElement.textContent = `最终结果:${finalRate.toFixed( 2 )} 人民币`; } }; totalDeductionInput.addEventListener("input", updateCalculation); originalRateInput.addEventListener("input", updateCalculation); } customModal.style.display = "flex"; } return true; } return false; } // 检查decDelare点击前的条件 function checkDecDelareConditions() { const cusVoyageNoInput = document.getElementById("cusVoyageNo"); const noteS = document.getElementById("noteS"); if (!cusVoyageNoInput || !noteS) { return false; } const voyageValue = cusVoyageNoInput.value; const noteValue = noteS.value; if (voyageValue.includes("@") && !noteValue.includes("内河减")) { return true; } return false; } // 执行扣减操作 function performDeduction() { // 设置隐藏元素值 setHiddenFieldValues(); const totalDeductionInput = document.getElementById("totalDeductionInput"); const originalRateInput = document.getElementById("originalRateInput"); if (!totalDeductionInput || !originalRateInput) { Toast("未找到扣减金额输入框", "error", 3000); return false; } const deductionAmount = parseFloat(totalDeductionInput.value) || 0; const originalRate = parseFloat(originalRateInput.value) || 0; const finalRate = originalRate - deductionAmount; const otherRateInfo = getOtherRateInfo(); if (!otherRateInfo.rateElement || !otherRateInfo.currencyElement) { Toast("未找到杂费或币制输入框", "error", 3000); return false; } otherRateInfo.rateElement.value = finalRate.toFixed(2); otherRateInfo.currencyElement.value = "人民币"; // 设置otherMarkName为"总价" const otherMarkNameInput = document.getElementById("otherMarkName"); if (otherMarkNameInput) { otherMarkNameInput.value = "总价"; } const noteS = document.getElementById("noteS"); if (noteS) { const prefix = `<内河减 ${deductionAmount.toFixed(2)}元> `; noteS.value = prefix + (noteS.value || ""); } const customModal = document.getElementById("customModal"); if (customModal) { customModal.style.display = "none"; } Toast( `扣减操作完成!杂费已更新为${finalRate.toFixed(2)} 人民币`, "success", 5000 ); return true; } // 初始化监听 function initListener(deductionConfig) { const cusVoyageNoInput = document.getElementById("cusVoyageNo"); const cusTrafModeNameInput = document.getElementById("cusTrafModeName"); const decDelare = document.getElementById("decDelare"); const addHeadBtn = document.getElementById("addHeadBtn"); const customModal = document.getElementById("customModal"); const confirmModal = document.getElementById("confirmModal"); const otherRateConfirmModal = document.getElementById( "otherRateConfirmModal" ); const otherMarkConfirmModal = document.getElementById( "otherMarkConfirmModal" ); const confirmBtn = document.getElementById("confirmBtn"); const cancelBtn = document.getElementById("cancelBtn"); const confirmProceedBtn = document.getElementById("confirmProceedBtn"); const confirmCancelBtn = document.getElementById("confirmCancelBtn"); const otherRateConfirmBtn = document.getElementById("otherRateConfirmBtn"); const otherRateCancelBtn = document.getElementById("otherRateCancelBtn"); const otherMarkConfirmBtn = document.getElementById("otherMarkConfirmBtn"); const otherMarkCancelBtn = document.getElementById("otherMarkCancelBtn"); if (!cusVoyageNoInput) { setTimeout(() => initListener(deductionConfig), 1000); return; } cusVoyageNoInput.addEventListener("input", () => checkConditionsAndTrigger(deductionConfig) ); if (cusTrafModeNameInput) { cusTrafModeNameInput.addEventListener("input", () => checkConditionsAndTrigger(deductionConfig) ); } if (decDelare) { const handleDecDelareClick = function (event) { if (checkDecDelareConditions()) { event.preventDefault(); event.stopImmediatePropagation(); if (confirmModal) { confirmModal.style.display = "flex"; } return false; } }; decDelare.addEventListener("click", handleDecDelareClick, true); window.decDelareHandler = handleDecDelareClick; } if (addHeadBtn) { const handleAddHeadBtnClick = function (event) { if (checkDecDelareConditions()) { event.preventDefault(); event.stopImmediatePropagation(); if (confirmModal) { confirmModal.style.display = "flex"; } return false; } }; addHeadBtn.addEventListener("click", handleAddHeadBtnClick, true); window.addHeadBtnHandler = handleAddHeadBtnClick; } if (confirmProceedBtn) { confirmProceedBtn.addEventListener("click", function () { if (confirmModal) { confirmModal.style.display = "none"; } const containerStats = parseContainerTable(); if (containerStats) { const deductionResult = calculateDeduction( containerStats, deductionConfig ); if (!deductionResult.portMatch) { return; } const otherRateInfo = getOtherRateInfo(); const modalNotice = document.getElementById("modalNotice"); if (modalNotice) { modalNotice.innerHTML = `
提示:因插件无法获取内支线目的港,以申报港口默认作为目的港扣减,下方扣减金额支持手工调整
`; } const deductionDetailsElement = document.getElementById("deductionDetails"); if (deductionDetailsElement) { deductionDetailsElement.innerHTML = generateDeductionDetailsHTML(deductionResult); } const calculationFormElement = document.getElementById("calculationForm"); if (calculationFormElement) { calculationFormElement.innerHTML = generateCalculationFormHTML( otherRateInfo, deductionResult.total ); } const totalDeductionInput = document.getElementById( "totalDeductionInput" ); const deductionAmountInput = document.getElementById( "deductionAmountInput" ); const originalRateInput = document.getElementById("originalRateInput"); const finalRateInput = document.getElementById("finalRateInput"); if ( totalDeductionInput && deductionAmountInput && originalRateInput && finalRateInput ) { deductionAmountInput.value = totalDeductionInput.value; const updateCalculation = () => { deductionAmountInput.value = totalDeductionInput.value; const originalRate = parseFloat(originalRateInput.value) || 0; const deductionAmount = parseFloat(totalDeductionInput.value) || 0; const finalRate = originalRate - deductionAmount; finalRateInput.value = finalRate.toFixed(2); const finalResultElement = document.querySelector(".final-result"); if (finalResultElement) { finalResultElement.textContent = `最终结果:${finalRate.toFixed( 2 )} 人民币`; } }; totalDeductionInput.addEventListener("input", updateCalculation); originalRateInput.addEventListener("input", updateCalculation); } if (customModal) { customModal.style.display = "flex"; } } }); } if (confirmCancelBtn) { confirmCancelBtn.addEventListener("click", function () { if (confirmModal) { confirmModal.style.display = "none"; } const decDelare = document.getElementById("decDelare"); if (decDelare && window.decDelareHandler) { decDelare.removeEventListener("click", window.decDelareHandler, true); } const addHeadBtn = document.getElementById("addHeadBtn"); if (addHeadBtn && window.addHeadBtnHandler) { addHeadBtn.removeEventListener( "click", window.addHeadBtnHandler, true ); } triggerNativeDecDelare(); }); } if (confirmBtn) { confirmBtn.addEventListener("click", function () { performDeduction(); }); } if (cancelBtn) { cancelBtn.addEventListener("click", function () { const customModal = document.getElementById("customModal"); if (customModal) { customModal.style.display = "none"; } }); } if (otherRateConfirmBtn) { otherRateConfirmBtn.addEventListener("click", function () { if (otherRateConfirmModal) { otherRateConfirmModal.style.display = "none"; } triggerNativeDecDelare(); performDeduction(); }); } if (otherRateCancelBtn) { otherRateCancelBtn.addEventListener("click", function () { if (otherRateConfirmModal) { otherRateConfirmModal.style.display = "none"; } Toast("请补充杂费信息", "info", 3000); }); } if (otherMarkConfirmBtn) { otherMarkConfirmBtn.addEventListener("click", function () { if (otherMarkConfirmModal) { otherMarkConfirmModal.style.display = "none"; } const containerStats = parseContainerTable(); if (containerStats) { const deductionResult = calculateDeduction( containerStats, deductionConfig ); if (!deductionResult.portMatch) { return; } const otherRateInfo = getOtherRateInfo(); const modalNotice = document.getElementById("modalNotice"); if (modalNotice) { modalNotice.innerHTML = `
提示:因插件无法获取内支线目的港,以申报港口默认作为目的港扣减,下方扣减金额支持手工调整
`; } const deductionDetailsElement = document.getElementById("deductionDetails"); if (deductionDetailsElement) { deductionDetailsElement.innerHTML = generateDeductionDetailsHTML(deductionResult); } const calculationFormElement = document.getElementById("calculationForm"); if (calculationFormElement) { calculationFormElement.innerHTML = generateCalculationFormHTML( otherRateInfo, deductionResult.total ); } const totalDeductionInput = document.getElementById( "totalDeductionInput" ); const deductionAmountInput = document.getElementById( "deductionAmountInput" ); const originalRateInput = document.getElementById("originalRateInput"); const finalRateInput = document.getElementById("finalRateInput"); if ( totalDeductionInput && deductionAmountInput && originalRateInput && finalRateInput ) { deductionAmountInput.value = totalDeductionInput.value; const updateCalculation = () => { deductionAmountInput.value = totalDeductionInput.value; const originalRate = parseFloat(originalRateInput.value) || 0; const deductionAmount = parseFloat(totalDeductionInput.value) || 0; const finalRate = originalRate - deductionAmount; finalRateInput.value = finalRate.toFixed(2); const finalResultElement = document.querySelector(".final-result"); if (finalResultElement) { finalResultElement.textContent = `最终结果:${finalRate.toFixed( 2 )} 人民币`; } }; totalDeductionInput.addEventListener("input", updateCalculation); originalRateInput.addEventListener("input", updateCalculation); } if (customModal) { customModal.style.display = "flex"; } } }); } if (otherMarkCancelBtn) { otherMarkCancelBtn.addEventListener("click", function () { if (otherMarkConfirmModal) { otherMarkConfirmModal.style.display = "none"; } Toast("请补充杂费名称信息", "info", 3000); }); } if (customModal) { customModal.addEventListener("click", function (e) { if (e.target === customModal) { customModal.style.display = "none"; } }); } if (confirmModal) { confirmModal.addEventListener("click", function (e) { if (e.target === confirmModal) { confirmModal.style.display = "none"; } }); } if (otherRateConfirmModal) { otherRateConfirmModal.addEventListener("click", function (e) { if (e.target === otherRateConfirmModal) { otherRateConfirmModal.style.display = "none"; } }); } if (otherMarkConfirmModal) { otherMarkConfirmModal.addEventListener("click", function (e) { if (e.target === otherMarkConfirmModal) { otherMarkConfirmModal.style.display = "none"; } }); } } // 主初始化函数 async function main() { try { const deductionConfig = await loadDeductionConfig(); createModals(); if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => initListener(deductionConfig) ); } else { initListener(deductionConfig); } const observer = new MutationObserver(function (mutations) { for (let mutation of mutations) { if (mutation.type === "childList") { for (let node of mutation.addedNodes) { if (node.nodeType === 1) { if ( node.id === "cusVoyageNo" || node.querySelector("#cusVoyageNo") || node.id === "decDelare" || node.querySelector("#decDelare") || node.id === "addHeadBtn" || node.querySelector("#addHeadBtn") || node.id === "decContainerTable" || node.querySelector("#decContainerTable") || node.id === "iEPortName" || node.querySelector("#iEPortName") || node.id === "customMasterName" || node.querySelector("#customMasterName") || node.id === "iEDate" || node.querySelector("#iEDate") || node.id === "otherRate" || node.querySelector("#otherRate") || node.id === "otherCurr" || node.querySelector("#otherCurr") || node.id === "otherCurrName" || node.querySelector("#otherCurrName") || node.id === "otherMark" || node.querySelector("#otherMark") || node.id === "otherMarkName" || node.querySelector("#otherMarkName") ) { initListener(deductionConfig); break; } } } } } }); observer.observe(document.body, { childList: true, subtree: true, }); } catch (error) { Toast("加载扣减配置失败: " + error.message, "error", 5000); console.error("扣减配置加载失败:", error); } } // 启动主函数 main(); })();