Greasy Fork 还支持 简体中文。

bcs上架插件

自动填写仓库字段、替换 cookie,并提取勾选行的 SKU、价格、图片,加价计算,支持店铺选择与一键添加

目前為 2025-05-01 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         bcs上架插件
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  自动填写仓库字段、替换 cookie,并提取勾选行的 SKU、价格、图片,加价计算,支持店铺选择与一键添加
// @match        https://www.bcsozon.com/selectionZone/china
// @match        https://www.bcsozon.com/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()