bcs上架插件

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 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()