// ==UserScript== // @name 单一窗口-内河运费自动化扣减 // @namespace // // @version 1.24 // @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/neihe.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; } .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); } // 触发原生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); 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 => item.entryport === portName && item.destport === destPortName && isDateInRange(importDate, item.begin_date, item.end_date) ); 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); // 检查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() { 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 === 'otherCurrName' || node.querySelector('#otherCurrName') || 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(); })();