const TOOLS=[ {id:"color",name:"颜色转换器",cat:"frontend",icon:"palette",desc:"HEX / RGB / HSL 互转,支持取色器"}, {id:"gradient",name:"CSS渐变生成器",cat:"frontend",icon:"layers",desc:"线性/径向渐变可视化编辑"}, {id:"shadow",name:"CSS阴影生成器",cat:"frontend",icon:"square",desc:"box-shadow 可视化调整"}, {id:"json",name:"JSON格式化",cat:"frontend",icon:"braces",desc:"格式化 + 压缩 + 验证"}, {id:"html-entity",name:"HTML实体编解码",cat:"frontend",icon:"code",desc:"HTML特殊字符转义与还原"}, {id:"cron",name:"Cron解析器",cat:"backend",icon:"clock",desc:"Cron表达式人类可读解释+下次执行时间"}, {id:"jwt",name:"JWT解码器",cat:"backend",icon:"key",desc:"解析 Header / Payload,无需密钥"}, {id:"uuid",name:"UUID生成器",cat:"backend",icon:"hash",desc:"v1 / v4 / v7 多种版本"}, {id:"hash",name:"Hash计算器",cat:"backend",icon:"shield",desc:"MD5 / SHA1 / SHA256 / SHA512"}, {id:"base64",name:"Base64编解码",cat:"backend",icon:"file-text",desc:"文本与Base64互转,支持文件"}, {id:"url",name:"URL编解码",cat:"network",icon:"link",desc:"完整URL或单段编解码"}, {id:"timestamp",name:"时间戳转换",cat:"network",icon:"calendar",desc:"Unix时间戳 ↔ 人类可读时间"}, {id:"binary",name:"进制转换",cat:"network",icon:"toggle-right",desc:"十进制/二进制/十六进制/八进制"}, {id:"ip",name:"IP地址信息",cat:"network",icon:"globe",desc:"IPv4/IPv6地址解析详情"}, {id:"port",name:"端口扫描器",cat:"network",icon:"scan",desc:"常见端口快速检测(本地)"}, {id:"qrcode",name:"二维码生成器",cat:"network",icon:"qr-code",desc:"文本 / URL生成二维码"}, {id:"unit",name:"计量单位换算",cat:"daily",icon:"scale",desc:"长度/重量/温度/面积/体积"}, {id:"password",name:"密码生成器",cat:"daily",icon:"lock",desc:"自定义长度与字符类型"}, {id:"random",name:"随机数生成器",cat:"daily",icon:"dice",desc:"范围/数量/去重选项"}, {id:"countdown",name:"倒计时工具",cat:"daily",icon:"timer",desc:"倒计时 / 正计时工具"}, ]; const CATS=[ {id:"frontend",name:"前端工具"}, {id:"backend",name:"后端工具"}, {id:"network",name:"网络工具"}, {id:"daily",name:"生活工具"}, ]; const SVG={ palette:'', layers:'', square:'', braces:'', code:'', clock:'', key:'', hash:'', shield:'', "file-text":'', link:'', calendar:'', "toggle-right":'', globe:'', scan:'', "qr-code":'', scale:'', lock:'', dice:'', timer:'', home:'', server:'', wifi:'', }; let activeTool=null; function init(){renderSidebar();renderMobileTabs();renderHome();} function renderSidebar(){ const el=document.getElementById('sidebar'); let h=''; for(const cat of CATS){ const tt=TOOLS.filter(t=>t.cat===cat.id); h+='
'+cat.name+'
'; for(const t of tt)h+='
'+SVG[t.icon]+''+t.name+'
'; h+='
'; } el.innerHTML=h; } function renderMobileTabs(){ document.getElementById('mobileTabs').innerHTML=CATS.map(c=>'
'+c.name+'
').join(''); } function openFirstInCat(catId){const t=TOOLS.find(x=>x.cat===catId);if(t)openTool(t.id);} function showHome(){ activeTool=null; document.querySelectorAll('.sb-item').forEach(x=>x.classList.remove('active')); document.getElementById('home').classList.add('active'); document.getElementById('toolContent').classList.remove('active'); document.getElementById('toolContent').innerHTML=''; } function renderHome(){ const el=document.getElementById('home'); const catIcon={frontend:'code',backend:'server',network:'wifi',daily:'home'}; let h='

小白工具箱

你身边的瑞士军刀,'+TOOLS.length+'个常用工具

'+TOOLS.length+'
工具总数
'+CATS.length+'
分类数量
'; for(const cat of CATS){ const tt=TOOLS.filter(t=>t.cat===cat.id); if(!tt.length)continue; h+='
'+SVG[catIcon[cat.id]]+''+cat.name+'
'; for(const t of tt)h+='
'+SVG[t.icon]+'

'+t.name+'

'+t.desc+'

'; h+='
'; } el.innerHTML=h; } function openTool(id){ const t=TOOLS.find(t=>t.id===id); if(!t)return; activeTool=t; document.querySelectorAll('.sb-item').forEach(x=>x.classList.toggle('active',x.dataset.id===id)); document.getElementById('home').classList.remove('active'); const tc=document.getElementById('toolContent'); tc.classList.add('active'); tc.innerHTML=getToolHTML(t); setupTool(t.id); window.scrollTo(0,0); } function getToolHTML(t){ switch(t.id){ case 'color': return colorTool(); case 'gradient': return gradientTool(); case 'shadow': return shadowTool(); case 'json': return jsonTool(); case 'html-entity': return htmlEntityTool(); case 'cron': return cronTool(); case 'jwt': return jwtTool(); case 'uuid': return uuidTool(); case 'hash': return hashTool(); case 'base64': return base64Tool(); case 'url': return urlTool(); case 'timestamp': return timestampTool(); case 'binary': return binaryTool(); case 'ip': return ipTool(); case 'port': return portTool(); case 'qrcode': return qrcodeTool(); case 'unit': return unitTool(); case 'password': return passwordTool(); case 'random': return randomTool(); case 'countdown': return countdownTool(); default: return '

'+SVG[t.icon]+t.name+'

'+t.desc+'

工具开发中...

'; } } function S(v){return v===null||v===undefined||v==='';} function copyText(text,btn){ navigator.clipboard.writeText(text).then(()=>{ btn.textContent='已复制 ✓'; btn.classList.add('show'); setTimeout(()=>{btn.textContent='复制';btn.classList.remove('show');},2000); }); } // ========== COLOR TOOL ========== function colorTool(){ return `

${SVG.palette}颜色转换器

HEX / RGB / HSL 互转,支持取色器

输入
} // ========== GRADIENT TOOL ========== function gradientTool(){ return `

${SVG.layers}CSS渐变生成器

线性/径向渐变可视化编辑

渐变预览
} // ========== SHADOW TOOL ========== function shadowTool(){ return `

