update: 2026-03-28 20:59

This commit is contained in:
2026-03-28 20:59:52 +08:00
parent e21d58e603
commit 1c81d4e6ea
611 changed files with 27847 additions and 65061 deletions

View File

@@ -0,0 +1,13 @@
/**
* 在 iframe 内嵌展示时隐藏静态页自带的顶栏,避免与 FullscreenEmbed 顶栏重复
*/
(function () {
try {
if (window.self !== window.top) {
var el = document.createElement('style');
el.setAttribute('data-ig-embed', '1');
el.textContent = '.header{display:none!important}';
document.head.appendChild(el);
}
} catch (e) { /* 忽略 */ }
})();

View File

@@ -0,0 +1,13 @@
/* 由 SPA 在 iframe URL 上附加 ?sixty_base=encodeURIComponent(baseUrl);无参数时默认萌芽节点 */
(function () {
var fallback = 'https://60s.api.shumengya.top';
var base = fallback;
try {
var q = new URLSearchParams(window.location.search).get('sixty_base');
if (q) {
base = decodeURIComponent(q);
}
} catch (e) {}
base = String(base).replace(/\/+$/, '');
window.__SIXTY_API_BASE__ = base || fallback;
})();

View File

@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>AI资讯快报</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}
.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.date{display:flex;align-items:center;gap:6px;font-size:13px;color:#6b7280;padding-bottom:12px;border-bottom:1px solid #e5e7eb;margin-bottom:16px}
.item{display:flex;gap:10px;padding:11px 0;border-bottom:1px solid #f3f4f6}.item:last-child{border-bottom:none}
.num{flex-shrink:0;width:24px;height:24px;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;margin-top:1px;color:#9ca3af;background:#f3f4f6}
.num.t1{color:#fff;background:#ef4444}.num.t2{color:#fff;background:#f97316}.num.t3{color:#fff;background:#eab308}
.text{flex:1;font-size:14px;line-height:1.7}
.tip{margin-top:20px;padding:14px 16px;border-radius:12px;font-size:13px;line-height:1.6;color:#6b7280;background:#f0fdf4;border:1px solid rgba(34,197,94,.1);font-style:italic}
.cover{margin-top:16px;text-align:center}.cover img{max-width:100%;border-radius:10px;box-shadow:0 2px 10px rgba(0,0,0,.08)}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
@media(max-width:640px){.body{padding:16px 12px 32px}.text{font-size:13px}.header h1{font-size:14px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🤖 AI资讯快报</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
const API=window.__SIXTY_API_BASE__+'/v2/ai-news?encoding=json';
function escapeHtml(s){
if(s==null)return'';
return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
function pickNewsList(d){
if(!d||typeof d!=='object')return[];
if(Array.isArray(d))return d;
const keys=['news','items','list','data','content'];
for(const k of keys){
const v=d[k];
if(Array.isArray(v))return v;
}
return [];
}
function renderNewsItem(t,i){
const cls=i===0?'t1':i===1?'t2':i===2?'t3':'';
if(typeof t==='string'){
return `<div class="item"><div class="num ${cls}">${i+1}</div><div class="text">${escapeHtml(t)}</div></div>`;
}
if(t&&typeof t==='object'){
const title=t.title||t.name||'';
const link=t.link||t.url||'';
const detail=(t.detail||t.desc||t.description||'').trim();
const source=t.source||'';
const short=detail.length>220?detail.slice(0,220)+'…':detail;
let titleHtml=escapeHtml(title);
if(link)titleHtml=`<a href="${escapeHtml(link)}" target="_blank" rel="noopener" style="color:#059669;font-weight:600;text-decoration:none">${titleHtml} ↗</a>`;
let body=`<div class="text"><div style="margin-bottom:6px">${titleHtml}</div>`;
if(short)body+=`<div style="font-size:13px;color:#6b7280;line-height:1.65">${escapeHtml(short)}</div>`;
if(source)body+=`<div style="font-size:12px;color:#9ca3af;margin-top:6px">来源 · ${escapeHtml(source)}</div>`;
body+='</div>';
return `<div class="item"><div class="num ${cls}">${i+1}</div>${body}</div>`;
}
return `<div class="item"><div class="num ${cls}">${i+1}</div><div class="text">${escapeHtml(String(t))}</div></div>`;
}
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(API,{headers:{Accept:'application/json'}});
const json=await res.json();
if(json.code!=null&&json.code!==200&&json.code!==0){
throw new Error(json.message||('接口 code '+json.code));
}
const d=json.data||json;
let html='';
if(d.date)html+=`<div class="date">🕐 ${escapeHtml(d.date)} ${escapeHtml(d.day_of_week||'')}</div>`;
const news=pickNewsList(d);
if(news.length===0){
html+=`<div class="tip" style="margin-top:0;font-style:normal">
<strong>当日暂无 AI 资讯条目</strong><br><br>
官方说明:数据源并非每日更新,重大资讯也可能集中在晚间。建议 <strong>22:00 后</strong> 再试,或在接口中传入 <code style="background:#fff;padding:2px 6px;border-radius:6px">?date=2025-11-11</code> 查看历史日期。
</div>`;
}else{
news.forEach((t,i)=>{html+=renderNewsItem(t,i);});
}
if(d.tip)html+=`<div class="tip">💡 ${escapeHtml(d.tip)}</div>`;
if(d.image)html+=`<div class="cover"><img src="${escapeHtml(d.image)}" alt="封面" loading="lazy"></div>`;
el.innerHTML=html||'<div class="err">暂无数据</div>';
}catch(e){el.innerHTML=`<div class="err">加载失败:${escapeHtml(e.message)}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,111 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Epic免费游戏</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.rank-item{display:flex;align-items:stretch;gap:12px;padding:12px 14px;margin-bottom:6px;border-radius:12px;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.04);transition:all .15s}
.rank-item:hover{box-shadow:0 3px 10px rgba(0,0,0,.08);transform:translateX(2px)}
.thumb-wrap{flex-shrink:0;width:120px;min-height:68px;border-radius:10px;overflow:hidden;background:#f3f4f6;align-self:center}
.thumb-wrap img{display:block;width:100%;height:100%;min-height:68px;object-fit:cover}
.rank-main{display:flex;align-items:flex-start;gap:10px;flex:1;min-width:0}
.badge{flex-shrink:0;width:30px;height:30px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:800;color:#9ca3af;background:#f3f4f6}
.badge.t1{color:#fff;background:linear-gradient(135deg,#ef4444,#dc2626)}.badge.t2{color:#fff;background:linear-gradient(135deg,#f97316,#ea580c)}.badge.t3{color:#fff;background:linear-gradient(135deg,#eab308,#ca8a04)}
.rank-body{flex:1;min-width:0}
.rank-title{font-size:14px;font-weight:500;line-height:1.4;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rank-title a{color:inherit;text-decoration:none}.rank-title a:hover{color:#059669}
.rank-meta{font-size:11px;color:#b0b0b0;margin-top:2px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
@media(max-width:640px){.thumb-wrap{width:88px;min-height:50px}.thumb-wrap img{min-height:50px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🎮 Epic免费游戏</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
function safeHttpUrl(u){
if(!u||typeof u!=='string')return'';
const t=u.trim();
return /^https?:\/\//i.test(t)?t:'';
}
function escapeAttr(s){
return String(s).replace(/&/g,'&amp;').replace(/"/g,'&quot;');
}
function escapeHtml(s){
return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
/** 从 Epic / 60s 多种字段里取封面图 */
function pickEpicCover(item){
if(!item)return'';
const tryKeys=['poster','cover','coverUrl','image','imageUrl','thumbnail','icon','logo'];
for(const k of tryKeys){
const v=item[k];
if(typeof v==='string'&&safeHttpUrl(v))return safeHttpUrl(v);
}
const imgs=item.keyImages||item.images;
if(Array.isArray(imgs)&&imgs.length){
const wide=imgs.find(function(k){return k&&(/wide|landscape|offerimagewide|diesel/i.test(String(k.type||'')));});
const first=imgs[0];
const url=(wide&&wide.url)||(first&&first.url)||'';
return safeHttpUrl(url);
}
return'';
}
function pickEpicList(d){
if(Array.isArray(d))return d;
if(!d||typeof d!=='object')return[];
const keys=['games','freeGames','items','list','data','elements'];
for(let i=0;i<keys.length;i++){
const v=d[keys[i]];
if(Array.isArray(v))return v;
}
return[];
}
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/epic?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data||json;
const list=pickEpicList(d);
if(!list.length)throw new Error('暂无数据');
let html='';
list.slice(0,50).forEach((item,i)=>{
const title=item.title||item.name||String(item);
const link=item.link||item.url||item.storeUrl||'';
const hot=item.hot||item.hotScore||item.heat||item.score||'';
const desc=item.desc||item.description||item.subtitle||'';
const img=pickEpicCover(item);
const cls=i===0?'t1':i===1?'t2':i===2?'t3':'';
html+='<div class="rank-item">';
if(img)html+=`<div class="thumb-wrap"><img src="${escapeAttr(img)}" alt="" loading="lazy" decoding="async" onerror="this.style.visibility='hidden'"/></div>`;
html+='<div class="rank-main"><div class="badge '+cls+'">'+(i+1)+'</div><div class="rank-body">';
html+=`<div class="rank-title">${link?`<a href="${escapeAttr(link)}" target="_blank" rel="noopener">${escapeHtml(title)} ↗</a>`:escapeHtml(title)}</div>`;
if(desc)html+=`<div class="rank-meta">${escapeHtml(desc.length>120?desc.slice(0,120)+'…':desc)}</div>`;
if(hot)html+=`<div class="rank-meta">🔥 ${typeof hot==='number'?hot.toLocaleString():hot}</div>`;
html+='</div></div></div>';
});
el.innerHTML=html;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>农历信息</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.hero{background:linear-gradient(135deg,#312e81,#4c1d95);border-radius:20px;padding:28px 24px;margin-bottom:16px;color:#fff;text-align:center}
.big{font-size:26px;font-weight:800;text-shadow:0 2px 8px rgba(0,0,0,.2);margin-bottom:4px}
.sub{font-size:14px;opacity:.85;margin-bottom:12px}
.chips{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}
.chip{background:rgba(255,255,255,.15);padding:4px 12px;border-radius:8px;font-size:12px}
.section{background:#fff;border-radius:14px;padding:16px;margin-bottom:10px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
.section-title{font-size:13px;font-weight:700;color:#6b7280;margin-bottom:10px;display:flex;align-items:center;gap:6px}
.row{display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid #f9fafb}.row:last-child{border-bottom:none}
.rk{font-size:13px;color:#9ca3af}.rv{font-size:13px;color:#1f2937;font-weight:500}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🌙 农历信息</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/lunar?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data||json;
if(!d?.solar){el.innerHTML='<div class="err">暂无农历数据</div>';return}
const s=d.solar||{},l=d.lunar||{},z=d.zodiac||{},sc=d.sixty_cycle||{},st=d.stats||{},tb=d.taboo?.day||{};
let chips='';
if(d.constellation?.name)chips+=`<span class="chip">⭐ ${d.constellation.name}</span>`;
if(z.year)chips+=`<span class="chip">🐾 ${z.year}年</span>`;
if(d.phase?.name)chips+=`<span class="chip">🌙 ${d.phase.name}</span>`;
if(d.term?.stage?.name)chips+=`<span class="chip">🌿 ${d.term.stage.name}</span>`;
let html=`<div class="hero"><div class="big">${s.full||''} ${s.week_desc||''}</div><div class="sub">${l.year_desc||''} ${l.month_desc||''}${l.day_desc||''}</div><div class="chips">${chips}</div></div>`;
html+=`<div class="section"><div class="section-title">📅 日期信息</div><div class="row"><span class="rk">阳历</span><span class="rv">${s.full_with_time||s.full}</span></div><div class="row"><span class="rk">农历</span><span class="rv">${l.desc_short||l.month_desc+l.day_desc}</span></div><div class="row"><span class="rk">季节</span><span class="rv">${s.season_desc||''} (${s.season_name||''})</span></div>${s.is_leap_year!==undefined?`<div class="row"><span class="rk">闰年</span><span class="rv">${s.is_leap_year?'是':'否'}</span></div>`:''}</div>`;
if(sc.day)html+=`<div class="section"><div class="section-title">🔮 天干地支</div><div class="row"><span class="rk">年柱</span><span class="rv">${sc.year?.name||''}</span></div><div class="row"><span class="rk">月柱</span><span class="rv">${sc.month?.name||''}</span></div><div class="row"><span class="rk">日柱</span><span class="rv">${sc.day?.name||''}</span></div><div class="row"><span class="rk">时柱</span><span class="rv">${sc.hour?.name||''}</span></div></div>`;
if(st.percents_formatted)html+=`<div class="section"><div class="section-title">📊 时间进度</div><div class="row"><span class="rk">今年进度</span><span class="rv">${st.percents_formatted.year}</span></div><div class="row"><span class="rk">本月进度</span><span class="rv">${st.percents_formatted.month}</span></div><div class="row"><span class="rk">今天进度</span><span class="rv">${st.percents_formatted.day}</span></div><div class="row"><span class="rk">第几天</span><span class="rv">第 ${st.day_of_year} 天 / 第 ${st.week_of_year} 周</span></div></div>`;
if(tb.recommends||tb.avoids)html+=`<div class="section"><div class="section-title">📜 宜忌</div>${tb.recommends?`<div class="row"><span class="rk">宜</span><span class="rv" style="color:#16a34a">${tb.recommends.replace(/\./g,' · ')}</span></div>`:''}${tb.avoids?`<div class="row"><span class="rk">忌</span><span class="rv" style="color:#dc2626">${tb.avoids.replace(/\./g,' · ')}</span></div>`:''}</div>`;
el.innerHTML=html;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>历史上的今天</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.hero{background:linear-gradient(135deg,#92400e,#b45309);border-radius:16px;padding:20px;margin-bottom:16px;color:#fff;text-align:center}
.hero h2{font-size:22px;margin-bottom:4px}.hero p{font-size:13px;opacity:.8}
.card{background:#fff;border-radius:14px;padding:16px;margin-bottom:10px;box-shadow:0 1px 3px rgba(0,0,0,.04);border-left:3px solid #f59e0b}
.card.birth{border-left-color:#3b82f6}.card.death{border-left-color:#ef4444}
.year{display:inline-block;padding:2px 8px;border-radius:6px;font-size:12px;font-weight:700;margin-bottom:6px;background:#fef3c7;color:#92400e}
.card.birth .year{background:#dbeafe;color:#1e40af}.card.death .year{background:#fecaca;color:#991b1b}
.card-title{font-size:15px;font-weight:600;margin-bottom:6px;line-height:1.5}
.card-desc{font-size:13px;color:#6b7280;line-height:1.7}
.card-link{display:inline-flex;align-items:center;gap:4px;font-size:12px;color:#059669;margin-top:8px;text-decoration:none}
.card-link:hover{text-decoration:underline}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>📅 历史上的今天</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/today-in-history?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data||json;
const items=d?.items||(Array.isArray(d)?d:[]);
if(!items.length)throw new Error('暂无历史数据');
let html=`<div class="hero"><h2>📅 历史上的今天</h2><p>${d?.month||''}${d?.day||''}日 · 共 ${items.length} 条</p></div>`;
items.forEach(item=>{
const t=item.event_type||'event';
const label=t==='birth'?'出生':t==='death'?'逝世':'事件';
html+=`<div class="card ${t}"><div class="year">${item.year||''}年 · ${label}</div><div class="card-title">${item.title||''}</div>`;
if(item.description){const desc=item.description.length>200?item.description.slice(0,200)+'…':item.description;html+=`<div class="card-desc">${desc}</div>`}
if(item.link)html+=`<a class="card-link" href="${item.link}" target="_blank" rel="noopener">↗ 查看详情</a>`;
html+='</div>';
});
el.innerHTML=html;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,71 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>当日货币汇率</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.hero{background:linear-gradient(135deg,#065f46,#059669);border-radius:16px;padding:20px;margin-bottom:16px;color:#fff;text-align:center}
.hero h2{font-size:22px;margin-bottom:4px}.hero p{font-size:12px;opacity:.8}
.search{width:100%;padding:12px 16px;border:2px solid #e5e7eb;border-radius:12px;font-size:14px;font-family:inherit;margin-bottom:12px;transition:border-color .2s}
.search:focus{border-color:#4ade80;outline:none}
.table{border-radius:12px;overflow:hidden;border:1px solid #e5e7eb}
.row{display:flex;align-items:center;padding:12px 16px;border-bottom:1px solid #f3f4f6}
.row:last-child{border-bottom:none}.row:nth-child(even){background:#f9fafb}.row:hover{background:#f0fdf4}
.currency{flex:1;font-size:14px;font-weight:600}.rate{font-size:14px;color:#059669;font-weight:500;font-variant-numeric:tabular-nums}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
.hint{text-align:center;margin-top:12px;color:#9ca3af;font-size:12px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>💱 当日货币汇率</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
let allRates=[];let baseCode='CNY';
const common=['USD','EUR','GBP','JPY','KRW','HKD','TWD','SGD','AUD','CAD','CHF','RUB','THB','MYR','INR','VND'];
function renderTable(keyword){
let list=keyword?allRates.filter(r=>r.currency.toLowerCase().includes(keyword.toLowerCase())):
[...allRates.filter(r=>common.includes(r.currency)),...allRates.filter(r=>!common.includes(r.currency))];
let html='<div class="table">';
list.slice(0,80).forEach((r,i)=>{
html+=`<div class="row"><div class="currency">${r.currency}</div><div class="rate">1 ${baseCode} = ${Number(r.rate).toFixed(4)} ${r.currency}</div></div>`;
});
html+='</div>';
if(list.length>80)html+=`<div class="hint">共 ${list.length} 种货币,搜索查看更多</div>`;
return html;
}
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/exchange-rate?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data||json;
if(!d||!d.rates)throw new Error('暂无汇率数据');
allRates=d.rates;baseCode=d.base_code||'CNY';
let html=`<div class="hero"><h2>💱 ${baseCode} 汇率</h2><p>更新时间:${d.updated||'未知'}</p></div>`;
html+=`<input class="search" placeholder="搜索货币代码,如 USD、EUR..." oninput="filterRates(this.value)">`;
html+=`<div id="table-wrap">${renderTable('')}</div>`;
el.innerHTML=html;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
function filterRates(v){document.getElementById('table-wrap').innerHTML=renderTable(v)}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>必应每日壁纸</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px;text-align:center}
.img-wrap{border-radius:16px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,.1)}
.img-wrap img{width:100%;display:block}
.title{margin-top:16px;font-size:16px;font-weight:600;color:#374151}
.desc{margin-top:6px;font-size:13px;color:#6b7280}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🖼️ 必应每日壁纸</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
const BASE=window.__SIXTY_API_BASE__;
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(BASE+'/v2/bing?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data||json;
let url=typeof d==='string'&&d.startsWith('http')?d:d?.url||d?.image||d?.cover||`${BASE}/v2/bing?encoding=image-proxy`;
let html=`<div class="img-wrap"><img src="${url}" alt="必应壁纸" loading="lazy"></div>`;
if(d?.title)html+=`<div class="title">${d.title}</div>`;
if(d?.copyright||d?.desc)html+=`<div class="desc">${d.copyright||d.desc}</div>`;
el.innerHTML=html;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>摸鱼日历</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.hero{background:linear-gradient(135deg,#0e7490,#06b6d4);border-radius:20px;padding:28px 24px;margin-bottom:16px;color:#fff;text-align:center}
.emoji{font-size:48px;margin-bottom:8px}
.title{font-size:20px;font-weight:700;margin-bottom:4px}
.sub{font-size:13px;opacity:.85}
.quote{background:rgba(255,255,255,.12);border-radius:12px;padding:14px 16px;margin-top:16px;font-size:14px;font-style:italic;line-height:1.7}
.section{background:#fff;border-radius:14px;padding:16px;margin-bottom:10px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
.section-title{font-size:13px;font-weight:700;color:#6b7280;margin-bottom:10px;display:flex;align-items:center;gap:6px}
.progress-label{display:flex;justify-content:space-between;font-size:12px;color:#9ca3af;margin-bottom:4px;margin-top:10px}
.progress-bar{height:8px;background:#f3f4f6;border-radius:4px;overflow:hidden;margin-bottom:4px}
.progress-fill{height:100%;border-radius:4px;transition:width .6s ease}
.cd-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
.cd-item{border-radius:12px;padding:14px;text-align:center}
.cd-num{font-size:28px;font-weight:800;margin-bottom:2px}
.cd-label{font-size:12px;color:#6b7280}
.row{display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid #f9fafb}.row:last-child{border-bottom:none}
.rk{font-size:13px;color:#9ca3af}.rv{font-size:13px;color:#1f2937;font-weight:500}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
@media(max-width:480px){.cd-grid{grid-template-columns:1fr}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🐟 摸鱼日历</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/moyu?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data||json;
if(!d){el.innerHTML='<div class="err">暂无数据</div>';return}
const dt=d.date||{},p=d.progress||{},cd=d.countdown||{},nh=d.nextHoliday||{},nw=d.nextWeekend||{};
let html=`<div class="hero"><div class="emoji">🐟</div><div class="title">摸鱼日历</div><div class="sub">${dt.gregorian||''} ${dt.weekday||''} · 农历${dt.lunar?.monthCN||''}${dt.lunar?.dayCN||''} · ${dt.lunar?.zodiac||''}年</div>${d.moyuQuote?`<div class="quote">"${d.moyuQuote}"</div>`:''}</div>`;
html+='<div class="section"><div class="section-title">⏳ 时间进度</div>';
if(p.week)html+=`<div class="progress-label"><span>本周进度</span><span>${p.week.percentage}%${p.week.passed}/${p.week.total}天)</span></div><div class="progress-bar"><div class="progress-fill" style="width:${p.week.percentage}%;background:linear-gradient(90deg,#4ade80,#22c55e)"></div></div>`;
if(p.month)html+=`<div class="progress-label"><span>本月进度</span><span>${p.month.percentage}%(还剩${p.month.remaining}天)</span></div><div class="progress-bar"><div class="progress-fill" style="width:${p.month.percentage}%;background:linear-gradient(90deg,#60a5fa,#3b82f6)"></div></div>`;
if(p.year)html+=`<div class="progress-label"><span>本年进度</span><span>${p.year.percentage}%(还剩${p.year.remaining}天)</span></div><div class="progress-bar"><div class="progress-fill" style="width:${p.year.percentage}%;background:linear-gradient(90deg,#f472b6,#ec4899)"></div></div>`;
html+='</div>';
html+='<div class="section"><div class="section-title">🎯 倒计时</div><div class="cd-grid">';
html+=`<div class="cd-item" style="background:#f0fdf4"><div class="cd-num" style="color:#16a34a">${cd.toFriday??'-'}</div><div class="cd-label">距周五</div></div>`;
html+=`<div class="cd-item" style="background:#eff6ff"><div class="cd-num" style="color:#2563eb">${cd.toWeekEnd??'-'}</div><div class="cd-label">距周末</div></div>`;
if(nh.name)html+=`<div class="cd-item" style="background:#fef3c7"><div class="cd-num" style="color:#d97706">${nh.until??'-'}</div><div class="cd-label">距${nh.name}${nh.duration}天假)</div></div>`;
html+=`<div class="cd-item" style="background:#fce7f3"><div class="cd-num" style="color:#db2777">${cd.toYearEnd??'-'}</div><div class="cd-label">距年末</div></div>`;
html+='</div></div>';
if(d.today){
html+='<div class="section"><div class="section-title">📋 今日状态</div>';
html+=`<div class="row"><span class="rk">今天是</span><span class="rv">${d.today.isWeekend?'🎉 周末':'💼 工作日'}${d.today.isHoliday&&d.today.holidayName?` · ${d.today.holidayName}`:''}</span></div>`;
if(nw.date)html+=`<div class="row"><span class="rk">下个周末</span><span class="rv">${nw.date} ${nw.weekday}${nw.daysUntil}天后)</span></div>`;
if(nh.name)html+=`<div class="row"><span class="rk">下个假期</span><span class="rv">${nh.name} · ${nh.date}</span></div>`;
html+='</div>';
}
el.innerHTML=html;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>每天60s读懂世界</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}
.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.date{display:flex;align-items:center;gap:6px;font-size:13px;color:#6b7280;padding-bottom:12px;border-bottom:1px solid #e5e7eb;margin-bottom:16px}
.item{display:flex;gap:10px;padding:11px 0;border-bottom:1px solid #f3f4f6}
.item:last-child{border-bottom:none}
.num{flex-shrink:0;width:24px;height:24px;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;margin-top:1px;color:#9ca3af;background:#f3f4f6}
.num.t1{color:#fff;background:#ef4444}.num.t2{color:#fff;background:#f97316}.num.t3{color:#fff;background:#eab308}
.text{flex:1;font-size:14px;line-height:1.7}
.tip{margin-top:20px;padding:14px 16px;border-radius:12px;font-size:13px;line-height:1.6;color:#6b7280;background:#f0fdf4;border:1px solid rgba(34,197,94,.1);font-style:italic}
.cover{margin-top:16px;text-align:center}.cover img{max-width:100%;border-radius:10px;box-shadow:0 2px 10px rgba(0,0,0,.08)}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
@media(max-width:640px){.body{padding:16px 12px 32px}.text{font-size:13px}.header h1{font-size:14px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🌍 每天60s读懂世界</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
const API=window.__SIXTY_API_BASE__+'/v2/60s?encoding=json';
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(API,{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data||json;
let html='';
if(d.date)html+=`<div class="date">🕐 ${d.date} ${d.day_of_week||''}</div>`;
const news=d.news||[];
news.forEach((t,i)=>{
const cls=i===0?'t1':i===1?'t2':i===2?'t3':'';
html+=`<div class="item"><div class="num ${cls}">${i+1}</div><div class="text">${t}</div></div>`;
});
if(d.tip)html+=`<div class="tip">💡 ${d.tip}</div>`;
if(d.image)html+=`<div class="cover"><img src="${d.image}" alt="封面" loading="lazy"></div>`;
el.innerHTML=html||'<div class="err">暂无数据</div>';
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>JS趣味题</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 68px)}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:36px 28px;text-align:center;border:1px solid rgba(34,197,94,.12);position:relative;width:100%}
.quote::before{content:'"';position:absolute;top:10px;left:20px;font-size:60px;color:rgba(34,197,94,.15);font-family:serif;line-height:1}
.quote-text{font-size:18px;line-height:2;color:#374151;font-weight:500}
.quote-src{font-size:12px;color:#9ca3af;margin-top:16px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px;width:100%}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px;width:100%}
@media(max-width:640px){.quote-text{font-size:15px}.quote{padding:28px 20px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>💻 JS趣味题</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/awesome-js?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
let text='',source='';
if(typeof d==='string'){text=d}
else if(d&&typeof d==='object'){
for(const k of['content','text','hitokoto','duanzi','joke','saying','answer','kfc','data']){if(typeof d[k]==='string'){text=d[k];break}}
if(!text){for(const v of Object.values(d)){if(typeof v==='string'&&v.length>5){text=v;break}}}
if(!text)text=JSON.stringify(d,null,2);
source=d.from||d.source||d.author||'';
}else{text=String(d??'')}
el.innerHTML=`<div class="quote"><div class="quote-text">${text}</div>${source?`<div class="quote-src">—— ${source}</div>`:''}</div>`;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>今日运势</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 68px)}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:36px 28px;text-align:center;border:1px solid rgba(34,197,94,.12);position:relative;width:100%}
.quote::before{content:'"';position:absolute;top:10px;left:20px;font-size:60px;color:rgba(34,197,94,.15);font-family:serif;line-height:1}
.quote-text{font-size:18px;line-height:2;color:#374151;font-weight:500}
.quote-src{font-size:12px;color:#9ca3af;margin-top:16px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px;width:100%}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px;width:100%}
@media(max-width:640px){.quote-text{font-size:15px}.quote{padding:28px 20px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>⭐ 今日运势</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/luck?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
let text='',source='';
if(typeof d==='string'){text=d}
else if(d&&typeof d==='object'){
for(const k of['content','text','hitokoto','duanzi','joke','saying','answer','kfc','data']){if(typeof d[k]==='string'){text=d[k];break}}
if(!text){for(const v of Object.values(d)){if(typeof v==='string'&&v.length>5){text=v;break}}}
if(!text)text=JSON.stringify(d,null,2);
source=d.from||d.source||d.author||'';
}else{text=String(d??'')}
el.innerHTML=`<div class="quote"><div class="quote-text">${text}</div>${source?`<div class="quote-src">—— ${source}</div>`:''}</div>`;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>发病文学</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.form{display:flex;flex-direction:column;gap:10px;margin-bottom:20px;background:#fff;border-radius:16px;padding:20px;box-shadow:0 1px 4px rgba(0,0,0,.05)}
.form label{font-size:12px;font-weight:600;color:#6b7280}
.form input{padding:11px 14px;border:2px solid #e5e7eb;border-radius:10px;font-size:13px;font-family:inherit;transition:border-color .2s}
.form input:focus{border-color:#4ade80;outline:none}
.form button{display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:11px 22px;border:none;border-radius:10px;background:linear-gradient(135deg,#4ade80,#22c55e);color:#fff;font-size:13px;font-weight:600;cursor:pointer;transition:all .2s}
.form button:hover{transform:translateY(-1px)}.form button:disabled{opacity:.5;cursor:not-allowed;transform:none}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:36px 28px;text-align:center;border:1px solid rgba(34,197,94,.12);position:relative}
.quote::before{content:'"';position:absolute;top:10px;left:20px;font-size:60px;color:rgba(34,197,94,.15);font-family:serif;line-height:1}
.quote-text{font-size:16px;line-height:2;color:#374151;font-weight:500}
.loader{display:flex;flex-direction:column;align-items:center;padding:40px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:20px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>📖 发病文学</h1>
</div>
<div class="body">
<div class="form">
<label>对象名</label>
<input id="nameInput" placeholder="输入名字" onkeydown="if(event.key==='Enter')query()">
<button onclick="query()" id="submitBtn">🔍 生成</button>
</div>
<div id="result"></div>
</div>
<script>
async function query(){
const name=document.getElementById('nameInput').value.trim();
if(!name){document.getElementById('result').innerHTML='<div class="err">请输入名字</div>';return}
const el=document.getElementById('result');
const btn=document.getElementById('submitBtn');
btn.disabled=true;btn.textContent='生成中...';
el.innerHTML='<div class="loader"><div class="spinner"></div><span>生成中...</span></div>';
try{
const res=await fetch(`${window.__SIXTY_API_BASE__}/v2/fabing?encoding=json&name=${encodeURIComponent(name)}`,{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
const text=typeof d==='string'?d:d?.content||d?.text||JSON.stringify(d);
el.innerHTML=`<div class="quote"><div class="quote-text">${text}</div></div>`;
}catch(e){el.innerHTML=`<div class="err">生成失败:${e.message}</div>`}
finally{btn.disabled=false;btn.textContent='🔍 生成'}
}
</script>
</body>
</html>

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>疯狂星期四</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 68px)}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:36px 28px;text-align:center;border:1px solid rgba(34,197,94,.12);position:relative;width:100%}
.quote::before{content:'"';position:absolute;top:10px;left:20px;font-size:60px;color:rgba(34,197,94,.15);font-family:serif;line-height:1}
.quote-text{font-size:18px;line-height:2;color:#374151;font-weight:500}
.quote-src{font-size:12px;color:#9ca3af;margin-top:16px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px;width:100%}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px;width:100%}
@media(max-width:640px){.quote-text{font-size:15px}.quote{padding:28px 20px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🍗 疯狂星期四</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/kfc?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
let text='',source='';
if(typeof d==='string'){text=d}
else if(d&&typeof d==='object'){
for(const k of['content','text','hitokoto','duanzi','joke','saying','answer','kfc','data']){if(typeof d[k]==='string'){text=d[k];break}}
if(!text){for(const v of Object.values(d)){if(typeof v==='string'&&v.length>5){text=v;break}}}
if(!text)text=JSON.stringify(d,null,2);
source=d.from||d.source||d.author||'';
}else{text=String(d??'')}
el.innerHTML=`<div class="quote"><div class="quote-text">${text}</div>${source?`<div class="quote-src">—— ${source}</div>`:''}</div>`;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>答案之书</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 68px)}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:36px 28px;text-align:center;border:1px solid rgba(34,197,94,.12);position:relative;width:100%}
.quote::before{content:'"';position:absolute;top:10px;left:20px;font-size:60px;color:rgba(34,197,94,.15);font-family:serif;line-height:1}
.quote-text{font-size:18px;line-height:2;color:#374151;font-weight:500}
.quote-src{font-size:12px;color:#9ca3af;margin-top:16px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px;width:100%}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px;width:100%}
@media(max-width:640px){.quote-text{font-size:15px}.quote{padding:28px 20px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>📘 答案之书</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/answer?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
let text='',source='';
if(typeof d==='string'){text=d}
else if(d&&typeof d==='object'){
for(const k of['content','text','hitokoto','duanzi','joke','saying','answer','kfc','data']){if(typeof d[k]==='string'){text=d[k];break}}
if(!text){for(const v of Object.values(d)){if(typeof v==='string'&&v.length>5){text=v;break}}}
if(!text)text=JSON.stringify(d,null,2);
source=d.from||d.source||d.author||'';
}else{text=String(d??'')}
el.innerHTML=`<div class="quote"><div class="quote-text">${text}</div>${source?`<div class="quote-src">—— ${source}</div>`:''}</div>`;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>英文冷笑话</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 68px)}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:36px 28px;text-align:center;border:1px solid rgba(34,197,94,.12);position:relative;width:100%}
.quote::before{content:'"';position:absolute;top:10px;left:20px;font-size:60px;color:rgba(34,197,94,.15);font-family:serif;line-height:1}
.quote-text{font-size:18px;line-height:2;color:#374151;font-weight:500}
.quote-src{font-size:12px;color:#9ca3af;margin-top:16px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px;width:100%}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px;width:100%}
@media(max-width:640px){.quote-text{font-size:15px}.quote{padding:28px 20px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>😄 英文冷笑话</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/dad-joke?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
let text='',source='';
if(typeof d==='string'){text=d}
else if(d&&typeof d==='object'){
for(const k of['content','text','hitokoto','duanzi','joke','saying','answer','kfc','data']){if(typeof d[k]==='string'){text=d[k];break}}
if(!text){for(const v of Object.values(d)){if(typeof v==='string'&&v.length>5){text=v;break}}}
if(!text)text=JSON.stringify(d,null,2);
source=d.from||d.source||d.author||'';
}else{text=String(d??'')}
el.innerHTML=`<div class="quote"><div class="quote-text">${text}</div>${source?`<div class="quote-src">—— ${source}</div>`:''}</div>`;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -1,190 +0,0 @@
/* 背景样式文件 */
/* 主体背景 */
body {
background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 50%, #a5d6a7 100%);
background-attachment: fixed;
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
}
/* 背景动画 */
@keyframes gradientShift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
/* 装饰性背景元素 */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
radial-gradient(circle at 20% 80%, rgba(76, 175, 80, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(129, 199, 132, 0.1) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(165, 214, 167, 0.08) 0%, transparent 50%);
pointer-events: none;
z-index: -1;
}
/* 浮动装饰圆点 */
body::after {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
radial-gradient(2px 2px at 20px 30px, rgba(76, 175, 80, 0.3), transparent),
radial-gradient(2px 2px at 40px 70px, rgba(129, 199, 132, 0.2), transparent),
radial-gradient(1px 1px at 90px 40px, rgba(165, 214, 167, 0.3), transparent),
radial-gradient(1px 1px at 130px 80px, rgba(76, 175, 80, 0.2), transparent),
radial-gradient(2px 2px at 160px 30px, rgba(129, 199, 132, 0.3), transparent);
background-repeat: repeat;
background-size: 200px 100px;
animation: float 20s linear infinite;
pointer-events: none;
z-index: -1;
opacity: 0.6;
}
@keyframes float {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
100% {
transform: translateY(0px);
}
}
/* 题目容器背景增强 */
.question-container {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow:
0 8px 32px rgba(26, 77, 26, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
/* 错误容器背景 */
.error-container {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
/* 结果容器背景 */
.result-container {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
}
/* 代码块背景 */
.code-block {
background: rgba(248, 249, 250, 0.9);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
}
/* 选项背景 */
.option {
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
}
.option:hover {
background: rgba(76, 175, 80, 0.05);
}
.option.selected {
background: linear-gradient(135deg, rgba(76, 175, 80, 0.15), rgba(76, 175, 80, 0.08));
}
/* 按钮背景增强 */
.submit-btn {
background: linear-gradient(135deg, #4caf50, #45a049);
box-shadow: 0 4px 15px rgba(76, 175, 80, 0.2);
}
.show-answer-btn {
background: linear-gradient(135deg, #2196f3, #1976d2);
box-shadow: 0 4px 15px rgba(33, 150, 243, 0.2);
}
.retry-btn {
background: linear-gradient(135deg, #ff9800, #f57c00);
box-shadow: 0 4px 15px rgba(255, 152, 0, 0.2);
}
.refresh-btn {
background: linear-gradient(135deg, #4caf50, #45a049);
box-shadow: 0 4px 15px rgba(76, 175, 80, 0.2);
}
/* 移动端背景优化 */
@media (max-width: 768px) {
body {
background-attachment: scroll;
}
body::after {
opacity: 0.4;
background-size: 150px 75px;
}
.question-container {
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
}
/* 高对比度模式支持 */
@media (prefers-contrast: high) {
body {
background: #f0f8f0;
}
body::before,
body::after {
display: none;
}
.question-container {
background: #ffffff;
border: 2px solid #4caf50;
}
}
/* 减少动画模式支持 */
@media (prefers-reduced-motion: reduce) {
body {
animation: none;
background: #e8f5e8;
}
body::after {
animation: none;
}
.refresh-btn:hover {
transform: scale(1.1);
}
}

View File

@@ -1,597 +0,0 @@
/* 基础样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
line-height: 1.6;
color: #2d5a27;
min-height: 100vh;
overflow-x: hidden;
}
/* 容器布局 */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* 头部样式 */
.header {
text-align: center;
margin-bottom: 40px;
padding: 30px 0;
}
.header h1 {
font-size: 2.5rem;
color: #1a4d1a;
margin-bottom: 10px;
font-weight: 700;
text-shadow: 0 2px 4px rgba(26, 77, 26, 0.1);
}
.subtitle {
font-size: 1.1rem;
color: #4a7c59;
opacity: 0.8;
}
/* 主内容区域 */
.main-content {
flex: 1;
display: flex;
justify-content: center;
align-items: flex-start;
}
/* 加载动画 */
.loading {
text-align: center;
padding: 60px 20px;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid #e8f5e8;
border-top: 4px solid #4caf50;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading p {
color: #4a7c59;
font-size: 1.1rem;
}
/* 题目容器 */
.question-container {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
padding: 40px;
box-shadow: 0 10px 30px rgba(26, 77, 26, 0.1);
border: 2px solid rgba(76, 175, 80, 0.2);
width: 100%;
max-width: 800px;
backdrop-filter: blur(10px);
}
/* 题目头部 */
.question-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding-bottom: 15px;
border-bottom: 2px solid #e8f5e8;
}
.question-id {
font-size: 1.1rem;
color: #4caf50;
font-weight: 600;
background: linear-gradient(135deg, #e8f5e8, #c8e6c9);
padding: 8px 16px;
border-radius: 20px;
}
.refresh-btn {
background: linear-gradient(135deg, #4caf50, #45a049);
border: none;
border-radius: 50%;
width: 45px;
height: 45px;
color: white;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.refresh-btn:hover {
transform: rotate(180deg) scale(1.1);
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.3);
}
/* 题目文本 */
.question-text h2 {
font-size: 1.5rem;
color: #1a4d1a;
margin-bottom: 25px;
text-align: center;
}
/* 代码块 */
.code-block {
background: #f8f9fa;
border: 2px solid #e8f5e8;
border-radius: 12px;
margin: 25px 0;
overflow-x: auto;
position: relative;
}
.code-block pre {
margin: 0;
padding: 25px;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 0.95rem;
line-height: 1.5;
color: #2d5a27;
white-space: pre-wrap;
word-wrap: break-word;
background: transparent !important;
}
.code-block code {
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
background: transparent !important;
}
/* 代码高亮自定义样式 - 丰富的语法高亮 */
.code-block .hljs {
background: transparent !important;
color: #333333 !important;
}
/* JavaScript 关键字 - 蓝色 */
.code-block .hljs-keyword {
color: #0066cc !important;
font-weight: 600;
}
/* 字符串 - 绿色 */
.code-block .hljs-string {
color: #22aa22 !important;
}
/* 数字 - 橙色 */
.code-block .hljs-number {
color: #ff6600 !important;
}
/* 函数名 - 紫色 */
.code-block .hljs-function,
.code-block .hljs-title.function_ {
color: #9933cc !important;
font-weight: 600;
}
/* 变量名 - 深蓝色 */
.code-block .hljs-variable,
.code-block .hljs-name {
color: #0066aa !important;
}
/* 注释 - 灰色 */
.code-block .hljs-comment {
color: #888888 !important;
font-style: italic;
}
/* 内置对象和方法 - 深紫色 */
.code-block .hljs-built_in {
color: #663399 !important;
font-weight: 500;
}
/* 字面量 (true, false, null) - 红色 */
.code-block .hljs-literal {
color: #cc0000 !important;
font-weight: 600;
}
/* 操作符 - 深灰色 */
.code-block .hljs-operator {
color: #666666 !important;
}
/* 标点符号 - 深灰色 */
.code-block .hljs-punctuation {
color: #666666 !important;
}
/* 属性名 - 深蓝色 */
.code-block .hljs-property,
.code-block .hljs-attr {
color: #0066aa !important;
}
/* 类名和构造函数 - 深绿色 */
.code-block .hljs-title.class_,
.code-block .hljs-title {
color: #228833 !important;
font-weight: 600;
}
/* 参数 - 深蓝色 */
.code-block .hljs-params {
color: #0066aa !important;
}
/* 正则表达式 - 深红色 */
.code-block .hljs-regexp {
color: #aa0066 !important;
}
/* 模板字符串 - 深绿色 */
.code-block .hljs-template-variable,
.code-block .hljs-template-tag {
color: #228833 !important;
}
/* 选项容器 */
.options-container {
margin: 30px 0;
}
.option {
background: rgba(255, 255, 255, 0.8);
border: 2px solid #e8f5e8;
border-radius: 12px;
padding: 15px 20px;
margin: 12px 0;
cursor: pointer;
transition: all 0.3s ease;
font-size: 1rem;
position: relative;
overflow: hidden;
}
.option:hover {
border-color: #4caf50;
background: rgba(76, 175, 80, 0.05);
transform: translateX(5px);
}
.option.selected {
border-color: #4caf50;
background: linear-gradient(135deg, rgba(76, 175, 80, 0.1), rgba(76, 175, 80, 0.05));
color: #1a4d1a;
font-weight: 600;
}
.option.correct {
border-color: #4caf50;
background: linear-gradient(135deg, rgba(76, 175, 80, 0.2), rgba(76, 175, 80, 0.1));
color: #1a4d1a;
}
.option.incorrect {
border-color: #f44336;
background: linear-gradient(135deg, rgba(244, 67, 54, 0.1), rgba(244, 67, 54, 0.05));
color: #c62828;
}
/* 按钮样式 */
.action-buttons {
display: flex;
gap: 15px;
margin: 30px 0;
justify-content: center;
flex-wrap: wrap;
}
.submit-btn, .show-answer-btn, .retry-btn, .export-btn {
padding: 12px 30px;
border: none;
border-radius: 25px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
min-width: 120px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.submit-btn {
background: linear-gradient(135deg, #4caf50, #45a049);
color: white;
}
.submit-btn:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.3);
}
.submit-btn:disabled {
background: #cccccc;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.show-answer-btn {
background: linear-gradient(135deg, #2196f3, #1976d2);
color: white;
}
.show-answer-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(33, 150, 243, 0.3);
}
.retry-btn {
background: linear-gradient(135deg, #ff9800, #f57c00);
color: white;
}
.retry-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(255, 152, 0, 0.3);
}
.export-btn {
background: linear-gradient(135deg, #9c27b0, #7b1fa2);
color: white;
}
.export-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(156, 39, 176, 0.3);
}
.export-btn svg {
width: 16px;
height: 16px;
}
/* 结果容器 */
.result-container {
margin-top: 30px;
padding: 25px;
background: rgba(255, 255, 255, 0.9);
border-radius: 15px;
border: 2px solid #e8f5e8;
}
.result-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #e8f5e8;
}
.result-status {
font-size: 1.2rem;
font-weight: 600;
}
.result-status.correct {
color: #4caf50;
}
.result-status.incorrect {
color: #f44336;
}
.correct-answer {
font-weight: 600;
color: #4caf50;
background: rgba(76, 175, 80, 0.1);
padding: 5px 12px;
border-radius: 15px;
}
.explanation {
color: #2d5a27;
line-height: 1.7;
font-size: 1rem;
}
.explanation pre {
background: #f8f9fa;
border: 1px solid #e8f5e8;
border-radius: 8px;
padding: 15px;
margin: 15px 0;
overflow-x: auto;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
}
/* 错误容器 */
.error-container {
text-align: center;
padding: 60px 20px;
background: rgba(255, 255, 255, 0.9);
border-radius: 20px;
border: 2px solid rgba(244, 67, 54, 0.2);
max-width: 500px;
margin: 0 auto;
}
.error-icon {
font-size: 3rem;
margin-bottom: 20px;
}
.error-container h3 {
color: #f44336;
margin-bottom: 15px;
font-size: 1.5rem;
}
.error-container p {
color: #666;
margin-bottom: 25px;
font-size: 1.1rem;
}
/* 底部 */
.footer {
text-align: center;
padding: 30px 0;
margin-top: 40px;
color: #4a7c59;
opacity: 0.7;
border-top: 1px solid rgba(76, 175, 80, 0.2);
}
/* 平板端适配 (768px - 1024px) */
@media (max-width: 1024px) and (min-width: 768px) {
.container {
padding: 15px;
}
.header h1 {
font-size: 2.2rem;
}
.question-container {
padding: 30px;
}
.action-buttons {
flex-wrap: wrap;
}
}
/* 手机端适配 (最大768px) */
@media (max-width: 768px) {
.container {
padding: 10px;
}
.header {
margin-bottom: 25px;
padding: 20px 0;
}
.header h1 {
font-size: 1.8rem;
}
.subtitle {
font-size: 1rem;
}
.question-container {
padding: 20px;
border-radius: 15px;
}
.question-header {
flex-direction: column;
gap: 15px;
text-align: center;
}
.question-text h2 {
font-size: 1.3rem;
}
.code-block pre {
padding: 15px;
font-size: 0.85rem;
}
.option {
padding: 12px 15px;
font-size: 0.95rem;
}
.action-buttons {
flex-direction: column;
align-items: center;
}
.submit-btn, .show-answer-btn, .retry-btn {
width: 100%;
max-width: 200px;
}
.result-header {
flex-direction: column;
gap: 10px;
text-align: center;
}
.explanation {
font-size: 0.95rem;
}
.explanation pre {
padding: 10px;
font-size: 0.8rem;
}
}
/* 小屏手机适配 (最大480px) */
@media (max-width: 480px) {
.container {
padding: 8px;
}
.header h1 {
font-size: 1.6rem;
}
.question-container {
padding: 15px;
}
.question-id {
font-size: 1rem;
padding: 6px 12px;
}
.refresh-btn {
width: 40px;
height: 40px;
}
.code-block pre {
font-size: 0.8rem;
padding: 12px;
}
.option {
padding: 10px 12px;
font-size: 0.9rem;
}
.submit-btn, .show-answer-btn, .retry-btn {
padding: 10px 20px;
font-size: 0.95rem;
}
}

View File

@@ -1,91 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>随机JavaScript趣味题</title>
<link rel="preconnect" href="https://cdnjs.cloudflare.com">
<link rel="dns-prefetch" href="https://60s.api.shumengya.top">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/background.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/javascript.min.js"></script>
</head>
<body>
<div class="container">
<header class="header">
<h1>JavaScript趣味题</h1>
<p class="subtitle">测试你的JavaScript知识</p>
</header>
<main class="main-content">
<div class="loading" id="loading">
<div class="spinner"></div>
<p>正在加载题目...</p>
</div>
<div class="question-container" id="questionContainer" style="display: none;">
<div class="question-header">
<span class="question-id" id="questionId">题目 #1</span>
<button class="refresh-btn" id="refreshBtn" title="获取新题目">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="23 4 23 10 17 10"></polyline>
<polyline points="1 20 1 14 7 14"></polyline>
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path>
</svg>
</button>
</div>
<div class="question-text" id="questionText">
<h2>输出是什么?</h2>
</div>
<div class="code-block" id="codeBlock">
<pre><code id="codeContent" class="language-javascript"></code></pre>
</div>
<div class="options-container" id="optionsContainer">
<!-- 选项将通过JavaScript动态生成 -->
</div>
<div class="action-buttons">
<button class="submit-btn" id="submitBtn" disabled>提交答案</button>
<button class="show-answer-btn" id="showAnswerBtn">查看答案</button>
<button class="export-btn" id="exportBtn" title="导出为Markdown文件">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="7 10 12 15 17 10"></polyline>
<line x1="12" y1="15" x2="12" y2="3"></line>
</svg>
导出MD
</button>
</div>
<div class="result-container" id="resultContainer" style="display: none;">
<div class="result-header">
<span class="result-status" id="resultStatus"></span>
<span class="correct-answer" id="correctAnswer"></span>
</div>
<div class="explanation" id="explanation">
<!-- 解析内容 -->
</div>
</div>
</div>
<div class="error-container" id="errorContainer" style="display: none;">
<div class="error-icon">⚠️</div>
<h3>加载失败</h3>
<p id="errorMessage">网络连接异常,请稍后重试</p>
<button class="retry-btn" id="retryBtn">重新加载</button>
</div>
</main>
<footer class="footer">
<p>JavaScript趣味题集合</p>
</footer>
</div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -1,582 +0,0 @@
// JavaScript趣味题应用
class JSQuizApp {
constructor() {
this.apiEndpoints = [
'https://60s.api.shumengya.top',
];
this.currentApiIndex = 0;
this.currentQuestion = null;
this.selectedOption = null;
this.isAnswered = false;
this.loadStartTime = null;
this.initElements();
this.bindEvents();
this.preloadResources();
this.loadQuestion();
}
// 初始化DOM元素
initElements() {
this.elements = {
loading: document.getElementById('loading'),
questionContainer: document.getElementById('questionContainer'),
errorContainer: document.getElementById('errorContainer'),
questionId: document.getElementById('questionId'),
questionText: document.getElementById('questionText'),
codeContent: document.getElementById('codeContent'),
optionsContainer: document.getElementById('optionsContainer'),
submitBtn: document.getElementById('submitBtn'),
showAnswerBtn: document.getElementById('showAnswerBtn'),
refreshBtn: document.getElementById('refreshBtn'),
retryBtn: document.getElementById('retryBtn'),
exportBtn: document.getElementById('exportBtn'),
resultContainer: document.getElementById('resultContainer'),
resultStatus: document.getElementById('resultStatus'),
correctAnswer: document.getElementById('correctAnswer'),
explanation: document.getElementById('explanation'),
errorMessage: document.getElementById('errorMessage')
};
}
// 预加载资源
preloadResources() {
// 预连接API服务器
this.apiEndpoints.forEach(endpoint => {
const link = document.createElement('link');
link.rel = 'preconnect';
link.href = endpoint;
document.head.appendChild(link);
});
}
// 绑定事件
bindEvents() {
this.elements.submitBtn.addEventListener('click', () => this.submitAnswer());
this.elements.showAnswerBtn.addEventListener('click', () => this.showAnswer());
this.elements.refreshBtn.addEventListener('click', () => this.loadQuestion());
this.elements.retryBtn.addEventListener('click', () => this.loadQuestion());
this.elements.exportBtn.addEventListener('click', () => this.exportToMarkdown());
}
// 显示加载状态
showLoading() {
this.elements.loading.style.display = 'block';
this.elements.questionContainer.style.display = 'none';
this.elements.errorContainer.style.display = 'none';
}
// 显示题目
showQuestion() {
this.elements.loading.style.display = 'none';
this.elements.questionContainer.style.display = 'block';
this.elements.errorContainer.style.display = 'none';
}
// 显示错误
showError(message) {
this.elements.loading.style.display = 'none';
this.elements.questionContainer.style.display = 'none';
this.elements.errorContainer.style.display = 'block';
this.elements.errorMessage.textContent = message;
}
// 获取当前API地址
getCurrentApiUrl() {
return `${this.apiEndpoints[this.currentApiIndex]}/v2/awesome-js`;
}
// 切换到下一个API
switchToNextApi() {
this.currentApiIndex = (this.currentApiIndex + 1) % this.apiEndpoints.length;
}
// 加载题目
async loadQuestion() {
this.loadStartTime = Date.now();
this.showLoading();
this.resetQuestion();
let attempts = 0;
const maxAttempts = this.apiEndpoints.length;
while (attempts < maxAttempts) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch(this.getCurrentApiUrl(), {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
if (data.code === 200 && data.data) {
this.currentQuestion = data.data;
const loadTime = Date.now() - this.loadStartTime;
console.log(`题目加载完成,耗时: ${loadTime}ms`);
this.displayQuestion();
return;
} else {
throw new Error(data.message || '数据格式错误');
}
} catch (error) {
console.warn(`API ${this.getCurrentApiUrl()} 请求失败:`, error.message);
attempts++;
if (attempts < maxAttempts) {
this.switchToNextApi();
console.log(`切换到备用API: ${this.getCurrentApiUrl()}`);
} else {
this.showError(`所有API接口都无法访问请检查网络连接后重试。\n最后尝试的错误: ${error.message}`);
return;
}
}
}
}
// 重置题目状态
resetQuestion() {
this.selectedOption = null;
this.isAnswered = false;
this.elements.resultContainer.style.display = 'none';
this.elements.submitBtn.disabled = true;
this.elements.submitBtn.textContent = '提交答案';
this.elements.showAnswerBtn.style.display = 'inline-block';
// 清空选项容器,防止重复显示
this.elements.optionsContainer.innerHTML = '';
// 移除所有选项的事件监听器
const existingOptions = document.querySelectorAll('.option');
existingOptions.forEach(option => {
option.removeEventListener('click', this.selectOption);
});
}
// 显示题目内容
displayQuestion() {
const question = this.currentQuestion;
console.log('显示题目:', question);
// 设置题目ID
this.elements.questionId.textContent = `题目 #${question.id}`;
// 设置题目文本
this.elements.questionText.innerHTML = `<h2>${this.escapeHtml(question.question)}</h2>`;
// 设置代码内容并应用语法高亮
this.elements.codeContent.textContent = question.code;
// 应用语法高亮
if (typeof hljs !== 'undefined') {
hljs.highlightElement(this.elements.codeContent);
}
// 确保选项容器已清空
this.elements.optionsContainer.innerHTML = '';
// 生成选项
this.generateOptions(question.options);
this.showQuestion();
}
// 生成选项
generateOptions(options) {
// 确保清空容器
this.elements.optionsContainer.innerHTML = '';
// 验证选项数据
if (!Array.isArray(options) || options.length === 0) {
console.error('选项数据无效:', options);
return;
}
// 移除可能存在的重复选项
const uniqueOptions = [...new Set(options)];
uniqueOptions.forEach((option, index) => {
const optionElement = document.createElement('div');
optionElement.className = 'option';
optionElement.textContent = option;
optionElement.dataset.index = index;
optionElement.dataset.value = option.charAt(0); // A, B, C, D
optionElement.addEventListener('click', () => this.selectOption(optionElement));
this.elements.optionsContainer.appendChild(optionElement);
});
console.log('生成选项:', uniqueOptions);
}
// 选择选项
selectOption(optionElement) {
if (this.isAnswered) return;
// 移除之前的选中状态
document.querySelectorAll('.option.selected').forEach(el => {
el.classList.remove('selected');
});
// 设置当前选中
optionElement.classList.add('selected');
this.selectedOption = optionElement.dataset.value;
// 启用提交按钮
this.elements.submitBtn.disabled = false;
}
// 提交答案
submitAnswer() {
if (!this.selectedOption || this.isAnswered) return;
this.isAnswered = true;
this.elements.submitBtn.disabled = true;
this.elements.submitBtn.textContent = '已提交';
this.elements.showAnswerBtn.style.display = 'none';
const isCorrect = this.selectedOption === this.currentQuestion.answer;
// 显示结果
this.showResult(isCorrect);
// 标记选项
this.markOptions();
}
// 显示答案
showAnswer() {
this.isAnswered = true;
this.elements.submitBtn.disabled = true;
this.elements.submitBtn.textContent = '已显示答案';
this.elements.showAnswerBtn.style.display = 'none';
// 显示结果(不判断对错)
this.showResult(null);
// 标记正确答案
this.markCorrectAnswer();
}
// 显示结果
showResult(isCorrect) {
const resultContainer = this.elements.resultContainer;
const resultStatus = this.elements.resultStatus;
const correctAnswer = this.elements.correctAnswer;
const explanation = this.elements.explanation;
// 设置结果状态
if (isCorrect === true) {
resultStatus.textContent = '✅ 回答正确!';
resultStatus.className = 'result-status correct';
} else if (isCorrect === false) {
resultStatus.textContent = '❌ 回答错误';
resultStatus.className = 'result-status incorrect';
} else {
resultStatus.textContent = '💡 答案解析';
resultStatus.className = 'result-status';
}
// 设置正确答案
correctAnswer.textContent = `正确答案: ${this.currentQuestion.answer}`;
// 设置解析内容
explanation.innerHTML = this.formatExplanation(this.currentQuestion.explanation);
// 显示结果容器
resultContainer.style.display = 'block';
// 滚动到结果区域
setTimeout(() => {
resultContainer.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}, 100);
}
// 标记选项
markOptions() {
const options = document.querySelectorAll('.option');
const correctAnswer = this.currentQuestion.answer;
options.forEach(option => {
const optionValue = option.dataset.value;
if (optionValue === correctAnswer) {
option.classList.add('correct');
} else if (option.classList.contains('selected')) {
option.classList.add('incorrect');
}
// 禁用点击
option.style.pointerEvents = 'none';
});
}
// 标记正确答案
markCorrectAnswer() {
const options = document.querySelectorAll('.option');
const correctAnswer = this.currentQuestion.answer;
options.forEach(option => {
const optionValue = option.dataset.value;
if (optionValue === correctAnswer) {
option.classList.add('correct');
}
// 禁用点击
option.style.pointerEvents = 'none';
});
}
// 格式化解析内容
formatExplanation(explanation) {
// 转义HTML
let formatted = this.escapeHtml(explanation);
// 处理代码块
formatted = formatted.replace(/```js\n([\s\S]*?)\n```/g, '<pre><code>$1</code></pre>');
formatted = formatted.replace(/```javascript\n([\s\S]*?)\n```/g, '<pre><code>$1</code></pre>');
formatted = formatted.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>');
// 处理行内代码
formatted = formatted.replace(/`([^`]+)`/g, '<code style="background: #f0f0f0; padding: 2px 4px; border-radius: 3px; font-family: monospace;">$1</code>');
// 处理换行
formatted = formatted.replace(/\n\n/g, '</p><p>');
formatted = formatted.replace(/\n/g, '<br>');
// 包装段落
if (!formatted.includes('<p>')) {
formatted = '<p>' + formatted + '</p>';
}
return formatted;
}
// HTML转义
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 导出为Markdown
exportToMarkdown() {
if (!this.currentQuestion) {
alert('请先加载题目后再导出!');
return;
}
const question = this.currentQuestion;
const timestamp = new Date().toLocaleString('zh-CN');
// 构建Markdown内容
let markdown = `# JavaScript趣味题 #${question.id}\n\n`;
markdown += `> 导出时间: ${timestamp}\n\n`;
// 题目部分
markdown += `## 题目\n\n`;
markdown += `${question.question}\n\n`;
// 代码部分
markdown += `## 代码\n\n`;
markdown += `\`\`\`javascript\n${question.code}\n\`\`\`\n\n`;
// 选项部分
markdown += `## 选项\n\n`;
question.options.forEach((option, index) => {
const letter = String.fromCharCode(65 + index); // A, B, C, D
const isCorrect = letter === question.answer;
markdown += `${letter}. ${option}${isCorrect ? ' ✅' : ''}\n`;
});
markdown += `\n`;
// 答案部分
markdown += `## 正确答案\n\n`;
markdown += `**${question.answer}**\n\n`;
// 解析部分
markdown += `## 答案解析\n\n`;
// 清理解析内容中的HTML标签转换为Markdown格式
let explanation = question.explanation;
explanation = explanation.replace(/<br\s*\/?>/gi, '\n');
explanation = explanation.replace(/<p>/gi, '\n');
explanation = explanation.replace(/<\/p>/gi, '\n');
explanation = explanation.replace(/<code[^>]*>/gi, '`');
explanation = explanation.replace(/<\/code>/gi, '`');
explanation = explanation.replace(/<pre><code>/gi, '\n```javascript\n');
explanation = explanation.replace(/<\/code><\/pre>/gi, '\n```\n');
explanation = explanation.replace(/<[^>]*>/g, ''); // 移除其他HTML标签
explanation = explanation.replace(/\n\s*\n/g, '\n\n'); // 清理多余空行
markdown += explanation.trim() + '\n\n';
// 添加页脚
markdown += `---\n\n`;
markdown += `*本题目来源于JavaScript趣味题集合*\n`;
markdown += `*导出工具: JavaScript趣味题网页版*\n`;
// 创建下载
this.downloadMarkdown(markdown, `JavaScript趣味题_${question.id}_${new Date().getTime()}.md`);
}
// 下载Markdown文件
downloadMarkdown(content, filename) {
const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 清理URL对象
setTimeout(() => {
URL.revokeObjectURL(url);
}, 100);
// 显示成功提示
this.showExportSuccess(filename);
}
// 显示导出成功提示
showExportSuccess(filename) {
// 创建临时提示元素
const toast = document.createElement('div');
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: linear-gradient(135deg, #4caf50, #45a049);
color: white;
padding: 15px 20px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);
z-index: 10000;
font-size: 14px;
max-width: 300px;
word-wrap: break-word;
animation: slideInRight 0.3s ease-out;
`;
toast.innerHTML = `
<div style="display: flex; align-items: center; gap: 8px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
<div>
<div style="font-weight: 600;">导出成功!</div>
<div style="font-size: 12px; opacity: 0.9; margin-top: 2px;">${filename}</div>
</div>
</div>
`;
// 添加动画样式
const style = document.createElement('style');
style.textContent = `
@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOutRight {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
`;
document.head.appendChild(style);
document.body.appendChild(toast);
// 3秒后自动消失
setTimeout(() => {
toast.style.animation = 'slideOutRight 0.3s ease-in';
setTimeout(() => {
if (toast.parentNode) {
document.body.removeChild(toast);
}
if (style.parentNode) {
document.head.removeChild(style);
}
}, 300);
}, 3000);
}
}
// 页面加载完成后初始化应用
document.addEventListener('DOMContentLoaded', () => {
new JSQuizApp();
});
// 添加键盘快捷键支持
document.addEventListener('keydown', (e) => {
// 按R键刷新题目
if (e.key.toLowerCase() === 'r' && !e.ctrlKey && !e.metaKey) {
const refreshBtn = document.getElementById('refreshBtn');
if (refreshBtn && !document.querySelector('.loading').style.display !== 'none') {
refreshBtn.click();
}
}
// 按数字键1-4选择选项
if (['1', '2', '3', '4'].includes(e.key)) {
const options = document.querySelectorAll('.option');
const index = parseInt(e.key) - 1;
if (options[index] && !options[index].style.pointerEvents) {
options[index].click();
}
}
// 按Enter键提交答案
if (e.key === 'Enter') {
const submitBtn = document.getElementById('submitBtn');
if (submitBtn && !submitBtn.disabled) {
submitBtn.click();
}
}
});
// 添加触摸设备支持
if ('ontouchstart' in window) {
document.addEventListener('touchstart', () => {}, { passive: true });
}
// 添加网络状态监听
if ('navigator' in window && 'onLine' in navigator) {
window.addEventListener('online', () => {
console.log('网络连接已恢复');
});
window.addEventListener('offline', () => {
console.log('网络连接已断开');
});
}

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top"
]

View File

@@ -1,17 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"id": 11,
"question": "输出是什么?",
"code": "function Person(firstName, lastName) {\n this.firstName = firstName;\n this.lastName = lastName;\n}\n\nconst member = new Person(\"Lydia\", \"Hallie\");\nPerson.getFullName = function () {\n return `${this.firstName} ${this.lastName}`;\n}\n\nconsole.log(member.getFullName());",
"options": [
"A: `TypeError`",
"B: `SyntaxError`",
"C: `Lydia Hallie`",
"D: `undefined` `undefined`"
],
"answer": "A",
"explanation": "你不能像常规对象那样,给构造函数添加属性。如果你想一次性给所有实例添加特性,你应该使用原型。因此本例中,使用如下方式:\n\n```js\nPerson.prototype.getFullName = function () {\n return `${this.firstName} ${this.lastName}`;\n}\n```\n\n这才会使 `member.getFullName()` 起作用。为什么这么做有益的?假设我们将这个方法添加到构造函数本身里。也许不是每个 `Person` 实例都需要这个方法。这将浪费大量内存空间,因为它们仍然具有该属性,这将占用每个实例的内存空间。相反,如果我们只将它添加到原型中,那么它只存在于内存中的一个位置,但是所有实例都可以访问它!"
}
}

View File

@@ -1,81 +0,0 @@
/* 背景样式文件 */
body {
background: linear-gradient(135deg, #a8e6cf 0%, #dcedc1 25%, #ffd3a5 50%, #a8e6cf 75%, #88d8a3 100%);
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
position: relative;
}
/* 背景动画 */
@keyframes gradientShift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
/* 背景装饰元素 */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
radial-gradient(circle at 20% 80%, rgba(39, 174, 96, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(46, 204, 113, 0.1) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(26, 188, 156, 0.05) 0%, transparent 50%);
pointer-events: none;
z-index: -1;
}
/* 浮动装饰圆点 */
body::after {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
radial-gradient(2px 2px at 20px 30px, rgba(39, 174, 96, 0.3), transparent),
radial-gradient(2px 2px at 40px 70px, rgba(46, 204, 113, 0.2), transparent),
radial-gradient(1px 1px at 90px 40px, rgba(26, 188, 156, 0.3), transparent),
radial-gradient(1px 1px at 130px 80px, rgba(39, 174, 96, 0.2), transparent),
radial-gradient(2px 2px at 160px 30px, rgba(46, 204, 113, 0.3), transparent);
background-repeat: repeat;
background-size: 200px 100px;
animation: floatDots 20s linear infinite;
pointer-events: none;
z-index: -1;
}
@keyframes floatDots {
0% {
transform: translateY(0px);
}
100% {
transform: translateY(-100px);
}
}
/* 响应式背景调整 */
@media (max-width: 768px) {
body::after {
background-size: 150px 75px;
animation-duration: 25s;
}
}
@media (max-width: 480px) {
body::after {
background-size: 100px 50px;
animation-duration: 30s;
}
}

View File

@@ -1,339 +0,0 @@
/* 基础样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #2c3e50;
min-height: 100vh;
overflow-x: hidden;
}
/* 容器布局 */
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* 头部样式 */
.header {
text-align: center;
margin-bottom: 40px;
padding: 30px 0;
}
.title {
font-size: 2.5rem;
font-weight: 700;
color: #27ae60;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(39, 174, 96, 0.2);
}
.subtitle {
font-size: 1.1rem;
color: #7f8c8d;
font-weight: 400;
}
/* 主要内容区域 */
.main {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
}
.content-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
padding: 40px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(39, 174, 96, 0.1);
width: 100%;
max-width: 600px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.content-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15);
}
/* KFC文案内容 */
.kfc-content {
min-height: 200px;
padding: 30px;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-radius: 15px;
border-left: 5px solid #27ae60;
margin-bottom: 30px;
position: relative;
overflow: hidden;
}
.kfc-content::before {
content: '"';
position: absolute;
top: 10px;
left: 15px;
font-size: 3rem;
color: #27ae60;
opacity: 0.3;
font-family: serif;
}
.kfc-content p {
font-size: 1.1rem;
line-height: 1.8;
color: #2c3e50;
margin-left: 20px;
position: relative;
z-index: 1;
}
.loading-text {
text-align: center;
color: #7f8c8d;
font-style: italic;
}
/* 按钮组 */
.button-group {
display: flex;
gap: 15px;
justify-content: center;
margin-bottom: 20px;
}
.generate-btn, .copy-btn {
padding: 15px 30px;
border: none;
border-radius: 50px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.generate-btn {
background: linear-gradient(135deg, #27ae60 0%, #2ecc71 100%);
color: white;
box-shadow: 0 4px 15px rgba(39, 174, 96, 0.3);
}
.generate-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(39, 174, 96, 0.4);
}
.generate-btn:active {
transform: translateY(0);
}
.generate-btn:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
.copy-btn {
background: linear-gradient(135deg, #3498db 0%, #5dade2 100%);
color: white;
box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3);
}
.copy-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4);
}
/* 编号信息 */
.index-info {
text-align: center;
padding: 10px;
background: rgba(39, 174, 96, 0.1);
border-radius: 10px;
border: 1px solid rgba(39, 174, 96, 0.2);
}
.index-text {
color: #27ae60;
font-weight: 600;
font-size: 0.9rem;
}
#indexNumber {
color: #2c3e50;
font-weight: 700;
}
/* 底部 */
.footer {
text-align: center;
padding: 20px 0;
color: #7f8c8d;
font-size: 0.9rem;
margin-top: 40px;
}
/* 提示框 */
.toast {
position: fixed;
top: 20px;
right: 20px;
background: #27ae60;
color: white;
padding: 15px 25px;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
transform: translateX(400px);
transition: transform 0.3s ease;
z-index: 1000;
font-weight: 600;
}
.toast.show {
transform: translateX(0);
}
/* 平板端适配 (768px - 1024px) */
@media (max-width: 1024px) and (min-width: 768px) {
.container {
padding: 15px;
}
.title {
font-size: 2.2rem;
}
.content-card {
padding: 35px;
max-width: 550px;
}
.kfc-content {
padding: 25px;
min-height: 180px;
}
.button-group {
flex-direction: row;
gap: 12px;
}
.generate-btn, .copy-btn {
padding: 12px 25px;
font-size: 0.95rem;
}
}
/* 手机端适配 (最大768px) */
@media (max-width: 768px) {
.container {
padding: 10px;
}
.header {
margin-bottom: 30px;
padding: 20px 0;
}
.title {
font-size: 1.8rem;
margin-bottom: 8px;
}
.subtitle {
font-size: 1rem;
}
.content-card {
padding: 25px;
margin: 0 5px;
border-radius: 15px;
}
.kfc-content {
padding: 20px;
min-height: 150px;
margin-bottom: 25px;
}
.kfc-content::before {
font-size: 2.5rem;
top: 5px;
left: 10px;
}
.kfc-content p {
font-size: 1rem;
line-height: 1.7;
margin-left: 15px;
}
.button-group {
flex-direction: column;
gap: 10px;
}
.generate-btn, .copy-btn {
padding: 12px 20px;
font-size: 0.9rem;
width: 100%;
}
.footer {
font-size: 0.8rem;
margin-top: 30px;
}
.toast {
right: 10px;
left: 10px;
transform: translateY(-100px);
font-size: 0.9rem;
}
.toast.show {
transform: translateY(0);
}
}
/* 小屏手机适配 (最大480px) */
@media (max-width: 480px) {
.title {
font-size: 1.6rem;
}
.content-card {
padding: 20px;
margin: 0;
}
.kfc-content {
padding: 15px;
min-height: 120px;
}
.kfc-content p {
font-size: 0.95rem;
margin-left: 10px;
}
.generate-btn, .copy-btn {
padding: 10px 15px;
font-size: 0.85rem;
}
}

View File

@@ -1,46 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>随机KFC文案生成器</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/background.css">
</head>
<body>
<div class="container">
<header class="header">
<h1 class="title">🍗 随机KFC文案生成器</h1>
<p class="subtitle">疯狂星期四,文案来一套!</p>
</header>
<main class="main">
<div class="content-card">
<div class="kfc-content" id="kfcContent">
<p class="loading-text">点击按钮获取随机KFC文案...</p>
</div>
<div class="button-group">
<button class="generate-btn" id="generateBtn">
<span class="btn-text">生成文案</span>
<span class="btn-loading" style="display: none;">生成中...</span>
</button>
<button class="copy-btn" id="copyBtn" style="display: none;">复制文案</button>
</div>
<div class="index-info" id="indexInfo" style="display: none;">
<span class="index-text">文案编号: <span id="indexNumber"></span></span>
</div>
</div>
</main>
<footer class="footer">
<p>© 2024 KFC文案生成器 | 让每个星期四都疯狂起来</p>
</footer>
</div>
<div class="toast" id="toast"></div>
<script src="js/main.js"></script>
</body>
</html>

View File

@@ -1,240 +0,0 @@
// KFC文案生成器主要功能
class KFCGenerator {
constructor() {
this.apiEndpoints = [];
this.currentApiIndex = 0;
this.isLoading = false;
this.init();
}
// 初始化
async init() {
await this.loadApiEndpoints();
this.bindEvents();
}
// 加载API接口列表
async loadApiEndpoints() {
try {
// 直接硬编码API端点避免CORS问题
this.apiEndpoints = ["https://60s.api.shumengya.top"];
} catch (error) {
console.error('加载API接口列表失败:', error);
this.showToast('加载接口配置失败', 'error');
}
}
// 绑定事件
bindEvents() {
const generateBtn = document.getElementById('generateBtn');
const copyBtn = document.getElementById('copyBtn');
generateBtn.addEventListener('click', () => this.generateKFC());
copyBtn.addEventListener('click', () => this.copyContent());
}
// 生成KFC文案
async generateKFC() {
if (this.isLoading) return;
this.setLoadingState(true);
let success = false;
let attempts = 0;
const maxAttempts = this.apiEndpoints.length;
while (!success && attempts < maxAttempts) {
try {
const apiUrl = this.apiEndpoints[this.currentApiIndex];
const data = await this.fetchKFCData(apiUrl);
if (data && data.code === 200 && data.data && data.data.kfc) {
this.displayKFC(data.data);
success = true;
} else {
throw new Error('API返回数据格式错误');
}
} catch (error) {
console.error(`API ${this.currentApiIndex + 1} 请求失败:`, error);
this.currentApiIndex = (this.currentApiIndex + 1) % this.apiEndpoints.length;
attempts++;
}
}
if (!success) {
this.showError('所有API接口都无法访问请稍后重试');
}
this.setLoadingState(false);
}
// 请求KFC数据
async fetchKFCData(apiUrl) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
try {
const response = await fetch(`${apiUrl}/v2/kfc`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}
// 显示KFC文案
displayKFC(data) {
const contentElement = document.getElementById('kfcContent');
const indexElement = document.getElementById('indexNumber');
const indexInfo = document.getElementById('indexInfo');
const copyBtn = document.getElementById('copyBtn');
// 显示文案内容
contentElement.innerHTML = `<p>${this.escapeHtml(data.kfc)}</p>`;
// 显示编号信息
if (data.index) {
indexElement.textContent = data.index;
indexInfo.style.display = 'block';
} else {
indexInfo.style.display = 'none';
}
// 显示复制按钮
copyBtn.style.display = 'inline-block';
// 添加显示动画
contentElement.style.opacity = '0';
contentElement.style.transform = 'translateY(20px)';
setTimeout(() => {
contentElement.style.transition = 'all 0.5s ease';
contentElement.style.opacity = '1';
contentElement.style.transform = 'translateY(0)';
}, 100);
}
// 显示错误信息
showError(message) {
const contentElement = document.getElementById('kfcContent');
contentElement.innerHTML = `<p class="loading-text" style="color: #e74c3c;">${this.escapeHtml(message)}</p>`;
const copyBtn = document.getElementById('copyBtn');
const indexInfo = document.getElementById('indexInfo');
copyBtn.style.display = 'none';
indexInfo.style.display = 'none';
}
// 复制文案内容
async copyContent() {
const contentElement = document.getElementById('kfcContent');
const textContent = contentElement.querySelector('p')?.textContent;
if (!textContent || textContent.includes('点击按钮获取') || textContent.includes('失败')) {
this.showToast('没有可复制的内容', 'error');
return;
}
try {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(textContent);
} else {
// 降级方案
const textArea = document.createElement('textarea');
textArea.value = textContent;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
document.execCommand('copy');
textArea.remove();
}
this.showToast('文案已复制到剪贴板', 'success');
} catch (error) {
console.error('复制失败:', error);
this.showToast('复制失败,请手动选择复制', 'error');
}
}
// 设置加载状态
setLoadingState(loading) {
this.isLoading = loading;
const generateBtn = document.getElementById('generateBtn');
const btnText = generateBtn.querySelector('.btn-text');
const btnLoading = generateBtn.querySelector('.btn-loading');
if (loading) {
generateBtn.disabled = true;
btnText.style.display = 'none';
btnLoading.style.display = 'inline';
} else {
generateBtn.disabled = false;
btnText.style.display = 'inline';
btnLoading.style.display = 'none';
}
}
// 显示提示消息
showToast(message, type = 'success') {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.className = `toast ${type}`;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
// HTML转义
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
const generator = new KFCGenerator();
// 页面加载完成后自动生成一条文案
setTimeout(() => {
generator.generateKFC();
}, 1000);
});
// 添加键盘快捷键支持
document.addEventListener('keydown', (event) => {
// 按空格键生成文案
if (event.code === 'Space' && event.target.tagName !== 'INPUT' && event.target.tagName !== 'TEXTAREA') {
event.preventDefault();
document.getElementById('generateBtn').click();
}
// Ctrl+C 复制文案
if (event.ctrlKey && event.key === 'c' && event.target.tagName !== 'INPUT' && event.target.tagName !== 'TEXTAREA') {
const copyBtn = document.getElementById('copyBtn');
if (copyBtn.style.display !== 'none') {
event.preventDefault();
copyBtn.click();
}
}
});

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top"
]

View File

@@ -1,8 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"index": 78,
"kfc": "我叫夯大力 立冬给我准备了糖炒栗子了没有 没准备的自动绝交 再 v 我 50 吃疯狂星期四 然后再给我点杯奶茶 再给我两万块钱 懂吗你们"
}
}

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>随机一言</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 68px)}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:36px 28px;text-align:center;border:1px solid rgba(34,197,94,.12);position:relative;width:100%}
.quote::before{content:'"';position:absolute;top:10px;left:20px;font-size:60px;color:rgba(34,197,94,.15);font-family:serif;line-height:1}
.quote-text{font-size:18px;line-height:2;color:#374151;font-weight:500}
.quote-src{font-size:12px;color:#9ca3af;margin-top:16px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px;width:100%}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px;width:100%}
@media(max-width:640px){.quote-text{font-size:15px}.quote{padding:28px 20px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>💭 随机一言</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/hitokoto?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
let text='',source='';
if(typeof d==='string'){text=d}
else if(d&&typeof d==='object'){
for(const k of['content','text','hitokoto','duanzi','joke','saying','answer','kfc','data']){if(typeof d[k]==='string'){text=d[k];break}}
if(!text){for(const v of Object.values(d)){if(typeof v==='string'&&v.length>5){text=v;break}}}
if(!text)text=JSON.stringify(d,null,2);
source=d.from||d.source||d.author||'';
}else{text=String(d??'')}
el.innerHTML=`<div class="quote"><div class="quote-text">${text}</div>${source?`<div class="quote-src">—— ${source}</div>`:''}</div>`;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -1,167 +0,0 @@
/* 背景样式文件 - 金色光辉主题 */
/* 主背景 */
body {
background: linear-gradient(
135deg,
#f1f8e9 0%,
#dcedc8 25%,
#c8e6c8 50%,
#a5d6a7 75%,
#81c784 100%
);
background-size: 400% 400%;
animation: gradientShift 15s ease infinite;
position: relative;
}
/* 背景装饰层 */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
radial-gradient(circle at 20% 80%, rgba(129, 199, 132, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(165, 214, 167, 0.1) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(102, 187, 106, 0.05) 0%, transparent 50%);
pointer-events: none;
z-index: 1;
}
/* 动态光点效果 */
body::after {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
radial-gradient(2px 2px at 20px 30px, rgba(129, 199, 132, 0.3), transparent),
radial-gradient(2px 2px at 40px 70px, rgba(165, 214, 167, 0.2), transparent),
radial-gradient(1px 1px at 90px 40px, rgba(102, 187, 106, 0.4), transparent),
radial-gradient(1px 1px at 130px 80px, rgba(129, 199, 132, 0.2), transparent),
radial-gradient(2px 2px at 160px 30px, rgba(165, 214, 167, 0.3), transparent);
background-repeat: repeat;
background-size: 200px 100px;
animation: sparkle 20s linear infinite;
pointer-events: none;
z-index: 2;
}
/* 背景动画 */
@keyframes gradientShift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@keyframes sparkle {
0% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(-100vh);
opacity: 0;
}
}
/* 响应式背景调整 */
/* 平板端背景 */
@media (min-width: 768px) and (max-width: 1024px) {
body::after {
background-size: 250px 120px;
}
}
/* 电脑端背景 */
@media (min-width: 1024px) {
body {
background-size: 300% 300%;
}
body::after {
background-size: 300px 150px;
animation-duration: 25s;
}
}
/* 手机端背景优化 */
@media (max-width: 767px) {
body {
background-size: 200% 200%;
animation-duration: 10s;
}
body::before {
background:
radial-gradient(circle at 30% 70%, rgba(129, 199, 132, 0.08) 0%, transparent 40%),
radial-gradient(circle at 70% 30%, rgba(165, 214, 167, 0.08) 0%, transparent 40%);
}
body::after {
background-size: 150px 80px;
animation-duration: 15s;
}
}
/* 超小屏幕背景 */
@media (max-width: 479px) {
body {
background: linear-gradient(
135deg,
#f1f8e9 0%,
#dcedc8 50%,
#c8e6c8 100%
);
background-size: 150% 150%;
}
body::after {
background-size: 120px 60px;
}
}
/* 深色模式支持 */
@media (prefers-color-scheme: dark) {
body {
background: linear-gradient(
135deg,
#1b2e1b 0%,
#2e4a2e 25%,
#3e5e3e 50%,
#4e6e4e 75%,
#5e7e5e 100%
);
}
body::before {
background:
radial-gradient(circle at 20% 80%, rgba(129, 199, 132, 0.05) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(165, 214, 167, 0.05) 0%, transparent 50%);
}
}
/* 减少动画效果(用户偏好) */
@media (prefers-reduced-motion: reduce) {
body,
body::before,
body::after {
animation: none;
}
body {
background: linear-gradient(135deg, #f1f8e9 0%, #dcedc8 50%, #c8e6c8 100%);
}
}

View File

@@ -1,357 +0,0 @@
/* 基础样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #2e7d32;
overflow-x: hidden;
}
/* 容器布局 */
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 20px;
position: relative;
}
/* 头部样式 */
.header {
text-align: center;
margin-bottom: 40px;
z-index: 10;
}
.title {
font-size: 3rem;
font-weight: 700;
color: #2e7d32;
text-shadow:
0 0 10px rgba(129, 199, 132, 0.8),
0 0 20px rgba(129, 199, 132, 0.6),
0 0 30px rgba(129, 199, 132, 0.4);
margin-bottom: 10px;
animation: titleGlow 3s ease-in-out infinite alternate;
}
.subtitle {
font-size: 1.2rem;
color: #388e3c;
opacity: 0.9;
text-shadow: 0 0 5px rgba(102, 187, 106, 0.5);
}
/* 主内容区域 */
.main-content {
width: 100%;
max-width: 800px;
z-index: 10;
}
/* 一言容器 */
.quote-container {
background: linear-gradient(135deg, rgba(129, 199, 132, 0.1), rgba(165, 214, 167, 0.05));
border: 2px solid rgba(102, 187, 106, 0.3);
border-radius: 20px;
padding: 40px;
margin-bottom: 30px;
backdrop-filter: blur(10px);
box-shadow:
0 8px 32px rgba(102, 187, 106, 0.2),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
position: relative;
overflow: hidden;
}
.quote-container::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, #81c784, #a5d6a7, #81c784, #a5d6a7);
border-radius: 22px;
z-index: -1;
animation: borderGlow 4s linear infinite;
}
/* 加载状态 */
.loading {
display: none;
text-align: center;
color: #2e7d32;
}
.loading.show {
display: block;
}
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(102, 187, 106, 0.3);
border-top: 4px solid #2e7d32;
border-radius: 50%;
margin: 0 auto 15px;
animation: spin 1s linear infinite;
}
/* 一言显示 */
.quote-display {
display: block;
text-align: center;
}
.quote-display.hide {
display: none;
}
.quote-text {
font-size: 1.8rem;
line-height: 1.8;
color: #2e7d32;
margin-bottom: 20px;
text-shadow: 0 1px 2px rgba(102, 187, 106, 0.1);
font-weight: 500;
}
.quote-index {
font-size: 0.9rem;
color: #388e3c;
opacity: 0.8;
}
/* 错误信息 */
.error-message {
display: none;
text-align: center;
color: #66bb6a;
}
.error-message.show {
display: block;
}
.error-icon {
font-size: 2rem;
margin-bottom: 10px;
}
.error-text {
font-size: 1.1rem;
line-height: 1.5;
}
/* 控制按钮 */
.controls {
text-align: center;
}
.refresh-btn {
background: linear-gradient(135deg, #81c784, #a5d6a7);
border: none;
border-radius: 50px;
padding: 15px 30px;
font-size: 1.1rem;
font-weight: 600;
color: #2e7d32;
cursor: pointer;
display: inline-flex;
align-items: center;
gap: 10px;
transition: all 0.3s ease;
box-shadow:
0 4px 15px rgba(102, 187, 106, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
position: relative;
overflow: hidden;
}
.refresh-btn:hover {
transform: translateY(-2px);
box-shadow:
0 6px 20px rgba(102, 187, 106, 0.4),
inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.refresh-btn:active {
transform: translateY(0);
}
.refresh-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.btn-icon {
font-size: 1.2rem;
transition: transform 0.3s ease;
}
.refresh-btn:hover .btn-icon {
transform: rotate(180deg);
}
/* 底部 */
.footer {
margin-top: 40px;
text-align: center;
color: #388e3c;
opacity: 0.8;
font-size: 0.9rem;
}
/* 动画效果 */
@keyframes titleGlow {
0% {
text-shadow:
0 0 10px rgba(129, 199, 132, 0.8),
0 0 20px rgba(129, 199, 132, 0.6),
0 0 30px rgba(129, 199, 132, 0.4);
}
100% {
text-shadow:
0 0 15px rgba(129, 199, 132, 1),
0 0 25px rgba(129, 199, 132, 0.8),
0 0 35px rgba(129, 199, 132, 0.6);
}
}
@keyframes borderGlow {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 平板端适配 (768px - 1024px) */
@media (min-width: 768px) and (max-width: 1024px) {
.container {
padding: 30px;
}
.title {
font-size: 3.5rem;
}
.subtitle {
font-size: 1.3rem;
}
.quote-container {
padding: 50px;
}
.quote-text {
font-size: 2rem;
}
}
/* 电脑端适配 (1024px+) */
@media (min-width: 1024px) {
.container {
padding: 40px;
}
.title {
font-size: 4rem;
}
.subtitle {
font-size: 1.4rem;
}
.quote-container {
padding: 60px;
max-width: 900px;
}
.quote-text {
font-size: 2.2rem;
line-height: 1.9;
}
.refresh-btn {
padding: 18px 36px;
font-size: 1.2rem;
}
}
/* 手机端适配 (小于768px) */
@media (max-width: 767px) {
.container {
padding: 15px;
}
.header {
margin-bottom: 30px;
}
.title {
font-size: 2.5rem;
}
.subtitle {
font-size: 1rem;
}
.quote-container {
padding: 25px;
border-radius: 15px;
}
.quote-text {
font-size: 1.4rem;
line-height: 1.6;
}
.refresh-btn {
padding: 12px 24px;
font-size: 1rem;
}
.footer {
margin-top: 30px;
font-size: 0.8rem;
}
}
/* 超小屏幕适配 (小于480px) */
@media (max-width: 479px) {
.title {
font-size: 2rem;
}
.quote-container {
padding: 20px;
}
.quote-text {
font-size: 1.2rem;
}
.refresh-btn {
padding: 10px 20px;
font-size: 0.9rem;
}
}

View File

@@ -1,52 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>随机一言 - 金色光辉</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/background.css">
</head>
<body>
<div class="container">
<header class="header">
<h1 class="title">随机一言</h1>
<p class="subtitle">每一句话都是心灵的光芒</p>
</header>
<main class="main-content">
<div class="quote-container">
<div class="loading" id="loading">
<div class="loading-spinner"></div>
<p>正在获取一言...</p>
</div>
<div class="quote-display" id="quoteDisplay">
<div class="quote-text" id="quoteText">
点击下方按钮获取一言
</div>
<div class="quote-index" id="quoteIndex"></div>
</div>
<div class="error-message" id="errorMessage">
<div class="error-icon">⚠️</div>
<div class="error-text" id="errorText"></div>
</div>
</div>
<div class="controls">
<button class="refresh-btn" id="refreshBtn">
<span class="btn-icon">🔄</span>
<span class="btn-text">获取新一言</span>
</button>
</div>
</main>
<footer class="footer">
<p>愿每一句话都能温暖你的心</p>
</footer>
</div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -1,222 +0,0 @@
// 随机一言 JavaScript 功能实现
class HitokotoApp {
constructor() {
// API接口列表
this.apiEndpoints = [
"https://60s.api.shumengya.top"
];
this.currentEndpointIndex = 0;
this.isLoading = false;
// DOM 元素
this.elements = {
loading: document.getElementById('loading'),
quoteDisplay: document.getElementById('quoteDisplay'),
quoteText: document.getElementById('quoteText'),
quoteIndex: document.getElementById('quoteIndex'),
errorMessage: document.getElementById('errorMessage'),
errorText: document.getElementById('errorText'),
refreshBtn: document.getElementById('refreshBtn')
};
this.init();
}
// 初始化应用
init() {
this.bindEvents();
this.hideAllStates();
this.showQuoteDisplay();
}
// 绑定事件
bindEvents() {
this.elements.refreshBtn.addEventListener('click', () => {
this.fetchHitokoto();
});
// 键盘快捷键支持
document.addEventListener('keydown', (e) => {
if (e.code === 'Space' && !this.isLoading) {
e.preventDefault();
this.fetchHitokoto();
}
});
}
// 隐藏所有状态
hideAllStates() {
this.elements.loading.classList.remove('show');
this.elements.quoteDisplay.classList.remove('hide');
this.elements.errorMessage.classList.remove('show');
}
// 显示加载状态
showLoading() {
this.hideAllStates();
this.elements.loading.classList.add('show');
this.elements.quoteDisplay.classList.add('hide');
this.elements.refreshBtn.disabled = true;
this.isLoading = true;
}
// 显示一言内容
showQuoteDisplay() {
this.hideAllStates();
this.elements.quoteDisplay.classList.remove('hide');
this.elements.refreshBtn.disabled = false;
this.isLoading = false;
}
// 显示错误信息
showError(message) {
this.hideAllStates();
this.elements.errorMessage.classList.add('show');
this.elements.errorText.textContent = message;
this.elements.refreshBtn.disabled = false;
this.isLoading = false;
}
// 获取一言数据
async fetchHitokoto() {
if (this.isLoading) return;
this.showLoading();
// 尝试所有API接口
for (let i = 0; i < this.apiEndpoints.length; i++) {
const endpointIndex = (this.currentEndpointIndex + i) % this.apiEndpoints.length;
const endpoint = this.apiEndpoints[endpointIndex];
try {
const result = await this.tryFetchFromEndpoint(endpoint);
if (result.success) {
this.currentEndpointIndex = endpointIndex;
this.displayHitokoto(result.data);
return;
}
} catch (error) {
console.warn(`接口 ${endpoint} 请求失败:`, error.message);
continue;
}
}
// 所有接口都失败
this.showError('所有接口都无法访问,请检查网络连接或稍后重试');
}
// 尝试从指定接口获取数据
async tryFetchFromEndpoint(endpoint) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
try {
// 移除URL中的encoding=text参数确保返回JSON格式
const response = await fetch(`${endpoint}/v2/hitokoto`, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
// 验证返回数据格式
if (data.code === 200 && data.data && data.data.hitokoto) {
return {
success: true,
data: data.data
};
} else {
throw new Error('返回数据格式不正确');
}
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error('请求超时');
}
throw error;
}
}
// 显示一言内容
displayHitokoto(data) {
// 更新一言文本
this.elements.quoteText.textContent = data.hitokoto;
// 更新序号信息
if (data.index) {
this.elements.quoteIndex.textContent = `${data.index}`;
} else {
this.elements.quoteIndex.textContent = '';
}
// 添加淡入动画效果
this.elements.quoteText.style.opacity = '0';
this.elements.quoteIndex.style.opacity = '0';
setTimeout(() => {
this.elements.quoteText.style.transition = 'opacity 0.5s ease';
this.elements.quoteIndex.style.transition = 'opacity 0.5s ease';
this.elements.quoteText.style.opacity = '1';
this.elements.quoteIndex.style.opacity = '1';
}, 100);
this.showQuoteDisplay();
// 控制台输出调试信息
console.log('一言获取成功:', {
content: data.hitokoto,
index: data.index,
endpoint: this.apiEndpoints[this.currentEndpointIndex]
});
}
// 获取随机接口(用于负载均衡)
getRandomEndpoint() {
const randomIndex = Math.floor(Math.random() * this.apiEndpoints.length);
return this.apiEndpoints[randomIndex];
}
}
// 页面加载完成后初始化应用
document.addEventListener('DOMContentLoaded', () => {
const app = new HitokotoApp();
// 添加全局错误处理
window.addEventListener('error', (event) => {
console.error('页面发生错误:', event.error);
});
window.addEventListener('unhandledrejection', (event) => {
console.error('未处理的Promise拒绝:', event.reason);
});
// 页面可见性变化时的处理
document.addEventListener('visibilitychange', () => {
if (!document.hidden && !app.isLoading) {
// 页面重新可见时,可以选择刷新内容
console.log('页面重新可见');
}
});
console.log('随机一言应用初始化完成');
});
// 导出应用类(如果需要在其他地方使用)
if (typeof module !== 'undefined' && module.exports) {
module.exports = HitokotoApp;
}

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top"
]

View File

@@ -1,8 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"index": 2862,
"hitokoto": "你带上罪恶之冠,即使背负上所有罪恶和孤独,绝不让你受伤"
}
}

View File

@@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>每日笑话</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="card">
<p id="joke">加载中...</p>
<button id="next">换一个</button>
</div>
<script src="script.js"></script>
</body>
</html>

View File

@@ -1,107 +0,0 @@
/* background.css - 动态渐变背景 */
body {
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
background-size: 400% 400%;
animation: gradient 15s ease infinite;
}
@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
:root {
--bg-yellow: #FFFDE7; /* 浅黄 */
--bg-blue: #E3F2FD; /* 淡蓝 */
}
body {
background: linear-gradient(180deg, var(--bg-yellow) 0%, var(--bg-blue) 100%);
background-attachment: fixed; /* 固定背景,滚动时不移动 */
}
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
overflow: hidden;
transition: background-color 0.5s ease;
}
/* Light Theme (Default) */
[data-theme="light"] {
background: linear-gradient(to bottom, #87CEEB, #B0E0E6);
}
/* Dark Theme */
[data-theme="dark"] {
background: linear-gradient(to bottom, #232526, #414345);
}
[data-theme="dark"] .snowflake {
color: #999;
}
/* Winter Theme */
[data-theme="winter"] {
background: linear-gradient(to bottom, #a1c4fd, #c2e9fb);
}
[data-theme="winter"] .background-bottom {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 100px;
background: linear-gradient(to top, white, rgba(255, 255, 255, 0));
z-index: -1;
border-radius: 50% 50% 0 0 / 20px;
box-shadow: 0 -10px 20px rgba(255, 255, 255, 0.5);
}
#snowflake-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 0;
}
.snowflake {
position: absolute;
top: -10%;
color: white;
font-size: 20px;
user-select: none;
animation: fall linear infinite;
}
@keyframes fall {
to {
transform: translateY(105vh) rotate(360deg);
}
}
#frost-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('https://www.transparenttextures.com/patterns/ice-age.png') repeat;
opacity: 0;
pointer-events: none;
transition: opacity 0.5s ease-in-out;
z-index: 100;
}
#frost-overlay.is-frosted {
opacity: 0.3;
}

View File

@@ -1,217 +0,0 @@
:root {
--primary-color-light: #4A90E2;
--text-color-light: #333;
--card-bg-light: rgba(255, 255, 255, 0.85);
--primary-color-dark: #5271C4;
--text-color-dark: #E0E0E0;
--card-bg-dark: rgba(40, 40, 40, 0.85);
--primary-color-winter: #6A82FB;
--text-color-winter: #2c3e50;
--card-bg-winter: rgba(255, 255, 255, 0.7);
}
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 20px;
box-sizing: border-box;
text-align: center;
position: relative;
z-index: 1;
}
.top-nav {
position: absolute;
top: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.3);
padding: 5px;
border-radius: 50px;
backdrop-filter: blur(5px);
}
.theme-switcher {
display: flex;
gap: 5px;
}
.theme-btn {
background: transparent;
border: 2px solid transparent;
border-radius: 50%;
width: 40px;
height: 40px;
font-size: 1.5em;
cursor: pointer;
transition: transform 0.2s, border-color 0.2s;
}
.theme-btn:hover {
transform: scale(1.1);
}
.theme-btn.active {
border-color: white;
}
.title {
font-family: 'ZCOOL KuaiLe', cursive;
font-size: 3em;
margin-bottom: 20px;
transition: color 0.5s ease;
}
.joke-stream {
width: 100%;
max-width: 500px;
display: flex;
flex-direction: column;
gap: 25px;
}
.joke-card {
border-radius: 20px;
padding: 30px 40px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
width: 100%;
max-width: 500px;
min-height: 150px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.2);
transition: background-color 0.5s ease, border-color 0.5s ease;
}
#joke-text {
font-size: 1.5em;
line-height: 1.6;
transition: opacity 0.3s, color 0.5s ease;
}
/* --- Theming --- */
/* Light Theme */
[data-theme="light"] .title { color: white; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); }
[data-theme="light"] .joke-card { background-color: var(--card-bg-light); }
[data-theme="light"] #joke-text { color: var(--text-color-light); }
[data-theme="light"] #new-joke-btn { background-color: var(--primary-color-light); box-shadow: 0 4px 15px rgba(74, 144, 226, 0.4); }
[data-theme="light"] footer { color: rgba(255, 255, 255, 0.8); }
/* Dark Theme */
[data-theme="dark"] .title { color: #EAEAEA; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); }
[data-theme="dark"] .joke-card { background-color: var(--card-bg-dark); border-color: rgba(255, 255, 255, 0.1); }
[data-theme="dark"] #joke-text { color: var(--text-color-dark); }
[data-theme="dark"] #new-joke-btn { background-color: var(--primary-color-dark); box-shadow: 0 4px 15px rgba(82, 113, 196, 0.4); }
[data-theme="dark"] footer { color: rgba(200, 200, 200, 0.7); }
/* Winter Theme */
[data-theme="winter"] .title { color: #1e3a5f; text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.7); }
[data-theme="winter"] .joke-card {
background-color: var(--card-bg-winter);
border-color: rgba(255, 255, 255, 0.8);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1), inset 0 0 15px rgba(255, 255, 255, 0.5);
}
[data-theme="winter"] #joke-text { color: var(--text-color-winter); }
[data-theme="winter"] #new-joke-btn { background-color: var(--primary-color-winter); box-shadow: 0 4px 15px rgba(106, 130, 251, 0.4); }
[data-theme="winter"] footer { color: #1e3a5f; }
.controls {
margin-top: 30px;
}
#new-joke-btn {
color: white;
font-size: 1.2em;
font-weight: bold;
padding: 15px 35px;
border: none;
border-radius: 50px;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.5s ease;
}
#new-joke-btn:hover {
transform: translateY(-3px);
}
#new-joke-btn:active {
transform: translateY(1px);
}
.interactions {
margin-top: 25px;
display: flex;
gap: 20px;
}
.interaction-btn {
background: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(255, 255, 255, 0.9);
border-radius: 50%;
width: 50px;
height: 50px;
font-size: 1.5em;
cursor: pointer;
transition: transform 0.2s, background-color 0.2s;
}
.interaction-btn:hover {
transform: scale(1.1);
background: white;
}
footer {
position: absolute;
bottom: 10px;
font-size: 0.9em;
transition: color 0.5s ease;
}
/* Loader */
#loader {
position: absolute;
transition: color 0.5s ease;
}
[data-theme="light"] #loader { color: var(--primary-color-light); }
[data-theme="dark"] #loader { color: var(--primary-color-dark); }
[data-theme="winter"] #loader { color: var(--primary-color-winter); }
.snowflake-loader {
font-size: 40px;
display: inline-block;
animation: spin 1.5s linear infinite;
}
.snowflake-loader::before {
content: '❄';
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.hidden {
display: none;
}
/* Responsive */
@media (max-width: 600px) {
.title {
font-size: 2.5em;
}
.joke-card {
padding: 25px;
}
#joke-text {
font-size: 1.2em;
}
.top-nav {
top: 10px;
right: 10px;
}
}

View File

@@ -1,58 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>随机冷笑话</title>
<link href="https://fonts.googleapis.com/css2?family=ZCOOL+KuaiLe&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/background.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body data-theme="light">
<div id="snowflake-container"></div>
<div id="frost-overlay"></div>
<div class="background-bottom"></div>
<nav class="top-nav">
<div class="theme-switcher">
<button class="theme-btn" data-theme-target="light" title="清新风">☀️</button>
<button class="theme-btn" data-theme-target="dark" title="暗黑风">🌙</button>
<button class="theme-btn" data-theme-target="winter" title="冰雪风">❄️</button>
</div>
</nav>
<div class="container">
<header>
<h1 class="title">冷笑话生成器</h1>
</header>
<main class="joke-card">
<div id="loader" class="hidden">
<div class="snowflake-loader"></div>
<p>思考中...</p>
</div>
<p id="joke-text">点击下面的按钮,来点冷笑话吧!</p>
</main>
<div class="controls">
<button id="new-joke-btn">再来一个</button>
</div>
<div class="interactions">
<button class="interaction-btn" id="like-btn" title="好笑">👍</button>
<button class="interaction-btn" id="dislike-btn" title="不好笑">👎</button>
<button class="interaction-btn" id="collect-btn" title="收藏">⭐️</button>
<button class="interaction-btn" id="share-btn" title="分享">🔗</button>
</div>
</div>
<footer>
<p>&copy; 2024 冷笑话工坊</p>
</footer>
<audio id="wind-sound" src="https://www.soundjay.com/nature/sounds/wind-howl-01.mp3" preload="auto"></audio>
<audio id="snow-sound" src="https://www.soundjay.com/nature/sounds/walking-in-snow-01.mp3" preload="auto"></audio>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -1,117 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
const jokeTextElem = document.getElementById('joke-text');
const newJokeBtn = document.getElementById('new-joke-btn');
const snowflakeContainer = document.getElementById('snowflake-container');
const frostOverlay = document.getElementById('frost-overlay');
const windSound = document.getElementById('wind-sound');
const snowSound = document.getElementById('snow-sound');
const loader = document.getElementById('loader');
const themeBtns = document.querySelectorAll('.theme-btn');
const apiEndpoints = [
'https://60s.api.shumengya.top/v2/dad-joke',
];
let currentApiIndex = 0;
async function fetchJoke() {
jokeTextElem.classList.add('hidden');
loader.classList.remove('hidden');
try {
const response = await fetch(apiEndpoints[currentApiIndex]);
if (!response.ok) throw new Error('Network response was not ok');
const data = await response.json();
if (data.code === 200 && data.data.content) {
updateJokeText(data.data.content);
if (document.body.dataset.theme === 'winter' && Math.random() < 0.3) {
triggerFrostEffect();
}
} else {
throw new Error('API returned invalid data');
}
} catch (error) {
console.error('Fetch error:', error);
currentApiIndex = (currentApiIndex + 1) % apiEndpoints.length;
if (currentApiIndex !== 0) {
fetchJoke();
} else {
jokeTextElem.textContent = '冰箱坏了,暂时没有冷笑话...';
}
} finally {
loader.classList.add('hidden');
jokeTextElem.classList.remove('hidden');
}
}
function updateJokeText(text) {
jokeTextElem.textContent = '';
let i = 0;
const typing = setInterval(() => {
if (i < text.length) {
jokeTextElem.textContent += text.charAt(i);
i++;
} else {
clearInterval(typing);
}
}, 50);
}
function createSnowflakes() {
const snowflakeCount = document.body.dataset.theme === 'dark' ? 50 : 30;
snowflakeContainer.innerHTML = '';
for (let i = 0; i < snowflakeCount; i++) {
const snowflake = document.createElement('div');
snowflake.className = 'snowflake';
snowflake.textContent = '❄️';
snowflake.style.left = `${Math.random() * 100}vw`;
snowflake.style.fontSize = `${Math.random() * 15 + 10}px`;
snowflake.style.opacity = Math.random() * 0.5 + 0.3;
const duration = Math.random() * 10 + 8;
const delay = Math.random() * 10;
snowflake.style.animation = `fall ${duration}s linear ${delay}s infinite`;
snowflakeContainer.appendChild(snowflake);
}
}
function triggerFrostEffect() {
frostOverlay.classList.add('is-frosted');
windSound.play().catch(e => console.error("Audio play failed:", e));
setTimeout(() => {
frostOverlay.classList.remove('is-frosted');
}, 2000);
}
function setTheme(theme) {
document.body.dataset.theme = theme;
localStorage.setItem('joke-theme', theme);
themeBtns.forEach(btn => {
btn.classList.toggle('active', btn.dataset.themeTarget === theme);
});
if (theme === 'winter') {
snowSound.play().catch(e => console.error("Audio play failed:", e));
}
// Recreate snowflakes for theme-specific density
createSnowflakes();
}
themeBtns.forEach(btn => {
btn.addEventListener('click', () => {
setTheme(btn.dataset.themeTarget);
});
});
newJokeBtn.addEventListener('click', fetchJoke);
// Initial setup
const savedTheme = localStorage.getItem('joke-theme') || 'light';
setTheme(savedTheme);
fetchJoke();
});

View File

@@ -1 +0,0 @@
["https://60s.api.shumengya.top"]

View File

@@ -1,8 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"index": 121,
"content": "这个世界上谁最懂猪?蜘蛛(知猪)人。"
}
}

View File

@@ -1,90 +0,0 @@
body {
background-color: #1a1a1a;
color: #e0e0e0;
font-family: 'Courier New', Courier, monospace;
overflow: hidden;
margin: 0;
padding: 0;
}
#bg-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -2;
overflow: hidden;
transition: transform 0.2s ease-out;
}
.floating-emoji {
position: absolute;
user-select: none;
opacity: 0;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
@keyframes float-top-to-bottom {
0% { transform: translateY(-10vh) rotate(0deg); opacity: 0; }
10%, 90% { opacity: 0.7; }
100% { transform: translateY(110vh) rotate(360deg); opacity: 0; }
}
@keyframes float-bottom-to-top {
0% { transform: translateY(110vh) rotate(0deg); opacity: 0; }
10%, 90% { opacity: 0.7; }
100% { transform: translateY(-10vh) rotate(360deg); opacity: 0; }
}
@keyframes float-left-to-right {
0% { transform: translateX(-10vw) rotate(0deg); opacity: 0; }
10%, 90% { opacity: 0.7; }
100% { transform: translateX(110vw) rotate(360deg); opacity: 0; }
}
@keyframes float-right-to-left {
0% { transform: translateX(110vw) rotate(0deg); opacity: 0; }
10%, 90% { opacity: 0.7; }
100% { transform: translateX(-10vw) rotate(360deg); opacity: 0; }
}
.text-fragment {
position: absolute;
font-size: 24px;
color: rgba(255, 0, 255, 0.4);
opacity: 0;
animation: float-fragment 15s linear infinite, fade-in-out 15s linear infinite;
user-select: none;
}
@keyframes float-fragment {
0% { transform: translate(0, 0) rotate(0deg); }
25% { transform: translate(20px, 40px) rotate(15deg); }
50% { transform: translate(-30px, -10px) rotate(-10deg); }
75% { transform: translate(10px, -30px) rotate(5deg); }
100% { transform: translate(0, 0) rotate(0deg); }
}
@keyframes fade-in-out {
0%, 100% { opacity: 0; }
10%, 90% { opacity: 0.4; }
}
.screen-crack {
position: absolute;
width: 200px;
height: 200px;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M 100 100 L 0 0 M 100 100 L 200 0 M 100 100 L 50 200 M 100 100 L 150 200" stroke="rgba(255,255,255,0.5)" stroke-width="1" fill="none"/></svg>');
opacity: 0;
animation: flicker-crack 25s steps(1, end) infinite;
}
@keyframes flicker-crack {
0%, 100% { opacity: 0; }
50% { opacity: 0.3; }
51% { opacity: 0; }
75% { opacity: 0.2; }
76% { opacity: 0; }
}

View File

@@ -1,235 +0,0 @@
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
box-sizing: border-box;
position: relative;
z-index: 1;
}
.content-card {
background: rgba(20, 20, 20, 0.7);
border: none;
padding: 40px;
max-width: 600px;
width: 100%;
text-align: center;
backdrop-filter: blur(5px);
position: relative;
clip-path: polygon(2% 5%, 97% 0%, 100% 95%, 0% 100%);
}
.body-animated .content-card {
animation: tremble 0.4s infinite, glitch-shadow 1.5s steps(1, end) infinite;
}
@keyframes tremble {
0% { clip-path: polygon(2% 5%, 97% 0%, 100% 95%, 0% 100%); }
25% { clip-path: polygon(2% 5%, 98% 2%, 99% 100%, 1% 98%); }
50% { clip-path: polygon(3% 4%, 96% 1%, 100% 96%, 2% 100%); }
75% { clip-path: polygon(1% 6%, 97% 3%, 98% 95%, 0% 99%); }
100% { clip-path: polygon(2% 5%, 97% 0%, 100% 95%, 0% 100%); }
}
@keyframes glitch-shadow {
0% {
box-shadow:
0 0 8px rgba(255, 0, 255, 0.5),
inset 0 0 8px rgba(255, 0, 255, 0.4);
}
33% {
box-shadow:
0 0 8px rgba(0, 255, 255, 0.5),
inset 0 0 8px rgba(0, 255, 255, 0.4);
}
66% {
box-shadow:
0 0 8px rgba(0, 255, 0, 0.5),
inset 0 0 8px rgba(0, 255, 0, 0.4);
}
100% {
box-shadow:
0 0 8px rgba(255, 0, 255, 0.5),
inset 0 0 8px rgba(255, 0, 255, 0.4);
}
}
#literature-text {
font-size: 1.2em;
line-height: 1.8;
min-height: 100px;
color: #e0e0e0;
text-shadow: 0 0 5px rgba(0, 255, 135, 0.5);
animation: text-flicker 15s linear infinite;
}
.body-animated #literature-text {
animation: text-flicker 15s linear infinite, text-shadow-glitch 2s steps(1, end) infinite;
}
@keyframes text-flicker {
0%, 100% { opacity: 1; }
50.0% { opacity: 0.95; }
50.5% { opacity: 1; }
}
@keyframes text-shadow-glitch {
0% {
text-shadow:
1px 0 0 rgba(255,0,255,0.5),
-1px 0 0 rgba(0,255,255,0.5);
}
10% {
text-shadow:
-1px 0 0 rgba(255,0,255,0.5),
1px 0 0 rgba(0,255,255,0.5);
}
11%, 100% {
text-shadow: none;
}
}
.controls {
margin-top: 30px;
display: flex;
align-items: center;
gap: 20px;
}
#new-literature-btn {
background-color: #ff00ff;
color: #fff;
border: none;
padding: 12px 25px;
font-size: 1em;
cursor: pointer;
border-radius: 5px;
text-transform: uppercase;
font-weight: bold;
transition: transform 0.2s, box-shadow 0.2s;
box-shadow: 0 0 10px #ff00ff, 0 0 20px #ff00ff;
}
#new-literature-btn:hover {
transform: scale(1.05);
box-shadow: 0 0 15px #ff00ff, 0 0 30px #ff00ff;
}
#new-literature-btn:active {
transform: scale(0.95);
}
/* Animation Toggle Switch */
.switch-container {
display: flex;
align-items: center;
gap: 10px;
color: #aaa;
}
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
}
input:checked + .slider {
background-color: #ff00ff;
}
input:checked + .slider:before {
transform: translateX(26px);
}
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
/* Glitch Overlay & Animations */
#glitch-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
pointer-events: none;
}
.body-animated #glitch-overlay {
animation: color-shift 15s steps(1, end) infinite;
}
@keyframes color-shift {
0%, 100% { background: transparent; }
10% { background: rgba(255, 0, 0, 0.05); }
10.1% { background: transparent; }
20% { background: rgba(0, 255, 0, 0.05); }
20.1% { background: transparent; }
30% { background: rgba(0, 0, 255, 0.05); }
30.1% { background: transparent; }
}
.flicker-block {
position: absolute;
background: rgba(255, 255, 255, 0.1);
opacity: 0;
}
.body-animated .flicker-block {
animation: flicker 3s infinite;
}
@keyframes flicker {
0%, 100% { opacity: 0; }
50% { opacity: 1; }
}
/* Responsive Design */
@media (max-width: 768px) {
.content-card {
padding: 20px;
}
#literature-text {
font-size: 1em;
}
.controls {
flex-direction: column;
}
}

View File

@@ -1,34 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>随机发病文学</title>
<link rel="stylesheet" href="css/background.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="bg-container">
</div>
<div id="glitch-overlay"></div>
<div class="container">
<div class="content-card">
<p id="literature-text">正在加载发病文学...</p>
</div>
<div class="controls">
<button id="new-literature-btn">再疯一次</button>
<div class="switch-container">
<label for="animation-toggle">关闭动画</label>
<label class="switch">
<input type="checkbox" id="animation-toggle" checked>
<span class="slider round"></span>
</label>
</div>
</div>
</div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -1,147 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
const literatureTextElem = document.getElementById('literature-text');
const newLiteratureBtn = document.getElementById('new-literature-btn');
const animationToggle = document.getElementById('animation-toggle');
const bgContainer = document.getElementById('bg-container');
const body = document.body;
const apiEndpoints = [
'https://60s.api.shumengya.top/v2/fabing',
// Add fallback APIs here if available
];
let currentApiIndex = 0;
async function fetchLiterature() {
literatureTextElem.textContent = '正在卖力发疯中...';
literatureTextElem.style.opacity = '0.5';
try {
const response = await fetch(apiEndpoints[currentApiIndex]);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
if (data.code === 200) {
literatureTextElem.textContent = data.data.saying;
} else {
throw new Error('API returned an error');
}
} catch (error) {
console.error('Fetch error:', error);
currentApiIndex = (currentApiIndex + 1) % apiEndpoints.length;
if (currentApiIndex !== 0) {
fetchLiterature(); // Retry with the next API
} else {
literatureTextElem.textContent = '疯不起来了,请稍后再试。';
}
} finally {
literatureTextElem.style.opacity = '1';
}
}
function createFloatingEmojis() {
const existingEmojis = bgContainer.querySelectorAll('.floating-emoji');
existingEmojis.forEach(e => e.remove());
const emojis = ['🤯', '😵', '🤪', '🥴', '🤡', '👹', '👻', '💀', '💥', '🔥', '🌪️', '😵‍💫'];
const animationNames = ['float-top-to-bottom', 'float-bottom-to-top', 'float-left-to-right', 'float-right-to-left'];
const emojiCount = 25;
for (let i = 0; i < emojiCount; i++) {
const emojiEl = document.createElement('div');
emojiEl.className = 'floating-emoji';
emojiEl.textContent = emojis[Math.floor(Math.random() * emojis.length)];
const animationName = animationNames[Math.floor(Math.random() * animationNames.length)];
emojiEl.style.animationName = animationName;
emojiEl.style.animationDuration = `${Math.random() * 10 + 15}s`; // 15-25 seconds
emojiEl.style.animationDelay = `${Math.random() * 20}s`;
emojiEl.style.fontSize = `${Math.random() * 20 + 20}px`;
// Set initial position based on animation direction
if (animationName.includes('top') || animationName.includes('bottom')) { // Vertical movement
emojiEl.style.left = `${Math.random() * 100}vw`;
} else { // Horizontal movement
emojiEl.style.top = `${Math.random() * 100}vh`;
}
bgContainer.appendChild(emojiEl);
}
}
function createFragments() {
const existingFragments = bgContainer.querySelectorAll('.text-fragment');
existingFragments.forEach(f => f.remove());
const fragments = ['我', '疯', '了', '', '', '…', '救命', '为什么', '好烦', '啊啊啊'];
for (let i = 0; i < 20; i++) {
const frag = document.createElement('div');
frag.className = 'text-fragment';
frag.textContent = fragments[Math.floor(Math.random() * fragments.length)];
frag.style.top = `${Math.random() * 100}%`;
frag.style.left = `${Math.random() * 100}%`;
frag.style.animationDelay = `${Math.random() * 15}s`;
frag.style.fontSize = `${Math.random() * 12 + 12}px`;
bgContainer.appendChild(frag);
}
}
function createCracks() {
for (let i = 0; i < 2; i++) {
const crack = document.createElement('div');
crack.className = 'screen-crack';
crack.style.top = `${Math.random() * 80}%`;
crack.style.left = `${Math.random() * 80}%`;
crack.style.transform = `rotate(${Math.random() * 360}deg)`;
crack.style.animationDelay = `${Math.random() * 25}s`;
bgContainer.appendChild(crack);
}
}
function createFlickerBlocks() {
const glitchOverlay = document.getElementById('glitch-overlay');
for (let i = 0; i < 3; i++) {
const block = document.createElement('div');
block.className = 'flicker-block';
block.style.width = `${Math.random() * 100 + 50}px`;
block.style.height = `${Math.random() * 100 + 50}px`;
block.style.top = `${Math.random() * 90}%`;
block.style.left = `${Math.random() * 90}%`;
block.style.animationDuration = `${Math.random() * 2 + 2}s`;
block.style.animationDelay = `${Math.random() * 3}s`;
glitchOverlay.appendChild(block);
}
}
function toggleAnimations() {
if (animationToggle.checked) {
body.classList.add('body-animated');
} else {
body.classList.remove('body-animated');
}
}
document.addEventListener('mousemove', (e) => {
if (!animationToggle.checked) return;
const x = (window.innerWidth / 2) - e.pageX;
const y = (window.innerHeight / 2) - e.pageY;
bgContainer.style.transform = `translateX(${x / 50}px) translateY(${y / 50}px)`;
});
newLiteratureBtn.addEventListener('click', fetchLiterature);
animationToggle.addEventListener('change', toggleAnimations);
// Initial setup
createFloatingEmojis();
createFragments();
createCracks();
createFlickerBlocks();
toggleAnimations();
fetchLiterature();
window.addEventListener('resize', () => {
createFloatingEmojis();
createFragments();
});
});

View File

@@ -1 +0,0 @@
["https://60s.api.shumengya.top"]

View File

@@ -1,8 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"index": 347,
"duanzi": "我不想读书,主要是因为家里牛啊,猪啊羊啊都没人喂。"
}
}

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>随机唱歌</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 68px)}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:36px 28px;text-align:center;border:1px solid rgba(34,197,94,.12);position:relative;width:100%}
.quote::before{content:'"';position:absolute;top:10px;left:20px;font-size:60px;color:rgba(34,197,94,.15);font-family:serif;line-height:1}
.quote-text{font-size:18px;line-height:2;color:#374151;font-weight:500}
.quote-src{font-size:12px;color:#9ca3af;margin-top:16px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px;width:100%}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px;width:100%}
@media(max-width:640px){.quote-text{font-size:15px}.quote{padding:28px 20px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🎤 随机唱歌</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/changya?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
let text='',source='';
if(typeof d==='string'){text=d}
else if(d&&typeof d==='object'){
for(const k of['content','text','hitokoto','duanzi','joke','saying','answer','kfc','data']){if(typeof d[k]==='string'){text=d[k];break}}
if(!text){for(const v of Object.values(d)){if(typeof v==='string'&&v.length>5){text=v;break}}}
if(!text)text=JSON.stringify(d,null,2);
source=d.from||d.source||d.author||'';
}else{text=String(d??'')}
el.innerHTML=`<div class="quote"><div class="quote-text">${text}</div>${source?`<div class="quote-src">—— ${source}</div>`:''}</div>`;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -1,251 +0,0 @@
/* 随机唱歌音频 - 淡绿色清新风格样式 */
/* 重置样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #a8e6cf 0%, #dcedc1 50%, #ffd3a5 100%);
min-height: 100vh;
color: #2d5016;
line-height: 1.6;
overflow-x: hidden;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 20px;
}
/* 头部 */
.header {
text-align: center;
margin-bottom: 20px;
background: rgba(255, 255, 255, 0.85);
border-radius: 20px;
padding: 24px;
box-shadow: 0 8px 25px rgba(45, 80, 22, 0.08);
backdrop-filter: blur(10px);
}
.header h1 {
font-size: 2rem;
color: #2d5016;
margin-bottom: 10px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
}
.header p {
color: #5a7c65;
font-size: 1rem;
}
/* 用户卡片 */
.user-card {
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
background: rgba(255, 255, 255, 0.9);
padding: 16px;
border-radius: 15px;
box-shadow: 0 4px 18px rgba(45, 80, 22, 0.08);
margin-bottom: 15px;
text-align: center;
}
.avatar {
width: 56px;
height: 56px;
border-radius: 50%;
object-fit: cover;
border: 3px solid rgba(129, 199, 132, 0.5);
}
.user-info {
display: flex;
flex-direction: column;
}
.nickname {
font-weight: 700;
font-size: 1.1rem;
color: #2d5016;
}
.meta {
color: #5a7c65;
font-size: 0.9rem;
}
/* 歌曲信息 */
.song-card {
background: rgba(255, 255, 255, 0.9);
padding: 16px;
border-radius: 15px;
box-shadow: 0 4px 18px rgba(45, 80, 22, 0.08);
margin-bottom: 15px;
text-align: center;
}
.song-title {
font-size: 1.2rem;
font-weight: 700;
margin-bottom: 8px;
color: #1b5e20;
}
.song-meta {
color: #5a7c65;
font-size: 0.95rem;
margin-bottom: 10px;
}
/* 歌词 */
.lyrics {
background: rgba(129, 199, 132, 0.1);
border-radius: 12px;
padding: 12px;
max-height: 220px;
overflow: auto;
}
.lyrics p {
margin-bottom: 6px;
}
/* 音频播放器卡片 */
.audio-card {
background: rgba(255, 255, 255, 0.9);
padding: 16px;
border-radius: 15px;
box-shadow: 0 4px 18px rgba(45, 80, 22, 0.08);
margin-bottom: 15px;
}
.audio-actions {
display: flex;
flex-direction: column;
gap: 12px;
align-items: center;
margin-top: 10px;
}
.btn {
background: linear-gradient(135deg, #81c784 0%, #66bb6a 100%);
color: white;
border: none;
padding: 10px 18px;
border-radius: 10px;
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition: all 0.25s ease;
box-shadow: 0 4px 12px rgba(129, 199, 132, 0.35);
text-decoration: none;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 18px rgba(129, 199, 132, 0.45);
}
.info {
color: #5a7c65;
font-size: 0.9rem;
}
/* 加载与错误 */
.loading, .error {
text-align: center;
padding: 30px;
background: rgba(255, 255, 255, 0.85);
border-radius: 15px;
box-shadow: 0 5px 20px rgba(45, 80, 22, 0.08);
}
.spinner {
width: 36px;
height: 36px;
border: 4px solid #e8f5e8;
border-top: 4px solid #81c784;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 18px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 动画 */
.fade-in {
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
/* 平板端适配 */
@media (max-width: 1024px) and (min-width: 768px) {
.container { padding: 16px; }
.header h1 { font-size: 1.8rem; }
}
/* 手机端优先优化 */
@media (max-width: 767px) {
.container { padding: 12px; }
.header { padding: 18px; }
.header h1 { font-size: 1.6rem; gap: 8px; }
.user-card {
padding: 16px;
flex-direction: column;
text-align: center;
}
.avatar {
width: 80px;
height: 80px;
margin-bottom: 8px;
}
.song-card, .audio-card {
padding: 16px;
}
.lyrics {
max-height: 180px;
text-align: left;
padding: 16px;
}
.audio-actions {
flex-direction: column;
gap: 15px;
align-items: center;
}
.info {
text-align: center;
line-height: 1.8;
}
.btn {
width: 100%;
max-width: 200px;
text-align: center;
}
}

View File

@@ -1,67 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>随机唱歌音频 - 60s API 集合</title>
<meta name="description" content="随机唱歌音频,数据源自 60s.viki.moe提供用户信息、歌曲信息、歌词与音频播放。" />
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<div class="container">
<header class="header">
<h1>
🎵 随机唱歌音频
</h1>
<p>数据来自官方/权威源头,以确保稳定与实时 · 支持本地数据回退</p>
</header>
<!-- 加载与错误状态 -->
<section id="loading" class="loading">
<div class="spinner"></div>
<p>正在加载中,请稍候…</p>
</section>
<section id="error" class="error" style="display: none;">
<p>获取数据失败,请稍后重试</p>
</section>
<!-- 内容区域 -->
<main id="content" style="display: none;" class="fade-in">
<!-- 用户信息 -->
<div class="user-card">
<img id="avatar" class="avatar" src="" alt="用户头像" />
<div class="user-info">
<div class="nickname" id="nickname">-</div>
<div class="meta">性别:<span id="gender">-</span></div>
</div>
</div>
<!-- 歌曲信息 -->
<div class="song-card">
<div class="song-title" id="song-title">-</div>
<div class="song-meta" id="song-meta">-</div>
<div class="lyrics" id="lyrics"></div>
</div>
<!-- 音频播放 -->
<div class="audio-card">
<audio id="audio" controls style="width: 100%;"></audio>
<div class="audio-actions">
<button class="btn" id="refresh-btn">换一首</button>
<div class="info">
❤ 喜欢:<span id="like-count">-</span>
· ⏱ 时长:<span id="duration">--:--</span>
· 🗓 发布:<span id="publish-time">-</span>
· 🔗 <a id="link" href="#" class="btn" style="padding: 6px 10px; border-radius: 8px; background: #81c784;">查看原帖</a>
</div>
</div>
</div>
</main>
</div>
<script src="./js/script.js"></script>
</body>
</html>

View File

@@ -1,252 +0,0 @@
// 随机唱歌音频 页面脚本
(function () {
'use strict';
const API = {
endpoints: [],
currentIndex: 0,
params: {
encoding: 'json'
},
localFallback: '返回接口.json',
// 初始化API接口列表
async init() {
try {
const res = await fetch('./接口集合.json');
const endpoints = await res.json();
this.endpoints = endpoints.map(endpoint => `${endpoint}/v2/changya`);
} catch (e) {
// 如果无法加载接口集合,使用默认接口
this.endpoints = ['https://60s.api.shumengya.top/v2/changya'];
}
},
// 获取当前接口URL
getCurrentUrl() {
if (this.endpoints.length === 0) return null;
const url = new URL(this.endpoints[this.currentIndex]);
Object.entries(this.params).forEach(([k, v]) => url.searchParams.append(k, v));
return url.toString();
},
// 切换到下一个接口
switchToNext() {
this.currentIndex = (this.currentIndex + 1) % this.endpoints.length;
return this.currentIndex < this.endpoints.length;
},
// 重置到第一个接口
reset() {
this.currentIndex = 0;
}
};
// DOM 元素引用
const els = {
loading: null,
error: null,
container: null,
avatar: null,
nickname: null,
gender: null,
songTitle: null,
songMeta: null,
lyrics: null,
audio: null,
likeCount: null,
publishTime: null,
link: null,
refreshBtn: null,
};
function initDom() {
els.loading = document.getElementById('loading');
els.error = document.getElementById('error');
els.container = document.getElementById('content');
els.avatar = document.getElementById('avatar');
els.nickname = document.getElementById('nickname');
els.gender = document.getElementById('gender');
els.songTitle = document.getElementById('song-title');
els.songMeta = document.getElementById('song-meta');
els.lyrics = document.getElementById('lyrics');
els.audio = document.getElementById('audio');
els.likeCount = document.getElementById('like-count');
els.publishTime = document.getElementById('publish-time');
els.link = document.getElementById('link');
els.refreshBtn = document.getElementById('refresh-btn');
}
function showLoading() {
els.loading.style.display = 'block';
els.error.style.display = 'none';
els.container.style.display = 'none';
}
function showError(msg) {
els.loading.style.display = 'none';
els.error.style.display = 'block';
els.container.style.display = 'none';
els.error.querySelector('p').textContent = msg || '获取数据失败,请稍后重试';
}
function showContent() {
els.loading.style.display = 'none';
els.error.style.display = 'none';
els.container.style.display = 'block';
}
function formatDuration(ms) {
if (!ms && ms !== 0) return '';
const totalSeconds = Math.floor(ms / 1000);
const m = Math.floor(totalSeconds / 60).toString().padStart(2, '0');
const s = (totalSeconds % 60).toString().padStart(2, '0');
return `${m}:${s}`;
}
function safeText(text) {
const div = document.createElement('div');
div.textContent = text == null ? '' : String(text);
return div.innerHTML;
}
async function fetchFromAPI() {
// 初始化API接口列表
await API.init();
// 重置API索引到第一个接口
API.reset();
// 尝试所有API接口
for (let i = 0; i < API.endpoints.length; i++) {
try {
const url = API.getCurrentUrl();
console.log(`尝试接口 ${i + 1}/${API.endpoints.length}: ${url}`);
const resp = await fetch(url, {
cache: 'no-store',
timeout: 10000 // 10秒超时
});
if (!resp.ok) {
throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
}
const data = await resp.json();
if (data && data.code === 200) {
console.log(`接口 ${i + 1} 请求成功`);
return data;
}
throw new Error(data && data.message ? data.message : '接口返回异常');
} catch (e) {
console.warn(`接口 ${i + 1} 失败:`, e.message);
// 如果不是最后一个接口,切换到下一个
if (i < API.endpoints.length - 1) {
API.switchToNext();
continue;
}
// 所有接口都失败了
console.warn('所有远程接口都失败,尝试本地数据');
return null;
}
}
}
async function fetchFromLocal() {
try {
const resp = await fetch(API.localFallback + `?t=${Date.now()}`);
if (!resp.ok) throw new Error(`本地文件HTTP ${resp.status}`);
const data = await resp.json();
return data;
} catch (e) {
console.error('读取本地返回接口.json失败:', e);
return null;
}
}
function render(data) {
const d = data?.data || {};
const user = d.user || {};
const song = d.song || {};
const audio = d.audio || {};
// 用户信息
els.avatar.src = user.avatar_url || '';
els.avatar.alt = (user.nickname || '用户') + ' 头像';
els.nickname.textContent = user.nickname || '未知用户';
els.gender.textContent = user.gender === 'female' ? '女' : user.gender === 'male' ? '男' : '未知';
// 歌曲信息
els.songTitle.textContent = song.name || '未知歌曲';
els.songMeta.textContent = song.singer ? `演唱:${song.singer}` : '';
els.lyrics.innerHTML = '';
if (Array.isArray(song.lyrics)) {
const frag = document.createDocumentFragment();
song.lyrics.forEach(line => {
const p = document.createElement('p');
p.innerHTML = safeText(line);
frag.appendChild(p);
});
els.lyrics.appendChild(frag);
}
// 音频
els.audio.src = audio.url || '';
els.audio.preload = 'none';
// 其他信息
els.likeCount.textContent = typeof audio.like_count === 'number' ? audio.like_count : '-';
const publish = audio.publish || (audio.publish_at ? new Date(audio.publish_at).toLocaleString() : '');
els.publishTime.textContent = publish;
els.link.href = audio.link || '#';
els.link.target = '_blank';
// 时长信息
const durationEl = document.getElementById('duration');
durationEl.textContent = formatDuration(audio.duration);
showContent();
}
async function load() {
showLoading();
try {
// 先尝试远程API
const data = await fetchFromAPI();
if (data) {
render(data);
return;
}
// 远程API失败尝试本地数据
const localData = await fetchFromLocal();
if (localData) {
render(localData);
return;
}
// 都失败了
showError('获取数据失败,请稍后重试');
} catch (e) {
console.error('加载数据时发生错误:', e);
showError('获取数据失败,请稍后重试');
}
}
function bindEvents() {
if (els.refreshBtn) {
els.refreshBtn.addEventListener('click', load);
}
// 快捷键 Ctrl+R 刷新(不拦截浏览器默认刷新)
}
document.addEventListener('DOMContentLoaded', () => {
initDom();
bindEvents();
load();
});
})();

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top"
]

View File

@@ -1,32 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"user": {
"nickname": "𝑮𝑺_迷鹿_",
"gender": "female",
"avatar_url": "http://img-cdn.api.singduck.cn/user-img/6afbebcfae6144478c150d0c1d0d5899.jpg"
},
"song": {
"name": "恶作剧",
"singer": "王蓝茵",
"lyrics": [
"我想我会开始想念你",
"可是我刚刚才遇见了你",
"我怀疑这奇遇只是个恶作剧",
"我想我已慢慢喜欢你",
"因为我拥有爱情的勇气",
"我任性投入你给的恶作剧",
"你给的恶作剧"
]
},
"audio": {
"url": "http://audio-cdn.api.singduck.cn/ugc/220929_965696173_b822a290c553.wav?auth_key=1755845643-0-0-4029539b73e17337dcac49cc4e0ecfcc",
"duration": 35050,
"like_count": 955,
"link": "https://m.api.singduck.cn/user-piece/toGZlBfZbukck2sHb",
"publish": "2022/09/29 18:33:51",
"publish_at": 1664447631000
}
}
}

View File

@@ -1,36 +0,0 @@
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
margin: 0;
min-height: 100vh;
overflow-x: hidden;
transition: background 0.5s ease;
}
/* Hand-drawn Comic Theme Background - FRESH GREEN VERSION */
body.theme-comic {
background: linear-gradient(-45deg, #c8e6c9, #dcedc8, #f1f8e9, #e8f5e8);
background-size: 400% 400%;
animation: gradientBG 15s ease infinite;
}
@keyframes gradientBG {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
/* Placeholder for Emoji Theme Background */
body.theme-emoji {
background-color: #fffde7;
}
/* Placeholder for Retro TV Theme Background */
body.theme-retro {
background-color: #3d2b1f;
}

View File

@@ -1,200 +0,0 @@
@import url('https://fonts.googleapis.com/css2?family=Zhi+Mang+Xing&display=swap');
/* --- General & Theme Switcher --- */
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
text-align: center;
}
.theme-switcher {
position: fixed;
top: 15px;
right: 15px;
display: flex;
gap: 5px;
background: rgba(255, 255, 255, 0.8);
padding: 5px;
border-radius: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 100;
}
.theme-icon {
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.2s ease;
border: 2px solid transparent;
}
.theme-icon.active {
border-color: #66bb6a;
transform: scale(1.1);
}
/* --- Comic Theme Styles --- */
.theme-comic header h1 {
font-family: 'Zhi Mang Xing', cursive;
font-size: 4em;
color: #2e7d32; /* Fresh Green */
text-shadow: 2px 2px 0 #fff;
margin: 0.2em 0;
}
.theme-comic .divider {
height: 3px;
background: linear-gradient(90deg, #81c784, #a5d6a7, #c8e6c9, #66bb6a);
border-radius: 3px;
margin: 20px auto;
width: 80%;
}
.theme-comic .joke-card {
background: rgba(248, 255, 248, 0.9); /* Light green tinted white */
backdrop-filter: blur(5px);
border-radius: 15px;
padding: 40px;
min-height: 200px;
box-shadow: 0 8px 25px rgba(102, 187, 106, 0.15);
display: flex;
justify-content: center;
align-items: center;
position: relative;
margin-bottom: 20px;
transform: rotate(-1deg);
transition: transform 0.2s ease;
border: 1px solid rgba(129, 199, 132, 0.3);
}
.theme-comic .joke-card:hover {
transform: rotate(1deg) scale(1.02);
}
.theme-comic .joke-text {
font-family: 'Zhi Mang Xing', cursive;
font-size: 2em;
line-height: 1.6;
color: #1b5e20;
}
.theme-comic .new-joke-btn {
background: linear-gradient(135deg, #66bb6a, #81c784); /* Fresh Green Gradient */
color: white;
font-family: 'Zhi Mang Xing', cursive;
font-size: 2.5em;
border: none;
border-radius: 50px;
padding: 10px 30px;
cursor: pointer;
box-shadow: 0 5px 0 #388e3c; /* Darker Green */
transition: all 0.1s ease-in-out;
}
.theme-comic .new-joke-btn:active {
transform: translateY(5px);
box-shadow: none;
}
/* --- Loading Animation --- */
.loading-container { display: none; }
.loading-container.visible { display: block; }
.loading-anim {
height: 60px;
width: 80px;
margin: 0 auto 10px;
}
.book {
transform-style: preserve-3d;
transform: rotateY(-30deg);
animation: flip 3s infinite;
}
.book, .book-page {
width: 40px;
height: 55px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -20px;
margin-top: -27.5px;
}
.book-page {
background: #a5d6a7;
border: 1px solid #66bb6a;
border-radius: 3px;
transform-origin: left;
}
.book-page:nth-child(1) { animation: flip-page 3s infinite; }
.book-page:nth-child(2) { animation: flip-page 3s -1s infinite; }
.book-page:nth-child(3) { animation: flip-page 3s -2s infinite; }
@keyframes flip { 50% { transform: rotateY(30deg); } }
@keyframes flip-page { 30%, 100% { transform: rotateY(180deg); } }
/* --- Feedback Buttons & Animations --- */
.feedback-buttons {
display: flex;
justify-content: center;
gap: 15px;
margin-bottom: 30px;
}
.feedback-btn {
background: none;
border: none;
font-size: 2em;
cursor: pointer;
transition: transform 0.2s ease;
}
.feedback-btn:hover { transform: scale(1.2); }
#animation-container {
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
pointer-events: none; z-index: 999;
}
.confetti, .snowflake {
position: absolute;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
.confetti {
width: 10px; height: 10px;
animation-name: fall;
}
.snowflake {
font-size: 20px; color: #fff;
animation-name: fall;
}
@keyframes fall {
from { transform: translateY(-10vh) rotate(0deg); }
to { transform: translateY(110vh) rotate(360deg); }
}
.joke-card.absurd {
animation: absurd-flash 0.5s 2;
}
@keyframes absurd-flash {
0%, 100% { border: 2px solid transparent; }
50% { border: 5px solid red; }
}
/* --- General Joke Text Visibility --- */
.joke-text {
opacity: 0;
transform: scale(0.9);
transition: opacity 0.4s ease, transform 0.4s ease;
}
.joke-text.visible {
opacity: 1;
transform: scale(1);
}
/* --- Responsive --- */
@media (max-width: 600px) {
.theme-comic header h1 { font-size: 3em; }
.theme-comic .joke-card { padding: 25px; transform: rotate(0); }
.theme-comic .joke-card:hover { transform: rotate(0); }
.theme-comic .joke-text { font-size: 1.5em; }
}

View File

@@ -1,57 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>段子游乐场</title>
<link rel="stylesheet" href="css/background.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body class="theme-comic"> <!-- Default Theme -->
<div class="theme-switcher">
<div class="theme-icon" data-theme="theme-comic" title="手绘漫画">✏️</div>
</div>
<div class="container">
<header>
<h1>段子游乐场</h1>
<div class="divider"></div>
</header>
<main>
<div id="joke-card" class="joke-card">
<div class="loading-container">
<div class="loading-anim">
<div class="book">
<div class="book-page"></div>
<div class="book-page"></div>
<div class="book-page"></div>
</div>
</div>
<p>段子菌正在翻笑话库...</p>
</div>
<p id="joke-text" class="joke-text"></p>
</div>
<div class="feedback-buttons">
<button id="btn-lol" class="feedback-btn" title="笑到拍桌">🤣</button>
<button id="btn-cold" class="feedback-btn" title="有点冷">🥶</button>
<button id="btn-seen" class="feedback-btn" title="似曾相识">🤔</button>
<button id="btn-absurd" class="feedback-btn" title="离谱但好笑">🤯</button>
</div>
<button id="new-joke-btn" class="new-joke-btn">
<span class="btn-text">再来一个!</span>
</button>
</main>
</div>
<!-- Animation & Sound Containers -->
<div id="animation-container"></div>
<audio id="sound-lol" src="https://www.myinstants.com/media/sounds/yay-6326.mp3" preload="auto"></audio>
<audio id="sound-cold" src="https://www.myinstants.com/media/sounds/zapsplat_cartoon_whoosh_fast_swoosh_001_76761.mp3" preload="auto"></audio>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -1,122 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
// Elements
const body = document.body;
const jokeTextElem = document.getElementById('joke-text');
const newJokeBtn = document.getElementById('new-joke-btn');
const loadingContainer = document.querySelector('.loading-container');
const animationContainer = document.getElementById('animation-container');
const jokeCard = document.getElementById('joke-card');
// API
const apiBaseUrls = ["https://60s.api.shumengya.top"];
const apiPath = "/v2/duanzi";
let currentApiIndex = 0;
// --- Core Functions ---
const showLoading = (isLoading) => {
loadingContainer.classList.toggle('visible', isLoading);
if (isLoading) jokeTextElem.classList.remove('visible');
};
const displayJoke = (joke) => {
jokeTextElem.textContent = joke;
showLoading(false);
setTimeout(() => jokeTextElem.classList.add('visible'), 50);
};
const fetchJoke = async () => {
showLoading(true);
try {
const url = apiBaseUrls[currentApiIndex] + apiPath;
const response = await fetch(url, { timeout: 5000 });
if (!response.ok) throw new Error('Network response was not ok');
const data = await response.json();
if (data.code === 200 && data.data && data.data.duanzi) {
displayJoke(data.data.duanzi);
} else {
throw new Error('Invalid data format');
}
} catch (error) {
console.error(`API error with ${apiBaseUrls[currentApiIndex]}:`, error);
currentApiIndex = (currentApiIndex + 1) % apiBaseUrls.length;
if (currentApiIndex !== 0) {
fetchJoke(); // Try next API
} else {
displayJoke('段子菌迷路了!点击‘再来一个’让它重新找路~');
}
}
};
// --- Theme Switcher ---
const themeSwitcher = document.querySelector('.theme-switcher');
themeSwitcher.addEventListener('click', (e) => {
if (e.target.classList.contains('theme-icon')) {
const theme = e.target.dataset.theme;
body.className = theme; // Set body class to the selected theme
// Update active icon
themeSwitcher.querySelectorAll('.theme-icon').forEach(icon => icon.classList.remove('active'));
e.target.classList.add('active');
alert(`主题已切换!部分主题(如表情包、复古电视)将在后续阶段实现。`);
}
});
// Set initial active theme icon
themeSwitcher.querySelector(`[data-theme="${body.className}"]`).classList.add('active');
// --- Feedback Buttons & Animations ---
const btnLol = document.getElementById('btn-lol');
const btnCold = document.getElementById('btn-cold');
const btnSeen = document.getElementById('btn-seen');
const btnAbsurd = document.getElementById('btn-absurd');
const soundLol = document.getElementById('sound-lol');
const soundCold = document.getElementById('sound-cold');
btnLol.addEventListener('click', () => {
soundLol.play();
createParticles(20, 'confetti');
});
btnCold.addEventListener('click', () => {
soundCold.play();
createParticles(15, 'snowflake');
});
btnSeen.addEventListener('click', () => {
displayJoke("原来你也听过!那再给你换个新鲜的~");
setTimeout(fetchJoke, 1500);
});
btnAbsurd.addEventListener('click', () => {
jokeCard.classList.add('absurd');
setTimeout(() => jokeCard.classList.remove('absurd'), 1000);
});
function createParticles(count, type) {
animationContainer.innerHTML = ''; // Clear previous
const colors = ['#ffca28', '#ff7043', '#29b6f6', '#66bb6a'];
for (let i = 0; i < count; i++) {
const particle = document.createElement('div');
particle.classList.add(type);
if (type === 'confetti') {
particle.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
} else {
particle.textContent = '❄️';
}
particle.style.left = `${Math.random() * 100}vw`;
const duration = Math.random() * 3 + 2; // 2-5 seconds
const delay = Math.random() * -duration; // Start at different times
particle.style.animationDuration = `${duration}s`;
particle.style.animationDelay = `${delay}s`;
animationContainer.appendChild(particle);
}
}
// --- Event Listeners ---
newJokeBtn.addEventListener('click', fetchJoke);
// --- Initial Load ---
fetchJoke();
});

View File

@@ -1 +0,0 @@
["https://60s.api.shumengya.top"]

View File

@@ -1,8 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"index": 347,
"duanzi": "我不想读书,主要是因为家里牛啊,猪啊羊啊都没人喂。"
}
}

View File

@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>随机段子</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 68px)}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:36px 28px;text-align:center;border:1px solid rgba(34,197,94,.12);position:relative;width:100%}
.quote::before{content:'"';position:absolute;top:10px;left:20px;font-size:60px;color:rgba(34,197,94,.15);font-family:serif;line-height:1}
.quote-text{font-size:18px;line-height:2;color:#374151;font-weight:500}
.quote-src{font-size:12px;color:#9ca3af;margin-top:16px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px;width:100%}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px;width:100%}
@media(max-width:640px){.quote-text{font-size:15px}.quote{padding:28px 20px}}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>😂 随机段子</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/duanzi?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
let text='',source='';
if(typeof d==='string'){text=d}
else if(d&&typeof d==='object'){
for(const k of['content','text','hitokoto','duanzi','joke','saying','answer','kfc','data']){if(typeof d[k]==='string'){text=d[k];break}}
if(!text){for(const v of Object.values(d)){if(typeof v==='string'&&v.length>5){text=v;break}}}
if(!text)text=JSON.stringify(d,null,2);
source=d.from||d.source||d.author||'';
}else{text=String(d??'')}
el.innerHTML=`<div class="quote"><div class="quote-text">${text}</div>${source?`<div class="quote-src">—— ${source}</div>`:''}</div>`;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -1,163 +0,0 @@
/* 随机答案之书 - 淡绿色清新风格样式(与随机唱歌音频一致) */
/* 重置样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #a8e6cf 0%, #dcedc1 50%, #ffd3a5 100%);
min-height: 100vh;
color: #2d5016;
line-height: 1.6;
overflow-x: hidden;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 20px;
}
/* 头部 */
.header {
text-align: center;
margin-bottom: 20px;
background: rgba(255, 255, 255, 0.85);
border-radius: 20px;
padding: 24px;
box-shadow: 0 8px 25px rgba(45, 80, 22, 0.08);
backdrop-filter: blur(10px);
}
.header h1 {
font-size: 2rem;
color: #2d5016;
margin-bottom: 10px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
}
.header p {
color: #5a7c65;
font-size: 1rem;
}
/* 按钮 */
.btn {
background: linear-gradient(135deg, #81c784 0%, #66bb6a 100%);
color: white;
border: none;
padding: 10px 18px;
border-radius: 10px;
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition: all 0.25s ease;
box-shadow: 0 4px 12px rgba(129, 199, 132, 0.35);
text-decoration: none;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 18px rgba(129, 199, 132, 0.45);
}
/* 加载与错误 */
.loading, .error {
text-align: center;
padding: 30px;
background: rgba(255, 255, 255, 0.85);
border-radius: 15px;
box-shadow: 0 5px 20px rgba(45, 80, 22, 0.08);
}
.spinner {
width: 36px;
height: 36px;
border: 4px solid #e8f5e8;
border-top: 4px solid #81c784;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 18px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 动画 */
.fade-in {
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
/* 答案卡片 */
.answer-card {
background: rgba(255, 255, 255, 0.9);
padding: 16px;
border-radius: 15px;
box-shadow: 0 4px 18px rgba(45, 80, 22, 0.08);
margin-bottom: 15px;
text-align: center;
}
.answer-text {
font-size: 1.4rem;
font-weight: 700;
margin-bottom: 8px;
color: #1b5e20;
word-break: break-word;
}
.answer-en {
color: #5a7c65;
font-size: 1rem;
margin-bottom: 10px;
}
.meta {
color: #5a7c65;
font-size: 0.95rem;
}
.actions {
display: flex;
gap: 12px;
align-items: center;
justify-content: center;
margin-top: 12px;
}
/* 手机端优先优化 */
@media (max-width: 767px) {
.container { padding: 12px; }
.header { padding: 18px; }
.header h1 { font-size: 1.6rem; gap: 8px; }
.answer-card { padding: 16px; }
.answer-text { font-size: 1.3rem; }
.answer-en { font-size: 0.95rem; }
.actions {
flex-direction: column;
gap: 15px;
}
.btn {
width: 100%;
max-width: 220px;
text-align: center;
}
}

View File

@@ -1,45 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>📘真理之道</title>
<meta name="description" content="当你踌躇不定,犹豫不决时,不妨来这里看看吧。" />
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<div class="container">
<header class="header">
<h1>📘真理之道</h1>
<p>当你踌躇不定,犹豫不决时,不妨来这里看看吧</p>
</header>
<!-- 加载与错误状态 -->
<section id="loading" class="loading">
<div class="spinner"></div>
<p>正在加载中,请稍候…</p>
</section>
<section id="error" class="error" style="display: none;">
<p>获取数据失败,请稍后重试</p>
</section>
<!-- 内容区域 -->
<main id="content" style="display: none;" class="fade-in">
<div class="answer-card">
<div class="answer-text" id="answer">-</div>
<div class="answer-en" id="answer-en" style="display: none;">-</div>
<div class="meta">编号:<span id="index">-</span></div>
<div class="actions">
<button class="btn" id="refresh-btn">换一个</button>
<button class="btn" id="copy-btn">复制</button>
</div>
</div>
</main>
</div>
<script src="./js/script.js"></script>
</body>
</html>

View File

@@ -1,224 +0,0 @@
// 随机答案之书 页面脚本
(function () {
'use strict';
const API = {
endpoints: [],
currentIndex: 0,
params: {
encoding: 'json'
},
localFallback: '返回接口.json',
// 初始化API接口列表
async init() {
try {
const res = await fetch('./接口集合.json');
const endpoints = await res.json();
this.endpoints = endpoints.map(endpoint => `${endpoint}/v2/answer`);
} catch (e) {
// 如果无法加载接口集合,使用默认接口
this.endpoints = ['https://60s.api.shumengya.top/v2/answer'];
}
},
// 获取当前接口URL
getCurrentUrl() {
if (this.endpoints.length === 0) return null;
const url = new URL(this.endpoints[this.currentIndex]);
Object.entries(this.params).forEach(([k, v]) => url.searchParams.append(k, v));
return url.toString();
},
// 切换到下一个接口
switchToNext() {
this.currentIndex = (this.currentIndex + 1) % this.endpoints.length;
return this.currentIndex < this.endpoints.length;
},
// 重置到第一个接口
reset() {
this.currentIndex = 0;
}
};
// DOM 元素引用
const els = {
loading: null,
error: null,
container: null,
answer: null,
answerEn: null,
indexEl: null,
refreshBtn: null,
copyBtn: null,
};
function initDom() {
els.loading = document.getElementById('loading');
els.error = document.getElementById('error');
els.container = document.getElementById('content');
els.answer = document.getElementById('answer');
els.answerEn = document.getElementById('answer-en');
els.indexEl = document.getElementById('index');
els.refreshBtn = document.getElementById('refresh-btn');
els.copyBtn = document.getElementById('copy-btn');
}
function showLoading() {
els.loading.style.display = 'block';
els.error.style.display = 'none';
els.container.style.display = 'none';
}
function showError(msg) {
els.loading.style.display = 'none';
els.error.style.display = 'block';
els.container.style.display = 'none';
els.error.querySelector('p').textContent = msg || '获取数据失败,请稍后重试';
}
function showContent() {
els.loading.style.display = 'none';
els.error.style.display = 'none';
els.container.style.display = 'block';
}
function safeText(text) {
const div = document.createElement('div');
div.textContent = text == null ? '' : String(text);
return div.innerHTML;
}
async function fetchFromAPI() {
// 初始化API接口列表
await API.init();
// 重置API索引到第一个接口
API.reset();
// 尝试所有API接口
for (let i = 0; i < API.endpoints.length; i++) {
try {
const url = API.getCurrentUrl();
console.log(`尝试接口 ${i + 1}/${API.endpoints.length}: ${url}`);
const resp = await fetch(url, {
cache: 'no-store',
timeout: 10000 // 10秒超时兼容同目录页面风格
});
if (!resp.ok) {
throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
}
const data = await resp.json();
if (data && data.code === 200) {
console.log(`接口 ${i + 1} 请求成功`);
return data;
}
throw new Error(data && data.message ? data.message : '接口返回异常');
} catch (e) {
console.warn(`接口 ${i + 1} 失败:`, e.message);
// 如果不是最后一个接口,切换到下一个
if (i < API.endpoints.length - 1) {
API.switchToNext();
continue;
}
// 所有接口都失败了
console.warn('所有远程接口都失败,尝试本地数据');
return null;
}
}
}
async function fetchFromLocal() {
try {
const resp = await fetch(API.localFallback + `?t=${Date.now()}`);
if (!resp.ok) throw new Error(`本地文件HTTP ${resp.status}`);
const data = await resp.json();
return data;
} catch (e) {
console.error('读取本地返回接口.json失败:', e);
return null;
}
}
function render(data) {
const d = data?.data || {};
const cn = d.answer || '';
const en = d.answer_en || '';
const idx = d.index != null ? d.index : d.id != null ? d.id : '-';
els.answer.innerHTML = safeText(cn || '-');
if (en) {
els.answerEn.style.display = 'block';
els.answerEn.innerHTML = safeText(en);
} else {
els.answerEn.style.display = 'none';
els.answerEn.innerHTML = '';
}
els.indexEl.textContent = idx;
showContent();
}
async function load() {
showLoading();
try {
// 先尝试远程API
const data = await fetchFromAPI();
if (data) {
render(data);
return;
}
// 远程API失败尝试本地数据
const localData = await fetchFromLocal();
if (localData) {
render(localData);
return;
}
// 都失败了
showError('获取数据失败,请稍后重试');
} catch (e) {
console.error('加载数据时发生错误:', e);
showError('获取数据失败,请稍后重试');
}
}
function bindEvents() {
if (els.refreshBtn) {
els.refreshBtn.addEventListener('click', load);
}
if (els.copyBtn) {
els.copyBtn.addEventListener('click', async () => {
const textParts = [];
const cn = els.answer?.textContent?.trim();
const en = els.answerEn?.textContent?.trim();
if (cn) textParts.push(cn);
if (en) textParts.push(en);
const finalText = textParts.join('\n');
try {
await navigator.clipboard.writeText(finalText);
const old = els.copyBtn.textContent;
els.copyBtn.textContent = '已复制';
setTimeout(() => { els.copyBtn.textContent = old; }, 1200);
} catch (e) {
alert('复制失败,请手动选择文本复制');
}
});
}
}
document.addEventListener('DOMContentLoaded', () => {
initDom();
bindEvents();
load();
});
})();

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top"
]

View File

@@ -1,10 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"id": "63",
"answer": "那不值得纠结",
"answer_en": "It's not worth worrying about",
"index": 62
}
}

View File

@@ -1,26 +0,0 @@
body {
background: linear-gradient(-45deg, #f1f8e9, #e8f5e8, #c8e6c9, #dcedc8);
background-size: 400% 400%;
animation: gradientBG 20s ease infinite;
color: #2e7d32;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
overflow-x: hidden;
}
@keyframes gradientBG {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}

View File

@@ -1,342 +0,0 @@
.container {
text-align: center;
padding: 20px;
max-width: 600px;
width: 100%;
box-sizing: border-box;
}
header h1 {
font-size: 2.8em;
color: #2e7d32;
text-shadow: 0 0 10px #81c784, 0 0 20px #a5d6a7;
margin-bottom: 0.2em;
}
header p {
font-size: 1.2em;
color: #388e3c;
margin-bottom: 40px;
}
.crystal-ball-container {
perspective: 1000px;
margin-bottom: 40px;
}
.crystal-ball {
width: 200px;
height: 200px;
background: radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.6), rgba(200, 230, 201, 0.3));
border-radius: 50%;
margin: 0 auto;
position: relative;
box-shadow: 0 0 30px #81c784, 0 0 60px #66bb6a, inset 0 0 20px rgba(220, 255, 220, 0.3);
animation: float 6s ease-in-out infinite;
transform-style: preserve-3d;
}
.reflection {
width: 80px;
height: 40px;
background: rgba(255, 255, 255, 0.3);
border-radius: 50%;
position: absolute;
top: 20px;
left: 40px;
transform: rotate(-30deg);
filter: blur(5px);
}
.swirl {
position: absolute;
top: 50%;
left: 50%;
width: 120%;
height: 120%;
background: linear-gradient(45deg, rgba(200, 230, 201, 0.2), rgba(129, 199, 132, 0.3));
border-radius: 50%;
animation: swirl 10s linear infinite;
transform: translate(-50%, -50%);
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-20px); }
}
@keyframes swirl {
from { transform: translate(-50%, -50%) rotate(0deg); }
to { transform: translate(-50%, -50%) rotate(360deg); }
}
.fortune-card {
background: rgba(248, 255, 248, 0.8);
border-radius: 15px;
padding: 30px;
margin-bottom: 30px;
min-height: 120px;
display: flex;
justify-content: center;
align-items: center;
backdrop-filter: blur(10px);
border: 1px solid rgba(129, 199, 132, 0.3);
box-shadow: 0 8px 32px 0 rgba(102, 187, 106, 0.2);
transition: opacity 0.5s ease-in-out;
}
.fortune-content {
opacity: 0;
transition: opacity 0.5s ease-in-out;
}
.fortune-content.visible {
opacity: 1;
}
#luck-desc {
font-size: 2em;
color: #2e7d32;
margin: 0 0 10px;
}
#luck-tip {
font-size: 1.1em;
color: #388e3c;
margin: 0;
padding-bottom: 20px; /* Add some space before the new details */
}
.fortune-details {
display: flex;
justify-content: space-around;
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid rgba(255, 255, 255, 0.2);
}
.detail-item {
text-align: center;
}
.detail-item h3 {
font-size: 0.9em;
color: #66bb6a;
margin: 0 0 5px;
font-weight: normal;
}
.detail-item p {
font-size: 1.2em;
margin: 0;
font-weight: bold;
}
#lucky-color {
display: inline-block;
width: 24px;
height: 24px;
border-radius: 50%;
border: 2px solid white;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
/* Remove the text content */
font-size: 0;
}
/* Tarot Card Styles */
.tarot-container {
margin-top: 40px;
margin-bottom: 40px;
}
.tarot-container h2 {
font-size: 1.5em;
color: #2e7d32;
text-shadow: 0 0 8px #81c784;
margin-bottom: 20px;
}
.tarot-card-container {
width: 180px;
height: 280px;
perspective: 1000px;
margin: 0 auto;
cursor: pointer;
}
.tarot-card-inner {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.8s;
transform-style: preserve-3d;
}
.tarot-card-container.flipped .tarot-card-inner {
transform: rotateY(180deg);
}
.tarot-card-front,
.tarot-card-back {
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
}
.tarot-card-back {
background: linear-gradient(135deg, #66bb6a, #388e3c);
border: 2px solid #81c784;
display: flex;
justify-content: center;
align-items: center;
font-size: 3em;
color: #c8e6c9;
}
.tarot-card-back::after {
content: '✧'; /* A simple star symbol */
text-shadow: 0 0 10px #e8f5e8;
}
.tarot-card-front {
background: linear-gradient(135deg, #4caf50, #66bb6a);
border: 2px solid #81c784;
color: white;
transform: rotateY(180deg);
padding: 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#tarot-name {
font-size: 1.4em;
color: #e8f5e8;
margin: 0 0 10px;
}
#tarot-interpretation {
font-size: 0.9em;
text-align: center;
margin: 0;
}
/* Side Decorations */
.side-decor {
position: fixed;
top: 0;
bottom: 0;
width: 15vw;
height: 100vh;
pointer-events: none;
z-index: 0;
}
.left-decor {
left: 0;
}
.right-decor {
right: 0;
}
.decor-symbol {
position: absolute;
color: rgba(129, 199, 132, 0.5);
text-shadow: 0 0 10px rgba(200, 230, 201, 0.7);
animation: floatSymbol 20s infinite ease-in-out;
}
@keyframes floatSymbol {
0%, 100% {
transform: translateY(0) rotate(0deg);
opacity: 0;
}
25%, 75% {
opacity: 0.8;
}
50% {
transform: translateY(-20vh) rotate(180deg);
opacity: 0.3;
}
}
#get-fortune-btn {
background: linear-gradient(45deg, #66bb6a, #4caf50);
color: white;
border: none;
border-radius: 50px;
padding: 15px 30px;
font-size: 1.1em;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
box-shadow: 0 0 15px #81c784;
}
#get-fortune-btn:hover {
transform: scale(1.05);
box-shadow: 0 0 25px #a5d6a7;
}
#get-fortune-btn:active {
transform: scale(0.98);
}
.loading-spinner {
border: 4px solid rgba(129, 199, 132, 0.3);
border-left-color: #66bb6a;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
display: none; /* Hidden by default */
}
.loading-spinner.visible {
display: block;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
footer {
margin-top: 40px;
color: rgba(46, 125, 50, 0.7);
}
/* Responsive Design */
@media (max-width: 768px) {
header h1 {
font-size: 2.2em;
}
.crystal-ball {
width: 150px;
height: 150px;
}
.fortune-card {
padding: 20px;
}
.fortune-details {
flex-direction: column;
gap: 15px;
}
.tarot-card-container {
width: 150px;
height: 233px;
}
}
/* Hide side decor on smaller screens */
@media (max-width: 1200px) {
.side-decor {
display: none;
}
}

View File

@@ -1,71 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>水晶球占卜</title>
<link rel="stylesheet" href="css/background.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="side-decor left-decor"></div>
<div class="container">
<header>
<h1>水晶球占卜</h1>
<p>洞察你今日的运势</p>
</header>
<main>
<div class="crystal-ball-container">
<div class="crystal-ball">
<div class="reflection"></div>
<div class="swirl"></div>
</div>
</div>
<div id="fortune-card" class="fortune-card">
<div class="loading-spinner"></div>
<div class="fortune-content">
<h2 id="luck-desc"></h2>
<p id="luck-tip"></p>
<div class="fortune-details">
<div class="detail-item">
<h3>今日咒语</h3>
<p id="fortune-summary"></p>
</div>
<div class="detail-item">
<h3>幸运色</h3>
<p id="lucky-color"></p>
</div>
<div class="detail-item">
<h3>幸运数字</h3>
<p id="lucky-number"></p>
</div>
</div>
</div>
</div>
<!-- New Tarot Card Section -->
<div class="tarot-container">
<h2>每日塔罗指引</h2>
<div id="tarot-card" class="tarot-card-container">
<div class="tarot-card-inner">
<div class="tarot-card-back">
<!-- Back of the card design -->
</div>
<div class="tarot-card-front">
<h3 id="tarot-name"></h3>
<p id="tarot-interpretation"></p>
</div>
</div>
</div>
</div>
<button id="get-fortune-btn">再次占卜</button>
</main>
<footer>
<p>仅供娱乐,祝您好运</p>
</footer>
</div>
<div class="side-decor right-decor"></div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -1,170 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
const getFortuneBtn = document.getElementById('get-fortune-btn');
const fortuneCard = document.getElementById('fortune-card');
const fortuneContent = fortuneCard.querySelector('.fortune-content');
const luckDescElem = document.getElementById('luck-desc');
const luckTipElem = document.getElementById('luck-tip');
const fortuneSummaryElem = document.getElementById('fortune-summary');
const luckyColorElem = document.getElementById('lucky-color');
const luckyNumberElem = document.getElementById('lucky-number');
const loadingSpinner = fortuneCard.querySelector('.loading-spinner');
const tarotCardContainer = document.getElementById('tarot-card');
const tarotNameElem = document.getElementById('tarot-name');
const tarotInterpretationElem = document.getElementById('tarot-interpretation');
const apiBaseUrls = [
"https://60s.api.shumengya.top",
];
const apiPath = "/v2/luck";
const mantras = [
"顺其自然,皆是美好。",
"相信直觉,它知道方向。",
"每一次呼吸都是新的开始。",
"心怀感恩,好运自来。",
"拥抱变化,发现惊喜。",
"你的能量,超乎想象。",
"保持微笑,宇宙会回应你。"
];
const tarotDeck = [
{ name: "愚者", interpretation: "新的开始,无限的潜力,天真和自由。勇敢地迈出第一步。" },
{ name: "魔术师", interpretation: "创造力,意志力,显化。你拥有实现目标所需的一切资源。" },
{ name: "女祭司", interpretation: "直觉,潜意识,神秘。倾听你内心的声音,智慧在你之内。" },
{ name: "皇后", interpretation: "丰饶,母性,创造。享受生活的美好,与自然和谐相处。" },
{ name: "皇帝", interpretation: "权威,结构,控制。建立秩序和纪律,掌控你的生活。" },
{ name: "教皇", interpretation: "传统,信仰,灵性指导。寻求智慧和知识,遵循传统。" },
{ name: "恋人", interpretation: "爱,和谐,选择。做出与你内心价值观一致的决定。" },
{ name: "战车", interpretation: "胜利,决心,控制。以坚定的意志力克服障碍,勇往直前。" },
{ name: "力量", interpretation: "勇气,内在力量,同情。用温柔和耐心驯服内心的野兽。" },
{ name: "隐士", interpretation: "内省,孤独,寻求真理。花时间独处,向内寻求答案。" },
{ name: "命运之轮", interpretation: "变化,命运,转折点。生活总在变化,顺应潮流。" },
{ name: "正义", interpretation: "公平,真理,因果。为你的行为负责,寻求平衡。" },
{ name: "倒吊人", interpretation: "新的视角,顺从,牺牲。放手,从不同的角度看问题。" },
{ name: "死神", interpretation: "结束,转变,新生。一个周期的结束是另一个周期的开始。" },
{ name: "节制", interpretation: "平衡,和谐,耐心。融合对立的力量,找到中间道路。" },
{ name: "恶魔", interpretation: "束缚,物质主义,诱惑。认识到你的束缚,并寻求解放。" },
{ name: "塔", interpretation: "突变,启示,解放。旧的结构正在崩塌,为新的结构让路。" },
{ name: "星星", interpretation: "希望,灵感,平静。在黑暗之后,总有希望的曙光。" },
{ name: "月亮", interpretation: "幻觉,恐惧,潜意识。面对你的恐惧,相信你的直觉。" },
{ name: "太阳", interpretation: "成功,喜悦,活力。拥抱光明,享受生活的乐趣。" },
{ name: "审判", interpretation: "觉醒,重生,评估。一个反思和更新的时刻。" },
{ name: "世界", interpretation: "完成,整合,成就。一个旅程的成功结束,庆祝你的成就。" }
];
let currentApiIndex = 0;
const showLoading = (isLoading) => {
if (isLoading) {
fortuneContent.classList.remove('visible');
loadingSpinner.classList.add('visible');
} else {
loadingSpinner.classList.remove('visible');
setTimeout(() => {
fortuneContent.classList.add('visible');
}, 100);
}
};
const fetchFortune = async () => {
showLoading(true);
tarotCardContainer.classList.remove('flipped'); // Reset card on new fetch
try {
const url = apiBaseUrls[currentApiIndex] + apiPath;
const response = await fetch(url, { timeout: 5000 });
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
if (data.code === 200 && data.data) {
updateFortune(data.data);
drawTarotCard(); // Draw a tarot card on success
} else {
throw new Error('Invalid data format');
}
} catch (error) {
console.error(`API error with ${apiBaseUrls[currentApiIndex]}:`, error);
currentApiIndex = (currentApiIndex + 1) % apiBaseUrls.length;
if (currentApiIndex !== 0) {
fetchFortune(); // Try next API
} else {
displayError();
}
}
};
const updateFortune = (data) => {
luckDescElem.textContent = data.luck_desc || '运势';
luckTipElem.textContent = data.luck_tip || '今日运势平平,保持好心情。';
// Generate and display additional details
fortuneSummaryElem.textContent = mantras[Math.floor(Math.random() * mantras.length)];
luckyColorElem.style.backgroundColor = `#${Math.floor(Math.random()*16777215).toString(16).padStart(6, '0')}`;
luckyNumberElem.textContent = Math.floor(Math.random() * 100);
showLoading(false);
};
const displayError = () => {
luckDescElem.textContent = '占卜失败';
luckTipElem.textContent = '无法连接到星辰之力,请稍后再试。';
fortuneSummaryElem.textContent = '---';
luckyColorElem.style.backgroundColor = 'transparent';
luckyNumberElem.textContent = '-';
showLoading(false);
tarotNameElem.textContent = '指引中断';
tarotInterpretationElem.textContent = '星辰之力暂时无法连接。';
tarotCardContainer.classList.add('flipped'); // Show error on card
};
const drawTarotCard = () => {
const card = tarotDeck[Math.floor(Math.random() * tarotDeck.length)];
tarotNameElem.textContent = card.name;
tarotInterpretationElem.textContent = card.interpretation;
// Flip the card after a short delay to allow the main content to appear
setTimeout(() => {
tarotCardContainer.classList.add('flipped');
}, 500);
};
const createSideDecorations = () => {
const leftContainer = document.querySelector('.left-decor');
const rightContainer = document.querySelector('.right-decor');
if (!leftContainer || !rightContainer) return;
const symbols = ['✧', '✦', '☾', '✶', '✵', '✩', '✨'];
const symbolCount = 15; // Number of symbols per side
const createSymbols = (container) => {
for (let i = 0; i < symbolCount; i++) {
const symbol = document.createElement('span');
symbol.classList.add('decor-symbol');
symbol.textContent = symbols[Math.floor(Math.random() * symbols.length)];
// Randomize properties for a more natural look
symbol.style.top = `${Math.random() * 90}vh`;
symbol.style.left = `${Math.random() * 80}%`;
symbol.style.fontSize = `${Math.random() * 20 + 10}px`;
symbol.style.animationDelay = `${Math.random() * 20}s`;
symbol.style.animationDuration = `${Math.random() * 20 + 15}s`; // Duration between 15s and 35s
container.appendChild(symbol);
}
};
createSymbols(leftContainer);
createSymbols(rightContainer);
};
getFortuneBtn.addEventListener('click', fetchFortune);
tarotCardContainer.addEventListener('click', () => {
tarotCardContainer.classList.toggle('flipped');
});
// Initial actions on page load
fetchFortune();
createSideDecorations();
});

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top"
]

View File

@@ -1,10 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"luck_desc": "恋愛運",
"luck_rank": 21,
"luck_tip": "闪亮的邂逅之日!顺其自然吧",
"luck_tip_index": 19
}
}

