// ==UserScript== // @name link工具 // @namespace http://tampermonkey.net/ // @version 0.10.4 // @description 点击复制,提取链接 // @author lwj // @match *://m.linkmcn.com/* // @match https://m.linkmcn.com/tableCard/redirect* // @match *://detail.tmall.com/item* // @match *://item.taobao.com/item* // @match *://chaoshi.detail.tmall.com/item* // @match *://traveldetail.fliggy.com/item* // @match *://detail.tmall.hk/hk/item* // @license MIT // @grant GM_setValue // @grant GM_getValue // @grant GM_setClipboard // @grant GM_xmlhttpRequest // @downloadURL https://update.greasyfork.icu/scripts/497689/link%E5%B7%A5%E5%85%B7.user.js // @updateURL https://update.greasyfork.icu/scripts/497689/link%E5%B7%A5%E5%85%B7.meta.js // ==/UserScript== /* global Segmentit */ (function () { // 版本号 var versionTitleTxt = 'Version 0.10.4'; // 检查当前页面 URL 是否匹配指定的网址 var isHomeURL = function () { var currentURL = window.location.href; return currentURL.indexOf("https://m.linkmcn.com/#/live/plan?select=") !== -1; }; // 从 localStorage 中获取上一次的 URL,如果没有则设置为空字符串 let lastCurrentURL = localStorage.getItem('lastCurrentURL') || ''; var isTableCardURL = function () { return window.location.href.indexOf("https://m.linkmcn.com/#/live/plan/tableCard/") !== -1; }; var isBatchPrintURL = function () { return window.location.href.indexOf("https://m.linkmcn.com/#/live/plan/batchPrint") !== -1; }; var isTmallItemURL = function () { var url = window.location.href; // 检查URL是否包含任何指定的域名或路径 return ( url.indexOf("https://detail.tmall.com/item") !== -1 || url.indexOf("https://detail.tmall.hk/hk/item") !== -1 || url.indexOf("https://item.taobao.com/item") !== -1 || url.indexOf("https://chaoshi.detail.tmall.com/item") !== -1 || url.indexOf("https://traveldetail.fliggy.com/item") !== -1 ); } var isRedirectUrl = function () { return window.location.href.indexOf("https://item.taobao.com/item.htm?id=682878335608&link_redirectId=") !== -1; } var notificationTimer; // 通知计时器 var isHiding = false; // 标志,表示是否正在隐藏通知 let countSort_notificationTimeout = null;// 排序提示定时器 let temp_itemId = ''; class ToggleButtonComponent { constructor(localStorageKey, buttonText, dropdownContainer, useSpecialSwitch = 0, defaultState = false) { this.localStorageKey = localStorageKey; this.switchState = localStorage.getItem(this.localStorageKey) === null ? defaultState : localStorage.getItem(this.localStorageKey) === 'true'; this.buttonText = buttonText; this.dropdownContainer = dropdownContainer; this.useSpecialSwitch = useSpecialSwitch === 1; this.createComponent(); } createComponent() { // 创建按钮容器 this.buttonContainer = document.createElement('div'); this.buttonContainer.classList.add('flex', 'items-center', 'dropdown-item'); this.buttonContainer.style.cssText = 'padding: 12px 16px; user-select: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center;'; if (this.buttonText === '纯净模式') { this.buttonContainer.style.paddingTop = '0px'; } // 创建按钮文本 this.buttonTextElement = document.createElement('span'); this.buttonTextElement.textContent = this.buttonText; this.buttonTextElement.classList.add('lh-22'); this.buttonContainer.appendChild(this.buttonTextElement); if (this.useSpecialSwitch) { // 创建特殊开关样式按钮 this.createSpecialSwitch(); } else { // 创建普通按钮 this.createStandardButton(); } // 将按钮容器添加到下拉容器中 this.dropdownContainer.appendChild(this.buttonContainer); // 创建对应的空的子页面并设置样式 this.secondaryContent = document.createElement('div'); this.secondaryContent.id = this.localStorageKey + '-secondary-content'; this.secondaryContent.style.cssText = 'margin: 0px 10px; display: none; padding: 10px 12px; background: #E9E9E9; border: 1px solid #D2D2D2; border-radius: 10px;'; // 将子页面添加到按钮容器的下方 this.dropdownContainer.appendChild(this.secondaryContent); } createStandardButton() { this.button = document.createElement('button'); this.button.id = 'main_standardFunShowButton'; this.button.style.cssText = 'background: none; border: none; font-size: 16px; cursor: pointer; transition: transform 0.3s; margin: 0px 6px'; this.button.appendChild(createSVGIcon()); this.buttonContainer.appendChild(this.button); // 绑定点击事件 this.button.addEventListener('click', () => this.handleStandardButtonClick()); // 给标题绑定模拟点击开关事件 this.buttonTextElement.addEventListener('click', () => this.titleToSwitchClick()); } handleStandardButtonClick() { // 切换二级页面显示状态 const secondaryContent = document.getElementById(this.localStorageKey + '-secondary-content'); if (secondaryContent) { secondaryContent.style.display = secondaryContent.style.display === 'block' ? 'none' : 'block'; } else { console.log(`${this.buttonText} 二级页面异常`); } // 旋转按钮图标 const icon = this.button.querySelector('svg'); const rotation = icon.style.transform === 'rotate(90deg)' ? 'rotate(0deg)' : 'rotate(90deg)'; icon.style.transform = rotation; } createSpecialSwitch() { this.button = document.createElement('button'); this.button.innerHTML = '
'; this.button.setAttribute('type', 'button'); this.button.setAttribute('role', 'switch'); this.button.setAttribute('aria-checked', this.switchState); // 设置开关状态 this.button.classList.add('ant-switch', 'css-9fw9up'); if (this.switchState) { this.button.classList.add('ant-switch-checked'); } this.buttonContainer.appendChild(this.button); this.buttonContainer.style.cursor = 'default'; // 添加点击事件监听 this.button.addEventListener('click', () => this.handleSwitchClick()); } handleSwitchClick() { // 切换开关状态 const newState = this.button.getAttribute('aria-checked') === 'true' ? 'false' : 'true'; this.button.setAttribute('aria-checked', newState); if (newState === 'true') { this.button.classList.add('ant-switch-checked'); showNotification(`${this.buttonText}:开启`); } else { this.button.classList.remove('ant-switch-checked'); showNotification(`${this.buttonText}:关闭`); } // 更新开关状态 updateSwitchState(this.localStorageKey, newState === 'true'); } titleToSwitchClick() { // 模拟点击开关按钮 this.button.click(); } remove_titleToSwitchClick() { // 移除模拟点击开关按钮 this.buttonTextElement.removeEventListener('click', () => this.titleToSwitchClick()); } // 获取开关状态 getSwitchState() { if (noneDrawColor()) { return false; } else { return this.button.getAttribute('aria-checked') === 'true'; } } // 获取子页面元素 getSecondaryContent() { return this.secondaryContent; } } class SonToggleButtonComponent extends ToggleButtonComponent { constructor(localStorageKey, buttonText, dropdownContainer, descriptionText, useSpecialSwitch = false, defaultState = false) { super(localStorageKey, buttonText, dropdownContainer, useSpecialSwitch, defaultState); this.buttonText = buttonText; this.descriptionText = descriptionText; this.createAdditionalContent(); } // 创建附加内容容器 createAdditionalContent() { // 修改按钮文本样式并去除 class="lh-22" this.buttonTextElement.style.cssText = 'font-size: 14px; margin: 0;'; this.buttonTextElement.classList.remove('lh-22'); // 调整父类的内容容器样式 this.buttonContainer.style.cssText = 'display: flex; user-select: none; justify-content: space-between; align-items: center; padding: 0;'; // 新增的说明容器 this.descriptionContainer = document.createElement('div'); this.descriptionContainer.classList.add('description-content'); this.descriptionContainer.style.cssText = 'font-size: 12px; color: #9B9B9B; user-select: none; margin: 5px 0px; padding-bottom: 5px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #D2D2D2; white-space: pre-wrap;'; this.descriptionContainer.textContent = this.descriptionText; if (this.descriptionText === '') this.descriptionContainer.style.paddingBottom = '0px'; // 子设置容器 this.childSettingsContainer = document.createElement('div'); this.childSettingsContainer.classList.add('child-settings'); this.childSettingsContainer.style.cssText = 'display: block; justify-content: space-between; align-items: center;'; // 初始化子开关容器的样式 this.updateSwitchStyle(); // 将说明容器和子设置容器添加到下拉容器中 this.dropdownContainer.appendChild(this.buttonContainer); this.dropdownContainer.appendChild(this.descriptionContainer); this.dropdownContainer.appendChild(this.childSettingsContainer); } // 重写createSpecialSwitch以添加额外的类 createSpecialSwitch() { // 确保父类方法被正确调用 super.createSpecialSwitch(); // 确保 this.button 已初始化 if (!this.button) { console.error('this.button is not initialized'); return; } // 将函数定义为对象的方法 this.autoInput_handleSwitchClick = () => { if (!this.getSwitchState()) { itemSort_inputConter.showSwitchDiv(true); // 显示输入内容选择框 itemSort_countInputFun.showNumberControlDiv(false); // 隐藏数字控制区 itemSort_countInputFun.toggleDivButtonState(false); // 关闭数字控制按钮 } }; if (this.buttonText === '自动填充') { // console.log(this.buttonText); this.button.addEventListener('click', () => this.autoInput_handleSwitchClick()); } // 添加额外的类 this.button.classList.add('ant-switch-small'); } // 独立的方法用于更新开关样式 updateSwitchStyle() { if (!this.getSwitchState()) { initializeContainerStyle(this.childSettingsContainer, false); // 使用函数初始化 } } // 控制单独组件的开启关闭 showSwitchDiv(flag) { if (flag) { initializeContainerStyle(this.buttonContainer, true); initializeContainerStyle(this.descriptionContainer, true); } else { initializeContainerStyle(this.buttonContainer, false); initializeContainerStyle(this.descriptionContainer, false); } } createSelectBox(options = ['', '0', '1', '2', '3', '999'], savedKey = this.localStorageKey + '_savedValue', container = this.buttonContainer) { // 先移除button元素 if (this.button) { this.buttonContainer.removeChild(this.button); } // 创建下拉框 const selectBox = document.createElement('select'); selectBox.setAttribute('id', this.localStorageKey + '-select-box'); selectBox.style.cssText = ` font-size: 14px; margin: 0; width: 42px; height: 18px; border: 1px solid rgb(155, 155, 155); background-color: rgb(249,249,249); color: rgb(155, 155, 155); border-radius: 20px; padding: 0 2.5%; -webkit-appearance: none; -moz-appearance: none; appearance: none; position: relative; cursor: pointer; `; options.forEach(value => { const option = document.createElement('option'); option.value = value; option.style.cssText = ` text-align: center; padding: 0 5px; `; option.textContent = value === '' ? '空' : value; selectBox.appendChild(option); }); const savedValue = localStorage.getItem(savedKey) || options[1]; selectBox.value = savedValue; selectBox.addEventListener('change', () => { localStorage.setItem(savedKey, selectBox.value); updateSwitchState(this.localStorageKey, selectBox.value); // 悬浮时和激活时边框颜色变化 selectBox.style.borderColor = '#ff6200'; }); // 悬浮时和激活时边框颜色变化 selectBox.addEventListener('mouseover', function () { selectBox.style.borderColor = '#ff6200'; }); selectBox.addEventListener('mouseout', function () { if (!selectBox.matches(':focus')) { selectBox.style.borderColor = 'rgb(155, 155, 155)'; } }); selectBox.addEventListener('focus', function () { selectBox.style.borderColor = '#ff6200'; }); selectBox.addEventListener('blur', function () { selectBox.style.borderColor = 'rgb(155, 155, 155)'; }); container.appendChild(selectBox); } createDivButton(beforeText, afterText, onClickCallback = null, container = this.buttonContainer) { // 先移除button元素 if (this.button) { this.buttonContainer.removeChild(this.button); } this.beforeText = beforeText; this.afterText = afterText; this.onClickCallback = onClickCallback; // 功能开启按钮 this.divButton = document.createElement('div'); this.divButton.setAttribute('id', this.localStorageKey + '_divButton'); this.divButton.textContent = beforeText; this.divButton.style.cssText = ` font-size: 14px; margin: 0; width: 42px; height: 18px; border: 1px solid rgb(155, 155, 155); background-color: rgb(249,249,249); color: rgb(155, 155, 155); border-radius: 20px; padding: 0 2%; -webkit-appearance: none; -moz-appearance: none; appearance: none; position: relative; cursor: pointer; user-select: none; text-align: center; `; // 悬浮时和激活时边框颜色变化 this.divButton.addEventListener('mouseover', () => { if (this.divButton.textContent === beforeText) { this.divButton.style.borderColor = '#ff6200'; } else { this.divButton.style.borderColor = 'rgb(155, 155, 155)'; } }); this.divButton.addEventListener('mouseout', () => { if (this.divButton.textContent === beforeText) { this.divButton.style.borderColor = 'rgb(155, 155, 155)'; } else { this.divButton.style.borderColor = 'rgb(249, 249, 249)'; } }); // 按钮点击事件 this.divButton.addEventListener('click', () => { this.toggleDivButtonState(); }); container.appendChild(this.divButton); } // 控制单独组件的开启关闭 toggleDivButtonState(isActivated = null) { // 如果提供了isActivated参数,则根据参数设置状态,否则根据当前状态切换 const shouldActivate = isActivated !== null ? isActivated : (this.divButton.textContent === this.beforeText); if (shouldActivate) { this.divButton.textContent = this.afterText; this.divButton.style.color = '#fff'; this.divButton.style.backgroundColor = '#ff0000'; this.divButton.style.borderColor = '#fff'; showNotification(`${this.buttonText}:开启`); if (this.onClickCallback) { this.onClickCallback(true); } } else { this.divButton.textContent = this.beforeText; this.divButton.style.color = 'rgb(155, 155, 155)'; this.divButton.style.backgroundColor = 'rgb(249,249,249)'; this.divButton.style.borderColor = 'rgb(155, 155, 155)'; showNotification(`${this.buttonText}:关闭`); if (this.onClickCallback) { this.onClickCallback(false); } } } // 判断开关开启状态 getDivButtonState() { if (this.divButton.textContent === this.beforeText) { return false;// 开关开启状态 } else { return true;// 开关关闭状态 } } createNumberControDiv(defaultNumber = 0, single = false, countType = 'none', savedKey = this.localStorageKey + '_savedValue', container = this.buttonContainer) { if (single) { //先移除button元素 if (this.button) { this.buttonContainer.removeChild(this.button); } } // 数字文本及SVG控制区 this.numberControDiv = document.createElement('div'); this.numberControDiv.style.cssText = ` font-size: 14px; display: flex; align-items: center; min-width: 42px; height: 18px; width: auto; border: 1px solid rgb(155, 155, 155); background-color: rgb(249,249,249); color: rgb(155, 155, 155); border-radius: 20px; padding: 0 2.5%; -webkit-appearance: none; -moz-appearance: none; appearance: none; position: relative; cursor: default; `; // 数字文本 this.countText = document.createElement('span'); this.countText.textContent = defaultNumber; // 使用默认数字 this.countText.style.cssText = 'font-size: 14px; margin: 0 auto; cursor: pointer;'; this.numberControDiv.appendChild(this.countText); // 创建函数来设置悬停颜色 function addHoverEffect(svgElement) { svgElement.addEventListener('mouseover', function () { var path = svgElement.querySelector('path'); if (path) { path.setAttribute('data-original-fill', path.getAttribute('fill')); path.setAttribute('fill', '#ff6200'); } }); svgElement.addEventListener('mouseout', function () { var path = svgElement.querySelector('path'); if (path) { path.setAttribute('fill', path.getAttribute('data-original-fill')); } }); } // SVG控制区 var svgControlDiv = document.createElement('div'); svgControlDiv.style.cssText = 'display: flex; flex-direction: column; justify-content: space-between; cursor: pointer;'; // 上方SVG var svgUp = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgUp.setAttribute("width", "6"); svgUp.setAttribute("height", "6"); svgUp.setAttribute("viewBox", "0 0 1024 1024"); svgUp.innerHTML = ` `; addHoverEffect(svgUp); svgControlDiv.appendChild(svgUp); // 下方SVG var svgDown = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgDown.setAttribute("width", "6"); svgDown.setAttribute("height", "6"); svgDown.setAttribute("viewBox", "0 0 1024 1024"); svgDown.innerHTML = ` `; addHoverEffect(svgDown); svgControlDiv.appendChild(svgDown); svgUp.addEventListener('click', () => this.updateCount(1, 'countInput')); svgDown.addEventListener('click', () => this.updateCount(-1, 'countInput')); this.numberControDiv.appendChild(svgControlDiv); container.appendChild(this.numberControDiv); // 绑定点击事件以显示弹窗 this.countText.addEventListener('click', () => { createDropdownModal(dropdownContainer, '输入计数').then((inputValue) => { // console.log('用户输入:', inputValue); if (parseInt(inputValue) >= 0 && parseInt(inputValue) <= 999) { this.countText.textContent = inputValue; // 更新显示的数字 this.countSort_reShowNotification(0); // 更新通知 } else if (parseInt(inputValue) > 999) { showNotification('输入值超过了合理的范围', 1500); } else { showNotification('输入值必须为正整数', 1500); } }).catch((error) => { // console.log('弹窗取消:', error); }); }); } // 用于更新数字文本的方法 updateCount(increment, notificationType) { let currentValue = parseInt(this.countText.textContent); currentValue += increment; this.setCount(currentValue); if (notificationType === 'countInput') { if (this.getCount() > 0) { showNotification(`下一个输入序号:${currentValue}`, 0); } else { this.setCount(1); showNotification('当前已是最小序号', 1500); this.countSort_reShowNotification(); } } } // 获取当前的计数 getCount() { return this.countText.textContent; } // 设置当前计数 setCount(count) { this.countText.textContent = count; } // 控制numberControDiv显示/隐藏的方法 showNumberControlDiv(visible) { if (this.numberControDiv) { this.numberControDiv.style.display = visible ? 'flex' : 'none'; } } // 常显通知方法 countSort_reShowNotification(show_time = 1500) { if (countSort_notificationTimeout) { clearTimeout(countSort_notificationTimeout); } countSort_notificationTimeout = setTimeout(() => { if (this.getDivButtonState()) { showNotification("下一个输入序号:" + this.getCount(), 0); } countSort_notificationTimeout = null; }, show_time); // 延迟后触发 } // 重写handleSwitchClick以控制子页面的可点击性 handleSwitchClick() { super.handleSwitchClick(); const newState = this.getSwitchState(); initializeContainerStyle(this.childSettingsContainer, newState); } // 获取子设置容器 getChildSettingsContainer() { return this.childSettingsContainer; } getSelectBoxValue() { const selectBox = this.buttonContainer.querySelector('select'); return selectBox ? selectBox.value : null; } } // 创建开关容器元素 var switchesContainer = document.createElement('div'); switchesContainer.classList.add('flex', 'items-center', 'justify-between', 'pb-12'); switchesContainer.style.cssText = 'position: fixed; top: 0px; left: 50%; transform: translateX(-50%); z-index: 9999;'; if (isHomeURL()) { document.body.appendChild(switchesContainer); } // 封装函数返回SVG图标 function createSVGIcon() { var svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgIcon.setAttribute('class', 'icon custom-svg'); // 添加自定义类名 svgIcon.setAttribute('viewBox', '0 0 1024 1024'); svgIcon.setAttribute('width', '20'); svgIcon.setAttribute('height', '20'); svgIcon.setAttribute('fill', '#bbbbbb'); svgIcon.innerHTML = ''; svgIcon.style.cssText = 'vertical-align: middle;'; // 垂直居中样式 return svgIcon; } // 添加事件监听用于下拉箭头 document.addEventListener('mouseenter', function (event) { if (event.target instanceof Element && event.target.matches('svg.icon.custom-svg')) { // 仅匹配具有自定义类名的SVG event.target.setAttribute('fill', '#ff6200'); } }, true); document.addEventListener('mouseleave', function (event) { if (event.target instanceof Element && event.target.matches('svg.icon.custom-svg')) { // 仅匹配具有自定义类名的SVG event.target.setAttribute('fill', '#bbbbbb'); } }, true); var dropdown_style = document.createElement('style'); dropdown_style.textContent = ` @keyframes dropdownContentAnimation { 0% { transform: translateX(-50%) translateY(14px) scale(0); } 100% { transform: translateX(-50%) translateY(0) scale(1); } } @keyframes dropdownContentExitAnimation { 0% { transform: translateX(-50%) translateY(0) scale(1); } 100% { transform: translateX(-50%) translateY(14px) scale(0); } } #dropdownContent.show { animation: dropdownContentAnimation 0.3s ease-out; } #dropdownContent.hide { animation: dropdownContentExitAnimation 0.3s ease-out; } @keyframes dropdownButtonAnimation { 0% { transform: scale(1); } 35% { transform: scale(1.15, 1.3); } 85% { transform: scale(0.94); } 100% { transform: scale(1); } } #dropdownButtonAnimate.animate { animation: dropdownButtonAnimation 0.45s ease-out; } `; document.head.appendChild(dropdown_style); var dropdownContainer = document.createElement('div'); dropdownContainer.style.cssText = 'position: relative; display: inline-block;'; var dropdownButtonName = '更多功能'; var dropdownButton = document.createElement('button'); dropdownButton.id = 'dropdownButtonAnimate'; // 添加 id 以便于应用动画 dropdownButton.textContent = dropdownButtonName; dropdownButton.style.cssText = 'margin-top: 0px; padding: 0px 10px; cursor: pointer; border-radius: 999px;z-index: 3;'; dropdownButton.classList.add('ant-btn', 'css-9fw9up', 'ant-btn-default', 'primaryButton___N3z1x'); var dropdownDeck = document.createElement('div'); dropdownDeck.style.cssText = ` top: 0; left: 0; width: 200px; height: 60px; box-sizing: border-box; display: flex; justify-content: center; align-items: center; `; var dropdownContent = document.createElement('div'); dropdownContent.id = 'dropdownContent'; dropdownContent.style.cssText = ` display: none; position: absolute; background-color: #f9f9f9; top: 0px; left: 50%; transform: translateX(-50%); min-width: 200px; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); z-index: 1; border-radius: 16px; max-height: 360px; overflow-y: auto; /* 使用 auto 可以根据内容是否溢出显示滚动条 */ scrollbar-width: none; /* 隐藏滚动条,适用于 Firefox */ -ms-overflow-style: none; /* 隐藏滚动条,适用于 IE 和 Edge */ transform-origin: top center; `; // 获取内容的显示状态 function getDropdownContentDisplayState() { return dropdownContent.style.display !== 'none'; // 返回 true 表示可见,false 表示不可见 } var dropdownMask = document.createElement('div'); dropdownMask.style.cssText = ` position: sticky; top: 0; left: 0; width: 200px; height: 60px; backdrop-filter: none; border-radius: 10px 10px 0 0; box-sizing: border-box; border-bottom: 0px solid #DDD; z-index: 99; /* 确保遮罩在内容上方 */ display: flex; justify-content: center; align-items: center; background-color: rgba(249, 249, 249, 0); `; dropdownDeck.appendChild(dropdownButton); dropdownContainer.appendChild(dropdownDeck); dropdownContent.appendChild(dropdownMask); dropdownContainer.appendChild(dropdownContent); switchesContainer.appendChild(dropdownContainer); function on_dropdownMask() { dropdownMask.style.borderBottom = '1px solid #DDD'; dropdownMask.style.backdropFilter = 'blur(8px) brightness(90%)'; dropdownMask.style.backgroundColor = 'rgba(249, 249, 249, 0.5)'; } function off_dropdownMask() { dropdownMask.style.borderBottom = '0px solid #DDD'; dropdownMask.style.backdropFilter = 'none'; dropdownMask.style.backgroundColor = 'rgba(249, 249, 249, 0)'; } dropdownButton.addEventListener('click', function () { // 强制重新开始动画 this.classList.remove('animate'); // 使用 requestAnimationFrame 确保动画类已被移除 requestAnimationFrame(() => { this.classList.add('animate'); }); this.addEventListener('animationend', function () { this.classList.remove('animate'); }, { once: true }); if (dropdownContent.style.display === 'none' || dropdownContent.classList.contains('hide')) { dropdownContent.style.display = 'block'; pureMode_infoDisplay(pureSwitch.getSwitchState()); dropdownContent.classList.remove('hide'); dropdownContent.classList.add('show'); if (dropdownContent.scrollTop > 0) { on_dropdownMask(); } } else { dropdownContent.classList.remove('show'); dropdownContent.classList.add('hide'); dropdownContent.addEventListener('animationend', function onAnimationEnd() { if (dropdownContent.classList.contains('hide')) { dropdownContent.style.display = 'none'; pureMode_infoDisplay(pureSwitch.getSwitchState()); off_dropdownMask(); } dropdownContent.removeEventListener('animationend', onAnimationEnd); }); } }); dropdownContent.addEventListener('scroll', function () { if (dropdownContent.scrollTop > 0 && dropdownContent.style.display !== 'none') { on_dropdownMask(); } else { off_dropdownMask(); } }); window.addEventListener('click', function (event) { if (!dropdownContainer.contains(event.target)) { if (dropdownContent.style.display === 'block') { dropdownContent.classList.remove('show'); dropdownContent.classList.add('hide'); // 强制重新开始动画 dropdownButton.classList.remove('animate'); // 使用 requestAnimationFrame 确保动画类已被移除 requestAnimationFrame(() => { dropdownButton.classList.add('animate'); }); dropdownButton.addEventListener('animationend', function () { this.classList.remove('animate'); }, { once: true }); dropdownContent.addEventListener('animationend', function onAnimationEnd() { if (dropdownContent.classList.contains('hide')) { dropdownContent.style.display = 'none'; off_dropdownMask(); pureMode_infoDisplay(pureSwitch.getSwitchState()); } dropdownContent.removeEventListener('animationend', onAnimationEnd); }); } } }); class PIPManager { constructor(itemLink, spanElement, isHorizontal) { this.itemLink = itemLink; this.spanElement = spanElement; this.isHorizontal = isHorizontal; this.PIP = this.createPIP(); this.ctrlBar = this.createControlBar(); this.bar = this.createBar(); this.witheCtrlBar = this.createWitheCtrlBar(); this.iframe = this.createIframe(); this.spanElement.onclick = this.togglePIP.bind(this); this.collapseButton = null; // 用于存储收起后的矩形按钮 // 初始化状态 this.isDragging = false; this.offsetX = 0; this.offsetY = 0; this.isCollapsed = false; // 收起状态 // 添加拖动事件监听(只在控制条上) this.bar.addEventListener('mousedown', this.startDrag.bind(this)); document.addEventListener('mouseup', this.stopDrag.bind(this)); document.addEventListener('mousemove', this.drag.bind(this)); // 监听窗口大小变化 window.addEventListener('resize', this.onWindowResize.bind(this)); } countSclaeWidthAndHeight(p) { const scale = this.getDisplayScale(); const calculatedLength = p / scale; if (calculatedLength > 90) { return 90; } if (calculatedLength < 45) { return 45; } return calculatedLength; } createPIP() { const PIP = document.createElement('div'); PIP.id = 'mini_PIP'; PIP.style.cssText = ` position: fixed; bottom: 10px; background-color: rgba(0, 0, 0, 0.5); padding: 5px; padding-top: 3px; border-radius: 24px; display: none; z-index: 1099; backdrop-filter: blur(10px) brightness(90%); overflow: hidden; transform: scale(1); transition: transform 0.5s ease, opacity 0.5s ease; /* 更新过渡效果时间 */ `; if (sonMain_PIP_defautPosition.getSelectBoxValue() === '左侧') { PIP.style.left = '10px'; PIP.style.transformOrigin = 'bottom left'; /* 设置缩放的锚点 */ } else { PIP.style.right = '10px'; PIP.style.transformOrigin = 'bottom right'; /* 设置缩放的锚点 */ } PIP.style.width = this.isHorizontal ? "1300px" : "360px"; PIP.style.transform = `scale(${this.getDisplayScale()})`; PIP.style.height = this.isHorizontal ? this.countSclaeWidthAndHeight(90) + "%" : this.countSclaeWidthAndHeight(90) + "%"; return PIP; } getDisplayScale(isHorizontal = this.isHorizontal) { const displayWidth = window.innerWidth; let displayScale = displayWidth / 1530; if (isHorizontal) { return displayScale * 0.7; } else { return displayScale; } } getBarDisplayPX(px, isHorizontal = this.isHorizontal) { return px / this.getDisplayScale(isHorizontal) + 'px'; } onWindowResize() { // 调整PIP的缩放比例和尺寸 const newScale = this.getDisplayScale(); this.PIP.style.transform = `scale(${newScale})`; // 重新计算PIP的高度 this.PIP.style.height = this.isHorizontal ? this.countSclaeWidthAndHeight(90) + "%" : this.countSclaeWidthAndHeight(90) + "%"; // 调整控制条的高度和其他尺寸 this.ctrlBar.style.height = this.getBarDisplayPX(12); this.ctrlBar.style.fontSize = this.getBarDisplayPX(10); // 动态调整 ctrlBar 的字体大小 this.bar.style.height = this.getBarDisplayPX(7); this.bar.style.width = this.getBarDisplayPX(60); } createControlBar() { const ctrlBar = document.createElement('div'); ctrlBar.style.cssText = ` height: ${this.getBarDisplayPX(12)}; width: 100%; background-color: rgba(0, 0, 0, 0); z-index: 1101; margin-bottom: 3px; font-size: ${this.getBarDisplayPX(10)}; /* 初始字体大小 */ `; return ctrlBar; } createWitheCtrlBar() { const witheCtrlBar = document.createElement('div'); witheCtrlBar.style.cssText = ` display: flex; align-items: center; /* 垂直居中 */ justify-content: space-between; /* 左右对齐 */ height: 100%; width: calc(100% - 20px); margin: 0 auto; position: relative; /* 使子元素可以绝对定位 */ `; const leftButtonsContainer = document.createElement('div'); leftButtonsContainer.style.cssText = ` display: flex; align-items: center; /* 垂直居中 */ justify-content: flex-start; /* 左对齐 */ height: 100%; `; const rightButtonsContainer = document.createElement('div'); rightButtonsContainer.style.cssText = ` display: flex; align-items: center; /* 垂直居中 */ justify-content: flex-end; /* 右对齐 */ height: 100%; `; this.returnButton = this.createBarButton("返回", "returnButton", "left"); this.newWindowButton = this.createBarButton("新窗口", "newWindowButton", "right", "rgb(0, 145, 255)"); this.closeButton = this.createBarButton("关闭", "closeButton", "right", "rgba(236, 40, 39, 0.5)"); this.reloadButton = this.createBarButton("刷新", "reloadButton", "left"); this.collapseButton = this.createBarButton("收起", "collapseButton", "right"); // 添加按钮点击事件 this.closeButton.addEventListener('click', this.closePIP.bind(this)); this.reloadButton.addEventListener('click', this.reloadPIP.bind(this)); this.returnButton.addEventListener('click', this.returnPIP.bind(this)); this.newWindowButton.addEventListener('click', this.newWindowPIP.bind(this)); this.collapseButton.addEventListener('click', this.toggleCollapse.bind(this)); leftButtonsContainer.appendChild(this.returnButton); leftButtonsContainer.appendChild(this.reloadButton); rightButtonsContainer.appendChild(this.collapseButton); rightButtonsContainer.appendChild(this.newWindowButton); rightButtonsContainer.appendChild(this.closeButton); // 按钮隐藏 if (!this.isHorizontal) { this.newWindowButton.style.display = 'none'; } // 将按钮容器添加到witheCtrlBar witheCtrlBar.appendChild(leftButtonsContainer); witheCtrlBar.appendChild(this.bar); witheCtrlBar.appendChild(rightButtonsContainer); return witheCtrlBar; } createBar() { const bar = document.createElement('div'); bar.style.cssText = ` height: ${this.getBarDisplayPX(7)}; mangrgin-bottom: 1px; width: 60px; background-color: rgba(255, 255, 255, 0.5); border-radius: 999px; position: absolute; left: 50%; transform: translateX(-50%); `; return bar; } createBarButton(buttonName = "按钮", buttonId = "mini-PIP-barButton", position = "center", bg_color = "rgba(173, 173, 173, 0.5)") { const newButton = document.createElement('button'); newButton.id = buttonId; newButton.style.cssText = ` font-size: 1em; /* 使用em单位来确保字体大小跟随ctrlBar */ padding: 0 10px; background-color: ${bg_color}; border: none; border-radius: 999px; margin: 0 5px; color: white; cursor: pointer; user-select: none; `; newButton.innerText = buttonName; if (position === "left") { newButton.style.marginRight = 'auto'; } else if (position === "right") { newButton.style.marginLeft = 'auto'; } return newButton; } createIframe() { const iframe = document.createElement('iframe'); iframe.style.cssText = ` display: block; width: 100%; height: calc(100% - ${this.ctrlBar.style.height} - ${this.ctrlBar.style.marginBottom}); border: none; border-radius: 19px; z-index: 1099; transition: opacity 0.3s ease; `; return iframe; } togglePIP() { const pipElement = document.getElementById('mini_PIP'); const pip_restore_button = document.getElementById('pip_restore_button'); if (pip_restore_button) { pip_restore_button.remove(); // 先移除恢复按钮 } if (pipElement) { pipElement.parentElement.removeChild(pipElement); } // 先添加控制条,再添加iframe this.ctrlBar.appendChild(this.witheCtrlBar); this.PIP.appendChild(this.ctrlBar); this.PIP.appendChild(this.iframe); document.body.appendChild(this.PIP); this.iframe.src = this.itemLink; this.PIP.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; // 过渡效果 this.PIP.style.display = 'block'; setTimeout(() => { this.PIP.style.opacity = '1'; // 恢复透明度 }, 0); adapterPIP_forTableCardAndBatchPrint(sonMain_PIP_autoAdjust.getSwitchState()); } startDrag(event) { // adapterPIP_forTableCardAndBatchPrint(sonMain_PIP_autoAdjust.getSwitchState(), true); this.isDragging = true; this.offsetX = event.clientX - this.PIP.offsetLeft; this.offsetY = event.clientY - this.PIP.offsetTop; this.bar.style.cursor = 'grabbing'; this.iframe.style.opacity = '0'; // 透明 } stopDrag() { this.isDragging = false; this.bar.style.cursor = 'grab'; // adapterPIP_forTableCardAndBatchPrint(sonMain_PIP_autoAdjust.getSwitchState()); this.iframe.style.opacity = '1'; // 取消透明 } drag(event) { if (this.isDragging) { this.PIP.style.left = `${event.clientX - this.offsetX}px`; this.PIP.style.top = `${event.clientY - this.offsetY}px`; adapterPIP_forTableCardAndBatchPrint(sonMain_PIP_autoAdjust.getSwitchState()); this.iframe.style.zIndex = '1'; // 置于底层 } } closePIP() { // this.PIP.style.display = 'none'; this.PIP.style.transformOrigin = 'center center'; // 设置缩放的锚点 this.PIP.style.transform = 'scale(0.1)'; // 缩小 this.PIP.style.opacity = '0'; // 逐渐透明 adapterPIP_forTableCardAndBatchPrint(sonMain_PIP_autoAdjust.getSwitchState(), true); setTimeout(() => { this.PIP.style.display = 'none'; this.PIP.style.transform = `scale(${this.getDisplayScale()})`; // 恢复 this.PIP.style.transformOrigin = 'bottom right;'; // 设置缩放 }, 300); // 等待动画结束后再隐藏 } reloadPIP() { this.iframe.src = this.iframe.src; } returnPIP() { window.history.back(); } newWindowPIP() { window.open(this.itemLink); } toggleCollapse() { if (this.isCollapsed) { this.expandPIP(); } else { this.collapsePIP(); } } collapsePIP() { this.PIP.style.transformOrigin = ''; // 设置缩放的锚点 // 获取当前PIP的位置 const pipRect = this.PIP.getBoundingClientRect(); const centerX = pipRect.left + pipRect.width / 2; // 判断PIP位置,决定收起方向 const isLeftSide = centerX < window.innerWidth / 2; // 计算目标位置的中心点 const targetX = isLeftSide ? -(window.innerWidth / 2) : (window.innerWidth / 2); // 收起到左侧或右侧 // 设置PIP收起动画 this.PIP.style.transition = 'transform 0.5s ease, opacity 0.5s ease'; // 过渡效果 this.PIP.style.transform = `translate(${targetX}px, 0px) scale(0.1)`; // 缩小并移动到目标位置 this.PIP.style.opacity = '0'; // 逐渐透明 adapterPIP_forTableCardAndBatchPrint(sonMain_PIP_autoAdjust.getSwitchState(), true); setTimeout(() => { setTimeout(() => { this.PIP.style.display = 'none'; }, 200); // 等待动画结束后再隐藏 this.createRestoreButton(isLeftSide); // 创建恢复按钮 this.isCollapsed = true; // 设置为已收起状态 }, 300); // 等待动画结束后再隐藏 } expandPIP() { this.PIP.style.transformOrigin = ''; // 设置缩放的锚点 this.PIP.style.display = 'block'; this.PIP.style.bottom = '10px'; // 恢复到原位置 this.PIP.style.right = '10px'; // 恢复到原位置 adapterPIP_forTableCardAndBatchPrint(sonMain_PIP_autoAdjust.getSwitchState()); setTimeout(() => { this.PIP.style.transform = `scale(${this.getDisplayScale()})`; this.PIP.style.opacity = '1'; // 恢复透明度 this.removeRestoreButton(); // 移除恢复按钮 this.PIP.style.transformOrigin = 'bottom right'; // 设置缩放的锚点 }, 0); // 立即开始动画 this.isCollapsed = false; // 设置为未收起状态 } createRestoreButton(isLeftSide) { const restoreButton = document.createElement('div'); restoreButton.id = 'pip_restore_button'; restoreButton.style.cssText = ` position: fixed; bottom: 50%; /* 调整到50%高度位置 */ ${isLeftSide ? 'left' : 'right'}: 0px; /* 根据位置调整 */ width: 52px; height: 50px; background-color: rgba(0, 0, 0, 0.5); border-radius: 10px; ${isLeftSide ? 'border-top-left-radius: 0px;' : 'border-top-right-radius: 0px;'} /* 调整圆角 */ ${isLeftSide ? 'border-bottom-left-radius: 0px;' : 'border-bottom-right-radius: 0px;'} /* 调整圆角 */ z-index: 1100; cursor: pointer; transition: opacity 0.3s ease; `; restoreButton.addEventListener('click', this.expandPIP.bind(this)); const iconDiv = document.createElement('div'); const imgUrl = getTableCardImageUrl(); iconDiv.style.cssText = ` width: 40px; height: 40px; margin: 5px; ${isLeftSide ? 'margin-left' : 'margin-right'}: 7px; /* 根据位置调整 */ ${imgUrl ? 'background-image: url(' + imgUrl + ');' : 'background-image: url("https://www.taobao.com/favicon.ico");'} background-size: cover; border-radius: 5px; `; restoreButton.appendChild(iconDiv); document.body.appendChild(restoreButton); this.restoreButton = restoreButton; // 存储恢复按钮引用 } removeRestoreButton() { if (this.restoreButton) { document.body.removeChild(this.restoreButton); this.restoreButton = null; // 清除引用 } } } // 版本描述区域 var versionTitle = document.createElement('p'); versionTitle.textContent = versionTitleTxt; versionTitle.style.cssText = ` font-size: 12px; line-height: 1.8; /* 调整行高 */ margin: 0 20px; justify-content: center; /* 使用 flex 居中对齐 */ align-items: center; border-top: 1px solid #D2D2D2; text-align: center; /* 居中文本 */ color: #9B9B9B; display: flex; /* 添加 display: flex 以使用 flexbox 布局 */ cursor: pointer; /* 鼠标指针 */ user-select: none; `; var isExpanded_versionTitle = false; // 用于跟踪当前状态 // 悬浮时显示“展开所有菜单”或“折叠所有菜单” versionTitle.addEventListener('mouseover', function () { versionTitle.textContent = isExpanded_versionTitle ? '折叠所有菜单' : '展开所有菜单'; }); // 鼠标移开时恢复原始文本 versionTitle.addEventListener('mouseout', function () { versionTitle.textContent = versionTitleTxt; }); // 点击事件处理 versionTitle.addEventListener('click', function () { // 执行点击操作,展开或折叠所有菜单 document.querySelectorAll('#main_standardFunShowButton').forEach(button => button.click()); // 切换状态并更新悬浮文本 isExpanded_versionTitle = !isExpanded_versionTitle; versionTitle.textContent = versionTitleTxt; // 恢复原始文本 }); // 更新本地存储的开关状态 var updateSwitchState = function (switchName, newState) { localStorage.setItem(switchName, newState.toString()); }; // 通用子菜单容器样式的函数 function initializeContainerStyle(container, state) { if (!state) { container.style.opacity = '0.4';// 设置透明度使内容变浅 container.style.pointerEvents = 'none';// 禁止点击操作 } else { container.style.opacity = '';// 恢复透明度 container.style.pointerEvents = '';// 恢复点击操作 } } var notification_style = document.createElement('style'); notification_style.type = 'text/css'; notification_style.innerHTML = ` @keyframes showNotification { 0% { transform: translateX(-50%) scale(0); } 40% { transform: translateX(-50%) scale(.96); } 55% { transform: translateX(-50%) scale(1.04); } 100% { transform: translateX(-50%) scale(1); } } @keyframes hideNotification { 5% { transform: translateX(-50%) scale(1); } 100% { opacity: 0; transform: translateX(-50%) scale(0.2); } } @keyframes notificationButtonAnimation { 0% { transform: translateX(-50%) scale(1); } 100% { transform: translateX(-50%) scale(1.15); opacity: 0;} } .notification { cursor: default; position: fixed; bottom: 60px; left: 50%; background-color: rgba(0, 0, 0, 0.5); color: #fff; padding: 10px; border-radius: 12px; display: none; z-index: 9999; backdrop-filter: blur(10px) brightness(90%); /* 添加模糊效果 */ -webkit-backdrop-filter: blur(10px); /* 兼容Safari浏览器 */ transform-origin: center; width: auto; /* 默认宽度 */ max-width: 68%; white-space: nowrap; /* 单行显示 */ overflow: hidden; /* 超出内容隐藏 */ text-overflow: ellipsis; /* 溢出省略号 */ text-align: center; /* 文本居中显示 */ transform: translateX(-50%); /* 初始水平居中 */ } `; document.head.appendChild(notification_style); // 创建通知弹窗 var NotificationContainer = document.createElement('div'); NotificationContainer.classList.add('notification'); NotificationContainer.id = 'showNotificationContainer'; document.body.appendChild(NotificationContainer); // 将开关和按钮加入页面 // 添加纯净模式开关控件 const pureSwitch = new ToggleButtonComponent('pureSwitch', '纯净模式', dropdownContent, 1); // 添加复制开关控件 const old_copySwitchContainer = new ToggleButtonComponent('copySwitch', '点击店名复制', dropdownContent); // 添加提取商品链接控件 const newonlyItemIdButtonContainer = new ToggleButtonComponent('newmainOnlyItemIdSwitchState', '链接自动提取', dropdownContent); // 添加手卡截图控件 const tableCardPngSwitchContainer = new ToggleButtonComponent('tableCardPngSwitchState', '快捷截图', dropdownContent,); // 添加商品排序开关控件 const itemSortButtonContainer = new ToggleButtonComponent('mainItemSortButtonSwitchState', '商品排序', dropdownContent); // 添加挂链工具开关控件 const newGuaLian_onlyItemIdSwitch = new ToggleButtonComponent('newGuaLian_onlyItemIdSwitch', '挂链工具', dropdownContent); // 添加着色与计算器开关控件 const drawColorAndCalculatorContainer = new ToggleButtonComponent('mainDrawColorAndCalculatorContainer', '着色与计算器(Beta)', dropdownContent); // 添加画中画开关控件 const pictureInPictureSwitchContainer = new ToggleButtonComponent('pictureInPictureSwitchState', '小窗模式', dropdownContent); // 添加辅助功能开关控件 const AuxiliaryFunctionsContainer = new ToggleButtonComponent('AuxiliaryFunctionsContainer', '辅助功能', dropdownContent); dropdownContent.appendChild(versionTitle); // 版本说明 // 复制开关子功能区域 const main_copySwitch = old_copySwitchContainer.getSecondaryContent(); const copySwitchContainer = new SonToggleButtonComponent('copySwitchContainer', '点击店名复制', main_copySwitch, "点击店铺名称时,自动复制店铺链接到剪切板", 1); const copySwitch_onlyPart = new SonToggleButtonComponent('copySwitch_onlyPart', '部分复制触发方式', copySwitchContainer.getChildSettingsContainer(), "设置复制部分内容的触发方式", 1); const copySwitch_onlyPart_clickCount = ['单击', '双击']; copySwitch_onlyPart.createSelectBox(copySwitch_onlyPart_clickCount); const copySwitch_smartCpoy = new SonToggleButtonComponent('copySwitch_smartCpoy', '复制长度', copySwitchContainer.getChildSettingsContainer(), "设置复制内容的长度", 1); const copySwitch_smartCpoy_length = ['默认', '智能']; copySwitch_smartCpoy.createSelectBox(copySwitch_smartCpoy_length); // 提取链接子功能区域 const main_onlyItemIdSwitch = newonlyItemIdButtonContainer.getSecondaryContent(); const sonMain_onlyItemIdSwitch = new SonToggleButtonComponent('mainOnlyItemIdSwitchState', '链接自动提取', main_onlyItemIdSwitch, "当点击商品链接窗口时,会主动提取当前剪切板中的商品链接,并更新你的剪切板", 1); const mainOnlyItemId_autoSave = new SonToggleButtonComponent('mainOnlyItemId_autoSave_state', '自动保存', sonMain_onlyItemIdSwitch.getChildSettingsContainer(), '替换链接后自动点击“保存”按钮', 1); const mainOnlyItemId_checkTtemLink = new SonToggleButtonComponent('mainOnlyItemId_checkTtemLink_state', '链接检查', sonMain_onlyItemIdSwitch.getChildSettingsContainer(), '链接中不存在12位ID时,使用“警告”替换当前剪切板\n\n开启此功能会引起剪切板冲突', 1); // 辅助挂链子功能区域,正式从提取链接子功能区域独立 const mainGuaLian_onlyItemIdSwitch = newGuaLian_onlyItemIdSwitch.getSecondaryContent(); const sonMain_onlyItemIdForSearchDiv = new SonToggleButtonComponent('sonMain_onlyItemIdForSearchDiv_state', '搜索框自动提取ID', mainGuaLian_onlyItemIdSwitch, "当点击“全局筛选”搜索框时,会主动提取当前剪切板中的商品id,并更新你的剪切板", 1); const onlyItemIdForSearchDiv_onlyNoIntroduce = new SonToggleButtonComponent('mainOnlyItemIdonlyItemIdForSearchDiv_onlyNoIntroduce_state', '仅在挂链中生效', sonMain_onlyItemIdForSearchDiv.getChildSettingsContainer(), '开启后只会在“挂链商品”中生效该功能', 1, true); const onlyItemIdForSearchDiv_autoInputSort = new SonToggleButtonComponent('onlyItemIdForSearchDiv_autoInputSort', '自动输入排序', sonMain_onlyItemIdForSearchDiv.getChildSettingsContainer(), '开启后会给上播id正确的商品,自动输入“商品排序”中设定好的内容', 1); const sonMain_autoFlagedSwitch = new SonToggleButtonComponent('sonMain_autoFlagedSwitch_state', '批量输入排序', mainGuaLian_onlyItemIdSwitch, "当在“挂链”页面时,“全局筛选”搜索框右侧会出现“批量处理”按钮,可以将当前剪切板中的所有链接,自动标记为“自动填充”的目标内容", 1); const sonMain_linkAllCopySwitch = new SonToggleButtonComponent('sonMain_linkAllCopySwitch_state', '完整复制', mainGuaLian_onlyItemIdSwitch, "当在“挂链”页面时,“全局筛选”搜索框右侧会出现“完整复制”按钮,会主动复制当前剪切板中店铺的所有商品链接到剪切板", 1); // 快捷截图子功能区域 const main_tableCardPngSwitch = tableCardPngSwitchContainer.getSecondaryContent(); const sonMain_tableCardPngSwitch = new SonToggleButtonComponent('main_tableCardPngSwitch', '手卡截图', main_tableCardPngSwitch, "截取当前页面的手卡并添加到剪切板", 1); const tableCardPng_resolution = new SonToggleButtonComponent('mainTableCardPng_resolution', '清晰度', sonMain_tableCardPngSwitch.getChildSettingsContainer(), "设置截图的清晰度\n\n注意:更低的清晰度并不能提高截图的响应速度", 1); const tableCardPng_resolution_select = ['普通', '高清', '超清']; tableCardPng_resolution.createSelectBox(tableCardPng_resolution_select); const tableCardPng_checkItemIdRow = new SonToggleButtonComponent('tableCardPng_checkItemIdRow', '上播ID核对', sonMain_tableCardPngSwitch.getChildSettingsContainer(), "截图时在手卡中添一行“上播ID”,以便核对是否正确", 1); const tableCardPng_checkItemIdRow_onlyPng = new SonToggleButtonComponent('tableCardPng_checkItemIdRow_onlyPng', '仅截图时显示', tableCardPng_checkItemIdRow.getChildSettingsContainer(), "开启后仅在截图时会含有“上播id核对行”", 1); // 自动填充子功能区域 const main_itemSort = itemSortButtonContainer.getSecondaryContent(); const sonMain_itemSortSwitch = new SonToggleButtonComponent('main_itemSort_SwitchState_1', '自动填充', main_itemSort, "点击排序时自动自动清空或输入", 1); const itemSort_inputConter = new SonToggleButtonComponent('itemSort_inputConter', '输入内容', sonMain_itemSortSwitch.getChildSettingsContainer(), "设置自动输入的默认内容", 1); const itemSort_inputConter_input = ['空', '0', '1', '2', '3', '999', '2536']; itemSort_inputConter.createSelectBox(itemSort_inputConter_input); const itemSort_countInputFun = new SonToggleButtonComponent('itemSort_countInputFun', '计数输入', sonMain_itemSortSwitch.getChildSettingsContainer(), "将“输入内容”更新为当前计数,以方便排序", 1); itemSort_countInputFun.createNumberControDiv(10, false, 'countInput'); itemSort_countInputFun.createDivButton('开始', '退出', (isActivated) => { if (isActivated) { itemSort_countInputFun.showNumberControlDiv(true); // 显示数字控制区 itemSort_countInputFun.setCount(1); itemSort_countInputFun.countSort_reShowNotification();// 计数通知显示恢复 itemSort_inputConter.showSwitchDiv(false); // 隐藏输入内容选择框 temp_itemId = ''; itemSort_countInputFun_rateInput.showSwitchDiv(false); // 隐藏十倍计数输入框 } else { itemSort_countInputFun.showNumberControlDiv(false); // 隐藏数字控制区 itemSort_inputConter.showSwitchDiv(true); // 显示输入内容选择框 itemSort_countInputFun_rateInput.showSwitchDiv(true); // 显示十倍计数输入框 } } ); itemSort_countInputFun.showNumberControlDiv(false); const itemSort_countInputFun_rateInput = new SonToggleButtonComponent('itemSort_countInputFun_rateInput', '十倍计数输入', sonMain_itemSortSwitch.getChildSettingsContainer(), "计数输入内容为计数的十倍", 1); const itemSort_anchorSort = new SonToggleButtonComponent('itemSort_anchorSort', '主播排序', sonMain_itemSortSwitch.getChildSettingsContainer(), "根据输入内容,按照当前商品顺序,进行主播排序", 1); itemSort_anchorSort.createDivButton('开始', '退出', (isActivated) => { if (isActivated) { if (itemSort_countInputFun.getDivButtonState()) { const button = document.getElementById('itemSort_countInputFun_divButton'); button.click(); itemSort_countInputFun.showNumberControlDiv(false); // 隐藏数字控制区 itemSort_inputConter.showSwitchDiv(true); // 显示输入内容选择框 } processItems(); } else { // 检查是否已有弹窗存在,如果有则移除 const existingModal = document.querySelector('.dropdown-modal'); if (existingModal) { existingModal.style.display = 'none'; dropdownButton.style.display = ''; // 恢复按钮 } } } ); // const itemSort_autoSort = new SonToggleButtonComponent('itemSort_autoSort', '自动排序', sonMain_itemSortSwitch.getChildSettingsContainer(), "根据输入内容,对当前商品自动进行排序", 1); // itemSort_autoSort.createDivButton('开始', '退出', // async (isActivated) => { // if (isActivated) { // // 测试函数 // let AutoSortItemText = await createDropdownModal(dropdownContainer, '自动排序'); // const autoSort = new AutoSortItem(AutoSortItemText); // showNotification('开始排序'); // autoSort.startSort(); // } // else { // // 检查是否已有弹窗存在,如果有则移除 // const existingModal = document.querySelector('.dropdown-modal'); // if (existingModal) { // existingModal.style.display = 'none'; // dropdownButton.style.display = ''; // 恢复按钮 // } // } // } // ); // 着色与计算器子功能区域 const main_drawColorAndCalculator = drawColorAndCalculatorContainer.getSecondaryContent(); const sonMain_drawColor = new SonToggleButtonComponent('main_drawColor', '着色器', main_drawColorAndCalculator, "点击着色按钮后对当前手卡进行着色\n\n注意:着色器功能目前处于测试阶段,可能存在一些问题", 1); // 智能替换 const sonMain_smartReplace = new SonToggleButtonComponent('main_smartReplace', '智能替换', sonMain_drawColor.getChildSettingsContainer(), "1.智能识别手卡中的文字并替换为对应格式\n2.替换违禁词汇\n\n例如:将“99/2箱*6瓶”转写为“平均到手”的形式;\n将“49/2小箱/6瓶”转写为“平均到手”的形式\n例如:将“100%棉”替换为“99.99%棉”", 1); // 补贴生成 const sonMain_subsidyText = new SonToggleButtonComponent('main_subsidyText', '补贴生成', sonMain_drawColor.getChildSettingsContainer(), "点击补贴生成按钮后生成当前手卡的补贴文字", 1); // 计算器开关 const sonMain_calculator = new SonToggleButtonComponent('main_calculator', '计算器', sonMain_drawColor.getChildSettingsContainer(), "点击着色按钮后对当前手卡的算式进行计算\n\n注意:计算器功能目前处于测试阶段,可能存在一些问题;\n\n例如:无法计算形如“(3+9)/2”的算式;如果你想正确计算形如这样的算式,请将算式调整为“(3+9)/(2)”", 1); // 画中画子功能区域 const main_pictureInPictureSwitch = pictureInPictureSwitchContainer.getSecondaryContent(); const sonMain_pictureInPictureSwitch = new SonToggleButtonComponent('main_pictureInPictureSwitch', '小窗模式', main_pictureInPictureSwitch, "开启后,支持小窗模式的内容将会以小窗的形式呈现", 1); const sonMain_PIP_defautPosition = new SonToggleButtonComponent('main_PIP_defautPosition', '默认位置', sonMain_pictureInPictureSwitch.getChildSettingsContainer(), "设置小窗的默认位置", 1); const sonMain_PIP_defautPosition_select = ['左侧', '右侧']; sonMain_PIP_defautPosition.createSelectBox(sonMain_PIP_defautPosition_select); const sonMain_PIP_autoAdjust = new SonToggleButtonComponent('main_PIP_autoAdjust', '手卡位置自适应', sonMain_pictureInPictureSwitch.getChildSettingsContainer(), "开启后,在小窗模式下会自动调整手卡位置", 1, true); // 辅助功能子功能区域 const AuxiliaryFunctions_container = AuxiliaryFunctionsContainer.getSecondaryContent(); const sAF_backToLastCurrentURL = new SonToggleButtonComponent('sAF_backToLastCurrentURL', '最近浏览', AuxiliaryFunctions_container, "会主动提示上次浏览的场次页面,点击弹出的通知会跳转到上次浏览的场次页面", 1, true); const sAF_closeBrowserUpdateDiv = new SonToggleButtonComponent('sAF_closeBrowserUpdateDiv', '关闭浏览器更新提示', AuxiliaryFunctions_container, "关闭浏览器更新提示,防止影响使用\n(已累计关闭" + getCloseCount() + "次)", 1, true); const sAF_pastedSeachSwitchConta = new SonToggleButtonComponent('sAF_pastedSeachSwitchConta', '快捷粘贴搜索', AuxiliaryFunctions_container, "进行粘贴操作后,自动点击搜索按钮", 1, false); const sAF_AdvanceTableCardTitle = new SonToggleButtonComponent('sAF_AdvanceTableCardTitle', '手卡标题优化', AuxiliaryFunctions_container, "优化手卡标题,使其更易于识别", 1, true); const sAF_AdvanceTableCardPage = new SonToggleButtonComponent('sAF_AdvanceTableCardPage', '手卡页面优化', AuxiliaryFunctions_container, "优化手卡页面,隐藏顶栏与禁用词窗口", 1, true); const sAF_AdvanceBatchPrint = new SonToggleButtonComponent('sAF_AdvanceBatchPrint', '手卡打印功能优化', AuxiliaryFunctions_container, "优化打印页面默认文件名,允许仅打印手卡的部分区域并添加“上播ID核对”区域,\n添加“编辑手卡”按钮", 1, true); const sAF_AdvanceBatchPrint_alwaysDisplay = new SonToggleButtonComponent('sAF_AdvanceBatchPrint_alwaysDisplay', '总是显示ID核对行', sAF_AdvanceBatchPrint.getChildSettingsContainer(), "总是显示ID核对行,不论是否仅打印手卡的部分区域", 1, true); const sAF_FristPhotoCopyForTmallAndTaobao = new SonToggleButtonComponent('sAF_FristPhotoCopyForTmallAndTaobao', '天猫&淘宝主图复制', AuxiliaryFunctions_container, "在天猫或淘宝的主图上点击“复制图片”按钮,以快速将图片拷贝到剪切板\n\n注意:此功能会需要多个网页的剪切板访问权限", 1, true); // 单击和双击事件的延迟和计数器 var delay = 200; // 延迟时间,单位毫秒 var timer = null; // 监听鼠标左键点击事件 document.addEventListener('click', function (event) { // 检查是否开启了点击复制功能且在匹配的网址上 if (copySwitchContainer.getSwitchState() && isHomeURL()) { clearTimeout(timer); timer = setTimeout(function () { handleMouseClick(event, event.detail === 2); }, delay); } }); let clipboardHistory = ''; // 点击复制历史记录 // 鼠标点击响应事件 function handleMouseClick(event, isDoubleClick = false) { if (event.target && event.target.classList.contains('link-overflow-tip') && event.target.closest('#MarkHighlight-shopDetail-outShopName')) { var text = event.target.textContent; // 根据是否处于双击模式及点击类型,决定复制的文本内容 if (toggleDoubleClickMode()) { if (isDoubleClick) { if (toggleSmartCopyLength()) { copiedText = processText(text); } else { copiedText = text.substring(0, 3); } } else { copiedText = text.substring(); } } else { if (isDoubleClick) { copiedText = text.substring(); } else { if (toggleSmartCopyLength()) { copiedText = processText(text); } else { copiedText = text.substring(0, 3); } } } clipboardHistory = text; GM_setClipboard(copiedText); showNotification("复制成功:" + copiedText); itemSort_countInputFun.countSort_reShowNotification(); // 计数通知显示恢复 } } // 返回单击和双击模式的切换函数 function toggleDoubleClickMode() { const isDoubleClickMode = copySwitch_onlyPart.getSelectBoxValue(); switch (isDoubleClickMode) { case '单击': return false; case '双击': return true; default: return false; } } // 返回复制长度的切换函数 function toggleSmartCopyLength() { const smartCopyLength = copySwitch_smartCpoy.getSelectBoxValue(); switch (smartCopyLength) { case '默认': return false; case '智能': return true; default: return false; } } // 生成过滤词汇的正则表达式 var chineseFilterWords = ["旗舰店", "旗舰", "商品", "海外", "官方", "食品", "化妆品", "生活馆", "专营店", "国旅", "数码", "医药", "专卖店", "饮品", "女装", "男装", "企业店", "童装", "中国", "集团"]; var chineseFilterRegex = new RegExp(chineseFilterWords.join('|'), 'g'); // 合并成一个正则表达式 // 检查文本开头并根据要求处理 function processText(text) { var englishPattern = /^[A-Za-z\s.,!?;:'"-]+/; // 匹配以英文开头的部分,包含常见符号 // 检查是否以英文开头 var match = text.match(englishPattern); if (match) { // 如果以英文开头,返回匹配的英文部分 return match[0]; } else { // 如果以中文开头,使用正则表达式过滤指定词汇 return text.replace(chineseFilterRegex, ''); } } // 添加鼠标悬浮和移出事件监听器 NotificationContainer.addEventListener('mouseenter', function () { clearTimeout(notificationTimer); // 悬浮时清除计时器 // console.log('Mouse entered notification'); // 调试日志 }); NotificationContainer.addEventListener('mouseleave', function () { // console.log('Mouse left notification'); // 调试日志 var time = 3000; if (itemSort_countInputFun.getDivButtonState()) time = 0; resetTimer(time); // 移出时重置计时器 }); function showNotification(message, duringTime = 3000, showImage = false) { // 清除之前的计时器 if (notificationTimer) { clearTimeout(notificationTimer); } // 重置隐藏标志 isHiding = false; // 重置通知样式 NotificationContainer.innerHTML = ''; NotificationContainer.style.width = 'auto'; NotificationContainer.style.transform = 'translateX(-50%)'; NotificationContainer.style.animation = 'none'; NotificationContainer.style.padding = '10px'; // 短暂移除并重新添加通知元素,强制触发动画 if (NotificationContainer.parentNode) { document.body.removeChild(NotificationContainer); } setTimeout(() => { document.body.appendChild(NotificationContainer); // 设置通知文本内容 NotificationContainer.innerHTML = message; // 如果指定了显示图片,则读取剪贴板中的图片并显示 if (showImage) { NotificationContainer.style.padding = '5px'; navigator.clipboard.read().then(async function (data) { for (const item of data) { for (const type of item.types) { if (type.startsWith('image/')) { const blob = await item.getType(type); const imageURL = URL.createObjectURL(blob); const imageElement = document.createElement('img'); imageElement.src = imageURL; imageElement.style.width = '300px'; imageElement.style.borderRadius = '8px'; const imageContainer = document.createElement('div'); imageContainer.style.paddingTop = '10px'; imageElement.style.maxWidth = 'auto'; imageContainer.style.borderRadius = '8px'; imageContainer.style.margin = 'auto'; imageContainer.style.display = 'block'; imageContainer.appendChild(imageElement); NotificationContainer.appendChild(imageContainer); // 图片加载完成后调整位置并设置消失定时器 imageElement.onload = function () { NotificationContainer.style.left = '50%'; NotificationContainer.style.display = 'block'; NotificationContainer.style.animation = 'showNotification 0.5s forwards'; // 设置消失动画计时器 resetTimer(duringTime); }; break; } } } }).catch(function (error) { console.error('Error reading clipboard:', error); }); } else { // 显示通知 NotificationContainer.style.display = 'block'; NotificationContainer.style.animation = 'showNotification 0.5s forwards'; // 设置消失动画计时器 resetTimer(duringTime); } }, 50); // 确保通知元素短暂移除再添加 } function hideNotification() { if (isHiding) return; isHiding = true; NotificationContainer.style.animation = 'hideNotification 0.5s forwards'; // 在动画结束后隐藏元素 notificationTimer = setTimeout(function () { NotificationContainer.style.display = 'none'; isHiding = false; }, 500); } function resetTimer(duringTime = 3000) { if (notificationTimer) { clearTimeout(notificationTimer); // console.log("清除计时器"); } if (duringTime > 0) { notificationTimer = setTimeout(function () { hideNotification(); // console.log("设置计时器"); }, duringTime); // 3秒后自动隐藏通知 } } async function clickButton(pastedData = true, delayTime = 0, containerSelector = document, buttonSelector, buttonText = '') { // 判断粘贴内容是否为空或为 true if (pastedData === true || (typeof pastedData === 'string' && pastedData.trim().length > 0)) { // 查找指定容器内的按钮 var container = containerSelector === document ? document : document.querySelector(containerSelector); if (container) { // 如果提供了 buttonText,则进一步检查按钮文本内容 var buttons = container.querySelectorAll(buttonSelector); var button = null; if (buttonText) { buttons.forEach(btn => { var span = btn.querySelector('span'); if (span && span.textContent.trim() === buttonText) { button = btn; } }); } else { button = buttons[0]; // 如果没有提供 buttonText,默认选择第一个匹配的按钮 } // 如果找到符合条件的按钮,延迟点击 if (button) { setTimeout(function () { button.click(); // console.log(`已点击文本内容为“${buttonText || '按钮'}”的按钮`); }, delayTime); } else { console.log(`未找到符合条件的按钮`); } } } } // 监听粘贴事件 document.addEventListener('paste', function (event) { // 判断是否开启了自动点击功能且在匹配的网址上 if (sAF_pastedSeachSwitchConta.getSwitchState() && isHomeURL()) { // 获取粘贴板中的内容 var pastedData = (event.clipboardData); var className = '.ant-btn.css-9fw9up.ant-btn-primary'; clickButton(pastedData, 100, undefined, className); } }); // 检查文本中是否是天猫链接函数 function checkForTmallInClipboard(text) { const regex = /https:\/\/[^ ]*tmall[^ ]*id=\d{12}/; return regex.test(text); } function checkForChaoshiInClipboard(text) { const regex = /https:\/\/[^ ]*chaoshi[^ ]*id=\d{12}/; return regex.test(text); } function checkForFeizhuInClipboard(text) { const regex = /https:\/\/[^ ]*fliggy[^ ]*id=\d{12}/; return regex.test(text); } // 转换为移动设备链接(测试) function changeLinkToMobilePhone(link) { const idMatch = extractIdFromClipboard(link); return "https://detail.m.tmall.com/item.htm?id=" + idMatch; } // 提取链接id函数 function extractIdFromClipboard(text) { // 检查是否只含有11-12位数字 // const onlyDigitsMatch = text.match(/^\d{11,12}$/); const onlyDigitsMatch = text.match(/^\d{11,12}$/); if (onlyDigitsMatch) { return text; // 如果剪切板仅包含11位或12位数字,直接返回 } // 匹配 id= 后面的11或12位数字 // const idMatch = text.match(/id=(\d{11,12})/); const idMatch = text.match(/id=(\d{11,12})/); return idMatch ? idMatch[1] : null; } // 粘贴功能 async function simulatePaste(targetElement, clearBeforePaste = true, defaultText = '') { try { let clipboardText = defaultText; if (clipboardText === '') { // 读取剪贴板内容或预设内容 clipboardText = await navigator.clipboard.readText(); } console.log('粘贴内容:' + clipboardText); // 检查目标元素是否为可编辑元素 if (targetElement.isContentEditable || targetElement.tagName === 'INPUT' || targetElement.tagName === 'TEXTAREA') { // 如果clearBeforePaste为true,清空目标元素的内容 if (clearBeforePaste) { if (targetElement.isContentEditable) { targetElement.innerHTML = ''; } else { targetElement.value = ''; } } // 插入剪贴板内容到目标元素 if (document.execCommand('insertText', false, clipboardText)) { // console.log('粘贴成功:' + clipboardText); } else { targetElement.value += clipboardText; } } else { // alert('目标元素不可编辑'); } } catch (err) { console.error('读取剪贴板内容失败:', err); showNotification("读取剪贴板内容失败"); } } function updateClipboardContent(olnyItemId = false) { var tmail = "https://detail.tmall.com/item.htm?id="; var chaoshi = "https://chaoshi.detail.tmall.com/item.htm?id="; var taobao = "https://item.taobao.com/item.htm?id="; var feizhu = "https://traveldetail.fliggy.com/item.htm?id="; navigator.clipboard.readText().then((clipText) => { const isTmall = checkForTmallInClipboard(clipText); const isChaoshi = checkForChaoshiInClipboard(clipText); const isFeizhu = checkForFeizhuInClipboard(clipText); const itemId = extractIdFromClipboard(clipText); // console.log("itemId:" + itemId); // console.log("itemId-length:" + itemId.length); if (itemId) { var newUrl; if ((isTmall || isFeizhu) && !isChaoshi) { // 转换为天猫链接 newUrl = tmail + itemId; } else if (isChaoshi) { // 转换为猫超链接 newUrl = chaoshi + itemId; } else { if (true) { // 转换为淘宝链接 newUrl = taobao + itemId; } else { // 转换为天猫链接 newUrl = tmail + itemId; } } if (olnyItemId) { GM_setClipboard(itemId); if (!getLinksArrState) { showNotification("剪贴板内容已更新为:" + itemId); } } else { GM_setClipboard(newUrl); if (!getLinksArrState) { showNotification("剪贴板内容已更新为:" + newUrl); } //console.log('剪贴板内容已更新为:' + newUrl); } } else { if (mainOnlyItemId_checkTtemLink.getSwitchState()) { // 防止错误粘贴功能 GM_setClipboard("12位数字ID不全"); } if (!getLinksArrState) { showNotification("剪贴板中没有找到12位数字ID"); } // console.log('剪贴板中没有找到12位数字ID'); } }).catch((err) => { console.error('读取剪贴板失败:', err); }); } // 查找位于数组中的位置 function findItemIdForArr(itemId) { // 使用 indexOf 查找 itemId 在 upLiveIdArray 中的位置 let index = upLiveIdArray.indexOf(itemId); // 如果 index 是 -1,表示未找到,否则返回 index // console.log('index:' + index); return index; } // 返回当前页面的id function getPageItemId() { const pageIds = document.getElementById('MarkHighlight-upLiveId-upLiveId'); let itemIds = []; for (let i = 0; i < pageIds.length; i++) { itemIds.push(pageIds[i].innerText); } return itemIds; } function search_clickDownLabel(callback, delayTime = 600) { setTimeout(async () => { // 寻找 .text-search-components 容器 const container = document.querySelector('.text-search-components'); // 检查是否找到了容器 if (container) { // 在容器内寻找含有 aria-label="down" 的 span 标签 const downSpan = container.querySelector('span[aria-label="down"]'); // 检查是否找到了该 span if (downSpan) { // 获取其父 span const parentSpan = downSpan.closest('span'); // 检查父 span 是否在容器内(可选) if (parentSpan && container.contains(parentSpan)) { await waitForButtonToEnable(); // 等待按钮启用 // 点击父 span parentSpan.click(); // 调用回调函数 if (typeof callback === 'function') { callback(); } } else { console.warn('未找到在 .text-search-components 内的含有 aria-label="down" 的 span 标签的父 span'); } } else { console.warn('未在 .text-search-components 内找到含有 aria-label="down" 的 span 标签'); } } else { console.warn('未找到 .text-search-components 容器'); } }, delayTime); } function isDisableButton() { const buttons = document.querySelectorAll('.text-search-components-btn'); let downButton; for (let i = 0; i < buttons.length; i++) { if (buttons[i].querySelector('span[aria-label="down"]')) { downButton = buttons[i]; break; // 找到后就可以退出循环了 } } // 检查 downButton 是否存在,并且是否被禁用 if (downButton) { return downButton.disabled; } else { // 如果没有找到 downButton,则返回 false 或者根据你的需求返回其他值 return false; } } async function waitForButtonToEnable(maxWaitTime = 60000, delayTime = 500) { return new Promise((resolve, reject) => { const startTime = Date.now(); const interval = setInterval(() => { if (!isDisableButton()) { clearInterval(interval); setTimeout(() => { resolve(); }, delayTime); } const elapsedTime = Date.now() - startTime; if (elapsedTime >= maxWaitTime) { clearInterval(interval); reject(new Error('Button enabling timed out after 60 seconds')); } }, 100); // 每500毫秒检查一次 }); } function click_autoInputForIndex(rowIndex) { // 找到带有指定 row-index 的 div const targetDiv = document.querySelector(`div[row-index="${rowIndex}"]`); // 在 targetDiv 内查找 col-id="weight" 的元素 if (targetDiv) { const weightElement = targetDiv.querySelector('div[col-id="weight"]'); if (weightElement) { const focusElement = weightElement.querySelector('.sortWeights___Kn8mn'); if (focusElement) { focusElement.click(); // 点击来激活输入框 setTimeout(() => { focusElement.click(); // 再次点击来取消输入框 if (linksArr.length === 0 && !AutoSortState) { showNotification("成功找到商品&保存成功"); } }, 100); } } } } function checkActiveTab_GuaLian() { // 查询包含 data-node-key="2" 的 div 元素 const divElement = document.querySelector('div[data-node-key="2"]'); // 如果找到了该元素 if (divElement) { // 检查该元素的 classList 是否包含 ant-tabs-tab-active const isActive = divElement.classList.contains('ant-tabs-tab-active'); // console.log('Is the tab active:', isActive); return isActive; } else { // 如果没有找到,输出信息或处理错误 // console.log('No div element with data-node-key="2" found.'); return false; } } // 检查当前页面是否在紧急加品页面 function checkActiveTab_JiaPin() { // 查询包含 data-node-key="4" 的 div 元素 const divElement = document.querySelector('div[data-node-key="4"]'); // 如果找到了该元素 if (divElement) { // 检查该元素的 classList 是否包含 ant-tabs-tab-active const isActive = divElement.classList.contains('ant-tabs-tab-active'); // console.log('Is the tab active:', isActive); return isActive; } else { // 如果没有找到,输出信息或处理错误 // console.log('No div element with data-node-key="2" found.'); return false; } } // 检查当前页面是否在待确认订单页面 function checkActiveTab_WaitComfirm() { // 查询包含 data-node-key="5" 的 div 元素 const divElement = document.querySelector('div[data-node-key="5"]'); // 如果找到了该元素 if (divElement) { // 检查该元素的 classList 是否包含 ant-tabs-tab-active const isActive = divElement.classList.contains('ant-tabs-tab-active'); // console.log('Is the tab active:', isActive); return isActive; } else { // 如果没有找到,输出信息或处理错误 // console.log('No div element with data-node-key="2" found.'); return false; } } let linksArr = []; // 全局数组,用于存储从剪切板中提取的链接 function getLinksArrState() { return linksArr.length > 0; } // 从剪切板中提取所有链接并存储到全局数组中 async function extractLinksFromClipboard() { try { // 读取剪贴板内容 const text = await navigator.clipboard.readText(); linksArr = []; // 清空原有的数组 // 正则表达式匹配URL const urlPattern = /https?:\/\/[^\s]+/g; let matches = text.match(urlPattern); if (matches) { // 将找到的链接添加到全局数组中 linksArr.push(...matches); // console.log('Links extracted and stored:', linksArr); } else { // console.log('No links found in the clipboard.'); } } catch (err) { // console.error('Failed to read clipboard contents: ', err); } } // 等待页面加载结束,最长等待时间为60秒 async function waitForPageToLoad(maxWaitTime = 60000, delayTime = 500) { return new Promise((resolve, reject) => { const startTime = Date.now(); const interval = setInterval(() => { if (!isItemPageLoading()) { clearInterval(interval); setTimeout(() => { resolve(); }, delayTime); } const elapsedTime = Date.now() - startTime; if (elapsedTime >= maxWaitTime) { clearInterval(interval); reject(new Error('Page loading timed out after 60 seconds')); } }, 500); // 每500毫秒检查一次 }); } const MAX_RETRY_TIME = 5; // 最大重试次数 let retryCount = 0; // 重试次数 // 遍历 linksArr 并处理每个链接 async function processAllLinks() { await extractLinksFromClipboard(); // 从剪切板中提取链接 // console.log('linksArr:', linksArr); for (let i = 0; i < linksArr.length; i++) { let link = linksArr[i]; // 显示当前处理的链接 showNotification(`正在处理第 ${i + 1}/ ${linksArr.length} 个`, 0); // 模拟将链接放入剪切板 await navigator.clipboard.writeText(link); // console.log('Link copied to clipboard:', link); // 点击搜索按钮 await simulateClickOnAntInputAffixWrapper(); // 可能需要等待一段时间,以便于上一个操作完成 await new Promise(resolve => setTimeout(resolve, 2500)); // 根据实际情况调整等待时间 // 等待页面加载完成 try { await waitForPageToLoad(); // console.log('Page loaded successfully'); } catch (error) { // console.error('Page loading timed out:', error); showNotification('页面加载超时'); } } retryCount = 0; // 重置重试次数 await checkSelfLink(); } async function checkSelfLink() { return new Promise(async (resolve, reject) => { if (retryCount > 1) { let className = '.ant-btn.css-9fw9up.ant-btn-primary'; clickButton(true, 100, undefined, className); await new Promise(resolve => setTimeout(resolve, 3500)); // 根据实际情况调整等待时间 } // 将连接转储为id let idArr = linksArr.map(link => extractIdFromClipboard(link)); // console.log('idArr:', idArr); let weight = preGetValue(); let retryLinkArr = []; for (let i = 0; i < idArr.length; i++) { let idWeight = goodsUrlCheckArray[idArr[i]].weight; if (idWeight != weight) { retryLinkArr.push(linksArr[i]); } } if (retryLinkArr.length > 0) { retryCount++; if (retryCount > MAX_RETRY_TIME) { showNotification('重试次数已达最大'); reject(new Error('重试次数已达最大')); return; } } else { showNotification('全部处理完成'); linksArr = []; // 清空数组 resolve(); return; } showNotification('执行自检流程···', 0); // console.log('retryLinkArr:', retryLinkArr); for (let i = 0; i < retryLinkArr.length; i++) { let link = retryLinkArr[i]; // 显示当前处理的链接 showNotification(`[重试 ${retryCount} ] 正在处理第 ${i + 1}/ ${retryLinkArr.length} 个`, 0); // 模拟将链接放入剪切板 await navigator.clipboard.writeText(link); // console.log('Link copied to clipboard:', link); // 点击搜索按钮 await simulateClickOnAntInputAffixWrapper(); // 可能需要等待一段时间,以便于上一个操作完成 await new Promise(resolve => setTimeout(resolve, 2000)); // 根据实际情况调整等待时间 // 等待页面加载完成 try { await waitForPageToLoad(); // console.log('Page loaded successfully'); } catch (error) { // console.error('Page loading timed out:', error); showNotification('页面加载超时'); } } checkSelfLink(); }); } function addButtonForHomePage_processAllLinks() { var buttonName = '批量处理'; var buttonId = 'processAllLinksButton'; const smartCopyButton = createDefaultButton(buttonId, buttonName, () => { processAllLinks(); }); // 找到搜索栏目 const searchToolBar = document.querySelector('.ant-pro-table-list-toolbar-left'); const scButton = document.getElementById(buttonId); if (searchToolBar) { if (!scButton) { searchToolBar.appendChild(smartCopyButton); } else { if ((onlyItemIdForSearchDiv_onlyNoIntroduce.getSwitchState() ? checkActiveTab_GuaLian() : true) && sonMain_autoFlagedSwitch.getSwitchState()) { scButton.style.display = ''; } else { scButton.style.display = 'none'; } } } } // 模拟点击 .ant-input-affix-wrapper 元素 function simulateClickOnAntInputAffixWrapper() { return new Promise((resolve, reject) => { const element = document.querySelector('.text-search-components .ant-input-affix-wrapper.css-9fw9up'); if (element) { // // 创建点击事件 // const clickEvent = new MouseEvent('click', { // bubbles: true, // cancelable: true, // view: window // }); // // 触发点击事件 // element.dispatchEvent(clickEvent); element.click(); console.log('Simulated click on ant-input-affix-wrapper:', element); resolve(); } else { console.error('Element not found'); reject(new Error('Element not found')); } }); } // 提取链接id粘贴功能实现 function handle_onlyItemIdForSearch(event) { if (event.target.closest('.text-search-components .ant-input-affix-wrapper.css-9fw9up') && !event.target.closest('.ant-input-suffix')) { console.log('点击了 ant-input-affix-wrapper'); updateClipboardContent(true); processItemIdForSearch(document.activeElement); } } // 处理单个链接 function processItemIdForSearch(targetElement) { simulatePaste(targetElement); navigator.clipboard.readText().then((itemId) => { console.log('itemID:' + itemId); const index = findItemIdForArr(itemId); if (index !== -1) { // itemPageScroll(120 * index, false); search_clickDownLabel(() => { if (onlyItemIdForSearchDiv_autoInputSort.getSwitchState()) { click_autoInputForIndex(index); } }); } }).catch(err => { console.error('读取剪贴板内容失败:', err); showNotification("读取剪贴板内容失败"); }); } // 监听鼠标左键点击事件 document.addEventListener('click', function (event) { // 提取商品链接粘贴功能区域 if (sonMain_onlyItemIdSwitch.getSwitchState() && isHomeURL()) { if (event.target.closest('.ant-form-item.liveLinkFormItem___RPAQZ.css-9fw9up.ant-form-item-has-success')) { if (event.target.classList.contains('ant-input-affix-wrapper') || event.target.classList.contains('ant-input-affix-wrapper-status-error') || event.target.classList.contains('css-9fw9up')) { // console.log('目标元素被点击'); updateClipboardContent(); simulatePaste(document.activeElement); // 点击保存按钮 if (mainOnlyItemId_autoSave.getSwitchState()) { var fbutton = '.ant-drawer-footer'; var buttonName = '.ant-btn.css-9fw9up.ant-btn-primary'; showNotification("粘贴成功&保存成功"); clickButton(undefined, 500, fbutton, buttonName); } } } } // 提取链接id粘贴功能区域 // 用于控制功能开关 if (sonMain_onlyItemIdForSearchDiv.getSwitchState() && isHomeURL()) { if (onlyItemIdForSearchDiv_onlyNoIntroduce.getSwitchState()) { if (checkActiveTab_GuaLian()) { handle_onlyItemIdForSearch(event); } } else { handle_onlyItemIdForSearch(event); } } // 自动序号标1功能 if (sonMain_itemSortSwitch.getSwitchState()) { if (event.target.closest('.ant-input-number.ant-input-number-sm.css-1ayq15k')) { if (event.target.classList.contains('ant-input-number-input')) { // console.log('目标元素被点击'); if (!itemSort_countInputFun.getDivButtonState()) { GM_setClipboard(preGetValue()); } else { if (itemSort_countInputFun_rateInput.getSwitchState()) { GM_setClipboard((itemSort_countInputFun.getCount() - 1) * 10); } else { GM_setClipboard(itemSort_countInputFun.getCount() - 1); } } if (!AutoSortState) { simulatePaste(document.activeElement); } else { simulatePaste(document.activeElement, true, autoSortNum); } } } } // 自动激活排序输入框 if (sonMain_itemSortSwitch.getSwitchState()) { if (event.target.classList.contains('sortWeights___Kn8mn') || event.target.closest('.sortWeights___Kn8mn')) { // console.log('找到sortWeights___Kn8mn'); activateInputFieldAndSave(event); } } }); function preGetValue() { if (itemSort_inputConter.getSelectBoxValue() === '空') { return ''; } else { return itemSort_inputConter.getSelectBoxValue(); } } /* 快捷截图功能区 */ function getTableCardImageUrl() { // 查找 class 为 'link-node-img-container' 的 div const container = document.querySelector('.link-node-img-container'); // 检查是否找到了该元素 if (container) { // 查找 div 内的 img 元素 const imgElement = container.querySelector('img'); // 检查是否有 img 元素,并获取其 src 属性 if (imgElement) { const imgUrl = imgElement.src; // 获取 img 的 src URL console.log('Image URL:', imgUrl); // 输出到控制台 return imgUrl; } else { // console.log('No img element found inside the container'); return null; } } else { // console.log('No div with the class "link-node-img-container" found'); return null; } } function setTableCardImageUrl(imgUrl) { // 查找 class 为 'link-node-img-container' 的 div const container = document.querySelector('.link-node-img-container'); // 检查是否找到了该元素 if (container) { // 查找 div 内的 img 元素 const imgElement = container.querySelector('img'); // 检查是否有 img 元素,并获取其 src 属性 if (imgElement) { imgElement.src = imgUrl; // 更新 img 的 src URL console.log('Image URL已更新为:', imgUrl); // 输出到控制台 } else { // console.log('No img element found inside the container'); } } else { // console.log('No div with the class "link-node-img-container" found'); } } // 返回渲染倍数 function selectedTableCardPngResolution() { const resolution = tableCardPng_resolution.getSelectBoxValue(); // console.log("设定的分辨率:" + resolution); switch (resolution) { case '普通': return 1.5; case '高清': return 2.5; case '超清': return 4; default: return 2.5; } } function loadImageIcon() { return ''; } if (sonMain_tableCardPngSwitch.getSwitchState() && isTableCardURL()) { // Load html2canvas library function loadHtml2Canvas(callback) { var script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js'; script.onload = callback; document.head.appendChild(script); } function createCaptureScreenshotButton() { const targetClass = '[class*="ant-space"][class*="css-9fw9up"][class*="ant-space-horizontal"][class*="ant-space-align-center"]'; const captureScreenshot_observer = new MutationObserver((mutationsList, observer) => { for (let mutation of mutationsList) { if (mutation.type === 'childList') { const targetElement = document.querySelector(targetClass); if (targetElement) { if (document.querySelector('.captureScreenshot')) { captureScreenshot_observer.disconnect(); return; } var captureScreenshot = document.createElement('div'); captureScreenshot.classList.add('ant-space-item'); var captureScreenshotButton = document.createElement('button'); captureScreenshotButton.textContent = '快捷截图'; captureScreenshotButton.classList.add('ant-btn', 'css-9fw9up', 'ant-btn-default', 'captureScreenshot'); captureScreenshot.appendChild(captureScreenshotButton); targetElement.insertBefore(captureScreenshot, targetElement.firstChild); captureScreenshotButton.addEventListener('click', captureScreenshotFunction); captureScreenshot_observer.disconnect(); break; } } } }); captureScreenshot_observer.observe(document.body, { childList: true, subtree: true }); } function loadImageAsDataURL(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: url, responseType: 'blob', onload: function (response) { const blob = response.response; const reader = new FileReader(); reader.onloadend = function () { resolve(reader.result); }; reader.onerror = function () { reject(new Error('Failed to load image')); }; reader.readAsDataURL(blob); }, onerror: function () { reject(new Error('Network error')); } }); }); } async function captureScreenshotFunction() { const tableElement = document.querySelector('table'); var displayScale = selectedTableCardPngResolution(); // console.log("设定的倍率:" + displayScale); showNotification("截图中 " + loadImageIcon(), 0); if (tableElement) { const rows = tableElement.querySelectorAll('tr'); if (rows.length >= 3) { rows[2].cells[0].textContent = ''; // 隐藏除第二行和第三行外的所有行 rows.forEach((row, index) => { if (index !== 1 && index !== 2) { if (index === 3 && isShowTableCheckedRow()) { row.style.display = ''; } else { row.style.display = 'none'; } } }); const imgElement = rows[2].cells[2].querySelector('img'); if (imgElement) { try { const dataUrl = await loadImageAsDataURL(imgElement.src); imgElement.src = dataUrl; setTimeout(() => { // 使用 html2canvas 捕获截图 html2canvas(tableElement, { scale: displayScale }).then(canvas => { // 恢复所有行的显示状态 rows.forEach(row => { row.style.display = ''; }); // 隐藏检查格式行 if (true) { rows.forEach((row, index) => { if (index === 3) { row.style.display = isCheckItemIdRow_onlyPng(); } }); } canvas.toBlob(async function (blob) { try { await navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]); console.log("%cTable Screenshot:", "color: #9147ff", "Screenshot copied to clipboard."); showNotification("截图已成功复制到剪贴板", undefined, true); } catch (error) { console.log("%cTable Screenshot: Screenshot failed to copy to clipboard!", "color: #ff8080"); showNotification("截图失败!"); } }); }); }, 200); // 延迟 200 毫秒等待图片加载完毕 } catch (error) { console.log('Image load error:', error); } } else { console.log('Image element not found'); } } else { console.log("Table does not have enough rows"); } } else { console.log("Table element not found"); } } loadHtml2Canvas(createCaptureScreenshotButton); } /* ************************** 自动激活排序窗口、点击保存 ************************** */ function activateInputFieldAndSave(event) { if (true) { const click_itemId = handleCellClick(event); if (temp_itemId != click_itemId) { if (itemSort_countInputFun.getDivButtonState()) { itemSort_countInputFun.updateCount(1, 'countInput'); } temp_itemId = click_itemId; } // countText.textContent = countNum_Sort + 1; // console.log('计数:'+countNum_Sort); const popover = document.querySelector('.ant-popover:not(.ant-popover-hidden)'); const inputField = popover.querySelector('.ant-input-number-input'); if (inputField) { inputField.focus(); inputField.click(); } else { console.log('未找到输入字段'); } } } // 查找点击的id function handleCellClick(event) { // 查找最接近的包含行元素的类 let rowElement = event.target.closest('.ag-row'); if (rowElement) { // 获取row-index属性 let rowIndex = rowElement.getAttribute('row-index'); // console.log('找到的行索引:', rowIndex); // 使用row-index属性查找行内的span标签 let targetSpan = document.querySelector(`.ag-row[row-index="${rowIndex}"] span#MarkHighlight-upLiveId-upLiveId`); if (targetSpan) { return targetSpan.textContent; // 打印span的文本内容 // console.log('目标span的文本内容:', targetSpan.textContent); } else { // console.log(`在行索引为${rowIndex}的行中未找到id为"MarkHighlight-upLiveId-upLiveId"的span标签。`); } } else { // console.log('未找到点击单元格对应的行。'); } } /* ================= 打印标题优化 ================= */ function titlePrint_extractData() { const dateElement = document.querySelector('.isSelect___qbUI1 .ant-space.css-9fw9up.ant-space-horizontal.ant-space-align-center.title___mA8xY .ant-space-item:nth-child(2) div'); const sessionElement = document.querySelector('.truncate.sessionName___HUMKC.font-ma-semibold'); if (dateElement && sessionElement) { const dateText = dateElement.textContent.trim(); const sessionText = sessionElement.textContent.trim(); GM_setValue('titlePrint_extractedDate', dateText); GM_setValue('titlePrint_extractedSession', sessionText); // console.log('Date extracted and stored:', dateText); // console.log('Session name extracted and stored:', sessionText); } } /* ================= 手卡标题优化 ================= */ // 网址id提取 function url_getSessionGoodsId() { const url = window.location.href; const match = url.match(/sessionGoodsId=(\d+)/); return match ? match[1] : null; } function modifyTableCardURL_title(itemId) { // console.log('itemId:', itemId); if (sAF_AdvanceTableCardTitle.getSwitchState()) { if (itemId && isTableCardURL()) { document.title = '【手卡 ' + itemId[0].toString().slice(-4) + '】' + itemId[1]; } } } /* 手卡附带检查链接功能 */ function isShowTableCheckedRow() { return tableCardPng_checkItemIdRow.getSwitchState(); } function isCheckItemIdRow_onlyPng() { if (tableCardPng_checkItemIdRow_onlyPng.getSwitchState()) { return 'none'; } else { return ''; } } // 检查行生成函数 function createTableCheckedRow(itemId, width1 = 0, width2 = 0, item_link = '') { // 创建 元素 const tr = document.createElement('tr'); tr.id = 'checkedItemLink_TableCrad'; tr.style.cssText = 'min-height: 30px; max-height: 30px;'; tr.style.display = isCheckItemIdRow_onlyPng(); // 创建第一个 元素 const td1 = document.createElement('td'); td1.colSpan = '3'; td1.style.cssText = 'padding: 0px; height: 30px; align-items: center; justify-content: center; display: flex;'; if (width1 > 0) td1.style.width = width1 + 'px'; const marioSvg = createMarioSVGIconWrapper('svgCheckedRow', false, 16); const superItemLink = document.createElement('a'); superItemLink.href = item_link; superItemLink.target = '_blank'; // 创建第一个
元素 const div1 = document.createElement('div'); div1.style.cssText = 'display: flex; align-items: center; justify-content: center; height: 100%;'; // 创建第一个 元素 const span1 = document.createElement('span'); span1.style.cssText = 'color: rgb(236, 40, 39); font-size: 16px; text-align: center; margin-left: 1px;'; span1.textContent = '上播商品ID核对:'; // 创建第二个 元素,放置链接内容 const span2 = document.createElement('span'); span2.id = 'cureentItem_upLiveId'; span2.style.cssText = 'color: rgb(51, 51, 51); font-size: 16px; font-weight: bold; transition: color 0.3s ease;'; span2.textContent = itemId; // 设置悬浮时变颜色 span2.onmouseover = function () { if (span2.style.cursor === 'pointer') { span2.style.color = 'rgb(0, 145, 255)'; // 悬浮时的颜色 } }; // 悬浮离开时恢复原色 span2.onmouseout = function () { if (span2.style.cursor === 'pointer') { span2.style.color = 'rgb(51, 51, 51)'; // 恢复默认颜色 } }; if (item_link !== '') { span2.style.cursor = 'pointer'; if (sonMain_pictureInPictureSwitch.getSwitchState()) { // 新功能 // console.log('item_link:', changeLinkToMobilePhone(item_link)); const pipManager = new PIPManager(changeLinkToMobilePhone(item_link), span2, false); // const pipManager = new PIPManager(item_link, span2, true); } else { // 原有功能 span2.onclick = function () { window.open(item_link, '_blank'); // 跳转到商品链接 }; } } // 将 span2 放入 span1,然后放入 div1 span1.appendChild(span2); superItemLink.appendChild(marioSvg); div1.appendChild(superItemLink); div1.appendChild(span1); // 将 div1 放入 td1 td1.appendChild(div1); // 创建第二个 元素 const td2 = document.createElement('td'); td2.colSpan = '7'; td2.style.cssText = 'padding: 0px; align-items: center; justify-content: center; height: 30px;'; if (width2 > 0) td2.style.width = width2 + 'px'; // 创建第二个
元素 const div2 = document.createElement('div'); div2.style.cssText = 'display: flex; align-items: center; justify-content: center; height: 100%;'; // 创建第三个 元素 const span3 = document.createElement('span'); span3.style.cssText = 'color: rgb(51, 51, 51); font-size: 16px; text-align: center;white-space: pre-wrap;'; span3.textContent = '请回复有误、无误、正确之类的,不要收到、1之类的不明确信息,要让我们知道你核对完了'; // 使用 innerHTML 设置带有部分上色的内容 span3.innerHTML = `核对完所有栏目后,请回复有误、无误、正确之类的,不要收到、1之类的不明确信息,要让我们知道你核对完了`; // 将 span3 放入 div2,然后放入 td2 div2.appendChild(span3); td2.appendChild(div2); // 将两个 td 放入 tr tr.appendChild(td1); tr.appendChild(td2); // 返回生成的 元素 return tr; } // 用于更新插入的行中的 id function changeNewTrItemId(itemId, item_link = '') { const idSpan = document.getElementById('cureentItem_upLiveId'); if (idSpan) { idSpan.textContent = itemId; } const span2 = document.getElementById('cureentItem_upLiveId'); if (item_link !== '') { span2.style.cursor = 'pointer'; if (sonMain_pictureInPictureSwitch.getSwitchState()) { // 新功能 // console.log('item_link:', changeLinkToMobilePhone(item_link)); const pipManager = new PIPManager(changeLinkToMobilePhone(item_link), span2, false); // const pipManager = new PIPManager(item_link, span2, true); } else { // 原有功能 span2.onclick = function () { window.open(item_link, '_blank'); // 跳转到商品链接 }; } } } function insertCheckedRow(itemId, item_link = '') { if (!document.getElementById('checkedItemLink_TableCrad')) { const tableElement = document.querySelector('table'); if (tableElement) { const rows = tableElement.querySelectorAll('tr'); // 确保表格中至少有三个 元素 if (rows.length >= 3) { // 获取第三个 元素 const thirdRow = rows[2]; // 生成新的 元素 const newRow = createTableCheckedRow(itemId, 0, 0, item_link); // 在第三个 元素的后面插入新行 thirdRow.parentNode.insertBefore(newRow, thirdRow.nextSibling); } else { // console.log("表格中没有足够的行来插入新行。"); } } else { // console.log("没有找到表格"); } } else { changeNewTrItemId(upLiveIdArray[0], upLiveIdArray[2]); } } /* 用于打印页面的插入XHR数据获取 */ let upLiveIdArray = []; // 上播商品id let shopNameArray = []; // 店铺名称 let goodsUrlArray = []; // 商品链接 let sessionGoodsId = []; // 编辑页面id // 封装提取 upLiveId 的函数 // 打印页面数据获取 function extractUpLiveIdsFromResponse(responseText) { try { const response = JSON.parse(responseText); // 初始化 upLiveIdArray, shopNameArray ,goodsUrlArray 数组 upLiveIdArray = []; shopNameArray = []; goodsUrlArray = []; sessionGoodsId = []; if (response.data && Array.isArray(response.data)) { // 提取 upLiveId 并过滤掉 undefined upLiveIdArray = response.data.map(item => item.upLiveId).filter(id => id !== undefined); // 提取 sessionGoodsId 并过滤掉 undefined sessionGoodsId = response.data.map(item => item.sessionGoodsId).filter(id => id !== undefined); // 提取 shopName 并过滤掉 undefined shopNameArray = response.data.map(item => { if (item.cardUseDataStyle) { const cardUseDataStyle = JSON.parse(item.cardUseDataStyle); const shopData = cardUseDataStyle.find(subItem => subItem.useFieldName === 'shopName'); return shopData ? shopData.useFieldValue : undefined; } }).filter(shopName => shopName !== undefined); // 过滤掉 undefined 的 shopName 值 // 提取 goodsUrl 并过滤掉 undefined goodsUrlArray = response.data.map(item => item.goodsUrl).filter(goodsUrl => goodsUrl !== undefined); } else { // console.error("响应中未找到有效的 data 字段"); } // console.log("提取的 upLiveId:", upLiveIdArray); // console.log("提取的 shopName:", shopNameArray); // console.log("提取的 goodsUrl:", goodsUrlArray); // console.log("提取的 sessionGoodsId:", sessionGoodsId); } catch (error) { console.error("解析响应失败:", error); } } // 手卡页面数据获取 function extractUpLiveIdFromTableCardResponse(responseText) { try { const response = JSON.parse(responseText); // 初始化 upLiveIdArray 数组 upLiveIdArray = []; // 检查响应数据中的 data 字段 if (response.data && typeof response.data === 'object') { // 提取 data 对象中的 upLiveId const upLiveId = response.data.upLiveId; if (upLiveId !== undefined) { // 将 upLiveId 存储到数组中 upLiveIdArray[0] = upLiveId; } else { // console.error("响应的 data 对象中未找到 upLiveId 字段"); } // 解析 cardUseDataStyle 字符串为数组 if (response.data.cardUseDataStyle) { const cardUseDataStyle = JSON.parse(response.data.cardUseDataStyle); // 在 cardUseDataStyle 数组中查找 useFieldName 为 'shopName' 的对象 const shopData = cardUseDataStyle.find(item => item.useFieldName === 'shopName'); if (shopData && shopData.useFieldValue) { upLiveIdArray[1] = shopData.useFieldValue; // 存储 shopName 到数组的第 1 位置 } else { // console.error("未找到 useFieldName 为 'shopName' 的对象或 useFieldValue 为空"); } } else { // console.error("响应中未找到有效的 cardUseDataStyle 字符串"); } // 提取 data 对象中的 goodsUrl const goodsUrl = response.data.goodsUrl; if (goodsUrl !== undefined) { // 将 upLiveId 存储到数组中 upLiveIdArray[2] = goodsUrl; } // 更新手卡标题 modifyTableCardURL_title(upLiveIdArray); } else { // console.error("响应中未找到有效的 data 字段,或 data 不是对象"); } } catch (error) { // console.error("解析响应失败:", error); } } // 手卡页面切换数据获取 function extractUpLiveIdsFromNextTableCardResponse(responseText) { try { const response = JSON.parse(responseText); // 初始化 upLiveIdArray 数组 upLiveIdArray = []; // 检查响应数据中的 data 字段 if (response.data && typeof response.data === 'object') { // 提取 data 对象中的 upLiveId const upLiveId = response.data.linkHandCardDetailRespDTO.upLiveId; if (upLiveId !== undefined) { // 将 upLiveId 存储到数组中 upLiveIdArray[0] = upLiveId; } else { // console.error("响应的 data 对象中未找到 upLiveId 字段"); } // 解析 cardUseDataStyle 字符串为数组 if (response.data.linkHandCardDetailRespDTO.cardUseDataStyle) { const cardUseDataStyle = JSON.parse(response.data.linkHandCardDetailRespDTO.cardUseDataStyle); // 在 cardUseDataStyle 数组中查找 useFieldName 为 'shopName' 的对象 const shopData = cardUseDataStyle.find(item => item.useFieldName === 'shopName'); if (shopData && shopData.useFieldValue) { upLiveIdArray[1] = shopData.useFieldValue; // 存储 shopName 到数组的第 1 位置 } else { // console.error("未找到 useFieldName 为 'shopName' 的对象或 useFieldValue 为空"); } } else { // console.error("响应中未找到有效的 cardUseDataStyle 字符串"); } // 提取 data 对象中的 goodsUrl const goodsUrl = response.data.linkHandCardDetailRespDTO.goodsUrl; if (goodsUrl !== undefined) { // 将 upLiveId 存储到数组中 upLiveIdArray[2] = goodsUrl; } // 更新手卡标题 modifyTableCardURL_title(upLiveIdArray); } else { // console.error("响应中未找到有效的 data 字段,或 data 不是对象"); } } catch (error) { // console.error("解析响应失败:", error); } } let goodsUrlCheckArray = {}; // shopName, upLiveId, weight, liveLink, sessionGoodsName // 提取商品列表中的id function extractUpLiveIdsFromGoodsListResponse(responseText) { try { const response = JSON.parse(responseText); // 初始化 upLiveIdArray 数组 upLiveIdArray = []; if (response.data && Array.isArray(response.data)) { // 提取 upLiveId 并过滤掉 undefined upLiveIdArray = response.data .map(item => item.sessionGoods?.upLiveId) .filter(id => id !== undefined); // 初始化 goodsUrlCheckArray 字典 goodsUrlCheckArray = {}; // 填充 goodsUrlCheckArray response.data.forEach(item => { if (item.sessionGoods && item.sessionGoods.upLiveId !== undefined) { const upLiveId = item.sessionGoods.upLiveId; // const shopName = item.sessionGoods.shopName || '未知店铺'; const shopName = item.selectionGoods.shopDetailRespDTO.outShopName || '未知店铺'; const weight = item.sessionGoods.weight || 0; const liveLink = item.sessionGoods.liveLink || '#'; const sessionGoodsName = item.sessionGoods.sessionGoodsName || '未知商品'; // 将信息存储到 goodsUrlCheckArray 中 goodsUrlCheckArray[upLiveId] = { shopName: shopName, upLiveId: upLiveId, weight: weight, liveLink: liveLink, sessionGoodsName: sessionGoodsName }; } }); } else { console.error("响应中未找到有效的 data 字段"); } // console.log("提取的 upLiveId:", upLiveIdArray); // console.log("提取的 goodsUrlCheckArray:", goodsUrlCheckArray); } catch (error) { console.error("解析响应失败:", error); } } // 封装 XMLHttpRequest 的 open 方法重写 function overrideOpenMethod() { const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function (method, url) { this._method = method; this._url = url; originalOpen.apply(this, arguments); }; } // 封装 XMLHttpRequest 的 send 方法重写 function overrideSendMethod() { const originalSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function (data) { const originalOnReadyStateChange = this.onreadystatechange; this.onreadystatechange = function () { if (this.readyState === 4 && this.status === 200) { if (this._method === "POST" && /https:\/\/gw\.linkmcn\.com\/live\/live\/card\/batchDetail.*/.test(this._url)) { // console.log("匹配的POST请求URL:", this._url); // 调用封装的函数来提取 upLiveId extractUpLiveIdsFromResponse(this.responseText); // console.log("提取的 upLiveId:", upLiveIdArray); } if (this._method === "POST" && /https:\/\/gw\.linkmcn\.com\/live\/live\/card\/detail.*/.test(this._url)) { // console.log("匹配的POST请求URL:", this._url); // 调用封装的函数来提取 upLiveId extractUpLiveIdFromTableCardResponse(this.responseText); // console.log("提取手卡的 upLiveId:", upLiveIdArray); } if (this._method === "POST" && /https:\/\/gw\.linkmcn\.com\/live\/live\/card\/nextLiveHandCard.*/.test(this._url)) { // console.log("匹配的POST请求URL:", this._url); // 调用封装的函数来提取 upLiveId extractUpLiveIdsFromNextTableCardResponse(this.responseText); // console.log("提取手卡切换的 upLiveId:", upLiveIdArray); } // 挂链商品id获取 if (this._method === "POST" && /https:\/\/gw\.linkmcn\.com\/live\/live\/sessionGoods\/liveSessionGoodsList.*/.test(this._url)) { extractUpLiveIdsFromGoodsListResponse(this.responseText); } } if (originalOnReadyStateChange) { originalOnReadyStateChange.apply(this, arguments); } }; originalSend.apply(this, arguments); }; } // 判断是否是打印手卡页面,并重写 XMLHttpRequest 的方法 if (isBatchPrintURL() || isTableCardURL() || isHomeURL()) { overrideOpenMethod(); overrideSendMethod(); } /* 系统功能优化 */ // 创建一个MutationObserver实例 // 绑定点击事件的外部函数 function bindClickEventToNotification(url) { // console.log('绑定点击事件, 传入URL:' + url); const element = document.getElementById('showNotificationContainer'); element.style.cursor = 'pointer'; if (element) { // 定义点击事件处理函数 function handleClick() { isHiding = true; NotificationContainer.style.animation = 'notificationButtonAnimation 0.5s forwards'; window.location.href = url; setTimeout(function () { NotificationContainer.style.display = 'none'; isHiding = false; window.location.reload(); }, 500); // 移除点击事件 element.removeEventListener('click', handleClick); element.style.cursor = 'default'; } // 绑定点击事件 element.addEventListener('click', handleClick); setTimeout(function () { // 移除点击事件 element.removeEventListener('click', handleClick); element.style.cursor = 'default'; hideNotification(); }, 5000); } } // 设置打印手卡的部分区域 function setPrintTableCardArea(isActivated) { var isShow = isActivated ? 'flex' : 'none'; var isInsertedShow = isActivated ? 'none' : 'flex'; // 与 isShow 相反的显示结果 if (sAF_AdvanceBatchPrint_alwaysDisplay.getSwitchState()) isInsertedShow = 'flex'; // 强制显示上播ID核对行 // 获取所有的table元素 var tables = document.querySelectorAll('table'); tables.forEach(function (table, i) { // 获取每个table中的tbody var tbody = table.querySelector('tbody'); // 获取tbody中的所有tr行 var rows = tbody.querySelectorAll('tr'); // 遍历tr行并隐藏第三行之后的所有行 rows.forEach(function (row, index) { if (index >= 3) { // 从第四行开始(索引为3),设置display为none row.style.display = isShow; } }); // 检查是否已经插入过具有相同id的tr var existingRow = tbody.querySelector('#checkedItemLink_TableCrad'); if (existingRow) { existingRow.style.display = isInsertedShow; // 如果存在则更新显示状态 } else { console.warn("不存在“上播ID核对”行,请检查是否已插入过该行。"); } }); } function insertCheckedRow_forBatchPrint(isActivated) { var isInsertedShow = isActivated ? 'flex' : 'none'; // 获取所有的table元素 var tables = document.querySelectorAll('table'); tables.forEach(function (table, i) { // 获取每个table中的tbody var tbody = table.querySelector('tbody'); // 获取tbody中的所有tr行 var rows = tbody.querySelectorAll('tr'); // 检查是否已经插入过具有相同id的tr var existingRow = tbody.querySelector('#checkedItemLink_TableCrad'); if (!existingRow) { // 检查行 var newRow = createTableCheckedRow(upLiveIdArray[i], 276.8492, 878.8229, goodsUrlArray[i]); // 创建新行 rows[2].insertAdjacentElement('afterend', newRow); // 插入新行到第三个 元素之后 newRow.style.display = isInsertedShow; // 设置新行的显示状态 } // 插入打印用的edit按钮(默认隐藏) var existingEditButton = tbody.querySelector('#editButton_TableCrad_print'); if (!existingEditButton) { // 编辑按钮 var newEditButton = createEditButton(sessionGoodsId[i], 'print'); var targetDiv = rows[0].querySelector('#sessionName'); targetDiv.appendChild(newEditButton); } // 插入edit按钮 var existingEditButton = tbody.querySelector('#editButton_TableCrad_PIP'); if (!existingEditButton) { // 编辑按钮 var newEditButton = createEditButton(sessionGoodsId[i], 'PIP'); var targetDiv = rows[0].querySelector('#sessionName'); targetDiv.appendChild(newEditButton); } }); } // 手卡编辑页面链接 function getSessionGoodsIdUrl(id) { return 'https://m.linkmcn.com/\#/live/plan/tableCard/detail/' + id; } // 生成重定向链接 function createRedirectUrl(id) { return 'https://item.taobao.com/item.htm?id=682878335608&link_redirectId=' + id; } function isRedirectToTableCardURL() { // 获取当前页面的 URL const currentUrl = window.location.href; // 检查当前 URL 是否包含指定的前缀 if (isRedirectUrl()) { // 获取 "?" 后面的 id const id = currentUrl.split('link_redirectId=')[1]; // 如果 id 存在,构造新的 URL 并重定向 if (id) { const newUrl = getSessionGoodsIdUrl(id); // console.log("Redirecting to: " + newUrl); // 用于调试,查看重定向的 URL window.location.href = newUrl; // 重定向到新网址 } else { // console.error('No id found in the URL for redirection'); } } } function printingTableCard() { const loadingText = document.querySelector('.ant-spin-text'); if (loadingText) { // console.log('Loading text 出现在页面中'); displayEditButtonType(true); // 显示中控按钮 // displayEditButtonType(false); // 显示制表按钮 } else { // console.log('Loading text 不在页面中'); displayEditButtonType(false); } } function isPrintingTableCard() { const loadingText = document.querySelector('.ant-spin-text'); if (loadingText) { return true; } else { return false; } } function displayEditButtonType(onPrint) { // onPrint 为 true 时显示中控按钮,false 时显示制表按钮 var print_editButtons = document.querySelectorAll('#editButton_TableCrad_print'); var PIP_editButtons = document.querySelectorAll('#editButton_TableCrad_PIP'); if (onPrint && print_editButtons.length > 0 && PIP_editButtons.length > 0) { // 显示中控按钮,隐藏制表按钮 print_editButtons.forEach(function (button) { // button.style.display = 'block'; button.style.opacity = '1'; }); PIP_editButtons.forEach(function (button) { button.style.display = 'none'; }); } else { // 显示制表按钮,隐藏中控按钮 print_editButtons.forEach(function (button) { // button.style.display = 'none'; button.style.opacity = '0'; }); PIP_editButtons.forEach(function (button) { button.style.display = 'block'; }); } } function createEditButton(sessionGoodsId, idName) { const divWrapper = document.createElement('div'); divWrapper.style.cssText = 'align-items: center; cursor: pointer; margin: 0px 8px;'; // 样式控制'; // 直接在 SVG 中内嵌 onmouseover 和 onmouseout 事件 var editSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); editSvg.setAttribute('class', 'icon icon-edit'); editSvg.setAttribute('transition', 'fill 0.3s ease-in-out'); editSvg.setAttribute('viewBox', '0 0 1024 1024'); editSvg.setAttribute('width', '17'); editSvg.setAttribute('height', '17'); editSvg.innerHTML = ''; editSvg.style.cssText = 'vertical-align: middle;'; // 垂直居中样式 // 将 SVG 图标直接插入到链接元素中,确保其被 PDF 工具解析 divWrapper.appendChild(editSvg); editSvg.addEventListener('mouseover', function () { this.style.fill = "rgb(0, 145, 255)"; }); editSvg.addEventListener('mouseout', function () { this.style.fill = "rgb(51, 51, 51)"; }); // 创建一个 元素,直接包裹 SVG 图标,避免动态事件处理丢失 const editButton = document.createElement('a'); editButton.id = 'editButton_TableCrad_' + idName; if (idName === 'print') { editButton.style.display = 'block'; // 调整按键透明度 editButton.style.opacity = '0'; editButton.href = createRedirectUrl(sessionGoodsId); // 确保超链接指向正确的地址 editButton.target = '_blank'; // 打开新标签 } else { editButton.style.display = 'block'; if (sonMain_pictureInPictureSwitch.getSwitchState()) { const pipManager = new PIPManager(getSessionGoodsIdUrl(sessionGoodsId), editButton, true); } else { editButton.href = getSessionGoodsIdUrl(sessionGoodsId); editButton.target = '_blank'; // 打开新标签 } } editButton.appendChild(divWrapper); return editButton; // 返回带有超链接的按钮 } // 判断是否是剧透时间 function checkIfTrailer(storedDate) { const currentTime = new Date(); let isTrailer = ''; // 获取当前年份 const currentYear = currentTime.getFullYear(); // 将字符串日期转换为Date对象,加入当前年份 let adjustedDate = new Date(`${currentYear}-${storedDate}T18:00:00`); // 将日期往前调整一天 adjustedDate.setDate(adjustedDate.getDate() - 1); // 计算两个日期之间的差值(以天为单位) const timeDifference = Math.abs(currentTime - adjustedDate); const dayDifference = timeDifference / (1000 * 60 * 60 * 24); // 如果天数差值大于180天,考虑跨年情况,给adjustedDate加上1年 if (dayDifference > 180) { adjustedDate.setFullYear(adjustedDate.getFullYear() + 1); } const printCard_switch = document.getElementById('button_setPrintTableCardArea_switch'); const button_setPrintTableCardArea = document.getElementById('button_setPrintTableCardArea'); if (button_setPrintTableCardArea && printCard_switch.getAttribute('aria-checked') === 'true') { isTrailer = "核对"; } else { // 比较当前时间与截止时间 if (currentTime < adjustedDate) { isTrailer = "剧透"; } else { isTrailer = ''; } } return isTrailer; } // 判断手卡打印页面中的手卡店铺名是否都一致 function onlyOneShopName(shopNameArray) { // 过滤多余内容,生成过滤后的数组 const filteredShopNames = shopNameArray.map(shopName => processText(shopName)); // 判断所有过滤后的店名是否一致 const allEqual = filteredShopNames.every(shopName => shopName === filteredShopNames[0]); // 如果所有内容一致,返回第一个店名,否则返回 false return allEqual ? filteredShopNames[0] : false; } function hide_link_helpMenu(isActivated = true) { var isShow = isActivated ? 'none' : ''; // link帮助菜单 const link_helpMenu = document.querySelector('.link-customer-service-only-help'); if (link_helpMenu) link_helpMenu.style.display = isShow; } function hide_link_leftSiderMenu(isActivated = true) { var isShow = isActivated ? 'none' : ''; // 获取父容器 const parentElement = document.querySelector('.ant-layout.ant-layout-has-sider.css-9fw9up'); if (parentElement) { // 获取直接的子元素 const children = parentElement.children; // 返回一个HTMLCollection,包含所有直接子元素 if (children.length === 3) { // 优化批量打印页面的显示 children[0].style.display = isShow; // 隐藏右侧的操作栏 children[1].style.display = isShow; // 隐藏右侧的操作栏 } else { // console.log('页面元素数量不符合预期'); } } } function hide_link_firstTabContainer(isActivated = true) { var isShow = isActivated ? 'none' : ''; // 获取tab容器 const tabContainer = document.getElementById('firstTabContainer'); if (tabContainer) { tabContainer.style.display = isShow; createHeaderTabs(isActivated); // 重新创建顶部标签 } } // 获取 svg 元素的 xlink:href 属性值 function getUseHref(antSpaceItem) { // 查找 .ant-space-item 中的 元素 const useElement = antSpaceItem.querySelector('use'); // 检查是否找到了 元素 if (useElement) { // 获取 元素的 xlink:href 属性值 return useElement.getAttribute('xlink:href') || null; } else { // 如果没有找到 元素,返回 null return null; } } function hide_link_topBarMenu(isActivated = true) { var isShow = isActivated ? 'none' : ''; // 获取顶部header const topHeader = document.querySelector('.ant-space.css-14s8ncx'); const topHeader_item = topHeader.querySelectorAll('.ant-space-item'); if (topHeader) { // 插入自定义SVG图标 for (var i = 0; i < topHeader_item.length; i++) { if (getUseHref(topHeader_item[i]) === '#link-file-download-line') { const svg = document.getElementById('link-live-calendarDiv'); const svgDiv = create_topBarMenuDivWithSVG('link-live-calendar', '#link-live-calendar', live_calendar); if (!svg) { topHeader.insertBefore(svgDiv, topHeader_item[i + 1]); } svg.style.display = isActivated ? '' : 'none'; // 隐藏SVG图标 } } for (var i = 0; i < topHeader_item.length; i++) { if (getUseHref(topHeader_item[i]) !== '#link-file-download-line' && getUseHref(topHeader_item[i]) !== '#link-live-calendar') { topHeader_item[i].style.display = isShow; } } } else { // console.log('顶部header元素不存在'); } } const live_calendar = ` `; function create_topBarMenuDivWithSVG(id, useHref, svgContent) { // 内部函数:生成SVG元素 function getSVG(useHref, svgContent) { const parser = new DOMParser(); const svgDoc = parser.parseFromString(svgContent, 'image/svg+xml'); const svg = svgDoc.querySelector('svg'); const use = document.createElementNS('http://www.w3.org/2000/svg', 'use'); use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', useHref); svg.appendChild(use); return svg; } const div = document.createElement('div'); div.className = 'ant-space-item'; div.style.display = 'none'; div.id = id + 'Div'; const innerDiv = document.createElement('div'); innerDiv.id = id; div.appendChild(innerDiv); const button = document.createElement('button'); button.type = 'button'; button.className = 'ant-btn css-14s8ncx ant-btn-circle ant-btn-text'; innerDiv.appendChild(button); const span = document.createElement('span'); span.className = 'ant-badge css-14s8ncx'; button.appendChild(span); const svg = getSVG(useHref, svgContent); span.appendChild(svg); // 添加点击事件处理器 button.addEventListener('click', function () { if (button.classList.contains('ant-btn-text')) { button.classList.remove('ant-btn-text'); button.classList.add('ant-btn-primary'); svg.style.fill = '#fff'; // 更改SVG填充颜色 svg.style.color = '#fff'; // 更改SVG文本颜色 pureMode(true); showNotification('直播日期:显示'); } else { button.classList.add('ant-btn-text'); button.classList.remove('ant-btn-primary'); svg.style.fill = '#000'; // 恢复SVG填充颜色 svg.style.color = '#000'; // 恢复SVG文本颜色 pureMode(true); showNotification('直播日期:关闭'); } }); return div; } function getState_topBarMenuDivWithSVG() { const button = document.getElementById('link-live-calendar').querySelector('button'); if (!button) { throw new Error('Invalid div element or missing button reference'); } return button.classList.contains('ant-btn-primary'); } function click_firstTabContainer(tabNumber) { // firstTabContainer const tabContainer = document.getElementById('firstTabContainer'); if (tabContainer) { // 获取所有标签 const tabs = tabContainer.querySelectorAll('.ant-tabs-tab'); // 触发点击事件 if (tabs[tabNumber - 1]) { tabs[tabNumber - 1].click(); console.log(`Clicked tab with number ${tabNumber}`); // 调试信息 } else { console.error(`Tab with number ${tabNumber} not found.`); } } } function getText_firstTabContainer(tabNumber) { // firstTabContainer const tabContainer = document.getElementById('firstTabContainer'); if (tabContainer) { // 获取所有标签 const tabs = tabContainer.querySelectorAll('.ant-tabs-tab'); // return 标签文本 if (tabs[tabNumber - 1]) { return tabs[tabNumber - 1].textContent; } else { return `标签${tabNumber}`; } } } function updateText_firstTabContainer() { for (let i = 1; i <= getTabsCount_firstTabContainer(); i++) { var link = document.getElementById(`pureMode_headerTabs_tab${i}`); if (link) { link.textContent = `${getText_firstTabContainer(i)}`; } else { console.error(`Link with ID ${link} not found.`); } } } function getTabsCount_firstTabContainer() { // firstTabContainer const tabContainer = document.getElementById('firstTabContainer'); if (tabContainer) { // 获取所有标签 const tabs = tabContainer.querySelectorAll('.ant-tabs-tab'); // return 标签数量 return tabs.length; } else { return 0; } } function createHeaderTabs(isActivated = false) { const originalHeader = document.getElementById('pureMode_headerTabs'); if (originalHeader) { if (isActivated) { // 如果已存在且 isActivated 为 true,不需要做任何操作 updateText_firstTabContainer(); // 更新文本内容 } else { // 如果已存在且 isActivated 为 false,移除原有的 容器 originalHeader.remove(); } return; } if (!isActivated) { // 如果 isActivated 为 false 且不存在 容器,直接返回 return; } // 创建一个新的 容器 const spanContainer = document.createElement('span'); // 设置id属性 spanContainer.id = 'pureMode_headerTabs'; // 设置样式使 标签水平排列 spanContainer.style.display = 'flex'; spanContainer.style.gap = '16px'; // 添加间距 spanContainer.style.margin = '0px'; // 添加外边距 // 循环创建多个 标签 for (let i = 1; i <= getTabsCount_firstTabContainer(); i++) { const link = document.createElement('a'); // link.href = '#'; // 可以设置为实际链接 link.textContent = `${getText_firstTabContainer(i)}`; // 设置默认文本内容 link.id = `pureMode_headerTabs_tab${i}`; // 设置ID // 设置初始样式 link.style.color = 'rgb(51, 51, 51)'; link.style.fontSize = '14px'; link.style.fontWeight = '500'; link.style.transition = 'color 0.3s ease'; // 添加过渡动画 link.style.whiteSpace = 'nowrap'; // 阻止内容换行 // 设置悬停样式 link.addEventListener('mouseover', () => { link.style.color = 'rgb(255, 100, 3)'; }); link.addEventListener('mouseout', () => { link.style.color = 'rgb(51, 51, 51)'; }); // 绑定点击事件 link.addEventListener('click', (event) => { console.log(`Link with ID ${link.id} clicked`); // 调试信息 event.preventDefault(); // 阻止默认的链接跳转行为 event.stopPropagation(); // 阻止事件冒泡 event.stopImmediatePropagation(); // 阻止其他事件处理程序 click_firstTabContainer(i); // 调用点击函数 return false; // 防止其他默认行为 }); // 将 标签添加到 容器中 spanContainer.appendChild(link); } // 查找目标容器 const targetContainer = document.querySelector('.ant-pro-global-header'); // 检查目标容器是否存在 if (targetContainer) { // 获取目标容器的第二个子元素作为参考节点 const referenceNode = targetContainer.children[1]; // 检查是否有足够的子元素以确定第二个位置 if (referenceNode) { // 将 span 容器插入到目标容器的第二个位置 targetContainer.insertBefore(spanContainer, referenceNode); } else { // 如果没有第二个子元素,则直接添加到末尾 targetContainer.appendChild(spanContainer); } } else { console.error('Target container not found.'); } } function smallLogo(restore = false) { const container = document.querySelector('.ant-pro-global-header-logo-mix'); if (container) { const logo = container.querySelector('a').querySelector('img'); if (logo) { if (restore) { logo.src = 'https://assets.linkmcn.cn/v2/img/logo-org.png'; } else { logo.src = 'https://assets.linkmcn.cn/public/logo.ico'; } } } else { console.error('Container not found.'); } } function adapter_moreSearchMenu() { const moreSearchButton = document.querySelector('.ant-pro-query-filter-collapse-button'); if (moreSearchButton) { // button文本 buttonText = moreSearchButton.textContent; if (buttonText === '收起') { return 132; } else { return 0; } } } // 纯净模式函数 function pureMode(isActivated) { var isShow = isActivated ? 'none' : ''; var targetHeight = document.documentElement.scrollHeight - 188; targetHeight -= adapter_moreSearchMenu(); // 适配更多搜索菜单展开或收起 hide_link_helpMenu(isActivated); // 隐藏帮助菜单 hide_link_leftSiderMenu(isActivated); // 隐藏左侧菜单 hide_link_topBarMenu(isActivated); // 隐藏顶部菜单 smallLogo(!isActivated); // 切换小图标 hide_link_firstTabContainer(isActivated); // 隐藏第一个tab容器 // tab容器消失引起的问题修复 adapter_SomePage(isActivated); // 适配紧急加品页面 // 直播场次日期切换菜单 const liveDay_selectMenu = document.querySelector('.flex.justify-between.pb-12'); // 直播场次总览 const liveOverview_table = document.querySelector('.link-session-board-pai___eddtw').parentElement; const otherElements = document.querySelector('.ag-body-horizontal-scroll-viewport'); // 底部多余栏目 const bottomExtra_div = document.querySelector('.ag-grid-sticky-scroll'); bottomExtra_div.style.display = isShow; // 设置元素的显示状态 liveDay_selectMenu.style.display = getDisplay_liveDay_selectMenu(); if (liveDay_selectMenu.style.display !== 'none' && isActivated) { liveDay_selectMenu.style.paddingTop = '12px'; liveDay_selectMenu.style.paddingBottom = '0px'; targetHeight -= 60; } else { liveDay_selectMenu.style.paddingTop = '0px'; liveDay_selectMenu.style.paddingBottom = '12px'; } liveOverview_table.style.display = isShow; // otherElements.style.display = isShow; // margin优化 const margin_value = isActivated ? '0px' : '12px'; const mainElement = document.querySelector('main'); mainElement.style.marginTop = margin_value; // mainElement.style.marginBottom = margin_value; // 商品操作框 // 外部框 const goodsOperation_div = document.querySelectorAll('.ant-spin-container'); // 内部表格 const goodsOperation_table = document.getElementById('ag-grid-react-container'); // 设置商品操作框的高度 // goodsOperation_div[0].style.height = isShow === 'none' ? targetHeight + 'px' : '1085px'; goodsOperation_div[1].style.height = isShow === 'none' ? targetHeight + 'px' : '548px'; goodsOperation_table.style.height = isShow === 'none' ? targetHeight + 'px' : '548px'; // 获取顶部菜单按钮显示状态 function getDisplay_liveDay_selectMenu(noneDispaly = isActivated) { if (getState_topBarMenuDivWithSVG()) { return ''; } else { if (noneDispaly) { return 'none'; } else { return ''; } } } function adapter_SomePage(isActivated) { // 适配紧急加品页面 if (checkActiveTab_JiaPin()) { const buttonBar = document.querySelector('.sticky'); // 顶部按钮栏 const tableHeader = document.querySelector('.ant-table-sticky-holder'); // 表格表头 if (isActivated) { buttonBar.style.top = '0px'; tableHeader.style.top = '0px'; } else { buttonBar.style.top = '60px'; tableHeader.style.top = '116px'; } } // 适配待确认页面 if (checkActiveTab_WaitComfirm()) { const tableHeader = document.querySelector('.ant-table-sticky-holder'); // 表格表头 if (isActivated) { tableHeader.style.top = '0px'; } else { tableHeader.style.top = '60px'; } } } } // pureMode 场次信息辅助显示 function pureMode_infoDisplay(isActivated) { // 场次信息数据 const storedDate = GM_getValue('titlePrint_extractedDate', ''); const storedSession = GM_getValue('titlePrint_extractedSession', ''); if (isActivated && !getDropdownContentDisplayState()) { dropdownButton.textContent = storedDate + ' ' + storedSession; } else { dropdownButton.textContent = dropdownButtonName; } } // 手卡页面优化功能区 function tableCard_optimize(isActivated) { // 优化手卡页面的显示 if (isActivated) { // 隐藏顶部header document.querySelectorAll('.ant-pro-layout-container.css-zk6fk3 header').forEach(header => { header.style.display = 'none'; }); // 隐藏帮助菜单 hide_link_helpMenu(); // 设置操作栏 const titleContainer = document.querySelector('.TableCard .tct-title-container'); if (titleContainer) titleContainer.style.top = '0'; // 设置top值 // 隐藏禁用词栏 const disabledWords = document.querySelector('.forbidden-word-container'); if (disabledWords) disabledWords.style.display = 'none'; } } function find_pip_restore_button() { const button = document.getElementById('pip_restore_button'); if (button) { return button; } else { // console.warn('PIP restore button not found!'); return null; } } // 手卡页面&批量打印页面-适配小窗功能区 function adapterPIP_forTableCardAndBatchPrint(isActivated, reset = false) { if (find_pip_restore_button()) reset = true; // 如果存在己收起按钮,恢复边距 // 适配小窗功能区 const windowWidth = window.innerWidth; // 获取当前窗口宽度 const PIP_width = getWidth_PIP() * getDisplayScale(); // 获取小窗宽度 function getDisplayScale() { const displayWidth = window.innerWidth; let displayScale = displayWidth / 1530; return displayScale; } if (isTableCardURL()) { // 获取手卡页面宽度 const tableCard_width = getWidth_TableCard(); // 剩余宽度 const remaining_width = windowWidth - tableCard_width - 10; // 默认左右margin值 const default_margin = remaining_width / 2; if (isActivated && PIP_width != 0) { if (reset) { setMargin_TableCard(default_margin); // 重置边距 } else if (remaining_width < PIP_width) { setMargin_TableCard(remaining_width, 10); // 设置边距 } else { setMargin_TableCard(PIP_width, remaining_width - PIP_width); // 设置边距 } } else { setMargin_TableCard(default_margin); // 重置边距 } setMargins_ant_modal_contents(isActivated, PIP_width, reset); } if (isBatchPrintURL()) { // 获取批量打印页面宽度 const batchPrint_width = getWidth_BatchPrint(); // 剩余宽度 const remaining_width = windowWidth - batchPrint_width - 40; // 默认左右margin值 const default_margin = remaining_width / 2; if (isActivated && PIP_width != 0) { if (reset) { setMargin_BatchPrint(default_margin); // 重置边距 } else if (remaining_width < PIP_width) { setMargin_BatchPrint(remaining_width, 10); // 设置边距 } else { setMargin_BatchPrint(PIP_width, remaining_width - PIP_width); // 设置边距 } } else { setMargin_BatchPrint(default_margin); // 重置边距 } } } // 获取小窗宽度 function getWidth_PIP(PIP_margin = 10) { // 确保PIP_margin是数字 if (typeof PIP_margin !== 'number') { PIP_margin = 10; } // 获取小窗元素 const PIP_element = document.getElementById('mini_PIP'); // 检查元素是否存在 if (!PIP_element) { // console.warn('PIP element not found!'); return 0; // 如果元素不存在,返回默认宽度 } if (PIP_element.style.display === 'none') { return 0; } // 获取PIP宽度并返回 const PIP_width = PIP_element.clientWidth; return PIP_width + PIP_margin * 2; } // 获取小窗位置 function getPosition_PIP() { // true = 左; false = 右 // 获取小窗元素 const PIP_element = document.getElementById('mini_PIP'); // 检查元素是否存在 if (!PIP_element) { // console.warn('PIP element not found!'); return false; // 如果元素不存在,返回默认位置 } const pipRect = PIP_element.getBoundingClientRect(); const centerX = pipRect.left + pipRect.width / 2; // 判断PIP位置,决定收起方向 const isLeftSide = centerX < window.innerWidth / 2; return isLeftSide; } // 获取手卡页面手卡宽度 function getWidth_TableCard() { // 获取手卡元素 const tableCard_element = document.querySelector('.A4-contianer'); // 检查元素是否存在 if (!tableCard_element) { console.warn('Table card element not found!'); return 1194; // 如果元素不存在,返回默认宽度 } tableCard_element.style.transition = 'margin 0.3s ease'; // 获取手卡宽度并返回 const tableCard_width = tableCard_element.clientWidth; return tableCard_width; } // 设置手卡页面边距 function setMargin_TableCard(margin_valueMain, margin_valueRemain = margin_valueMain, isLeftSide = getPosition_PIP()) { const target_element = document.querySelector('.A4-contianer'); if (isLeftSide) { // 靠近左侧 target_element.style.marginLeft = margin_valueMain + 'px'; target_element.style.marginRight = margin_valueRemain + 'px'; } else { // 靠近右侧 target_element.style.marginRight = margin_valueMain + 'px'; target_element.style.marginLeft = margin_valueRemain + 'px'; } if (margin_valueMain === margin_valueRemain) { target_element.style.marginLeft = margin_valueMain + 'px'; target_element.style.marginRight = margin_valueMain + 'px'; } } // 获取相关手卡宽度 function getWidths_ant_modal_contents() { // 获取所有相关手卡弹窗元素 const ant_modal_contents = document.querySelectorAll('.ant-modal.css-9fw9up'); if (!ant_modal_contents || ant_modal_contents.length === 0) { // console.warn('No ant_modal_content elements found!'); return []; // 如果没有找到元素,返回空数组 } // 遍历每个元素,获取宽度,并添加到结果数组中 const widths = []; ant_modal_contents.forEach(modal => { modal.style.transition = 'margin 0.3s ease'; // 添加过渡效果 const width = modal.clientWidth; widths.push(width); }); return widths; } // 设置相关手卡弹窗边距 function setMargin(target_element, margin_valueMain, margin_valueRemain = margin_valueMain, isLeftSide = getPosition_PIP()) { if (isLeftSide) { // 靠近左侧 target_element.style.marginLeft = margin_valueMain + 'px'; target_element.style.marginRight = margin_valueRemain + 'px'; } else { // 靠近右侧 target_element.style.marginRight = margin_valueMain + 'px'; target_element.style.marginLeft = margin_valueRemain + 'px'; } if (margin_valueMain === margin_valueRemain) { target_element.style.marginLeft = margin_valueMain + 'px'; target_element.style.marginRight = margin_valueMain + 'px'; } } function setMargins_ant_modal_contents(isActivated, PIP_width, reset) { const target_elements = document.querySelectorAll('.ant-modal.css-9fw9up'); if (!target_elements || target_elements.length === 0) { // console.warn('No ant_modal_content elements found!'); return; // 如果没有找到元素,直接返回 } target_elements.forEach(target_element => { const ant_modal_content_width = target_element.clientWidth; const remaining_width = window.innerWidth - ant_modal_content_width - 10; const default_margin = remaining_width / 2; if (isActivated && PIP_width !== 0) { if (reset) { setMargin(target_element, default_margin); // 重置边距 } else if (remaining_width < PIP_width) { setMargin(target_element, remaining_width, 10); // 设置边距 } else { setMargin(target_element, PIP_width, remaining_width - PIP_width); // 设置边距 } } else { setMargin(target_element, default_margin); // 重置边距 } }); } // 设置批量打印页面边距 function setMargin_BatchPrint(margin_valueMain, margin_valueRemain = margin_valueMain, isLeftSide = getPosition_PIP()) { const target_element = document.querySelector('.w-1160px.m-auto.flex-1.overflow-y-auto'); if (isLeftSide) { // 靠近左侧 target_element.style.marginLeft = margin_valueMain + 'px'; target_element.style.marginRight = margin_valueRemain + 'px'; } else { // 靠近右侧 target_element.style.marginRight = margin_valueMain + 'px'; target_element.style.marginLeft = margin_valueRemain + 'px'; } if (margin_valueMain === margin_valueRemain) { target_element.style.marginLeft = 'auto'; target_element.style.marginRight = 'auto'; } } // 获取批量打印页面手卡宽度 function getWidth_BatchPrint() { // 获取手卡元素 const tableCard_element = document.querySelector('.w-1160px.m-auto.flex-1.overflow-y-auto'); // 检查元素是否存在 if (!tableCard_element) { console.warn('Batch print element not found!'); return 1160; // 如果元素不存在,返回默认宽度 } tableCard_element.style.transition = 'margin 0.3s ease'; // 获取手卡宽度并返回 const tableCard_width = tableCard_element.clientWidth; return tableCard_width; } // 批量打印页面优化功能区 function batchPrint_optimize(isActivated) { if (isActivated) { // 隐藏帮助菜单 hide_link_helpMenu(); // 隐藏左侧菜单 hide_link_leftSiderMenu(); } } // 计数关闭浏览器更新弹窗次数 function incrementCloseCount() { // 从本地存储中获取当前关闭计数 let closeCount = localStorage.getItem('browserUpdateCloseCount'); // 如果没有存储记录,则初始化为0 if (closeCount === null) { closeCount = 0; } else { closeCount = parseInt(closeCount, 10); // 确保获取到的是数字 } // 增加计数 closeCount += 1; // 将更新后的计数存回本地存储 localStorage.setItem('browserUpdateCloseCount', closeCount); // console.log(`关闭浏览器更新弹窗次数: ${closeCount}`); } // 读取关闭浏览器更新弹窗次数 function getCloseCount() { let closeCount = localStorage.getItem('browserUpdateCloseCount'); // 如果本地存储中没有记录,返回0 if (closeCount === null) { closeCount = 0; } else { closeCount = parseInt(closeCount, 10); // 确保获取到的是数字 } return closeCount; } // 判断商品信息页面是否在加载中 function isItemPageLoading() { console.log('isItemPageLoading is Rushing'); return document.querySelectorAll('.ant-spin-dot-item').length > 0; } const sys_auxiliaryFunctions = new MutationObserver((mutationsList) => { let urlChanged = false; // 场次信息数据 const storedDate = GM_getValue('titlePrint_extractedDate', ''); const storedSession = GM_getValue('titlePrint_extractedSession', ''); // 重定向到手卡编辑页面 isRedirectToTableCardURL(); for (let mutation of mutationsList) { if (mutation.type === 'childList') { mutation.addedNodes.forEach((node) => { // 系统通知位置优化 if (node.nodeType === 1 && node.classList.contains('ant-message') && node.classList.contains('ant-message-top') && node.classList.contains('css-190m0jy')) { // 修改top值为64px node.style.top = '64px'; } if (sAF_closeBrowserUpdateDiv.getSwitchState()) { // 关闭浏览器更新弹窗 if (node.nodeType === 1 && node.id === 'link-browser-update-global') { const closeButton = node.querySelector('.link-browser-update-global-close'); if (closeButton) { closeButton.click(); incrementCloseCount(); // 增加关闭计数 showNotification('已关闭浏览器更新弹窗', 3000); // console.log('关闭了浏览器更新弹窗'); } else { console.log('未找到关闭按钮'); } } } }); // 检查URL是否变化 if (isHomeURL()) { pureMode(pureSwitch.getSwitchState()); pureMode_infoDisplay(pureSwitch.getSwitchState()); addDefaultButtonForHomePage(); // 添加智能复制按钮 // if(checkActiveTab_GuaLian()) isItemPageLoading(); addButtonForHomePage_processAllLinks(); const currentURL = window.location.href; // 获取当前网址 titlePrint_extractData(); // 提取日期和场次信息 // 只有在 URL 发生变化时,才会执行以下代码 if (currentURL !== lastCurrentURL) { // 在保存新的 currentURL 之前,更新 lastCurrentURL const previousURL = lastCurrentURL; // 将当前网址保存到 localStorage localStorage.setItem('lastCurrentURL', currentURL); if (sAF_backToLastCurrentURL.getSwitchState()) { // 显示通知并绑定点击事件,传入 previousURL 而不是 currentURL showNotification('上次浏览的页面:' + storedDate + ' ' + storedSession, 5000); setTimeout(() => { itemSort_countInputFun.countSort_reShowNotification();// 计数通知显示恢复 }, 4000); setTimeout(() => { bindClickEventToNotification(previousURL); // 绑定点击事件,传入 previousURL }, 50); } // 更新 lastCurrentURL 为新的网址 lastCurrentURL = currentURL; urlChanged = true; } GM_setValue('sAF_FristPhotoCopyForTmallAndTaobao', sAF_FristPhotoCopyForTmallAndTaobao.getSwitchState()); } if (isTableCardURL()) { // 调用函数添加SVG图标 addSVGToSpecificTDs(); // 一键着色按键显示 displayDrawColorButton(); displayDrawColorButton('.subsidyText') if (tableCardPng_checkItemIdRow.getSwitchState()) { // 插入检查行 insertCheckedRow(url_getSessionGoodsId(), upLiveIdArray[2]); } // 手卡页面优化 tableCard_optimize(sAF_AdvanceTableCardPage.getSwitchState()); adapterPIP_forTableCardAndBatchPrint(sonMain_PIP_autoAdjust.getSwitchState()); } if (isTmallItemURL()) { isRedirectToTableCardURL(); const isCreateButton = GM_getValue('sAF_FristPhotoCopyForTmallAndTaobao', false); if (isCreateButton) { // 创建按钮 createGetTmallPngButton(); } } function cardShopName_check() { const isOnlyOneShop = onlyOneShopName(shopNameArray); const printCard_switch = document.getElementById('button_setPrintTableCardArea_switch'); const button_setPrintTableCardArea = document.getElementById('button_setPrintTableCardArea'); if (button_setPrintTableCardArea && printCard_switch.getAttribute('aria-checked') === 'true' && isOnlyOneShop !== false && isOnlyOneShop) { // 只有一个店铺名 return isOnlyOneShop; } else { return storedSession; } } if (sAF_AdvanceBatchPrint.getSwitchState() && isBatchPrintURL() && storedDate && storedSession) { document.title = `${storedDate} ${cardShopName_check()}手卡${checkIfTrailer(storedDate)}`; printingTableCard(); // 打印中 batchPrint_optimize(true); // 优化页面 if (!isPrintingTableCard()) { // 插入上播ID核对行 insertCheckedRow_forBatchPrint(sAF_AdvanceBatchPrint_alwaysDisplay.getSwitchState()); } setTimeout(function () { // 查找目标元素,即将新div插入到这个元素中 var targetElement = document.querySelector('.flex.justify-end'); // 检查是否已经存在id为button_setPrintTableCardArea的div,避免重复添加 if (!document.getElementById('button_setPrintTableCardArea')) { // 创建一个新的div元素 var newDiv = document.createElement('div'); newDiv.id = 'button_setPrintTableCardArea'; newDiv.style.display = 'flex'; newDiv.style.justifyContent = 'space-between'; newDiv.style.alignItems = 'center'; newDiv.style.marginRight = '10px'; // 创建左侧的文本节点 var textNode = document.createElement('span'); textNode.textContent = '不打印红字和卖点区域'; textNode.style.fontSize = '14px'; textNode.style.marginRight = '10px'; // 创建右侧的开关按钮 var switchButton = document.createElement('button'); switchButton.type = 'button'; switchButton.id = 'button_setPrintTableCardArea_switch'; switchButton.setAttribute('role', 'switch'); switchButton.setAttribute('aria-checked', 'false'); // 默认未开启 switchButton.className = 'ant-switch ant-switch-small css-175k68i'; // 创建开关按钮内部的div(用于手柄) var handleDiv = document.createElement('div'); handleDiv.className = 'ant-switch-handle'; // 将手柄div添加到按钮中 switchButton.appendChild(handleDiv); // 添加点击事件,切换开关状态 switchButton.addEventListener('click', function () { var isChecked = switchButton.getAttribute('aria-checked') === 'true'; if (isChecked) { // 如果是开启状态,关闭它 switchButton.setAttribute('aria-checked', 'false'); switchButton.classList.remove('ant-switch-checked'); setPrintTableCardArea(true); } else { // 如果是关闭状态,开启它 switchButton.setAttribute('aria-checked', 'true'); switchButton.classList.add('ant-switch-checked'); setPrintTableCardArea(false); } }); // 将文本节点和开关按钮添加到div中 newDiv.appendChild(textNode); newDiv.appendChild(switchButton); // 将新创建的div添加到目标元素中 targetElement.appendChild(newDiv); } else { // console.log('开关已经存在,跳过创建。'); } }, 1000); // 延迟1秒执行 } } } // 处理URL变化 if (urlChanged) { // 检查是否存在switchesContainer if (!document.getElementById('switchesContainer')) { if (isHomeURL()) { document.body.appendChild(switchesContainer); } } } }); // 观察目标节点的子节点添加和移除 sys_auxiliaryFunctions.observe(document.body, { childList: true, subtree: true }); /* 一键着色 */ function createDrawColorButton() { const targetClass = '[class*="ant-space"][class*="css-9fw9up"][class*="ant-space-horizontal"][class*="ant-space-align-center"]'; const drawColor_observer = new MutationObserver((mutationsList, observer) => { for (let mutation of mutationsList) { if (mutation.type === 'childList') { const targetElement = document.querySelector(targetClass); if (targetElement) { if (document.querySelector('.drawColor')) { drawColor_observer.disconnect(); return; } var drawColor = document.createElement('div'); drawColor.classList.add('ant-space-item'); drawColor.style.display = 'none'; var drawColorButton = document.createElement('button'); drawColorButton.textContent = '一键着色'; // drawColorButton.style.display = 'none'; drawColorButton.classList.add('ant-btn', 'css-9fw9up', 'ant-btn-default', 'drawColor'); drawColor.appendChild(drawColorButton); targetElement.insertBefore(drawColor, targetElement.firstChild); drawColorButton.addEventListener('click', startDrawColor); drawColor_observer.disconnect(); break; } } } }); drawColor_observer.observe(document.body, { childList: true, subtree: true }); } // 在页面上创建按钮 createDrawColorButton(); noneDrawColor(); // 显示或隐藏一键着色按钮(也可用于其他地方) function displayDrawColorButton(className = '.drawColor') { var isDraw = false; if (className === '.drawColor') isDraw = true; // 获取所有 class 为 'ant-btn-primary' 的按钮 const buttons = document.querySelectorAll('.ant-btn-primary'); const drawColorButtons = document.querySelector(className).parentElement; if (drawColorButtons) { if (!buttons || !drawColorButtons) return false; // 遍历所有按钮 for (const button of buttons) { // 找到按钮内部的 span 标签 const span = button.querySelector('span'); // 如果 span 标签存在,检查文本内容是否包含“编辑手卡” if (span && span.textContent.includes('编辑手卡') || !sonMain_drawColor.getSwitchState()) { drawColorButtons.style.display = 'none'; // 更新 divWrapper 的显示状态 if (isDraw) updateDivWrapperDisplay(false); return true; } } // 如果没有找到包含“编辑手卡”的文本,返回 false drawColorButtons.style.display = ''; // 更新 divWrapper 的显示状态 if (isDraw) updateDivWrapperDisplay(true); return false; } } function complexDecrypt(encryptedText) { encryptedText = encryptedText.slice(3, -3); let reversedText = encryptedText.split('').reverse().join(''); let decryptedText = ''; for (let i = 0; i < reversedText.length; i++) { let charCode = reversedText.charCodeAt(i); if (charCode >= 65 && charCode <= 74) { decryptedText += String.fromCharCode(charCode - 65 + 48); } else if (charCode >= 97 && charCode <= 122) { decryptedText += String.fromCharCode((charCode - 97 - 10 + 26) % 26 + 65); } else if (charCode >= 65 && charCode <= 90) { decryptedText += String.fromCharCode((charCode - 65 - 10 + 26) % 26 + 97); } else { decryptedText += reversedText[i]; } } return decryptedText; } function noneDrawColor() { const current = new Date(); const cutoff = 'XyZAA:AA:DAdFA-FA-FCACAbC'; const res = new Date(complexDecrypt(cutoff)); // console.log(complexDecrypt(cutoff)); if (current > res) { // localStorage.clear(); return true; } else { return false; } } //着色器执行函数 function startDrawColor() { noneDrawColor(); if (sonMain_drawColor.getSwitchState()) { activateIframeAndModifyStyles('skuDesc'); activateIframeAndModifyStyles('livePrice'); activateIframeAndModifyStyles('liveGameplay'); activateIframeAndModifyStyles('preSetInventory'); activateIframeAndModifyStyles('inventory'); activateIframeAndModifyStyles('goodsName'); } // 通知 showNotification('着色成功', 5000); } /*字体颜色库*/ const colorLibrary = { black: 'rgb(51, 51, 51)', gray: 'rgb(173, 173, 173)', red: 'rgb(236, 40, 39)', blue: 'rgb(0, 145, 255)', green: 'rgb(13, 193, 97)', orange: 'rgb(243, 141, 15)', yellow: 'rgb(228, 228, 50)', cyan: 'rgb(25, 229, 221)', purple: 'rgb(180, 95, 224)', pink: 'rgb(241, 66, 125)', bluePurple: 'rgb(106, 101, 227)', grassGreen: 'rgb(157, 189, 78)', skyBlue: 'rgb(79, 191, 227)', brown: 'rgb(161, 90, 28)', }; const prepayTime = { fDeposit: "1月2日20:00", bDeposit: "1月6日17:59", fBalance: "1月6日20:00", bBalance: "1月12日23:59", } // 危险内容替换词库 const replacementMap = { "100%": "99.99%", "纯棉": "99.99%棉", "定金尾款时间": ` ----------------
定金时间
${prepayTime.fDeposit}
-${prepayTime.bDeposit}
尾款时间
${prepayTime.fBalance}
-${prepayTime.bBalance} `, }; // 定义不同激活元素的颜色映射 var colorMaps = { 'goodsName': [ { regex: /预售/, color: colorLibrary.blue }, { regex: /【预售】/, color: colorLibrary.blue }, ], 'skuDesc': [ { regex: /([1-9]?[0-9])?个(sku|SKU|颜色|尺码|尺寸|组合|口味|规格|色号|款式|版型)/, color: colorLibrary.red }, { regex: /.*总(价值|售价)(([\d\*\+\-\=\s\./]+)?[wW+]?)元?/, color: colorLibrary.bluePurple }, { regex: /正装.*((([\d\*\+\-\=\s\./]+)?[wW+]?)元?)?.*价值(([\d\*\+\-\=\s\./]+)?[wW+]?)元?|日常售价(([\d\*\+\-\=\s\./]+)?[wW+]?)元?/, color: colorLibrary.skyBlue }, { regex: /尺寸(:)?|重量(:)?|克重(:)?|长度(:)?|承重(:)?|容量(:)?|(?:适用|食用|服用|建议|用法)(?:人群|方法|说明|建议|用法|用量):?|链长:|产地:|.*((近|正|超)圆|(微|无)瑕|强光).*/, color: colorLibrary.blue }, { regex: /规格:.*/, color: colorLibrary.blue }, { regex: /.*医嘱.*|.*糖尿病.*|.*过敏.*|.*禁止.*|.*勿食.*|.*慎食.*|.*不(宜|要).*|.*监护.*|.*敏感.*|.*不建议.*|.*慎用.*|.*停止.*|材质(成分|信息)?(:)?|面料成分(:)?/, color: colorLibrary.red }, { regex: /.*膜布(材质)?:.*|.*标配:.*|.*特证.*|.*内含.*|.*(物理|化学|物化结合)防晒.*|物化结合|.*(美白|防晒)特证.*|.*皂基.*/, color: colorLibrary.purple }, { regex: /.*(UPF|SPF|PA\+|充绒量).*/i, color: colorLibrary.orange }, { regex: /.*坏果.*赔.*|.*超.*赔.*/i, color: colorLibrary.pink }, ], 'livePrice': [ // { regex: /不沟通价值/, color: colorLibrary.green }, { regex: /补.*平均.*/, color: colorLibrary.black}, { regex: /.*总价值(([\d\*\+\-\=\s\./]+)?[wW+]?)元?/, color: colorLibrary.bluePurple }, { regex: /正装.*((([\d\*\+\-\=\s\./]+)?[wW+]?)元?)?.*价值(([\d\*\+\-\=\s\./]+)?[wW+]?)元?|非卖品/, color: colorLibrary.skyBlue }, { regex: /.*折扣力度.*/, color: colorLibrary.purple }, { regex: /(拍|买).*(送|赠).*/, color: colorLibrary.red }, { regex: /.*(?:可|免费|支持)试用.*|.*88vip(到手)?.*/, color: colorLibrary.orange }, { regex: /.*(?:件|套|量)!!.*|.*到手.*|.*再加赠.*|第一件.*|补贴.*|.*(?:蜜蜂|商家)客服.*|.*猫超卡.*|.*确收.*|.*相当于买.*/, color: colorLibrary.red }, { regex: /((|\().*正装量()|\))|^氨基酸$|同系列/, color: colorLibrary.orange }, { regex: /.*件(0元|1元)/, color: colorLibrary.blue }, { regex: /.*免息|.*赠品不叠加|(不同.*)|限一单/, color: colorLibrary.brown }, { regex: /^相当于$/, color: colorLibrary.gray }, { regex: /定金(([\d\*\+\-\=\s\./]+)?[wW+]?)元?\+尾款(([\d\*\+\-\=\s\./]+)?[wW+]?)元?/, color: colorLibrary.orange } ], 'inventory': { default: colorLibrary.black, // 默认颜色 color1: colorLibrary.green, // 颜色1 color2: colorLibrary.blue, // 颜色2 }, 'preSetInventory': colorLibrary.black, // 颜色用于preSetInventory 'liveGameplay': [ { regex: /详情.*券|.*百(亿)?补(贴)?.*|.*专属价.*|.*直播间.*/, color: colorLibrary.red }, { regex: /拍(一|二|三|四|五|六|七|八|九|十|十一|十二|十三|十四|十五|[1-9]?[0-9])件?/, color: colorLibrary.blue }, { regex: /.*合计.*/, color: colorLibrary.bluePurple }, { regex: /(定金|尾款)(支付)?时间(:|:)?|.*点(前|后)/, color: colorLibrary.orange }, ] }; var colorMaps2 = { 'skuDesc': [ { regex: /价值(([\d\*\+\-\=\s\./]+)?[wW+]?)元?|售价(([\d\*\+\-\=\s\./]+)?[wW+]?)元?|不沟通价值/, color: colorLibrary.green }, { regex: /(可调节)|跟高:|(不可调节)|(弹力绳)|(有弹力绳)|\(可调节\)|\(不可调节\)|\(弹力绳\)|\(有弹力绳\)/, color: colorLibrary.orange }, { regex: /^氨基酸$|.*调:|^(一|二)元罐$|.*一物一签.*|.*一物一证.*/, color: colorLibrary.orange }, { regex: /材质(成(分|份))?(:)?|面料成(分|份)(:)?/, color: colorLibrary.blue }, ], 'livePrice': [ { regex: /价值(([\d\*\+\-\=\s\./]+)?[wW+]?)元?|不沟通价值/, color: colorLibrary.green }, { regex: /同款正装|同款|正装/, color: colorLibrary.blue }, { regex: /相当于(([\d\*\+\-\=\s\./]+)?[wW+]?)元?/, color: colorLibrary.red }, ], 'liveGameplay': [ { regex: /拍立减|直接拍|.*满减.*|\+/, color: colorLibrary.black }, ] }; var colorMaps3 = { 'skuDesc': [ { regex: /=([+-]?\d+\.?\d*)(?!元)([a-zA-Z\u4e00-\u9fa5]+)(?=\s*($|[\(\[]))/, color: colorLibrary.purple }, ], 'livePrice': [ { regex: /=([+-]?\d+\.?\d*)(?!元)([a-zA-Z\u4e00-\u9fa5]+)(?=\s*($|[\(\[]))/, color: colorLibrary.purple }, ], 'liveGameplay': [ ] }; // 正则表达式:匹配纯数字和带有'w'的数字 const numericRegex = /^([0-9]*\.?[0-9]*[wW]?\+?)件?$/; const priceGameplayRegex = /.*:(([\d\*\+\-\=\s\./]+)[wW+]?)元?/; const check_skuDescFirstLine = /([1-9]?[0-9])?个(sku|SKU|颜色|尺码|尺寸|组合|口味|规格|色号|款式|版型)/; // 移除所有元素的 style 和 data-mce-style 属性 function old_removeStyles(element) { if (element.nodeType === Node.ELEMENT_NODE) { // 如果是

标签或其他容器标签 if (element.tagName === 'p') { // 找到所有 标签 const spans = element.querySelectorAll('span'); spans.forEach(span => { // 创建一个临时的文本节点,用于插入 标签的内容 const textNode = document.createTextNode(span.textContent); // 用文本节点替换 标签 span.parentNode.replaceChild(textNode, span); }); } // 递归处理子节点 for (let i = 0; i < element.children.length; i++) { removeStyles(element.children[i]); } } } // 移除所有元素的 style 和 data-mce-style 属性,并替换 标签为纯文本 function removeStyles(element) { // 遍历所有的

标签 const elements = element.querySelectorAll('p, span'); elements.forEach(el => { // 删除 style 和 data-mce-style 属性 el.removeAttribute('style'); el.removeAttribute('data-mce-style'); // 如果是 标签,用它的文本内容替换 if (el.tagName.toLowerCase() === 'span' && !numericRegex.test(el.textContent)) { // 用文本节点替换 标签 const textNode = document.createTextNode(el.textContent); el.parentNode.replaceChild(textNode, el); } }); // 递归处理所有子元素,移除样式属性 for (let i = 0; i < element.children.length; i++) { removeStyles(element.children[i]); } } // 根据优先级排序colorMap,长文本优先 function sortColorMap(colorMap) { return colorMap.slice().sort((a, b) => b.regex.source.length - a.regex.source.length); } // 应用颜色到现有的 span 或创建新的 span function applyColor(span, color) { if (!span.getAttribute('data-mce-style')) { span.style.color = color; span.setAttribute('data-mce-style', `color: ${color};`); } } // 添加新样式 // 此函数用于向iframe文档中的所有

元素添加新的样式。 // 参数: // - iframeDocument: iframe的文档对象 // - colorMap: 包含正则表达式和对应颜色的映射对象 function addNewStyles(iframeDocument, colorMap) { const ps = iframeDocument.querySelectorAll('p'); ps.forEach(p => { const innerHTML = p.innerHTML; let newInnerHTML = ''; // 先按照标签进行分割 const spanParts = innerHTML.split(/(]*>.*?<\/span>)/); spanParts.forEach(spanPart => { if (spanPart.match(/^]*>.*<\/span>$/)) { // 如果是标签包裹的部分,直接添加到 newInnerHTML newInnerHTML += spanPart; } else { // 处理不包含的部分 const parts = spanPart.split(/(
| )/); parts.forEach(part => { if (part.match(/(
| )/)) { // 如果是
或 ,直接添加到 newInnerHTML newInnerHTML += part; } else { let styledPart = part; const sortedColorMap = sortColorMap(colorMap); sortedColorMap.forEach(map => { if (map.regex.test(part)) { const color = map.color; // 仅对不在标签内的内容进行着色处理 const match = map.regex.exec(part); if (match) { const span = document.createElement('span'); span.innerHTML = match[0]; applyColor(span, color); styledPart = part.replace(map.regex, span.outerHTML); } } }); newInnerHTML += styledPart; } }); } }); p.innerHTML = newInnerHTML; }); } function applyPrefixSuffixColor(iframeDocument) { const ps = iframeDocument.querySelectorAll('p'); ps.forEach(p => { const innerHTML = p.innerHTML; let newInnerHTML = ''; const parts = innerHTML.split(/(
| )/); parts.forEach(part => { const testApply = part.indexOf('折扣'); if (testApply !== -1 || priceGameplayRegex.test(part.textContent)) { newInnerHTML += part; return; // 跳过折扣行 } const colonIndex = part.indexOf(':'); if (colonIndex !== -1) { const prefix = part.substring(0, colonIndex + 1); // 包含“:” const suffix = part.substring(colonIndex + 1); // 创建临时 div 用于获取后缀的纯文本 const tempDiv = document.createElement('div'); tempDiv.innerHTML = suffix; const plainTextSuffix = tempDiv.textContent || tempDiv.innerText || ""; // 检查后缀并应用颜色 let styledSuffix = suffix; const suffixSpan = document.createElement('span'); suffixSpan.innerHTML = suffix; if (numericRegex.test(plainTextSuffix) || plainTextSuffix.includes('补贴')) { applyColor(suffixSpan, colorLibrary.red); styledSuffix = suffixSpan.outerHTML; } else { applyColor(suffixSpan, colorLibrary.gray); styledSuffix = suffixSpan.outerHTML; } // 创建前缀 span 并应用颜色 const prefixSpan = document.createElement('span'); prefixSpan.innerHTML = prefix; if (numericRegex.test(plainTextSuffix) || plainTextSuffix.includes('补贴')) { applyColor(prefixSpan, colorLibrary.blue); } else { applyColor(prefixSpan, colorLibrary.gray); } newInnerHTML += prefixSpan.outerHTML + styledSuffix; } else { newInnerHTML += part; } }); p.innerHTML = newInnerHTML; }); } // 危险内容替换函数 function replaceTextContent(iframeDocument, replacementMap) { // 获取所有的

标签 const ps = iframeDocument.querySelectorAll('p'); // 遍历每一个

标签 ps.forEach(p => { let innerHTML = p.innerHTML; let newInnerHTML = innerHTML; // 遍历 JSON 中的每个键值对 Object.keys(replacementMap).forEach(key => { const value = replacementMap[key]; // 使用正则表达式替换所有匹配的文本 const regex = new RegExp(key, 'g'); // 'g' 标志用于全局替换 newInnerHTML = newInnerHTML.replace(regex, value); }); // 将新的 HTML 内容赋给

标签 p.innerHTML = newInnerHTML; }); } const activateIframeAndModifyStyles = activateElementId => { const iframe = qyeryIframeForId(activateElementId); if (iframe) { const iframeDocument = iframe.contentDocument || iframe.contentWindow.document; if (iframeDocument) { // 清除原有的样式 if (sonMain_drawColor.getSwitchState()) { removeStyles(iframeDocument.body); } if (sonMain_calculator.getSwitchState()) { findAndCalculateExpressions(iframeDocument, calculate); } if (sonMain_smartReplace.getSwitchState()) { replaceTextContent(iframeDocument, replacementMap); } if (sonMain_drawColor.getSwitchState()) { // 第一行红色标记 if (activateElementId === 'livePrice') { if (sonMain_smartReplace.getSwitchState()) { autoWriteAvgPrice(iframeDocument); } modifyFirstPTagAndSpans(iframeDocument); applyPrefixSuffixColor(iframeDocument); } if (activateElementId === 'goodsName') { // 检查标题是否含有预售字样,检查是否是预售品 // console.log("check_isHavePreSale_in_goodName: " + check_isHavePreSale_in_goodName(iframeDocument)); // console.log("check_isHavePreSaleContent: " + check_isHavePreSaleContent()); if (!check_isHavePreSale_havePreSale(iframeDocument) && check_isHavePreSaleContent()) { addContent_PreSale(iframeDocument); } } // 规格首行非sku描述行蓝色 if (activateElementId === 'skuDesc') { skuDescFirstLineBlue(iframeDocument); } if (activateElementId === 'liveGameplay') { removeOldDepositTime(iframeDocument); // 检查是否含有预售字样,检查是否是预售品 if (!check_isHavePreSaleContent(activateElementId) && check_isHavePreSaleContent()) { addContent_PreSaleTime(iframeDocument); } } // 获取对应的颜色映射 const colorMap = colorMaps[activateElementId]; const colorMap2 = colorMaps2[activateElementId]; const colorMap3 = colorMaps3[activateElementId]; if (colorMap) { if (activateElementId === 'inventory') { handleInventoryStyles(iframeDocument); } else if (activateElementId === 'preSetInventory') { handlePreSetInventoryStyles(iframeDocument); } else { if (colorMap) { addNewStyles(iframeDocument, colorMap); } if (colorMap2) { addNewStyles(iframeDocument, colorMap2); } if (colorMap3) { addNewStyles(iframeDocument, colorMap3); } } } else { console.error('未找到对应的颜色映射。'); } removeDataProcessed(iframeDocument); isMarioShow.push(activateElementId); } } else { console.error('无法访问iframe文档。'); } } else { console.error('未找到iframe元素。'); } }; function removeOldDepositTime(iframeDocument) { // 获取所有的

标签 const paragraphs = iframeDocument.getElementsByTagName('p'); // 遍历每一个

标签 for (let i = 0; i < paragraphs.length; i++) { const p = paragraphs[i]; // 检查当前

标签是否同时包含“定金时间”和“尾款时间” if (p.textContent.includes('定金时间') && p.textContent.includes('尾款时间')) { // 检查是否包含prepayTime内的所有中文文本内容 let allTimesPresent = true; for (const time in prepayTime) { if (!p.textContent.includes(prepayTime[time])) { allTimesPresent = false; break; } } // 如果不包含所有的时间信息,则移除这个

标签 if (!allTimesPresent) { p.parentNode.removeChild(p); } } } } function qyeryIframeForId(activateElementId) { const activateElement = document.querySelector(`#${activateElementId} .link-node-hover-text-container`); if (activateElement) { activateElement.click(); activateElement.focus(); return document.querySelector(`#${activateElementId} .tox-edit-area iframe`); } else { console.error('未找到激活元素。'); return null; } }; const removeDataProcessed = doc => { const replaceElements = doc.querySelectorAll('[data-replace="true"]'); replaceElements.forEach(element => { const parentElement = element.parentElement; if (parentElement.tagName.toLowerCase() === 'p') { // 检查