${SVG.square}CSS阴影生成器

box-shadow 可视化调整

预览
} // ========== JSON TOOL ========== function jsonTool(){ return `

${SVG.braces}JSON格式化

格式化 + 压缩 + 验证

输入 JSON
输出
输出结果将显示在这里...
`; } // ========== HTML ENTITY TOOL ========== function htmlEntityTool(){ return `

${SVG.code}HTML实体编解码

HTML特殊字符转义与还原

输入
输出
输出结果将显示在这里...
`; } // ========== CRON TOOL ========== function cronTool(){ return `

${SVG.clock}Cron解析器

Cron表达式人类可读解释 + 下次执行时间

输入 Cron 表达式
人类可读描述
每分钟执行一次
下次执行时间(5次)
} // ========== JWT TOOL ========== function jwtTool(){ return `

${SVG.key}JWT解码器

解析 Header / Payload(无需密钥,不验证签名)

输入 JWT
Header
Payload
`; } // ========== UUID TOOL ========== function uuidTool(){ return `

${SVG.hash}UUID生成器

v1 / v4 / v7 多种版本

生成选项
结果
点击"生成"获取UUID...
} // ========== HASH TOOL ========== function hashTool(){ return `

${SVG.shield}Hash计算器

MD5 / SHA1 / SHA256 / SHA512

