Greasy Fork

Greasy Fork is available in English.

小红书广告数据查询与展示

在当前页面插入悬浮元素,点击展开窗口并发送请求,将结果展示在表格中并提供Excel下载按钮

当前为 2025-03-31 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         小红书广告数据查询与展示
// @namespace    http://tampermonkey.net/
// @version      1.12
// @description  在当前页面插入悬浮元素,点击展开窗口并发送请求,将结果展示在表格中并提供Excel下载按钮
// @author       You
// @match        https://ad.xiaohongshu.com/aurora*
// @grant        GM_xmlhttpRequest
// @connect      ad.xiaohongshu.com
// @license MIT
// ==/UserScript==

(function () {
  "use strict";

  function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  //提示==========

  // 注入样式
  const style = document.createElement("style");
  style.textContent = `
.custom-toast {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    padding: 12px 24px;
    border-radius: 4px;
    background: #333;
    color: white;
    box-shadow: 0 2px 8px rgba(0,0,0,0.2);
    opacity: 0;
    transition: all 0.3s ease;
    z-index: 9999;
    top: 20px;
    margin-top: 0;
}
.custom-toast.show {
    opacity: 1;
    margin-top: 0 !important;
}
.custom-toast.success { background: #67c23a; }
.custom-toast.warning { background: #e6a23c; }
.custom-toast.error { background: #f56c6c; }
.custom-toast.info { background: #909399; }
`;
  document.head.appendChild(style);

  // 提示队列管理
  const toastStack = {
    list: [],
    add(toast) {
      this.list.push(toast);
      this.updatePositions();
    },
    remove(toast) {
      this.list = this.list.filter((t) => t !== toast);
      this.updatePositions();
    },
    updatePositions() {
      this.list.forEach((toast, index) => {
        const baseTop = 20;
        const spacing = 60;
        const targetTop = baseTop + index * spacing;
        toast.style.top = `${targetTop}px`;
      });
    },
  };

  // 提示函数
  window.showToast = function (message, type = "info", duration = 3000) {
    const toast = document.createElement("div");
    toast.className = `custom-toast ${type}`;
    toast.textContent = message;

    document.body.appendChild(toast);
    void toast.offsetHeight; // 触发重绘

    toastStack.add(toast);
    toast.classList.add("show");

    setTimeout(() => {
      toast.classList.remove("show");
      setTimeout(() => {
        toast.remove();
        toastStack.remove(toast);
      }, 300);
    }, duration);
  };

  // // 使用示例
  // showToast('第一个提示', 'success');
  // setTimeout(() => showToast('第二个提示在下方', 'error'), 500);
  // setTimeout(() => showToast('第三个提示继续下移', 'info'), 1000);

  //提示----------

  //圆球=====================
  const sheet = new CSSStyleSheet();
  sheet.replaceSync(`
    /* 加载转圈圈 */
.loading {
  width: 30px;
  height: 30px;
  border: 2px solid #000;
  border-top-color: transparent;
  border-radius: 100%;

  animation: circle infinite 0.75s linear;
}
/* 加载转圈圈动画 */
@keyframes circle {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

/* 下面是卡片的样式 */
      #overlay {
        position: fixed;
        top: 50%;
        left: 50%;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.5);
        z-index: 999;
        transform: translate(-50%, -50%);
      }
      #card {
        position: fixed;
        top: 50%;
        left: 50%;
        width: 500px; /* 设置卡片的宽度 */
        height: 300px; /* 设置卡片的高度 */
        background-color: white;
        border: 1px solid #0057ff ;
        padding: 20px;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        z-index: 2147483647;
        transform: translate(-50%, -50%);
        border-radius: 8px
      }

/* 下面是卡片中输入框还有下拉框的样式 */

 #card select {
    width: 100%;
    padding: 12px 20px;
    margin: 8px 0;
    box-sizing: border-box;
    border: 2px solid #ccc;
    border-radius: 4px;
    background-color: #f8f8f8;
    font-size: 16px;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007CB2%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');
    background-repeat: no-repeat;
    background-position: right 10px top 50%;
    background-size: 12px 12px;
}

 #card label {
    display: block;
    margin-bottom: 8px;
    font-size: 16px;
    color: #333;
    font-weight: bold;
}
    #card input[type="text"],#card textarea {
    width: 100%;
    padding: 12px 20px;
    margin: 8px 0;
    box-sizing: border-box;
    border: 2px solid #ccc;
    border-radius: 4px;
    background-color: #f8f8f8;
    font-size: 16px;
}
    #card button,.card button {
    margin-bottom: 10px;
    margin-top: 10px;
    margin-left: 10px;
margin-right: 10px;
    padding: 8px 16px;
    background-color: rgb(0, 102, 204);
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    
}

  `);

  function addStyleSheet(sheet) {
    const allSheets = [...document.adoptedStyleSheets, sheet];
    document.adoptedStyleSheets = allSheets;
  }
  addStyleSheet(sheet);
  // 存储请求返回的数据
  let responseData = [];
  function addBallAttributes(ball, text) {
    ball.style.cssText = `
      position: fixed; 
      right: 10px; 
      bottom: 10px; 
      width: 60px; 
      height: 60px; 
      background-color: #0066CC; 
      border-radius: 50%; 
      cursor: pointer; 
      display: flex; 
      align-items: center; 
      justify-content: center; 
      font-size: 12px; 
      color: white; 
      z-index: 9999;
    `;
    ball.textContent = text;
  }
  // 创建隐藏的小球元素
  const ball = document.createElement("div");
  addBallAttributes(ball, "检查链接");
  document.body.appendChild(ball);

  // 创建悬浮窗口元素
  const floatingWindow = document.createElement("div");
  floatingWindow.style.cssText = `
    position: fixed; 
    right: 20px; 
    top: 20px; 
    width: 50vw; 
    height: 80vh; 
    background-color: white; 
    border: 1px solid #0066CC; 
    border-radius: 8px; 
    display: none; 
    padding: 20px; 
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 
    z-index: 9999;
  `; // 改成 cssom
  document.body.appendChild(floatingWindow);

  // 创建关闭按钮
  const closeButton = document.createElement("div");
  closeButton.style.cssText = `
    position: absolute; 
    right: 10px; 
    top: 10px; 
    cursor: pointer; 
    font-size: 20px; 
    color: #0066CC;
  `; // 改成 cssom
  closeButton.innerHTML = "×";
  floatingWindow.appendChild(closeButton);

  // 创建按钮容器
  const buttonContainer = document.createElement("div");
  buttonContainer.style.cssText = `
    margin-bottom: 20px;
  `; // 改成 cssom
  floatingWindow.appendChild(buttonContainer);
  function addButtonAttributes(checkButton, text) {
    checkButton.textContent = text; //"检查";
    checkButton.style.cssText = `
      margin-right: 10px; 
      padding: 8px 16px; 
      background-color: #0066CC; 
      color: white; 
      border: none; 
      border-radius: 4px; 
      cursor: pointer;
    `; // 改成 cssom
  }
  // 创建检查按钮
  const checkButton = document.createElement("button");
  addButtonAttributes(checkButton, "检查");
  buttonContainer.appendChild(checkButton);

  // 创建下载按钮
  const downloadButton = document.createElement("button");
  addButtonAttributes(downloadButton, "下载");
  buttonContainer.appendChild(downloadButton);

  // 创建链接统计文本容器
  const linkStatsContainer = document.createElement("div");
  linkStatsContainer.style.cssText = `
    margin-bottom: 20px; 
    font-size: 14px; 
    color: #333333;
  `; // 改成 cssom
  floatingWindow.appendChild(linkStatsContainer);

  // 创建表格容器
  const tableContainer = document.createElement("div");
  tableContainer.style.cssText = `
    height: calc(100% - 100px); 
    overflow-y: auto; 
    overflow-x: auto;
  `; // 改成 cssom
  floatingWindow.appendChild(tableContainer);

  // 创建进度条
  const progressBar = document.createElement("progress");
  progressBar.style.cssText = `
    width: 100%; 
    margin-top: 10px; 
    display: none;
  `; // 改成 cssom
  progressBar.value = 0;
  progressBar.max = 100;
  floatingWindow.appendChild(progressBar);

  // 显示小球
  ball.style.display = "flex";

  // 点击小球展开悬浮窗口
  ball.addEventListener("click", function () {
    floatingWindow.style.display = "block";
    ball.style.display = "none";
  });

  // 点击关闭按钮
  closeButton.addEventListener("click", function () {
    floatingWindow.style.display = "none";
    ball.style.display = "flex";
    tableContainer.innerHTML = "";
    linkStatsContainer.innerHTML = "";
    responseData = []; // 清空存储的数据
  });

  // 点击检查按钮发送请求
  checkButton.addEventListener("click", function () {
    checkButton.disabled = true;
    checkButton.style.backgroundColor = "rgb(105, 102, 102)";
    const loading = document.createElement("div");
    loading.className = "loading";
    loading.id = "loading-indicator"; // 添加一个唯一ID
    tableContainer.appendChild(loading);
    sendRequest().then(() => {
      checkButton.disabled = false;
      checkButton.style.backgroundColor = "rgb(0, 102, 204)";

      // 使用更安全的方式移除loading
      const loadingElement = document.getElementById("loading-indicator");
      if (loadingElement) {
        loadingElement.remove();
      }
    });
  });

  // 点击下载按钮
  downloadButton.addEventListener("click", function () {
    if (responseData.length > 0) {
      downloadExcel(responseData);
    } else {
      alert("没有可下载的数据!");
    }
  });

  // 发送请求
  async function sendRequest() {
    let maxPageNum = 4;
    let pageNum = 1;
    let totalPage = 1;
    let allData = [];
    do {
      const response = await fetch(
        `https://ad.xiaohongshu.com/api/leona/rtb/creativity/list?pageNum=${pageNum}&pageSize=50`,
        {
          method: "POST",
          headers: {
            accept: "application/json, text/plain, */*",
            "accept-language":
              "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
            "content-type": "application/json;charset=UTF-8",
            priority: "u=1, i",
            "sec-ch-ua":
              '"Not A(Brand";v="8", "Chromium";v="132", "Microsoft Edge";v="132"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "same-origin",
          },
          body: JSON.stringify({
            startTime: new Date().toISOString().split("T")[0],
            endTime: new Date().toISOString().split("T")[0],
            pageNum: pageNum,
            pageSize: 50,
          }),
        }
      );
      const data = await response.json();
      // console.log(data.data.list);

      allData = allData.concat(data.data.list);
      totalPage = data.data.totalPage;
      pageNum++;
    } while (pageNum <= totalPage || pageNum <= maxPageNum);

    try {
      // 保存响应数据
      responseData = allData;

      // 统计链接重复次数
      const clickUrlCounts = {};
      const expoUrlCounts = {};

      allData.forEach((item) => {
        if (item.clickUrls && item.clickUrls[0]) {
          const clickUrl = extractUrlParam(item.clickUrls[0]);
          clickUrlCounts[clickUrl] = (clickUrlCounts[clickUrl] || 0) + 1;
        }
        if (item.expoUrls && item.expoUrls[0]) {
          const expoUrl = extractUrlParam(item.expoUrls[0]);
          expoUrlCounts[expoUrl] = (expoUrlCounts[expoUrl] || 0) + 1;
        }
      });

      // 读取option 本地持久化的存储
      const storedOption = localStorage.getItem("data");
      const option = JSON.parse(storedOption);
      option.forEach((item) => {
        const link = item.link;
        const relink = link.match(/e=[^&]+/);
        if (relink) {
          item.relink = relink[0];
        } else {
          item.relink = link;
        }
      });
      console.log(option);

      if (storedOption) {
        Object.entries(clickUrlCounts).forEach(([url, count]) => {
          if (url) {
            const div = document.createElement("div");
            div.style.cssText = `
                    margin-bottom: 5px;
                  `; // 改成 cssom
            div.textContent = `点击链接:${url} 有${count}条`;
            const relink = url.match(/e=.*?(&|$)/)[0];
            if (option.some((item) => item.relink === relink)) {
              div.textContent += ` 配置符合:${
                option.find((item) => item.relink === relink).name
              }`;
            } else {
              div.textContent += " 无配置符合";
            }
            linkStatsContainer.appendChild(div);
          }
        });

        Object.entries(expoUrlCounts).forEach(([url, count]) => {
          if (url) {
            const div = document.createElement("div");
            div.style.cssText = `
                    margin-bottom: 5px;
                  `; // 改成 cssom
            div.textContent = `曝光链接:${url} 有${count}条`;
            const relink = url.match(/e=.*?(&|$)/)[0];
            if (option.some((item) => item.relink === relink)) {
              div.textContent += ` 配置符合:${
                option.find((item) => item.relink === relink).name
              }`;
            } else {
              div.textContent += " 无配置符合";
            }
            linkStatsContainer.appendChild(div);
          }
        });
      } else {
        Object.entries(clickUrlCounts).forEach(([url, count]) => {
          if (url) {
            const div = document.createElement("div");
            div.style.cssText = `
                    margin-bottom: 5px;
                  `; // 改成 cssom
            div.textContent = `点击链接:${url} 有${count}条`;
            div.textContent += " 无配置符合";
            linkStatsContainer.appendChild(div);
          }
        });

        Object.entries(expoUrlCounts).forEach(([url, count]) => {
          if (url) {
            const div = document.createElement("div");
            div.style.cssText = `
                    margin-bottom: 5px;
                  `; // 改成 cssom
            div.textContent = `曝光链接:${url} 有${count}条`;
            div.textContent += " 无配置符合";
            linkStatsContainer.appendChild(div);
          }
        });
      }

      createTable(allData);
      showToast("读取成功", "success");
    } catch (error) {
      console.error("解析响应数据时出错:", error);
      showToast("读取报错,可能是没有配置", "error");
    }
  }

  // 提取URL参数
  function extractUrlParam(url) {
    const match = url.match(/https:\/\/magellan.alimama.com\/(.*?)&/);
    return match ? match[1] : "";
  }

  // 创建表格
  function createTable(data) {
    const table = document.createElement("table");
    table.style.cssText = `
      width: 100%; 
      border-collapse: collapse; 
      background-color: white;
    `; // 改成 cssom

    // 创建表头
    const thead = document.createElement("thead");
    thead.style.cssText = `
      background-color: #0066CC;
    `; // 改成 cssom
    const headerRow = document.createElement("tr");
    const headers = ["创建时间", "创意名", "创意ID", "点击链接", "曝光链接"];
    headers.forEach((headerText) => {
      const th = document.createElement("th");
      th.style.cssText = `
        border: 1px solid #0066CC; 
        padding: 12px; 
        color: white; 
        font-weight: bold;
      `; // 改成 cssom
      th.textContent = headerText;
      headerRow.appendChild(th);
    });
    thead.appendChild(headerRow);
    table.appendChild(thead);

    // 创建表体
    const tbody = document.createElement("tbody");
    data.forEach((item, index) => {
      const row = document.createElement("tr");
      row.style.cssText = `
        background-color: ${index % 2 === 0 ? "#F5F8FA" : "white"};
      `; // 改成 cssom

      const createTime = item.creativityCreateTime;
      const creativityName = item.creativityName;
      const creativityId = item.creativityId;
      const clickUrl = item.clickUrls
        ? JSON.stringify(item.clickUrls.map(extractUrlParam)).replace(
            /,/g,
            "\n"
          )
        : "";
      const expoUrl = item.expoUrls
        ? JSON.stringify(item.expoUrls.map(extractUrlParam)).replace(/,/g, "\n")
        : "";

      const values = [
        createTime,
        creativityName,
        creativityId,
        clickUrl,
        expoUrl,
      ];
      values.forEach((value) => {
        const td = document.createElement("td");
        td.style.cssText = `
          border: 1px solid #E5E5E5; 
          padding: 12px; 
          color: #333333;
        `; // 改成 cssom
        td.textContent = value;
        row.appendChild(td);
      });
      tbody.appendChild(row);
    });
    table.appendChild(tbody);

    // 清空表格容器并插入新表格
    tableContainer.innerHTML = "";
    tableContainer.appendChild(table);
  }

  // 下载Excel
  function downloadExcel(data) {
    // 添加BOM头,解决中文乱码问题
    const BOM = "\uFEFF";
    const headers = ["创建时间", "创意名", "创意ID", "点击链接", "曝光链接"];
    const csvContent = [headers.join(",")];

    data.forEach((item) => {
      const createTime = item.creativityCreateTime || "";
      const creativityName = item.creativityName || "";
      const creativityId = item.creativityId || "";
      const clickUrl =
        item.clickUrls && item.clickUrls[0]
          ? JSON.stringify(item.clickUrls.map(extractUrlParam)).replace(
              /,/g,
              "\n"
            )
          : "";
      const expoUrl =
        item.expoUrls && item.expoUrls[0]
          ? JSON.stringify(item.expoUrls.map(extractUrlParam)).replace(
              /,/g,
              "\n"
            )
          : "";

      // 处理CSV中的特殊字符
      const escapeCsvValue = (value) => {
        if (typeof value !== "string") return value;
        if (
          value.includes(",") ||
          value.includes('"') ||
          value.includes("\n")
        ) {
          return `"${value.replace(/"/g, '""')}"`;
        }
        return value;
      };

      const values = [
        createTime,
        creativityName,
        creativityId,
        clickUrl,
        expoUrl,
      ].map(escapeCsvValue);
      csvContent.push(values.join(","));
    });

    const csv = BOM + csvContent.join("\n");
    const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    const timestamp = new Date().toLocaleString().replace(/[/:]/g, "-");

    link.setAttribute("href", url);
    link.setAttribute("download", `data_${timestamp}.csv`);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
  }

  function option() {
    const div = document.createElement("div");
    div.className = "card";
    div.style.cssText = `
        position: absolute; 
        top: 50%; 
        left: 50%; 
        transform: translate(-50%, -50%); 
        z-index: 9999; 
        width: 500px; 
        height: 300px; 
        overflow-x: auto; 
        overflow-y: auto; 
        background: white; 
        border: 1px solid rgb(0, 102, 204); 
        border-radius: 8px;
      `;
    const table = document.createElement("table");
    table.style.cssText = `
        width: 100%; 
        border-collapse: collapse;
      `;
    const addButton = document.createElement("button");
    addButton.textContent = "添加";
    addButton.onclick = () => {
      const newRow = document.createElement("tr");
      const newTd1 = document.createElement("td");
      const newLinkInput = document.createElement("input");
      newLinkInput.type = "text";
      newTd1.appendChild(newLinkInput);
      newRow.appendChild(newTd1);
      const newTd2 = document.createElement("td");
      const newNameInput = document.createElement("input");
      newNameInput.type = "text";
      newTd2.appendChild(newNameInput);
      newRow.appendChild(newTd2);
      tbody.insertBefore(newRow, tbody.children[0]);
    };
    const saveButton = document.createElement("button");
    saveButton.textContent = "保存(关闭)";
    saveButton.onclick = () => {
      const rows = tbody.rows;
      const data = [];
      for (let i = 0; i < rows.length; i++) {
        const link = rows[i].cells[0].children[0].value;
        const name = rows[i].cells[1].children[0].value;
        data.push({ link, name });
      }
      localStorage.setItem("data", JSON.stringify(data));
      div.style.display = "none";
    };
    const clearButton = document.createElement("button");
    clearButton.textContent = "清空";
    clearButton.onclick = () => {
      tbody.innerHTML = ""; // 清空tbody中的所有内容
    };
    div.appendChild(addButton);
    div.appendChild(saveButton);
    div.appendChild(clearButton);

    const thead = document.createElement("thead");
    const tr = document.createElement("tr");
    const th1 = document.createElement("th");
    th1.textContent = "链接";
    tr.appendChild(th1);
    const th2 = document.createElement("th");
    th2.textContent = "名字";
    tr.appendChild(th2);
    thead.appendChild(tr);

    const tbody = document.createElement("tbody");
    const storedData = localStorage.getItem("data");
    if (storedData) {
      const data = JSON.parse(storedData);
      data.forEach((item) => {
        const row = document.createElement("tr");
        const td1 = document.createElement("td");
        const linkInput = document.createElement("input");
        linkInput.type = "text";
        linkInput.value = item.link;
        td1.appendChild(linkInput);
        row.appendChild(td1);
        const td2 = document.createElement("td");
        const nameInput = document.createElement("input");
        nameInput.type = "text";
        nameInput.value = item.name;
        td2.appendChild(nameInput);
        row.appendChild(td2);
        tbody.appendChild(row);
      });
    } else {
      const row = document.createElement("tr");
      const td1 = document.createElement("td");
      const linkInput = document.createElement("input");
      linkInput.type = "text";
      td1.appendChild(linkInput);
      row.appendChild(td1);
      const td2 = document.createElement("td");
      const nameInput = document.createElement("input");
      nameInput.type = "text";
      td2.appendChild(nameInput);
      row.appendChild(td2);
      tbody.appendChild(row);
    }

    table.appendChild(thead);
    table.appendChild(tbody);
    div.appendChild(table);
    document.body.appendChild(div);
  }

  //tools==================
  function create_car() {
    // 创建遮罩层
    const overlay = document.createElement("div");
    overlay.id = "overlay";

    // 创建卡片
    const card = document.createElement("div");
    card.id = "card";

    // 创建关闭按钮
    const closeButton = document.createElement("span");
    closeButton.textContent = "x";
    closeButton.style.position = "absolute";
    closeButton.style.top = "10px";
    closeButton.style.right = "10px";
    closeButton.style.cursor = "pointer";
    closeButton.addEventListener("click", function () {
      document.body.removeChild(overlay);
      document.body.removeChild(card);
    });
    card.appendChild(closeButton);
    return {
      overlay,
      card,
      closeButton,
    };
  }

  //tools-------------------
  //======================改名
  // 创建打开卡片的按钮
  const openButton = document.createElement("button");
  addButtonAttributes(openButton, "修改单元内计划字符");

  // 为打开按钮添加点击事件监听器
  openButton.addEventListener("click", function () {
    const { overlay, card, closeButton } = create_car();

    // 创建第一个输入框及其标签
    const oldCharLabel = document.createElement("label");
    oldCharLabel.textContent = "旧字符";
    const oldCharInput = document.createElement("input");
    oldCharInput.type = "text";

    // 创建第二个输入框及其标签
    const newCharLabel = document.createElement("label");
    newCharLabel.textContent = "新字符";
    const newCharInput = document.createElement("input");
    newCharInput.type = "text";

    // 创建替换按钮
    const replaceButton = document.createElement("button");
    replaceButton.textContent = "替换";
    replaceButton.addEventListener("click", async function () {
      const oldChar = oldCharInput.value;
      const newChar = newCharInput.value;
      await mainSend(oldChar, newChar);

      // 这里可以执行其他脚本,例如替换页面上的文本
      console.log(`将 "${oldChar}" 替换为 "${newChar}"`);
    });

    // 将元素添加到卡片中
    card.appendChild(closeButton);
    card.appendChild(oldCharLabel);
    card.appendChild(oldCharInput);
    card.appendChild(newCharLabel);
    card.appendChild(newCharInput);
    card.appendChild(replaceButton);

    // 将遮罩层和卡片添加到页面中
    document.body.appendChild(overlay);
    document.body.appendChild(card);
  });

  async function mainSend(old1, new1) {
    const n = location.href.match(/[0-9]{1,20}/g);
    const r = await fetch(
      "https://ad.xiaohongshu.com/api/leona/rtb/creativity/list",
      {
        headers: {
          accept: "application/json, text/plain, */*",
          "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
          "content-type": "application/json;charset=UTF-8",
          priority: "u=1, i",
          "sec-ch-ua":
            '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"',
          "sec-ch-ua-mobile": "?0",
          "sec-ch-ua-platform": '"macOS"',
          "sec-fetch-dest": "empty",
          "sec-fetch-mode": "cors",
          "sec-fetch-site": "same-origin",
          "x-b3-traceid": "37e8ffc9e25f798c",
        },
        referrer:
          "https://ad.xiaohongshu.com/aurora/ad/manage/103584356/192658846/creativity",
        referrerPolicy: "strict-origin-when-cross-origin",
        body: `{\"campaignId\":${n[0]},\"unitId\":${n[1]},\"startTime\":\"${
          new Date().toISOString().split("T")[0]
        }\",\"endTime\":\"${
          new Date().toISOString().split("T")[0]
        }\",\"pageNum\":1,\"pageSize\":50}`,
        method: "POST",
        mode: "cors",
        credentials: "include",
      }
    );

    const j = await r.json();
    const total = j.data.list.length;
    let completed = 0;
    const sheet = new CSSStyleSheet();
    sheet.replaceSync(`
      #progressBar {
        width: 0;
        height: 20px;
        background-color: #54FF9F;
        position: fixed;
        bottom: 10px;
        left: 50%;
        transform: translateX(-50%);
        z-index: 2147483647;
      }
    `);
    addStyleSheet(sheet);
    // document.adoptedStyleSheets = [sheet];
    const progressBar = document.createElement("div");
    progressBar.id = "progressBar";
    progressBar.innerText = "进度";
    document.body.appendChild(progressBar);

    for (let index = 0; index < j.data.list.length; index++) {
      const element = j.data.list[index];
      const oldName = element.creativityName;
      const regex = new RegExp(old1, "g");
      const newName = oldName.replace(regex, new1);
      await reanmeSend(element.creativityId, newName);
      completed++;
      const progress = (completed / total) * 100;
      progressBar.style.width = `${progress}%`;
    }

    document.body.removeChild(progressBar);
    showToast("完成", "success");
    // alert("完成");
  }
  async function reanmeSend(id, name) {
    return fetch(
      "https://ad.xiaohongshu.com/api/leona/rtb/creativity/batch/update/name",
      {
        headers: {
          accept: "application/json, text/plain, */*",
          "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
          "content-type": "application/json;charset=UTF-8",
          priority: "u=1, i",
          "sec-ch-ua":
            '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"',
          "sec-ch-ua-mobile": "?0",
          "sec-ch-ua-platform": '"macOS"',
          "sec-fetch-dest": "empty",
          "sec-fetch-mode": "cors",
          "sec-fetch-site": "same-origin",
          "x-b3-traceid": "dee287ce9b6526cc",
        },
        //"referrer": "https://ad.xiaohongshu.com/aurora/ad/manage/103596579/192712174/creativity",
        referrerPolicy: "strict-origin-when-cross-origin",
        body: `{\"creativityId\":${id},\"creativityName\":\"${name}\"}`,
        method: "POST",
        mode: "cors",
        credentials: "include",
      }
    );
  }

  //调价函数======================

  function getCurrentTimestamp() {
    return Math.floor(Date.now() / 1000);
  }

  async function getData(body, bid, result) {
    body.removeBind = 0;
    body.sourceFlag = "web";
    body.pageEnterTime = getCurrentTimestamp() - 10;
    body.pageSubmitTime = getCurrentTimestamp();
    body.keywordWithBid.map((e) => {
      e.bid = bid * 100;
    });
    const r = await fetch("https://ad.xiaohongshu.com/api/leona/rtb/unit", {
      headers: {
        accept: "application/json, text/plain, */*",
        "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        "content-type": "application/json",
        priority: "u=1, i",
        "sec-ch-ua":
          '"Chromium";v="134", "Not:A-Brand";v="24", "Microsoft Edge";v="134"',
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": '"Windows"',
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors",
        "sec-fetch-site": "same-origin",
        "x-b3-traceid": "631398efd0ea1db1",
      },
      // "referrer": "https://ad.xiaohongshu.com/aurora/ad/edit/unit/107358958/208378008/4/2?byManage=true&manageLevel=byAccount&AFormGrayFlag=false",
      referrerPolicy: "strict-origin-when-cross-origin",
      body: JSON.stringify(body),
      method: "PUT",
      mode: "cors",
      credentials: "include",
    });
    const j = await r.json();
    showToast(`单元${body.unitName}调整出价${bid},${j.msg}`, "success");
    console.log(`单元${body.unitName}调整出价${bid},${j.msg}`);
    result.push(`单元${body.unitName}调整出价${bid},${j.msg}`);
  }

  async function set_bid(bid) {
    const r = await fetch(
      "https://ad.xiaohongshu.com/api/leona/rtb/unit/search",
      {
        headers: {
          accept: "application/json, text/plain, */*",
          "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
          "content-type": "application/json",
          priority: "u=1, i",
          "sec-ch-ua":
            '"Chromium";v="134", "Not:A-Brand";v="24", "Microsoft Edge";v="134"',
          "sec-ch-ua-mobile": "?0",
          "sec-ch-ua-platform": '"Windows"',
          "sec-fetch-dest": "empty",
          "sec-fetch-mode": "cors",
          "sec-fetch-site": "same-origin",
          "x-b3-traceid": "e900951027b4cc32",
        },
        referrer: "https://ad.xiaohongshu.com/aurora/ad/manage/creativity",
        referrerPolicy: "strict-origin-when-cross-origin",
        body: `{\"startTime\":\"${
          new Date().toISOString().split("T")[0]
        }\",\"endTime\":\"${
          new Date().toISOString().split("T")[0]
        }\",\"pageNum\":1,\"pageSize\":100}`,
        method: "POST",
        mode: "cors",
        credentials: "include",
      }
    )
      .then((response) => response.json())
      .then(async (data) => {
        showToast(
          `获取数据:当前获取单元${data.data.list.length}条\n开始执行调价`,
          "info"
        );
        const result = [];
        for (let index = 0; index < data.data.list.length; index++) {
          const element = data.data.list[index];
          showToast(`当前执行单元${element.unitName},调整出价为${bid}`, "info");
          console.log(`当前执行单元${element.unitName},调整出价为${bid}`);

          await getData(element, bid, result);
          await sleep(1000);
        }
        alert(result.join("\n"));
      });
  }

  //调价函数----------------------

  // 创意开启关闭创意============================



  // 关闭计划
  async function closePlan(chunkedA,isColse) {

    const text = isColse = 1?"开启创意":"关闭创意";
    for (let i = 0; i < chunkedA.length; i++) {
      const ids = chunkedA[i];
      let retry = true;
      while (retry) {
        const r = await fetch(
          "https://ad.xiaohongshu.com/api/leona/rtb/creativity/batch/status",
          {
            headers: {
              accept: "application/json, text/plain, */*",
              "accept-language":
                "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
              "content-type": "application/json;charset=UTF-8",
              priority: "u=1, i",
              "sec-ch-ua":
                '"Not(A:Brand";v="99", "Microsoft Edge";v="133", "Chromium";v="133"',
              "sec-ch-ua-mobile": "?0",
              "sec-ch-ua-platform": '"macOS"',
              "sec-fetch-dest": "empty",
              "sec-fetch-mode": "cors",
              "sec-fetch-site": "same-origin",
              "x-b3-traceid": "c1adc74c127d40f2",
            },
            referrer: "https://ad.xiaohongshu.com/aurora/ad/manage/creativity",
            referrerPolicy: "strict-origin-when-cross-origin",
            // 2是关闭 1是开启
            body: JSON.stringify({
              ids: ids,
              actionType: parseInt(isColse),
            }),
            method: "PUT",
            mode: "cors",
            credentials: "include",
          }
        );
        const res = await r.json();
        console.log(res.msg);
        if (res.msg === "成功") {
          showToast(`${text},${res.msg}:${JSON.stringify(ids)}`, "success");
          retry = false;
        } else {
          retry = true;
        }
        await new Promise((resolve) => setTimeout(resolve, 500));
      }
    }
  }

  function split_array(array, number) {
    // 将数组a以number个为一组切割
    const chunkedA = array.reduce((acc, _, index) => {
      const chunkIndex = Math.floor(index / number);
      if (!acc[chunkIndex]) {
        acc[chunkIndex] = [];
      }
      acc[chunkIndex].push(_);
      return acc;
    }, []);
    return chunkedA;
  }

  // 创意开启关闭创意-----------------------------

  // 创建配置按钮
  const optionButton = document.createElement("button");
  addButtonAttributes(optionButton, "配置");

  // 开启关闭创意============================

  const openOrClose = document.createElement("button");
  addButtonAttributes(openOrClose, "关闭/开启创意");
  openOrClose.onclick = () => {
    const { overlay, card, closeButton } = create_car();
    // 创建第一个下拉列表
    const creativeIdSelect = document.createElement("select");
    creativeIdSelect.options.add(new Option("创意ID", "creativeId"));
    creativeIdSelect.options.add(new Option("文字匹配", "textMatch"));
    card.appendChild(creativeIdSelect);

    // 创建第二个下拉列表
    const toggleSelect = document.createElement("select");
    toggleSelect.options.add(new Option("关闭", "2"));
    toggleSelect.options.add(new Option("开启", "1"));

    card.appendChild(toggleSelect);

    // 创建多行文本输入框
    const textArea = document.createElement("textarea");
    card.appendChild(textArea);

    // 创建请求按钮
    const requestButton = document.createElement("button");
    requestButton.textContent = "请求";
    requestButton.onclick = async () => {
      const chunkedA = split_array(textArea.value.trim().split(/\n|,\n/g).map(e=>e.trim()), 50);
      // console.log();
      
      closePlan(chunkedA,toggleSelect.value);
    };
    card.appendChild(requestButton);
    // 将遮罩层和卡片添加到页面中
    document.body.appendChild(overlay);
    document.body.appendChild(card);

    
  };

  // 批量调价搜索词
  const modify_the_price = document.createElement("button");
  addButtonAttributes(modify_the_price, "批量调整出价");

  modify_the_price.onclick = () => {
    const bid = prompt("请输入出价");
    //判断bid是否是数值 并且就bid转换成小数
    if (isNaN(bid)) {
      showToast("请输入数字", "error");
      return;
    }

    if (bid) {
      var Newbid = parseFloat(bid);
      set_bid(Newbid);
    }
  };



  // const download_today = document.createElement("button");
  // addButtonAttributes(download_today, "下载今日创建");
  // download_today.onclick =  () => {


  //   fetch("https://ad.xiaohongshu.com/api/leona/rtb/creativity/list", {
  //     "headers": {
  //       "accept": "application/json, text/plain, */*",
  //       "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
  //       "content-type": "application/json",
  //       "priority": "u=1, i",
  //       "sec-ch-ua": "\"Chromium\";v=\"134\", \"Not:A-Brand\";v=\"24\", \"Microsoft Edge\";v=\"134\"",
  //       "sec-ch-ua-mobile": "?0",
  //       "sec-ch-ua-platform": "\"macOS\"",
  //       "sec-fetch-dest": "empty",
  //       "sec-fetch-mode": "cors",
  //       "sec-fetch-site": "same-origin",
  //       "x-b3-traceid": "268ef6d4ba91e008"
  //     },
  //     "referrer": "https://ad.xiaohongshu.com/aurora/ad/manage/creativity",
  //     "referrerPolicy": "strict-origin-when-cross-origin",
  //     "body": "{\"startTime\":\"2025-03-28\",\"endTime\":\"2025-03-28\",\"creativityCreateBeginTime\":\"2025-03-27\",\"creativityCreateEndTime\":\"2025-03-27\",\"pageNum\":1,\"pageSize\":20}",
  //     "method": "POST",
  //     "mode": "cors",
  //     "credentials": "include"
  //   });
  // };
  // 加载元素
  optionButton.onclick = option;
  buttonContainer.appendChild(optionButton);
  buttonContainer.appendChild(openButton);
  buttonContainer.appendChild(openOrClose);
  buttonContainer.appendChild(modify_the_price);
  // buttonContainer.appendChild(download_today);
})();