XNSim/XNSimHtml/components/overview-page.js

641 lines
22 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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');
}
}
});
}
// 添加Q&A和帮助链接的事件监听
const qaLink = this.shadowRoot.querySelector('#qa-link');
const helpLink = this.shadowRoot.querySelector('#help-link');
if (qaLink) {
qaLink.addEventListener('click', (e) => {
e.preventDefault();
// 获取子工具栏
const subToolbar = document.querySelector('sub-toolbar');
if (subToolbar) {
// 触发与常见问题按钮相同的事件
const event = new CustomEvent('sub-item-selected', {
detail: {
parent: 'home',
text: 'Q&A',
icon: 'question'
},
bubbles: true,
composed: true
});
subToolbar.dispatchEvent(event);
}
});
}
if (helpLink) {
helpLink.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: 'help'
},
bubbles: true,
composed: true
});
subToolbar.dispatchEvent(event);
}
});
}
}
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);
display: flex;
flex-direction: column;
}
.about-section .section-title {
margin-bottom: 15px;
}
.about-section p {
margin-bottom: 15px;
}
.about-section .version-list {
margin-bottom: auto;
}
.help-links {
margin-top: auto;
display: flex;
gap: 16px;
justify-content: center;
padding-top: 20px;
border-top: 1px solid #eee;
}
.help-link {
position: relative;
color: #667eea;
text-decoration: none;
display: flex;
align-items: center;
gap: 6px;
font-size: 15px;
padding: 4px 2px;
transition: all 0.3s ease;
}
.help-link:hover {
color: #764ba2;
}
.help-link::before {
content: '';
display: inline-block;
width: 16px;
height: 16px;
background-size: 16px;
background-repeat: no-repeat;
background-position: center;
transition: all 0.3s ease;
/* 将黑色图标转换为蓝色 (#667eea) */
filter: brightness(0) saturate(100%) invert(53%) sepia(95%) saturate(1731%) hue-rotate(213deg) brightness(99%) contrast(94%) !important;
}
#qa-link::before {
background-image: url('assets/icons/png/question_b.png');
}
#help-link::before {
background-image: url('assets/icons/png/help_b.png');
}
.help-link:hover::before {
/* 将黑色图标转换为紫色 (#764ba2) */
filter: brightness(0) saturate(100%) invert(36%) sepia(24%) saturate(1674%) hue-rotate(233deg) brightness(94%) contrast(92%) !important;
}
.help-link::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1px;
background: currentColor;
transform: scaleX(0);
transform-origin: right;
transition: transform 0.3s ease;
}
.help-link:hover::after {
transform: scaleX(1);
transform-origin: left;
}
.help-link::before {
content: '';
display: inline-block;
width: 18px;
height: 18px;
background-size: 18px;
background-repeat: no-repeat;
background-position: center;
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.1));
transition: all 0.3s ease;
}
.help-link:hover::before {
transform: scale(1.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 class="help-links">
<a href="#" class="help-link" id="qa-link">Q&A</a>
<a href="#" class="help-link" id="help-link">帮助</a>
</div>
</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);