输入文本
结果 (Hex)
在此输入文本...
`; } // ========== BASE64 TOOL ========== function base64Tool(){ return `

${SVG['file-text']}Base64编解码

文本与Base64互转,支持文件

输入
输出
结果将显示在这里...
`; } // ========== URL TOOL ========== function urlTool(){ return `

${SVG.link}URL编解码

完整URL或单段编解码

输入
输出
结果将显示在这里...
`; } // ========== TIMESTAMP TOOL ========== function timestampTool(){ return `

${SVG.calendar}时间戳转换

Unix时间戳 ↔ 人类可读时间

当前时间
时间戳 → 日期
结果...
日期 → 时间戳
秒: -- | 毫秒: --
} // ========== BINARY TOOL ========== function binaryTool(){ return `

${SVG['toggle-right']}进制转换

十进制/二进制/十六进制/八进制

输入值
转换结果
二进制 (BIN)
-
八进制 (OCT)
-
十进制 (DEC)
-
十六进制 (HEX)
-
`; } // ========== IP TOOL ========== function ipTool(){ return `

${SVG.globe}IP地址信息

IPv4/IPv6 地址解析详情

输入 IP 地址
解析结果
输入值
-
类型
-
版本
-
`; } // ========== PORT TOOL ========== function portTool(){ return `

${SVG.scan}端口扫描器

常见端口快速检测(本地)

扫描目标
扫描结果
点击"扫描"开始...
`; } // ========== QRCODE TOOL ========== function qrcodeTool(){ return `

${SVG['qr-code']}二维码生成器

文本 / URL 生成二维码

输入内容
二维码
`; } // ========== UNIT TOOL ========== function unitTool(){ return `

${SVG.scale}计量单位换算

长度/重量/温度/面积/体积

换算类型
结果
} // ========== PASSWORD TOOL ========== function passwordTool(){ return `

${SVG.lock}密码生成器

自定义长度与字符类型

配置
生成的密码
} // ========== RANDOM TOOL ========== function randomTool(){ return `

${SVG.dice}随机数生成器

范围/数量/去重选项

配置
结果
`; } // ========== COUNTDOWN TOOL ========== function countdownTool(){ return `

${SVG.timer}倒计时工具

倒计时 / 正计时工具

