Price Helper

複製 Vendoritem ID / 商品連結;貼上 ID + 受託人(找不到受託人則僅貼 ID);清空搜尋欄。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Price Helper
// @namespace    AOScript
// @version      1.0
// @description  複製 Vendoritem ID / 商品連結;貼上 ID + 受託人(找不到受託人則僅貼 ID);清空搜尋欄。
// @author       AO-AO
// @match        https://price.tw.coupang.com/*
// @grant        none
// @license      MIT
// @run-at       document-idle
// ==/UserScript==

(function () {
  'use strict';

  /** ================================
   *  🔧 顯示/隱藏開關(true=顯示 / false=隱藏)
   *  ================================ */
  const ENABLE_VENDOR_ID          = true;  // 📋 複製 Vendoritem ID
  const ENABLE_ALL_LINKS          = false;  // 📋 複製所有商品連結(去重)
  const ENABLE_PASTE_ID_ASSIGNEE  = true;  // 📎 貼上 ID + 受託人(找不到受託人就只貼 ID)
  const ENABLE_CLEAR_INPUT        = true;  // 🧹 清空搜尋欄

  /** ================================
   *  📏 位置控制(可調)
   *  ================================ */
  const TOP_START = 50;     // 第一顆按鈕起始高度(再往下挪)
  const ROW_GAP   = 50;     // 同組內按鈕縱向間距
  const GROUP_GAP = 70;     // 上下兩組按鈕之間的大間距

  // --- 上組(兩顆) ---
  const top1 = TOP_START;                  // 第一顆
  const top2 = TOP_START + ROW_GAP;        // 第二顆
  // --- 下組(兩顆) ---
  const top3 = TOP_START + ROW_GAP + GROUP_GAP;             // 第三顆
  const top4 = TOP_START + ROW_GAP + GROUP_GAP + ROW_GAP;   // 第四顆

  /** ================================
   *  🎨 顯目配色
   *  ================================ */
  const palette = {
    vendorId: '#FF6B00',   // 橙色:Vendor ID
    allLinks: '#0078FF',   // 藍色:所有連結
    pasteIA:  '#00A651',   // 綠色:貼 ID + 受託人
    clearBox: '#E53935'    // 紅色:清空
  };

  // ✅ 模擬原生輸入,觸發框架監聽(AntD / React)
  function setNativeValue(element, value) {
    const prototype = Object.getPrototypeOf(element);
    const valueSetter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set;
    if (valueSetter) valueSetter.call(element, value);
    else element.value = value;
    element.dispatchEvent(new Event('input', { bubbles: true }));
    element.dispatchEvent(new Event('change', { bubbles: true }));
  }

  // ✅ 嘗試觸發搜尋(優先按搜尋按鈕,否則送 Enter)
  function triggerSearch(inputEl) {
    const searchBtn =
      document.querySelector('button[data-elm-id="Button__Search"]') ||
      document.querySelector('button[data-elm-id*="Search"]') ||
      document.querySelector('button[aria-label*="search" i]');
    if (searchBtn) {
      searchBtn.click();
      return;
    }
    if (inputEl) {
      const opts = { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13, which: 13 };
      inputEl.dispatchEvent(new KeyboardEvent('keydown', opts));
      inputEl.dispatchEvent(new KeyboardEvent('keypress', opts));
      inputEl.dispatchEvent(new KeyboardEvent('keyup', opts));
    }
  }

  // ✅ 通用按鈕建立(極簡樣式,字體跟隨頁面)
  function createButton(text, top, bgColor, onClick) {
    const btn = document.createElement('button');
    btn.textContent = text;
    btn.style.position = 'fixed';
    btn.style.top = `${top}px`;
    btn.style.right = '20px';
    btn.style.zIndex = '99999';
    btn.style.padding = '9px 11px';
    btn.style.backgroundColor = bgColor;
    btn.style.color = '#fff';
    btn.style.border = 'none';
    btn.style.borderRadius = '6px';
    btn.style.cursor = 'pointer';

    // 字體跟隨頁面原本大小(不固定 13px)
    const bodyFontSize = getComputedStyle(document.body)?.fontSize;
    if (bodyFontSize && bodyFontSize !== '0px') {
      btn.style.fontSize = bodyFontSize; // 例如 14px / 15px / 16px
    } // 否則不設置,讓瀏覽器自行繼承

    // 字型採用系統字體,與頁面相容
    btn.style.fontFamily = 'inherit';

    btn.addEventListener('click', (e) => onClick(e, btn));
    document.body.appendChild(btn);
  }

  // 🔎 取得 Vendoritem ID(取第一筆)
  function getVendorItemId() {
    const vendorDivs = Array.from(document.querySelectorAll('div[data-elm-id="text"]'))
      .filter((el) => el.textContent.trim() === 'Vendoritem ID')
      .map((el) => el.parentElement);
    if (vendorDivs.length === 0) return null;
    const vendorText = vendorDivs[0].textContent.replace('Vendoritem ID', '').trim();
    return vendorText || null;
  }

  // 🔎 取得受託人(顯示為「受託人 : 名字」)
  function getAssigneeName() {
    const assigneeSpan = document.querySelector('[data-elm-id="TaskAssigneeName"]');
    if (!assigneeSpan) return null;
    const m = assigneeSpan.textContent.match(/受託人\s*:\s*(\S+)/);
    return m && m[1] ? m[1].trim() : null;
  }

  const INPUT_SELECTOR = 'input[data-elm-id="Input__SearchFilter"]';

  // 1) 📋 複製 Vendoritem ID(可隱藏)
  if (ENABLE_VENDOR_ID) {
    createButton('📋 複製 Vendoritem ID', top1, palette.vendorId, (_e, btn) => {
      const id = getVendorItemId();
      if (!id) {
        alert('找不到 Vendoritem ID');
        return;
      }
      GM_setClipboard(id);
      btn.textContent = '✅ 已複製 ID';
      setTimeout(() => (btn.textContent = '📋 複製 Vendoritem ID'), 1500);
    });
  }

  // 2) 📋 複製所有商品連結(去重)(可隱藏)
  if (ENABLE_ALL_LINKS) {
    createButton('📋 複製所有連結', top2, palette.allLinks, (_e, btn) => {
      const links = document.querySelectorAll('a.ManualMappingListContainer__siteLink___hZYay');
      const hrefs = Array.from(links).map((link) => link.href).filter(Boolean);
      const uniqueHrefs = Array.from(new Set(hrefs));
      GM_setClipboard(uniqueHrefs.join('\n'));
      btn.textContent = `✅ 已複製 ${uniqueHrefs.length} 筆`;
      setTimeout(() => (btn.textContent = '📋 複製所有連結'), 1500);
    });
  }

  // 3) 📎 貼上 ID + 受託人(找不到受託人就只貼 ID)(可隱藏)
  if (ENABLE_PASTE_ID_ASSIGNEE) {
    createButton('📎 貼上 ID + 受託人', top3, palette.pasteIA, (_e, btn) => {
      const inputBox = document.querySelector(INPUT_SELECTOR);
      const id = getVendorItemId();
      const assignee = getAssigneeName();
      if (!inputBox || !id) {
        alert('找不到輸入框或 Vendoritem ID');
        return;
      }
      const combined = assignee ? `${id};${assignee}` : id;
      setNativeValue(inputBox, combined);
      triggerSearch(inputBox);
      btn.textContent = assignee ? '✅ 已貼上 ID + 受託人' : '✅ 已貼上 ID';
      setTimeout(() => (btn.textContent = '📎 貼上 ID + 受託人'), 1500);
    });
  }

  // 4) 🧹 清空搜尋欄(可隱藏)
  if (ENABLE_CLEAR_INPUT) {
    createButton('🧹 清空搜尋欄', top4, palette.clearBox, (_e, btn) => {
      const inputBox = document.querySelector(INPUT_SELECTOR);
      if (!inputBox) {
        alert('找不到輸入框');
        return;
      }
      setNativeValue(inputBox, '');
      triggerSearch(inputBox);
      btn.textContent = '✅ 已清空';
      setTimeout(() => (btn.textContent = '🧹 清空搜尋欄'), 1500);
    });
  }
})();
``