一括受発注チェック

条件に基づいてチェックボックスを一括操作

  1. // ==UserScript==
  2. // @name 一括受発注チェック
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.02
  5. // @description 条件に基づいてチェックボックスを一括操作
  6. // @license MIT
  7. // @match *://plus-nao.com/forests/*/sku_check/*
  8. // @match *://plus-nao.com/forests/*/sku_edit/*
  9. // @grant GM_addStyle
  10. // @run-at document-end
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. 'use strict';
  15.  
  16. let selectedHorizontal = [];
  17. let selectedVertical = [];
  18.  
  19. let horizontalAxisNames = [];
  20. let verticalAxisNames = [];
  21.  
  22. const rows = document.querySelectorAll('table.formdot tbody tr');
  23.  
  24. rows.forEach(row => {
  25. const cells = row.querySelectorAll('td');
  26. if (cells.length > 3) {
  27. const horizontal = cells[2].textContent.trim();
  28. const vertical = cells[3].textContent.trim();
  29.  
  30. if (horizontal && !horizontalAxisNames.includes(horizontal)) {
  31. horizontalAxisNames.push(horizontal);
  32. }
  33. if (vertical && !verticalAxisNames.includes(vertical)) {
  34. verticalAxisNames.push(vertical);
  35. }
  36. }
  37. });
  38.  
  39. const buttonContainer = document.createElement('div');
  40. buttonContainer.id = 'custom-button-container';
  41. document.body.appendChild(buttonContainer);
  42.  
  43. createAxisButtons('横軸', horizontalAxisNames, 'horizontal', buttonContainer);
  44. createAxisButtons('縦軸', verticalAxisNames, 'vertical', buttonContainer);
  45.  
  46. const onOffContainer = document.createElement('div');
  47. onOffContainer.id = 'on-off-container';
  48. buttonContainer.appendChild(onOffContainer);
  49.  
  50. const onButton = createActionButton('オン', () => toggleCheckboxes(true));
  51. const offButton = createActionButton('オフ', () => toggleCheckboxes(false));
  52. onOffContainer.appendChild(onButton);
  53. onOffContainer.appendChild(offButton);
  54.  
  55. const hideButton = document.createElement('button');
  56. hideButton.textContent = '-';
  57. hideButton.id = 'hide-button';
  58. buttonContainer.appendChild(hideButton);
  59. hideButton.onclick = hideContainer;
  60.  
  61. const showButton = document.createElement('button');
  62. showButton.textContent = '+';
  63. showButton.id = 'show-button';
  64. showButton.style.position = 'fixed';
  65. showButton.style.right = '25px';
  66. showButton.style.top = '50%';
  67. showButton.style.transform = 'translateY(-50%)';
  68. document.body.appendChild(showButton);
  69. showButton.onclick = showContainer;
  70.  
  71. const configButton = document.createElement('button');
  72. configButton.textContent = '⚙';
  73. configButton.id = 'config-button';
  74. buttonContainer.appendChild(configButton);
  75.  
  76. configButton.onclick = () => {
  77. const isHidden = toggleRememberStateButton.style.display === 'none';
  78. toggleRememberStateButton.style.display = isHidden ? 'block' : 'none';
  79. };
  80.  
  81. const toggleRememberStateButton = document.createElement('button');
  82. toggleRememberStateButton.textContent = getRememberState() ? '表示状態の記憶: オン' : '表示状態の記憶: オフ';
  83. toggleRememberStateButton.id = 'toggle-remember-state';
  84. toggleRememberStateButton.style.display = 'none';
  85. toggleRememberStateButton.style.position = 'absolute';
  86. toggleRememberStateButton.style.bottom = '-24px';
  87. toggleRememberStateButton.style.left = '-2px';
  88. toggleRememberStateButton.title = 'オン: リロード時は最後の表示状態を維持\nオフ: リロード時は常に展開';
  89. buttonContainer.appendChild(toggleRememberStateButton);
  90. toggleRememberStateButton.onclick = toggleRememberState;
  91.  
  92. window.addEventListener('load', restoreState);
  93.  
  94. function createAxisButtons(label, axisNames, axis, container) {
  95. const axisContainer = document.createElement('div');
  96. axisContainer.classList.add('axis-container');
  97.  
  98. const axisLabel = document.createElement('div');
  99. axisLabel.textContent = label;
  100. axisLabel.classList.add('axis-label');
  101. axisContainer.appendChild(axisLabel);
  102.  
  103. axisNames.forEach(name => {
  104. const button = document.createElement('button');
  105. button.textContent = name;
  106. button.classList.add('axis-button');
  107. button.dataset.axis = axis;
  108. button.dataset.name = name;
  109. button.onclick = () => toggleSelection(button, axis, name);
  110. axisContainer.appendChild(button);
  111. });
  112.  
  113. container.appendChild(axisContainer);
  114. }
  115.  
  116. function toggleSelection(button, axis, name) {
  117. if (axis === 'horizontal') {
  118. if (selectedHorizontal.includes(name)) {
  119. selectedHorizontal = selectedHorizontal.filter(item => item !== name);
  120. } else {
  121. selectedHorizontal.push(name);
  122. }
  123. } else if (axis === 'vertical') {
  124. if (selectedVertical.includes(name)) {
  125. selectedVertical = selectedVertical.filter(item => item !== name);
  126. } else {
  127. selectedVertical.push(name);
  128. }
  129. }
  130. updateButtonStyles();
  131. }
  132.  
  133. function updateButtonStyles() {
  134. document.querySelectorAll('.axis-button[data-axis="horizontal"]').forEach(button => {
  135. button.classList.toggle('selected', selectedHorizontal.includes(button.dataset.name));
  136. });
  137. document.querySelectorAll('.axis-button[data-axis="vertical"]').forEach(button => {
  138. button.classList.toggle('selected', selectedVertical.includes(button.dataset.name));
  139. });
  140. }
  141.  
  142. function toggleCheckboxes(state) {
  143. let feedbackMessage = '';
  144.  
  145. rows.forEach(row => {
  146. const cells = row.querySelectorAll('td');
  147. const checkbox = row.querySelector('td input[type="checkbox"]');
  148. if (cells.length > 3 && checkbox) {
  149. const horizontal = cells[2].textContent.trim();
  150. const vertical = cells[3].textContent.trim();
  151.  
  152. if (selectedHorizontal.length > 0 && selectedVertical.length > 0) {
  153. if (selectedHorizontal.includes(horizontal) && selectedVertical.includes(vertical)) {
  154. checkbox.checked = state;
  155. feedbackMessage = `「${selectedHorizontal.join('」「')}」 ${selectedVertical.join('」「')}」 の条件に一致する項目を変更しました。`;
  156. }
  157. } else if (selectedHorizontal.length > 0 && selectedVertical.length === 0) {
  158. if (selectedHorizontal.includes(horizontal)) {
  159. checkbox.checked = state;
  160. feedbackMessage = `「${selectedHorizontal.join('」「')}」 に一致する項目を変更しました。`;
  161. }
  162. } else if (selectedVertical.length > 0 && selectedHorizontal.length === 0) {
  163. if (selectedVertical.includes(vertical)) {
  164. checkbox.checked = state;
  165. feedbackMessage = `「${selectedVertical.join('」「')}」 に一致する項目を変更しました。`;
  166. }
  167. }
  168. }
  169. });
  170.  
  171. if (!feedbackMessage) {
  172. feedbackMessage = '選択条件がありません。';
  173. }
  174.  
  175. displayFeedback(feedbackMessage);
  176. }
  177.  
  178. function createActionButton(label, callback) {
  179. const button = document.createElement('button');
  180. button.textContent = label;
  181. button.classList.add('on-off-button');
  182. button.onclick = callback;
  183. return button;
  184. }
  185.  
  186. function displayFeedback(message) {
  187. let feedbackDiv = document.getElementById('feedback-message');
  188.  
  189. if (!feedbackDiv) {
  190. feedbackDiv = document.createElement('div');
  191. feedbackDiv.id = 'feedback-message';
  192. document.body.appendChild(feedbackDiv);
  193. }
  194.  
  195. feedbackDiv.textContent = message;
  196. feedbackDiv.style.display = 'block';
  197.  
  198. setTimeout(() => {
  199. feedbackDiv.style.display = 'none';
  200. }, 3000);
  201. }
  202.  
  203. function hideContainer() {
  204. const container = document.getElementById('custom-button-container');
  205. const showButton = document.getElementById('show-button');
  206. container.style.display = 'none';
  207. showButton.style.display = 'block';
  208. if (getRememberState()) {
  209. localStorage.setItem('buttonContainerState', 'hidden');
  210. }
  211. }
  212.  
  213. function showContainer() {
  214. const container = document.getElementById('custom-button-container');
  215. const showButton = document.getElementById('show-button');
  216. container.style.display = 'grid';
  217. showButton.style.display = 'none';
  218. if (getRememberState()) {
  219. localStorage.setItem('buttonContainerState', 'visible');
  220. }
  221. }
  222.  
  223. function restoreState() {
  224. if (getRememberState()) {
  225. const savedState = localStorage.getItem('buttonContainerState');
  226. const container = document.getElementById('custom-button-container');
  227. const showButton = document.getElementById('show-button');
  228.  
  229. if (savedState === 'hidden') {
  230. container.style.display = 'none';
  231. showButton.style.display = 'block';
  232. } else {
  233. container.style.display = 'grid';
  234. showButton.style.display = 'none';
  235. }
  236. }
  237. }
  238.  
  239. function toggleRememberState() {
  240. const currentState = getRememberState();
  241. localStorage.setItem('rememberState', currentState ? 'false' : 'true');
  242. toggleRememberStateButton.textContent = currentState ? '表示状態の記憶: オフ' : '表示状態の記憶: オン';
  243. }
  244.  
  245. function getRememberState() {
  246. return localStorage.getItem('rememberState') !== 'false';
  247. }
  248.  
  249. GM_addStyle(`
  250. #custom-button-container {
  251. position: fixed;
  252. top: 50%;
  253. right: 10px;
  254. min-width: 150px;
  255. transform: translateY(-50%);
  256. background-color: #fff;
  257. padding: 10px 20px;
  258. border: 1px solid #ccc;
  259. z-index: 1000;
  260. display: grid;
  261. grid-template-columns: 1fr 1fr;
  262. max-height: 90vh;
  263. }
  264.  
  265. .axis-container {
  266. display: flex;
  267. flex-direction: column;
  268. overflow-y: auto;
  269. padding-bottom: 45px;
  270. max-height: 80vh;
  271. }
  272.  
  273. .axis-label {
  274. margin-bottom: 3px;
  275. font-weight: bold;
  276. text-align: center;
  277. }
  278.  
  279. .axis-button {
  280. margin: 3px;
  281. background-color: gray;
  282. color: white;
  283. border: none;
  284. padding: 3px 10px;
  285. cursor: pointer;
  286. text-align: center;
  287. }
  288.  
  289. .axis-button.selected {
  290. background-color: #205668;
  291. color: white;
  292. }
  293.  
  294. .axis-button:hover {
  295. background-color: #888;
  296. }
  297.  
  298. .axis-button.selected:hover {
  299. background-color: #205668 !important;
  300. }
  301.  
  302. #on-off-container {
  303. position: fixed;
  304. bottom: 0;
  305. left: 10px;
  306. right: 10px;
  307. background-color: #ffffff;
  308. padding: 10px;
  309. display: grid;
  310. grid-template-columns: 1fr 1fr;
  311. gap: 10px;
  312. border-top: 1px solid #ccc;
  313. z-index: 1001;
  314. }
  315.  
  316. .on-off-button {
  317. background-color: #4c72af;
  318. color: white;
  319. padding: 5px 10px;
  320. border: none;
  321. cursor: pointer;
  322. transition: transform 0.1s ease, background-color 0.1s ease, box-shadow 0.1s ease;
  323. }
  324.  
  325. .on-off-button:last-child {
  326. background-color: #f44336;
  327. }
  328.  
  329. .on-off-button:active {
  330. transform: scale(0.95);
  331. background-color: #3b5a8e;
  332. box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.3);
  333. }
  334.  
  335. .on-off-button:last-child:active {
  336. background-color: #d32f2f;
  337. box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.3);
  338. }
  339.  
  340. .on-off-button:hover {
  341. background-color: #3c80b5;
  342. transition: background-color 0.3s;
  343. }
  344.  
  345. .on-off-button:last-child:hover {
  346. background-color: #e53935;
  347. transition: background-color 0.3s;
  348. }
  349.  
  350. #feedback-message {
  351. position: fixed;
  352. bottom: 20px;
  353. left: 50%;
  354. transform: translateX(-50%);
  355. background-color: #4CAF50;
  356. color: white;
  357. padding: 10px;
  358. border-radius: 5px;
  359. z-index: 1002;
  360. }
  361.  
  362. #hide-button {
  363. position: absolute;
  364. top: 0;
  365. left: 0;
  366. background-color: #ccc;
  367. color: white;
  368. border: none;
  369. padding: 2px 7px;
  370. cursor: pointer;
  371. }
  372.  
  373. #config-button {
  374. position: absolute;
  375. top: 0;
  376. left: 22px;
  377. background-color: #ccc;
  378. color: white;
  379. border: none;
  380. padding: 1px 4px;
  381. cursor: pointer;
  382. }
  383.  
  384. #hide-button, #config-button {
  385. position: absolute;
  386. background-color: #ccc;
  387. color: white;
  388. border: none;
  389. cursor: pointer;
  390. transition: background-color 0.3s, color 0.3s;
  391. }
  392.  
  393. #hide-button:hover, #config-button:hover {
  394. background-color: #888;
  395. color: #fff;
  396. }
  397.  
  398. #show-button {
  399. width: 40px;
  400. height: 40px;
  401. background: rgba(102, 204, 102, 0.5);
  402. backdrop-filter: blur(8px);
  403. border: 1px solid rgba(102, 204, 102, 0.4);
  404. border-radius: 50%;
  405. font-size: 26px;
  406. font-weight: bold;
  407. color: #fff;
  408. display: none;
  409. justify-content: center;
  410. align-items: center;
  411. cursor: pointer;
  412. transition: all 0.3s ease;
  413. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  414. pointer-events: auto;
  415. transform-origin: center;
  416. text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
  417. opacity: 0;
  418. animation: fadeIn 0.5s forwards;
  419. }
  420.  
  421. #show-button:hover {
  422. transform: scale(1.5);
  423. background: rgba(102, 204, 102, 0.8);
  424. font-size: 32px;
  425. box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
  426. }
  427.  
  428. #showButton:active {
  429. transform: scale(1.35);
  430. background: rgba(102, 204, 102, 0.8);
  431. transition: transform 0.05s ease;
  432. }
  433.  
  434. #showButton.fadeOut {
  435. animation: fadeOut 0.5s forwards;
  436. }
  437.  
  438. @keyframes fadeIn {
  439. from { opacity: 0; transform: scale(0.5); }
  440. to { opacity: 1; transform: scale(1); }
  441. }
  442.  
  443. @keyframes fadeOut {
  444. from { opacity: 1; transform: scale(1); }
  445. to { opacity: 0; transform: scale(0.5); }
  446. }
  447. `);
  448. })();