倒计时模式 - 输入时分秒
05:00
// ========== TOOL IMPLEMENTATIONS ========== // Color conversions function hexToRgb(h){ let r=0,g=0,b=0; if(h.match(/^#?[0-9A-Fa-f]{6}$/)){ const hex=h.replace('#',''); r=parseInt(hex.slice(0,2),16);g=parseInt(hex.slice(2,4),16);b=parseInt(hex.slice(4,6),16); } return[r,g,b]; } function rgbToHex(r,g,b){return'#'+[r,g,b].map(x=>Math.max(0,Math.min(255,x)).toString(16).padStart(2,'0')).join('');} function rgbToHsl(r,g,b){ r/=255;g/=255;b/=255; const max=Math.max(r,g,b),min=Math.min(r,g,b); let h,s,l=(max+min)/2; if(max===min){h=s=0;} else{const d=max-min;s=l>.5?d/(2-max-min):d/(max+min); switch(max){case r:h=((g-b)/d+(gMath.round(x*255)); const hue2rgb=(p,q,t)=>{if(t<0)t+=1;if(t>1)t-=1;if(t<1/6)return p+(q-p)*6*t;if(t<1/2)return q;if(t<2/3)return p+(q-p)*(2/3-t)*6;return p;}; const q=l<.5?l*(1+s):l+s-l*s; const p=2*l-q; return[hue2rgb(p,q,h+1/3),hue2rgb(p,q,h),hue2rgb(p,q,h-1/3)].map(x=>Math.round(x*255)); } function convertColor(src){ if(src==='hex'){ const hex=document.getElementById('cHex').value; const[r,g,b]=hexToRgb(hex); const[h,s,l]=rgbToHsl(r,g,b); document.getElementById('cR').value=r;document.getElementById('cG').value=g;document.getElementById('cB').value=b; document.getElementById('cH').value=h;document.getElementById('cS').value=s;document.getElementById('cL').value=l; document.getElementById('colorPreview').style.background=hex; document.getElementById('colorPicker').value=hex; }else if(src==='rgb'){ const r=+document.getElementById('cR').value,g=+document.getElementById('cG').value,b=+document.getElementById('cB').value; const hex=rgbToHex(r,g,b); const[h,s,l]=rgbToHsl(r,g,b); document.getElementById('cHex').value=hex; document.getElementById('cH').value=h;document.getElementById('cS').value=s;document.getElementById('cL').value=l; document.getElementById('colorPreview').style.background=hex; document.getElementById('colorPicker').value=hex; }else if(src==='hsl'){ const h=+document.getElementById('cH').value,s=+document.getElementById('cS').value,l=+document.getElementById('cL').value; const[r,g,b]=hslToRgb(h,s,l); const hex=rgbToHex(r,g,b); document.getElementById('cHex').value=hex; document.getElementById('cR').value=r;document.getElementById('cG').value=g;document.getElementById('cB').value=b; document.getElementById('colorPreview').style.background=hex; document.getElementById('colorPicker').value=hex; } } function pickColor(v){ document.getElementById('cHex').value=v; convertColor('hex'); } // Gradient function updateGradient(){ const type=document.getElementById('gradType').value; const from=document.getElementById('gradFrom').value; const to=document.getElementById('gradTo').value; const angle=document.getElementById('gradAngle').value; let css=''; if(type==='linear')css=`linear-gradient(${angle}deg, ${from}, ${to})`; else if(type==='radial')css=`radial-gradient(circle, ${from}, ${to})`; else css=`conic-gradient(from ${angle}deg, ${from}, ${to})`; document.getElementById('gradPreview').style.background=css; document.getElementById('gradOutput').textContent=css; } // Shadow function updateShadow(){ const x=document.getElementById('shX').value; const y=document.getElementById('shY').value; const blur=document.getElementById('shBlur').value; const spread=document.getElementById('shSpread').value; const color=document.getElementById('shColor').value; const type=document.getElementById('shType').value; const sh=`${x}px ${y}px ${blur}px ${spread}px ${color} ${type}`; document.getElementById('shadowBox').style.boxShadow=sh; document.getElementById('shOutput').textContent=`box-shadow: ${sh};`; } // JSON function formatJSON(){ const v=document.getElementById('jsonInput').value.trim(); const out=document.getElementById('jsonOutput'); if(!v){out.textContent='请输入JSON';out.className='output-box empty';return;} try{const j=JSON.parse(v);out.textContent=JSON.stringify(j,null,2);out.className='output-box';} catch(e){out.textContent='JSON格式错误: '+e.message;out.className='output-box error';} } function minifyJSON(){ const v=document.getElementById('jsonInput').value.trim(); const out=document.getElementById('jsonOutput'); if(!v){out.textContent='请输入JSON';out.className='output-box empty';return;} try{const j=JSON.parse(v);out.textContent=JSON.stringify(j);out.className='output-box';} catch(e){out.textContent='JSON格式错误: '+e.message;out.className='output-box error';} } function clearJSON(){document.getElementById('jsonInput').value='';document.getElementById('jsonOutput').textContent=''输出结果将显示在这里...';document.getElementById('jsonOutput').className='output-box empty';} // HTML Entity function encodeHE(){ const v=document.getElementById('heInput').value; const out=document.getElementById('heOutput'); const encoded=v.replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'",'''}[c])); out.textContent=encoded;out.className='output-box'; } function decodeHE(){ const v=document.getElementById('heInput').value; const out=document.getElementById('heOutput'); try{ const textarea=document.createElement('textarea'); textarea.innerHTML=v; out.textContent=textarea.value; out.className='output-box'; }catch(e){out.textContent='解码错误: '+e.message;out.className='output-box error';} } function doHtmlEntity(){} // Cron function parseCron(){ const expr=document.getElementById('cronInput').value.trim(); const descEl=document.getElementById('cronDesc'); const nextEl=document.getElementById('cronNext'); if(!expr){descEl.textContent='请输入Cron表达式';nextEl.textContent='';return;} const parts=expr.split(/\s+/); if(parts.length<5){descEl.textContent='无效表达式,需要5段';nextEl.textContent='';return;} const[min,hour,dom,mon,dow]=parts; descEl.textContent='每分钟执行一次';nextEl.textContent=''; // Human readable let desc=''; if(min==='*'&&hour==='*'&&dom==='*'&&mon==='*'&&dow==='*')desc='每分钟'; else if(min==='0'&&hour==='*')desc='每小时整点'; else if(min==='0'&&hour==='0')desc='每天午夜'; else if(dow!=='*'&&dom==='*')desc=`每${['日','一','二','三','四','五','六'][+dow]||dow}`; else if(min!=='*'&&hour!=='*')desc=`每天 ${hour}:${min.padStart(2,'0')}`; else desc=`${expr} — 自定义调度`; descEl.textContent=desc; // Next 5 runs const now=new Date(); const runs=[]; let d=new Date(now); for(let i=0;i<100&&runs.length<5;i++){ d=new Date(d.getTime()+60000); if(min!=='*'&&+min!==d.getMinutes())continue; if(hour!=='*'&&+hour!==d.getHours())continue; runs.push(d.toLocaleString('zh-CN')); } nextEl.textContent=runs.join('\n')||'无法计算'; } // JWT function decodeJWT(){ const token=document.getElementById('jwtInput').value.trim(); const hEl=document.getElementById('jwtHeader'); const pEl=document.getElementById('jwtPayload'); if(!token){hEl.textContent='';pEl.textContent='';return;} try{ const[headerB64,payloadB64]=token.split('.'); const header=JSON.parse(atob(headerB64.replace(/-/g,'+').replace(/_/g,'/'))); const payload=JSON.parse(atob(payloadB64.replace(/-/g,'+').replace(/_/g,'/'))); hEl.textContent=JSON.stringify(header,null,2); pEl.textContent=JSON.stringify(payload,null,2); }catch(e){hEl.textContent='解码失败: '+e.message;hEl.className='output-box error';pEl.textContent='';hEl.className='output-box';} } // UUID function genUUIDs(){ const ver=document.getElementById('uuidVer').value; const count=+document.getElementById('uuidCount').value||1; const out=document.getElementById('uuidOutput'); const uuids=[]; for(let i=0;i{ const r=Math.random()*16|0; return(c==='x'?r:(r&0x3|0x8).toString(16)); })); }else if(ver==='1'){ const m=16;const d=()=>Math.random()*m|0; uuids.push(`${d().toString(m)}${d().toString(m)}${d().toString(m)}${d().toString(m)}-${d().toString(m)}${d().toString(m)}${d().toString(m)}-${m.toString(16)}xxx${d().toString(m)}${d().toString(m)}-${d().toString(m)}${d().toString(m)}${d().toString(m)}${d().toString(m)}${d().toString(m)}${d().toString(m)}${d().toString(m)}`); }else{ // v7: unix ts ms const t=Date.now().toString(16).padStart(12,'0'); const r=()=>Math.random().toString(16).slice(2,10); uuids.push(`${t.slice(0,8)}-${t.slice(8,12)}-7${r().slice(0,3)}-${(parseInt(r().slice(0,2),16)&0x0f|0x70).toString(16)}${r().slice(1,4)}-${r().slice(4)}`); } } out.textContent=uuids.join('\n');out.className='output-box'; } // Hash - using Web Crypto API async function computeHash(){ const text=document.getElementById('hashInput').value; const algo=document.getElementById('hashAlgo').value; const out=document.getElementById('hashOutput'); if(!text){out.textContent='在此输入文本...';out.className='output-box empty';return;} try{ const buf=new TextEncoder().encode(text); const hash=await crypto.subtle.digest(algo.replace('sha','SHA-'),buf); out.textContent=Array.from(new Uint8Array(hash)).map(b=>b.toString(16).padStart(2,'0')).join(''); out.className='output-box'; }catch(e){out.textContent='Hash计算失败: '+e.message;out.className='output-box error';} } // Base64 function encodeB64(){ const v=document.getElementById('b64Input').value; document.getElementById('b64Output').textContent=btoa(unescape(encodeURIComponent(v))); document.getElementById('b64Output').className='output-box'; } function decodeB64(){ try{ const v=document.getElementById('b64Input').value; document.getElementById('b64Output').textContent=decodeURIComponent(escape(atob(v))); document.getElementById('b64Output').className='output-box'; }catch(e){document.getElementById('b64Output').textContent='Base64格式错误';document.getElementById('b64Output').className='output-box error';} } function doBase64(){} // URL function encodeURL(){ const v=document.getElementById('urlInput').value; try{ document.getElementById('urlOutput').textContent=encodeURIComponent(v); document.getElementById('urlOutput').className='output-box'; }catch(e){document.getElementById('urlOutput').textContent='编码错误: '+e.message;} } function decodeURL(){ try{ const v=document.getElementById('urlInput').value; document.getElementById('urlOutput').textContent=decodeURIComponent(v); document.getElementById('urlOutput').className='output-box'; }catch(e){document.getElementById('urlOutput').textContent='解码错误: '+e.message;} } function doURL(){} // Timestamp function updateTSNow(){ const now=Math.floor(Date.now()/1000); const ms=Date.now(); const d=new Date(); document.getElementById('tsNow').textContent=`Unix时间戳(秒): ${now}\nUnix时间戳(毫秒): ${ms}\n本地时间: ${d.toLocaleString('zh-CN')}`; } function tsToDate(){ const sec=document.getElementById('tsSec').value.trim(); const el=document.getElementById('tsDateOut'); if(!sec){el.textContent='请输入时间戳';return;} try{el.textContent=new Date(+sec*1000).toLocaleString('zh-CN');}catch(e){el.textContent='错误: '+e.message;} } function tsMsToDate(){ const ms=document.getElementById('tsMs').value.trim(); const el=document.getElementById('tsDateOut'); if(!ms){el.textContent='请输入毫秒时间戳';return;} try{el.textContent=new Date(+ms).toLocaleString('zh-CN');}catch(e){el.textContent='错误: '+e.message;} } function dateToTS(){ const v=document.getElementById('tsDateIn').value; const el=document.getElementById('tsOut'); if(!v){el.textContent='秒: -- | 毫秒: --';return;} try{ const d=new Date(v); el.textContent=`秒: ${Math.floor(d.getTime()/1000)} | 毫秒: ${d.getTime()}`; }catch(e){el.textContent='错误: '+e.message;} } function useNowTimestamp(){ const now=Math.floor(Date.now()/1000); document.getElementById('tsSec').value=now; document.getElementById('tsMs').value=Date.now(); tsToDate();tsMsToDate(); } // Binary function convertBase(){ const val=document.getElementById('binInput').value.trim(); const from=+document.getElementById('binFrom').value; const el2=document.getElementById('binOut2'); const el8=document.getElementById('binOut8'); const el10=document.getElementById('binOut10'); const el16=document.getElementById('binOut16'); if(!val){el2.textContent='-';el8.textContent='-';el10.textContent='-';el16.textContent='-';return;} try{ const dec=parseInt(val,from); el2.textContent=dec.toString(2); el8.textContent=dec.toString(8); el10.textContent=dec.toString(10); el16.textContent=dec.toString(16).toUpperCase(); }catch(e){el2.textContent='错误';el8.textContent='错误';el10.textContent='错误';el16.textContent='错误';} } // IP function parseIP(){ const ip=document.getElementById('ipInput').value.trim(); const valEl=document.getElementById('ipVal'); const typeEl=document.getElementById('ipType'); const verEl=document.getElementById('ipVer'); const resultEl=document.getElementById('ipResult'); if(!ip){valEl.textContent='-';typeEl.textContent='-';verEl.textContent='-';return;} valEl.textContent=ip; // Detect version and type if(/^(\d{1,3}\.){3}\d{1,3}$/.test(ip)){ verEl.textContent='IPv4'; const parts=ip.split('.').map(Number); const isPrivate=parts[0]===10||(parts[0]===172&&parts[1]>=16&&parts[1]<=31)||(parts[0]===192&&parts[1]===168)||parts[0]===127; const isLoopback=parts[0]===127; typeEl.textContent=isLoopback?'环回地址':isPrivate?'私有地址':'公网地址'; }else if(/^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$/.test(ip)){ verEl.textContent='IPv6'; typeEl.textContent=ip==='::1'?'环回地址':ip.startsWith('fe80')?'链路本地地址':'公网/其他'; }else{ verEl.textContent='未知'; typeEl.textContent='格式错误'; } } function detectLocalIP(){ document.getElementById('ipInput').value='检测中...'; const RTCPeerConnection=window.RTCPeerConnection||window.webkitRTCPeerConnection; if(!RTCPeerConnection){document.getElementById('ipInput').value='浏览器不支持WebRTC';return;} const pc=new RTCPeerConnection({iceServers:[]}); pc.createDataChannel(''); pc.createOffer().then(o=>pc.setLocalDescription(o)); pc.onicecandidate=e=>{ if(!e.candidate)return; const match=e.candidate.candidate.match(/(\d+\.\d+\.\d+\.\d+)/); if(match){document.getElementById('ipInput').value=match[1];pc.close();} }; } // Port async function scanPorts(){ const host=document.getElementById('portHost').value; const list=document.getElementById('portList').value; const out=document.getElementById('portOutput'); const ports=list.split(',').map(p=>parseInt(p.trim())).filter(p=>!isNaN(p)&&p>0&&p<65536); if(!ports.length){out.textContent='请输入有效的端口列表';return;} out.textContent='正在扫描...\n'; out.className='output-box'; const results=[]; const controller=new AbortController(); const timeout=setTimeout(()=>controller.abort(),3000); for(const port of ports){ try{ const resp=await fetch(`https://${host}:${port}`,{method:'HEAD',signal:controller.signal}).catch(()=>null); results.push({port,open:resp&&resp.ok}); }catch{results.push({port,open:null}); } } clearTimeout(timeout); out.textContent=results.map(r=>`端口 ${r.port}: ${r.open===true?'开放 ✓':r.open===false?'关闭 ✗':'超时/不可达'}`).join('\n'); } // QR Code (using a simple canvas-based QR encoder) function genQR(){ const text=document.getElementById('qrInput').value; const canvas=document.getElementById('qrCanvas'); if(!text){canvas.getContext('2d').clearRect(0,0,canvas.width,canvas.height);return;} // Simple QR encoding using a basic algorithm - encode text as QR // For demo, we'll use a placeholder that renders a simple grid const size=200; canvas.width=size;canvas.height=size; const ctx=canvas.getContext('2d'); ctx.clearRect(0,0,size,size); ctx.fillStyle='#fff'; ctx.fillRect(0,0,size,size); // Use a simple hash-based pattern for visual QR-like output // In production you'd use a proper QR library const hash=text.split('').reduce((acc,c)=>acc+c.charCodeAt(0),0); ctx.fillStyle='#000'; const moduleCount=25; const moduleSize=Math.floor(size/moduleCount); for(let y=0;y{ ctx.fillStyle='#000'; ctx.fillRect(ox,oy,moduleSize*7,moduleSize*7); ctx.fillStyle='#fff'; ctx.fillRect(ox+moduleSize,oy+moduleSize,moduleSize*5,moduleSize*5); ctx.fillStyle='#000'; ctx.fillRect(ox+moduleSize*2,oy+moduleSize*2,moduleSize*3,moduleSize*3); }; drawFinder(0,0);drawFinder(moduleCount*moduleSize-7*moduleSize,0);drawFinder(0,moduleCount*moduleSize-7*moduleSize); } // Unit const UNIT_CONFIGS={ length:{units:['m','cm','mm','km','mi','ft','in','yd'],factor:[1,100,1000,0.001,1609.344,0.3048,0.0254,0.9144]}, weight:{units:['kg','g','mg','t','lb','oz'],factor:[1,1000,1e6,1000,0.453592,0.0283495]}, temp:{units:['°C','°F','K'],fromCelsius:[1,(v=>v*9/5+32),(v=>v+273.15)]}, area:{units:['m²','km²','ha','acre','ft²'],factor:[1,1e6,10000,4046.856,0.092903]}, volume:{units:['L','mL','m³','gal','ft³'],factor:[1,1000,0.001,3.78541,28.3168]}, }; function renderUnitInputs(){ const type=document.getElementById('unitType').value; const fields=document.getElementById('unitFields'); const cfg=UNIT_CONFIGS[type]; let h=''; for(const unit of cfg.units){ h+=`
`; } fields.innerHTML=h; } function convertUnit(){ const type=document.getElementById('unitType').value; const cfg=UNIT_CONFIGS[type]; const out=document.getElementById('unitOutput'); let lines=[]; if(type==='temp'){ const c=+document.getElementById('unit_C').value||0; lines.push(`°C: ${c}`); lines.push(`°F: ${(c*9/5+32).toFixed(2)}`); lines.push(`K: ${(c+273.15).toFixed(2)}`); }else{ for(let i=0;i`${u}: ${(base/cfg.factor[j]).toFixed(6)}`).join('\n'); lines.push(`${unit} = ${results}`); } } out.textContent=lines.join('\n\n'); out.className='output-box'; } // Password function genPassword(){ const len=+document.getElementById('pwdLen').value; const set=document.getElementById('pwdSet').value; const chars={'all':'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*','alpha':'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789','letters':'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz','num':'0123456789'}[set]; let pwd=''; for(let i=0;imax-min+1){out.textContent='去重模式下数量不能超过范围';out.className='output-box error';return;} const nums=[]; const set=new Set(); while(nums.length{ if(cdSeconds<=0){cdPause();cdSeconds=0;updateCDDisplay();return;} cdSeconds--; const th=Math.floor(cdSeconds/3600); const tm=Math.floor((cdSeconds%3600)/60); const ts=cdSeconds%60; document.getElementById('cdDisplay').textContent=`${String(th).padStart(2,'0')}:${String(tm).padStart(2,'0')}:${String(ts).padStart(2,'0')}`; },1000); } function cdPause(){ if(cdInterval){clearInterval(cdInterval);cdInterval=null;} cdRunning=false; document.getElementById('cdStartBtn').textContent='继续'; document.getElementById('cdDisplay').classList.remove('running'); } function cdReset(){ cdPause(); cdSeconds=0; updateCDDisplay(); document.getElementById('cdStartBtn').textContent='开始'; } // Search function handleSearch(q){ if(!q.trim()){document.querySelectorAll('.sb-item').forEach(x=>x.style.display='');renderHome();return;} const ql=q.toLowerCase(); TOOLS.forEach(t=>{ const el=document.querySelector(`.sb-item[data-id="${t.id}"]`); if(el)el.style.display=(t.name.includes(ql)||t.desc.includes(ql)||t.id.includes(ql))?'':'none'; }); } // Init init();