492 lines
16 KiB
JavaScript
492 lines
16 KiB
JavaScript
class OverviewPage extends HTMLElement {
|
||
constructor() {
|
||
super();
|
||
this.attachShadow({ mode: 'open' });
|
||
this.versions = [];
|
||
}
|
||
|
||
connectedCallback() {
|
||
this.loadVersions().then(() => {
|
||
this.render();
|
||
this.startClock();
|
||
this.setupEventListeners();
|
||
}).catch(error => {
|
||
console.error('加载版本信息失败:', error);
|
||
this.render();
|
||
this.startClock();
|
||
this.setupEventListeners();
|
||
});
|
||
}
|
||
|
||
disconnectedCallback() {
|
||
if (this.clockInterval) {
|
||
clearInterval(this.clockInterval);
|
||
}
|
||
}
|
||
|
||
async loadVersions() {
|
||
try {
|
||
const response = await fetch('/api/versions');
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP error! status: ${response.status}`);
|
||
}
|
||
this.versions = await response.json();
|
||
} catch (error) {
|
||
console.error('加载版本信息失败:', error);
|
||
this.versions = [];
|
||
}
|
||
}
|
||
|
||
formatVersionRecord(version) {
|
||
const date = version.date;
|
||
const time = version.time;
|
||
const verNum = version.verNum;
|
||
const title = version.title;
|
||
|
||
return `【${date} ${time}】v${verNum} ${title}`;
|
||
}
|
||
|
||
startClock() {
|
||
const updateClock = () => {
|
||
const dateElement = this.shadowRoot.querySelector('.current-time .date');
|
||
const timeElement = this.shadowRoot.querySelector('.current-time .time');
|
||
const now = new Date();
|
||
|
||
dateElement.textContent = now.toLocaleString('zh-CN', {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit'
|
||
});
|
||
|
||
timeElement.textContent = now.toLocaleString('zh-CN', {
|
||
hour: '2-digit',
|
||
minute: '2-digit',
|
||
second: '2-digit',
|
||
hour12: false
|
||
});
|
||
};
|
||
|
||
updateClock();
|
||
this.clockInterval = setInterval(updateClock, 1000);
|
||
}
|
||
|
||
setupEventListeners() {
|
||
const detailsLink = this.shadowRoot.querySelector('.details-link');
|
||
if (detailsLink) {
|
||
detailsLink.addEventListener('click', (e) => {
|
||
e.preventDefault();
|
||
// 获取子工具栏
|
||
const subToolbar = document.querySelector('sub-toolbar');
|
||
if (subToolbar) {
|
||
// 触发与更新记录按钮相同的事件
|
||
const event = new CustomEvent('sub-item-selected', {
|
||
detail: {
|
||
parent: 'home',
|
||
text: '更新记录',
|
||
icon: 'clock'
|
||
},
|
||
bubbles: true,
|
||
composed: true
|
||
});
|
||
subToolbar.dispatchEvent(event);
|
||
|
||
// 激活更新记录按钮
|
||
const updateRecordButton = subToolbar.shadowRoot.querySelector('.sub-item[data-icon="clock"]');
|
||
if (updateRecordButton) {
|
||
// 移除其他按钮的激活状态
|
||
const siblings = updateRecordButton.parentElement.querySelectorAll('.sub-item');
|
||
siblings.forEach(si => si.classList.remove('active'));
|
||
// 激活更新记录按钮
|
||
updateRecordButton.classList.add('active');
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
render() {
|
||
// 添加加载状态的样式
|
||
const style = `
|
||
.update-list {
|
||
min-height: 100px;
|
||
position: relative;
|
||
}
|
||
|
||
.update-list.loading::after {
|
||
content: '加载中...';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
color: #666;
|
||
}
|
||
|
||
.update-list.error::after {
|
||
content: '加载失败';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
color: #ff4444;
|
||
}
|
||
`;
|
||
|
||
this.shadowRoot.innerHTML = `
|
||
<style>
|
||
${style}
|
||
:host {
|
||
display: block;
|
||
height: 100%;
|
||
}
|
||
|
||
.overview-container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
display: grid;
|
||
grid-template-columns: repeat(12, 1fr);
|
||
gap: 20px;
|
||
padding: 20px;
|
||
}
|
||
|
||
.welcome-card {
|
||
grid-column: span 8;
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
color: white;
|
||
border-radius: 12px;
|
||
padding: 30px;
|
||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.welcome-card h1 {
|
||
font-size: 32px;
|
||
margin: 0 0 10px 0;
|
||
}
|
||
|
||
.welcome-card p {
|
||
font-size: 16px;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.current-time {
|
||
grid-column: span 4;
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.current-time h2 {
|
||
font-size: 18px;
|
||
color: #2c3e50;
|
||
margin: 0 0 15px 0;
|
||
}
|
||
|
||
.current-time .value {
|
||
font-size: 24px;
|
||
color: #3498db;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.current-time .date{
|
||
display: block;
|
||
font-size: 20px;
|
||
color: #764ba2;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.current-time .time {
|
||
display: block;
|
||
font-size: 40px;
|
||
color: #667eea;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.version-info {
|
||
grid-column: span 4;
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.about-section {
|
||
grid-column: span 4;
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.calendar-widget {
|
||
grid-column: span 4;
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
.updates-log {
|
||
grid-column: span 12;
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
position: relative;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 18px;
|
||
color: #2c3e50;
|
||
margin: 0 0 15px 0;
|
||
}
|
||
|
||
.version-list, .update-list {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
.version-list li, .update-list li {
|
||
padding: 8px 0;
|
||
border-bottom: 1px solid #eee;
|
||
color: #2c3e50;
|
||
}
|
||
|
||
.version-list li:last-child, .update-list li:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.calendar {
|
||
text-align: center;
|
||
}
|
||
|
||
.calendar .month {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
color: #2c3e50;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.calendar-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(7, 1fr);
|
||
gap: 5px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.calendar-header {
|
||
display: grid;
|
||
grid-template-columns: repeat(7, 1fr);
|
||
gap: 5px;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.calendar-header span {
|
||
font-size: 14px;
|
||
color: #666;
|
||
text-align: center;
|
||
}
|
||
|
||
.calendar-day {
|
||
padding: 5px;
|
||
text-align: center;
|
||
font-size: 14px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.calendar-day.today {
|
||
background-color: #667eea;
|
||
color: white;
|
||
}
|
||
|
||
.calendar-day.other-month {
|
||
color: #ccc;
|
||
}
|
||
|
||
.version-list {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
.version-list li {
|
||
padding: 8px 0;
|
||
border-bottom: 1px solid #eee;
|
||
color: #2c3e50;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.version-list li .label {
|
||
color: #666;
|
||
font-size: 0.9em;
|
||
min-width: 80px;
|
||
}
|
||
|
||
.version-list li .value {
|
||
color: #2c3e50;
|
||
font-weight: 500;
|
||
text-align: right;
|
||
}
|
||
|
||
.version-list li:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.version-note {
|
||
color: #666;
|
||
font-size: 0.9em;
|
||
line-height: 1.4;
|
||
padding: 8px 0;
|
||
background: #f8f9fa;
|
||
border-radius: 4px;
|
||
margin-top: 8px;
|
||
padding: 10px;
|
||
}
|
||
|
||
.version-loading {
|
||
text-align: center;
|
||
color: #666;
|
||
padding: 20px 0;
|
||
}
|
||
|
||
.details-link {
|
||
position: absolute;
|
||
top: 20px;
|
||
right: 20px;
|
||
color: #667eea;
|
||
text-decoration: none;
|
||
font-size: 14px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
transition: color 0.3s;
|
||
}
|
||
|
||
.details-link:hover {
|
||
color: #764ba2;
|
||
}
|
||
|
||
.details-link::after {
|
||
content: '›';
|
||
font-size: 18px;
|
||
line-height: 1;
|
||
margin-top: -2px;
|
||
}
|
||
</style>
|
||
<div class="overview-container">
|
||
<div class="welcome-card">
|
||
<h1>欢迎使用 XNSim</h1>
|
||
<p>XNSim 是一个功能强大的仿真系统,为您提供专业的飞行模拟仿真分析工具和直观的操作界面。</p>
|
||
</div>
|
||
|
||
<div class="current-time">
|
||
<h2>当前时间</h2>
|
||
<div class="value">
|
||
<span class="date"></span>
|
||
<span class="time"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="version-info">
|
||
<h2 class="section-title">版本信息</h2>
|
||
${this.versions.length > 0 ? `
|
||
<ul class="version-list">
|
||
<li>
|
||
<span class="label">当前版本</span>
|
||
<span class="value">v${this.versions[0].verNum}</span>
|
||
</li>
|
||
<li>
|
||
<span class="label">发布日期</span>
|
||
<span class="value">${this.versions[0].date}</span>
|
||
</li>
|
||
<li>
|
||
<span class="label">发布时间</span>
|
||
<span class="value">${this.versions[0].time}</span>
|
||
</li>
|
||
</ul>
|
||
` : `
|
||
<div class="version-loading">版本信息加载中...</div>
|
||
`}
|
||
</div>
|
||
|
||
<div class="about-section">
|
||
<h2 class="section-title">关于系统</h2>
|
||
<p>XNSim 是新一代飞行模拟数据包仿真分析平台,致力于提供高效、准确的飞行模拟仿真解决方案。</p>
|
||
<ul class="version-list">
|
||
<li>开发团队:XNSim Team</li>
|
||
<li>技术支持:无</li>
|
||
<li>官方网站:无</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="calendar-widget">
|
||
<h2 class="section-title">日历</h2>
|
||
<div class="calendar">
|
||
<div class="month"></div>
|
||
<div class="calendar-header">
|
||
<span>日</span>
|
||
<span>一</span>
|
||
<span>二</span>
|
||
<span>三</span>
|
||
<span>四</span>
|
||
<span>五</span>
|
||
<span>六</span>
|
||
</div>
|
||
<div class="calendar-grid"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="updates-log">
|
||
<h2 class="section-title">更新记录</h2>
|
||
<a href="#" class="details-link">详细信息</a>
|
||
<ul class="update-list ${this.versions.length === 0 ? 'error' : ''}">
|
||
${this.versions.slice(0, 3).map(version => `
|
||
<li>${this.formatVersionRecord(version)}</li>
|
||
`).join('')}
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
// 初始化日历显示
|
||
const now = new Date();
|
||
const calendarElement = this.shadowRoot.querySelector('.calendar');
|
||
calendarElement.querySelector('.month').textContent = now.toLocaleString('zh-CN', { month: 'long' });
|
||
calendarElement.querySelector('.calendar-grid').innerHTML = this.generateCalendarGrid(now);
|
||
}
|
||
|
||
generateCalendarGrid(date) {
|
||
const year = date.getFullYear();
|
||
const month = date.getMonth();
|
||
const today = new Date();
|
||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||
const firstDay = new Date(year, month, 1).getDay();
|
||
const lastDayPrevMonth = new Date(year, month, 0).getDate();
|
||
let gridHtml = '';
|
||
|
||
// 上个月的日期
|
||
for (let i = firstDay - 1; i >= 0; i--) {
|
||
gridHtml += `<div class="calendar-day other-month">${lastDayPrevMonth - i}</div>`;
|
||
}
|
||
|
||
// 当月的日期
|
||
for (let day = 1; day <= daysInMonth; day++) {
|
||
const isToday = day === today.getDate() &&
|
||
month === today.getMonth() &&
|
||
year === today.getFullYear();
|
||
gridHtml += `<div class="calendar-day${isToday ? ' today' : ''}">${day}</div>`;
|
||
}
|
||
|
||
// 下个月的日期
|
||
const remainingDays = 42 - (firstDay + daysInMonth); // 保持6行格式
|
||
for (let day = 1; day <= remainingDays; day++) {
|
||
gridHtml += `<div class="calendar-day other-month">${day}</div>`;
|
||
}
|
||
|
||
return gridHtml;
|
||
}
|
||
}
|
||
|
||
customElements.define('overview-page', OverviewPage);
|