// ==UserScript== // @name rejectorder // @namespace https://scriptcat.org/zh-CN/script-show-page/3815 // @version 1.5 // @description 在'退货通知单'增加功能:历史旧价查询(按年份分页)、客户单号/备注重复单提醒,对外版本 // @author fengxia // @match http://122.13.25.247:8888/sales/rejectBill.do // @match http://47.107.106.156:8888/sales/rejectBill.do // @icon data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDEiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCA0MSA0MSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHJva2Utd2lkdGg9IjEuNSIgY2xhc3M9ImgtNiB3LTYiIHJvbGU9ImltZyI+PHRpdGxlPkNoYXRHUFQ8L3RpdGxlPjx0ZXh0IHg9Ii05OTk5IiB5PSItOTk5OSI+Q2hhdEdQVDwvdGV4dD48cGF0aCBkPSJNMzcuNTMyNCAxNi44NzA3QzM3Ljk4MDggMTUuNTI0MSAzOC4xMzYzIDE0LjA5NzQgMzcuOTg4NiAxMi42ODU5QzM3Ljg0MDkgMTEuMjc0NCAzNy4zOTM0IDkuOTEwNzYgMzYuNjc2IDguNjg2MjJDMzUuNjEyNiA2LjgzNDA0IDMzLjk4ODIgNS4zNjc2IDMyLjAzNzMgNC40OTg1QzMwLjA4NjQgMy42Mjk0MSAyNy45MDk4IDMuNDAyNTkgMjUuODIxNSAzLjg1MDc4QzI0Ljg3OTYgMi43ODkzIDIzLjcyMTkgMS45NDEyNSAyMi40MjU3IDEuMzYzNDFDMjEuMTI5NSAwLjc4NTU3NSAxOS43MjQ5IDAuNDkxMjY5IDE4LjMwNTggMC41MDAxOTdDMTYuMTcwOCAwLjQ5NTA0NCAxNC4wODkzIDEuMTY4MDMgMTIuMzYxNCAyLjQyMjE0QzEwLjYzMzUgMy42NzYyNCA5LjM0ODUzIDUuNDQ2NjYgOC42OTE3IDcuNDc4MTVDNy4zMDA4NSA3Ljc2Mjg2IDUuOTg2ODYgOC4zNDE0IDQuODM3NyA5LjE3NTA1QzMuNjg4NTQgMTAuMDA4NyAyLjczMDczIDExLjA3ODIgMi4wMjgzOSAxMi4zMTJDMC45NTY0NjQgMTQuMTU5MSAwLjQ5ODkwNSAxNi4yOTg4IDAuNzIxNjk4IDE4LjQyMjhDMC45NDQ0OTIgMjAuNTQ2NyAxLjgzNjEyIDIyLjU0NDkgMy4yNjggMjQuMTI5M0MyLjgxOTY2IDI1LjQ3NTkgMi42NjQxMyAyNi45MDI2IDIuODExODIgMjguMzE0MUMyLjk1OTUxIDI5LjcyNTYgMy40MDcwMSAzMS4wODkyIDQuMTI0MzcgMzIuMzEzOEM1LjE4NzkxIDM0LjE2NTkgNi44MTIzIDM1LjYzMjIgOC43NjMyMSAzNi41MDEzQzEwLjcxNDEgMzcuMzcwNCAxMi44OTA3IDM3LjU5NzMgMTQuOTc4OSAzNy4xNDkyQzE1LjkyMDggMzguMjEwNyAxNy4wNzg2IDM5LjA1ODcgMTguMzc0NyAzOS42MzY2QzE5LjY3MDkgNDAuMjE0NCAyMS4wNzU1IDQwLjUwODcgMjIuNDk0NiA0MC40OTk4QzI0LjYzMDcgNDAuNTA1NCAyNi43MTMzIDM5LjgzMjEgMjguNDQxOCAzOC41NzcyQzMwLjE3MDQgMzcuMzIyMyAzMS40NTU2IDM1LjU1MDYgMzIuMTExOSAzMy41MTc5QzMzLjUwMjcgMzMuMjMzMiAzNC44MTY3IDMyLjY1NDcgMzUuOTY1OSAzMS44MjFDMzcuMTE1IDMwLjk4NzQgMzguMDcyOCAyOS45MTc4IDM4Ljc3NTIgMjguNjg0QzM5Ljg0NTggMjYuODM3MSA0MC4zMDIzIDI0LjY5NzkgNDAuMDc4OSAyMi41NzQ4QzM5Ljg1NTYgMjAuNDUxNyAzOC45NjM5IDE4LjQ1NDQgMzcuNTMyNCAxNi44NzA3Wk0yMi40OTc4IDM3Ljg4NDlDMjAuNzQ0MyAzNy44ODc0IDE5LjA0NTkgMzcuMjczMyAxNy42OTk0IDM2LjE1MDFDMTcuNzYwMSAzNi4xMTcgMTcuODY2NiAzNi4wNTg2IDE3LjkzNiAzNi4wMTYxTDI1LjkwMDQgMzEuNDE1NkMyNi4xMDAzIDMxLjMwMTkgMjYuMjY2MyAzMS4xMzcgMjYuMzgxMyAzMC45Mzc4QzI2LjQ5NjQgMzAuNzM4NiAyNi41NTYzIDMwLjUxMjQgMjYuNTU0OSAzMC4yODI1VjE5LjA1NDJMMjkuOTIxMyAyMC45OThDMjkuOTM4OSAyMS4wMDY4IDI5Ljk1NDEgMjEuMDE5OCAyOS45NjU2IDIxLjAzNTlDMjkuOTc3IDIxLjA1MiAyOS45ODQyIDIxLjA3MDcgMjkuOTg2NyAyMS4wOTAyVjMwLjM4ODlDMjkuOTg0MiAzMi4zNzUgMjkuMTk0NiAzNC4yNzkxIDI3Ljc5MDkgMzUuNjg0MUMyNi4zODcyIDM3LjA4OTIgMjQuNDgzOCAzNy44ODA2IDIyLjQ5NzggMzcuODg0OVpNNi4zOTIyNyAzMS4wMDY0QzUuNTEzOTcgMjkuNDg4OCA1LjE5NzQyIDI3LjcxMDcgNS40OTgwNCAyNS45ODMyQzUuNTU3MTggMjYuMDE4NyA1LjY2MDQ4IDI2LjA4MTggNS43MzQ2MSAyNi4xMjQ0TDEzLjY5OSAzMC43MjQ4QzEzLjg5NzUgMzAuODQwOCAxNC4xMjMzIDMwLjkwMiAxNC4zNTMyIDMwLjkwMkMxNC41ODMgMzAuOTAyIDE0LjgwODggMzAuODQwOCAxNS4wMDczIDMwLjcyNDhMMjQuNzMxIDI1LjExMDNWMjguOTk3OUMyNC43MzIxIDI5LjAxNzcgMjQuNzI4MyAyOS4wMzc2IDI0LjcxOTkgMjkuMDU1NkMyNC43MTE1IDI5LjA3MzYgMjQuNjk4OCAyOS4wODkzIDI0LjY4MjkgMjkuMTAxMkwxNi42MzE3IDMzLjc0OTdDMTQuOTA5NiAzNC43NDE2IDEyLjg2NDMgMzUuMDA5NyAxMC45NDQ3IDM0LjQ5NTRDOS4wMjUwNiAzMy45ODExIDcuMzg3ODUgMzIuNzI2MyA2LjM5MjI3IDMxLjAwNjRaTTQuMjk3MDcgMTMuNjE5NEM1LjE3MTU2IDEyLjA5OTggNi41NTI3OSAxMC45MzY0IDguMTk4ODUgMTAuMzMyN0M4LjE5ODg1IDEwLjQwMTMgOC4xOTQ5MSAxMC41MjI4IDguMTk0OTEgMTAuNjA3MVYxOS44MDhDOC4xOTM1MSAyMC4wMzc4IDguMjUzMzQgMjAuMjYzOCA4LjM2ODIzIDIwLjQ2MjlDOC40ODMxMiAyMC42NjE5IDguNjQ4OTMgMjAuODI2NyA4Ljg0ODYzIDIwLjk0MDRMMTguNTcyMyAyNi41NTQyTDE1LjIwNiAyOC40OTc5QzE1LjE4OTQgMjguNTA4OSAxNS4xNzAzIDI4LjUxNTUgMTUuMTUwNSAyOC41MTczQzE1LjEzMDcgMjguNTE5MSAxNS4xMTA3IDI4LjUxNiAxNS4wOTI0IDI4LjUwODJMNy4wNDA0NiAyMy44NTU3QzUuMzIxMzUgMjIuODYwMSA0LjA2NzE2IDIxLjIyMzUgMy41NTI4OSAxOS4zMDQ2QzMuMDM4NjIgMTcuMzg1OCAzLjMwNjI0IDE1LjM0MTMgNC4yOTcwNyAxMy42MTk0Wk0zMS45NTUgMjAuMDU1NkwyMi4yMzEyIDE0LjQ0MTFMMjUuNTk3NiAxMi40OTgxQzI1LjYxNDIgMTIuNDg3MiAyNS42MzMzIDEyLjQ4MDUgMjUuNjUzMSAxMi40Nzg3QzI1LjY3MjkgMTIuNDc2OSAyNS42OTI4IDEyLjQ4MDEgMjUuNzExMSAxMi40ODc5TDMzLjc2MzEgMTcuMTM2NEMzNC45OTY3IDE3Ljg0OSAzNi4wMDE3IDE4Ljg5ODIgMzYuNjYwNiAyMC4xNjEzQzM3LjMxOTQgMjEuNDI0NCAzNy42MDQ3IDIyLjg0OSAzNy40ODMyIDI0LjI2ODRDMzcuMzYxNyAyNS42ODc4IDM2LjgzODIgMjcuMDQzMiAzNS45NzQzIDI4LjE3NTlDMzUuMTEwMyAyOS4zMDg2IDMzLjk0MTUgMzAuMTcxNyAzMi42MDQ3IDMwLjY2NDFDMzIuNjA0NyAzMC41OTQ3IDMyLjYwNDcgMzAuNDczMyAzMi42MDQ3IDMwLjM4ODlWMjEuMTg4QzMyLjYwNjYgMjAuOTU4NiAzMi41NDc0IDIwLjczMjggMzIuNDMzMiAyMC41MzM4QzMyLjMxOSAyMC4zMzQ4IDMyLjE1NCAyMC4xNjk4IDMxLjk1NSAyMC4wNTU2Wk0zNS4zMDU1IDE1LjAxMjhDMzUuMjQ2NCAxNC45NzY1IDM1LjE0MzEgMTQuOTE0MiAzNS4wNjkgMTQuODcxN0wyNy4xMDQ1IDEwLjI3MTJDMjYuOTA2IDEwLjE1NTQgMjYuNjgwMyAxMC4wOTQzIDI2LjQ1MDQgMTAuMDk0M0MyNi4yMjA2IDEwLjA5NDMgMjUuOTk0OCAxMC4xNTU0IDI1Ljc5NjMgMTAuMjcxMkwxNi4wNzI2IDE1Ljg4NThWMTEuOTk4MkMxNi4wNzE1IDExLjk3ODMgMTYuMDc1MyAxMS45NTg1IDE2LjA4MzcgMTEuOTQwNUMxNi4wOTIxIDExLjkyMjUgMTYuMTA0OCAxMS45MDY4IDE2LjEyMDcgMTEuODk0OUwyNC4xNzE5IDcuMjUwMjVDMjUuNDA1MyA2LjUzOTAzIDI2LjgxNTggNi4xOTM3NiAyOC4yMzgzIDYuMjU0ODJDMjkuNjYwOCA2LjMxNTg5IDMxLjAzNjQgNi43ODA3NyAzMi4yMDQ0IDcuNTk1MDhDMzMuMzcyMyA4LjQwOTM5IDM0LjI4NDIgOS41Mzk0NSAzNC44MzM0IDEwLjg1MzFDMzUuMzgyNiAxMi4xNjY3IDM1LjU0NjQgMTMuNjA5NSAzNS4zMDU1IDE1LjAxMjhaTTE0LjI0MjQgMjEuOTQxOUwxMC44NzUyIDE5Ljk5ODFDMTAuODU3NiAxOS45ODkzIDEwLjg0MjMgMTkuOTc2MyAxMC44MzA5IDE5Ljk2MDJDMTAuODE5NSAxOS45NDQxIDEwLjgxMjIgMTkuOTI1NCAxMC44MDk4IDE5LjkwNThWMTAuNjA3MUMxMC44MTA3IDkuMTgyOTUgMTEuMjE3MyA3Ljc4ODQ4IDExLjk4MTkgNi41ODY5NkMxMi43NDY2IDUuMzg1NDQgMTMuODM3NyA0LjQyNjU5IDE1LjEyNzUgMy44MjI2NEMxNi40MTczIDMuMjE4NjkgMTcuODUyNCAyLjk5NDY0IDE5LjI2NDkgMy4xNzY3QzIwLjY3NzUgMy4zNTg3NiAyMi4wMDg5IDMuOTM5NDEgMjMuMTAzNCA0Ljg1MDY3QzIzLjA0MjcgNC44ODM3OSAyMi45MzcgNC45NDIxNSAyMi44NjY4IDQuOTg0NzNMMTQuOTAyNCA5LjU4NTE3QzE0LjcwMjUgOS42OTg3OCAxNC41MzY2IDkuODYzNTYgMTQuNDIxNSAxMC4wNjI2QzE0LjMwNjUgMTAuMjYxNiAxNC4yNDY2IDEwLjQ4NzcgMTQuMjQ3OSAxMC43MTc1TDE0LjI0MjQgMjEuOTQxOVpNMTYuMDcxIDE3Ljk5OTFMMjAuNDAxOCAxNS40OTc4TDI0LjczMjUgMTcuOTk3NVYyMi45OTg1TDIwLjQwMTggMjUuNDk4M0wxNi4wNzEgMjIuOTk4NVYxNy45OTkxWiIgZmlsbD0iY3VycmVudENvbG9yIj48L3BhdGg+PC9zdmc+ // @require https://scriptcat.org/lib/513/2.1.0/ElementGetter.js // @require https://scriptcat.org/lib/637/1.4.6/ajaxHooker.js // @grant none // ==/UserScript== (function () { 'use strict'; // ===== 配置常量 ===== const CONFIG = { panelWidth: 400, // 历史旧价面板宽度(px) panelHeight: 470, // 历史旧价面板高度(px) bodyHeight: 330, // 年份表格区域高度(px) summaryHeight: 100, // 底部汇总区域高度(px) dialogWidth: 1010, // 原弹窗宽度,用于计算面板偏移 leftRatio: 0.85, // 原弹窗左移比例 rightRatio: 0.15, // 新面板 right 偏移比例 startYearMin: 2022, // 年份 tab 最早起始年 yearSpan: 5, // 年份 tab 跨度 rows: 1000, // 接口单页最大行数 toastDurationMs: 3000, // toast 提示自动消失时间(毫秒) }; // 从当前地址提取服务器 IP,供接口请求使用;提取失败时回退到当前 origin const ipMatch = /(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}/.exec(window.location.href); const BASE_URL = ipMatch ? `${window.location.protocol}//${ipMatch[0]}:${window.location.port || '8888'}` : window.location.origin; window.test = ipMatch ? ipMatch[0] : ''; // 兼容旧全局变量 // ===== 通用工具 ===== // HTML 转义,防止接口返回值注入页面 function escapeHtml(value) { return String(value ?? '').replace(/[&<>"']/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', }[c])); } // 非阻塞提示,替代 alert function notify(msg) { console.warn('[rejectorder]', msg); const $toast = $('
').text(msg).appendTo(document.body); setTimeout(() => $toast.fadeOut(500, () => $toast.remove()), CONFIG.toastDurationMs); } // 通用查询:POST 到指定接口并返回解析后的 JSON,失败时 reject async function postQuery(path, params) { const url = new URL(path, BASE_URL); for (const [key, value] of Object.entries(params)) { url.searchParams.set(key, Array.isArray(value) ? value.join(',') : String(value ?? '')); } const resp = await fetch(url, { method: 'POST' }); if (!resp.ok) { throw new Error(`Error ${resp.status}: ${resp.statusText}`); } const text = await resp.text(); try { return JSON.parse(text); } catch (err) { // 会话过期等场景下接口可能返回登录页 HTML throw new Error('响应不是有效 JSON,可能登录已过期'); } } // 日期函数:传入年份返回该年区间,否则返回近 90 天区间 function getIntervalDate(year) { const pad = n => String(n).padStart(2, '0'); if (year) { return { start_date: `${year}-01-01`, end_date: `${year}-12-31` }; } const date = new Date(); const end_date = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`; date.setDate(date.getDate() - 90); const start_date = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`; return { start_date, end_date }; } // ===== 历史旧价查询 ===== // 根据出入库流水账获取退货单数据 async function showCustomerSalesFlowList(customer, products, year) { const query_date = getIntervalDate(year); const data = await postQuery('/report/storage/showInOutFlowListData.do', { businessdate1: query_date.start_date, businessdate2: query_date.end_date, id: '', brandid: '', goodsid: products, billtype: ['1', '5'], supplierid: '', customerid: customer, storageid: '', customersort: '', audituserid: '', page: '1', rows: CONFIG.rows, sort: 'businessdate', order: 'desc', }); return data.rows || []; } // 通过查询订单追踪明细表获取订单数据(当前未启用,保留备用) async function showSalesOrderTrackReportData(customer, products, year) { const query_date = getIntervalDate(year); const data = await postQuery('/report/sales/showSalesOrderTrackReportData.do', { businessdate1: query_date.start_date, businessdate2: query_date.end_date, id: '', brandid: '', goodsid: products, customerid: customer, checkstatus: '', salesuser: '', pcustomerid: '', indooruserid: '', sourceid: '', goodssort: '', page: '1', rows: CONFIG.rows, sort: 'businessdate', order: 'asc', }); return data.rows || []; } // 把流水数据转换为展示用列表 function transformFlowRows(rows) { return rows.map(row => ({ goodsid: row.goodsid, date: row.businessdate, unitnum: Number(row.enternum) === 0 ? Number(row.outnum) : Number(row.enternum) * -1, price: row.price, })); } // 渲染历史旧价表格与单价汇总 function renderHistoryPrice(list_order, products) { const bodyRows = list_order.length ? list_order.map((item, i) => ` ${escapeHtml(item.goodsid)} ${escapeHtml(item.date)} ${escapeHtml(item.unitnum)} ${escapeHtml(item.price)} `).join('') : `${escapeHtml(products)}无销售`; const table_html = `
编码 日期 数量 单价
${bodyRows}
`; return { table_html, summary_html: buildSummaryHtml(list_order) }; } // 按单价分组汇总数量 function buildSummaryHtml(list_order) { const amountGroups = {}; list_order.forEach(item => { const amount = Number(item.price); amountGroups[amount] = (amountGroups[amount] || 0) + Number(item.unitnum); }); return Object.entries(amountGroups) .map(([amount, totalQuantity]) => `单价 ${escapeHtml(amount)}: 数量总和 = ${escapeHtml(Math.round(totalQuantity * 100) / 100)}`) .join('
'); } // 历史旧价查询缓存:以 客户+商品 为作用域,按年份缓存已查询的结果 const historyCache = new Map(); // key: year -> list_order let historyCacheScope = ''; // 当前缓存对应的 客户+商品 // 查询历史旧价:命中缓存直接渲染,否则 取数 -> 转换 -> 渲染 async function queryHistoryPrice(customer, products, year) { const $panel = $(`.panel-body-noborder.layout-body.${year}`); // 商品或客户变更后旧数据不再适用,清空缓存重新查询 const scope = `${customer}|${products}`; if (scope !== historyCacheScope) { historyCache.clear(); historyCacheScope = scope; } const render = list_order => { const { table_html, summary_html } = renderHistoryPrice(list_order, products); $panel.html(table_html); $('#second_reject').html(summary_html ? `不同单价的数量总和:
${summary_html}` : ''); }; // 同一年份重复切换时直接使用缓存结果,不再请求服务器 if (historyCache.has(year)) { render(historyCache.get(year)); return; } $panel.html('
加载中...
'); try { const returns_order = await showCustomerSalesFlowList(customer, products, year); const list_order = transformFlowRows(returns_order); historyCache.set(year, list_order); render(list_order); } catch (err) { $panel.html(`
${escapeHtml(err.message)}
`); } } // 读取当前表单上下文并刷新历史旧价 function refreshHistoryPrice() { const customer_id = $('#sales-customer-rejectBillAddPage-hidden').val(); const products_id = $('#sales-goodsId-billDetailAddPage-hidden').val(); const select_year = $('.new_div .tabs-selected span').first().html(); if (!products_id) return; queryHistoryPrice(customer_id, products_id, (select_year || '').trim()); } // ===== 历史旧价窗口 ===== // 注入面板样式(抽离自原内联 style) function injectStyles() { const css = ` .new_div{z-index:9999;position:absolute;display:block;width:${CONFIG.panelWidth}px;height:${CONFIG.panelHeight}px;background-color:#ffffff;} .new_div .tabs-wrap{margin-left:0;margin-right:0;width:${CONFIG.panelWidth}px;} .new_div .tabs{height:27px;} .new_div .tabs-inner{height:26px;line-height:26px;} .new_div .layout-body{width:${CONFIG.panelWidth}px;height:${CONFIG.bodyHeight}px;display:none;overflow:auto;} .second_div{z-index:9998;position:absolute;display:block;width:${CONFIG.panelWidth}px;left:0;bottom:0;background-color:#ffffff;} .second_div .panel-body{width:${CONFIG.panelWidth}px;height:${CONFIG.summaryHeight}px;display:block;} .rejectorder-toast{position:fixed;top:20px;left:50%;transform:translateX(-50%);z-index:99999;background:#333;color:#fff;padding:8px 16px;border-radius:4px;max-width:60%;} .rejectorder-loading,.rejectorder-error{padding:10px;color:#666;} .rejectorder-error{color:#c00;}`; $('