Greasy Fork

Greasy Fork is available in English.

抖店达人助手

抖店达人数据导出工具

当前为 2024-12-18 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         抖店达人助手
// @namespace    https://github.com/yourusername
// @version      2.1.0
// @author       your-name
// @description  抖店达人数据导出工具
// @match        https://buyin.jinritemai.com/dashboard/servicehall/business-homepage?sec_shop_id*
// @connect      shop_api.uinstall.eu.org
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @license MIT
// ==/UserScript==

(function(){"use strict";const N={templates:[],productSettings:{},productIds:[],contactInfo:{phone:"",wechat:""},activeTemplateId:""},D="INVITE_CARD_CONFIG";function b(){const e=GM_getValue(D,N);return{templates:e.templates||N.templates,productSettings:e.productSettings||{},productIds:e.productIds||[],contactInfo:{phone:e.contactInfo?.phone||"",wechat:e.contactInfo?.wechat||""},activeTemplateId:e.activeTemplateId||N.activeTemplateId}}function v(e){GM_setValue(D,e)}function q(e,t){let o;return(...n)=>{clearTimeout(o),o=window.setTimeout(()=>e(...n),t)}}function Z(){const e=document.createElement("div");e.className="shop-config-overlay",e.style.cssText="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:1000;display:none;";const t=document.createElement("div");t.className="shop-config-panel",t.style.cssText="position:fixed;top:0;right:0;width:960px;height:100vh;background:white;box-shadow:-2px 0 8px rgba(0,0,0,0.15);z-index:1001;display:flex;flex-direction:column;font-size:14px;";const o=document.createElement("style");o.textContent=`
        .shop-config-panel .header { padding:16px 24px; border-bottom:1px solid #f0f0f0; display:flex; justify-content:space-between; align-items:center; background:white; }
        .shop-config-panel .content { flex:1; overflow-y:auto; padding:16px; background-color:#fafbfc; display:flex; gap:16px; }
        .shop-config-panel .footer { padding:16px 24px; border-top:1px solid #f0f0f0; text-align:right; background:white; }
        .shop-config-panel h3 { margin:0; color:#000000d9; font-weight:500; font-size:16px; }
        .shop-config-panel .form-block { background:white; border-radius:2px; padding:16px; margin-bottom:16px; }
        .shop-config-panel .highlight-text { font-size:14px; font-weight:500; color:#000000d9; margin-bottom:16px; display:flex; align-items:center; }
        .shop-config-panel .form-row { display:flex; margin-bottom:16px; }
        .shop-config-panel .form-label { width:120px; text-align:right; padding-right:16px; color:#898b8f; line-height:32px; }
        .shop-config-panel .form-content { flex:1; }
        .shop-config-panel input[type="text"], .shop-config-panel textarea { width:288px; padding:4px 11px; border:1px solid #d9d9d9; border-radius:2px; font-size:14px; }
        .shop-config-panel textarea.large { width:100%; height:160px; resize:none; }
        .shop-config-panel .checkbox-group { display:flex; flex-wrap:wrap; gap:16px; }
        .shop-config-panel .checkbox-wrapper { display:inline-flex; align-items:center; cursor:pointer; user-select:none; }
        .shop-config-panel .checkbox-inner { position:relative; width:16px; height:16px; border:1px solid #d9d9d9; border-radius:2px; margin-right:8px; }
        .shop-config-panel .checkbox-wrapper.checked .checkbox-inner { background:#1966ff; border-color:#1966ff; }
        .shop-config-panel .checkbox-wrapper.checked .checkbox-inner:after { content:''; position:absolute; left:4px; top:1px; width:6px; height:9px; border:2px solid #fff; border-top:0; border-left:0; transform:rotate(45deg); }
        .shop-config-panel .table { width:100%; border-collapse:collapse; }
        .shop-config-panel .table th, .shop-config-panel .table td { padding:12px 16px; border-bottom:1px solid #f0f0f0; text-align:left; vertical-align:middle; }
        .shop-config-panel .table th { background:#fafafa; font-weight:500; color:#000000d9; }
        .shop-config-panel .product-card { display:flex; align-items:center; gap:12px; }
        .shop-config-panel .product-image { width:32px; height:32px; border-radius:2px; object-fit:cover; }
        .shop-config-panel .product-info { flex:1; min-width:0; }
        .shop-config-panel .product-title { font-size:13px; margin-bottom:4px; color:#252931; }
        .shop-config-panel .product-meta { color:#898b8f; font-size:12px; }
        .shop-config-panel .switch { position:relative; display:inline-block; width:28px; height:16px; background:#ccc; border-radius:100px; cursor:pointer; vertical-align:middle; }
        .shop-config-panel .switch.checked { background:#1966ff; }
        .shop-config-panel .switch-handle { position:absolute; top:2px; left:2px; width:12px; height:12px; background:white; border-radius:50%; transition:left 0.2s; }
        .shop-config-panel .switch.checked .switch-handle { left:14px; }
        .shop-config-panel .btn { padding:4px 15px; border-radius:2px; border:1px solid #d9d9d9; background:white; cursor:pointer; font-size:14px; }
        .shop-config-panel .btn-primary { background:#1966ff; border-color:#1966ff; color:white; }
        .shop-config-panel .btn-link { border:none; padding:0; color:#1966ff; }
        .shop-config-panel .set-end-time { min-width:80px; text-align:left; }
    `,document.head.appendChild(o);const n=document.createElement("div");n.className="header",n.innerHTML=`
        <h3>邀请配置</h3>
        <button style="font-size:20px;line-height:1;padding:0 8px;border:none;background:none;">×</button>
    `;const i=document.createElement("div");i.className="content";const c=document.createElement("div");c.style.flex="1";const r=document.createElement("div");r.className="form-block",r.innerHTML=`
        <div class="highlight-text">邀约信息</div>
        <div class="form-row">
            <div class="form-label">邀约内容</div>
            <div class="form-content">
                <textarea class="large" placeholder="请输入邀约内容"></textarea>
            </div>
        </div>
        <div class="form-row">
            <div class="form-label">专属权益</div>
            <div class="form-content">
                <div class="checkbox-group">
                    <label class="checkbox-wrapper checked">
                        <span class="checkbox-inner"></span>
                        <span>专属高佣</span>
                    </label>
                    <label class="checkbox-wrapper checked">
                        <span class="checkbox-inner"></span>
                        <span>免费申样</span>
                    </label>
                    <label class="checkbox-wrapper">
                        <span class="checkbox-inner"></span>
                        <span>视频素材支持</span>
                    </label>
                    <label class="checkbox-wrapper">
                        <span class="checkbox-inner"></span>
                        <span>优质视频投流</span>
                    </label>
                </div>
            </div>
        </div>
    `;const p=document.createElement("div");p.className="form-block",p.innerHTML=`
        <div class="highlight-text">联系方式</div>
        <div class="form-row">
            <div class="form-label">手机号</div>
            <div class="form-content">
                <input type="text" placeholder="请输入手机号" maxlength="11">
            </div>
        </div>
        <div class="form-row">
            <div class="form-label">微信号</div>
            <div class="form-content">
                <input type="text" placeholder="请输入微信号" maxlength="20">
            </div>
        </div>
    `;const a=document.createElement("div");a.className="form-block",a.innerHTML=`
        <div class="highlight-text">商品配置</div>
        <div style="margin-bottom:16px">
            <button type="button" class="btn btn-primary">添加商品</button>
        </div>
        <table class="table">
            <thead>
                <tr>
                    <th>商品信息</th>
                    <th style="width:120px">专属佣金</th>
                    <th style="width:100px">免审申样</th>
                    <th style="width:160px">策略结束时间</th>
                    <th style="width:80px">操作</th>
                </tr>
            </thead>
            <tbody></tbody>
        </table>
    `,c.appendChild(r),c.appendChild(p),c.appendChild(a),i.appendChild(c);const w=document.createElement("div");w.style.cssText="width:286px;flex-shrink:0;",w.innerHTML=`
        <div class="highlight-text" style="margin:4px 0 8px 4px">效果预览</div>
        <img width="286" src="https://p3-infra.elabpic.com/tos-cn-i-ax5x5hote5/3343d634a25844368fe5ec79df459dc0~tplv-ax5x5hote5-image.image">
    `,i.appendChild(w);const x=document.createElement("div");x.className="footer",x.innerHTML='<button type="button" class="btn">取消</button>';const d=document.createElement("button");d.textContent="预览配置",d.className="btn",d.style.marginRight="8px",d.onclick=()=>ee(),x.insertBefore(d,x.firstChild),t.appendChild(n),t.appendChild(i),t.appendChild(x),e.appendChild(t);const f=n.querySelector("button"),y=x.querySelector(".btn:last-child");[f,y].forEach(l=>{l.onclick=()=>{e.style.display="none",t.style.display="none"}}),e.onclick=l=>{l.target===e&&(e.style.display="none",t.style.display="none")};const m=b(),S=r.querySelector("textarea");S.value=m.templates[0]?.content||"",S.onchange=q(l=>{const s=b(),u=l.target.value,h="template_"+Date.now();s.templates.length===0?(s.templates.push({id:h,name:"邀约模板",content:u,rights:[{right:1},{right:2}]}),s.activeTemplateId=h):s.templates[0].content=u,v(s)},300),r.querySelectorAll(".checkbox-wrapper").forEach((l,s)=>{const u=m.templates[0]?.rights||[{right:1},{right:2}],h=[1,2,4,3][s];u.some(g=>g.right===h)&&l.classList.add("checked"),l.onclick=()=>{const g=b();l.classList.contains("checked")?(l.classList.remove("checked"),g.templates[0].rights=g.templates[0].rights.filter(k=>k.right!==h)):(l.classList.add("checked"),g.templates[0].rights.push({right:h})),v(g)}});const[X,K]=p.querySelectorAll("input");X.value=m.contactInfo.phone,K.value=m.contactInfo.wechat;function xe(l){return/^1[3-9]\d{9}$/.test(l)}function be(l){return/^[a-zA-Z0-9_-]{6,20}$/.test(l)}function ye(l){return/^\d{6,20}$/.test(l)}X.onchange=q(l=>{const s=l.target.value;if(!xe(s)){window.alert("请输入正确的手机号码");return}const u=b();u.contactInfo.phone=s,v(u)},300),K.onchange=q(l=>{const s=l.target.value;if(!be(s)){window.alert("请输入正确的微信号(6-20位字母、数字、下划线)");return}const u=b();u.contactInfo.wechat=s,v(u)},300);const Y=a.querySelector("tbody"),ve=a.querySelector(".btn-primary");ve.onclick=()=>{const l=prompt("请输入商品ID");if(!l)return;if(!ye(l)){window.alert("请输入正确的商品ID(6-20位数字)");return}const s=b();if(s.productIds.includes(l)){window.alert("该商品已添加");return}s.productIds.push(l),s.productSettings[l]={sampleStatus:1,cosRatio:40,timeRadio:"long",validTime:"3000-01-01 00:00:00"},v(s),E()};function E(){const l=b();Y.innerHTML=l.productIds.map(s=>{const u=l.productSettings[s],h=u?.validTime&&u.timeRadio==="end"?u.validTime.split(" ")[0]:"长期";return`
                <tr>
                    <td>
                        <div class="product-card">
                            <img class="product-image" src="https://placeholder.com/32x32" alt="">
                            <div class="product-info">
                                <div class="product-title">商品ID: ${s}</div>
                                <div class="product-meta">
                                    <span>佣金:${u?.cosRatio||0}%</span>
                                </div>
                            </div>
                        </div>
                    </td>
                    <td>
                        <button type="button" class="btn btn-link set-ratio" data-id="${s}">
                            ${u?.cosRatio?`${u.cosRatio}%`:"设置"}
                        </button>
                    </td>
                    <td>
                        <div class="switch ${u?.sampleStatus===3?"checked":""}" data-id="${s}">
                            <div class="switch-handle"></div>
                        </div>
                    </td>
                    <td>
                        <button type="button" class="btn btn-link set-end-time" data-id="${s}">
                            ${h}
                        </button>
                    </td>
                    <td>
                        <button type="button" class="btn btn-link delete-product" data-id="${s}">删除</button>
                    </td>
                </tr>
            `}).join(""),Y.querySelectorAll("[data-id]").forEach(s=>{const u=s.getAttribute("data-id");s.classList.contains("set-ratio")?s.onclick=()=>{const h=b(),g=h.productSettings[u]?.cosRatio||40,$=prompt("请输入专属佣金比例(%)",g.toString());if($!==null){const k=parseInt($);!isNaN(k)&&k>=0&&k<=100?(h.productSettings[u].cosRatio=k,v(h),E()):window.alert("请输入0-100之间的有效数字")}}:s.classList.contains("switch")?s.onclick=()=>{const h=b(),g=h.productSettings[u].sampleStatus;h.productSettings[u].sampleStatus=g===3?1:3,v(h),E()}:s.classList.contains("set-end-time")?s.onclick=()=>{const h=b(),g=h.productSettings[u];if(g.timeRadio==="long"){if(confirm("是否设置策略束时间?")){const k=new Date,we=new Date(k.getTime()+7*24*60*60*1e3),C=document.createElement("input");C.type="date",C.value=we.toISOString().split("T")[0],C.min=k.toISOString().split("T")[0],C.style.cssText=`
                                position: fixed;
                                top: 50%;
                                left: 50%;
                                transform: translate(-50%, -50%);
                                padding: 8px;
                                border: 1px solid #d9d9d9;
                                border-radius: 2px;
                                font-size: 14px;
                                z-index: 1003;
                            `,document.body.appendChild(C);const _=document.createElement("div");_.style.cssText=`
                                position: fixed;
                                top: 0;
                                left: 0;
                                right: 0;
                                bottom: 0;
                                background: rgba(0,0,0,0.5);
                                z-index: 1002;
                            `,document.body.appendChild(_),_.onclick=()=>{document.body.removeChild(C),document.body.removeChild(_)},C.onchange=ke=>{const Ce=ke.target.value;g.timeRadio="end",g.validTime=`${Ce} 23:59:59`,v(h),E(),document.body.removeChild(C),document.body.removeChild(_)},setTimeout(()=>{C.focus()},100)}}else confirm("是否改为长期?")&&(g.timeRadio="long",g.validTime="3000-01-01 00:00:00",v(h),E())}:s.classList.contains("delete-product")&&(s.onclick=()=>{if(confirm("确定删除该商品吗?")){const h=b();h.productIds=h.productIds.filter(g=>g!==u),delete h.productSettings[u],v(h),E()}})})}return E(),e}function Q(){const e=document.querySelector(".shop-config-overlay");if(e)e.style.display="block",e.querySelector(".shop-config-panel").style.display="flex";else{const t=Z();document.body.appendChild(t),t.style.display="block",t.querySelector(".shop-config-panel").style.display="flex"}}function ee(){const e=I("preview_account_id"),t=JSON.stringify(e,null,2),o=document.createElement("div");o.style.cssText="position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:white;padding:24px;border-radius:2px;box-shadow:0 3px 6px -4px rgba(0,0,0,.12),0 6px 16px 0 rgba(0,0,0,.08);z-index:1002;width:800px;max-height:90vh;display:flex;flex-direction:column;",o.innerHTML=`
        <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;">
            <h3 style="margin:0">配置预览</h3>
            <button style="font-size:20px;line-height:1;padding:0 8px;border:none;background:none;cursor:pointer;">×</button>
        </div>
        <pre style="flex:1;overflow:auto;background:#f5f5f5;padding:16px;border-radius:2px;margin:0;font-family:monospace;font-size:12px;">${t}</pre>
    `,o.querySelector("button").onclick=()=>document.body.removeChild(o),document.body.appendChild(o)}const A={},O={},T={name:"",avatar:"",shopId:""};function I(e){const t=b(),o=t.templates.find(n=>n.id===t.activeTemplateId);if(!o)throw new Error("Template not found");return{account_id:e,account_type:1,invite_card:{content:o.content,rights:o.rights,product_ids:t.productIds,product_setting:t.productIds.filter(n=>t.productSettings[n]).map(n=>{const i=t.productSettings[n];return{product_id:n,author_sample_status:i.sampleStatus,orient_cos_ratio_detail:{orient_kol_cos_ratio:i.cosRatio,time_radio:i.timeRadio,valid_time:i.validTime||"3000-01-01 00:00:00",suggest_orient_kol_cos_ratio:53,...i.cosRatio?{}:{cos_ratio_range:{low:0,high:80}}}}})},contact_info:t.contactInfo}}function te(){window.addEventListener("load",function(){const e=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(t,o,n,i,c){return typeof o=="string"&&(o.includes("/square_pc_api/shop/shopProfileAuthorList")?this.addEventListener("load",function(){try{const r=JSON.parse(this.response),p=this.responseURL;A[p]=r,r.data?.author_list?.forEach(a=>{a.avatar&&(O[a.avatar]=p)}),console.log("已缓存达人列表数据,当前缓存数量:",Object.keys(A).length)}catch(r){console.error("解析达人列表响应失败:",r)}}):o.includes("/square_pc_api/shop/shopProfile")&&this.addEventListener("load",function(){try{const r=JSON.parse(this.response);if(r.code===0&&r.data?.basic_info){const{basic_info:p}=r.data;T.name=p.name||"",T.avatar=p.avatar||"",T.shopId=p.shop_id?.toString()||"",console.log("已缓存店铺信息:",T)}}catch(r){console.error("解析店铺信息响应失败:",r)}})),e.apply(this,[t,o,n??!0,i,c])}})}function oe(e){const t=O[e];if(!t)return null;const o=A[t];return o?.data?.author_list?o.data.author_list.find(n=>n.avatar===e):null}function ne(){return{...T}}function H(e){const t=oe(e);return t||(console.log("未找到店铺资料:",e),null)}function ie(e){console.log("开始批量获取店铺资料, 总数:",e.length);const t=e.map(o=>H(o)).filter(o=>o!==null);return console.log("成功获取店铺资料数量:",t.length),t}function F(e){const o=e.querySelector(".card-info__avatar img")?.getAttribute("src")||null;return o||(console.log("未找到头像URL"),null)}function U(e){const t=F(e);return t?H(t):null}function re(e){const t=e.map(F).filter(o=>o!==null);return ie(t)}async function j(e){return new Promise((t,o)=>{GM_xmlhttpRequest({method:"POST",url:"https://shop_api.uinstall.eu.org:888/shop/api/v1/douyin/contact",headers:{"Content-Type":"application/json","User-Agent":window.navigator.userAgent,Cookie:document.cookie},data:JSON.stringify(e),onload:function(n){try{const i=JSON.parse(n.responseText);n.status===200&&i.code===200?t(i):(console.error("联系方式查询失败:",i),o(new Error(i.message||"请求失败")))}catch(i){console.error("解析响应失败:",i),o(i)}},onerror:function(n){console.error("请求发送失败:",n),o(new Error("网络请求失败"))}})})}async function P(e){return new Promise((t,o)=>{GM_xmlhttpRequest({method:"POST",url:"https://buyin.jinritemai.com/connection/pc/im/invite/card/send",headers:{"Content-Type":"application/json","User-Agent":window.navigator.userAgent,Cookie:document.cookie},data:JSON.stringify(e),onload:function(n){try{const i=JSON.parse(n.responseText);i.code===0?t(i):(console.error("发送邀约失败:",i),o(new Error(i.msg||"请求失败")))}catch(i){console.error("解析响应失败:",i),o(i)}},onerror:function(n){console.error("请求发送失败:",n),o(new Error("网络请求失败"))}})})}function R(e){try{return new Date(e).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})}catch{return e}}function ce(){const e=document.createElement("div");e.className="shop-log-panel",e.style.cssText=`
        position: fixed;
        bottom: 20px;
        left: 20px;
        width: 400px;
        max-height: 500px;
        background: white;
        padding: 15px;
        border-radius: 8px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.15);
        z-index: 1000;
        display: flex;
        flex-direction: column;
        gap: 10px;
        overflow-y: auto;
    `;const t=document.createElement("div");t.style.cssText=`
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 5px;
        margin: -15px -15px 5px -15px;
        background: #f5f5f5;
        border-radius: 8px 8px 0 0;
        border-bottom: 1px solid #eee;
    `;const o=document.createElement("div");o.textContent="操作日志",o.style.cssText=`
        font-weight: bold;
        padding-left: 10px;
    `;const n=document.createElement("button");n.innerHTML="−",n.style.cssText=`
        background: none;
        border: none;
        font-size: 16px;
        cursor: pointer;
        padding: 0 10px;
        color: #666;
        width: 24px;
        height: 24px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 4px;
        &:hover {
            background: #f0f0f0;
        }
    `;let i=!1;const c=document.createElement("div");c.className="log-content",n.addEventListener("click",()=>{i=!i,i?(c.style.display="none",n.innerHTML="+",e.style.maxHeight="auto",e.style.height="auto"):(c.style.display="block",n.innerHTML="−",e.style.maxHeight="500px")}),t.appendChild(o),t.appendChild(n),c.style.cssText=`
        font-size: 12px;
        line-height: 1.5;
        color: #666;
    `;const r=document.createElement("style");return r.textContent=`
        .log-entry {
            margin-bottom: 1px;
            padding: 2px 8px;
            border-radius: 2px;
            background: #f9f9f9;
            display: flex;
            align-items: center;
            gap: 4px;
            font-size: 12px;
            line-height: 1.3;
        }
        .log-entry.success {
            border-left: 2px solid #52c41a;
            color: #333;
        }
        .log-entry.error {
            border-left: 2px solid #ff4d4f;
            color: #333;
        }
        .log-entry.info {
            border-left: 2px solid #1890ff;
            color: #333;
        }
        .log-entry .timestamp {
            color: #999;
            font-size: 11px;
            flex-shrink: 0;
            min-width: 50px;
        }
        .log-entry .message {
            flex: 1;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            color: #333;
            padding-right: 8px;
        }
        .log-entry .details {
            color: #999;
            font-size: 11px;
            flex-shrink: 0;
            margin-left: auto;
            max-width: 200px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
        .log-entry:hover {
            background: #f0f0f0;
        }
        .log-entry:hover .message,
        .log-entry:hover .details {
            white-space: normal;
            overflow: visible;
        }
        .log-content {
            max-height: 400px;
            overflow-y: auto;
            padding-right: 4px;
            display: flex;
            flex-direction: column-reverse;
        }
        .log-content::-webkit-scrollbar {
            width: 4px;
            height: 4px;
        }
        .log-content::-webkit-scrollbar-thumb {
            background: #ccc;
            border-radius: 2px;
        }
        .log-content::-webkit-scrollbar-track {
            background: #f1f1f1;
            border-radius: 2px;
        }
    `,document.head.appendChild(r),e.appendChild(t),e.appendChild(c),e}function M(e,t){const o=document.querySelector(".log-content");if(o){const n=document.createElement("div");n.className=`log-entry ${t.type}`;const i=document.createElement("span");i.className="timestamp",i.textContent=new Date().toLocaleTimeString("zh-CN",{hour12:!1});const c=document.createElement("span");if(c.className="message",c.textContent=e,t.details){const r=document.createElement("span");r.className="details";const p=[];t.details.source==="db"&&t.details.savedAt&&p.push(`DB:${R(t.details.savedAt)}`),t.details.source==="api"&&t.details.remaining!==void 0&&p.push(`API:${t.details.remaining}`),t.details.errorMessage&&p.push(t.details.errorMessage),r.textContent=p.join(" | "),n.appendChild(r)}n.appendChild(i),n.appendChild(c),o.insertBefore(n,o.firstChild)}}function se(){const e=document.querySelector(".log-content");e&&(e.innerHTML="")}function L(e){M(e,{type:"info"})}function J(e,t){M(e,{type:"success",details:t})}function z(e,t){M(e,{type:"error",details:t})}function B(e){return e>=1e8?(e/1e8).toFixed(0)+"E":e>=1e4?(e/1e4).toFixed(0)+"W":e.toString()}function ae(e){if(e==null)return"";const t=Math.floor(e/100)*100;return t>=1e4?(t/1e4).toFixed(1)+"W":t>=1e3?(t/1e3).toFixed(1)+"K":t.toString()}function le(e){const t=e.sale?.low,o=e.sale?.high;return t==null||o==null?"":t===0&&o===0?"0":t===o?B(t):`${B(t)}-${B(o)}`}const V=[{key:"name",title:"达人名称"},{key:"level",title:"等级"},{key:"fans_num",title:"粉丝数",format:ae},{key:"sale_range",title:"店铺推广销售额",getValue:e=>e,format:le},{key:"live_num",title:"关联直播场次"},{key:"video_num",title:"关联短视频数"},{key:"promotion_num",title:"推广商品数"},{key:"wechat_id",title:"Wechat"}];async function de(){const e=Array.from(document.querySelectorAll('.shop-card-checkbox input[type="checkbox"]:checked')).map(a=>a.closest(".shop-card")).filter(a=>a!==null);if(e.length===0){alert("请先选择要导出的达人");return}const t=confirm(`已选中 ${e.length} 个达人,是否要发送邀约?`);if(t){const a=b();if(!a.templates.length||!a.activeTemplateId){alert("请先配置邀约模板");return}if(!a.productIds.length){alert("请先配置商品");return}if(!a.contactInfo.phone||!a.contactInfo.wechat){alert("请先配置联系方式");return}}se(),L(`开始处理 | 已选中 ${e.length} 个达人`);const o=re(e);if(o.length===0){z("未找到达人数据");return}let n=0,i=0,c=0,r=0;const p=[];for(const a of o)try{const w=a.name||a.nickname||"未知达人";let x="";const d=await j(a);let f=w,y=[];if((d.code===200||d.code===0)&&d.data?.wechat_id)n++,x=d.data.wechat_id,f+=` | 查询成功: ${x}`,d.source==="db"&&d.saved_at&&y.push(`DB:${R(d.saved_at)}`),d.source==="api"&&d.remaining!==void 0&&y.push(`API:${d.remaining}`);else{i++;const m=d.message||"未找到联系方式";f+=` | 查询失败: ${m}`,d.source==="api"&&d.remaining!==void 0&&y.push(`API:${d.remaining}`)}if(t)try{const m=I(a.sec_author_id),S=await P(m);S.code===0?(c++,f+=" | 邀约成功"):(r++,f+=` | 邀约失败: ${S.msg}`)}catch(m){r++;const S=m.message;f+=` | 邀约失败: ${S}`}y.length>0&&(f+=` | ${y.join(" | ")}`),f.includes("失败")?z(f):J(f),p.push({...a,wechat_id:x})}catch(w){i++;const x=w.message;let f=`${a.name||a.nickname||"未知达人"} | 查询失败: ${x}`;if(t)try{const y=I(a.sec_author_id),m=await P(y);m.code===0?(c++,f+=" | 邀约成功"):(r++,f+=` | 邀约失败: ${m.msg}`)}catch(y){r++;const m=y.message;f+=` | 邀约失败: ${m}`}z(f),p.push({...a,wechat_id:""})}if(L("------------------------"),L(t?`处理完成 | 查询成功率: ${n}/${o.length} | 邀约成功率: ${c}/${o.length}`:`处理完成 | 查询成功率: ${n}/${o.length}`),n>0){const a=pe(p),w=new Blob(["\uFEFF"+a],{type:"text/csv;charset=utf-8;"}),x=URL.createObjectURL(w),d=document.createElement("a");d.href=x;const{name:f}=ne(),y=new Date().toISOString().split("T")[0],m=f?`${f}_达人数据_${y}.csv`:`达人数据_${y}.csv`;d.download=m,document.body.appendChild(d),d.click(),document.body.removeChild(d),URL.revokeObjectURL(x),J("文件导出完成")}}function pe(e){const t=V.map(n=>n.title).join(","),o=e.map(n=>V.map(i=>{let c;if(i.getValue)c=i.getValue(n);else if(i.key.startsWith("sale_")){const r=i.key.replace("sale_","");c=n.sale?.[r]}else c=n[i.key];return i.format?G(i.format(c)):G(c)}).join(","));return[t,...o].join(`
`)}function G(e){return e==null?"":typeof e=="boolean"?e?"是":"否":typeof e=="number"?e.toString():(typeof e=="object"&&!Array.isArray(e)&&(e=JSON.stringify(e)),typeof e=="string"&&(e.includes(",")||e.includes(`
`)||e.includes('"'))?`"${e.replace(/"/g,'""')}"`:String(e))}function W(e){const t=document.querySelectorAll('.shop-card-checkbox input[type="checkbox"]:checked').length;e.textContent=`导出选中(${t})`}function ue(){const e=document.createElement("div");e.className="shop-control-panel",e.style.cssText=`
        position: fixed;
        bottom: 20px;
        right: 20px;
        background: white;
        padding: 15px;
        border-radius: 8px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.15);
        z-index: 1000;
        display: flex;
        flex-direction: column;
        gap: 10px;
    `;const t=document.createElement("div");t.style.cssText=`
        padding: 5px;
        margin: -15px -15px 5px -15px;
        background: #f5f5f5;
        border-radius: 8px 8px 0 0;
        border-bottom: 1px solid #eee;
        text-align: center;
        font-weight: bold;
    `,t.textContent="批量操作";const o=document.createElement("button");o.textContent="全选",o.style.cssText=`
        padding: 8px 16px;
        background-color: #1890ff;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        margin-bottom: 8px;
    `;const n=document.createElement("button");n.textContent="导出选中(0)",n.style.cssText=`
        padding: 8px 16px;
        background-color: #52c41a;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        margin-bottom: 8px;
    `;const i=document.createElement("button");i.textContent="邀请配置",i.style.cssText=`
        padding: 8px 16px;
        background-color: #722ed1;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
    `;let c=!1;return o.addEventListener("click",()=>{c=!c,o.textContent=c?"取消全选":"全选",document.querySelectorAll('.shop-card-checkbox input[type="checkbox"]').forEach(p=>{p.checked=c}),W(n)}),n.addEventListener("click",de),i.addEventListener("click",Q),document.addEventListener("checkbox-change",()=>{W(n)}),e.appendChild(t),e.appendChild(o),e.appendChild(n),e.appendChild(i),e}function he(){const e=document.createElement("div");e.className="shop-card-checkbox",e.style.cssText=`
        display: flex;
        align-items: center;
        padding: 0 10px;
        margin-right: 10px;
    `;const t=document.createElement("input");return t.type="checkbox",t.style.cssText=`
        width: 16px;
        height: 16px;
        cursor: pointer;
    `,t.addEventListener("change",o=>{o.stopPropagation();const n=o.target.checked;console.log("选中状态:",n),document.dispatchEvent(new CustomEvent("checkbox-change"))}),t.addEventListener("click",o=>{o.stopPropagation()}),e.appendChild(t),e}function fe(e){const t=document.createElement("div");t.style.cssText=`
        display: flex;
        gap: 8px;
    `;const o=document.createElement("button");o.textContent="查询",o.style.cssText=`
        padding: 5px 15px;
        background-color: #1890ff;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
    `;const n=document.createElement("button");return n.textContent="发送邀约",n.style.cssText=`
        padding: 5px 15px;
        background-color: #52c41a;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
    `,o.addEventListener("click",async i=>{i.stopPropagation(),i.preventDefault();try{const c=U(e);if(!c){alert("未找到达人资料");return}const r=await j(c);if((r.code===200||r.code===0)&&r.data?.wechat_id){const p=[`达人名称: ${c.name||c.nickname||"未知"}`,`联系方式: ${r.data.wechat_id}`,`数据来源: ${r.source==="db"?"数据库":"API查询"}`,r.remaining?`API剩余次数: ${r.remaining}`:"",r.source==="db"&&r.saved_at?`数据库更新时间: ${R(r.saved_at)}`:""].filter(Boolean).join(`
`);alert(p)}else alert(`查询失败: ${r.message||"未找到联系方式"}`)}catch(c){console.error("查询联系方式失败:",c),alert("查询联系方式失败: "+c.message)}}),n.addEventListener("click",async i=>{i.stopPropagation(),i.preventDefault();try{const c=U(e);if(!c){alert("未找到达人资料");return}const r=b();if(!r.templates.length||!r.activeTemplateId){alert("请先配置邀约模板");return}if(!r.productIds.length){alert("请先配置商品");return}if(!r.contactInfo.phone||!r.contactInfo.wechat){alert("请先配置联系方式");return}const p=I(c.sec_author_id),a=await P(p);a.code===0?alert("邀约发送成功!"):alert(`邀约发送失败: ${a.msg}`)}catch(c){console.error("发送邀约失败:",c),alert("发送邀约失败: "+c.message)}}),t.appendChild(o),t.appendChild(n),t}function ge(e,t){document.querySelector(".shop-control-panel")||document.body.appendChild(ue()),document.querySelector(".shop-log-panel")||document.body.appendChild(ce());const o=document.body;new MutationObserver(()=>{document.querySelectorAll(e).forEach(r=>{r.querySelector(".shop-card-checkbox")||t(r)})}).observe(o,{childList:!0,subtree:!0}),document.querySelectorAll(e).forEach(c=>{c.querySelector(".shop-card-checkbox")||t(c)})}function me(e){const t=he(),o=fe(e);e.insertBefore(t,e.firstChild),e.appendChild(o)}(function(){ge(".shop-card",me),te()})()})();