您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动填写仓库字段、替换 cookie,并提取勾选行的 SKU、价格、图片,加价计算,支持店铺选择与一键添加
当前为
// ==UserScript== // @name bcs上架插件 // @namespace http://tampermonkey.net/ // @version 2.2 // @description 自动填写仓库字段、替换 cookie,并提取勾选行的 SKU、价格、图片,加价计算,支持店铺选择与一键添加 // @match https://www.bcsozon.top/selectionZone/china // @match https://www.bcsozon.top/selectionZone/chinaNew // @grant none // @license TANGMING // ==/UserScript== function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function init() { console.log("✅ 初始化插件..."); (function () { 'use strict'; // 添加按钮到页面 const button = document.createElement("button"); button.innerText = "采集商品并设置库存"; button.style.position = "fixed"; button.style.top = "100px"; button.style.right = "20px"; button.style.zIndex = "9999"; button.style.padding = "10px 16px"; button.style.background = "#409EFF"; button.style.color = "white"; button.style.border = "none"; button.style.borderRadius = "4px"; button.style.cursor = "pointer"; button.onclick = extractCheckedRows; document.body.appendChild(button); // 显示 loading 遮罩 function showLoading(text = "处理中...") { let loadingEl = document.createElement('div'); loadingEl.id = 'custom-loading-mask'; loadingEl.style.cssText = ` position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.4); z-index: 10000; display: flex; align-items: center; justify-content: center; `; loadingEl.innerHTML = ` <div style="background: white; padding: 24px 32px; border-radius: 10px; font-size: 18px; font-weight: bold; color: #409EFF; box-shadow: 0 0 15px rgba(0,0,0,0.2);"> 🔄 ${text} </div> `; document.body.appendChild(loadingEl); } // 隐藏 loading 遮罩 function hideLoading() { const loadingEl = document.getElementById('custom-loading-mask'); if (loadingEl) { loadingEl.remove(); } } // 显示右下角通知 function notify(msg, color = "#67C23A") { const notice = document.createElement('div'); notice.style.cssText = ` position: fixed; bottom: 30px; right: 30px; background: ${color}; color: white; padding: 10px 20px; border-radius: 6px; font-size: 14px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 10001; `; notice.innerText = msg; document.body.appendChild(notice); setTimeout(() => notice.remove(), 3000); } console.log("✅ 脚本已注入!"); const CHECKBOX_CLASS = 'my-checkbox-cell'; async function fetchShops() { try { const adminToken = document.cookie.split('; ').find(row => row.startsWith('Admin-Token='))?.split('=')[1]; if (!adminToken) { alert("❌ 未找到 Admin-Token,请检查是否已登录!"); return []; } const res = await fetch("https://www.bcsozon.top/prod-api/system/ozonShop/ozon/list", { headers: { accept: "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8", authorization: `Bearer ${adminToken}`, "cache-control": "no-cache", pragma: "no-cache" }, method: "GET", mode: "cors", credentials: "include" }); const data = await res.json(); return data?.data?.rows || []; } catch (err) { console.error("❌ 获取店铺失败", err); return []; } } function addControlPanel(shops) { const panel = document.createElement('div'); panel.style.cssText = ` position: fixed; top: 10px; right: 10px; z-index: 9999; background: #fff; padding: 12px; border: 1px solid #ddd; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); `; const options = shops.map(shop => `<option value="${shop.id}">${shop.shopUsername}</option>`).join(''); panel.innerHTML = ` <div style="margin-bottom: 8px;"> <select id="shopSelect" style="height: 36px; width: 200px;"> <option value="">请选择店铺</option> ${options} </select> </div> <div style="margin-bottom: 8px;"> <input type="text" id="shopNameInput" readonly placeholder="请选择店铺" class="el-input__inner" style="height: 36px; width: 200px;"> </div> <div style="margin-bottom: 8px;"> <button id="btnSelectAll" style="width: 200px; height: 36px; background: #67C23A; color: white; border: none; border-radius: 4px;">全选当前页</button> </div> <div style="margin-bottom: 8px;"> <button id="btnDeselectAll" style="width: 200px; height: 36px; background: #F56C6C; color: white; border: none; border-radius: 4px;">取消全选</button> </div> <div style="margin-bottom: 8px;"> <button id="btnExtract" style="width: 200px; height: 36px; background: #409EFF; color: white; border: none; border-radius: 4px;">采集商品并且设置库存</button> </div> `; document.body.appendChild(panel); // 全选按钮 document.getElementById('btnSelectAll').addEventListener('click', () => { const checkboxes = document.querySelectorAll('input[type="checkbox"].my-row-check'); checkboxes.forEach(checkbox => checkbox.checked = true); }); // 取消全选按钮 document.getElementById('btnDeselectAll').addEventListener('click', () => { const checkboxes = document.querySelectorAll('input[type="checkbox"].my-row-check'); checkboxes.forEach(checkbox => checkbox.checked = false); }); document.getElementById('btnExtract').addEventListener('click', extractCheckedRows); document.getElementById('btnMarkup').addEventListener('click', calculateMarkup); document.getElementById('btnAddToShop').addEventListener('click', addToSelectedShop); document.getElementById('shopSelect').addEventListener('change', (e) => { const selectedOption = e.target.options[e.target.selectedIndex]; document.getElementById('shopNameInput').value = selectedOption.text; }); } async function extractCheckedRows() { const button = document.getElementById('btnExtract'); button.disabled = true; const originalText = button.innerText; button.innerText = "处理中..."; const checkedRows = []; const token = document.cookie.split('; ').find(c => c.startsWith('Admin-Token='))?.split('=')[1]; if (!token) { alert("❌ 未获取到 Admin-Token,请确认已登录!"); button.disabled = false; button.innerText = originalText; return; } const checkboxes = document.querySelectorAll('input[type="checkbox"].my-row-check:checked'); if (checkboxes.length === 0) { alert("⚠️ 没有勾选任何行!"); button.disabled = false; button.innerText = originalText; return; } const clientId = document.getElementById('shopSelect').value; if (!clientId) { alert("❌ 请选择一个店铺!"); button.disabled = false; button.innerText = originalText; return; } showLoading("正在采集并设置库存,请稍候..."); try { // 获取仓库 ID const res = await fetch("https://www.bcsozon.top/prod-api/system/ozonRecord/warehouse", { method: "POST", credentials: "include", headers: { "accept": "application/json, text/plain, */*", "content-type": "application/json;charset=UTF-8", "authorization": "Bearer " + token, }, body: JSON.stringify({shopId: clientId}) }); const result = await res.json(); const warehouse_id = result?.data?.result?.[0]?.warehouse_id; if (!warehouse_id) throw new Error("未获取到仓库ID"); // 获取用户名 const profile_res = await fetch("https://www.bcsozon.top/prod-api/system/user/profile", { method: "GET", credentials: "include", headers: { "authorization": "Bearer " + token }, }); const profile_res_json = await profile_res.json(); const userName = profile_res_json?.data?.userName; const sku_list = [] // 逐个处理勾选项 for (const checkbox of checkboxes) { const row = checkbox.closest('tr'); const cells = row.querySelectorAll('td'); const img = row.querySelector('img')?.src || ''; const sku = cells[2]?.innerText.trim(); const priceText = cells[14]?.innerText.trim(); const price = parseFloat(priceText?.replace(/[^\d.]/g, '') || 0); try { const catRes = await fetch("https://www.bcsozon.top/prod-api/system/ozonRecord/getCategoryId", { method: "POST", credentials: "include", headers: { "authorization": "Bearer " + token, "content-type": "application/json;charset=UTF-8" }, body: JSON.stringify({ oModel: true, brandStatus: true, sku }) }); const categoryId = (await catRes.json())?.data; // 添加商品 const addRes = await fetch("https://www.bcsozon.top/prod-api/system/ozonRecord/ht/user/add", { method: "POST", credentials: "include", headers: { "authorization": "Bearer " + token, "content-type": "application/json;charset=UTF-8" }, body: JSON.stringify({ oModel: true, brandStatus: true, sku: parseInt(sku), categoryId: categoryId, categories: [], price: price * 0.0856 * 2.15, shopIds: [parseInt(clientId)], sourcess: [] }) }); const addJson = await addRes.json(); if (addJson.code === 200) { sku_list.push(sku) } else { alert(`❌ SKU ${sku} 添加失败:${addJson.msg || "未知错误"}`); } checkedRows.push({img, sku, price, categoryId}); } catch (itemErr) { console.error(`❌ 处理 SKU ${sku} 时出错:`, itemErr); alert(`❌ SKU ${sku} 处理失败,请检查控制台`); } } // 设置库存 setTimeout(async () => { const ofprid_list = [] fetch("https://www.bcsozon.top/prod-api/system/ozonRecord/fixOzonStatus", { method: "GET", credentials: "include", headers: { "authorization": "Bearer " + token } }); await sleep(3000) for (let i = 0; i < sku_list.length; i++) { const prodRes = await fetch(`https://www.bcsozon.top/prod-api/system/ozonRecord/ozon/list?pageNum=1&pageSize=10&username=${userName}&sku=${sku_list[i]}`, { method: "GET", credentials: "include", headers: { "authorization": "Bearer " + token } }); const prodData = await prodRes.json(); const ofprid = prodData?.rows?.[0]?.offerId; const productId = prodData?.rows?.[0]?.productId; ofprid_list.push(`${ofprid},${productId}`) } await sleep(3000) fetch("https://www.bcsozon.top/prod-api/system/ozonRecord/pl/add/stocks", { method: "POST", credentials: "include", headers: { "authorization": "Bearer " + token, "content-type": "application/json;charset=UTF-8" }, body: JSON.stringify({ warehouseId: warehouse_id, stock: "999", ofprid: ofprid_list, shopId: clientId }) }); await sleep(2000) fetch("https://www.bcsozon.top/prod-api/system/ozonRecord/pl/add/stocks", { method: "POST", credentials: "include", headers: { "authorization": "Bearer " + token, "content-type": "application/json;charset=UTF-8" }, body: JSON.stringify({ warehouseId: warehouse_id, stock: "999", ofprid: ofprid_list, shopId: clientId }) }); }, 1 * 60 * 1000); console.table(checkedRows); hideLoading(); notify("✅ 处理完成"); alert(`✅ 成功处理 ${checkedRows.length} 个商品!十分钟后设置库存,请不要刷新网页`); window._checkedRows = checkedRows; } catch (err) { console.error("❌ 整体处理失败:", err); alert("❌ 操作失败,请查看控制台详情!"); } finally { button.disabled = false; button.innerText = originalText; } } function addCheckboxToRows(rows) { rows.forEach((row, index) => { if (row.querySelector(`.${CHECKBOX_CLASS}`)) return; const checkboxTd = document.createElement('td'); checkboxTd.className = `el-table__cell ${CHECKBOX_CLASS} is-center`; checkboxTd.style.textAlign = 'center'; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.className = 'my-row-check'; checkbox.dataset.index = index; checkboxTd.appendChild(checkbox); row.insertBefore(checkboxTd, row.firstChild); }); } function addCheckboxHeader() { const headerRow = document.querySelector('.el-table__header-wrapper thead tr'); if (headerRow && !headerRow.querySelector(`.${CHECKBOX_CLASS}`)) { const th = document.createElement('th'); th.className = `el-table__cell ${CHECKBOX_CLASS} is-center`; th.innerText = '选择'; headerRow.insertBefore(th, headerRow.firstChild); } } const waitForTable = setInterval(async () => { const rows = document.querySelectorAll('.el-table__body-wrapper tbody tr'); if (rows.length > 0) { clearInterval(waitForTable); addCheckboxToRows(rows); addCheckboxHeader(); const shops = await fetchShops(); addControlPanel(shops); } }, 500); })(); } function addRefreshButton() { // 避免重复添加 if (document.getElementById('refresh-selection-btn')) return; const btn = document.createElement('button'); btn.innerText = '触发插件'; btn.id = 'refresh-selection-btn'; btn.style.position = 'fixed'; btn.style.top = '20px'; btn.style.right = '20px'; btn.style.zIndex = '9999'; btn.style.padding = '10px 15px'; btn.style.backgroundColor = '#4CAF50'; btn.style.color = 'white'; btn.style.border = 'none'; btn.style.borderRadius = '5px'; btn.style.cursor = 'pointer'; btn.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)'; btn.onclick = () => { console.log("触发插件"); init() }; document.body.appendChild(btn); } addRefreshButton()