新增: 多布局切换+秒显示+节日倒计时+等宽数字+作者署名
This commit is contained in:
11
config.go
11
config.go
@@ -20,6 +20,13 @@ const (
|
|||||||
WPColor WallpaperType = "color"
|
WPColor WallpaperType = "color"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Layout string
|
||||||
|
|
||||||
|
const (
|
||||||
|
LayoutSingle Layout = "single"
|
||||||
|
LayoutMulti Layout = "multi"
|
||||||
|
)
|
||||||
|
|
||||||
type ThemeName string
|
type ThemeName string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -41,6 +48,7 @@ type Config struct {
|
|||||||
Color2 string `json:"color2"`
|
Color2 string `json:"color2"`
|
||||||
ColorGradient bool `json:"colorGradient"`
|
ColorGradient bool `json:"colorGradient"`
|
||||||
WallpaperText string `json:"wallpaperText"`
|
WallpaperText string `json:"wallpaperText"`
|
||||||
|
Layout Layout `json:"layout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultZodiac = "射手座"
|
const defaultZodiac = "射手座"
|
||||||
@@ -72,6 +80,9 @@ func loadConfig() *Config {
|
|||||||
if cfg.Color1 == "" {
|
if cfg.Color1 == "" {
|
||||||
cfg.Color1 = "#1a1a2e"
|
cfg.Color1 = "#1a1a2e"
|
||||||
}
|
}
|
||||||
|
if cfg.Layout == "" {
|
||||||
|
cfg.Layout = LayoutSingle
|
||||||
|
}
|
||||||
return &cfg
|
return &cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
36
systray.go
36
systray.go
@@ -40,6 +40,18 @@ func onSystrayReady() {
|
|||||||
mPause := systray.AddMenuItem("暂停", "暂停/继续")
|
mPause := systray.AddMenuItem("暂停", "暂停/继续")
|
||||||
systray.AddSeparator()
|
systray.AddSeparator()
|
||||||
|
|
||||||
|
// 布局
|
||||||
|
mLayout := systray.AddMenuItem("布局设置", "")
|
||||||
|
mLayoutSingle := mLayout.AddSubMenuItem("合并卡片", "")
|
||||||
|
mLayoutMulti := mLayout.AddSubMenuItem("独立卡片", "")
|
||||||
|
if cfg.Layout == LayoutMulti {
|
||||||
|
mLayoutMulti.Check()
|
||||||
|
} else {
|
||||||
|
mLayoutSingle.Check()
|
||||||
|
}
|
||||||
|
|
||||||
|
systray.AddSeparator()
|
||||||
|
|
||||||
// 壁纸主题
|
// 壁纸主题
|
||||||
mTheme := systray.AddMenuItem("壁纸主题", "")
|
mTheme := systray.AddMenuItem("壁纸主题", "")
|
||||||
for _, t := range themeNames {
|
for _, t := range themeNames {
|
||||||
@@ -92,6 +104,30 @@ func onSystrayReady() {
|
|||||||
mRestart := systray.AddMenuItem("重启", "重启程序")
|
mRestart := systray.AddMenuItem("重启", "重启程序")
|
||||||
mQuit := systray.AddMenuItem("退出", "退出程序")
|
mQuit := systray.AddMenuItem("退出", "退出程序")
|
||||||
|
|
||||||
|
// 布局切换
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
<-mLayoutSingle.ClickedCh
|
||||||
|
cfg := loadConfig()
|
||||||
|
cfg.Layout = LayoutSingle
|
||||||
|
saveConfig(cfg)
|
||||||
|
mLayoutSingle.Check()
|
||||||
|
mLayoutMulti.Uncheck()
|
||||||
|
reloadWallpaper()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
<-mLayoutMulti.ClickedCh
|
||||||
|
cfg := loadConfig()
|
||||||
|
cfg.Layout = LayoutMulti
|
||||||
|
saveConfig(cfg)
|
||||||
|
mLayoutSingle.Uncheck()
|
||||||
|
mLayoutMulti.Check()
|
||||||
|
reloadWallpaper()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// 主题切换监听
|
// 主题切换监听
|
||||||
for i, item := range themeItems {
|
for i, item := range themeItems {
|
||||||
go func(idx int, mi *systray.MenuItem) {
|
go func(idx int, mi *systray.MenuItem) {
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ func buildWallpaperHTML(cfg *Config) string {
|
|||||||
bg = themeAurora
|
bg = themeAurora
|
||||||
}
|
}
|
||||||
html := strings.Replace(overlayHTML, "{{BACKGROUND}}", bg, 1)
|
html := strings.Replace(overlayHTML, "{{BACKGROUND}}", bg, 1)
|
||||||
|
html = strings.Replace(html, "{{LAYOUT}}", string(cfg.Layout), 1)
|
||||||
|
|
||||||
// 注入自定义文字
|
// 注入自定义文字
|
||||||
if cfg.WallpaperType == WPTheme && cfg.Theme == ThemeText && cfg.WallpaperText != "" {
|
if cfg.WallpaperType == WPTheme && cfg.Theme == ThemeText && cfg.WallpaperText != "" {
|
||||||
|
|||||||
300
web/overlay.html
300
web/overlay.html
@@ -1,4 +1,4 @@
|
|||||||
<!-- v3 -->
|
<!-- v4 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh">
|
<html lang="zh">
|
||||||
<head>
|
<head>
|
||||||
@@ -10,49 +10,38 @@ html, body {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #000;
|
background: #000;
|
||||||
|
font-family: "Microsoft YaHei", sans-serif;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#info {
|
/* ===== 公共卡片样式 ===== */
|
||||||
position: fixed;
|
.card {
|
||||||
top: 40px;
|
|
||||||
right: 40px;
|
|
||||||
background: rgba(0, 0, 0, 0.25);
|
background: rgba(0, 0, 0, 0.25);
|
||||||
backdrop-filter: blur(24px);
|
backdrop-filter: blur(24px);
|
||||||
-webkit-backdrop-filter: blur(24px);
|
-webkit-backdrop-filter: blur(24px);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
padding: 28px 32px;
|
padding: 24px 28px;
|
||||||
color: #ffffff;
|
|
||||||
font-family: "Microsoft YaHei", sans-serif;
|
|
||||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), inset 0 0 0 1px rgba(255,255,255,0.08);
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), inset 0 0 0 1px rgba(255,255,255,0.08);
|
||||||
text-align: right;
|
|
||||||
min-width: 320px;
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.time {
|
.time {
|
||||||
font-size: 72px;
|
font-size: 72px;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
color: #fff;
|
|
||||||
text-shadow: 0 2px 20px rgba(0,0,0,0.5);
|
text-shadow: 0 2px 20px rgba(0,0,0,0.5);
|
||||||
letter-spacing: -2px;
|
letter-spacing: -2px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
font-family: "Segoe UI", "Microsoft YaHei", sans-serif;
|
||||||
}
|
}
|
||||||
.date {
|
.date {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 400;
|
|
||||||
color: rgba(255,255,255,0.7);
|
color: rgba(255,255,255,0.7);
|
||||||
margin-top: 8px;
|
margin-bottom: 6px;
|
||||||
text-shadow: 0 1px 6px rgba(0,0,0,0.5);
|
text-shadow: 0 1px 6px rgba(0,0,0,0.5);
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.divider {
|
|
||||||
height: 1px;
|
|
||||||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.15), transparent);
|
|
||||||
margin: 16px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.weather-section {}
|
|
||||||
.current-weather {
|
.current-weather {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -64,13 +53,12 @@ html, body {
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: rgba(255,255,255,0.45);
|
color: rgba(255,255,255,0.45);
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
.weather-forecast {
|
.weather-forecast {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 6px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
padding-bottom: 6px;
|
padding-bottom: 6px;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@@ -78,19 +66,19 @@ html, body {
|
|||||||
.forecast-item {
|
.forecast-item {
|
||||||
background: rgba(255,255,255,0.06);
|
background: rgba(255,255,255,0.06);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 8px 10px;
|
padding: 10px 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
min-width: 52px;
|
min-width: 58px;
|
||||||
font-size: 11px;
|
font-size: 12px;
|
||||||
color: rgba(255,255,255,0.8);
|
color: rgba(255,255,255,0.85);
|
||||||
border: 1px solid rgba(255,255,255,0.04);
|
border: 1px solid rgba(255,255,255,0.04);
|
||||||
}
|
}
|
||||||
.forecast-time { margin-bottom: 4px; opacity: 0.6; font-size: 10px; }
|
.forecast-icon { font-size: 20px; margin: 4px 0; }
|
||||||
.forecast-temp { font-weight: 500; margin-top: 2px; }
|
.forecast-time { opacity: 0.6; font-size: 10px; }
|
||||||
|
.forecast-temp { font-weight: 600; margin-top: 2px; font-size: 13px; }
|
||||||
.daily-forecast {
|
.daily-forecast {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 6px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
padding-bottom: 6px;
|
padding-bottom: 6px;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
@@ -98,24 +86,27 @@ html, body {
|
|||||||
.daily-item {
|
.daily-item {
|
||||||
background: rgba(255,255,255,0.04);
|
background: rgba(255,255,255,0.04);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 6px 8px;
|
padding: 8px 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
min-width: 48px;
|
min-width: 54px;
|
||||||
font-size: 11px;
|
font-size: 12px;
|
||||||
color: rgba(255,255,255,0.8);
|
color: rgba(255,255,255,0.85);
|
||||||
border: 1px solid rgba(255,255,255,0.03);
|
border: 1px solid rgba(255,255,255,0.03);
|
||||||
}
|
}
|
||||||
|
.daily-icon { font-size: 20px; margin: 3px 0; }
|
||||||
|
|
||||||
.zodiac {
|
.zodiac-text {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: rgba(255,255,255,0.9);
|
color: rgba(255,255,255,0.9);
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
text-shadow: 0 1px 4px rgba(0,0,0,0.5);
|
text-shadow: 0 1px 4px rgba(0,0,0,0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.weather-forecast::-webkit-scrollbar,
|
.divider {
|
||||||
.daily-forecast::-webkit-scrollbar,
|
height: 1px;
|
||||||
#info::-webkit-scrollbar { display: none; }
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.15), transparent);
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
#author {
|
#author {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -123,59 +114,98 @@ html, body {
|
|||||||
right: 30px;
|
right: 30px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: rgba(255,255,255,0.5);
|
color: rgba(255,255,255,0.5);
|
||||||
font-family: "Microsoft YaHei", sans-serif;
|
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
pointer-events: none;
|
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: 40px;
|
||||||
|
right: 40px;
|
||||||
|
text-align: left;
|
||||||
|
min-width: 320px;
|
||||||
|
}
|
||||||
|
body.layout-single #info .date {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== MULTI 布局(独立卡片) ===== */
|
||||||
|
body.layout-multi #layout-single { display: none; }
|
||||||
|
body.layout-multi #layout-multi { display: block; }
|
||||||
|
|
||||||
|
body.layout-multi #card-time {
|
||||||
|
position: fixed;
|
||||||
|
top: 40px;
|
||||||
|
right: 40px;
|
||||||
|
text-align: left;
|
||||||
|
min-width: 280px;
|
||||||
|
}
|
||||||
|
body.layout-multi #card-weather {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 80px;
|
||||||
|
right: 40px;
|
||||||
|
text-align: right;
|
||||||
|
min-width: 420px;
|
||||||
|
}
|
||||||
|
body.layout-multi #card-zodiac {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 80px;
|
||||||
|
left: 40px;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="layout-{{LAYOUT}}">
|
||||||
{{BACKGROUND}}
|
{{BACKGROUND}}
|
||||||
|
|
||||||
<div id="info">
|
<!-- ===== SINGLE 布局 ===== -->
|
||||||
<div class="time" id="time">00:00</div>
|
<div id="layout-single">
|
||||||
<div class="date" id="date">1月1日 周一</div>
|
<div id="info" class="card">
|
||||||
<div class="divider"></div>
|
<div class="date" id="date">1月1日 周一</div>
|
||||||
<div class="weather-section">
|
<div class="time" id="time">00:00</div>
|
||||||
<div class="current-weather" id="currentWeather">加载中...</div>
|
<div class="divider"></div>
|
||||||
<div class="forecast-title">24小时预报</div>
|
<div>
|
||||||
<div class="weather-forecast" id="hourlyForecast"></div>
|
<div class="current-weather" id="currentWeather">加载中...</div>
|
||||||
<div class="forecast-title" style="margin-top: 12px;">7日预报</div>
|
<div class="forecast-title">24小时预报</div>
|
||||||
<div class="daily-forecast" id="dailyForecast"></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-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-zodiac" class="card">
|
||||||
|
<div class="zodiac-text" id="zodiac2">加载中...</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="divider"></div>
|
|
||||||
<div class="zodiac" id="zodiac">加载中...</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="author">绝尘</div>
|
<div id="author">绝尘</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let lastTimeStr = '';
|
var lastTimeStr='', lastDateStr='', lastZodiac='';
|
||||||
let lastDateStr = '';
|
|
||||||
let lastZodiac = '';
|
|
||||||
|
|
||||||
window.updateWeatherFromGo = function(data) {
|
|
||||||
if (typeof data === 'string') data = JSON.parse(data);
|
|
||||||
var el = document.getElementById('currentWeather');
|
|
||||||
if (el && data.current) el.textContent = data.current;
|
|
||||||
var fel = document.getElementById('hourlyForecast');
|
|
||||||
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">' + item.time + '</div><div>' + item.icon + '</div><div class="forecast-temp">' + item.temp + '</div></div>';
|
|
||||||
}).join('');
|
|
||||||
} else { fel.innerHTML = '<div style="font-size:11px;opacity:0.4">暂无数据</div>'; }
|
|
||||||
}
|
|
||||||
var del = document.getElementById('dailyForecast');
|
|
||||||
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;margin-bottom:3px;font-size:10px">' + item.date + '</div><div>' + item.icon + '</div><div class="forecast-temp">' + item.tempMin + '°~' + item.tempMax + '°</div></div>';
|
|
||||||
}).join('');
|
|
||||||
} else { del.innerHTML = '<div style="font-size:11px;opacity:0.4">暂无数据</div>'; }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var zodiacData = {
|
var zodiacData = {
|
||||||
'白羊座':{icon:'♈',date:'3.21-4.19',fortune:'今日运势旺盛,适合开展新计划。'},
|
'白羊座':{icon:'♈',date:'3.21-4.19',fortune:'今日运势旺盛,适合开展新计划。'},
|
||||||
@@ -192,36 +222,106 @@ var zodiacData = {
|
|||||||
'双鱼座':{icon:'♓',date:'2.19-3.20',fortune:'艺术灵感丰富,适合创作。'}
|
'双鱼座':{icon:'♓',date:'2.19-3.20',fortune:'艺术灵感丰富,适合创作。'}
|
||||||
};
|
};
|
||||||
|
|
||||||
function getUserZodiac() { return window.userZodiac || '射手座'; }
|
function getUserZodiac(){ return window.userZodiac||'射手座'; }
|
||||||
|
|
||||||
function updateZodiacDisplay() {
|
function setEl(id,html){
|
||||||
var name = getUserZodiac();
|
var e=document.getElementById(id);
|
||||||
if (name === lastZodiac) return;
|
if(e) e.innerHTML=html;
|
||||||
lastZodiac = name;
|
}
|
||||||
var el = document.getElementById('zodiac');
|
function setText(id,txt){
|
||||||
if (!el) return;
|
var e=document.getElementById(id);
|
||||||
var z = zodiacData[name] || {icon:'✨',date:'',fortune:'运势平稳,保持平常心。'};
|
if(e) e.textContent=txt;
|
||||||
el.innerHTML = z.icon + ' ' + name + '运势 <span style="opacity:0.4;font-size:12px">' + z.date + '</span><br><span style="opacity:0.6;font-size:12px">' + z.fortune + '</span>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTime() {
|
function updateZodiacDisplay(){
|
||||||
var now = new Date();
|
var name=getUserZodiac();
|
||||||
var hh = String(now.getHours()).padStart(2, '0');
|
if(name===lastZodiac) return;
|
||||||
var mm = String(now.getMinutes()).padStart(2, '0');
|
lastZodiac=name;
|
||||||
var month = now.getMonth() + 1;
|
var z=zodiacData[name]||{icon:'✨',date:'',fortune:'运势平稳,保持平常心。'};
|
||||||
var day = now.getDate();
|
var html=z.icon+' '+name+'运势 <span style="opacity:0.4;font-size:12px">'+z.date+'</span><br><span style="opacity:0.6;font-size:12px">'+z.fortune+'</span>';
|
||||||
var week = ['周日','周一','周二','周三','周四','周五','周六'][now.getDay()];
|
setEl('zodiac',html);
|
||||||
var timeStr = hh + ':' + mm;
|
setEl('zodiac2',html);
|
||||||
var dateStr = month + '月' + day + '日 ' + week;
|
}
|
||||||
var timeEl = document.getElementById('time');
|
|
||||||
var dateEl = document.getElementById('date');
|
var holidays=[
|
||||||
if (timeEl && timeStr !== lastTimeStr) { timeEl.textContent = timeStr; lastTimeStr = timeStr; }
|
{m:1,d:1,name:'元旦'},
|
||||||
if (dateEl && dateStr !== lastDateStr) { dateEl.textContent = dateStr; lastDateStr = dateStr; }
|
{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+'天':'';
|
||||||
|
}
|
||||||
|
|
||||||
|
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=hh+':'+mm+':'+ss;
|
||||||
|
var dateStr=month+'月'+day+'日 '+week;
|
||||||
|
if(timeStr!==lastTimeStr){
|
||||||
|
setText('time',timeStr); setText('time2',timeStr); lastTimeStr=timeStr;
|
||||||
|
}
|
||||||
|
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();
|
updateZodiacDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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">'+item.time+'</div><div class="forecast-icon">'+item.icon+'</div><div class="forecast-temp">'+item.temp+'</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">'+item.date+'</div><div class="daily-icon">'+item.icon+'</div><div class="forecast-temp">'+item.tempMin+'°~'+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();
|
updateTime();
|
||||||
setInterval(updateTime, 1000);
|
setInterval(updateTime,1000);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user