(function(d){typeof define=="function"&&define.amd?define(d):d()})(function(){"use strict";const d="https://api.255705.com",g="1.0.0";class u extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this.appKey="",this.captchaType="one_click",this.apiBase=d,this.theme="light",this.lang="zh-CN",this.visible=!1,this.captchaData=null,this.sessionToken="",this.loading=!1,this._startTime=0,this._dragState=null,this._clickPoints=[],this._rotateAngle=0}static get observedAttributes(){return["app-key","captcha-type","api-base","theme","lang","visible"]}connectedCallback(){if(this.appKey=this.getAttribute("app-key")||"",this.captchaType=this.getAttribute("captcha-type")||"one_click",this.apiBase=this.getAttribute("api-base")||d,this.theme=this.getAttribute("theme")||"light",this.lang=this.getAttribute("lang")||"zh-CN",this.visible=this.getAttribute("visible")!=="false",!this.appKey){console.error("captcha-widget: app-key is required");return}this._render(),this._loadCaptcha()}attributeChangedCallback(t,e,a){if(e!==a){switch(t){case"app-key":this.appKey=a;break;case"captcha-type":this.captchaType=a;break;case"api-base":this.apiBase=a;break;case"theme":this.theme=a;break;case"visible":this.visible=a!=="false";break}this.shadowRoot&&t!=="visible"&&this._loadCaptcha()}}show(){this.visible=!0,this.setAttribute("visible","true");const t=this.shadowRoot.querySelector(".captcha-container");t&&(t.style.display="block"),this._loadCaptcha()}hide(){this.visible=!1,this.setAttribute("visible","false");const t=this.shadowRoot.querySelector(".captcha-container");t&&(t.style.display="none")}async _loadCaptcha(){if(!this.loading){this.loading=!0,this._showLoading();try{const e=await(await fetch(`${this.apiBase}/api/v1/captcha/get`,{method:"POST",headers:{"Content-Type":"application/json","X-Captcha-Key":this.appKey},body:JSON.stringify({app_key:this.appKey,captcha_type:this.captchaType,timestamp:Date.now(),client_type:"web"})})).json();if(e.code!==0&&e.code!==200){this._showError(e.message||"加载验证码失败");return}this.captchaData=e.data||e,this.sessionToken=this.captchaData.session_token||"",this._startTime=Date.now(),this.captchaData.need_secondary_verify?(this.captchaType=this.captchaData.secondary_type,this._renderSecondary()):this.captchaType==="one_click"?this._renderOneClick():this._renderCaptcha()}catch{this._showError("网络错误,请重试")}finally{this.loading=!1}}}async _verify(t){try{const e={app_key:this.appKey,lot_number:this.captchaData.lot_number,pass_token:this.captchaData.pass_token,captcha_type:this.captchaData.captcha_type||this.captchaType,answer:t,timestamp:Date.now(),client_type:"web"};this.sessionToken&&(e.session_token=this.sessionToken);const s=await(await fetch(`${this.apiBase}/api/v1/captcha/verify`,{method:"POST",headers:{"Content-Type":"application/json","X-Captcha-Key":this.appKey},body:JSON.stringify(e)})).json(),i=s.data||s;i.success||s.code===0||s.code===200?(this._renderSuccess(),this._emit("success",{lot_number:this.captchaData.lot_number,pass_token:this.captchaData.pass_token,session_token:this.sessionToken,sign_token:i.sign_token||"",session_verified:i.session_verified||!1,verify_time:Date.now()-this._startTime})):(this._renderFail(i.message||"验证失败"),this._emit("fail",{message:i.message}))}catch{this._showError("验证请求失败")}}_emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}_render(){this.shadowRoot.innerHTML=`
加载中...
`}_renderOneClick(){const t=this.shadowRoot.querySelector(".captcha-panel");if(!t)return;t.innerHTML=`
${this.captchaData.instruction||"点击按钮完成验证"}
`;const e=this.shadowRoot.getElementById("oneClickBtn");e.addEventListener("click",()=>{e.classList.add("loading"),this._verify({})}),this._bindRefresh()}_renderSecondary(){this._renderCaptcha()}_renderCaptcha(){const t=this.shadowRoot.querySelector(".captcha-panel");if(!t)return;const e=this.captchaData.captcha_type||this.captchaType;let a="";switch(e){case"slide":case"slide_region":a=this._renderSlideHTML();break;case"click":a=this._renderClickHTML();break;case"rotate":a=this._renderRotateHTML();break;case"click_icon":a=this._renderClickIconHTML();break;default:this._renderOneClick();return}const s=this.captchaData.need_secondary_verify;t.innerHTML=`
${s?'
安全验证
':""}
${this._getTypeName(e)}
${a}
`,this._bindCaptchaEvents(e),this._bindRefresh()}_renderSlideHTML(){const t=this.captchaData.background||this.captchaData.image||"",e=this.captchaData.puzzle||this.captchaData.thumb||"",a=this.captchaData.width||300,s=this.captchaData.height||220,i=this.captchaData.thumbX||0,c=this.captchaData.thumbY||0,o=this.captchaData.thumbWidth||60,r=this.captchaData.thumbHeight||60;return`
向右拖动滑块完成验证
`}_renderClickHTML(){const t=this.captchaData.background||this.captchaData.image||"",e=this.captchaData.width||300,a=this.captchaData.height||220,s=this.captchaData.instruction||"请依次点击:",i=this.captchaData.points||[];let c="";return Array.isArray(i)&&(c=i.map(o=>o.text||o.label||"").filter(Boolean).join(" ")),`
${s} ${c}
请在图片上依次点击文字
`}_renderClickIconHTML(){const t=this.captchaData.background||"",e=this.captchaData.width||300,a=this.captchaData.height||220,s=this.captchaData.instruction||"请依次点击指定的图标",i=this.captchaData.thumb||"";let c="";return i&&(c=``),`
${s}
${c}
请在图片上依次点击对应图标
`}_renderRotateHTML(){const t=this.captchaData.background||this.captchaData.image||"",e=this.captchaData.thumb||"",a=this.captchaData.thumbSize||100;return`
拖动滑块旋转图片至正确角度
`}_renderSuccess(){const t=this.shadowRoot.querySelector(".captcha-panel");t&&(t.innerHTML=`
验证成功
`,setTimeout(()=>this.hide(),1500))}_renderFail(t){const e=this.shadowRoot.querySelector(".captcha-panel");if(!e)return;e.innerHTML=`
${t||"验证失败"}
`;const a=this.shadowRoot.getElementById("retryBtn");a&&a.addEventListener("click",()=>this._loadCaptcha())}_showLoading(){const t=this.shadowRoot.querySelector(".captcha-panel");t&&(t.innerHTML=`
加载中...
`)}_showError(t){const e=this.shadowRoot.querySelector(".captcha-panel");if(!e)return;e.innerHTML=`
${t}
`;const a=this.shadowRoot.getElementById("retryBtn");a&&a.addEventListener("click",()=>this._loadCaptcha())}_bindRefresh(){const t=this.shadowRoot.getElementById("refreshBtn");t&&t.addEventListener("click",()=>this._loadCaptcha())}_bindCaptchaEvents(t){switch(t){case"slide":case"slide_region":this._bindSlideEvents();break;case"click":this._bindClickEvents();break;case"click_icon":this._bindClickIconEvents();break;case"rotate":this._bindRotateEvents();break}}_bindSlideEvents(){const t=this.shadowRoot.getElementById("slideThumb"),e=this.shadowRoot.getElementById("slideProgress");if(!t)return;const s=t.parentElement.offsetWidth-t.offsetWidth;this._dragState={startX:0,currentX:0,min:0,max:s};const i=r=>{r.preventDefault();let h=(r.touches?r.touches[0].clientX:r.clientX)-this._dragState.startX;h=Math.max(this._dragState.min,Math.min(this._dragState.max,h)),this._dragState.currentX=h,t.style.transform=`translateX(${h}px)`,e&&(e.style.width=`${h}px`);const p=this.shadowRoot.querySelector(".captcha-slider-piece");if(p){const l=this.captchaData.width||300,b=h/s;p.style.left=`${b*l}px`}},c=()=>{document.removeEventListener("mousemove",i),document.removeEventListener("mouseup",c),document.removeEventListener("touchmove",i),document.removeEventListener("touchend",c);const r=this.captchaData.width||300,n=this._dragState.currentX/s,h=Math.round(n*r);(this.captchaData.captcha_type||this.captchaType)==="slide_region"?this._verify({x:h,y:this.captchaData.thumbY||0}):this._verify({x:h})},o=r=>{const n=r.touches?r.touches[0].clientX:r.clientX;this._dragState.startX=n-this._dragState.currentX,document.addEventListener("mousemove",i),document.addEventListener("mouseup",c),document.addEventListener("touchmove",i,{passive:!1}),document.addEventListener("touchend",c)};t.addEventListener("mousedown",o),t.addEventListener("touchstart",o,{passive:!1})}_bindClickEvents(){const t=this.shadowRoot.getElementById("clickArea");if(!t)return;this._clickPoints=[];const a=(this.captchaData.points||[]).length||3;t.querySelectorAll(".captcha-click-marker").forEach(i=>i.remove()),t.addEventListener("click",i=>{const c=t.getBoundingClientRect(),o=Math.round(i.clientX-c.left),r=Math.round(i.clientY-c.top);this._clickPoints.push({x:o,y:r});const n=document.createElement("div");n.className="captcha-click-marker",n.style.left=`${o-12}px`,n.style.top=`${r-12}px`,n.textContent=this._clickPoints.length,t.appendChild(n),this._clickPoints.length>=a&&this._verify({points:this._clickPoints})})}_bindClickIconEvents(){const t=this.shadowRoot.getElementById("clickArea");if(!t)return;this._clickPoints=[];const a=(this.captchaData.icons||[]).length||3;t.querySelectorAll(".captcha-click-marker").forEach(i=>i.remove()),t.addEventListener("click",i=>{const c=t.getBoundingClientRect(),o=Math.round(i.clientX-c.left),r=Math.round(i.clientY-c.top);this._clickPoints.push({x:o,y:r});const n=document.createElement("div");n.className="captcha-click-marker",n.style.left=`${o-12}px`,n.style.top=`${r-12}px`,n.textContent=this._clickPoints.length,t.appendChild(n),this._clickPoints.length>=a&&this._verify({points:this._clickPoints})})}_bindRotateEvents(){const t=this.shadowRoot.getElementById("slideThumb"),e=this.shadowRoot.getElementById("slideProgress"),a=this.shadowRoot.getElementById("rotateThumb");if(!t||!a)return;const i=t.parentElement.offsetWidth-t.offsetWidth;this._dragState={startX:0,currentX:0,min:0,max:i},this._rotateAngle=0;const c=n=>{n.preventDefault();let p=(n.touches?n.touches[0].clientX:n.clientX)-this._dragState.startX;p=Math.max(this._dragState.min,Math.min(this._dragState.max,p)),this._dragState.currentX=p,t.style.transform=`translateX(${p}px)`,e&&(e.style.width=`${p}px`);const l=p/i;this._rotateAngle=Math.round(l*360),a.style.transform=`rotate(${this._rotateAngle}deg)`},o=()=>{document.removeEventListener("mousemove",c),document.removeEventListener("mouseup",o),document.removeEventListener("touchmove",c),document.removeEventListener("touchend",o),this._verify({angle:this._rotateAngle})},r=n=>{const h=n.touches?n.touches[0].clientX:n.clientX;this._dragState.startX=h-this._dragState.currentX,document.addEventListener("mousemove",c),document.addEventListener("mouseup",o),document.addEventListener("touchmove",c,{passive:!1}),document.addEventListener("touchend",o)};t.addEventListener("mousedown",r),t.addEventListener("touchstart",r,{passive:!1})}_getTypeName(t){return{slide:"滑块验证",slide_region:"区域滑块验证",click:"文字点选验证",rotate:"旋转验证",click_icon:"图标点选验证",one_click:"一键验证"}[t]||"安全验证"}_getStyles(){const t=this.theme==="dark",e=t?"#1a1a1a":"#ffffff",a=t?"#e0e0e0":"#333333",s=t?"#333333":"#e0e0e0",i=t?"#2a2a2a":"#f0f0f0",c="#1890ff",o="#1890ff";return` :host { display: inline-block; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; } * { box-sizing: border-box; margin: 0; padding: 0; } .captcha-container { display: block; user-select: none; -webkit-user-select: none; } .captcha-panel { background: ${e}; border-radius: 12px; box-shadow: 0 6px 30px rgba(0,0,0,0.12); padding: 16px; min-width: 300px; max-width: 340px; color: ${a}; position: relative; } .captcha-loading { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px; gap: 12px; color: #999; } .captcha-spinner { width: 32px; height: 32px; border: 3px solid ${s}; border-top-color: ${c}; border-radius: 50%; animation: captcha-spin 0.8s linear infinite; } @keyframes captcha-spin { to { transform: rotate(360deg); } } .captcha-main { display: flex; flex-direction: column; gap: 10px; } .captcha-header { display: flex; align-items: center; justify-content: space-between; } .captcha-title { font-size: 14px; font-weight: 600; } .captcha-secondary-badge { position: absolute; top: 0; left: 0; background: #ff4d4f; color: #fff; font-size: 11px; padding: 2px 8px; border-radius: 12px 0 8px 0; } .captcha-refresh-btn { background: none; border: none; cursor: pointer; color: #999; padding: 4px; border-radius: 4px; display: flex; align-items: center; transition: color 0.2s; } .captcha-refresh-btn:hover { color: ${c}; } .captcha-one-click { display: flex; flex-direction: column; gap: 12px; } .captcha-one-click-btn { display: flex; align-items: center; justify-content: center; gap: 8px; background: ${o}; color: #ffffff; border: none; border-radius: 8px; padding: 14px 24px; font-size: 15px; font-weight: 500; cursor: pointer; transition: all 0.3s; position: relative; overflow: hidden; } .captcha-one-click-btn:hover { opacity: 0.9; transform: translateY(-1px); } .captcha-one-click-btn.loading { pointer-events: none; opacity: 0.7; } .captcha-slide-wrap { position: relative; border-radius: 8px; overflow: hidden; border: 1px solid ${s}; } .captcha-bg-img { display: block; } .captcha-slider-piece { position: absolute; pointer-events: none; } .captcha-slide-track { position: relative; height: 40px; background: ${i}; border-radius: 20px; margin-top: 8px; overflow: hidden; border: 1px solid ${s}; } .captcha-slide-track-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #999; font-size: 13px; pointer-events: none; white-space: nowrap; } .captcha-slide-progress { position: absolute; top: 0; left: 0; height: 100%; background: rgba(24,144,255,0.15); width: 0; transition: none; } .captcha-slide-thumb { position: absolute; top: 2px; left: 2px; width: 36px; height: 36px; background: ${o}; color: #fff; border-radius: 50%; cursor: grab; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 6px rgba(24,144,255,0.3); transition: box-shadow 0.2s; z-index: 2; } .captcha-slide-thumb:active { cursor: grabbing; box-shadow: 0 4px 12px rgba(24,144,255,0.5); } .captcha-click-wrap { display: flex; flex-direction: column; gap: 8px; } .captcha-instruction { font-size: 14px; font-weight: 500; color: ${a}; padding: 8px 12px; background: ${i}; border-radius: 6px; text-align: center; } .captcha-click-area { position: relative; border-radius: 8px; overflow: hidden; border: 1px solid ${s}; cursor: crosshair; } .captcha-click-hint { font-size: 12px; color: #999; text-align: center; padding: 4px; } .captcha-click-marker { position: absolute; width: 24px; height: 24px; background: ${o}; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: bold; pointer-events: none; z-index: 2; box-shadow: 0 2px 6px rgba(0,0,0,0.2); animation: captcha-pop 0.2s ease-out; } @keyframes captcha-pop { from { transform: scale(0); } to { transform: scale(1); } } .captcha-icon-thumb-wrap { display: flex; justify-content: center; padding: 8px; background: ${i}; border-radius: 6px; } .captcha-icon-thumb { height: 40px; } .captcha-rotate-wrap { display: flex; flex-direction: column; align-items: center; gap: 10px; } .captcha-rotate-main { position: relative; border-radius: 50%; border: 2px solid ${s}; overflow: visible; } .captcha-rotate-bg { border-radius: 50%; display: block; } .captcha-rotate-thumb { position: absolute; top: 50%; left: 50%; transform-origin: center center; margin-left: -50px; margin-top: -50px; } .captcha-rotate-track { width: 100%; position: relative; height: 40px; background: ${i}; border-radius: 20px; overflow: hidden; border: 1px solid ${s}; } .captcha-rotate-track-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #999; font-size: 13px; pointer-events: none; white-space: nowrap; } .captcha-result { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 32px 16px; gap: 12px; } .captcha-result-text { font-size: 15px; font-weight: 500; } .captcha-result-success .captcha-result-text { color: #52c41a; } .captcha-result-fail .captcha-result-text { color: #ff4d4f; } .captcha-retry-btn { background: ${o}; color: #fff; border: none; border-radius: 6px; padding: 8px 24px; font-size: 14px; cursor: pointer; margin-top: 4px; } .captcha-retry-btn:hover { opacity: 0.9; } .captcha-footer { display: flex; align-items: center; justify-content: space-between; padding-top: 8px; } .captcha-powered { font-size: 11px; color: #bbb; } `}}customElements.get("captcha-widget")||customElements.define("captcha-widget",u),window.CaptchaWidget=u,window.CAPTCHA_VERSION=g});