您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
縦横軸コード管理ページでbyte数やスペース・記号・機種依存文字を検出し、それらが含まれる場合はSKUを追加できないようにする
// ==UserScript== // @name 縦横軸コード管理ページエラーチェック // @namespace http://tampermonkey.net/ // @version 1.04 // @description 縦横軸コード管理ページでbyte数やスペース・記号・機種依存文字を検出し、それらが含まれる場合はSKUを追加できないようにする // @license MIT // @match *://starlight.plusnao.co.jp/goods/axisCode* // @run-at document-end // @grant none // ==/UserScript== (function () { 'use strict'; let currentCode = ''; let saveButton = null; let modalSaveButtons = []; const alertBoxId = 'custom-alert-box'; let alertTypesSet = new Set(); function countByte(str) { if (!str) return 0; let length = 0; for (let char of str) { length += (char.match(/[^\x00-\xff]/)) ? 2 : 1; } return length; } function containsSpace(str) { return /[\u0020\u3000]/.test(str || ''); } function containsSymbols(str) { return /['&<>=+\*\/\]\[\\㎜㎝㎞㎎㎏㏄]/.test(str || ''); } function hasInvalidChar(str) { const allowedCharsOnly = /^[a-zA-Z0-9\- ]*$/; return !allowedCharsOnly.test(str || ''); } function highlightAxis(str) { return countByte(str) >= 33 || containsSpace(str) || containsSymbols(str); } function highlightCode(inputValue) { const combined = (currentCode || '') + (inputValue || ''); return countByte(combined) >= 21 || containsSpace(combined) || hasInvalidChar(inputValue); } function applyHighlight(input, conditionFn, color) { if (!input || typeof input.value !== 'string') return; const value = input.value; const combined = (currentCode || '') + value; const hasInvalid = hasInvalidChar(value); let shouldHighlight = false; try { shouldHighlight = conditionFn(value); input.style.border = shouldHighlight ? `2px solid red` : ''; } catch (e) {} if (!shouldHighlight) { if (countByte(value) < 33) alertTypesSet.delete('over33'); if (countByte(combined) < 21) alertTypesSet.delete('over21'); if (!containsSpace(value)) alertTypesSet.delete('space'); if (!containsSymbols(value)) alertTypesSet.delete('symbol'); if (!hasInvalid) alertTypesSet.delete('invalidChar'); } if (shouldHighlight) { if (countByte(value) >= 33) alertTypesSet.add('over33'); if (countByte(combined) >= 21) alertTypesSet.add('over21'); if (containsSpace(value)) alertTypesSet.add('space'); if (containsSymbols(value)) alertTypesSet.add('symbol'); if (hasInvalid) alertTypesSet.add('invalidChar'); } updateAlertMessages(); } function updateSaveButtonsState() { try { const hasBadInput = Array.from(document.querySelectorAll('input.form-control')).some(input => input && typeof input.style.border === 'string' && ( input.style.border.includes('red') || input.style.border.includes('blue') ) ); if (saveButton) { saveButton.disabled = hasBadInput; } modalSaveButtons.forEach(btn => { btn.disabled = hasBadInput; }); } catch (e) { } } const style = document.createElement('style'); style.innerHTML = ` #${alertBoxId} { position: fixed; top: 20px; right: 20px; background-color: #f8d7da; border: 1px solid #e57373; border-radius: 12px; padding: 15px 20px; z-index: 9999; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); font-size: 14px; max-width: 400px; line-height: 1.6; color: #721c24; font-family: "Helvetica Neue", Arial, sans-serif; } #${alertBoxId} span { position: absolute; top: -8px; right: -8px; width: 30px; height: 30px; background-color: #f44336; color: #fff; text-align: center; line-height: 30px; border-radius: 50%; font-weight: bold; cursor: pointer; box-shadow: 0 4px 8px rgba(0,0,0,0.2); transition: background-color 0.3s, transform 0.2s; } #${alertBoxId} span:hover { background-color: #d32f2f; transform: scale(1.1); } #${alertBoxId} div { margin-bottom: 5px; margin-top: 5px; } `; document.head.appendChild(style); function updateAlertMessages() { let alertBox = document.getElementById(alertBoxId); const messages = []; if (alertTypesSet.has('space')) messages.push('・コード、または項目名にスペースが含まれています。'); if (alertTypesSet.has('symbol')) messages.push('・項目名に機種依存文字か半角記号が含まれています。'); if (alertTypesSet.has('over33')) messages.push('・項目名が32byteを超えています。<br> 32byte以内に収めてください。'); if (alertTypesSet.has('over21')) messages.push('・代表商品コード+SKUが20byteを超えています。<br> 20byte以内に収めてください。'); if (alertTypesSet.has('invalidChar')) messages.push('・コードに使用できない文字が含まれています。'); if (messages.length === 0) { if (alertBox) { alertBox.remove(); } return; } if (!alertBox) { alertBox = document.createElement('div'); alertBox.id = alertBoxId; document.body.appendChild(alertBox); } let newMessagesHTML = messages.map(msg => `<div>${msg}</div>`).join(''); alertBox.innerHTML = `<span onclick="this.parentNode.remove()">×</span>` + newMessagesHTML; } function recalculateAllAlerts() { alertTypesSet.clear(); document.querySelectorAll('table.table-bordered tbody tr').forEach(tr => { const axisInput = tr?.children?.[1]?.querySelector('input.form-control'); if (axisInput) { const value = axisInput.value || ''; if (countByte(value) >= 33) alertTypesSet.add('over33'); if (containsSpace(value)) alertTypesSet.add('space'); if (containsSymbols(value)) alertTypesSet.add('symbol'); } }); document.querySelectorAll('div.modal-content').forEach(modal => { const inputs = modal.querySelectorAll('input.form-control'); if (inputs.length > 0) { const first = inputs[0]?.value || ''; const second = inputs[1]?.value || ''; if (countByte(currentCode + first) >= 21) alertTypesSet.add('over21'); if (countByte(second) >= 33) alertTypesSet.add('over33'); if (containsSpace(first)) alertTypesSet.add('space'); if (containsSpace(second)) alertTypesSet.add('space'); if (containsSymbols(second)) alertTypesSet.add('symbol'); if (hasInvalidChar(first)) alertTypesSet.add('invalidChar'); } }); updateAlertMessages(); updateSaveButtonsState(); } function attachListeners(input, conditionFn) { if (!input || input.dataset.hasListener) return; const handler = () => { applyHighlight(input, conditionFn); recalculateAllAlerts(); updateSaveButtonsState(); }; input.addEventListener('input', handler); handler(); input.dataset.hasListener = 'true'; } function extractCodeFromUrl() { const urlParams = new URLSearchParams(window.location.search); currentCode = urlParams.get('code') || ''; } function detectSaveButtons() { const buttons = document.querySelectorAll('div.row10.mb10 button.btn.btn-primary'); saveButton = Array.from(buttons).find(btn => btn.textContent.includes('項目名保存')) || null; modalSaveButtons = Array.from(document.querySelectorAll('div.modal-footer button.btn-primary')) .filter(btn => btn.textContent.includes('保存')); } function highlightInputs() { try { extractCodeFromUrl(); detectSaveButtons(); const modal = document.getElementById('modalAxisCodeInsertForm'); const isModalVisible = modal && modal.style.display === 'block'; if (!isModalVisible) { document.querySelectorAll('table.table-bordered tbody tr').forEach(tr => { const axisInput = tr?.children?.[1]?.querySelector('input.form-control'); if (axisInput) { attachListeners(axisInput, highlightAxis); } }); } document.querySelectorAll('div.modal-content').forEach(modal => { const modalInputs = modal.querySelectorAll('input.form-control'); const codeInput = modalInputs[0]; const axisInput = modalInputs[1]; if (codeInput) attachListeners(codeInput, highlightCode); if (axisInput) attachListeners(axisInput, highlightAxis); }); } catch (e) {} } function clearModalHighlights(modal) { if (!modal) return; modal.querySelectorAll('input.form-control').forEach(input => { input.style.border = ''; }); } function observeDynamicElements() { new MutationObserver(() => { highlightInputs(); }).observe(document.body, { childList: true, subtree: true }); observeModalDisplayState(); } function observeModalDisplayState() { const modal = document.getElementById('modalAxisCodeInsertForm'); if (!modal) return; let previousDisplay = modal.style.display; new MutationObserver(() => { const currentDisplay = modal.style.display; if (previousDisplay !== currentDisplay) { previousDisplay = currentDisplay; if (currentDisplay === 'none') { clearModalHighlights(modal); recalculateAllAlerts(); updateSaveButtonsState(); } else { highlightInputs(); recalculateAllAlerts(); updateSaveButtonsState(); } } }).observe(modal, { attributes: true, attributeFilter: ['style'] }); } window.addEventListener('load', () => { highlightInputs(); observeDynamicElements(); }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址