Files
u-desktop/web/overlay.html

935 lines
27 KiB
HTML

<!-- v4 -->
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<style>
* { margin: 0; padding: 0; }
html, body {
width: 100%;
height: 100%;
overflow: hidden;
background: #000;
font-family: "Segoe UI", "Microsoft YaHei", sans-serif;
color: #fff;
font-variant-numeric: tabular-nums;
}
:root {
--card-bg: rgba(22, 19, 28, 0.56);
--card-bg-strong: rgba(24, 20, 30, 0.68);
--card-line: rgba(255,255,255,0.10);
--card-line-soft: rgba(255,255,255,0.06);
--text-main: rgba(255,255,255,0.92);
--text-soft: rgba(255,255,255,0.66);
--text-faint: rgba(255,255,255,0.42);
--accent-warm: #ffd86b;
--accent-cool: #6bdcff;
--shadow-card: 0 18px 60px rgba(0,0,0,0.32), inset 0 1px 0 rgba(255,255,255,0.10);
--layout-x: 48px;
--layout-top: 38px;
--layout-bottom: 72px;
--layout-gap: 18px;
--layout-col-gap: 24px;
--right-panel: 400px;
--knowledge-panel: 460px;
--time-panel-h: 154px;
--zodiac-panel-h: 326px;
--photo-panel-h: 360px;
}
/* ===== 公共卡片样式 ===== */
.card {
position: relative;
box-sizing: border-box;
overflow: hidden;
background: linear-gradient(145deg, rgba(255,255,255,0.075), rgba(255,255,255,0.025)), var(--card-bg);
backdrop-filter: blur(28px) saturate(1.2);
-webkit-backdrop-filter: blur(28px) saturate(1.2);
border: 1px solid var(--card-line);
border-radius: 8px;
padding: 22px 24px;
box-shadow: var(--shadow-card);
}
.card::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
border-radius: inherit;
background:
linear-gradient(90deg, rgba(255,255,255,0.13), transparent 34%),
radial-gradient(circle at 12% 0%, rgba(255,216,107,0.13), transparent 38%);
opacity: 0.55;
}
.card > * {
position: relative;
}
.time {
font-size: 66px;
font-weight: 200;
text-shadow: 0 3px 28px rgba(0,0,0,0.42);
letter-spacing: 0;
line-height: 1;
font-variant-numeric: tabular-nums;
color: rgba(255,255,255,0.96);
}
@keyframes hourlyGlow {
0% { text-shadow: 0 0 30px rgba(255,255,255,1), 0 0 80px rgba(180,200,255,0.8), 0 0 120px rgba(100,150,255,0.5); color: #fff; }
8% { text-shadow: 0 0 50px rgba(255,255,255,1), 0 0 100px rgba(180,200,255,1), 0 0 160px rgba(100,150,255,0.6); }
18% { text-shadow: 0 0 20px rgba(255,255,255,0.6), 0 0 40px rgba(180,200,255,0.3); }
28% { text-shadow: 0 0 35px rgba(255,255,255,0.85), 0 0 70px rgba(180,200,255,0.6), 0 0 100px rgba(100,150,255,0.35); }
38% { text-shadow: 0 0 15px rgba(255,255,255,0.4), 0 0 30px rgba(180,200,255,0.2); }
48% { text-shadow: 0 0 25px rgba(255,255,255,0.6), 0 0 50px rgba(180,200,255,0.4); }
60% { text-shadow: 0 0 10px rgba(255,255,255,0.25), 0 0 20px rgba(180,200,255,0.12); }
75% { text-shadow: 0 0 15px rgba(255,255,255,0.35), 0 0 30px rgba(180,200,255,0.2); }
100% { text-shadow: 0 2px 20px rgba(0,0,0,0.5); color: #fff; }
}
.time.hourly-glow {
animation: hourlyGlow 6s ease-out forwards;
}
.date {
font-size: 13px;
color: var(--text-soft);
margin-bottom: 8px;
text-shadow: 0 1px 6px rgba(0,0,0,0.5);
letter-spacing: 0;
}
.current-weather {
font-size: 17px;
font-weight: 600;
color: var(--text-main);
text-shadow: 0 1px 4px rgba(0,0,0,0.5);
margin-bottom: 16px;
text-align: right;
}
.forecast-title {
font-size: 11px;
font-weight: 600;
color: var(--text-faint);
letter-spacing: 0;
margin-bottom: 9px;
text-align: right;
}
.weather-forecast {
display: grid;
grid-template-columns: repeat(8, minmax(60px, 1fr));
gap: 7px;
overflow: hidden;
padding-bottom: 0;
}
.forecast-item {
background: rgba(255,255,255,0.055);
border-radius: 8px;
padding: 9px 8px;
text-align: center;
min-width: 0;
font-size: 12px;
color: var(--text-main);
border: 1px solid var(--card-line-soft);
}
.forecast-icon { font-size: 22px; margin: 5px 0; }
.forecast-time { color: var(--text-faint); font-size: 10px; }
.forecast-temp { font-weight: 700; margin-top: 2px; font-size: 14px; }
.forecast-pop { font-size: 10px; color: var(--text-faint); margin-top: 2px; }
.daily-forecast {
display: grid;
grid-template-columns: repeat(7, minmax(64px, 1fr));
gap: 7px;
overflow: hidden;
padding-bottom: 0;
}
.daily-item {
background: rgba(255,255,255,0.04);
border-radius: 8px;
padding: 9px 8px;
text-align: center;
min-width: 0;
font-size: 12px;
color: var(--text-main);
border: 1px solid var(--card-line-soft);
}
.daily-icon { font-size: 22px; margin: 5px 0; }
.zodiac-text {
font-size: 14px;
color: var(--text-main);
line-height: 1.6;
text-shadow: 0 1px 4px rgba(0,0,0,0.5);
}
.zodiac-title {
font-size: 16px;
font-weight: 650;
margin-bottom: 3px;
}
.zodiac-date {
font-size: 11px;
color: var(--text-faint);
margin-bottom: 12px;
}
.zodiac-bar {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 7px;
font-size: 12px;
}
.zodiac-bar-label {
width: 28px;
color: var(--text-soft);
flex-shrink: 0;
}
.zodiac-bar-track {
flex: 1;
height: 5px;
background: rgba(255,255,255,0.10);
border-radius: 999px;
overflow: hidden;
}
.zodiac-bar-fill {
height: 100%;
border-radius: 999px;
transition: width 0.6s ease;
}
.zodiac-bar-val {
width: 30px;
text-align: right;
font-size: 11px;
color: var(--text-soft);
flex-shrink: 0;
}
.zodiac-tags {
display: flex;
gap: 7px;
flex-wrap: wrap;
margin: 10px 0 9px;
}
.zodiac-tag {
font-size: 10px;
background: rgba(255,255,255,0.08);
padding: 4px 8px;
border-radius: 6px;
color: var(--text-soft);
border: 1px solid rgba(255,255,255,0.05);
}
.zodiac-summary {
font-size: 12px;
color: var(--text-soft);
line-height: 1.65;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* ===== AI 资讯 ===== */
.ainews-header {
font-size: 11px;
font-weight: 700;
color: var(--text-faint);
letter-spacing: 0;
margin-bottom: 14px;
}
.ainews-item {
display: flex;
gap: 14px;
margin-bottom: 12px;
padding-bottom: 12px;
border-bottom: 1px solid var(--card-line-soft);
min-height: 58px;
}
.ainews-item:last-child {
margin-bottom: 0;
padding-bottom: 0;
border-bottom: none;
}
.ainews-img {
width: 92px;
height: 58px;
border-radius: 6px;
object-fit: cover;
flex-shrink: 0;
opacity: 0.92;
box-shadow: 0 8px 22px rgba(0,0,0,0.22);
}
.ainews-body {
flex: 1;
min-width: 0;
}
.ainews-title-row {
display: flex;
align-items: baseline;
gap: 10px;
}
.ainews-title {
font-size: 14px;
font-weight: 650;
color: var(--text-main);
line-height: 1.4;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
min-width: 0;
}
.ainews-source {
font-size: 10px;
color: var(--text-faint);
flex-shrink: 0;
}
.ainews-desc {
font-size: 12px;
color: var(--text-soft);
line-height: 1.5;
margin-top: 5px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
@media (max-width: 1500px) {
:root {
--layout-x: 32px;
--layout-col-gap: 18px;
--right-panel: 360px;
--knowledge-panel: 380px;
--time-panel-h: 144px;
--zodiac-panel-h: 312px;
--photo-panel-h: 320px;
}
.time {
font-size: 64px;
}
.weather-forecast {
grid-template-columns: repeat(4, 1fr);
}
.daily-forecast {
grid-template-columns: repeat(4, 1fr);
}
}
/* ===== 知识卡片 ===== */
.knowledge-header {
font-size: 11px;
color: var(--text-faint);
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 6px;
letter-spacing: 0;
font-weight: 700;
}
.knowledge-keyword-tag {
background: rgba(255,255,255,0.09);
padding: 3px 8px;
border-radius: 6px;
font-size: 10px;
color: var(--text-soft);
}
.knowledge-content {
font-size: 16px;
color: var(--text-main);
line-height: 1.55;
text-shadow: 0 1px 4px rgba(0,0,0,0.5);
}
.divider {
height: 1px;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.14), transparent);
margin: 18px 0;
}
#author {
position: fixed;
bottom: 60px;
right: 30px;
font-size: 16px;
color: rgba(255,255,255,0.42);
letter-spacing: 0;
z-index: 10;
pointer-events: none;
}
.weather-forecast::-webkit-scrollbar,
.daily-forecast::-webkit-scrollbar { display: none; }
/* ===== SINGLE 布局(现有) ===== */
body.layout-single #layout-single { display: block; }
body.layout-single #layout-multi { display: none; }
body.layout-single #info {
position: fixed;
top: 42px;
right: 42px;
text-align: left;
width: min(760px, calc(50vw - 52px));
max-height: calc(100vh - 84px);
z-index: 10;
}
body.layout-single #info .date {
text-align: left;
}
/* ===== MULTI 布局(独立卡片) ===== */
body.layout-multi #layout-single { display: none; }
body.layout-multi #layout-multi {
position: fixed;
inset: var(--layout-top) var(--layout-x) var(--layout-bottom);
z-index: 10;
display: grid;
grid-template-columns: minmax(420px, 1fr) minmax(360px, var(--knowledge-panel)) var(--right-panel);
grid-template-rows: var(--time-panel-h) var(--layout-gap) var(--zodiac-panel-h) minmax(32px, 1fr) auto;
grid-template-areas:
"photo knowledge time"
"photo knowledge ."
"photo knowledge zodiac"
". . ."
"news weather weather";
column-gap: var(--layout-col-gap);
row-gap: 0;
pointer-events: none;
}
body.layout-multi #layout-multi > .card {
pointer-events: none;
}
body.layout-multi #card-time {
grid-area: time;
text-align: left;
width: 100%;
height: 100%;
padding: 22px 30px;
}
body.layout-multi #card-zodiac {
grid-area: zodiac;
width: 100%;
height: 100%;
padding: 22px 28px;
}
body.layout-multi #card-knowledge {
grid-area: knowledge;
align-self: stretch;
width: 100%;
min-height: 0;
padding: 22px 26px;
}
body.layout-multi #card-knowledge .knowledge-content {
display: -webkit-box;
-webkit-line-clamp: 8;
-webkit-box-orient: vertical;
overflow: hidden;
}
body.layout-multi #card-ainews {
grid-area: news;
align-self: end;
width: 100%;
max-height: 390px;
}
body.layout-multi #card-weather {
grid-area: weather;
align-self: end;
width: 100%;
min-width: 0;
text-align: right;
padding: 22px 28px 24px;
}
body.layout-multi #card-photo {
grid-area: photo;
position: relative;
top: auto;
left: auto;
align-self: start;
width: 100%;
max-height: var(--photo-panel-h);
padding: 16px;
}
body.layout-multi #card-photo img {
max-height: calc(var(--photo-panel-h) - 32px);
}
/* ===== 卡片隐藏 ===== */
body.hide-time #card-time,
body.hide-time #info .time,
body.hide-time #info .date { display: none !important; }
body.hide-weather #card-weather,
body.hide-weather #info .weather-section,
body.hide-weather #info .current-weather,
body.hide-weather #info .forecast-title,
body.hide-weather #info .weather-forecast,
body.hide-weather #info .daily-forecast { display: none !important; }
body.hide-zodiac #card-zodiac,
body.hide-zodiac #info .zodiac-text { display: none !important; }
body.hide-ainews #card-ainews,
body.hide-ainews #info .ainews-section { display: none !important; }
body.hide-knowledge #card-knowledge,
body.hide-knowledge #info .knowledge-section { display: none !important; }
body.hide-photo #card-photo { display: none !important; }
/* ===== 相册 ===== */
#card-photo {
position: fixed;
top: 44px;
left: 48px;
width: min(860px, calc(50vw - 72px));
box-sizing: border-box;
z-index: 10;
padding: 16px;
}
.photo-wrap {
position: relative;
border-radius: 8px;
overflow: hidden;
}
#card-photo img {
width: 100%;
max-height: 450px;
object-fit: cover;
display: block;
border-radius: 8px;
transition: opacity 0.5s ease;
}
.photo-info {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 20px 14px 10px;
background: linear-gradient(transparent, rgba(0,0,0,0.5));
}
.photo-counter {
font-size: 11px;
opacity: 0.7;
display: block;
margin-bottom: 6px;
}
.photo-progress {
height: 3px;
background: rgba(255,255,255,0.15);
border-radius: 2px;
overflow: hidden;
}
.photo-progress-bar {
height: 100%;
width: 0%;
background: rgba(255,255,255,0.6);
border-radius: 2px;
}
/* ===== 电子相册模式 ===== */
body.photo-frame-mode #bg-layer { display: none !important; }
body.photo-frame-mode #card-photo { display: none !important; }
body.photo-frame-mode #layout-multi { display: none !important; }
body.photo-frame-mode #layout-single { display: none !important; }
body.photo-frame-mode #author { display: none !important; }
#photo-frame-bg {
display: none;
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
z-index: 4;
object-fit: cover;
filter: blur(30px) brightness(0.5);
transform: scale(1.1);
transition: opacity 0.8s ease;
}
#photo-frame-img {
display: none;
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
z-index: 5;
object-fit: contain;
transition: opacity 0.8s ease;
}
body.photo-frame-mode #photo-frame-bg { display: block; }
body.photo-frame-mode #photo-frame-img { display: block; }
/* 相册时钟叠加层 */
.photo-frame-clock {
position: fixed; top: 28px; right: 36px; z-index: 10;
font-family: -apple-system, "SF Pro Display", "Segoe UI", sans-serif;
font-size: 52px; font-weight: 200; letter-spacing: 2px;
color: #fff;
text-shadow: 0 0 20px rgba(0,0,0,0.8), 0 0 40px rgba(0,0,0,0.5), 0 2px 4px rgba(0,0,0,0.9);
pointer-events: none;
opacity: 0;
transition: opacity 0.5s ease;
}
body.photo-frame-mode .photo-frame-clock { opacity: 1; }
.photo-frame-date {
position: fixed; top: 86px; right: 38px; z-index: 10;
font-family: -apple-system, "SF Pro Display", "Segoe UI", sans-serif;
font-size: 15px; font-weight: 400;
color: rgba(255,255,255,0.8);
text-shadow: 0 0 12px rgba(0,0,0,0.7), 0 1px 3px rgba(0,0,0,0.8);
pointer-events: none;
opacity: 0;
transition: opacity 0.5s ease;
}
body.photo-frame-mode .photo-frame-date { opacity: 1; }
</style>
</head>
<body class="layout-{{LAYOUT}} {{BODY_CLASSES}}">
{{BACKGROUND}}
<!-- ===== SINGLE 布局 ===== -->
<div id="layout-single">
<div id="info" class="card">
<div class="date" id="date">1月1日 周一</div>
<div class="time" id="time">00:00</div>
<div class="divider"></div>
<div class="ainews-section">
<div class="ainews-header">🤖 AI 资讯</div>
<div id="ainews">加载中...</div>
</div>
<div class="divider"></div>
<div class="knowledge-section">
<div class="knowledge-header">💡 知识卡片 <span class="knowledge-keyword-tag" id="knowledgeTag"></span></div>
<div class="knowledge-content" id="knowledge">请设置知识关键字</div>
</div>
<div class="divider"></div>
<div>
<div class="current-weather" id="currentWeather">加载中...</div>
<div class="forecast-title">24小时预报</div>
<div class="weather-forecast" id="hourlyForecast"></div>
<div class="forecast-title" style="margin-top:12px">7日预报</div>
<div class="daily-forecast" id="dailyForecast"></div>
</div>
<div class="divider"></div>
<div class="zodiac-text" id="zodiac">加载中...</div>
</div>
</div>
<!-- ===== MULTI 布局 ===== -->
<div id="layout-multi">
<div id="card-time" class="card">
<div class="date" id="date2">1月1日 周一</div>
<div class="time" id="time2">00:00</div>
</div>
<div id="card-zodiac" class="card">
<div class="zodiac-text" id="zodiac2">加载中...</div>
</div>
<div id="card-knowledge" class="card">
<div class="knowledge-header">💡 知识卡片 <span class="knowledge-keyword-tag" id="knowledgeTag2"></span></div>
<div class="knowledge-content" id="knowledge2">请设置知识关键字</div>
</div>
<div id="card-ainews" class="card">
<div class="ainews-header">🤖 AI 资讯</div>
<div id="ainews2">加载中...</div>
</div>
<div id="card-weather" class="card">
<div class="current-weather" id="currentWeather2">加载中...</div>
<div class="forecast-title">24小时预报</div>
<div class="weather-forecast" id="hourlyForecast2"></div>
<div class="forecast-title" style="margin-top:12px">7日预报</div>
<div class="daily-forecast" id="dailyForecast2"></div>
</div>
<div id="card-photo" class="card" style="display:none">
<div class="photo-wrap">
<img id="photoImg" src="" alt="">
<div class="photo-info">
<span class="photo-counter" id="photoCounter"></span>
<div class="photo-progress"><div class="photo-progress-bar" id="photoProgress"></div></div>
</div>
</div>
</div>
</div>
<div id="author">绝尘</div>
<!-- 相册模式全屏图片 -->
<img id="photo-frame-bg" src="" alt="">
<img id="photo-frame-img" src="" alt="">
<!-- 相册模式时钟 -->
<div class="photo-frame-clock" id="photoFrameClock"></div>
<div class="photo-frame-date" id="photoFrameDate"></div>
<script>
var lastTimeStr='', lastDateStr='', lastZodiac='';
var horoscopeInfo=null;
var zodiacData = {
'白羊座':{icon:'♈',date:'3.21-4.19'},
'金牛座':{icon:'♉',date:'4.20-5.20'},
'双子座':{icon:'♊',date:'5.21-6.21'},
'巨蟹座':{icon:'♋',date:'6.22-7.22'},
'狮子座':{icon:'♌',date:'7.23-8.22'},
'处女座':{icon:'♍',date:'8.23-9.22'},
'天秤座':{icon:'♎',date:'9.23-10.23'},
'天蝎座':{icon:'♏',date:'10.24-11.22'},
'射手座':{icon:'♐',date:'11.23-12.21'},
'摩羯座':{icon:'♑',date:'12.22-1.19'},
'水瓶座':{icon:'♒',date:'1.20-2.18'},
'双鱼座':{icon:'♓',date:'2.19-3.20'}
};
var barColors={all:'#e0e0e0',love:'#ff6b9d',work:'#4fc3f7',money:'#ffd54f',health:'#81c784'};
function getUserZodiac(){ return window.userZodiac||'射手座'; }
function setEl(id,html){
var e=document.getElementById(id);
if(e) e.innerHTML=html;
}
function setText(id,txt){
var e=document.getElementById(id);
if(e) e.textContent=txt;
}
function escapeHTML(value){
return String(value == null ? '' : value)
.replace(/&/g,'&amp;')
.replace(/</g,'&lt;')
.replace(/>/g,'&gt;')
.replace(/"/g,'&quot;')
.replace(/'/g,'&#39;');
}
function safeImageURL(value){
var url=String(value || '').trim();
return /^(https?:|data:image\/)/i.test(url) ? url : '';
}
function buildBar(label,val,color){
var v=parseInt(val)||0;
return '<div class="zodiac-bar">'+
'<span class="zodiac-bar-label">'+label+'</span>'+
'<div class="zodiac-bar-track"><div class="zodiac-bar-fill" style="width:'+v+'%;background:'+color+'"></div></div>'+
'<span class="zodiac-bar-val">'+val+'%</span></div>';
}
function buildZodiacHTML(name){
var z=zodiacData[name]||{icon:'✨',date:''};
var html='<div class="zodiac-title">'+z.icon+' '+name+'运势</div>';
html+='<div class="zodiac-date">'+z.date+'</div>';
if(horoscopeInfo&&horoscopeInfo.zodiac===name){
html+=buildBar('综合',horoscopeInfo.all,barColors.all);
html+=buildBar('爱情',horoscopeInfo.love,barColors.love);
html+=buildBar('工作',horoscopeInfo.work,barColors.work);
html+=buildBar('财运',horoscopeInfo.money,barColors.money);
html+=buildBar('健康',horoscopeInfo.health,barColors.health);
html+='<div class="zodiac-tags">';
if(horoscopeInfo.luckyColor) html+='<span class="zodiac-tag">🎨 '+escapeHTML(horoscopeInfo.luckyColor)+'</span>';
if(horoscopeInfo.luckyNum) html+='<span class="zodiac-tag">🔢 '+escapeHTML(horoscopeInfo.luckyNum)+'</span>';
if(horoscopeInfo.noble) html+='<span class="zodiac-tag">⭐ '+escapeHTML(horoscopeInfo.noble)+'</span>';
html+='</div>';
if(horoscopeInfo.summary) html+='<div class="zodiac-summary">'+escapeHTML(horoscopeInfo.summary)+'</div>';
} else {
html+='<div style="opacity:0.4;font-size:12px;margin-top:8px">运势加载中...</div>';
}
return html;
}
function updateZodiacDisplay(){
var name=getUserZodiac();
if(name===lastZodiac) return;
lastZodiac=name;
var html=buildZodiacHTML(name);
setEl('zodiac',html);
setEl('zodiac2',html);
}
var holidays=[
{m:1,d:1,name:'元旦'},
{m:2,d:14,name:'情人节'},
{m:3,d:8,name:'妇女节'},
{m:4,d:5,name:'清明节'},
{m:5,d:1,name:'劳动节'},
{m:5,d:4,name:'青年节'},
{m:6,d:1,name:'儿童节'},
{m:7,d:1,name:'建党节'},
{m:8,d:1,name:'建军节'},
{m:9,d:10,name:'教师节'},
{m:10,d:1,name:'国庆节'},
{m:10,d:31,name:'万圣节'},
{m:12,d:25,name:'圣诞节'}
];
function getNextHoliday(now){
var y=now.getFullYear(), results=[];
for(var i=0;i<holidays.length;i++){
var h=holidays[i];
var target=new Date(y,h.m-1,h.d);
var diff=Math.ceil((target-now)/(1000*60*60*24));
if(diff>0&&diff<=60) results.push({diff:diff,name:h.name});
if(diff<0){
target=new Date(y+1,h.m-1,h.d);
diff=Math.ceil((target-now)/(1000*60*60*24));
if(diff>0&&diff<=60) results.push({diff:diff,name:h.name});
}
}
results.sort(function(a,b){return a.diff-b.diff;});
return results.length>0?'距'+results[0].name+'还有'+results[0].diff+'天':'';
}
window.setCardVisible=function(card,visible){
if(visible){document.body.classList.remove('hide-'+card);}
else{document.body.classList.add('hide-'+card);}
};
window.setWallpaperVisible=function(visible){
var bg=document.getElementById('bg-layer');
if(bg){bg.style.display=visible?'':'none';}
};
window.setPhotoFrameMode=function(enabled){
if(enabled){
document.body.classList.add('photo-frame-mode');
} else {
document.body.classList.remove('photo-frame-mode');
}
};
window._showSeconds={{SHOW_SECONDS}};
window.setShowSeconds=function(v){window._showSeconds=v; updateTime();};
function updateTime(){
var now=new Date();
var hh=String(now.getHours()).padStart(2,'0');
var mm=String(now.getMinutes()).padStart(2,'0');
var ss=String(now.getSeconds()).padStart(2,'0');
var month=now.getMonth()+1;
var day=now.getDate();
var week=['周日','周一','周二','周三','周四','周五','周六'][now.getDay()];
var timeStr=window._showSeconds?(hh+':'+mm+':'+ss):(hh+':'+mm);
var dateStr=month+'月'+day+'日 '+week;
if(timeStr!==lastTimeStr){
setText('time',timeStr); setText('time2',timeStr); lastTimeStr=timeStr;
if(mm==='00'&&ss==='00'){
['time','time2'].forEach(function(id){
var el=document.getElementById(id);
if(el){
el.classList.remove('hourly-glow');
void el.offsetWidth;
el.classList.add('hourly-glow');
el.addEventListener('animationend',function(){ el.classList.remove('hourly-glow'); },{once:true});
}
});
}
}
if(dateStr!==lastDateStr){
var holiday=getNextHoliday(now);
var displayStr=holiday?dateStr+' <span style="opacity:0.5;font-size:12px">「'+holiday+'」</span>':dateStr;
setEl('date',displayStr); setEl('date2',displayStr); lastDateStr=dateStr;
}
updateZodiacDisplay();
// 相册模式时钟
var fc=document.getElementById('photoFrameClock');
var fd=document.getElementById('photoFrameDate');
if(fc) fc.textContent=timeStr;
if(fd) fd.textContent=dateStr;
}
window.updateHoroscopeFromGo=function(data){
console.log('[horoscope] received:', typeof data, JSON.stringify(data).substring(0,100));
if(typeof data==='string') data=JSON.parse(data);
horoscopeInfo=data;
lastZodiac='';
window.userZodiac=data.zodiac;
updateZodiacDisplay();
};
window.updateAINewsFromGo=function(items){
if(typeof items==='string') items=JSON.parse(items);
if(!items||!items.length) return;
var html='';
var count=Math.min(items.length,5);
for(var i=0;i<count;i++){
var n=items[i];
var time=n.ctime||'';
if(time.length>10) time=time.substring(5,10);
html+='<div class="ainews-item">';
var picUrl=safeImageURL(n.picUrl);
if(picUrl){
html+='<img class="ainews-img" src="'+escapeHTML(picUrl)+'" loading="lazy" onerror="this.style.display=\'none\'">';
}
html+='<div class="ainews-body">';
html+='<div class="ainews-title-row"><span class="ainews-title">'+escapeHTML(n.title)+'</span><span class="ainews-source">'+escapeHTML(n.source)+' · '+escapeHTML(time)+'</span></div>';
if(n.description) html+='<div class="ainews-desc">'+escapeHTML(n.description)+'</div>';
html+='</div></div>';
}
setEl('ainews',html);
setEl('ainews2',html);
};
window.updateKnowledgeFromGo=function(data){
if(typeof data==='string') data=JSON.parse(data);
var ids=['knowledge','knowledge2'];
var tagIds=['knowledgeTag','knowledgeTag2'];
ids.forEach(function(id,i){
var el=document.getElementById(id);
if(el) el.textContent=data.content||'';
var tag=document.getElementById(tagIds[i]);
if(tag) tag.textContent=data.keyword?'#'+data.keyword:'';
});
};
window.updateWeatherFromGo=function(data){
if(typeof data==='string') data=JSON.parse(data);
function renderWeather(curId,hourlyId,dailyId){
if(data.current) setText(curId,data.current);
var fel=document.getElementById(hourlyId);
if(fel){
if(data.hourly&&data.hourly.length>0){
fel.innerHTML=data.hourly.map(function(item){
return '<div class="forecast-item"><div class="forecast-time">'+escapeHTML(item.time)+'</div><div class="forecast-icon">'+escapeHTML(item.icon)+'</div><div class="forecast-temp">'+escapeHTML(item.temp)+'</div>'+(item.pop&&item.pop!=='0'?'<div class="forecast-pop">'+escapeHTML(item.pop)+'%</div>':'')+'</div>';
}).join('');
} else { fel.innerHTML='<div style="font-size:11px;opacity:0.4">暂无数据</div>'; }
}
var del=document.getElementById(dailyId);
if(del){
if(data.daily&&data.daily.length>0){
del.innerHTML=data.daily.map(function(item){
return '<div class="daily-item"><div style="opacity:0.6;font-size:10px">'+escapeHTML(item.date)+'</div><div class="daily-icon">'+escapeHTML(item.icon)+'</div><div class="forecast-temp">'+escapeHTML(item.tempMin)+'°~'+escapeHTML(item.tempMax)+'°</div></div>';
}).join('');
} else { del.innerHTML='<div style="font-size:11px;opacity:0.4">暂无数据</div>'; }
}
}
renderWeather('currentWeather','hourlyForecast','dailyForecast');
renderWeather('currentWeather2','hourlyForecast2','dailyForecast2');
};
updateTime();
setInterval(updateTime,1000);
window.updatePhotoFromGo=function(data){
if(typeof data==='string') data=JSON.parse(data);
var pfImg=document.getElementById('photo-frame-img');
var pfBg=document.getElementById('photo-frame-bg');
if(document.body.classList.contains('photo-frame-mode')&&pfImg){
if(!data||!data.src) return;
pfImg.style.opacity='0';
pfBg.style.opacity='0';
setTimeout(function(){
pfBg.src=data.src;
pfImg.src=data.src;
pfImg.onload=function(){pfImg.style.opacity='1';pfBg.style.opacity='1';};
},400);
return;
}
var card=document.getElementById('card-photo');
if(!card) return;
if(!data||!data.src){card.style.display='none';return;}
card.style.display='';
var img=document.getElementById('photoImg');
var counter=document.getElementById('photoCounter');
var bar=document.getElementById('photoProgress');
img.style.opacity='0';
setTimeout(function(){
img.src=data.src;
img.onload=function(){img.style.opacity='1';};
},300);
if(data.counter) counter.textContent=data.counter;
bar.style.transition='none';
bar.style.width='0%';
requestAnimationFrame(function(){
requestAnimationFrame(function(){
bar.style.transition='width '+(data.interval||15)+'s linear';
bar.style.width='100%';
});
});
};
</script>
</body>
</html>