View File

@@ -1,330 +0,0 @@
/* Epic Games 免费游戏 - 淡绿色清新风格样式 */
/* 重置样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #a8e6cf 0%, #dcedc1 50%, #ffd3a5 100%);
min-height: 100vh;
color: #2d5016;
line-height: 1.6;
overflow-x: hidden;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* 头部 */
.header {
text-align: center;
margin-bottom: 30px;
background: rgba(255, 255, 255, 0.85);
border-radius: 20px;
padding: 24px;
box-shadow: 0 8px 25px rgba(45, 80, 22, 0.08);
backdrop-filter: blur(10px);
}
.header h1 {
font-size: 2.2rem;
color: #2d5016;
margin-bottom: 10px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
}
.header p {
color: #5a7c65;
font-size: 1rem;
}
/* 统计信息 */
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 25px;
}
.stat-card {
background: rgba(255, 255, 255, 0.9);
padding: 16px;
border-radius: 15px;
text-align: center;
box-shadow: 0 4px 18px rgba(45, 80, 22, 0.08);
}
.stat-number {
font-size: 1.8rem;
font-weight: 700;
color: #1b5e20;
margin-bottom: 5px;
}
.stat-label {
color: #5a7c65;
font-size: 0.9rem;
}
/* 游戏网格 */
.games-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
/* 游戏卡片 */
.game-card {
background: rgba(255, 255, 255, 0.95);
border-radius: 18px;
overflow: hidden;
box-shadow: 0 6px 25px rgba(45, 80, 22, 0.1);
transition: all 0.3s ease;
position: relative;
}
.game-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 35px rgba(45, 80, 22, 0.15);
}
.game-cover {
width: 100%;
height: 180px;
object-fit: cover;
border-radius: 0;
}
.game-info {
padding: 18px;
}
.game-title {
font-size: 1.1rem;
font-weight: 700;
color: #1b5e20;
margin-bottom: 8px;
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.game-description {
color: #5a7c65;
font-size: 0.9rem;
margin-bottom: 12px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 1.4;
}
.game-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.game-price {
font-size: 1rem;
font-weight: 600;
}
.original-price {
color: #81c784;
text-decoration: line-through;
}
.free-price {
color: #2e7d32;
font-weight: 700;
}
.game-seller {
color: #5a7c65;
font-size: 0.85rem;
}
.game-dates {
background: rgba(129, 199, 132, 0.1);
padding: 10px;
border-radius: 10px;
margin-bottom: 12px;
font-size: 0.85rem;
color: #2d5016;
}
.free-period {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
}
.game-actions {
display: flex;
gap: 10px;
}
.btn {
flex: 1;
background: linear-gradient(135deg, #81c784 0%, #66bb6a 100%);
color: white;
border: none;
padding: 10px 16px;
border-radius: 10px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: all 0.25s ease;
box-shadow: 0 4px 12px rgba(129, 199, 132, 0.35);
text-decoration: none;
text-align: center;
display: inline-block;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 18px rgba(129, 199, 132, 0.45);
}
.btn-secondary {
background: linear-gradient(135deg, #a5d6a7 0%, #81c784 100%);
}
/* 状态标签 */
.status-badge {
position: absolute;
top: 12px;
right: 12px;
padding: 6px 12px;
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
color: white;
text-shadow: 0 1px 2px rgba(0,0,0,0.2);
}
.status-free {
background: linear-gradient(135deg, #4caf50 0%, #2e7d32 100%);
}
.status-upcoming {
background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
}
/* 加载与错误 */
.loading, .error {
text-align: center;
padding: 40px;
background: rgba(255, 255, 255, 0.85);
border-radius: 15px;
box-shadow: 0 5px 20px rgba(45, 80, 22, 0.08);
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #e8f5e8;
border-top: 4px solid #81c784;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 动画 */
.fade-in {
animation: fadeIn 0.6s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* 平板端适配 */
@media (max-width: 1024px) and (min-width: 768px) {
.container { padding: 16px; }
.header h1 { font-size: 2rem; }
.games-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
}
/* 手机端优化 */
@media (max-width: 767px) {
.container { padding: 12px; }
.header { padding: 18px; }
.header h1 { font-size: 1.8rem; gap: 8px; }
.stats {
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 8px;
}
.stat-card {
padding: 10px 8px;
flex: 1;
min-width: 0;
}
.stat-number { font-size: 1.4rem; }
.stat-label { font-size: 0.75rem; }
.games-grid {
grid-template-columns: 1fr;
gap: 16px;
}
.game-card { margin: 0 4px; }
.game-cover { height: 160px; }
.game-info { padding: 14px; }
.game-actions {
flex-direction: column;
}
.btn {
width: 100%;
padding: 12px;
}
}
/* 小屏手机优化 */
@media (max-width: 480px) {
.stats {
grid-template-columns: 1fr;
}
.game-meta {
flex-direction: column;
align-items: flex-start;
gap: 6px;
}
}
/* 高分辨率显示器优化 */
@media (min-width: 1400px) {
.games-grid {
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
}
}

View File

@@ -1,63 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Epic Games 免费游戏 - 60s API 集合</title>
<meta name="description" content="Epic Games 免费游戏列表,数据源自 60s.viki.moe提供当前免费和即将免费的游戏信息。" />
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<div class="container">
<header class="header">
<h1>
🎮 Epic Games 免费游戏
</h1>
</header>
<!-- 加载与错误状态 -->
<section id="loading" class="loading">
<div class="spinner"></div>
<p>正在加载游戏数据,请稍候…</p>
</section>
<section id="error" class="error" style="display: none;">
<p>获取数据失败,请稍后重试</p>
<button id="refresh-btn" class="btn" style="margin-top: 15px;">重新加载</button>
</section>
<!-- 内容区域 -->
<main id="content" style="display: none;" class="fade-in">
<!-- 统计信息 -->
<div class="stats">
<div class="stat-card">
<div class="stat-number" id="total-games">0</div>
<div class="stat-label">总游戏数</div>
</div>
<div class="stat-card">
<div class="stat-number" id="free-now">0</div>
<div class="stat-label">当前免费</div>
</div>
<div class="stat-card">
<div class="stat-number" id="upcoming">0</div>
<div class="stat-label">即将免费</div>
</div>
</div>
<!-- 游戏列表 -->
<div class="games-grid" id="games-grid">
<!-- 游戏卡片将通过 JavaScript 动态生成 -->
</div>
<!-- 刷新按钮 -->
<div style="text-align: center; margin-top: 30px;">
<button id="refresh-btn" class="btn btn-secondary">🔄 刷新数据</button>
</div>
</main>
</div>
<script src="./js/script.js"></script>
</body>
</html>

View File

@@ -1,266 +0,0 @@
// Epic Games 免费游戏 页面脚本
(function () {
'use strict';
const API = {
endpoints: [],
currentIndex: 0,
// 初始化API接口列表
async init() {
try {
const res = await fetch('./接口集合.json');
const endpoints = await res.json();
this.endpoints = endpoints.map(endpoint => `${endpoint}/v2/epic`);
} catch (e) {
// 如果无法加载接口集合,使用默认接口
this.endpoints = ['https://60s.api.shumengya.top/v2/epic'];
}
},
// 获取当前接口URL
getCurrentUrl(encoding) {
if (this.endpoints.length === 0) return null;
const url = new URL(this.endpoints[this.currentIndex]);
if (encoding) url.searchParams.set('encoding', encoding);
return url.toString();
},
// 切换到下一个接口
switchToNext() {
this.currentIndex = (this.currentIndex + 1) % this.endpoints.length;
return this.currentIndex < this.endpoints.length;
},
// 重置到第一个接口
reset() {
this.currentIndex = 0;
}
};
// DOM 元素引用
const els = {
loading: null,
error: null,
container: null,
gamesGrid: null,
totalGames: null,
freeNow: null,
upcoming: null,
refreshBtn: null,
};
function initDom() {
els.loading = document.getElementById('loading');
els.error = document.getElementById('error');
els.container = document.getElementById('content');
els.gamesGrid = document.getElementById('games-grid');
els.totalGames = document.getElementById('total-games');
els.freeNow = document.getElementById('free-now');
els.upcoming = document.getElementById('upcoming');
els.refreshBtn = document.getElementById('refresh-btn');
}
function showLoading() {
els.loading.style.display = 'block';
els.error.style.display = 'none';
els.container.style.display = 'none';
}
function showError(msg) {
els.loading.style.display = 'none';
els.error.style.display = 'block';
els.container.style.display = 'none';
els.error.querySelector('p').textContent = msg || '获取数据失败,请稍后重试';
}
function showContent() {
els.loading.style.display = 'none';
els.error.style.display = 'none';
els.container.style.display = 'block';
}
function safeText(text) {
const div = document.createElement('div');
div.textContent = text == null ? '' : String(text);
return div.innerHTML;
}
function formatDate(dateStr) {
if (!dateStr) return '';
try {
const date = new Date(dateStr);
return date.toLocaleDateString('zh-CN', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
} catch (e) {
return dateStr;
}
}
async function fetchData(preferLocal = false) {
if (preferLocal) {
try {
const res = await fetch('./返回接口.json', { cache: 'no-store' });
const json = await res.json();
return json;
} catch (e) {
throw new Error('本地数据加载失败');
}
}
// 重置API索引到第一个接口
API.reset();
// 尝试所有API接口
for (let i = 0; i < API.endpoints.length; i++) {
try {
const url = API.getCurrentUrl();
console.log(`尝试接口 ${i + 1}/${API.endpoints.length}: ${url}`);
const res = await fetch(url, {
cache: 'no-store',
timeout: 10000 // 10秒超时
});
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
const json = await res.json();
if (json && json.code === 200) {
console.log(`接口 ${i + 1} 请求成功`);
return json;
}
throw new Error(json && json.message ? json.message : '接口返回异常');
} catch (e) {
console.warn(`接口 ${i + 1} 失败:`, e.message);
// 如果不是最后一个接口,切换到下一个
if (i < API.endpoints.length - 1) {
API.switchToNext();
continue;
}
// 所有接口都失败了,尝试本地数据
console.warn('所有远程接口都失败,尝试本地数据');
try {
const res = await fetch('./返回接口.json', { cache: 'no-store' });
const json = await res.json();
return json;
} catch (e2) {
throw new Error('所有接口和本地数据都无法访问');
}
}
}
}
function createGameCard(game) {
const isFree = game.is_free_now;
const statusClass = isFree ? 'status-free' : 'status-upcoming';
const statusText = isFree ? '限时免费' : '即将免费';
return `
<div class="game-card fade-in">
<div class="status-badge ${statusClass}">${statusText}</div>
<img class="game-cover" src="${safeText(game.cover)}" alt="${safeText(game.title)} 封面" loading="lazy" />
<div class="game-info">
<h3 class="game-title">${safeText(game.title)}</h3>
<p class="game-description">${safeText(game.description)}</p>
<div class="game-meta">
<div class="game-price">
<span class="original-price">${safeText(game.original_price_desc)}</span>
<span class="free-price">免费</span>
</div>
<div class="game-seller">${safeText(game.seller)}</div>
</div>
<div class="game-dates">
<div class="free-period">
<span>开始:${formatDate(game.free_start)}</span>
<span>结束:${formatDate(game.free_end)}</span>
</div>
</div>
<div class="game-actions">
<a href="${safeText(game.link)}" target="_blank" class="btn">
${isFree ? '立即领取' : '查看详情'}
</a>
</div>
</div>
</div>
`;
}
function updateStats(games) {
const total = games.length;
const freeNow = games.filter(game => game.is_free_now).length;
const upcoming = total - freeNow;
els.totalGames.textContent = total;
els.freeNow.textContent = freeNow;
els.upcoming.textContent = upcoming;
}
function renderGames(games) {
if (!Array.isArray(games) || games.length === 0) {
els.gamesGrid.innerHTML = '<div style="grid-column: 1/-1; text-align: center; padding: 40px; color: #5a7c65;">暂无游戏数据</div>';
return;
}
// 按状态排序:免费的在前
const sortedGames = [...games].sort((a, b) => {
if (a.is_free_now && !b.is_free_now) return -1;
if (!a.is_free_now && b.is_free_now) return 1;
return 0;
});
const html = sortedGames.map(game => createGameCard(game)).join('');
els.gamesGrid.innerHTML = html;
updateStats(games);
}
function render(data) {
const games = data?.data || [];
renderGames(games);
showContent();
}
async function load() {
showLoading();
// 初始化API接口列表
await API.init();
try {
const data = await fetchData(false);
render(data);
} catch (e) {
console.error('数据获取失败:', e);
showError(e.message || '获取数据失败,请稍后重试');
}
}
function bindEvents() {
if (els.refreshBtn) {
els.refreshBtn.addEventListener('click', load);
}
// 快捷键 Ctrl+R 刷新(不拦截浏览器默认刷新)
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 'r' && !e.defaultPrevented) {
// 不阻止默认行为,让浏览器正常刷新
}
});
}
document.addEventListener('DOMContentLoaded', () => {
initDom();
bindEvents();
load();
});
})();

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top"
]

View File

@@ -1,66 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": [
{
"id": "9aa227e2ba294bb1a95c95fde892eb31",
"title": "《Totally Reliable Delivery Service》 Standard Edition",
"cover": "https://cdn1.epicgames.com/52b90f9a982a404781b189f6a7903226/offer/EGS_TotallyReliableDeliveryService_WereFiveGames_S1-2560x1440-47e6e9562d62705a75ea7b7096d0b8dc.jpg",
"original_price": 52,
"original_price_desc": "¥52.00",
"description": "穿好护腰护具发动货车送货的时间到啦在一个高度互动的沙盒世界中与最多三位好友一起随意地完成送货。货物已试投这就是我们靠谱快递Totally Reliable Delivery Service的品质保证",
"seller": "Infogrames LLC",
"is_free_now": true,
"free_start": "2025/08/14 23:00:00",
"free_start_at": 1755183600000,
"free_end": "2025/08/21 23:00:00",
"free_end_at": 1755788400000,
"link": "https://store.epicgames.com/store/zh-CN/p/totally-reliable-delivery-service/home"
},
{
"id": "8ea3500dc38e4f429702bf889c172d3d",
"title": "Hidden Folks",
"cover": "https://cdn1.epicgames.com/spt-assets/7bfd56b0586348dcb139945d9e59f988/hidden-folks-1b7hh.png",
"original_price": 47,
"original_price_desc": "¥47.00",
"description": "Search for hidden folks in hand-drawn, interactive, miniature landscapes. Unfurl tent flaps, cut through bushes, slam doors, and poke some crocodiles! Rooooaaaarrrr!!!!!",
"seller": "Adriaan de Jongh",
"is_free_now": true,
"free_start": "2025/08/14 23:00:00",
"free_start_at": 1755183600000,
"free_end": "2025/08/21 23:00:00",
"free_end_at": 1755788400000,
"link": "https://store.epicgames.com/store/zh-CN/p/hidden-folks-239d16"
},
{
"id": "4cbb6c3704d240f19c3dd5f5cb2b0cb4",
"title": "Kamaeru",
"cover": "https://cdn1.epicgames.com/spt-assets/44313cfbb62b4df5801d0c8d541c2624/kamaeru-40asc.png",
"original_price": 62,
"original_price_desc": "¥62.00",
"description": "Foster a sanctuary for frogs and restore the biodiversity of the wetlands in Kamaeru, a cozy frog collecting game, where you take pictures of frogs, play mini-games and decorate your habitat. Hop right to it!",
"seller": "Armor Games Studios",
"is_free_now": false,
"free_start": "2025/08/21 23:00:00",
"free_start_at": 1755788400000,
"free_end": "2025/08/28 23:00:00",
"free_end_at": 1756393200000,
"link": "https://store.epicgames.com/store/zh-CN/p/kamaeru-0c301e"
},
{
"id": "0d9a533f0e684cc18620a8f408e8e72c",
"title": "Strange Horticulture",
"cover": "https://cdn1.epicgames.com/spt-assets/15e8e3eba65a4763a815d6eae1d763b2/strange-horticulture-offer-2wghv.png",
"original_price": 45,
"original_price_desc": "¥45.00",
"description": "款神秘学解谜游戏,你将扮演当地植物商店的店主,寻找并识别新的植物,悠闲撸猫,与女巫团体交谈,或加入异教。收集各种强大的植物,用它们来影响故事走向,揭开昂德米尔镇的黑暗谜团。",
"seller": "Iceberg Interactive",
"is_free_now": false,
"free_start": "2025/08/21 23:00:00",
"free_start_at": 1755788400000,
"free_end": "2025/08/28 23:00:00",
"free_end_at": 1756393200000,
"link": "https://store.epicgames.com/store/zh-CN/p/strange-horticulture-360e80"
}
]
}

View File

@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>IP查询</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.hero{background:linear-gradient(135deg,#1e40af,#3b82f6);border-radius:20px;padding:28px 24px;color:#fff;text-align:center;margin-bottom:16px}
.ip{font-size:28px;font-weight:800;letter-spacing:2px}.sub{font-size:13px;opacity:.8;margin-top:8px}
.section{background:#fff;border-radius:14px;padding:16px;margin-bottom:10px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
.section-title{font-size:13px;font-weight:700;color:#6b7280;margin-bottom:10px}
.row{display:flex;justify-content:space-between;padding:6px 0;border-bottom:1px solid #f9fafb}.row:last-child{border-bottom:none}
.rk{font-size:13px;color:#9ca3af}.rv{font-size:13px;color:#1f2937;font-weight:500}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🌐 IP查询</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/ip?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
const ip=typeof d==='string'?d:d?.ip||d?.query||'';
const loc=d?.location||d?.addr||d?.city||'';
const isp=d?.isp||d?.org||'';
let html=`<div class="hero"><div class="ip">${ip||'未知'}</div><div class="sub">${loc} ${isp?'· '+isp:''}</div></div>`;
html+='<div class="section"><div class="section-title">🌐 详细信息</div>';
if(d?.country)html+=`<div class="row"><span class="rk">国家</span><span class="rv">${d.country}</span></div>`;
if(d?.region)html+=`<div class="row"><span class="rk">地区</span><span class="rv">${d.region}</span></div>`;
if(d?.city)html+=`<div class="row"><span class="rk">城市</span><span class="rv">${d.city}</span></div>`;
if(isp)html+=`<div class="row"><span class="rk">ISP</span><span class="rv">${isp}</span></div>`;
if(d?.timezone)html+=`<div class="row"><span class="rk">时区</span><span class="rv">${d.timezone}</span></div>`;
html+='</div>';
el.innerHTML=html;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Whois查询</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.form{display:flex;flex-direction:column;gap:10px;margin-bottom:20px;background:#fff;border-radius:16px;padding:20px;box-shadow:0 1px 4px rgba(0,0,0,.05)}
.form label{font-size:12px;font-weight:600;color:#6b7280}
.form input{padding:11px 14px;border:2px solid #e5e7eb;border-radius:10px;font-size:13px;font-family:inherit;transition:border-color .2s}
.form input:focus{border-color:#4ade80;outline:none}
.form button{display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:11px 22px;border:none;border-radius:10px;background:linear-gradient(135deg,#4ade80,#22c55e);color:#fff;font-size:13px;font-weight:600;cursor:pointer;transition:all .2s}
.form button:hover{transform:translateY(-1px)}.form button:disabled{opacity:.5;cursor:not-allowed;transform:none}
.info-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
.info-card{background:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
.info-label{font-size:11px;color:#9ca3af;margin-bottom:3px}.info-val{font-size:14px;font-weight:600;word-break:break-all}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:28px 20px;text-align:center;border:1px solid rgba(34,197,94,.12)}
.quote-text{font-size:16px;line-height:2;color:#374151;font-weight:500}
.loader{display:flex;flex-direction:column;align-items:center;padding:40px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:20px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🔍 Whois查询</h1>
</div>
<div class="body">
<div class="form" id="formArea"><label>域名</label>
<input id="input_domain" placeholder="如 example.com" onkeydown="if(event.key==='Enter')query()">
<button onclick="query()" id="submitBtn">🔍 查询</button></div>
<div id="result"></div>
</div>
<script>
async function query(){
const params=new URLSearchParams({encoding:'json'});
const v_domain=document.getElementById('input_domain').value.trim();if(v_domain)params.set('domain',v_domain);
const el=document.getElementById('result');
const btn=document.getElementById('submitBtn');
btn.disabled=true;btn.textContent='查询中...';
el.innerHTML='<div class="loader"><div class="spinner"></div><span>查询中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/whois?'+params.toString(),{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
if(typeof d==='string'){el.innerHTML=`<div class="quote"><div class="quote-text">${d}</div></div>`;return}
if(Array.isArray(d)){let h='';d.forEach((item,i)=>{const t=item.title||item.name||String(item);h+=`<div class="info-card"><div class="info-label">#${i+1}</div><div class="info-val">${t}</div></div>`});el.innerHTML=`<div class="info-grid">${h}</div>`;return}
if(d&&typeof d==='object'){const entries=Object.entries(d).filter(([k])=>!['code','ok','api_updated'].includes(k));let h='';entries.forEach(([k,v])=>{h+=`<div class="info-card"><div class="info-label">${k}</div><div class="info-val">${typeof v==='object'?JSON.stringify(v):String(v)}</div></div>`});el.innerHTML=`<div class="info-grid">${h}</div>`;return}
el.innerHTML=`<div class="quote"><div class="quote-text">${String(d)}</div></div>`;
}catch(e){el.innerHTML=`<div class="err">查询失败:${e.message}</div>`}
finally{btn.disabled=false;btn.textContent='🔍 查询'}
}
</script>
</body>
</html>

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>二维码生成</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.form{display:flex;flex-direction:column;gap:10px;margin-bottom:20px;background:#fff;border-radius:16px;padding:20px;box-shadow:0 1px 4px rgba(0,0,0,.05)}
.form label{font-size:12px;font-weight:600;color:#6b7280}
.form input{padding:11px 14px;border:2px solid #e5e7eb;border-radius:10px;font-size:13px;font-family:inherit;transition:border-color .2s}
.form input:focus{border-color:#4ade80;outline:none}
.form button{display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:11px 22px;border:none;border-radius:10px;background:linear-gradient(135deg,#4ade80,#22c55e);color:#fff;font-size:13px;font-weight:600;cursor:pointer;transition:all .2s}
.form button:hover{transform:translateY(-1px)}.form button:disabled{opacity:.5;cursor:not-allowed;transform:none}
.info-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
.info-card{background:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
.info-label{font-size:11px;color:#9ca3af;margin-bottom:3px}.info-val{font-size:14px;font-weight:600;word-break:break-all}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:28px 20px;text-align:center;border:1px solid rgba(34,197,94,.12)}
.quote-text{font-size:16px;line-height:2;color:#374151;font-weight:500}
.loader{display:flex;flex-direction:column;align-items:center;padding:40px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:20px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>📱 二维码生成</h1>
</div>
<div class="body">
<div class="form" id="formArea"><label>内容</label>
<input id="input_text" placeholder="输入链接或文本" onkeydown="if(event.key==='Enter')query()">
<button onclick="query()" id="submitBtn">🔍 查询</button></div>
<div id="result"></div>
</div>
<script>
async function query(){
const params=new URLSearchParams({encoding:'json'});
const v_text=document.getElementById('input_text').value.trim();if(v_text)params.set('text',v_text);
const el=document.getElementById('result');
const btn=document.getElementById('submitBtn');
btn.disabled=true;btn.textContent='查询中...';
el.innerHTML='<div class="loader"><div class="spinner"></div><span>查询中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/qrcode?'+params.toString(),{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
if(typeof d==='string'){el.innerHTML=`<div class="quote"><div class="quote-text">${d}</div></div>`;return}
if(Array.isArray(d)){let h='';d.forEach((item,i)=>{const t=item.title||item.name||String(item);h+=`<div class="info-card"><div class="info-label">#${i+1}</div><div class="info-val">${t}</div></div>`});el.innerHTML=`<div class="info-grid">${h}</div>`;return}
if(d&&typeof d==='object'){const entries=Object.entries(d).filter(([k])=>!['code','ok','api_updated'].includes(k));let h='';entries.forEach(([k,v])=>{h+=`<div class="info-card"><div class="info-label">${k}</div><div class="info-val">${typeof v==='object'?JSON.stringify(v):String(v)}</div></div>`});el.innerHTML=`<div class="info-grid">${h}</div>`;return}
el.innerHTML=`<div class="quote"><div class="quote-text">${String(d)}</div></div>`;
}catch(e){el.innerHTML=`<div class="err">查询失败:${e.message}</div>`}
finally{btn.disabled=false;btn.textContent='🔍 查询'}
}
</script>
</body>
</html>

View File

@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>今日油价</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.info-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
.info-card{background:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
.info-label{font-size:11px;color:#9ca3af;margin-bottom:3px}.info-val{font-size:14px;font-weight:600;word-break:break-all}
.big-card{background:linear-gradient(135deg,#1e293b,#334155);border-radius:20px;padding:32px 24px;color:#fff;text-align:center;margin-bottom:16px}
.big-val{font-size:22px;font-weight:700;letter-spacing:3px;font-family:'Courier New',monospace;background:rgba(255,255,255,.1);padding:16px 20px;border-radius:12px;margin-top:12px;word-break:break-all;user-select:all;cursor:pointer}
.big-tip{font-size:12px;opacity:.6;margin-top:12px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>⛽ 今日油价</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/fuel-price?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
if(!d||typeof d!=='object'){el.innerHTML='<div class="err">暂无数据</div>';return}
let html='<div style="background:linear-gradient(135deg,#b45309,#f59e0b);border-radius:16px;padding:20px;color:#fff;text-align:center;margin-bottom:16px"><div style="font-size:20px;font-weight:700">⛽ 今日油价</div></div>';
if(typeof d==='object'&&!Array.isArray(d)){const entries=Object.entries(d).filter(([k])=>!['code','ok','time','update_time'].includes(k));html+='<div class="info-grid">';entries.forEach(([k,v])=>{html+='<div class="info-card"><div class="info-label">'+k+'</div><div class="info-val" style="color:#f59e0b">'+(typeof v==='object'?JSON.stringify(v):String(v))+'</div></div>'});html+='</div>'}
el.innerHTML=html;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>今日金价</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.info-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
.info-card{background:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
.info-label{font-size:11px;color:#9ca3af;margin-bottom:3px}.info-val{font-size:14px;font-weight:600;word-break:break-all}
.big-card{background:linear-gradient(135deg,#1e293b,#334155);border-radius:20px;padding:32px 24px;color:#fff;text-align:center;margin-bottom:16px}
.big-val{font-size:22px;font-weight:700;letter-spacing:3px;font-family:'Courier New',monospace;background:rgba(255,255,255,.1);padding:16px 20px;border-radius:12px;margin-top:12px;word-break:break-all;user-select:all;cursor:pointer}
.big-tip{font-size:12px;opacity:.6;margin-top:12px}
.loader{display:flex;flex-direction:column;align-items:center;padding:60px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:40px 16px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🥇 今日金价</h1>
<button class="btn" onclick="loadData()"></button>
</div>
<div class="body" id="content">
<div class="loader"><div class="spinner"></div><span>加载中...</span></div>
</div>
<script>
async function loadData(){
const el=document.getElementById('content');
el.innerHTML='<div class="loader"><div class="spinner"></div><span>加载中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/gold-price?encoding=json',{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
if(!d){el.innerHTML='<div class="err">暂无数据</div>';return}
let html='<div style="background:linear-gradient(135deg,#92400e,#fbbf24);border-radius:16px;padding:20px;color:#fff;text-align:center;margin-bottom:16px"><div style="font-size:20px;font-weight:700">🥇 今日金价</div></div>';
if(Array.isArray(d)){html+='<div style="border-radius:12px;overflow:hidden;border:1px solid #e5e7eb"><table style="width:100%;border-collapse:collapse"><thead><tr><th style="padding:10px 12px;font-size:12px;color:#6b7280;background:#f9fafb;text-align:left">品种</th><th style="padding:10px 12px;font-size:12px;color:#6b7280;background:#f9fafb;text-align:left">买入价</th><th style="padding:10px 12px;font-size:12px;color:#6b7280;background:#f9fafb;text-align:left">卖出价</th></tr></thead><tbody>';d.forEach(item=>{const n=item.name||item.title||'';html+='<tr><td style="padding:10px 12px;font-size:13px;border-top:1px solid #f3f4f6;font-weight:600">'+n+'</td><td style="padding:10px 12px;font-size:13px;border-top:1px solid #f3f4f6">'+(item.buy||item.bid||'-')+'</td><td style="padding:10px 12px;font-size:13px;border-top:1px solid #f3f4f6">'+(item.sell||item.ask||'-')+'</td></tr>'});html+='</tbody></table></div>'}
else if(typeof d==='object'){const entries=Object.entries(d).filter(([k])=>!['code','ok','time'].includes(k));html+='<div class="info-grid">';entries.forEach(([k,v])=>{html+='<div class="info-card"><div class="info-label">'+k+'</div><div class="info-val" style="color:#b45309">'+(typeof v==='object'?JSON.stringify(v):v)+'</div></div>'});html+='</div>'}
el.innerHTML=html;
}catch(e){el.innerHTML=`<div class="err">加载失败:${e.message}</div>`}
}
loadData();
</script>
</body>
</html>

View File

@@ -1,233 +0,0 @@
/* 动态背景样式 */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #f0f8e8 0%, #e8f5e8 50%, #d4f4dd 100%);
z-index: -2;
}
body::after {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
radial-gradient(circle at 20% 80%, rgba(144, 238, 144, 0.2) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(173, 255, 173, 0.2) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(152, 251, 152, 0.2) 0%, transparent 50%);
z-index: -1;
animation: backgroundMove 20s ease-in-out infinite;
}
@keyframes backgroundMove {
0%, 100% {
background:
radial-gradient(circle at 20% 80%, rgba(144, 238, 144, 0.2) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(173, 255, 173, 0.2) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(152, 251, 152, 0.2) 0%, transparent 50%);
}
25% {
background:
radial-gradient(circle at 60% 30%, rgba(144, 238, 144, 0.2) 0%, transparent 50%),
radial-gradient(circle at 30% 70%, rgba(173, 255, 173, 0.2) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(152, 251, 152, 0.2) 0%, transparent 50%);
}
50% {
background:
radial-gradient(circle at 80% 60%, rgba(144, 238, 144, 0.2) 0%, transparent 50%),
radial-gradient(circle at 20% 30%, rgba(173, 255, 173, 0.2) 0%, transparent 50%),
radial-gradient(circle at 60% 70%, rgba(152, 251, 152, 0.2) 0%, transparent 50%);
}
75% {
background:
radial-gradient(circle at 40% 90%, rgba(144, 238, 144, 0.2) 0%, transparent 50%),
radial-gradient(circle at 70% 10%, rgba(173, 255, 173, 0.2) 0%, transparent 50%),
radial-gradient(circle at 20% 60%, rgba(152, 251, 152, 0.2) 0%, transparent 50%);
}
}
/* 浮动粒子效果 */
.particles {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
}
.particle {
position: absolute;
width: 4px;
height: 4px;
background: rgba(255, 255, 255, 0.5);
border-radius: 50%;
animation: float 15s infinite linear;
}
.particle:nth-child(1) {
left: 10%;
animation-delay: 0s;
animation-duration: 12s;
}
.particle:nth-child(2) {
left: 20%;
animation-delay: 2s;
animation-duration: 18s;
}
.particle:nth-child(3) {
left: 30%;
animation-delay: 4s;
animation-duration: 15s;
}
.particle:nth-child(4) {
left: 40%;
animation-delay: 6s;
animation-duration: 20s;
}
.particle:nth-child(5) {
left: 50%;
animation-delay: 8s;
animation-duration: 14s;
}
.particle:nth-child(6) {
left: 60%;
animation-delay: 10s;
animation-duration: 16s;
}
.particle:nth-child(7) {
left: 70%;
animation-delay: 12s;
animation-duration: 22s;
}
.particle:nth-child(8) {
left: 80%;
animation-delay: 14s;
animation-duration: 13s;
}
.particle:nth-child(9) {
left: 90%;
animation-delay: 16s;
animation-duration: 19s;
}
.particle:nth-child(10) {
left: 15%;
animation-delay: 18s;
animation-duration: 17s;
}
@keyframes float {
0% {
transform: translateY(100vh) rotate(0deg);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(-100px) rotate(360deg);
opacity: 0;
}
}
/* 网格背景效果 */
.grid-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
linear-gradient(rgba(255, 255, 255, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.1) 1px, transparent 1px);
background-size: 50px 50px;
z-index: -1;
opacity: 0.3;
animation: gridMove 30s linear infinite;
}
@keyframes gridMove {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(50px, 50px);
}
}
/* 光晕效果 */
.glow-effect {
position: fixed;
top: 50%;
left: 50%;
width: 300px;
height: 300px;
background: radial-gradient(circle, rgba(74, 144, 226, 0.2) 0%, transparent 70%);
border-radius: 50%;
transform: translate(-50%, -50%);
z-index: -1;
animation: pulse 4s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% {
transform: translate(-50%, -50%) scale(1);
opacity: 0.5;
}
50% {
transform: translate(-50%, -50%) scale(1.2);
opacity: 0.8;
}
}
/* 响应式背景调整 */
@media (max-width: 768px) {
.grid-background {
background-size: 30px 30px;
}
.glow-effect {
width: 200px;
height: 200px;
}
.particle {
width: 3px;
height: 3px;
}
}
@media (max-width: 480px) {
.grid-background {
background-size: 20px 20px;
}
.glow-effect {
width: 150px;
height: 150px;
}
.particle {
width: 2px;
height: 2px;
}
}

View File

@@ -1,461 +0,0 @@
/* 全局样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
min-height: 100vh;
overflow-x: hidden;
/* 隐藏滚动条但保留滚动功能 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
/* 隐藏 Webkit 浏览器的滚动条 */
body::-webkit-scrollbar,
html::-webkit-scrollbar,
*::-webkit-scrollbar {
display: none;
}
/* 全局隐藏滚动条但保留滚动功能 */
html {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
/* 容器样式 */
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
position: relative;
z-index: 1;
}
/* 头部样式 */
.header {
text-align: center;
padding: 3rem 2rem 2rem;
background: linear-gradient(135deg, rgba(144, 238, 144, 0.15), rgba(152, 251, 152, 0.15));
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
.header h1 {
font-size: 2.5rem;
font-weight: 700;
background: linear-gradient(135deg, #228B22, #32CD32);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 0.5rem;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.header h1 i {
margin-right: 0.5rem;
background: linear-gradient(135deg, #228B22, #32CD32);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.subtitle {
font-size: 1.1rem;
color: #666;
font-weight: 300;
}
/* 主要内容区域 */
.main-content {
flex: 1;
padding: 2rem;
max-width: 800px;
margin: 0 auto;
width: 100%;
}
/* 查询按钮区域 */
.query-section {
text-align: center;
margin-bottom: 2rem;
}
.query-btn {
background: linear-gradient(135deg, #228B22, #32CD32);
color: white;
border: none;
padding: 1rem 2rem;
font-size: 1.1rem;
font-weight: 600;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(34, 139, 34, 0.3);
display: inline-flex;
align-items: center;
gap: 0.5rem;
min-width: 200px;
justify-content: center;
}
.query-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(34, 139, 34, 0.4);
background: linear-gradient(135deg, #1e7e1e, #2eb82e);
}
.query-btn:active {
transform: translateY(0);
}
.query-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
/* 加载动画 */
.loading {
text-align: center;
padding: 2rem;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid #f3f3f3;
border-top: 4px solid #4a90e2;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 1rem;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading p {
color: #666;
font-size: 1rem;
}
/* IP信息卡片 */
.ip-info {
animation: fadeInUp 0.6s ease;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.ip-card {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 2rem;
margin-bottom: 2rem;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.ip-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 2px solid #f0f0f0;
}
.ip-header i {
font-size: 1.5rem;
color: #4a90e2;
}
.ip-header h2 {
font-size: 1.5rem;
font-weight: 600;
color: #333;
}
.ip-display {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin-bottom: 1.5rem;
padding: 1.5rem;
background: linear-gradient(135deg, rgba(74, 144, 226, 0.1), rgba(80, 200, 120, 0.1));
border-radius: 15px;
border: 2px solid rgba(74, 144, 226, 0.2);
}
.ip-address {
font-size: 2rem;
font-weight: 700;
font-family: 'Courier New', monospace;
color: #2c3e50;
background: linear-gradient(135deg, #4a90e2, #50c878);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.copy-btn {
background: #4a90e2;
color: white;
border: none;
padding: 0.5rem;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
font-size: 1rem;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
.copy-btn:hover {
background: #3a7bc8;
transform: scale(1.1);
}
.ip-details {
display: grid;
gap: 1rem;
}
.detail-item {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem;
background: rgba(248, 249, 250, 0.8);
border-radius: 10px;
transition: all 0.3s ease;
}
.detail-item:hover {
background: rgba(74, 144, 226, 0.1);
transform: translateX(5px);
}
.detail-item i {
color: #4a90e2;
width: 20px;
text-align: center;
}
.detail-item .label {
font-weight: 600;
color: #555;
min-width: 80px;
}
.detail-item .value {
color: #333;
font-weight: 500;
}
/* IP地址说明区域 */
.ip-explanation {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 2rem;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.ip-explanation h3 {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1rem;
font-size: 1.3rem;
color: #333;
}
.ip-explanation h3 i {
color: #4a90e2;
}
.ip-explanation p {
color: #666;
line-height: 1.8;
margin-bottom: 1.5rem;
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.feature-item {
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 1rem;
background: rgba(248, 249, 250, 0.8);
border-radius: 12px;
transition: all 0.3s ease;
}
.feature-item:hover {
background: rgba(74, 144, 226, 0.1);
transform: translateY(-2px);
}
.feature-item i {
color: #4a90e2;
font-size: 1.5rem;
margin-top: 0.2rem;
}
.feature-item h4 {
font-size: 1rem;
font-weight: 600;
color: #333;
margin-bottom: 0.3rem;
}
.feature-item p {
font-size: 0.9rem;
color: #666;
line-height: 1.5;
margin: 0;
}
/* 错误信息 */
.error-message {
text-align: center;
padding: 2rem;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 99, 99, 0.3);
animation: fadeInUp 0.6s ease;
}
.error-message i {
font-size: 3rem;
color: #ff6b6b;
margin-bottom: 1rem;
}
.error-message p {
color: #666;
font-size: 1.1rem;
margin-bottom: 1.5rem;
}
.retry-btn {
background: #ff6b6b;
color: white;
border: none;
padding: 0.75rem 1.5rem;
font-size: 1rem;
font-weight: 600;
border-radius: 25px;
cursor: pointer;
transition: all 0.3s ease;
}
.retry-btn:hover {
background: #ff5252;
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(255, 107, 107, 0.3);
}
/* 页脚 */
.footer {
text-align: center;
padding: 2rem;
background: rgba(248, 249, 250, 0.8);
backdrop-filter: blur(10px);
border-top: 1px solid rgba(255, 255, 255, 0.2);
color: #666;
font-size: 0.9rem;
}
/* 响应式设计 */
@media (max-width: 768px) {
.header {
padding: 2rem 1rem 1.5rem;
}
.header h1 {
font-size: 2rem;
}
.main-content {
padding: 1rem;
}
.ip-card, .ip-explanation {
padding: 1.5rem;
}
.ip-address {
font-size: 1.5rem;
}
.ip-display {
flex-direction: column;
gap: 1rem;
}
.features {
grid-template-columns: 1fr;
}
.detail-item {
flex-direction: column;
align-items: flex-start;
gap: 0.3rem;
}
.detail-item .label {
min-width: auto;
}
}
@media (max-width: 480px) {
.header h1 {
font-size: 1.8rem;
}
.query-btn {
padding: 0.875rem 1.5rem;
font-size: 1rem;
min-width: 180px;
}
.ip-address {
font-size: 1.3rem;
}
.ip-card, .ip-explanation {
padding: 1rem;
}
}

View File

@@ -1,131 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>公网IP地址查询</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/background.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<div class="container">
<!-- 头部 -->
<header class="header">
<h1><i class="fas fa-globe"></i> 公网IP地址查询</h1>
<p class="subtitle">快速获取您的公网IP地址信息</p>
</header>
<!-- 主要内容区域 -->
<main class="main-content">
<!-- 查询按钮区域 -->
<div class="query-section">
<button id="queryBtn" class="query-btn">
<i class="fas fa-search"></i>
<span>查询我的IP地址</span>
</button>
</div>
<!-- 加载动画 -->
<div id="loading" class="loading" style="display: none;">
<div class="spinner"></div>
<p>正在获取IP地址信息...</p>
</div>
<!-- IP信息展示区域 -->
<div id="ip-info" class="ip-info" style="display: none;">
<div class="ip-card">
<div class="ip-header">
<i class="fas fa-network-wired"></i>
<h2>您的公网IP地址</h2>
</div>
<div class="ip-display">
<span id="ip-address" class="ip-address">---.---.---.---</span>
<button id="copyBtn" class="copy-btn" title="复制IP地址">
<i class="fas fa-copy"></i>
</button>
</div>
<div class="ip-details">
<div class="detail-item">
<i class="fas fa-clock"></i>
<span class="label">查询时间:</span>
<span id="query-time" class="value">--</span>
</div>
<div class="detail-item">
<i class="fas fa-map-marker-alt"></i>
<span class="label">位置信息:</span>
<span id="location" class="value">--</span>
</div>
<div class="detail-item">
<i class="fas fa-building"></i>
<span class="label">网络服务商:</span>
<span id="isp" class="value">--</span>
</div>
<div class="detail-item">
<i class="fas fa-flag"></i>
<span class="label">国家:</span>
<span id="country" class="value">--</span>
</div>
<div class="detail-item">
<i class="fas fa-map"></i>
<span class="label">地区:</span>
<span id="region" class="value">--</span>
</div>
<div class="detail-item">
<i class="fas fa-city"></i>
<span class="label">城市:</span>
<span id="city" class="value">--</span>
</div>
<div class="detail-item">
<i class="fas fa-clock"></i>
<span class="label">时区:</span>
<span id="timezone" class="value">--</span>
</div>
</div>
</div>
<!-- IP地址信息说明 -->
<div class="ip-explanation">
<h3><i class="fas fa-info-circle"></i> 什么是公网IP地址</h3>
<p>公网IP地址是您的设备在互联网上的唯一标识符由您的网络服务提供商(ISP)分配。通过这个地址,互联网上的其他设备可以找到并与您的设备通信。</p>
<div class="features">
<div class="feature-item">
<i class="fas fa-shield-alt"></i>
<div>
<h4>隐私保护</h4>
<p>了解您的IP地址有助于保护网络隐私</p>
</div>
</div>
<div class="feature-item">
<i class="fas fa-map-marker-alt"></i>
<div>
<h4>地理位置</h4>
<p>IP地址可以大致确定您的地理位置</p>
</div>
</div>
<div class="feature-item">
<i class="fas fa-cogs"></i>
<div>
<h4>网络配置</h4>
<p>用于网络故障排除和配置</p>
</div>
</div>
</div>
</div>
</div>
<!-- 错误信息 -->
<div id="error-message" class="error-message" style="display: none;">
<i class="fas fa-exclamation-triangle"></i>
<p>获取IP地址失败请检查网络连接或稍后重试</p>
<button id="retryBtn" class="retry-btn">重试</button>
</div>
</main>
<!-- 页脚 -->
</div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -1,343 +0,0 @@
// 公网IP地址查询应用
class IPQueryApp {
constructor() {
this.apiEndpoint = 'https://60s.api.shumengya.top/v2/ip';
this.init();
}
// 初始化应用
init() {
this.bindEvents();
this.createParticles();
this.createBackgroundElements();
console.log('IP查询应用初始化完成');
}
// 绑定事件
bindEvents() {
const queryBtn = document.getElementById('queryBtn');
const retryBtn = document.getElementById('retryBtn');
const copyBtn = document.getElementById('copyBtn');
if (queryBtn) {
queryBtn.addEventListener('click', () => this.queryIP());
}
if (retryBtn) {
retryBtn.addEventListener('click', () => this.queryIP());
}
if (copyBtn) {
copyBtn.addEventListener('click', () => this.copyIP());
}
// 页面加载完成后自动查询一次
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => this.queryIP(), 500);
});
}
// 创建浮动粒子
createParticles() {
const particlesContainer = document.createElement('div');
particlesContainer.className = 'particles';
document.body.appendChild(particlesContainer);
for (let i = 0; i < 10; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
particlesContainer.appendChild(particle);
}
}
// 创建背景元素
createBackgroundElements() {
// 创建网格背景
const gridBackground = document.createElement('div');
gridBackground.className = 'grid-background';
document.body.appendChild(gridBackground);
// 创建光晕效果
const glowEffect = document.createElement('div');
glowEffect.className = 'glow-effect';
document.body.appendChild(glowEffect);
}
// 显示加载状态
showLoading() {
const loading = document.getElementById('loading');
const ipInfo = document.getElementById('ipInfo');
const errorMessage = document.getElementById('errorMessage');
const queryBtn = document.getElementById('queryBtn');
if (loading) loading.style.display = 'block';
if (ipInfo) ipInfo.style.display = 'none';
if (errorMessage) errorMessage.style.display = 'none';
if (queryBtn) {
queryBtn.disabled = true;
queryBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 查询中...';
}
}
// 隐藏加载状态
hideLoading() {
const loading = document.getElementById('loading');
const queryBtn = document.getElementById('queryBtn');
if (loading) loading.style.display = 'none';
if (queryBtn) {
queryBtn.disabled = false;
queryBtn.innerHTML = '<i class="fas fa-search"></i> 查询我的IP';
}
}
// 显示错误信息
showError(message) {
const errorMessage = document.getElementById('error-message');
const ipInfo = document.getElementById('ip-info');
if (errorMessage) {
errorMessage.style.display = 'block';
const errorText = errorMessage.querySelector('p');
if (errorText) errorText.textContent = message || '获取IP信息失败请稍后重试';
}
if (ipInfo) ipInfo.style.display = 'none';
this.hideLoading();
}
// 查询IP地址
async queryIP() {
try {
this.showLoading();
console.log('开始查询IP地址...');
const response = await fetch(this.apiEndpoint, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
console.log('API响应状态:', response.status);
if (!response.ok) {
throw new Error(`HTTP错误: ${response.status}`);
}
const data = await response.json();
console.log('API返回数据:', data);
if (data.code === 200 && data.data) {
this.displayIPInfo(data.data);
} else {
throw new Error(data.message || '获取IP信息失败');
}
} catch (error) {
console.error('查询IP失败:', error);
this.showError(error.message);
}
}
// 显示IP信息
displayIPInfo(data) {
const ipInfo = document.getElementById('ip-info');
const errorMessage = document.getElementById('error-message');
// 更新IP地址显示
const ipAddressElement = document.getElementById('ip-address');
if (ipAddressElement && data.ip) {
ipAddressElement.textContent = data.ip;
}
// 更新查询时间
const queryTimeElement = document.getElementById('query-time');
if (queryTimeElement) {
const now = new Date();
queryTimeElement.textContent = now.toLocaleString('zh-CN');
}
// 更新详细信息 - 只显示API提供的数据
if (data.location) this.updateDetailItem('location', data.location);
else this.hideDetailItem('location');
if (data.isp) this.updateDetailItem('isp', data.isp);
else this.hideDetailItem('isp');
if (data.country) this.updateDetailItem('country', data.country);
else this.hideDetailItem('country');
if (data.region) this.updateDetailItem('region', data.region);
else this.hideDetailItem('region');
if (data.city) this.updateDetailItem('city', data.city);
else this.hideDetailItem('city');
if (data.timezone) this.updateDetailItem('timezone', data.timezone);
else this.hideDetailItem('timezone');
// 显示IP信息隐藏错误信息
if (ipInfo) ipInfo.style.display = 'block';
if (errorMessage) errorMessage.style.display = 'none';
this.hideLoading();
console.log('IP信息显示完成');
}
// 更新详细信息项
updateDetailItem(id, value) {
const element = document.getElementById(id);
if (element) {
element.textContent = value;
// 显示对应的详细信息行
const detailRow = element.closest('.detail-item');
if (detailRow) {
detailRow.style.display = 'flex';
}
}
}
// 隐藏详细信息项
hideDetailItem(id) {
const element = document.getElementById(id);
if (element) {
// 隐藏整个详细信息行
const detailRow = element.closest('.detail-item');
if (detailRow) {
detailRow.style.display = 'none';
}
}
}
// 复制IP地址
async copyIP() {
const ipAddressElement = document.getElementById('ip-address');
const copyBtn = document.getElementById('copyBtn');
if (!ipAddressElement || !ipAddressElement.textContent) {
this.showToast('没有可复制的IP地址', 'error');
return;
}
try {
await navigator.clipboard.writeText(ipAddressElement.textContent);
// 更新按钮状态
if (copyBtn) {
const originalHTML = copyBtn.innerHTML;
copyBtn.innerHTML = '<i class="fas fa-check"></i>';
copyBtn.style.background = '#50c878';
setTimeout(() => {
copyBtn.innerHTML = originalHTML;
copyBtn.style.background = '#4a90e2';
}, 1500);
}
this.showToast('IP地址已复制到剪贴板', 'success');
console.log('IP地址已复制:', ipAddressElement.textContent);
} catch (error) {
console.error('复制失败:', error);
this.showToast('复制失败,请手动选择复制', 'error');
}
}
// 显示提示消息
showToast(message, type = 'info') {
// 移除已存在的toast
const existingToast = document.querySelector('.toast');
if (existingToast) {
existingToast.remove();
}
// 创建新的toast
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.innerHTML = `
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}"></i>
<span>${message}</span>
`;
// 添加toast样式
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${type === 'success' ? '#50c878' : type === 'error' ? '#ff6b6b' : '#4a90e2'};
color: white;
padding: 1rem 1.5rem;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
z-index: 1000;
display: flex;
align-items: center;
gap: 0.5rem;
font-weight: 500;
animation: slideInRight 0.3s ease;
max-width: 300px;
`;
// 添加动画样式
const style = document.createElement('style');
style.textContent = `
@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOutRight {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
`;
document.head.appendChild(style);
document.body.appendChild(toast);
// 3秒后自动移除
setTimeout(() => {
toast.style.animation = 'slideOutRight 0.3s ease';
setTimeout(() => {
if (toast.parentNode) {
toast.remove();
}
if (style.parentNode) {
style.remove();
}
}, 300);
}, 3000);
}
// 格式化时间
formatTime(timestamp) {
const date = new Date(timestamp);
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
}
// 初始化应用
const app = new IPQueryApp();
// 导出到全局作用域(用于调试)
window.IPQueryApp = app;

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top/v2/ip"
]

View File

@@ -1,17 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"ip": "2401:b60:16:83::"
}
}
// 注意此API只返回IP地址不包含以下信息
// - location (位置信息)
// - isp (网络服务商)
// - country (国家)
// - region (地区)
// - city (城市)
// - timezone (时区)
//
// 使API

View File

@@ -1,590 +0,0 @@
/* 全局滚动条隐藏样式 */
html, body {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge */
}
html::-webkit-scrollbar,
body::-webkit-scrollbar,
*::-webkit-scrollbar {
display: none; /* Webkit浏览器 */
}
/* 农历主题背景样式 - 淡黄绿色到淡绿色清新渐变 */
body {
background: linear-gradient(135deg,
#f0f8e8 0%, /* 淡黄绿色 */
#e8f5e8 20%, /* 浅绿色 */
#d4f4dd 40%, /* 淡绿色 */
#c8f2d4 60%, /* 清新绿色 */
#b8f0c8 80%, /* 柔和绿色 */
#e8f5e8 100% /* 浅绿色 */
);
background-size: 400% 400%;
animation: gentleShift 30s ease infinite;
background-attachment: fixed;
min-height: 100vh;
position: relative;
/* 隐藏滚动条但保留滚动功能 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE/Edge */
}
@keyframes gentleShift {
0% { background-position: 0% 50%; }
25% { background-position: 100% 50%; }
50% { background-position: 100% 100%; }
75% { background-position: 0% 100%; }
100% { background-position: 0% 50%; }
}
/* 动态颜色调节系统 - 绿色主题版本 */
.adaptive-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background:
radial-gradient(circle at 20% 30%, rgba(200, 242, 212, 0.3) 0%, transparent 50%),
radial-gradient(circle at 80% 70%, rgba(184, 240, 200, 0.25) 0%, transparent 50%),
linear-gradient(45deg, rgba(232, 245, 232, 0.2) 0%, rgba(212, 244, 221, 0.3) 100%);
pointer-events: none;
z-index: 1;
animation: adaptiveShift 60s ease infinite;
}
@keyframes adaptiveShift {
0% {
background:
radial-gradient(circle at 20% 30%, rgba(232, 245, 232, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 70%, rgba(212, 244, 221, 0.15) 0%, transparent 50%),
linear-gradient(45deg, rgba(240, 248, 232, 0.1) 0%, rgba(232, 245, 232, 0.2) 100%);
}
25% {
background:
radial-gradient(circle at 70% 20%, rgba(200, 242, 212, 0.2) 0%, transparent 50%),
radial-gradient(circle at 30% 80%, rgba(184, 240, 200, 0.1) 0%, transparent 50%),
linear-gradient(135deg, rgba(212, 244, 221, 0.15) 0%, rgba(200, 242, 212, 0.25) 100%);
}
50% {
background:
radial-gradient(circle at 50% 50%, rgba(220, 246, 228, 0.15) 0%, transparent 50%),
radial-gradient(circle at 10% 90%, rgba(232, 245, 232, 0.12) 0%, transparent 50%),
linear-gradient(225deg, rgba(240, 248, 232, 0.12) 0%, rgba(212, 244, 221, 0.22) 100%);
}
75% {
background:
radial-gradient(circle at 90% 60%, rgba(184, 240, 200, 0.18) 0%, transparent 50%),
radial-gradient(circle at 40% 10%, rgba(240, 248, 232, 0.08) 0%, transparent 50%),
linear-gradient(315deg, rgba(232, 245, 232, 0.1) 0%, rgba(200, 242, 212, 0.2) 100%);
}
100% {
background:
radial-gradient(circle at 20% 30%, rgba(232, 245, 232, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 70%, rgba(212, 244, 221, 0.15) 0%, transparent 50%),
linear-gradient(45deg, rgba(240, 248, 232, 0.1) 0%, rgba(232, 245, 232, 0.2) 100%);
}
}
/* 高清稻穗贴图层 */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
/* 主稻穗束 - 高清细节 */
radial-gradient(ellipse 1.5px 12px at 50% 45%, #DAA520 0%, #B8860B 30%, transparent 80%),
radial-gradient(ellipse 1px 10px at 48% 50%, #FFD700 0%, #DAA520 40%, transparent 75%),
radial-gradient(ellipse 1.2px 11px at 52% 48%, #FFCC00 0%, #B8860B 35%, transparent 78%),
radial-gradient(ellipse 0.8px 9px at 49% 52%, #F4A460 0%, #DAA520 45%, transparent 70%),
radial-gradient(ellipse 1.3px 13px at 51% 46%, #DEB887 0%, #B8860B 38%, transparent 82%),
/* 次级稻穗 */
radial-gradient(ellipse 1px 8px at 30% 35%, #FFD700 0%, #DAA520 50%, transparent 75%),
radial-gradient(ellipse 0.9px 7px at 32% 38%, #FFCC00 0%, #B8860B 45%, transparent 70%),
radial-gradient(ellipse 1.1px 9px at 28% 36%, #DEB887 0%, #DAA520 40%, transparent 78%),
radial-gradient(ellipse 1px 8px at 70% 65%, #FFD700 0%, #DAA520 50%, transparent 75%),
radial-gradient(ellipse 0.8px 7px at 72% 68%, #F4A460 0%, #B8860B 45%, transparent 70%),
radial-gradient(ellipse 1.2px 9px at 68% 66%, #FFCC00 0%, #DAA520 40%, transparent 78%),
/* 散落稻粒 */
radial-gradient(ellipse 0.5px 4px at 20% 80%, #FFD700 0%, transparent 60%),
radial-gradient(ellipse 0.6px 5px at 80% 20%, #FFCC00 0%, transparent 65%),
radial-gradient(ellipse 0.4px 3px at 15% 25%, #DEB887 0%, transparent 55%),
radial-gradient(ellipse 0.7px 6px at 85% 75%, #DAA520 0%, transparent 70%),
/* 稻穗茎秆 - 更细致 */
linear-gradient(88deg, transparent 49%, #9ACD32 49.5%, #8FBC8F 50%, #9ACD32 50.5%, transparent 51%),
linear-gradient(92deg, transparent 49%, #8FBC8F 49.5%, #228B22 50%, #8FBC8F 50.5%, transparent 51%),
linear-gradient(85deg, transparent 49%, #32CD32 49.5%, #9ACD32 50%, #32CD32 50.5%, transparent 51%);
background-size:
25px 25px, 24px 24px, 26px 26px, 23px 23px, 27px 27px,
20px 20px, 19px 19px, 21px 21px,
22px 22px, 18px 18px, 23px 23px,
15px 15px, 16px 16px, 14px 14px, 17px 17px,
80px 80px, 85px 85px, 75px 75px;
background-position:
0 0, 12px 12px, 6px 18px, 18px 6px, 3px 21px,
40px 40px, 52px 48px, 35px 55px,
120px 120px, 135px 115px, 110px 130px,
200px 200px, 220px 180px, 180px 220px, 240px 160px,
0 0, 40px 40px, 20px 60px;
opacity: 0.25;
pointer-events: none;
z-index: -2;
animation: wheatSway 20s ease-in-out infinite;
}
@keyframes wheatSway {
0%, 100% {
transform: translateX(0) rotate(0deg);
}
25% {
transform: translateX(5px) rotate(0.5deg);
}
50% {
transform: translateX(-3px) rotate(-0.3deg);
}
75% {
transform: translateX(2px) rotate(0.2deg);
}
}
/* 大型稻穗背景层 */
body::after {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image:
/* 主稻穗茎秆 - 右侧大型 */
linear-gradient(85deg, transparent 45%, #9ACD32 47%, #8FBC8F 48%, #228B22 49%, #8FBC8F 50%, #9ACD32 51%, transparent 53%),
linear-gradient(87deg, transparent 46%, #32CD32 47.5%, #9ACD32 48.5%, #8FBC8F 49.5%, #9ACD32 50.5%, #32CD32 51.5%, transparent 54%),
/* 主稻穗穗头 - 大型椭圆稻粒群 */
radial-gradient(ellipse 8px 25px at 75% 15%, #FFD700 0%, #DAA520 30%, #B8860B 60%, transparent 85%),
radial-gradient(ellipse 7px 23px at 77% 18%, #FFCC00 0%, #DAA520 35%, transparent 80%),
radial-gradient(ellipse 9px 27px at 73% 12%, #F4A460 0%, #B8860B 40%, transparent 88%),
radial-gradient(ellipse 6px 22px at 79% 20%, #DEB887 0%, #DAA520 45%, transparent 75%),
radial-gradient(ellipse 8px 24px at 75% 16%, #FFD700 0%, #B8860B 38%, transparent 82%),
/* 稻穗分支 */
radial-gradient(ellipse 5px 18px at 72% 25%, #FFCC00 0%, #DAA520 50%, transparent 75%),
radial-gradient(ellipse 4px 16px at 78% 28%, #F4A460 0%, #B8860B 45%, transparent 70%),
radial-gradient(ellipse 6px 20px at 70% 22%, #DEB887 0%, #DAA520 40%, transparent 78%),
radial-gradient(ellipse 5px 17px at 80% 30%, #FFD700 0%, #B8860B 42%, transparent 76%),
/* 左侧稻穗茎秆 */
linear-gradient(95deg, transparent 15%, #9ACD32 17%, #8FBC8F 18%, #228B22 19%, #8FBC8F 20%, #9ACD32 21%, transparent 23%),
/* 左侧稻穗穗头 */
radial-gradient(ellipse 6px 20px at 25% 25%, #FFD700 0%, #DAA520 30%, transparent 80%),
radial-gradient(ellipse 5px 18px at 27% 28%, #FFCC00 0%, #B8860B 35%, transparent 75%),
radial-gradient(ellipse 7px 22px at 23% 22%, #F4A460 0%, #DAA520 40%, transparent 85%),
/* 麦田远景效果 */
linear-gradient(180deg, transparent 70%, rgba(255, 215, 0, 0.1) 75%, rgba(218, 165, 32, 0.15) 85%, rgba(255, 215, 0, 0.2) 95%, rgba(255, 215, 0, 0.25) 100%),
/* 散落稻粒 */
radial-gradient(ellipse 2px 8px at 60% 40%, #FFD700 0%, transparent 60%),
radial-gradient(ellipse 1.5px 6px at 40% 60%, #FFCC00 0%, transparent 65%),
radial-gradient(ellipse 2.5px 10px at 85% 50%, #DEB887 0%, transparent 70%),
radial-gradient(ellipse 1.8px 7px at 15% 80%, #DAA520 0%, transparent 68%);
background-size:
/* 主茎秆 */
100vw 80vh, 100vw 82vh,
/* 主穗头 */
50vw 60vh, 48vw 58vh, 52vw 62vh, 46vw 56vh, 50vw 60vh,
/* 分支 */
40vw 50vh, 38vw 48vh, 42vw 52vh, 36vw 46vh,
/* 左侧茎秆 */
100vw 70vh,
/* 左侧穗头 */
35vw 45vh, 33vw 43vh, 37vw 47vh,
/* 麦田远景 */
100vw 100vh,
/* 散落稻粒 */
20vw 20vh, 25vw 25vh, 30vw 30vh, 22vw 22vh;
background-position:
/* 主茎秆 */
70% 20%, 72% 18%,
/* 主穗头 */
60% 0%, 62% 2%, 58% -2%, 64% 4%, 60% 1%,
/* 分支 */
65% 15%, 67% 17%, 63% 13%, 69% 19%,
/* 左侧茎秆 */
20% 30%,
/* 左侧穗头 */
15% 20%, 17% 22%, 13% 18%,
/* 麦田远景 */
0% 0%,
/* 散落稻粒 */
30% 50%, 50% 70%, 80% 40%, 10% 80%;
background-repeat: no-repeat;
opacity: 0.4;
pointer-events: none;
z-index: -1;
animation: wheatSway 25s ease-in-out infinite;
}
@keyframes spiralRotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 流星效果容器 */
.meteor-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
overflow: hidden;
}
/* 流星轨迹 */
.meteor {
position: absolute;
width: 2px;
height: 2px;
background: radial-gradient(circle, #FFD700 0%, #FFA500 50%, transparent 100%);
border-radius: 50%;
box-shadow:
0 0 10px #FFD700,
0 0 20px #FFA500,
0 0 30px #FF8C00;
animation: meteorFall linear infinite;
}
/* 流星尾迹 */
.meteor::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 1px;
background: linear-gradient(90deg,
#FFD700 0%,
#FFA500 30%,
#FF8C00 60%,
transparent 100%);
transform-origin: 0 50%;
transform: rotate(-45deg);
opacity: 0.8;
}
@keyframes meteorFall {
0% {
transform: translateX(-100px) translateY(-100px);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateX(calc(100vw + 100px)) translateY(calc(100vh + 100px));
opacity: 0;
}
}
/* 多个流星的不同轨迹 */
.meteor:nth-child(1) {
top: 10%;
left: -100px;
animation-duration: 8s;
animation-delay: 0s;
}
.meteor:nth-child(2) {
top: 20%;
left: -100px;
animation-duration: 12s;
animation-delay: 2s;
}
.meteor:nth-child(3) {
top: 30%;
left: -100px;
animation-duration: 10s;
animation-delay: 4s;
}
.meteor:nth-child(4) {
top: 50%;
left: -100px;
animation-duration: 15s;
animation-delay: 6s;
}
.meteor:nth-child(5) {
top: 70%;
left: -100px;
animation-duration: 9s;
animation-delay: 8s;
}
.meteor:nth-child(6) {
top: 80%;
left: -100px;
animation-duration: 11s;
animation-delay: 10s;
}
/* 金色粒子效果 */
.golden-particles {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
}
.particle {
position: absolute;
width: 3px;
height: 3px;
background: radial-gradient(circle, #FFD700 0%, #FFA500 70%, transparent 100%);
border-radius: 50%;
animation: particleFloat linear infinite;
}
@keyframes particleFloat {
0% {
transform: translateY(100vh) rotate(0deg);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(-100px) rotate(360deg);
opacity: 0;
}
}
/* 粒子的不同位置和动画时长 */
.particle:nth-child(1) { left: 10%; animation-duration: 20s; animation-delay: 0s; }
.particle:nth-child(2) { left: 20%; animation-duration: 25s; animation-delay: 2s; }
.particle:nth-child(3) { left: 30%; animation-duration: 18s; animation-delay: 4s; }
.particle:nth-child(4) { left: 40%; animation-duration: 22s; animation-delay: 6s; }
.particle:nth-child(5) { left: 50%; animation-duration: 24s; animation-delay: 8s; }
.particle:nth-child(6) { left: 60%; animation-duration: 19s; animation-delay: 10s; }
.particle:nth-child(7) { left: 70%; animation-duration: 21s; animation-delay: 12s; }
.particle:nth-child(8) { left: 80%; animation-duration: 23s; animation-delay: 14s; }
.particle:nth-child(9) { left: 90%; animation-duration: 26s; animation-delay: 16s; }
/* 响应式设计 */
@media (max-width: 768px) {
.meteor {
width: 1px;
height: 1px;
}
.meteor::before {
width: 50px;
}
.particle {
width: 2px;
height: 2px;
}
body::before {
background-size:
30px 30px, 25px 25px, 35px 35px, 28px 28px, 32px 32px,
40px 40px, 45px 45px;
}
body::after {
background-size: 200px 200px, 150px 150px, 100px 100px;
}
}
/* 麦穗飘舞特效 */
.wheat-floating {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 2;
overflow: hidden;
}
/* 移动设备性能优化 */
@media (max-width: 768px) {
.wheat-floating {
display: none;
}
.golden-particles {
display: none;
}
.meteor-container {
display: none;
}
.adaptive-overlay {
animation: none;
background: rgba(255, 255, 255, 0.1);
}
}
.wheat-particle {
position: absolute;
width: 8px;
height: 20px;
background: linear-gradient(180deg,
#FFD700 0%,
#DAA520 50%,
#B8860B 100%
);
border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
opacity: 0.7;
animation: wheatFloat 15s linear infinite;
}
.wheat-particle::before {
content: '';
position: absolute;
top: -3px;
left: 50%;
transform: translateX(-50%);
width: 2px;
height: 8px;
background: #8B7355;
border-radius: 1px;
}
.wheat-particle::after {
content: '';
position: absolute;
top: 2px;
left: 1px;
width: 2px;
height: 4px;
background: #FFEC8C;
border-radius: 50%;
box-shadow:
3px 2px 0 #FFEC8C,
1px 6px 0 #FFEC8C,
4px 8px 0 #FFEC8C;
}
@keyframes wheatFloat {
0% {
transform: translateY(-100vh) translateX(0) rotate(0deg);
opacity: 0;
}
10% {
opacity: 0.7;
}
90% {
opacity: 0.7;
}
100% {
transform: translateY(100vh) translateX(50px) rotate(360deg);
opacity: 0;
}
}
/* 不同大小和速度的麦穗 */
.wheat-particle:nth-child(1) {
left: 10%;
animation-duration: 12s;
animation-delay: 0s;
transform: scale(0.8);
}
.wheat-particle:nth-child(2) {
left: 25%;
animation-duration: 18s;
animation-delay: 2s;
transform: scale(1.2);
}
.wheat-particle:nth-child(3) {
left: 40%;
animation-duration: 15s;
animation-delay: 4s;
transform: scale(0.9);
}
.wheat-particle:nth-child(4) {
left: 60%;
animation-duration: 20s;
animation-delay: 1s;
transform: scale(1.1);
}
.wheat-particle:nth-child(5) {
left: 75%;
animation-duration: 14s;
animation-delay: 3s;
transform: scale(0.7);
}
.wheat-particle:nth-child(6) {
left: 90%;
animation-duration: 16s;
animation-delay: 5s;
transform: scale(1.0);
}
.wheat-particle:nth-child(7) {
left: 5%;
animation-duration: 22s;
animation-delay: 6s;
transform: scale(0.6);
}
.wheat-particle:nth-child(8) {
left: 35%;
animation-duration: 13s;
animation-delay: 2.5s;
transform: scale(1.3);
}
/* 减少动画偏好设置 */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
.meteor,
.particle {
display: none;
}
}

View File

@@ -1,108 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🌙农历信息查询</title>
<link rel="stylesheet" href="css/background.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<!-- 动态调节遮罩层 -->
<div class="adaptive-overlay"></div>
<!-- 流星效果容器 -->
<div class="meteor-container">
<div class="meteor"></div>
<div class="meteor"></div>
<div class="meteor"></div>
<div class="meteor"></div>
<div class="meteor"></div>
<div class="meteor"></div>
</div>
<!-- 金色粒子效果容器 -->
<div class="golden-particles">
<div class="particle"></div>
<div class="particle"></div>
<div class="particle"></div>
<div class="particle"></div>
<div class="particle"></div>
<div class="particle"></div>
<div class="particle"></div>
<div class="particle"></div>
<div class="particle"></div>
</div>
<!-- 麦穗飘舞特效 -->
<div class="wheat-floating">
<div class="wheat-particle"></div>
<div class="wheat-particle"></div>
<div class="wheat-particle"></div>
<div class="wheat-particle"></div>
<div class="wheat-particle"></div>
<div class="wheat-particle"></div>
<div class="wheat-particle"></div>
<div class="wheat-particle"></div>
</div>
<div class="container">
<header class="header">
<h1 class="title">🌙农历信息查询</h1>
<p class="subtitle">传统文化 · 时光转换 · 节气查询</p>
<div class="date-selector">
<div class="input-group">
<label for="dateInput" class="input-label">
<span class="label-icon">📅</span>
选择日期
</label>
<input type="date" id="dateInput" class="date-input" />
</div>
<button id="queryBtn" class="query-btn">
<span class="btn-icon">🔍</span>
查询农历
</button>
</div>
<div class="update-time">
<span class="time-icon"></span>
<span id="updateTime">等待查询...</span>
</div>
</header>
<div class="loading" id="loading" style="display: none;">
<div class="loading-content">
<div class="glass-spinner"></div>
<div class="loading-text">
<span class="loading-emoji">🔮</span>
<p>正在查询农历信息...</p>
<div class="loading-dots">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
</div>
<div class="lunar-info" id="lunarInfo" style="display: none;">
<!-- 农历信息将动态生成 -->
</div>
<div class="error-message" id="errorMessage" style="display: none;">
<div class="error-content">
<div class="error-icon">😔</div>
<h3>查询失败了</h3>
<p>无法获取农历信息,请稍后重试</p>
<button onclick="queryLunarInfo()" class="retry-btn">
<span>🔄</span>
重新查询
</button>
</div>
</div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -1,475 +0,0 @@
// API接口列表
const API_ENDPOINTS = [
"https://60s.api.shumengya.top",
];
// 当前使用的API索引
let currentApiIndex = 0;
// DOM元素
const loadingElement = document.getElementById('loading');
const lunarInfoElement = document.getElementById('lunarInfo');
const errorMessageElement = document.getElementById('errorMessage');
const updateTimeElement = document.getElementById('updateTime');
const dateInput = document.getElementById('dateInput');
const queryBtn = document.getElementById('queryBtn');
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
initializePage();
});
// 初始化页面
function initializePage() {
// 设置默认日期为今天
const today = new Date();
const dateString = today.toISOString().split('T')[0];
dateInput.value = dateString;
// 绑定事件
queryBtn.addEventListener('click', queryLunarInfo);
dateInput.addEventListener('change', queryLunarInfo);
// 自动查询当天信息
queryLunarInfo();
}
// 查询农历信息
async function queryLunarInfo() {
const selectedDate = dateInput.value;
if (!selectedDate) {
showError('请选择查询日期');
return;
}
showLoading();
hideError();
hideLunarInfo();
try {
const data = await fetchLunarData(selectedDate);
displayLunarInfo(data.data);
updateQueryTime();
} catch (error) {
console.error('查询失败:', error);
showError('查询农历信息失败,请稍后重试');
}
hideLoading();
}
// 获取农历数据
async function fetchLunarData(date) {
for (let i = 0; i < API_ENDPOINTS.length; i++) {
const apiUrl = API_ENDPOINTS[currentApiIndex];
try {
const response = await fetch(`${apiUrl}/v2/lunar?date=${date}`, {
method: 'GET',
headers: {
'Accept': 'application/json',
},
timeout: 10000
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
if (data.code === 200 && data.data) {
return data;
} else {
throw new Error('数据格式错误');
}
} catch (error) {
console.error(`API ${apiUrl} 请求失败:`, error);
currentApiIndex = (currentApiIndex + 1) % API_ENDPOINTS.length;
if (i === API_ENDPOINTS.length - 1) {
throw new Error('所有API接口都无法访问');
}
}
}
}
// 显示农历信息
function displayLunarInfo(lunarData) {
lunarInfoElement.innerHTML = `
<div class="info-card">
<div class="card-header">
<div class="card-icon">📅</div>
<div class="card-title">公历信息</div>
</div>
<div class="card-content">
<div class="info-item">
<div class="item-icon">🗓️</div>
<div class="item-label">公历日期</div>
<div class="item-value">${lunarData.solar.year}${String(lunarData.solar.month).padStart(2, '0')}${String(lunarData.solar.day).padStart(2, '0')}日</div>
</div>
<div class="info-item">
<div class="item-icon">🌍</div>
<div class="item-label">星期</div>
<div class="item-value">${lunarData.solar.week_desc}</div>
</div>
<div class="info-item">
<div class="item-icon">🍂</div>
<div class="item-label">季节</div>
<div class="item-value">${lunarData.solar.season_name_desc}</div>
</div>
<div class="info-item">
<div class="item-icon">⭐</div>
<div class="item-label">星座</div>
<div class="item-value">${lunarData.constellation.name}</div>
</div>
</div>
</div>
<div class="info-card">
<div class="card-header">
<div class="card-icon">🌙</div>
<div class="card-title">农历信息</div>
</div>
<div class="card-content">
<div class="info-item">
<div class="item-icon">🏮</div>
<div class="item-label">农历日期</div>
<div class="item-value">${lunarData.lunar.desc_short}</div>
</div>
<div class="info-item">
<div class="item-icon">🐲</div>
<div class="item-label">生肖年</div>
<div class="item-value">${lunarData.zodiac.year}年</div>
</div>
<div class="info-item">
<div class="item-icon">☯️</div>
<div class="item-label">天干地支</div>
<div class="item-value">${lunarData.sixty_cycle.year.name}</div>
</div>
<div class="info-item">
<div class="item-icon">🌙</div>
<div class="item-label">月相</div>
<div class="item-value">${lunarData.phase.name}</div>
</div>
</div>
</div>
<div class="info-card">
<div class="card-header">
<div class="card-icon">🌾</div>
<div class="card-title">节气节日</div>
</div>
<div class="card-content">
<div class="info-item">
<div class="item-icon">🌱</div>
<div class="item-label">当前节气</div>
<div class="item-value">${lunarData.term.stage ? lunarData.term.stage.name : '无节气'}</div>
</div>
<div class="info-item">
<div class="item-icon">🎉</div>
<div class="item-label">法定假日</div>
<div class="item-value">${lunarData.legal_holiday ? lunarData.legal_holiday.name : '无假日'}</div>
</div>
<div class="info-item">
<div class="item-icon">🎊</div>
<div class="item-label">传统节日</div>
<div class="item-value">${lunarData.festival.both_desc || '无特殊节日'}</div>
</div>
<div class="info-item">
<div class="item-icon">📊</div>
<div class="item-label">一年第几天</div>
<div class="item-value">第${lunarData.stats.day_of_year}天</div>
</div>
</div>
</div>
<div class="info-card">
<div class="card-header">
<div class="card-icon">⏰</div>
<div class="card-title">时辰干支</div>
</div>
<div class="card-content">
<div class="info-item">
<div class="item-icon">🕐</div>
<div class="item-label">当前时辰</div>
<div class="item-value">${lunarData.lunar.hour_desc}</div>
</div>
<div class="info-item">
<div class="item-icon">☯️</div>
<div class="item-label">时辰干支</div>
<div class="item-value">${lunarData.sixty_cycle.hour.name}</div>
</div>
<div class="info-item">
<div class="item-icon">🐾</div>
<div class="item-label">时辰生肖</div>
<div class="item-value">${lunarData.zodiac.hour}</div>
</div>
<div class="info-item">
<div class="item-icon">🎵</div>
<div class="item-label">纳音</div>
<div class="item-value">${lunarData.nayin.hour}</div>
</div>
</div>
</div>
<div class="info-card">
<div class="card-header">
<div class="card-icon">📖</div>
<div class="card-title">黄历宜忌</div>
</div>
<div class="card-content">
<div class="info-item">
<div class="item-icon">✅</div>
<div class="item-label">宜</div>
<div class="item-value">${formatTabooText(lunarData.taboo.day.recommends)}</div>
</div>
<div class="info-item">
<div class="item-icon">❌</div>
<div class="item-label">忌</div>
<div class="item-value">${formatTabooText(lunarData.taboo.day.avoids)}</div>
</div>
<div class="info-item">
<div class="item-icon">🕐</div>
<div class="item-label">时辰宜</div>
<div class="item-value">${formatTabooText(lunarData.taboo.hour.recommends)}</div>
</div>
<div class="info-item">
<div class="item-icon">🚫</div>
<div class="item-label">时辰忌</div>
<div class="item-value">${formatTabooText(lunarData.taboo.hour.avoids)}</div>
</div>
</div>
</div>
<div class="info-card">
<div class="card-header">
<div class="card-icon">🌟</div>
<div class="card-title">运势财运</div>
</div>
<div class="card-content">
<div class="info-item">
<div class="item-icon">🍀</div>
<div class="item-label">今日运势</div>
<div class="item-value">${lunarData.fortune.today_luck}</div>
</div>
<div class="info-item">
<div class="item-icon">💼</div>
<div class="item-label">事业运</div>
<div class="item-value">${lunarData.fortune.career}</div>
</div>
<div class="info-item">
<div class="item-icon">💰</div>
<div class="item-label">财运</div>
<div class="item-value">${lunarData.fortune.money}</div>
</div>
<div class="info-item">
<div class="item-icon">💖</div>
<div class="item-label">感情运</div>
<div class="item-value">${lunarData.fortune.love}</div>
</div>
</div>
</div>
<div class="info-card">
<div class="card-header">
<div class="card-icon">📈</div>
<div class="card-title">年度统计</div>
</div>
<div class="card-content">
<div class="info-item">
<div class="item-icon">📊</div>
<div class="item-label">年度进度</div>
<div class="item-value">${lunarData.stats.percents_formatted.year}</div>
</div>
<div class="info-item">
<div class="item-icon">📅</div>
<div class="item-label">本月进度</div>
<div class="item-value">${lunarData.stats.percents_formatted.month}</div>
</div>
</div>
</div>
</div>
</div>
${generateHourlyTaboo(lunarData.taboo.hours)}
`;
showLunarInfo();
}
// 格式化宜忌文本
function formatTabooText(text) {
if (!text) return '无';
return text.replace(/\./g, '、');
}
// 生成十二时辰宜忌
function generateHourlyTaboo(hours) {
if (!hours || hours.length === 0) return '';
const hourCards = hours.map(hour => `
<div class="hour-item">
<div class="hour-name">${hour.hour}</div>
<div class="hour-content">
<div class="hour-recommends">
<span class="hour-label">宜:</span>
<span class="hour-text">${formatTabooText(hour.recommends) || '无'}</span>
</div>
<div class="hour-avoids">
<span class="hour-label">忌:</span>
<span class="hour-text">${formatTabooText(hour.avoids) || '无'}</span>
</div>
</div>
</div>
`).join('');
return `
<div class="info-card hours-card">
<div class="card-header">
<div class="card-icon">⏰</div>
<div class="card-title">十二时辰宜忌</div>
</div>
<div class="card-content">
<div class="hours-grid">
${hourCards}
</div>
</div>
</div>
`;
}
// 更新查询时间
function updateQueryTime() {
const now = new Date();
const timeStr = now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
updateTimeElement.textContent = `查询时间: ${timeStr}`;
// 添加成功提示
showSuccessMessage('🌙 农历信息已更新');
}
// 显示成功消息
function showSuccessMessage(message) {
// 移除之前的提示
const existingToast = document.querySelector('.success-toast');
if (existingToast) {
existingToast.remove();
}
const toast = document.createElement('div');
toast.className = 'success-toast';
toast.textContent = message;
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
color: #1a1a1a;
padding: 12px 20px;
border-radius: 25px;
border: 1px solid rgba(255, 255, 255, 0.3);
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.2);
z-index: 1000;
font-weight: 600;
font-size: 0.9em;
animation: glassToastSlide 0.5s ease-out;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
`;
document.body.appendChild(toast);
// 3秒后自动移除
setTimeout(() => {
toast.style.animation = 'glassToastSlideOut 0.5s ease-in forwards';
setTimeout(() => toast.remove(), 500);
}, 3000);
}
// 显示加载状态
function showLoading() {
loadingElement.style.display = 'block';
}
// 隐藏加载状态
function hideLoading() {
loadingElement.style.display = 'none';
}
// 显示农历信息
function showLunarInfo() {
lunarInfoElement.style.display = 'block';
}
// 隐藏农历信息
function hideLunarInfo() {
lunarInfoElement.style.display = 'none';
}
// 显示错误信息
function showError(message = '查询失败,请稍后重试') {
errorMessageElement.style.display = 'block';
const errorContent = errorMessageElement.querySelector('.error-content p');
if (errorContent) {
errorContent.textContent = message;
}
}
// 隐藏错误信息
function hideError() {
errorMessageElement.style.display = 'none';
}
// 添加CSS动画到页面
if (!document.querySelector('#toast-styles')) {
const style = document.createElement('style');
style.id = 'toast-styles';
style.textContent = `
@keyframes glassToastSlide {
from {
opacity: 0;
transform: translateX(100px) scale(0.8);
}
to {
opacity: 1;
transform: translateX(0) scale(1);
}
}
@keyframes glassToastSlideOut {
from {
opacity: 1;
transform: translateX(0) scale(1);
}
to {
opacity: 0;
transform: translateX(100px) scale(0.8);
}
}
`;
document.head.appendChild(style);
}
// 键盘快捷键支持
document.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
queryLunarInfo();
}
if (e.key === 'r' && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
queryLunarInfo();
}
});

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top"
]

View File

@@ -1,647 +0,0 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"solar": {
"year": 2025,
"month": 9,
"day": 1,
"hour": 17,
"minute": 58,
"second": 47,
"full": "2025-09-01",
"full_with_time": "2025-09-01 17:58:47",
"week": 1,
"week_desc": "星期一",
"week_desc_short": "一",
"season": 3,
"season_desc": "三季度",
"season_desc_short": "三",
"season_name": "秋",
"season_name_desc": "秋天",
"is_leap_year": false
},
"lunar": {
"year": "乙巳",
"month": "七",
"day": "初十",
"hour": "酉",
"full_with_hour": "农历乙巳年七月初十酉时",
"desc_short": "农历乙巳年七月初十",
"year_desc": "农历乙巳年",
"month_desc": "七月",
"day_desc": "初十",
"hour_desc": "酉时",
"is_leap_month": false
},
"stats": {
"day_of_year": 244,
"week_of_year": 36,
"week_of_month": 1,
"percents": {
"year": 0.665753424657534,
"month": 0.0333333333333333,
"week": 0.142857142857143,
"day": 0.749161909722222
},
"percents_formatted": {
"year": "66.58%",
"month": "3.33%",
"week": "14.29%",
"day": "74.92%"
}
},
"term": {
"today": null,
"stage": {
"name": "处暑",
"position": 10,
"is_jie": false,
"is_qi": true
}
},
"zodiac": {
"year": "蛇",
"month": "鸡",
"day": "鸡",
"hour": "鸡"
},
"sixty_cycle": {
"year": {
"heaven_stem": "乙",
"earth_branch": "巳",
"name": "乙巳年",
"name_short": "乙巳"
},
"month": {
"heaven_stem": "乙",
"earth_branch": "酉",
"name": "乙酉月",
"name_short": "乙酉"
},
"day": {
"heaven_stem": "癸",
"earth_branch": "酉",
"name": "癸酉日",
"name_short": "癸酉"
},
"hour": {
"heaven_stem": "辛",
"earth_branch": "酉",
"name": "辛酉时",
"name_short": "辛酉"
}
},
"legal_holiday": null,
"festival": {
"solar": null,
"lunar": null,
"both_desc": null
},
"phase": {
"name": "宵月",
"position": 10
},
"constellation": {
"name": "处女座",
"name_short": "处女"
},
"taboo": {
"day": {
"recommends": "解除.祭祀.祈福.求嗣.修造.动土.竖柱.上梁.安床.纳畜.盖屋.合脊.起基.入殓.破土.安葬",
"avoids": "出火.嫁娶.开光.进人口.出行.词讼.开市.入宅.移徙.赴任"
},
"hour": {
"hour": "酉时",
"hour_short": "酉",
"avoids": "乘船.造桥",
"recommends": "嫁娶.出行.移徙.入宅.开市.赴任.祈福.安床.开仓.盖屋.修造.求财"
},
"hours": [
{
"hour": "酉时",
"hour_short": "酉",
"recommends": "嫁娶.出行.移徙.入宅.开市.赴任.祈福.安床.开仓.盖屋.修造.求财",
"avoids": "乘船.造桥"
},
{
"hour": "戌时",
"hour_short": "戌",
"recommends": "嫁娶.移徙.安葬.进人口.求财",
"avoids": "出行.赴任.祈福.祭祀.开光.斋醮"
},
{
"hour": "亥时",
"hour_short": "亥",
"recommends": "嫁娶.移徙.交易.入宅.开市.安葬.求嗣.求财",
"avoids": "出行.赴任.动土.祈福.祭祀.修造.开光.斋醮"
},
{
"hour": "子时",
"hour_short": "子",
"recommends": "嫁娶.交易.入宅.开市.祈福.安葬.求嗣.求财",
"avoids": "出行.移徙.赴任.词讼.修造"
},
{
"hour": "丑时",
"hour_short": "丑",
"recommends": "嫁娶.祈福.安葬.祭祀.酬神.求财",
"avoids": "出行.赴任.动土.修造"
},
{
"hour": "寅时",
"hour_short": "寅",
"recommends": "嫁娶.出行.交易.开市.赴任.祈福.安床.祭祀.求嗣.求财",
"avoids": "盖屋.入殓.上梁"
},
{
"hour": "卯时",
"hour_short": "卯",
"recommends": "嫁娶.交易.入宅.开市.祈福.安床.安葬.求嗣.求财",
"avoids": "出行.赴任.修造"
},
{
"hour": "辰时",
"hour_short": "辰",
"recommends": "",
"avoids": "诸事不宜"
},
{
"hour": "巳时",
"hour_short": "巳",
"recommends": "嫁娶.出行.移徙.入宅.开市.祈福.安床.盖屋.祭祀.作灶",
"avoids": "安葬.修造.开光"
},
{
"hour": "午时",
"hour_short": "午",
"recommends": "嫁娶.出行.交易.开市.祈福.安床.求嗣.求财",
"avoids": "赴任.动土.词讼.修造"
},
{
"hour": "未时",
"hour_short": "未",
"recommends": "嫁娶.入宅.祈福.安葬.祭祀.修造.酬神.求财",
"avoids": "出行.赴任"
},
{
"hour": "申时",
"hour_short": "申",
"recommends": "嫁娶.出行.开市.赴任.安葬.求财",
"avoids": "祈福.祭祀.酬神.斋醮"
}
]
},
"julian_day": 2460919.5,
"nayin": {
"year": "覆灯火",
"month": "泉中水",
"day": "剑锋金",
"hour": "石榴木"
},
"baizi": {
"year_baizi": "性格温和,为人正直诚信。",
"day_baizi": "性格温和,为人正直诚信。"
},
"fortune": {
"today_luck": "今日学习运好,适合进修",
"career": "领导能力突出,升职有望",
"money": "偏财运不错,可小试投资",
"love": "感情需要沟通,避免误会"
},
"constants": {
"legal_holiday_list": [
{
"name": "元旦节",
"date": "2025-01-01",
"start": "2025-01-01",
"end": "2025-01-01"
},
{
"name": "春节",
"date": "2025-01-29",
"start": "2025-01-26",
"end": "2025-02-08"
},
{
"name": "清明节",
"date": "2025-04-04",
"start": "2025-04-04",
"end": "2025-04-06"
},
{
"name": "劳动节",
"date": "2025-05-01",
"start": "2025-04-27",
"end": "2025-05-05"
},
{
"name": "端午节",
"date": "2025-05-31",
"start": "2025-05-31",
"end": "2025-06-02"
},
{
"name": "国庆中秋",
"date": "2025-10-01",
"start": "2025-09-28",
"end": "2025-10-11"
}
],
"phase_list": [
{
"name": "朔月",
"lunar_day": 1
},
{
"name": "既朔月",
"lunar_day": 2
},
{
"name": "蛾眉新月",
"lunar_day": 3
},
{
"name": "蛾眉新月",
"lunar_day": 4
},
{
"name": "蛾眉月",
"lunar_day": 5
},
{
"name": "夕月",
"lunar_day": 6
},
{
"name": "上弦月",
"lunar_day": 7
},
{
"name": "上弦月",
"lunar_day": 8
},
{
"name": "九夜月",
"lunar_day": 9
},
{
"name": "宵月",
"lunar_day": 10
},
{
"name": "宵月",
"lunar_day": 11
},
{
"name": "宵月",
"lunar_day": 12
},
{
"name": "渐盈凸月",
"lunar_day": 13
},
{
"name": "小望月",
"lunar_day": 14
},
{
"name": "望月",
"lunar_day": 15
},
{
"name": "既望月",
"lunar_day": 16
},
{
"name": "立待月",
"lunar_day": 17
},
{
"name": "居待月",
"lunar_day": 18
},
{
"name": "寝待月",
"lunar_day": 19
},
{
"name": "更待月",
"lunar_day": 20
},
{
"name": "渐亏凸月",
"lunar_day": 21
},
{
"name": "下弦月",
"lunar_day": 22
},
{
"name": "下弦月",
"lunar_day": 23
},
{
"name": "有明月",
"lunar_day": 24
},
{
"name": "有明月",
"lunar_day": 25
},
{
"name": "蛾眉残月",
"lunar_day": 26
},
{
"name": "蛾眉残月",
"lunar_day": 27
},
{
"name": "残月",
"lunar_day": 28
},
{
"name": "晓月",
"lunar_day": 29
},
{
"name": "晦月",
"lunar_day": 30
}
],
"zodiac_list": [
"鼠",
"牛",
"虎",
"兔",
"龙",
"蛇",
"马",
"羊",
"猴",
"鸡",
"狗",
"猪"
],
"constellation_list": [
{
"name": "白羊",
"desc": "白羊座",
"start": "3月21日",
"end": "4月19日",
"range": "3月21日~4月19日",
"start_month": 3,
"start_day": 21,
"end_month": 4,
"end_day": 19
},
{
"name": "金牛",
"desc": "金牛座",
"start": "4月20日",
"end": "5月20日",
"range": "4月20日~5月20日",
"start_month": 4,
"start_day": 20,
"end_month": 5,
"end_day": 20
},
{
"name": "双子",
"desc": "双子座",
"start": "5月21日",
"end": "6月21日",
"range": "5月21日~6月21日",
"start_month": 5,
"start_day": 21,
"end_month": 6,
"end_day": 21
},
{
"name": "巨蟹",
"desc": "巨蟹座",
"start": "6月22日",
"end": "7月22日",
"range": "6月22日~7月22日",
"start_month": 6,
"start_day": 22,
"end_month": 7,
"end_day": 22
},
{
"name": "狮子",
"desc": "狮子座",
"start": "7月23日",
"end": "8月22日",
"range": "7月23日~8月22日",
"start_month": 7,
"start_day": 23,
"end_month": 8,
"end_day": 22
},
{
"name": "处女",
"desc": "处女座",
"start": "8月23日",
"end": "9月22日",
"range": "8月23日~9月22日",
"start_month": 8,
"start_day": 23,
"end_month": 9,
"end_day": 22
},
{
"name": "天秤",
"desc": "天秤座",
"start": "9月23日",
"end": "10月23日",
"range": "9月23日~10月23日",
"start_month": 9,
"start_day": 23,
"end_month": 10,
"end_day": 23
},
{
"name": "天蝎",
"desc": "天蝎座",
"start": "10月24日",
"end": "11月22日",
"range": "10月24日~11月22日",
"start_month": 10,
"start_day": 24,
"end_month": 11,
"end_day": 22
},
{
"name": "射手",
"desc": "射手座",
"start": "11月23日",
"end": "12月21日",
"range": "11月23日~12月21日",
"start_month": 11,
"start_day": 23,
"end_month": 12,
"end_day": 21
},
{
"name": "摩羯",
"desc": "摩羯座",
"start": "12月22日",
"end": "1月19日",
"range": "12月22日~1月19日",
"start_month": 12,
"start_day": 22,
"end_month": 1,
"end_day": 19
},
{
"name": "水瓶",
"desc": "水瓶座",
"start": "1月20日",
"end": "2月18日",
"range": "1月20日~2月18日",
"start_month": 1,
"start_day": 20,
"end_month": 2,
"end_day": 18
},
{
"name": "双鱼",
"desc": "双鱼座",
"start": "2月19日",
"end": "3月20日",
"range": "2月19日~3月20日",
"start_month": 2,
"start_day": 19,
"end_month": 3,
"end_day": 20
}
],
"heaven_stems": [
"甲",
"乙",
"丙",
"丁",
"戊",
"己",
"庚",
"辛",
"壬",
"癸"
],
"earth_branches": [
"子",
"丑",
"寅",
"卯",
"辰",
"巳",
"午",
"未",
"申",
"酉",
"戌",
"亥"
],
"solar_terms": [
{
"name": "立春",
"desc": "春季开始"
},
{
"name": "雨水",
"desc": "降雨增多"
},
{
"name": "惊蛰",
"desc": "春雷乍响"
},
{
"name": "春分",
"desc": "昼夜等长"
},
{
"name": "清明",
"desc": "天清地明"
},
{
"name": "谷雨",
"desc": "雨生百谷"
},
{
"name": "立夏",
"desc": "夏季开始"
},
{
"name": "小满",
"desc": "麦粒渐满"
},
{
"name": "芒种",
"desc": "麦类收割"
},
{
"name": "夏至",
"desc": "白昼最长"
},
{
"name": "小暑",
"desc": "天气渐热"
},
{
"name": "大暑",
"desc": "一年最热"
},
{
"name": "立秋",
"desc": "秋季开始"
},
{
"name": "处暑",
"desc": "暑热结束"
},
{
"name": "白露",
"desc": "露水增多"
},
{
"name": "秋分",
"desc": "昼夜等长"
},
{
"name": "寒露",
"desc": "露水渐凉"
},
{
"name": "霜降",
"desc": "开始降霜"
},
{
"name": "立冬",
"desc": "冬季开始"
},
{
"name": "小雪",
"desc": "开始降雪"
},
{
"name": "大雪",
"desc": "降雪增多"
},
{
"name": "冬至",
"desc": "白昼最短"
},
{
"name": "小寒",
"desc": "天气渐冷"
},
{
"name": "大寒",
"desc": "一年最冷"
}
]
}
}
}

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>化学元素查询</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.form{display:flex;flex-direction:column;gap:10px;margin-bottom:20px;background:#fff;border-radius:16px;padding:20px;box-shadow:0 1px 4px rgba(0,0,0,.05)}
.form label{font-size:12px;font-weight:600;color:#6b7280}
.form input{padding:11px 14px;border:2px solid #e5e7eb;border-radius:10px;font-size:13px;font-family:inherit;transition:border-color .2s}
.form input:focus{border-color:#4ade80;outline:none}
.form button{display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:11px 22px;border:none;border-radius:10px;background:linear-gradient(135deg,#4ade80,#22c55e);color:#fff;font-size:13px;font-weight:600;cursor:pointer;transition:all .2s}
.form button:hover{transform:translateY(-1px)}.form button:disabled{opacity:.5;cursor:not-allowed;transform:none}
.info-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
.info-card{background:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
.info-label{font-size:11px;color:#9ca3af;margin-bottom:3px}.info-val{font-size:14px;font-weight:600;word-break:break-all}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:28px 20px;text-align:center;border:1px solid rgba(34,197,94,.12)}
.quote-text{font-size:16px;line-height:2;color:#374151;font-weight:500}
.loader{display:flex;flex-direction:column;align-items:center;padding:40px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:20px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>⚗️ 化学元素查询</h1>
</div>
<div class="body">
<div class="form" id="formArea"><label>元素</label>
<input id="input_q" placeholder="如 Fe 或 铁" onkeydown="if(event.key==='Enter')query()">
<button onclick="query()" id="submitBtn">🔍 查询</button></div>
<div id="result"></div>
</div>
<script>
async function query(){
const params=new URLSearchParams({encoding:'json'});
const v_q=document.getElementById('input_q').value.trim();if(v_q)params.set('q',v_q);
const el=document.getElementById('result');
const btn=document.getElementById('submitBtn');
btn.disabled=true;btn.textContent='查询中...';
el.innerHTML='<div class="loader"><div class="spinner"></div><span>查询中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/chemical?'+params.toString(),{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
if(typeof d==='string'){el.innerHTML=`<div class="quote"><div class="quote-text">${d}</div></div>`;return}
if(Array.isArray(d)){let h='';d.forEach((item,i)=>{const t=item.title||item.name||String(item);h+=`<div class="info-card"><div class="info-label">#${i+1}</div><div class="info-val">${t}</div></div>`});el.innerHTML=`<div class="info-grid">${h}</div>`;return}
if(d&&typeof d==='object'){const entries=Object.entries(d).filter(([k])=>!['code','ok','api_updated'].includes(k));let h='';entries.forEach(([k,v])=>{h+=`<div class="info-card"><div class="info-label">${k}</div><div class="info-val">${typeof v==='object'?JSON.stringify(v):String(v)}</div></div>`});el.innerHTML=`<div class="info-grid">${h}</div>`;return}
el.innerHTML=`<div class="quote"><div class="quote-text">${String(d)}</div></div>`;
}catch(e){el.innerHTML=`<div class="err">查询失败:${e.message}</div>`}
finally{btn.disabled=false;btn.textContent='🔍 查询'}
}
</script>
</body>
</html>

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>哈希工具</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'KaiTi','楷体',serif;background:#f9fafb;color:#1f2937;line-height:1.6;min-height:100vh}
.header{background:linear-gradient(135deg,#065f46,#059669);color:#fff;padding:16px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:10}
.header h1{flex:1;font-size:16px;font-weight:700}.btn{width:36px;height:36px;border:none;border-radius:10px;background:rgba(255,255,255,.15);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}.btn:hover{background:rgba(255,255,255,.25)}
.body{max-width:720px;margin:0 auto;padding:20px 16px 40px}
.form{display:flex;flex-direction:column;gap:10px;margin-bottom:20px;background:#fff;border-radius:16px;padding:20px;box-shadow:0 1px 4px rgba(0,0,0,.05)}
.form label{font-size:12px;font-weight:600;color:#6b7280}
.form input{padding:11px 14px;border:2px solid #e5e7eb;border-radius:10px;font-size:13px;font-family:inherit;transition:border-color .2s}
.form input:focus{border-color:#4ade80;outline:none}
.form button{display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:11px 22px;border:none;border-radius:10px;background:linear-gradient(135deg,#4ade80,#22c55e);color:#fff;font-size:13px;font-weight:600;cursor:pointer;transition:all .2s}
.form button:hover{transform:translateY(-1px)}.form button:disabled{opacity:.5;cursor:not-allowed;transform:none}
.info-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
.info-card{background:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 1px 3px rgba(0,0,0,.04)}
.info-label{font-size:11px;color:#9ca3af;margin-bottom:3px}.info-val{font-size:14px;font-weight:600;word-break:break-all}
.quote{background:linear-gradient(135deg,#f0fdf4,#ecfdf5);border-radius:20px;padding:28px 20px;text-align:center;border:1px solid rgba(34,197,94,.12)}
.quote-text{font-size:16px;line-height:2;color:#374151;font-weight:500}
.loader{display:flex;flex-direction:column;align-items:center;padding:40px 0;color:#9ca3af;gap:10px;font-size:13px}
.spinner{width:24px;height:24px;border:3px solid #e5e7eb;border-top-color:#059669;border-radius:50%;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.err{text-align:center;padding:20px;color:#ef4444;font-size:14px}
</style>
<script src="/60sapi/ig-embed.js"></script>
<script src="/60sapi/sixty-runtime.js"></script>
</head>
<body>
<div class="header">
<button class="btn" onclick="history.back()"></button>
<h1>🗜️ 哈希工具</h1>
</div>
<div class="body">
<div class="form" id="formArea"><label>内容</label>
<input id="input_text" placeholder="输入需要哈希的文本" onkeydown="if(event.key==='Enter')query()">
<button onclick="query()" id="submitBtn">🔍 查询</button></div>
<div id="result"></div>
</div>
<script>
async function query(){
const params=new URLSearchParams({encoding:'json'});
const v_text=document.getElementById('input_text').value.trim();if(v_text)params.set('text',v_text);
const el=document.getElementById('result');
const btn=document.getElementById('submitBtn');
btn.disabled=true;btn.textContent='查询中...';
el.innerHTML='<div class="loader"><div class="spinner"></div><span>查询中...</span></div>';
try{
const res=await fetch(window.__SIXTY_API_BASE__+'/v2/hash?'+params.toString(),{headers:{Accept:'application/json'}});
const json=await res.json();
const d=json.data!==undefined?json.data:json;
if(typeof d==='string'){el.innerHTML=`<div class="quote"><div class="quote-text">${d}</div></div>`;return}
if(Array.isArray(d)){let h='';d.forEach((item,i)=>{const t=item.title||item.name||String(item);h+=`<div class="info-card"><div class="info-label">#${i+1}</div><div class="info-val">${t}</div></div>`});el.innerHTML=`<div class="info-grid">${h}</div>`;return}
if(d&&typeof d==='object'){const entries=Object.entries(d).filter(([k])=>!['code','ok','api_updated'].includes(k));let h='';entries.forEach(([k,v])=>{h+=`<div class="info-card"><div class="info-label">${k}</div><div class="info-val">${typeof v==='object'?JSON.stringify(v):String(v)}</div></div>`});el.innerHTML=`<div class="info-grid">${h}</div>`;return}
el.innerHTML=`<div class="quote"><div class="quote-text">${String(d)}</div></div>`;
}catch(e){el.innerHTML=`<div class="err">查询失败:${e.message}</div>`}
finally{btn.disabled=false;btn.textContent='🔍 查询'}
}
</script>
</body>
</html>

View File

@@ -1,577 +0,0 @@
/* Reset and Base Styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #f0f8e8 0%, #e8f5e8 50%, #d4f4dd 100%);
min-height: 100vh;
color: #333;
overflow-x: hidden;
/* 隐藏滚动条但保留滚动功能 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
/* 隐藏 Webkit 浏览器的滚动条 */
body::-webkit-scrollbar,
html::-webkit-scrollbar,
*::-webkit-scrollbar {
display: none;
}
/* 全局隐藏滚动条但保留滚动功能 */
html {
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
position: relative;
}
/* Header Styles */
.header {
text-align: center;
margin-bottom: 40px;
position: relative;
z-index: 2;
}
.header-content {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border-radius: 24px;
padding: 40px;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
}
.header-content::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1) 0%, transparent 50%, rgba(255, 255, 255, 0.1) 100%);
animation: shimmer 3s ease-in-out infinite;
}
@keyframes shimmer {
0%, 100% { transform: translateX(-100%); }
50% { transform: translateX(100%); }
}
.logo {
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
margin-bottom: 15px;
}
.logo i {
font-size: 48px;
background: linear-gradient(45deg, #228B22, #32CD32);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
.logo h1 {
font-size: 42px;
font-weight: 700;
color: white;
text-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}
.subtitle {
font-size: 18px;
color: rgba(255, 255, 255, 0.9);
font-weight: 400;
letter-spacing: 0.5px;
}
/* Floating Shapes */
.header-decoration {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
z-index: 1;
}
.floating-shapes {
position: relative;
width: 100%;
height: 100%;
}
.shape {
position: absolute;
border-radius: 50%;
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.05));
animation: float 6s ease-in-out infinite;
}
.shape-1 {
width: 80px;
height: 80px;
top: 10%;
left: 10%;
animation-delay: 0s;
}
.shape-2 {
width: 60px;
height: 60px;
top: 20%;
right: 15%;
animation-delay: 2s;
}
.shape-3 {
width: 100px;
height: 100px;
bottom: 15%;
left: 20%;
animation-delay: 4s;
}
@keyframes float {
0%, 100% { transform: translateY(0px) rotate(0deg); }
33% { transform: translateY(-20px) rotate(120deg); }
66% { transform: translateY(10px) rotate(240deg); }
}
/* Input Section */
.input-section {
margin-bottom: 40px;
}
.input-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 30px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
}
.input-card:hover {
transform: translateY(-5px);
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.15);
}
.card-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
.card-header i {
font-size: 24px;
color: #228B22;
}
.card-header h2 {
font-size: 24px;
font-weight: 600;
color: #333;
}
.input-wrapper {
position: relative;
}
#inputText {
width: 100%;
padding: 20px;
border: 2px solid #e1e5e9;
border-radius: 12px;
font-size: 16px;
font-family: inherit;
resize: vertical;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
}
#inputText:focus {
outline: none;
border-color: #228B22;
box-shadow: 0 0 0 3px rgba(34, 139, 34, 0.1);
background: rgba(255, 255, 255, 0.95);
}
.input-actions {
display: flex;
gap: 15px;
margin-top: 20px;
justify-content: flex-end;
}
/* Button Styles */
.btn {
padding: 12px 24px;
border: none;
border-radius: 10px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
text-decoration: none;
position: relative;
overflow: hidden;
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s;
}
.btn:hover::before {
left: 100%;
}
.btn-primary {
background: linear-gradient(135deg, #228B22 0%, #32CD32 100%);
color: white;
box-shadow: 0 4px 15px rgba(34, 139, 34, 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(34, 139, 34, 0.4);
}
.btn-secondary {
background: rgba(255, 255, 255, 0.8);
color: #666;
border: 1px solid #e1e5e9;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.95);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
/* Results Section */
.results-section {
opacity: 0;
transform: translateY(30px);
transition: all 0.5s ease;
}
.results-section.show {
opacity: 1;
transform: translateY(0);
}
.results-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 30px;
}
.result-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 30px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.3);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.result-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #228B22, #32CD32, #90EE90, #98FB98);
}
.result-card:hover {
transform: translateY(-5px);
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.15);
}
.result-card .card-header h3 {
font-size: 20px;
font-weight: 600;
color: #333;
}
.result-items {
display: flex;
flex-direction: column;
gap: 20px;
}
.result-item {
position: relative;
}
.result-item label {
display: block;
font-size: 14px;
font-weight: 500;
color: #666;
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.result-value {
display: flex;
align-items: center;
background: rgba(248, 250, 252, 0.8);
border: 1px solid #e1e5e9;
border-radius: 8px;
padding: 12px 16px;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 14px;
word-break: break-all;
position: relative;
transition: all 0.3s ease;
}
.result-value:hover {
background: rgba(248, 250, 252, 0.95);
border-color: #228B22;
}
.result-value .placeholder {
color: #999;
font-style: italic;
}
.copy-btn {
background: none;
border: none;
color: #228B22;
cursor: pointer;
padding: 8px;
border-radius: 6px;
transition: all 0.3s ease;
margin-left: auto;
flex-shrink: 0;
}
.copy-btn:hover {
background: rgba(34, 139, 34, 0.1);
color: #1e7e1e;
}
/* Loading Overlay */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(5px);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.loading-overlay.show {
opacity: 1;
visibility: visible;
}
.loading-spinner {
text-align: center;
color: white;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-top: 4px solid white;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Toast Notification */
.toast {
position: fixed;
bottom: 30px;
right: 30px;
background: linear-gradient(135deg, #228B22, #32CD32);
color: white;
padding: 16px 24px;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
display: flex;
align-items: center;
gap: 10px;
transform: translateX(400px);
transition: all 0.3s ease;
z-index: 1001;
}
.toast.show {
transform: translateX(0);
}
.toast i {
font-size: 18px;
}
/* Responsive Design */
@media (max-width: 768px) {
.container {
padding: 15px;
}
.header-content {
padding: 30px 20px;
}
.logo h1 {
font-size: 32px;
}
.logo i {
font-size: 36px;
}
.results-grid {
grid-template-columns: 1fr;
gap: 20px;
}
.input-actions {
flex-direction: column;
}
.btn {
justify-content: center;
}
.toast {
bottom: 20px;
right: 20px;
left: 20px;
transform: translateY(100px);
}
.toast.show {
transform: translateY(0);
}
}
@media (max-width: 480px) {
.input-card,
.result-card {
padding: 20px;
}
.card-header h2,
.card-header h3 {
font-size: 18px;
}
.result-value {
font-size: 12px;
padding: 10px 12px;
}
}
/* Animation Classes */
.fade-in {
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.slide-in {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
transform: translateX(-20px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.3);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.5);
}

View File

@@ -1,212 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多功能哈希工具 - Hash Toolkit</title>
<link rel="stylesheet" href="css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<div class="container">
<!-- Header Section -->
<header class="header">
<div class="header-content">
<div class="logo">
<i class="fas fa-fingerprint"></i>
<h1>Hash Toolkit</h1>
</div>
<p class="subtitle">多功能哈希、编码与压缩工具</p>
</div>
<div class="header-decoration">
<div class="floating-shapes">
<div class="shape shape-1"></div>
<div class="shape shape-2"></div>
<div class="shape shape-3"></div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="main-content">
<!-- Input Section -->
<section class="input-section">
<div class="input-card">
<div class="card-header">
<i class="fas fa-edit"></i>
<h2>输入内容</h2>
</div>
<div class="input-wrapper">
<textarea
id="inputText"
placeholder="请输入要处理的文本内容...\n支持中文、英文、特殊字符等"
rows="6"
></textarea>
<div class="input-actions">
<button id="clearBtn" class="btn btn-secondary">
<i class="fas fa-trash"></i>
清空
</button>
<button id="processBtn" class="btn btn-primary">
<i class="fas fa-cogs"></i>
开始处理
</button>
</div>
</div>
</div>
</section>
<!-- Results Section -->
<section class="results-section" id="resultsSection">
<div class="results-grid">
<!-- Hash Results -->
<div class="result-card hash-card">
<div class="card-header">
<i class="fas fa-hashtag"></i>
<h3>哈希算法</h3>
</div>
<div class="result-items">
<div class="result-item">
<label>MD5</label>
<div class="result-value" id="md5Result">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="md5Result">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="result-item">
<label>SHA1</label>
<div class="result-value" id="sha1Result">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="sha1Result">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="result-item">
<label>SHA256</label>
<div class="result-value" id="sha256Result">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="sha256Result">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="result-item">
<label>SHA512</label>
<div class="result-value" id="sha512Result">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="sha512Result">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Encoding Results -->
<div class="result-card encoding-card">
<div class="card-header">
<i class="fas fa-code"></i>
<h3>编码转换</h3>
</div>
<div class="result-items">
<div class="result-item">
<label>Base64 编码</label>
<div class="result-value" id="base64EncodeResult">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="base64EncodeResult">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="result-item">
<label>Base64 解码</label>
<div class="result-value" id="base64DecodeResult">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="base64DecodeResult">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="result-item">
<label>URL 编码</label>
<div class="result-value" id="urlEncodeResult">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="urlEncodeResult">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="result-item">
<label>URL 解码</label>
<div class="result-value" id="urlDecodeResult">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="urlDecodeResult">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Compression Results -->
<div class="result-card compression-card">
<div class="card-header">
<i class="fas fa-compress-alt"></i>
<h3>压缩算法</h3>
</div>
<div class="result-items">
<div class="result-item">
<label>Gzip 压缩</label>
<div class="result-value" id="gzipCompressResult">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="gzipCompressResult">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="result-item">
<label>Deflate 压缩</label>
<div class="result-value" id="deflateCompressResult">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="deflateCompressResult">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="result-item">
<label>Brotli 压缩</label>
<div class="result-value" id="brotliCompressResult">
<span class="placeholder">等待处理...</span>
<button class="copy-btn" data-target="brotliCompressResult">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
<!-- Loading Overlay -->
<div class="loading-overlay" id="loadingOverlay">
<div class="loading-spinner">
<div class="spinner"></div>
<p>正在处理中...</p>
</div>
</div>
<!-- Toast Notification -->
<div class="toast" id="toast">
<i class="fas fa-check-circle"></i>
<span id="toastMessage">复制成功!</span>
</div>
</div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -1,394 +0,0 @@
// API配置
const API_BASE_URL = 'https://60s.api.shumengya.top/v2/hash';
// DOM元素
const elements = {
inputText: document.getElementById('inputText'),
processBtn: document.getElementById('processBtn'),
clearBtn: document.getElementById('clearBtn'),
resultsSection: document.getElementById('resultsSection'),
loadingOverlay: document.getElementById('loadingOverlay'),
toast: document.getElementById('toast'),
toastMessage: document.getElementById('toastMessage')
};
// 结果元素映射
const resultElements = {
md5: document.getElementById('md5Result'),
sha1: document.getElementById('sha1Result'),
sha256: document.getElementById('sha256Result'),
sha512: document.getElementById('sha512Result'),
base64Encode: document.getElementById('base64EncodeResult'),
base64Decode: document.getElementById('base64DecodeResult'),
urlEncode: document.getElementById('urlEncodeResult'),
urlDecode: document.getElementById('urlDecodeResult'),
gzipCompress: document.getElementById('gzipCompressResult'),
deflateCompress: document.getElementById('deflateCompressResult'),
brotliCompress: document.getElementById('brotliCompressResult')
};
// 初始化
document.addEventListener('DOMContentLoaded', function() {
initializeEventListeners();
addInputAnimation();
});
// 事件监听器初始化
function initializeEventListeners() {
// 处理按钮点击
elements.processBtn.addEventListener('click', handleProcess);
// 清空按钮点击
elements.clearBtn.addEventListener('click', handleClear);
// 输入框回车键
elements.inputText.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.key === 'Enter') {
handleProcess();
}
});
// 复制按钮事件委托
document.addEventListener('click', function(e) {
if (e.target.closest('.copy-btn')) {
const copyBtn = e.target.closest('.copy-btn');
const targetId = copyBtn.getAttribute('data-target');
const targetElement = document.getElementById(targetId);
const textContent = targetElement.textContent.trim();
if (textContent && textContent !== '等待处理...' && textContent !== '处理失败') {
copyToClipboard(textContent);
}
}
});
// 输入框实时验证
elements.inputText.addEventListener('input', function() {
const hasContent = this.value.trim().length > 0;
elements.processBtn.disabled = !hasContent;
if (hasContent) {
elements.processBtn.classList.remove('disabled');
} else {
elements.processBtn.classList.add('disabled');
}
});
}
// 添加输入动画效果
function addInputAnimation() {
elements.inputText.addEventListener('focus', function() {
this.parentElement.classList.add('focused');
});
elements.inputText.addEventListener('blur', function() {
this.parentElement.classList.remove('focused');
});
}
// 处理主要功能
async function handleProcess() {
const inputValue = elements.inputText.value.trim();
if (!inputValue) {
showToast('请输入要处理的内容', 'error');
return;
}
// 显示加载状态
showLoading(true);
resetResults();
try {
// 调用API
const response = await fetch(`${API_BASE_URL}?content=${encodeURIComponent(inputValue)}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.code === 200 && data.data) {
displayResults(data.data);
showResultsSection();
showToast('处理完成!', 'success');
} else {
throw new Error(data.message || '处理失败');
}
} catch (error) {
console.error('处理错误:', error);
showToast(`处理失败: ${error.message}`, 'error');
displayError();
} finally {
showLoading(false);
}
}
// 显示结果
function displayResults(data) {
try {
// 哈希结果
updateResultElement('md5', data.md5 || '不可用');
// SHA系列
if (data.sha) {
updateResultElement('sha1', data.sha.sha1 || '不可用');
updateResultElement('sha256', data.sha.sha256 || '不可用');
updateResultElement('sha512', data.sha.sha512 || '不可用');
}
// Base64编码
if (data.base64) {
updateResultElement('base64Encode', data.base64.encoded || '不可用');
// BASE64解码只有当输入本身是BASE64格式时才显示解码结果
let base64DecodeResult = data.base64.decoded;
if (!base64DecodeResult) {
// 检查输入是否为有效的BASE64格式
const inputValue = elements.inputText.value.trim();
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
if (base64Regex.test(inputValue) && inputValue.length % 4 === 0) {
try {
base64DecodeResult = atob(inputValue);
} catch (e) {
base64DecodeResult = '解码失败';
}
} else {
base64DecodeResult = '输入非BASE64格式';
}
}
updateResultElement('base64Decode', base64DecodeResult || '不可用');
}
// URL编码
if (data.url) {
updateResultElement('urlEncode', data.url.encoded || '不可用');
updateResultElement('urlDecode', data.url.decoded || '不可用');
}
// 压缩结果(仅显示压缩,不显示解压)
if (data.gzip) {
updateResultElement('gzipCompress', data.gzip.encoded || '不可用');
}
if (data.deflate) {
updateResultElement('deflateCompress', data.deflate.encoded || '不可用');
}
if (data.brotli) {
updateResultElement('brotliCompress', data.brotli.encoded || '不可用');
}
} catch (error) {
console.error('显示结果时出错:', error);
showToast('显示结果时出错', 'error');
}
}
// 更新单个结果元素
function updateResultElement(key, value) {
const element = resultElements[key];
if (element) {
const textSpan = element.querySelector('span') || element;
textSpan.textContent = value;
textSpan.classList.remove('placeholder');
// 添加动画效果
element.classList.add('slide-in');
setTimeout(() => {
element.classList.remove('slide-in');
}, 300);
}
}
// 重置结果
function resetResults() {
Object.values(resultElements).forEach(element => {
if (element) {
const textSpan = element.querySelector('span') || element;
textSpan.textContent = '等待处理...';
textSpan.classList.add('placeholder');
}
});
}
// 显示错误状态
function displayError() {
Object.values(resultElements).forEach(element => {
if (element) {
const textSpan = element.querySelector('span') || element;
textSpan.textContent = '处理失败';
textSpan.classList.add('placeholder');
}
});
}
// 显示结果区域
function showResultsSection() {
elements.resultsSection.classList.add('show');
// 平滑滚动到结果区域
setTimeout(() => {
elements.resultsSection.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}, 100);
}
// 清空功能
function handleClear() {
elements.inputText.value = '';
elements.inputText.focus();
elements.resultsSection.classList.remove('show');
resetResults();
elements.processBtn.disabled = true;
elements.processBtn.classList.add('disabled');
showToast('内容已清空', 'info');
}
// 复制到剪贴板
async function copyToClipboard(text) {
try {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(text);
} else {
// 降级方案
const textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.left = '-999999px';
textArea.style.top = '-999999px';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
document.execCommand('copy');
textArea.remove();
}
showToast('复制成功!', 'success');
} catch (error) {
console.error('复制失败:', error);
showToast('复制失败,请手动复制', 'error');
}
}
// 显示/隐藏加载状态
function showLoading(show) {
if (show) {
elements.loadingOverlay.classList.add('show');
elements.processBtn.disabled = true;
elements.processBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 处理中...';
} else {
elements.loadingOverlay.classList.remove('show');
elements.processBtn.disabled = false;
elements.processBtn.innerHTML = '<i class="fas fa-cogs"></i> 开始处理';
}
}
// 显示提示消息
function showToast(message, type = 'success') {
elements.toastMessage.textContent = message;
// 设置图标和样式
const icon = elements.toast.querySelector('i');
icon.className = getToastIcon(type);
elements.toast.className = `toast ${type}`;
elements.toast.classList.add('show');
// 自动隐藏
setTimeout(() => {
elements.toast.classList.remove('show');
}, 3000);
}
// 获取提示图标
function getToastIcon(type) {
const icons = {
success: 'fas fa-check-circle',
error: 'fas fa-exclamation-circle',
info: 'fas fa-info-circle',
warning: 'fas fa-exclamation-triangle'
};
return icons[type] || icons.success;
}
// 工具函数:防抖
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// 工具函数:节流
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
// 添加键盘快捷键支持
document.addEventListener('keydown', function(e) {
// Ctrl+Enter 处理
if (e.ctrlKey && e.key === 'Enter') {
e.preventDefault();
if (!elements.processBtn.disabled) {
handleProcess();
}
}
// Escape 清空
if (e.key === 'Escape') {
handleClear();
}
});
// 页面可见性变化处理
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
// 页面隐藏时的处理
console.log('页面已隐藏');
} else {
// 页面显示时的处理
console.log('页面已显示');
}
});
// 错误处理
window.addEventListener('error', function(e) {
console.error('全局错误:', e.error);
showToast('发生未知错误,请刷新页面重试', 'error');
});
// 未处理的Promise拒绝
window.addEventListener('unhandledrejection', function(e) {
console.error('未处理的Promise拒绝:', e.reason);
showToast('网络请求失败,请检查网络连接', 'error');
});
// 导出函数供测试使用
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
handleProcess,
copyToClipboard,
showToast,
debounce,
throttle
};
}

View File

@@ -1,3 +0,0 @@
[
"https://60s.api.shumengya.top"
]

Some files were not shown because too many files have changed in this diff Show More