bcs上架插件

自动填写仓库字段、替换 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()