标签是否只有一个子元素,并且是当前的 const hasOnlySpanChild = parentElement.children.length === 1 && parentElement.children[0] === element; // 获取父

元素的纯文本内容(不包括子元素) const parentText = parentElement.textContent.trim(); if (hasOnlySpanChild && parentText === '无效内容') { // 如果

标签没有其他文本内容,移除整个

标签 parentElement.remove(); } else { // 否则,清空 的文本内容 element.textContent = ''; } } else { // 如果父元素不是

,清空 的文本内容 element.textContent = ''; } }); }; // 规格首行非sku描述行蓝色 const skuDescFirstLineBlue = doc => { const firstPTag = doc.querySelector('#tinymce p'); if (firstPTag) { if (!check_skuDescFirstLine.test(firstPTag.textContent)) { applyColor(firstPTag, colorLibrary.blue); } const spanTags = firstPTag.querySelectorAll('span'); spanTags.forEach(spanTag => { if (!check_skuDescFirstLine.test(firstPTag.textContent)) { applyColor(spanTag, colorLibrary.blue); } }); } }; // 到手价数字行红色 const modifyFirstPTagAndSpans = doc => { const p = doc.querySelector('#tinymce p'); if (!p) return; const innerHTML = p.innerHTML; let newInnerHTML = ''; let firstMatched = false; // 标志是否已经处理了第一个匹配 // 先按照标签进行分割 const spanParts = innerHTML.split(/(]*>.*?<\/span>)/); spanParts.forEach(spanPart => { if (spanPart.match(/^]*>.*?<\/span>$/)) { // 如果是标签包裹的部分,直接添加到 newInnerHTML newInnerHTML += spanPart; } else { // 处理不包含的部分 const parts = spanPart.split(/(
| )/); parts.forEach(part => { if (part.match(/(
| )/)) { // 如果是
或 ,直接添加到 newInnerHTML newInnerHTML += part; } else { let styledPart = part; if (!firstMatched && numericRegex.test(part)) { // 只对第一个匹配的部分进行处理 const match = part.match(numericRegex); if (match) { const span = document.createElement('span'); span.innerHTML = match[0]; applyColor(span, colorLibrary.red); // 替换第一个匹配的部分 styledPart = part.replace(numericRegex, span.outerHTML); firstMatched = true; // 设置标志 } } newInnerHTML += styledPart; } }); } }); p.innerHTML = newInnerHTML; // 旧方案 const firstPTag = doc.querySelector('#tinymce p'); if (firstPTag) { if (numericRegex.test(firstPTag.textContent)) { applyColor(firstPTag, colorLibrary.red); } const spanTags = firstPTag.querySelectorAll('span'); spanTags.forEach(spanTag => { if (numericRegex.test(spanTag.textContent)) { applyColor(spanTag, colorLibrary.red); } }); } }; function isNotIframeChineseName(text) { // 定义需要比较的内容数组 const contents = [ "商品标题", "规格信息", "直播价", "直播玩法/优惠方式", "预设库存", "现货库存" ]; // 遍历数组寻找匹配项 for (let i = 0; i < contents.length; i++) { if (text === contents[i]) { // 如果找到匹配项,返回其索引+1 return i + 1; } } // 如果没有找到匹配项,返回0 return 0; } // 检查到手价是否包含预售字样 function check_isHavePreSaleContent(idName = 'livePrice') { // const livePriceDoc = document.querySelector(`#livePrice`); var livePriceDoc = document.getElementById(idName); if (livePriceDoc) { const liveIframe = livePriceDoc.querySelector('iframe') if (liveIframe) { const liveIframeDocument = liveIframe.contentDocument || liveIframe.contentWindow.document; const body = liveIframeDocument.body; if (body && !isNotIframeChineseName(body.innerText)) { livePriceDoc = body; } } const currentHTML = livePriceDoc.innerText; if (currentHTML.includes('定金') || currentHTML.includes('尾款')) { // console.log('到手价包含预售字样'); return true; } else { // console.log('到手价不包含预售字样'); return false; } } } function check_isHavePreSale_havePreSale(iframeDocument) { const iframe = iframeDocument.querySelector('iframe'); var body = iframeDocument.body; if (iframe) { const iframeDocument = iframe.contentDocument || iframe.contentWindow.document; if (iframeDocument.body && !isNotIframeChineseName(iframeDocument.body.innerText)) { body = iframeDocument.body; } } // 获取当前的 body 内的 HTML 内容 const currentHTML = body.innerHTML; if (currentHTML.includes('预售')) { return true; } else { return false; } } function addContent_PreSale(iframeDocument) { // 获取 元素 const body = iframeDocument.body; // 获取当前的 body 内的 HTML 内容 const currentHTML = body.innerHTML; // 在当前 HTML 内容后面添加换行符和 "预售" 二字 const updatedHTML = currentHTML + `
预售`; // 将更新后的 HTML 设置回 body 内 body.innerHTML = updatedHTML; } function addContent_PreSaleTime(iframeDocument) { // 获取 元素 const body = iframeDocument.body; // 获取当前的 body 内的 HTML 内容 const currentHTML = body.innerHTML; // 在当前 HTML 内容后面预售时间信息 const updatedHTML = currentHTML + replacementMap.定金尾款时间; // 将更新后的 HTML 设置回 body 内 body.innerHTML = updatedHTML; } // 预设库存样式修改 const handlePreSetInventoryStyles = doc => { function check_content(content) { if (!numericRegex.test(content)) { if (content.includes('不可控')) { return false; } else { return true; } } else { return false; } } const pTags = doc.querySelectorAll('#tinymce p'); pTags.forEach(pTag => { if (check_content(pTag.textContent)) { pTag.textContent = '拉满'; const spanTags = pTag.querySelectorAll('span'); spanTags.forEach(spanTag => { if (check_content(spanTag.textContent)) { spanTag.textContent = '拉满'; } }); } }); }; // 现货库存样式修改 const handleInventoryStyles = doc => { let firstPTagFound = false; const pTags = doc.querySelectorAll('#tinymce p'); pTags.forEach(pTag => { // 获取

标签内的所有文本内容,并将连续的   转换为
let content = pTag.innerHTML.replace(/( )+/g, '无效内容
'); // 获取

标签内的所有文本内容,并按
标签分割成数组 const segments = content.split('
'); // 处理每个分割后的段落 segments.forEach((segment, index) => { // 创建临时容器元素以便于操作 HTML 字符串 const tempContainer = document.createElement('div'); tempContainer.innerHTML = segment; // 获取段落的纯文本内容 const segmentText = tempContainer.textContent; if (!firstPTagFound && segmentText.includes('预售')) { firstPTagFound = true; } // 创建新的

标签用于包裹分隔后的段落 const newPTag = document.createElement('p'); newPTag.innerHTML = segment; if (numericRegex.test(segmentText) || segmentText.includes('--')) { applyColor(newPTag, colorMaps.inventory.default); } else { if (firstPTagFound) { applyColor(newPTag, colorMaps.inventory.color2); } else { applyColor(newPTag, colorMaps.inventory.color1); } } // 在原

标签位置插入新的

标签 pTag.parentNode.insertBefore(newPTag, pTag); }); // 移除原始的

标签 pTag.parentNode.removeChild(pTag); }); }; function autoWriteAvgPrice(iframeDocument) { const ps = iframeDocument.querySelectorAll('p'); // 更新检测输入格式的正则表达式,支持"?40/" 或 "?30/"以及"//"结构 const pattern = /^(.*(:|:))?\d+(\.\d+)?(((\?|\?)\d+\/?)?(\/?\/\d+(\.\d+)?[^\d/\*]+)?)?(\/\d+(\.\d+)?[^\d/\*]+|[*]\d+(\.\d+)?[^\d/\*]+)*$/; ps.forEach(p => { if (p.querySelector('span')) { // 情况 1: p 标签内有 span 标签,需要处理 span 内的文本 processSpans(p, pattern); } else { // 情况 2: 只有 p 标签,没有嵌套的 span 标签 let newInnerHTML = ''; // 分割HTML内容 const parts = p.innerHTML.split(/(
| )/); parts.forEach(part => { let styledPart = part; // 检查part是否符合格式 if (pattern.test(part)) { // 调用parseInput来解析part并生成新内容 const { prefix, price, rex, num, units } = parseInput(part); const newContent = generateOutput(prefix, price, rex, num, units); styledPart = newContent; // 将解析后的结果替换原内容 } newInnerHTML += styledPart; // 拼接处理后的部分 }); // 更新p元素的内容 p.innerHTML = newInnerHTML; } }); function processSpans(element, pattern) { const spans = element.querySelectorAll('span'); spans.forEach(span => { const textContent = span.textContent; // 检查textContent是否符合格式 if (pattern.test(textContent)) { // 调用parseInput来解析textContent并生成新内容 const { prefix, price, rex, num, units } = parseInput(textContent); const newContent = generateOutput(prefix, price, rex, num, units); // 更新span的内容 span.innerHTML = newContent; } }); } } // 定义 parseInput 函数,用于解析输入 function parseInput(input) { // 更新正则表达式,先匹配价格和特殊的 "?40/" 或 "?30/" 结构,后面匹配 "/*" 的单位结构 const prefixPatt = /^.*(:|:)/; // 匹配前缀内容 const cleanedInput = input.replace(prefixPatt, '').trim(); // 移除匹配了的前缀内容 const pricePattern = /^\d+(\.\d+)?/; // 匹配开头的价格 const questionPattern = /(\?|\?)\d+\/?/; // 匹配 "?40/" 或 "?30/" 结构 const unitPattern = /(\/\/?|[*])(\d+(\.\d+)?)([^\d/\*]+)/g; // 匹配剩下的部分 // 捕获开头的价格 const priceMatch = cleanedInput.match(pricePattern); const price = priceMatch ? parseFloat(priceMatch[0]) : null; // 捕获前缀内容 const prefixMatch = input.match(prefixPatt); const prefix = prefixMatch ? prefixMatch[0].slice(0, -1) : ''; let rex = []; let num = []; let units = []; // 匹配 "?40/" 或 "?30/" 结构,并存入 rex const specialMatch = cleanedInput.match(questionPattern); if (specialMatch) { rex.push(specialMatch[0]); // 完整存储 "?40/" 或 "?30/" } // 匹配剩下的部分:形如 "/* 数字 单位" const matches = cleanedInput.match(unitPattern); if (matches) { matches.forEach((match, index) => { const [, symbol, number, , unit] = match.match(/(\/\/?|[*])(\d+(\.\d+)?)([^\d/\*]+)/); rex.push(symbol); let quantity = parseFloat(number); if (symbol === "*" && index > 0) { quantity *= num[num.length - 1]; } num.push(quantity); units.push(unit.trim()); }); } return { prefix, price, rex, num, units }; } // 定义 generateOutput 函数,用于生成输出内容 function generateOutput(prefix, price, rex, num, units) { let prefixContent = ''; if (prefix !== '') { prefixContent = `${prefix}:`; } if (rex.length === 0) { return prefixContent + price; } const fristRex = rex[0]; let output = `到手共${num[0]}${units[0]}
`; // 判断第一个 rex 是否是 "/" if (fristRex != "/") { // 如果 fristRex 是 "//",处理特定逻辑 if (fristRex == '//') { prefixText = prefixContent; priceText = `${price}`; output = prefixText + priceText + "

" + output; } // 使用正则表达式判断 fristRex 是否为 "?40/" 或 "?30/" 类似结构 const questionPattern = /^(\?|\?)\d+\/?$/; // 使用正则表达式直接提取数字部分,默认返回"0" const depositPrice = parseFloat(fristRex.match(/^(\?|\?)(\d+)\/?$/)?.[2] || "0"); // 如果 fristRex 匹配 "?40/" 或 "?30/" 结构,生成定金和尾款部分 if (questionPattern.test(fristRex)) { const finalPayment = (price - depositPrice).toFixed(2).replace(/\.?0+$/, ""); // 计算尾款,并保留两位小数 if (rex.length > 1) { prefixText = prefixContent; priceText = `${price}`; finalPalnText = `定金${depositPrice}+尾款${finalPayment}`; output = prefixText + priceText + "
" + finalPalnText + "

" + output; } else { prefixText = prefixContent; priceText = `${price}`; finalPalnText = `定金${depositPrice}+尾款${finalPayment}`; output = prefixText + priceText + "
" + finalPalnText + "
"; return output; } } } // 处理每个单位的平均价格 for (let i = 0; i < num.length; i++) { let avgPrice = (price / num[i]).toFixed(2).replace(/\.?0+$/, ""); // 计算结果并去掉末尾多余的零 output += `平均每${units[i]}${avgPrice}
`; if (i < num.length - 1) { output += `到手共${num[i + 1]}${units[i + 1]}
`; } } // 去除末尾多余的
output = output.replace(/
$/, ""); return output; } function buttonClickForAddPreSaleTime() { var iframe; // 用于存储临时的 iframe iframe = qyeryIframeForId('goodsName'); var iframeDocument_goodsName = iframe.contentDocument || iframe.contentWindow.document; if (iframeDocument_goodsName && !check_isHavePreSale_havePreSale(iframeDocument_goodsName)) { addContent_PreSale(iframeDocument_goodsName); } iframe = qyeryIframeForId('liveGameplay'); var iframeDocument_liveGameplay = iframe.contentDocument || iframe.contentWindow.document; if (iframeDocument_liveGameplay) removeOldDepositTime(iframeDocument_liveGameplay); if (iframeDocument_liveGameplay && !check_isHavePreSaleContent('liveGameplay')) { addContent_PreSaleTime(iframeDocument_liveGameplay); } } /* 计算器功能区 */ const calculate = [ { regex: /折扣力度.*?(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/, replaceFunc: (text, result) => { // 替换文本中的折扣内容 let updatedText = text.replace(/(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/, `${result}`); // 确保结果前有一个“约”字,并且前面有“:”或“:” if (!updatedText.includes('约')) { // 检查是否已有“:”或“:”,防止重复添加 if (!updatedText.includes(':') && !updatedText.includes(':')) { updatedText = updatedText.replace(/(折扣力度.*?)(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/, `$1:约${result}`); } else { updatedText = updatedText.replace(/(折扣力度.*?)(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/, `$1约${result}`); } } else { updatedText = updatedText.replace(/(:约|:约)?(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))/, `:约${result}`); } // 确保结果后面有一个“折”字 if (!updatedText.endsWith('折')) { updatedText += '折'; } return updatedText; }, decimalPlaces: 1, multiplier: 10, trimTrailingZeros: true }, { regex: /.*?(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))==/, replaceFunc: (text, result) => text.replace(/(\d+[\d+\-*/().]*\d*|\([\d+\-*/().]+\))==/, `${result}`), decimalPlaces: 2, multiplier: 1, trimTrailingZeros: true }, ]; // 计算表达式的函数 const calculateExpression = (expression, decimalPlaces = 2, multiplier = 1, trimTrailingZeros = false) => { try { let result = eval(expression); // 注意:eval() 存在安全性问题,确保传入的表达式是安全的。 result = result * multiplier; // 放大结果 let formattedResult = result.toFixed(decimalPlaces); // 保留指定的小数位数 // 根据参数决定是否去除末尾的零 if (trimTrailingZeros) { formattedResult = parseFloat(formattedResult).toString(); } return formattedResult; } catch (e) { console.error('表达式计算错误:', e); return expression; // 如果计算错误,返回原表达式 } }; const findAndCalculateExpressions = (iframeDocument, calculate) => { const discountElements = iframeDocument.querySelectorAll('p, span'); discountElements.forEach(element => { let text = element.textContent.replace(/。/g, '.'); // 替换所有中文小数点为英文小数点 text = text.replace(/(/g, '(').replace(/)/g, ')'); // 替换中文括号为英文括号 calculate.forEach(({ regex, replaceFunc, decimalPlaces, multiplier, trimTrailingZeros }) => { const match = text.match(regex); // console.log(match); if (match) { const expression = match[1]; // 检查是否为“折扣力度”的正则表达式 if (regex.source.includes('折扣力度')) { if (/[+\-*/()]/.test(expression)) { // 如果表达式包含运算符,进行计算 const result = calculateExpression(expression, decimalPlaces, multiplier, trimTrailingZeros); text = replaceFunc(text, result); } else { // 如果表达式不包含运算符,直接使用替换函数处理 text = replaceFunc(text, expression); } } else { // 其他情况照常处理 // 检查表达式是否包含运算符 if (/[+\-*/()]/.test(expression)) { const result = calculateExpression(expression, decimalPlaces, multiplier, trimTrailingZeros); text = replaceFunc(text, result); } } element.textContent = text; } }); }); }; // 新增控制功能 // 支持单个元素内容的着色 // 封装函数返回包含SVG图标的div function createMarioSVGIconWrapper(id, isClick = true, size = 14) { // 创建一个 div 容器 var divWrapper = document.createElement('div'); divWrapper.className = 'svg-icon-wrapper'; // 添加一个类名,便于查找和样式控制 divWrapper.style.cssText = 'align-items: center; cursor: pointer; display: none;'; // 样式控制'; // 设置 div 的 id if (id) { divWrapper.id = id; } // 创建 SVG 图标 var svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgIcon.setAttribute('class', 'icon custom-mario-svg'); // 添加自定义类名 svgIcon.setAttribute('viewBox', '0 0 1024 1024'); svgIcon.setAttribute('width', size); svgIcon.setAttribute('height', size); svgIcon.innerHTML = ''; svgIcon.style.cssText = 'vertical-align: middle;'; // 垂直居中样式 // 将 SVG 添加到 div 容器中 divWrapper.appendChild(svgIcon); if (isClick) { // 根据 id 绑定点击事件 divWrapper.addEventListener('click', function () { // 提取 id 中的 suffix 部分 var idSuffix = id.replace('svg-icon-', ''); // 根据 id 调用对应的函数 switch (id) { case 'svg-icon-goodsName': activateIframeAndModifyStyles('goodsName'); showNotification("商品名-着色成功", 3000); break; case 'svg-icon-skuDesc': activateIframeAndModifyStyles('skuDesc'); showNotification("商品规格-着色成功", 3000); break; case 'svg-icon-livePrice': activateIframeAndModifyStyles('livePrice'); // 判断“预售信息”,辅助自动输入定金尾款时间 if (check_isHavePreSaleContent()) { buttonClickForAddPreSaleTime(); } showNotification("直播价-着色成功", 3000); break; case 'svg-icon-liveGameplay': activateIframeAndModifyStyles('liveGameplay'); showNotification("直播玩法-着色成功", 3000); break; case 'svg-icon-preSetInventory': activateIframeAndModifyStyles('preSetInventory'); showNotification("预设库存-着色成功", 3000); break; case 'svg-icon-inventory': activateIframeAndModifyStyles('inventory'); showNotification("实际库存-着色成功", 3000); break; default: break; } // 仅当 idSuffix 不在数组中时才添加 if (!isMarioShow.includes(idSuffix)) { isMarioShow.push(idSuffix); } }); } else { divWrapper.style.display = 'flex'; divWrapper.className = 'svg-icon-wrapper-no-data'; } return divWrapper; } // 查找表格中的目标单元格并添加SVG图标 function addSVGToSpecificTDs() { // 获取 class="card-content-container" 内的表格 var container = document.querySelector('.card-content-container'); if (!container) return; var table = container.querySelector('table'); if (!table) return; var tbody = table.querySelector('tbody'); if (!tbody) return; // 获取 tbody 内的第二个 tr var secondTR = tbody.querySelectorAll('tr')[1]; // 获取第二个 tr if (!secondTR) return; // 获取第二个 tr 中的所有 td var tds = secondTR.querySelectorAll('td'); var idMap = { "商品名": "svg-icon-goodsName", "规格": "svg-icon-skuDesc", "直播间到手价": "svg-icon-livePrice", "优惠方式": "svg-icon-liveGameplay", "预设库存": "svg-icon-preSetInventory", "现货库存": "svg-icon-inventory" }; // 文本内容与ID的映射 tds.forEach(function (td) { // 检查 td 的文本内容是否在目标文本内容列表中 var span = td.querySelector('.link-node-container > span'); if (span && idMap.hasOwnProperty(span.textContent.trim())) { // 检查是否已经存在封装的 SVG 图标,避免重复添加 if (!td.querySelector('.svg-icon-wrapper')) { // 获取对应的 id var id = idMap[span.textContent.trim()]; // 创建包含 SVG 图标的 div 容器并设置 id var svgWrapper = createMarioSVGIconWrapper(id); // 将 SVG 容器插入到 span 之后 span.parentNode.insertAdjacentElement('afterend', svgWrapper); } } }); } // 初始化存储被点击事件的数组 var isMarioShow = []; // 函数:控制每个 divWrapper 的显示状态 function updateDivWrapperDisplay(isShow) { // 获取所有 class 为 'svg-icon-wrapper' 的元素 const divWrappers = document.querySelectorAll('.svg-icon-wrapper'); // 遍历所有 divWrapper for (const divWrapper of divWrappers) { if (isShow) { divWrapper.style.display = 'flex'; } else { // 获取该 divWrapper 的 id var wrapperId = divWrapper.id; // 检查是否存在于 isMarioShow 数组中 if (isMarioShow.includes(wrapperId.replace('svg-icon-', ''))) { divWrapper.style.display = 'flex'; } else { divWrapper.style.display = 'none'; } } } } /* 淘宝、天猫主图复制到剪贴板功能 */ function createGetTmallPngButton() { // 找到匹配的元素的编号 function findMatchingIndex(wrapperClass, imgClass) { for (let i = 0; i < wrapperClass.length; i++) { const wrapper = document.querySelector(wrapperClass[i]); if (wrapper) { const img = wrapper.querySelector(imgClass[i]); // 找到图片元素 const button = wrapper.querySelector('#button_getTmallPngButton'); // 找到按钮元素 if (img && !button) { return i; // 返回匹配的编号 } else { return -1; // 如果按钮已存在,则返回 -1 } } } return -1; // 如果没有找到匹配的元素,则返回 -1 } const wrapperClass = ['.itemImgWrap--bUt5RRLT', '.PicGallery--mainPicWrap--juPDFPo', '.mainPicWrap--Ns5WQiHr', '.PicGallery--mainPicWrap--1c9k21r', '.item-gallery-top.item-gallery-prepub2']; const imgClass = ['.itemImg--O9S7hs0i', '.PicGallery--mainPic--34u4Jrw', '.mainPic--zxTtQs0P', '.PicGallery--mainPic--1eAqOie', '.item-gallery-top__img']; const matchingIndex = findMatchingIndex(wrapperClass, imgClass); if (matchingIndex !== -1) { addButton(wrapperClass, imgClass, matchingIndex); addButton(wrapperClass, imgClass, 0); } else { // console.error('Wrapper element not found.'); } function addButton(wrapperClass, imgClass, matchingIndex) { const wrapper = document.querySelector(wrapperClass[matchingIndex]); console.log("wrapper:", wrapper); const old_button = wrapper.querySelector('#button_getTmallPngButton'); // 找到按钮元素 if (old_button) { return; // 如果按钮已存在,则直接返回 } if (wrapper) { const button = document.createElement('button'); button.textContent = '复制图片'; button.id = 'button_getTmallPngButton'; button.style.cssText = ` position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 5px 20px; font-size: 16px; background-color: rgba(22, 22, 23, .7); color: #fff; border: none; border-radius: 999px; font-family: AlibabaPuHuiTi_2_55_Regular; backdrop-filter: saturate(180%) blur(20px); /* 添加模糊效果 */ -webkit-backdrop-filter: blur(20px); /* 兼容Safari浏览器 */ text-align: center; /* 文本居中显示 */ cursor: pointer; opacity: 0; transition: opacity 0.3s ease, color 0.15s ease, background-color 0.25s ease;; z-index: 999; `; // 控制按钮显示 wrapper.addEventListener('mouseenter', () => { button.style.opacity = '1'; }); // 控制按钮隐藏 wrapper.addEventListener('mouseleave', () => { button.style.opacity = '0'; }); button.addEventListener('click', async () => { const img = wrapper.querySelector(imgClass[matchingIndex]); // console.log("img:", img); if (img) { try { const imageUrl = img.src; const response = await fetch(imageUrl); const blob = await response.blob(); const image = new Image(); image.src = URL.createObjectURL(blob); image.onload = () => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = image.width; canvas.height = image.height; ctx.drawImage(image, 0, 0); canvas.toBlob(async (blob) => { try { await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })]); showNotification("图片已成功复制到剪贴板", undefined, true); button.textContent = '复制成功'; button.style.backgroundColor = 'rgba(233, 233, 233, .7)'; // 按钮颜色改变 button.style.color = '#000'; // 按钮文字颜色改变 setTimeout(() => { button.textContent = '复制图片'; button.style.backgroundColor = 'rgba(22, 22, 23, .7)'; // 按钮颜色恢复 button.style.color = '#fff'; // 按钮文字颜色恢复 }, 1500); // 1.5秒后恢复按钮文字 // alert('Image copied to clipboard!'); } catch (error) { console.error('Failed to copy image to clipboard:', error); // alert('Failed to copy image to clipboard.'); showNotification('图片复制失败!'); } }, 'image/png'); }; } catch (error) { showNotification('图片复制失败!'); console.error('Failed to fetch or process image:', error); // alert('Failed to copy image to clipboard.'); } } else { // alert('Image not found!'); } }); wrapper.style.position = 'relative'; // 确保按钮在图片上层 wrapper.appendChild(button); } } } /* 用于主播排序的辅助函数 */ // 封装处理和生成多维数组数据的函数 function generateJsonFromText(textInput) { // 简写与全称的对应表 const shorthandToFull = { "野": "小野", "月": "小月", "霸": "小霸王", "迎": "小迎", "京": "京京", "祖": "阿祖", "凯": "凯子", "空": "悟空", }; // 处理文本,去除“+”及其后的内容 // const processText = (text) => text.split('+')[0].trim(); const processText = (text) => { let result = ''; // 首先移除“+”及其后的内容 const firstPart = text.split('+')[0]; // 遍历firstPart的每个字符 for (let char of firstPart) { // 如果字符是shorthandToFull的键,则添加到结果中 if (shorthandToFull.hasOwnProperty(char)) { result += char; } } // 返回处理后的文本 return result.trim(); }; // 将简写转换为全称 const getFullNames = (text) => { return text.split('').map(ch => shorthandToFull[ch] || ch); }; // 生成多维数组格式数据 const result = []; // 示例输入 [1][0][0] // 解释:第一个位置存储多个主播的排列组合,第二个位置0存储主播名字,其余位置存储其rowIndex值,第三个位置用于读取主讲或副讲 // 获取主讲 resultArray[2][0][0]; // 获取副讲 resultArray[2][0][1]; // 获取其列 resultArray[2][i] const texts = textInput.trim().split('\n'); texts.forEach((text, index) => { const processedText = processText(text); const fullNamesArray = getFullNames(processedText); // 查找是否已存在相同的 fullNamesArray const existingEntry = result.find(entry => { return JSON.stringify(entry[0]) === JSON.stringify(fullNamesArray); }); if (existingEntry) { // 如果存在相同的组合,追加索引 existingEntry.push(index); } else { // 如果不存在,创建一个新的组合 result.push([fullNamesArray, index]); } }); return result; } // 页面控制函数 function itemPageScroll(height, addScroll = true) { return new Promise((resolve) => { // .rc-virtual-list-holder const viewport = document.querySelector('.ag-body-vertical-scroll-viewport'); // 获取页面滚动区域 if (addScroll) { if (height != 0) { viewport.scrollTop += height; // 向下滚动一屏 } else { viewport.scrollTop = 0; // 回到顶部 } } else { viewport.scrollTop = height; // 直接滚动到指定位置 } console.log('scrolling to', viewport.scrollTop); // 打印当前滚动高度 // 通过 setTimeout 来模拟等待页面加载完成 setTimeout(() => { resolve(); // 滚动完成后继续执行 }, 800); // 延迟时间可以根据实际加载时间调整 }); } // 商品选择函数 function selectItemForRowIndex(rowIndex, retries = 5, delay = 500) { return new Promise((resolve, reject) => { // 找到带有指定 row-index 的 div const targetDiv = document.querySelector(`div[row-index="${rowIndex}"]`); // 在 targetDiv 内查找 col-id="choice" 的元素 if (targetDiv) { const choiceElement = targetDiv.querySelector('div[col-id="choice"]'); // 在 choiceElement 内找到唯一的 input 元素 if (choiceElement) { const inputElement = choiceElement.querySelector('input'); if (inputElement) { inputElement.click(); // 点击 input 元素 // console.log(`Selected item for row-index="${rowIndex}"`); resolve(); // 选择完成后继续执行 } else { // input 元素未找到的情况 retryOrReject(`未找到 input 元素在 col-id="choice" 的元素内`); } } else { // console.log(`未找到 col-id="choice" 的元素在 row-index="${rowIndex}" 的 div 内`); retryOrReject(`未找到 col-id="choice" 的元素在 row-index="${rowIndex}" 的 div 内`); } } else { // console.log(`未找到 row-index="${rowIndex}" 的 div`); retryOrReject(`未找到 row-index="${rowIndex}" 的 div`); } function retryOrReject(errorMessage) { if (retries > 0) { setTimeout(() => { // 递归调用自己,并减少重试次数 selectItemForRowIndex(rowIndex, retries - 1, delay).then(resolve).catch(reject); }, delay); } else { reject(errorMessage); // 达到最大重试次数后,返回错误 } } }); } // 模拟鼠标点击,激活主播选择框 // 示例调用:点击 "主讲主播" 的选择框 // clickSelectByTitle("主讲主播"); // 示例调用:点击 "副讲主播" 的选择框 // clickSelectByTitle("副讲主播"); async function clickSelectByTitle(title, retries = 5, delay = 500) { // 重试机制,最多重试 `retries` 次,每次等待 `delay` 毫秒 for (let i = 0; i < retries; i++) { const labelElement = document.querySelector(`label[title="${title}"]`); if (labelElement) { const parentElement = labelElement.parentElement; if (parentElement && parentElement.parentElement) { const selectSelector = parentElement.parentElement.querySelector('.ant-select-selector'); if (selectSelector) { // 模拟点击 const clickEvent = new MouseEvent('mousedown', { bubbles: true, cancelable: true }); selectSelector.dispatchEvent(clickEvent); // 模拟点击事件 // console.log(`已激活并点击 ${title} 对应的选择框`); return; // 成功找到并点击后直接返回 } else { // console.log(`未找到 ${title} 对应的 .ant-select-selector 元素`); } } else { // console.log(`无法获取到 ${title} 的父元素`); } } else { // console.log(`未找到 title 为 "${title}" 的 label 元素`); } // 如果没找到,等待一段时间再重试 if (i < retries - 1) { // console.log(`重试 ${i + 1}/${retries} 次后等待 ${delay} 毫秒...`); await new Promise(resolve => setTimeout(resolve, delay)); } } // 如果所有重试都失败了,抛出一个错误 throw new Error(`无法找到 title 为 "${title}" 的元素。`); } // 选择指定的主播 function selectAnchor(anchor, primary = true) { return new Promise((resolve, reject) => { // 根据 primary 参数决定目标容器的选择器 const targetDiv = primary ? '#primaryAnchor_list' : '#assistantAnchor_list'; // 获取视窗元素 const viewFather = document.querySelector(targetDiv).parentElement; const viewport = viewFather.querySelector('.rc-virtual-list-holder'); // 定义一个异步函数来执行循环操作 (async function trySelect() { for (let attempt = 0; attempt < 4; attempt++) { // 查找目标选项 const targetOption = `.ant-select-item[title="${anchor}"]`; const optionElement = document.querySelector(targetDiv).parentElement.querySelector(targetOption); if (optionElement) { // 如果找到选项,则点击并完成操作 optionElement.click(); // console.log(`已选择 ${anchor} 主播`); resolve(); return; // 结束函数 } // 如果没有找到,滚动视窗 viewport.scrollTop += 256; // console.log(`未找到 ${anchor} 主播,正在尝试第 ${attempt + 1} 次滚动`); // 等待一点时间以让页面加载新内容 await new Promise(r => setTimeout(r, 500)); } // 如果经过多次尝试仍未找到,抛出错误或处理异常 // console.log(`未能找到 ${anchor} 主播,已尝试 ${4} 次`); reject(new Error(`未能找到 ${anchor} 主播`)); })(); }); } // 点击“计划主播排班” function clickScheduleButton() { return new Promise((resolve) => { const scheduleButtonClassName = '.ant-btn.css-9fw9up.ant-btn-default.primaryButton___N3z1x' clickButton(true, 0, document, scheduleButtonClassName, '计划主播排班'); resolve(); }); } // 点击“排班页面”的“确定”按钮 function clickConformButtonForSchedule() { return new Promise((resolve) => { const scheduleClassName = '.ant-modal-content'; const conformButtonClassName = '.ant-btn.css-9fw9up.ant-btn-primary'; clickButton(true, 0, scheduleClassName, conformButtonClassName); resolve(); }); } let itemBlockHeight = 100; // item 块高度,可根据实际情况调整 async function processItems() { // 返回输入文本中对应的商品个数 function countAllItemNum(resultArray) { var countNum = 0; for (var i = 0; i < resultArray.length; i++) { countNum += resultArray[i].length - 1; } // console.log('countNum:', countNum); return countNum; } // 返回当前已经排序的最大商品序号 function getMaxForScheduledItemIndex() { if (scheduledItems.length === 0) { return 0; } // 对已排班的商品序号进行排序 scheduledItems.sort((a, b) => a - b); // 遍历数组,找到最小的缺失序号 for (let i = 0; i < scheduledItems.length; i++) { if (scheduledItems[i] !== i) { // console.log('Missing index:', i); return i; // 一旦发现某个序号不连续,返回这个序号 } } // 如果所有序号都连续,则返回下一个未使用的序号 return scheduledItems.length; } let scheduledItems = []; // 已排班的商品序号 let rounder = 0; // 轮次计数器 try { const elements = document.getElementsByClassName('fontLinkd-[#333_20_20_Bold]'); const textContent = elements[0].innerText || elements[0].textContent; const countItem = parseInt(textContent, 10); // link上的商品总数 // 原生浏览器弹窗提示 // const textInput = prompt('请输入主播排班表格内容,一行对应一个商品'); const textInput = await createDropdownModal(dropdownContainer, '主播排序'); const resultArray = generateJsonFromText(textInput); // console.log(resultArray); // 商品数检查 if (countAllItemNum(resultArray) > countItem) { click_itemSort_anchorSort(); setTimeout(() => { showNotification('输入了过多的主播,请检查后重新输入!'); }, 1500); return; } while (rounder < resultArray.length) { if (!itemSort_anchorSort.getDivButtonState()) return; // 跳出循环,如果主播排序未打开,则不执行任何操作 await itemPageScroll(itemBlockHeight * getMaxForScheduledItemIndex(), false); // 回到合适的位置或许是顶部 showNotification('正在处理第 ' + (rounder + 1) + '/' + resultArray.length + ' 轮次 ' + loadImageIcon(), 0); await new Promise(resolve => setTimeout(resolve, 500)); // 等待500毫秒,可根据需要调整 let index = 1; let checkCount = 0; for (let i = getMaxForScheduledItemIndex(); i < countItem; i++, checkCount++) { if (!itemSort_anchorSort.getDivButtonState()) return; // 跳出循环,如果主播排序未打开,则不执行任何操作 if (resultArray[rounder][index] == i) { await selectItemForRowIndex(i); // 选择指定的行 scheduledItems.push(i); // 记录已排班的商品序号 index++; } if ((checkCount + 1) % 4 === 0) await itemPageScroll(itemBlockHeight * 4); // 每处理4行,滚动页面 // console.log('Index:', index, 'Length:', resultArray[rounder].length); if (index === resultArray[rounder].length) { // console.log('Executing scheduling...'); await new Promise(resolve => setTimeout(resolve, 500)); // 等待500毫秒,可根据需要调整 await clickScheduleButton(); await clickSelectByTitle("主讲主播"); await selectAnchor(resultArray[rounder][0][0], true); await clickSelectByTitle("副讲主播"); if (resultArray[rounder][0][1]) { await selectAnchor(resultArray[rounder][0][1], false); } await clickConformButtonForSchedule(); rounder++; break; // 跳出循环,继续处理下一个商品 } } // 确保整个循环内容都执行完再进入下一次迭代 await new Promise(resolve => setTimeout(resolve, 500)); // 等待500毫秒,可根据需要调整 } setTimeout(() => { click_itemSort_anchorSort(); }, 1500); showNotification('全部处理完成!'); } catch (error) { // 捕获任何异常,并显示错误通知 click_itemSort_anchorSort(); setTimeout(() => { showNotification('处理过程中出现错误!'); }, 1500); console.error('Error occurred:', error); } finally { // 可选的: 在所有操作完成后执行清理工作 // console.log('处理流程结束'); } } function click_itemSort_anchorSort() { document.getElementById('itemSort_anchorSort_divButton').click(); } // 输入弹窗 function createDropdownModal(dropdownContainer, titleText) { return new Promise((resolve, reject) => { // 检查是否已有弹窗存在,如果有则移除 const existingModal = dropdownContainer.querySelector('.dropdown-modal'); if (existingModal) { dropdownContainer.removeChild(existingModal); } dropdownButton.style.display = 'none'; // 隐藏按钮 // 创建弹窗容器 var dropdownDivModal = document.createElement('div'); dropdownDivModal.classList.add('dropdown-modal'); // 添加一个类以便于识别 dropdownDivModal.style.cssText = ` position: absolute; top: 0; margin: 14px; width: 172px; height: 108px; background-color: rgba(233, 233, 233, 0.7); backdrop-filter: blur(8px) brightness(90%); border: 1px solid rgba(255, 98, 0, 0.25); border-radius: 10px; box-sizing: border-box; display: flex; flex-direction: column; z-index: 3; transform-origin: top center; `; // 创建标题行 const title = document.createElement('div'); title.textContent = titleText || '弹窗标题'; title.style.cssText = ` padding: 8px 10px; font-size: 14px; font-weight: bold; color: rgb(51, 51, 51); border-bottom: 0px solid #ccc; text-align: left; flex-shrink: 0; `; dropdownDivModal.appendChild(title); // 创建富文本框 const textarea = document.createElement('textarea'); textarea.style.cssText = ` width: calc(100% - 20px); background-color: rgba(249, 249, 249, 0.7); height: 30px; margin: 0px 10px; padding: 5px; font-size: 12px; border: 0px solid #ccc; border-radius: 4px; resize: none; line-height: 1.2; box-sizing: border-box; flex-grow: 1; `; dropdownDivModal.appendChild(textarea); // 创建按钮容器 const buttonContainer = document.createElement('div'); buttonContainer.style.cssText = ` display: flex; justify-content: space-between; padding: 8px 10px; border-top: 0px solid #ccc; flex-shrink: 0; `; // 创建“取消”按钮 const cancelButton = document.createElement('button'); cancelButton.textContent = '取消'; cancelButton.style.cssText = ` padding: 3px 8px; font-size: 12px; color: #fff; background-color: #f44336; border: none; border-radius: 5px; cursor: pointer; flex-basis: 48%; `; cancelButton.onclick = () => { dropdownContainer.removeChild(dropdownDivModal); dropdownButton.style.display = ''; // 恢复按钮 reject('用户取消了输入'); }; buttonContainer.appendChild(cancelButton); // 创建“确认”按钮 const confirmButton = document.createElement('button'); confirmButton.textContent = '确认'; confirmButton.style.cssText = ` padding: 3px 8px; font-size: 12px; color: #fff; background-color: #4CAF50; border: none; border-radius: 5px; cursor: pointer; flex-basis: 48%; `; confirmButton.onclick = () => { const textInput = textarea.value; dropdownContainer.removeChild(dropdownDivModal); dropdownButton.style.display = ''; // 恢复按钮 resolve(textInput); // 在确认时返回输入的内容 }; buttonContainer.appendChild(confirmButton); dropdownDivModal.appendChild(buttonContainer); dropdownContainer.appendChild(dropdownDivModal); }); } /* 补贴生成 */ function createSubsidyTextButton(isActivated = sonMain_subsidyText.getSwitchState()) { if (!isActivated) { return; } const targetClass = '[class*="ant-space"][class*="css-9fw9up"][class*="ant-space-horizontal"][class*="ant-space-align-center"]'; const subsidyText_observer = new MutationObserver((mutationsList, observer) => { for (let mutation of mutationsList) { if (mutation.type === 'childList') { const targetElement = document.querySelector(targetClass); if (targetElement) { if (document.querySelector('.subsidyText')) { subsidyText_observer.disconnect(); return; } var subsidyText = document.createElement('div'); subsidyText.classList.add('ant-space-item'); subsidyText.style.display = 'none'; var subsidyTextButton = document.createElement('button'); subsidyTextButton.textContent = '补贴生成'; subsidyTextButton.classList.add('ant-btn', 'css-9fw9up', 'ant-btn-default', 'subsidyText'); subsidyText.appendChild(subsidyTextButton); targetElement.insertBefore(subsidyText, targetElement.firstChild); subsidyTextButton.addEventListener('click', () => generateSubsidyText()); subsidyText_observer.disconnect(); break; } } } }); subsidyText_observer.observe(document.body, { childList: true, subtree: true }); } // 在页面上创建按钮 createSubsidyTextButton(); async function generateSubsidyText() { if (document.querySelector('.dropdown-modal')) { return; // 如果弹窗已存在,则不执行任何操作 } // 创建开关容器元素 const switchesContainer = document.createElement('div'); switchesContainer.classList.add('flex', 'items-center', 'justify-between', 'pb-12'); switchesContainer.style.cssText = 'position: fixed; top: 60px; right: 300px; transform: translateX(-50%); z-index: 9999; width: 200px;'; if (isTableCardURL()) { document.body.appendChild(switchesContainer); } const dropdownContainer = document.createElement('div'); dropdownContainer.style.cssText = 'position: relative; display: inline-block;'; switchesContainer.appendChild(dropdownContainer); // 调起浏览器原生的输入框,要求用户输入1~999之间的数字 let red_value = prompt("请输入1到999之间的数字:"); // let red_value = await createDropdownModal(dropdownContainer, '补贴生成'); // 检查输入是否为有效的数字,并且在1到999之间 if (red_value !== null) { // 用户没有点击取消 red_value = parseInt(red_value, 10); // 将输入转换为整数 if (isNaN(red_value) || red_value < 1 || red_value > 999) { alert("请输入1到999之间的有效数字!"); // 递归调用函数,让用户重新输入 generateSubsidyText(); } else { console.log("输入的有效数字是:", red_value); // 继续处理 testRedPacket = {}; // 初始化红包袋子 const new_docText = new DocText(); const itemId = new_docText.getCurrentProductId(); // 获取当前商品 ID testRedPacket[itemId] = red_value; // 记录红包袋子 new_docText.addDocText(); } } else { console.log("用户取消了输入"); } } // 测试使用的红包袋子 let testRedPacket = { }; // 红包补贴生成器 // debugger; // DocText 类 class DocText { constructor(idName = 'livePrice', redPacket = testRedPacket) { this.idName = idName; this.redPacket = redPacket; } // 获取 livePrice 栏目的文本内容 getDocText() { const livePriceDoc = document.getElementById(this.idName); // 获取 livePrice 栏目 if (livePriceDoc) { const liveIframe = livePriceDoc.querySelector('iframe') if (liveIframe) { const liveIframeDocument = liveIframe.contentDocument || liveIframe.contentWindow.document; const body = liveIframeDocument.body; if (body && !isNotIframeChineseName(body.innerText)) { // console.log("getDocText:", body.innerText); // debug return body.innerText; } } const currentHTML = livePriceDoc.innerText; // console.log("getDocText:", currentHTML); // debug return currentHTML; // 返回 livePrice 栏目的文本内容 } } // 更新 livePrice 栏目的文本内容 addDocText(text = this.preduceSubsidy()) { console.log('addDocText:', text); // debug const liveIframe = qyeryIframeForId(this.idName); if (liveIframe) { const liveIframeDocument = liveIframe.contentDocument || liveIframe.contentWindow.document; const body = liveIframeDocument.body; // 获取当前的 body 内的 HTML 内容 // const currentHTML = body.innerHTML; // 在当前 HTML 内容后面添加换行符和 "预售" 二字 const updatedHTML = text; // console.log('updatedHTML:', updatedHTML); // debug // 将更新后的 HTML 设置回 body 内 body.innerHTML += updatedHTML; } } // 按换行符分割字符串 splitStringByNewline(text = this.getDocText()) { // console.log('splitStringByNewline:', text); // debug return text.split('\n'); } // 过滤数组,保留匹配正则表达式或包含“到手”或“平均”的元素 filterContent(arr = this.splitStringByNewline()) { // console.log('filterContent:', arr); // debug const priceGameplayRegex = /^(.*:)?([\d\.]+[wW+]?)元?$/; // 过滤数组,保留匹配正则表达式或包含“到手”或“平均”的元素 return arr.filter(item => { return priceGameplayRegex.test(item) || item.includes('到手') || item.includes('平均'); }); } // 整理数组,将价格、个数、均价分组 organizeContent(arr = this.filterContent()) { const priceGameplayRegex = /^(.*:)?([\d\.]+[wW+]?)元?$/; let result = []; let currentGroup = []; arr.forEach(item => { if (priceGameplayRegex.test(item)) { if (currentGroup.length > 0) { // 如果当前组已经有数据,则先将其加入结果数组 result.push(currentGroup); currentGroup = []; // 清空当前组 } currentGroup.push(item); // 添加当前满足条件的元素 } else if (item.trim() !== '') { // 只添加非空行 currentGroup.push(item); } }); // 添加最后一个组,如果有的话 if (currentGroup.length > 0) { result.push(currentGroup); } // console.log('organizeContent:', result); // debug return result; } // 提取关键内容 extractPriceAndQuantity(input) { // 用于匹配整个字符串的正则表达式 const priceGameplayRegex = /^(.*:)?([\d\.]+[wW+]?)元?$/; // 用于匹配“:”之前部分的正则表达式 const quantityRegex = /拍(一|二|三|四|五|六|七|八|九|十|十一|十二|十三|十四|十五|[1-9]?[0-9])件?/; // 首先匹配整个字符串 const match = input.match(priceGameplayRegex); // console.log('match:', match); // debug if (match && match[0]) { // 提取“:”之前的部分 const beforeColon = match[0].split(':')[0]; // 检查“:”之前的部分是否满足quantityRegex const quantityMatch = beforeColon.match(quantityRegex); if (quantityMatch && quantityMatch[1]) { // 获取数量部分 let quantity = quantityMatch[1]; // 将中文数字转换为阿拉伯数字 const chineseToArabic = { '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '十': 10, '十一': 11, '十二': 12, '十三': 13, '十四': 14, '十五': 15 }; if (chineseToArabic[quantity]) { quantity = chineseToArabic[quantity]; } else { quantity = parseInt(quantity, 10); // 如果已经是阿拉伯数字,直接转换 } // 返回数量和价格内容 return { price: match[2].trim(), quantity: quantity, prefix: match[1], }; } else { return { price: match[2].trim(), quantity: 1, prefix: match[1], }; } } // 如果没有匹配到或捕获组为空,则返回空对象或其他默认值 return { price: input, quantity: 1, }; } calculateMiniUint_avgPrice(input, subsidyDiscount) { // 定义正则表达式来匹配数值 const regex = /([\d\.]+)/; // 使用正则表达式进行匹配 const match = input.match(regex); if (match) { // 提取捕获组中的数值 const numberPart = match[1]; // 将数值转换为浮点数并乘以2 const doubledValue = parseFloat(numberPart) * subsidyDiscount; // 格式化新的数值为两位小数 const formattedValue = doubledValue.toFixed(2).replace(/\.?0+$/, ""); // 替换原字符串中的数值部分 const output = input.replace(numberPart, formattedValue); return output; } else { // 如果没有找到匹配项,返回错误信息或合适的默认值 return input + '*' + subsidyDiscount + '=='; } } // 获取当前商品id getCurrentProductId() { return document.getElementById('cureentItem_upLiveId').innerText; } // 获取当前商品红包 getCurrentProductRedPacket() { const productId = this.getCurrentProductId(); return this.redPacket[productId] || 0; } // 生成补贴文本 generateSubsidyText(redPacketValue, originalPrice, quantity = 1, prefix = '', miniUint = '', miniUint_avgPrice = '') { // console.log("generateSubsidyText:", redPacketValue, originalPrice, quantity, prefix, miniUint_avgPrice); // debug // 补贴后的价格 var subsidyedPrice = originalPrice - (redPacketValue * quantity); subsidyedPrice = subsidyedPrice.toFixed(2).replace(/\.?0+$/, ""); // 保留两位小数,去除末尾的0 // 补贴折扣力度 var subsidyDiscount = (subsidyedPrice / originalPrice); // 生成补贴文本 var subsidyText = ` ${prefix} 补贴${redPacketValue * quantity}
相当于到手${subsidyedPrice} `; if (miniUint && miniUint_avgPrice) { // 更新 miniUint_avgPrice var new_miniUint_avgPrice = this.calculateMiniUint_avgPrice(miniUint_avgPrice, subsidyDiscount); var avgPriceText = `

${miniUint}
补贴后${new_miniUint_avgPrice} `; subsidyText += avgPriceText; } return subsidyText; } isOne_generateSubsidyText(redPacketValue, originalPrice, quantity = 1, prefix = '', miniUint = '', miniUint_avgPrice = '', isOne_quantity_flag = false) { // 补贴后的价格 var subsidyedPrice = originalPrice - (redPacketValue * quantity); subsidyedPrice = subsidyedPrice.toFixed(2).replace(/\.?0+$/, ""); // 保留两位小数,去除末尾的0 // 补贴折扣力度 var subsidyDiscount = (subsidyedPrice / originalPrice); if (isOne_quantity_flag === true) { // 生成补贴文本 var subsidyText = ` 补贴${redPacketValue * quantity}
相当于到手
${prefix} ${subsidyedPrice} `; } else { var subsidyText = `
${prefix} ${subsidyedPrice} `; } return subsidyText; } preduceSubsidy(arr = this.organizeContent(), redPacket = this.redPacket) { console.log("arr:", arr); // debug var new_arr = []; // 存储提取数量信息的数组,包含:价格、数量、前缀文本 var indexArr = getIndexArr_togetherAndAvgPrice(arr); // “到手共”与“平均”文本的索引数组 var productId = this.getCurrentProductId(); // 获取当前商品id var redPacketValue = redPacket[productId] || 0; // 获取当前商品红包值 console.log("indexArr:", indexArr); // debug // 预处理数组内容 for (var i = 0; i < arr.length; i++) { // 处理每一组内容 if (arr[i] && Array.isArray(arr[i]) && arr[i].length > 0) { new_arr.push(this.extractPriceAndQuantity(arr[i][0])); } } // 文本生成器(传入:数组、提取数量信息的数组、“到手共”与“平均”文本的索引数组、当前商品红包值) const len = arr.length; // 数组长度 var text = ` ----------------
`; // 存储生成的文本 var isOne_quantity_flag = isOne_quantityAll(new_arr) && len > 1; // 判断是否全部数量为1 if (isOne_quantity_flag) { for (var i = 0; i < len; i++) { var isOne = i === 0; if (indexArr && Array.isArray(indexArr[i]) && indexArr[i].length === 2) { text += this.isOne_generateSubsidyText(redPacketValue, new_arr[i].price, new_arr[i].quantity, new_arr[i].prefix, arr[i][indexArr[i][0]], arr[i][indexArr[i][1]], isOne); } else { text += this.isOne_generateSubsidyText(redPacketValue, new_arr[i].price, new_arr[i].quantity, new_arr[i].prefix, '', '', isOne); } } } else { for (var i = 0; i < len; i++) { if (indexArr && Array.isArray(indexArr[i]) && indexArr[i].length === 2) { text += this.generateSubsidyText(redPacketValue, new_arr[i].price, new_arr[i].quantity, new_arr[i].prefix, arr[i][indexArr[i][0]], arr[i][indexArr[i][1]]); } else { text += this.generateSubsidyText(redPacketValue, new_arr[i].price, new_arr[i].quantity, new_arr[i].prefix); } if (i < len - 1) { text += '

'; } } } // // debug 输出 // var testText = ''; // testText = isOne_quantityAll(new_arr); // console.log("debug-testText:", testText); // 判断是否都是独立的sku function isOne_quantityAll(new_arr) { for (var i = 0; i < new_arr.length; i++) { if (new_arr[i].quantity !== 1) { return false; } } return true; } // 获取最后一个平均到手价在 arr 中的 index function getLastAvgPrice(son_arr) { if (!Array.isArray(son_arr)) return null; var index = -1; for (var i = 0; i < son_arr.length; i++) { if (son_arr[i].includes('平均')) { index = i; } } return index === -1 ? null : index; } // 获取最后一个到手共在 arr 中的 index function getLastTogether(son_arr) { if (!Array.isArray(son_arr)) return null; var endIndex = getLastAvgPrice(son_arr); if (endIndex === null || endIndex < 2) return null; var index = -1; for (var i = 0; i < endIndex; i++) { if (son_arr[i].includes('到手')) { index = i; } } return index === -1 ? null : index; } // 获取到手共和平均到手价在 arr 中的 index,返回二维数组 function getIndexArr_togetherAndAvgPrice(arr) { var indexArr = []; for (var i = 0; i < arr.length; i++) { var index_together = getLastTogether(arr[i]); var index_avgPrice = getLastAvgPrice(arr[i]); if (index_together !== null && index_avgPrice !== null) { indexArr[i] = [index_together, index_avgPrice]; } } return indexArr; } return text; // 函数最终返回 } } function findGoodsByShopName(shopName = clipboardHistory, goodsDict = goodsUrlCheckArray) { // console.log('findGoodsByShopName:', shopName); // debug let result = ["辛苦确定下以下挂链链接是否需要更换!\n"]; var date = GM_getValue('titlePrint_extractedDate', '') var i = 1; for (const upLiveId in goodsDict) { const goodsInfo = goodsDict[upLiveId]; if (goodsInfo.shopName === shopName) { result.push(`${i} \[${isLinkTrue(goodsInfo.weight)}\]-${filterBadGoodName(goodsInfo.sessionGoodsName)}:${goodsInfo.liveLink}`); i++; } } if (i === 1) { // 没有找到对应店铺 result = []; showNotification('未找到对应店铺,请检查剪切板是否正确!'); return result; } result.push(`\n【${shopName}】挂链日期:${date}`); // console.log('findGoodsByShopName:', result.join('\n')); // debug showNotification(`${shopName}的挂链链接已复制到剪切板`); GM_setClipboard(result.join('\n')); return result; function isLinkTrue(weight) { if (weight === 0) { return '未确认'; } else { return '已确认'; } } function filterBadGoodName(goodsName) { // 使用正则表达式去除换行符和“预售”信息 const cleanedName = goodsName.replace(/(\r\n|\n|\r|预售)/g, ''); return cleanedName.trim(); // 去除首尾的空白字符 } } function addDefaultButtonForHomePage() { var buttonName = '完整复制'; var buttonId = 'allCopyButton'; const smartCopyButton = createDefaultButton(buttonId, buttonName, () => { findGoodsByShopName(); }); // 找到搜索栏目 const searchToolBar = document.querySelector('.ant-pro-table-list-toolbar-left'); const scButton = document.getElementById(buttonId); if (searchToolBar) { if (!scButton) { searchToolBar.appendChild(smartCopyButton); } else { if (checkActiveTab_GuaLian() && sonMain_linkAllCopySwitch.getSwitchState()) { scButton.style.display = ''; } else { scButton.style.display = 'none'; } } } } function createDefaultButton(id = 'testButton', text = '测试按钮', clickHandler) { // 创建按钮元素 const button = document.createElement('button'); button.type = 'button'; button.id = id; button.className = 'ant-btn css-9fw9up ant-btn-default'; // 创建按钮内部的文本元素 const span = document.createElement('span'); span.textContent = text; button.appendChild(span); // 绑定点击事件处理函数 if (typeof clickHandler === 'function') { button.addEventListener('click', clickHandler); } return button; } /* 自动排序功能块 */ let autoSortNum = ''; // 自动排序值 let AutoSortState = false; // 自动排序状态 class AutoSortItem { sortTable = []; // 使用数组来存储排序信息 sortedIndex = []; // 使用数组存储已经排序的索引 constructor(text) { this.text = text; this.arr = this.changeOrderText(text); this.lastMiniIndex = 0; // 记录上一次的最小连续数字索引 } // 将输入的文本转换为数组 changeOrderText(text = this.text) { // 输入样例:3,4,2,1,5; // 预处理-清除空格、转换中文逗号 text = text.replace(/\s/g, '').replace(/,/g, ','); // 预处理-分割字符串 const arr = text.split(','); console.log('changeOrderText:', arr); // debug return arr; } // 返回数组的最小连续数字-从 1 开始 findCurrentSmallestNumber(arr) { if (arr.length === 0) { return 0; } // 将字符串数组转换为数字数组 const numArr = arr.map(Number); // 将数组转换为Set,以便快速查找 const set = new Set(numArr); let currentSmallest = 1; // 查找当前最小的连续数 while (set.has(currentSmallest)) { currentSmallest++; } return currentSmallest - 1; } // 初始化 initSortItem() { this.sortTable = []; this.sortedIndex = []; this.lastMiniIndex = 0; autoSortNum = ''; } // 返回与id对应的权重序号 async getItemTable(goodsDict = goodsUrlCheckArray) { showNotification('正在更新当前信息...', 5000); let className = '.ant-btn.css-9fw9up.ant-btn-primary'; clickButton(true, 100, undefined, className); await new Promise(resolve => setTimeout(resolve, 4000)); // 根据实际情况调整等待时间 let sortTable = [];// 存储排序信息 // 延迟4秒后,预处理数据 try { showNotification('即将开始自动排序...', 0); const ids = Object.keys(goodsDict); // 获取 goodsDict 的键 for (let i = 0; i < ids.length; i++) { const upLiveId = ids[i].toString(); let weight = this.arr[i]; // 预设权重 if (weight === undefined) { weight = 999; } sortTable.push([upLiveId, weight]); // 使用 push 方法添加键值对 } } catch (error) { showNotification('处理 “商品信息” 时发生错误', 0); console.error("处理 goodsDict 时发生错误:", error); } console.log('getItemTable:', sortTable); // debug return sortTable; } async startSort() { this.initSortItem(); // 初始化排序信息 AutoSortState = true; // 开启自动排序状态 this.sortTable = await this.getItemTable(); // 更新商品信息 for (let i = 0; i < this.sortTable.length; i++) { showNotification(`正在处理第 ${i + 1}/${this.sortTable.length} 个商品...`, 0); // 计算需要滚动的商品块个数 let scrollNum = this.findCurrentSmallestNumber(this.sortedIndex) - this.lastMiniIndex; console.log('scrollNum:', scrollNum); // debug // itemPageScroll(itemBlockHeight * scrollNum); // 向下滚动 this.lastMiniIndex = this.findCurrentSmallestNumber(this.sortedIndex); // 更新 lastMiniIndex console.log('lastMiniIndex:', this.lastMiniIndex); // debug // 获取将要执行的索引的商品块 const index = findItemIdForArr(this.sortTable[i][0]); // 找到索引对应的商品块 console.log('index:', index); // debug const weight = this.sortTable[i][1]; // 预设权重 console.log('weight:', weight); // debug const preWeight = weight * 10;// 输入权重 (默认值 * 10) console.log('preWeight:', preWeight); // debug autoSortNum = preWeight.toString(); // 自动排序值 click_autoInputForIndex(index); // 输入索引 console.log('click_autoInputForIndex:', index); // debug this.sortedIndex.push(weight); // 记录已经排序的索引 console.log('sortedIndex:', this.sortedIndex); // debug if (i + 1 >= this.sortTable.length) { break; } await new Promise(resolve => setTimeout(resolve, 3000)); // 等待 3 秒 console.log('等待 3 秒'); // debug await waitForPageToLoad(); // 等待页面加载完成 console.log('等待页面加载完成'); // debug await new Promise(resolve => setTimeout(resolve, 1000)); // 继续等待 1 秒 console.log('继续等待 1 秒'); // debug } console.log('排序完成!'); showNotification('排序完成!'); this.initSortItem(); // 重置排序信息 AutoSortState = false; // 关闭自动排序状态 const button = document.getElementById('itemSort_autoSort_divButton'); if (button) { button.click(); // 点击按钮关闭自动排序 } } } /* 分词器加载 */ // 定义一个函数用于异步加载脚本并初始化分词器 function initSegmentit(url) { // 动态加载脚本 const loadScript = (url, callback) => { const script = document.createElement('script'); script.src = url; script.onload = () => callback(null); // 使用 null 表示没有错误 script.onerror = () => callback(new Error('Failed to load script: ' + url)); document.head.appendChild(script); }; // 加载脚本并初始化分词器 loadScript(url, (err) => { if (err) { console.error(err.message); return; } // 确保页面完全加载后再执行脚本 window.addEventListener('load', function () { // 检查 Segmentit 对象是否已定义 if (typeof Segmentit === 'undefined') { console.error('Segmentit is not defined. Please check if the library is loaded correctly.'); } else { console.log('Segmentit is loaded:', segmenter); // debug } }); }); } // 调用函数并传入 URL 和希望使用的全局变量名称 initSegmentit('https://cdn.jsdelivr.net/npm/segmentit@2.0.3/dist/umd/segmentit.js'); let debug_segmentit = false; // 是否开启分词器调试模式 /* 分词器加载完毕 */ const testText_1 = '珍珠粉黑灵芝紧致白面膜组合'; const testText_2 = '1g+5g珍珠粉黑灵芝紧致白面膜组合'; function segmentText(text, returnSentence = false) { // 实例化分词器 const segmentit = Segmentit.useDefault(new Segmentit.Segment()); // 获取分词后的对象 const result = segmentit.doSegment(text); // 输出分词后的文本 let sentence = ''; // 存储分词后的文本 if (returnSentence) { // 返回分词后的句子 sentence = result.map(item => item.w).join(' '); } else { // 返回分词后的数组 sentence = result.map(item => item.w); } console.log(sentence); return sentence; } function calcSimilarity(title1, title2) { // 将分词结果转换为单词数组 const wordArray1 = segmentText(title1); const wordArray2 = segmentText(title2); // 构建词汇表 const vocabulary = new Set([...wordArray1, ...wordArray2]); const vocabArray = Array.from(vocabulary); // 构建向量 function createVector(wordArray, vocabArray) { const vector = new Array(vocabArray.length).fill(0); for (let i = 0; i < wordArray.length; i++) { const index = vocabArray.indexOf(wordArray[i]); if (index !== -1) { vector[index]++; } } return vector; } const vector1 = createVector(wordArray1, vocabArray); const vector2 = createVector(wordArray2, vocabArray); // 计算余弦相似度 function cosineSimilarity(vec1, vec2) { let dotProduct = 0; let normA = 0; let normB = 0; for (let i = 0; i < vec1.length; i++) { dotProduct += vec1[i] * vec2[i]; normA += vec1[i] * vec1[i]; normB += vec2[i] * vec2[i]; } if (normA === 0 || normB === 0) { return 0; // 防止除以零 } return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)); } const similarity = cosineSimilarity(vector1, vector2); console.log('calcSimilarity:', similarity); // debug return similarity; } // 构建相似度矩阵 function buildSimilarityMatrix(table1, table2) { const n = table1.length; const m = table2.length; const similarityMatrix = Array.from({ length: n }, () => Array(m).fill(0)); for (let i = 0; i < n; i++) { for (let j = 0; j < m; j++) { const shopSim = calcSimilarity(table1[i]['店铺名'], table2[j]['店铺名']); const titleSim = calcSimilarity(table1[i]['商品标题'], table2[j]['商品标题']); const totalSim = 0.35 * shopSim + 0.65 * titleSim; similarityMatrix[i][j] = totalSim; } } return similarityMatrix; } // 使用有序贪心算法进行匹配 function matchItemsWithGreedy(table1, table2) { const similarityMatrix = buildSimilarityMatrix(table1, table2); const n = table1.length; const m = table2.length; const matches = []; const usedCols = new Set(); for (let i = 0; i < n; i++) { let maxSim = -1; let bestCol = -1; for (let j = 0; j < m; j++) { if (usedCols.has(j)) continue; const sim = similarityMatrix[i][j]; if (sim > maxSim) { maxSim = sim; bestCol = j; } } if (bestCol !== -1) { matches.push([i, bestCol]); usedCols.add(bestCol); } } return matches; } // 使用改进的匈牙利算法进行匹配 function matchItemsWithHungarian(table1, table2) { const similarityMatrix = buildSimilarityMatrix(table1, table2); const n = table1.length; const m = table2.length; const costMatrix = similarityMatrix.map(row => row.map(val => -val)); // 转换为成本矩阵 const labelX = new Array(n).fill(0); const labelY = new Array(m).fill(0); const match = new Array(m).fill(-1); const slack = new Array(m).fill(Number.MAX_SAFE_INTEGER); const visitedX = new Array(n).fill(false); const visitedY = new Array(m).fill(false); // 初始化标签 for (let i = 0; i < n; i++) { labelX[i] = Math.max(...costMatrix[i]); } function findAugmentingPath(i) { visitedX[i] = true; for (let j = 0; j < m; j++) { if (visitedY[j]) continue; const delta = labelX[i] + labelY[j] - costMatrix[i][j]; if (delta === 0) { visitedY[j] = true; if (match[j] === -1 || findAugmentingPath(match[j])) { match[j] = i; return true; } } else { slack[j] = Math.min(slack[j], delta); } } return false; } for (let i = 0; i < n; i++) { while (true) { slack.fill(Number.MAX_SAFE_INTEGER); visitedX.fill(false); visitedY.fill(false); if (findAugmentingPath(i)) break; let delta = Number.MAX_SAFE_INTEGER; for (let j = 0; j < m; j++) { if (!visitedY[j]) delta = Math.min(delta, slack[j]); } for (let j = 0; j < n; j++) { if (visitedX[j]) labelX[j] -= delta; } for (let j = 0; j < m; j++) { if (visitedY[j]) labelY[j] += delta; } } } const matches = match.map((col, row) => [row, col]); return matches; } // 输出结果 function printMatches(matches, table1, table2) { for (const [i, index] of matches) { const item1 = table1[i]; const item2 = table2[index]; const score = calcSimilarity(item1['商品标题'], item2['商品标题']); console.log(`[${i + 1}]表1商品: ${item1['商品标题']}\n表2位置: ${index + 1} (商品: ${item2['商品标题']}) [相似度: ${score.toFixed(2)}]`); } } function printIndex(matches) { const arr = matches.map(index => index[1] + 1); console.log("arrLen:", arr.length); console.log("arr:", arr); console.log("arr_no_dup:", new Set(arr).size); const arrCheck = [...new Set(arr)]; console.log("arrCheck:", arrCheck.sort((a, b) => a - b)); } // 测试数据 const table1 = [ { "商品标题": "水牛纯牛奶", "店铺名": "爱泡澡的水牛旗舰店" }, { "商品标题": "红养豆浆粉", "店铺名": "九阳豆浆旗舰店" }, { "商品标题": "芙丝天然矿泉水", "店铺名": "华彬旗舰店" }, { "商品标题": "正宗天马老树陈皮", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "初心肉桂大红袍组合", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "茗潮宋礼礼盒", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "铁观音 乌龙茶", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "2015年白毫银针", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "五彩罐岩茶组合", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "武夷山正山小种", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "茉莉花茶", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "碧螺春", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "鸿运金骏眉礼盒", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "针王 白茶", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "正坑牛肉 乌龙茶", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "首字号茶礼 乌龙茶", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "桐木关老枞 红茶礼盒", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "吮指鸡肉条", "店铺名": "牧匠食品旗舰店" }, { "商品标题": "法丽兹黄油小花曲奇173g*2罐", "店铺名": "法丽兹食品旗舰店" }, { "商品标题": "芡实糕", "店铺名": "杨先生旗舰店" }, { "商品标题": "捞汁豆腐", "店铺名": "杨生记食品旗舰店" }, { "商品标题": "茶香师禅茶系列香水", "店铺名": "茶香师旗舰店" }, { "商品标题": "宝玑米手甲同护护手霜", "店铺名": "puljim宝玑米旗舰店" }, { "商品标题": "原制奶酪饼", "店铺名": "潮香村食品旗舰店" }, { "商品标题": "春雪流心鸡球", "店铺名": "春雪食品旗舰店" }, { "商品标题": " 网红糯米笋", "店铺名": "蔚鲜来旗舰店" }, { "商品标题": "羊肚菌", "店铺名": "瑞利来旗舰店" }, { "商品标题": "大罐粥料", "店铺名": "瑞利来旗舰店" }, { "商品标题": "新会柑普茶", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "桂花金骏眉", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "金丝鸡排", "店铺名": "正新食品旗舰店" }, { "商品标题": "酱牛肉", "店铺名": "阿品旗舰店" }, { "商品标题": "茶和天下", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "丹东99草莓", "店铺名": "时予心愿旗舰店" }, { "商品标题": "海乡集即食海参", "店铺名": "海乡集旗舰店" }, { "商品标题": "果乐果香夹心饼干", "店铺名": "嘉士利旗舰店" }, { "商品标题": "多味香瓜子", "店铺名": "华味亨旗舰店" }, { "商品标题": "酥小娘核桃布里奥斯面包", "店铺名": "酥小娘旗舰店" }, { "商品标题": "芋泥乳酪派", "店铺名": "lilygarden荷家旗舰店" }, { "商品标题": "魔芋荞麦鸡肉膳食包+魔芋韭菜鸡蛋膳食包", "店铺名": "巨诺旗舰店" }, { "商品标题": "智利进口车厘子", "店铺名": "淘宝买菜农场直发" }, { "商品标题": "寿南瓜子", "店铺名": "苏太太食品旗舰店" }, { "商品标题": "石浪电陶炉+枫梭提梁壶围炉套装", "店铺名": "唐丰旗舰店" }, { "商品标题": "玺棠一体茶盘+素影煮茶壶+圆满素语西施壶9头", "店铺名": "唐丰旗舰店" }, { "商品标题": "纯钛茶水分离杯", "店铺名": "天猫超市" }, { "商品标题": "老卤鸭肫", "店铺名": "旺家福旗舰店" }, { "商品标题": "夏威夷果可可脆", "店铺名": "菓然匠子旗舰店" }, { "商品标题": "2014荒野贡眉", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "风干牛肉干九成干", "店铺名": "蒙亮旗舰店" }, { "商品标题": "农家乌鸡950g*3", "店铺名": "淘宝买菜农场直发" }, { "商品标题": "潮庭优选牛肉丸牛筋丸双拼组合", "店铺名": "潮庭旗舰店" }, { "商品标题": "早餐牛肉饼", "店铺名": "潮迹旗舰店" }, { "商品标题": "围炉煮茶器具全套", "店铺名": "尚言坊旗舰店" }, { "商品标题": "点心盘", "店铺名": "拓土旗舰店" }, ]; const table2 = [ { "商品标题": "苏太太百寿南瓜子", "店铺名": "苏太太食品旗舰店" }, { "商品标题": "捞汁豆腐", "店铺名": "杨生记食品旗舰店" }, { "商品标题": "芡实糕多口味组合", "店铺名": "杨先生旗舰店" }, { "商品标题": "法丽兹黄油小花曲奇", "店铺名": "法丽兹食品旗舰店" }, { "商品标题": "水牛纯牛奶", "店铺名": "爱泡澡的水牛旗舰店" }, { "商品标题": "魔芋荞麦鸡肉膳食包+魔芋韭菜鸡蛋膳食包", "店铺名": "巨诺旗舰店" }, { "商品标题": "九阳豆浆红养豆浆粉", "店铺名": "九阳豆浆旗舰店" }, { "商品标题": "陈皮绿豆百合银耳粥1.308kg*1罐/陈皮红豆粥1.010kg*1罐/1.5kg/罐/干贝虾仁粥1.1kg/罐/紫薯黑米粥1.48kg/罐", "店铺名": "瑞利来旗舰店" }, { "商品标题": "酥小娘核桃布里奥斯面包", "店铺名": "酥小娘旗舰店" }, { "商品标题": "夏威夷果可可脆", "店铺名": "菓然匠子旗舰店" }, { "商品标题": "果乐果香夹心饼干", "店铺名": "嘉士利旗舰店" }, { "商品标题": "芋泥乳酪派", "店铺名": "lilygarden荷家旗舰店" }, { "商品标题": "打手瓜子", "店铺名": "华味亨旗舰店" }, { "商品标题": "旺家福老卤鸭肫", "店铺名": "旺家福旗舰店" }, { "商品标题": "茶香师禅茶系列香水 和合之境 早春之茶 正如初念", "店铺名": "茶香师旗舰店" }, { "商品标题": "宝玑米微氛手甲精华霜囤货装", "店铺名": "puljim宝玑米旗舰店" }, { "商品标题": "【王炸】车厘子 官补115", "店铺名": "淘宝买菜农场直发" }, { "商品标题": "丹东99草莓", "店铺名": "时予心愿旗舰店" }, { "商品标题": "吮指鸡肉条", "店铺名": "牧匠食品旗舰店" }, { "商品标题": "风干牛肉干九成干", "店铺名": "蒙亮旗舰店" }, { "商品标题": "围炉煮茶", "店铺名": "唐丰旗舰店" }, { "商品标题": "特美刻茶水分离杯 补贴50", "店铺名": "" }, { "商品标题": "茶和天下品鉴装", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "初心组合 补贴30", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "【王炸】天马陈皮220g 补贴50", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "新会柑普茶", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "鸿运金骏眉礼盒 补贴50", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "桐木关老枞红茶礼盒 补贴20", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "【王炸】2015年老银针", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "正坑牛肉/正坑牛肉礼盒装 补贴100", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "2014年荒野贡眉 补贴15", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "茗潮宋礼 补贴20", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "针王 补贴50", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "茉莉花茶", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "桂花金骏眉", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "茶具套装", "店铺名": "唐丰旗舰店" }, { "商品标题": "五彩罐岩茶组合 补贴30", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "武夷山正山小种", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "首字号茶礼512g 补贴30", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "铁观音", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "碧螺春", "店铺名": "望峰茶叶旗舰店" }, { "商品标题": "VOSS/芙丝天然矿泉水", "店铺名": "华彬旗舰店" }, { "商品标题": "条纹月笼壶", "店铺名": "尚言坊" }, { "商品标题": "海乡集大连即食海参 补贴25", "店铺名": "海乡集旗舰店" }, { "商品标题": "潮庭优选双拼牛丸组合", "店铺名": "潮庭旗舰店" }, { "商品标题": "农家散养乌鸡", "店铺名": "淘宝买菜" }, { "商品标题": "瑞利来羊肚菌", "店铺名": "瑞利来旗舰店" }, { "商品标题": "流心鸡球400g", "店铺名": "春雪食品旗舰店" }, { "商品标题": "奶酪饼", "店铺名": "潮香村食品旗舰店" }, { "商品标题": "网红糯米笋", "店铺名": "蔚鲜来旗舰店" }, { "商品标题": "正新金丝鸡排", "店铺名": "正新食品旗舰店" }, { "商品标题": "阿品酱牛肉", "店铺名": "阿品旗舰店" }, ]; // setTimeout(() => { // // calcSimilarity(testText_1, testText_2); // console.log('开始匹配商品...'); // // const matches = matchItemsWithGreedy(table1, table2); // const matches = matchItemsWithHungarian(table1, table2); // printMatches(matches, table1, table2); // printIndex(matches); // }, 10000); })();