315 lines
10 KiB
HTML
315 lines
10 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>日本云服务器列表</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||
background-color: #f5f5f5;
|
||
padding: 10px;
|
||
}
|
||
.refresh-btn {
|
||
display: block;
|
||
margin: 0 auto 15px;
|
||
padding: 8px 20px;
|
||
background: #1a73e8;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
}
|
||
.refresh-btn:hover {
|
||
background: #1557b0;
|
||
}
|
||
.container {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
gap: 10px;
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
}
|
||
.server-card {
|
||
background-color: #fff;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 4px;
|
||
padding: 14px;
|
||
width: 320px;
|
||
}
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 8px;
|
||
}
|
||
.server-title {
|
||
font-size: 15px;
|
||
font-weight: bold;
|
||
color: #1a73e8;
|
||
}
|
||
.arrow-icon {
|
||
color: #1a73e8;
|
||
font-size: 14px;
|
||
}
|
||
.buy-link {
|
||
color: #1a73e8;
|
||
font-size: 13px;
|
||
text-decoration: none;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 2px;
|
||
}
|
||
.buy-link:hover {
|
||
text-decoration: underline;
|
||
}
|
||
.badges {
|
||
display: flex;
|
||
gap: 6px;
|
||
margin-bottom: 8px;
|
||
align-items: flex-start;
|
||
flex-wrap: wrap;
|
||
min-height: 66px;
|
||
}
|
||
.description-text {
|
||
color: #666;
|
||
font-size: 12px;
|
||
line-height: 1.4;
|
||
width: 100%;
|
||
margin-top: 4px;
|
||
}
|
||
.badge {
|
||
padding: 2px 8px;
|
||
border-radius: 3px;
|
||
font-size: 11px;
|
||
border: 1px solid;
|
||
}
|
||
.badge-orange {
|
||
color: #ff9800;
|
||
border-color: #ff9800;
|
||
background-color: #fff8e1;
|
||
}
|
||
.badge-green {
|
||
color: #4caf50;
|
||
border-color: #4caf50;
|
||
background-color: #e8f5e9;
|
||
}
|
||
.badge-blue {
|
||
color: #2196f3;
|
||
border-color: #2196f3;
|
||
background-color: #e3f2fd;
|
||
}
|
||
.info-grid {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
padding: 8px 0;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
.info-item {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 12px;
|
||
}
|
||
.info-label {
|
||
color: #666;
|
||
margin-right: 6px;
|
||
}
|
||
.info-value {
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
.date-row {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 8px 0;
|
||
color: #666;
|
||
font-size: 11px;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
.date-row .icon {
|
||
margin-left: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
.progress-section {
|
||
padding: 8px 0;
|
||
}
|
||
.progress-bar {
|
||
height: 14px;
|
||
background: linear-gradient(to right, #1a73e8 0%, #4285f4 100%);
|
||
border-radius: 7px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.progress-text {
|
||
position: absolute;
|
||
width: 100%;
|
||
text-align: center;
|
||
line-height: 14px;
|
||
color: #fff;
|
||
font-size: 10px;
|
||
}
|
||
.price-section {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: baseline;
|
||
margin-top: 8px;
|
||
padding-top: 8px;
|
||
border-top: 1px solid #f0f0f0;
|
||
}
|
||
.current-price {
|
||
color: #f44336;
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
}
|
||
.current-price .unit {
|
||
font-size: 12px;
|
||
font-weight: normal;
|
||
}
|
||
.original-price {
|
||
color: #999;
|
||
font-size: 12px;
|
||
text-decoration: line-through;
|
||
}
|
||
.server-card.highlight {
|
||
border: 2px solid #ff5722;
|
||
position: relative;
|
||
box-shadow: 0 4px 12px rgba(255, 87, 34, 0.3);
|
||
}
|
||
.highlight-badge {
|
||
position: absolute;
|
||
top: -1px;
|
||
right: -1px;
|
||
background: linear-gradient(135deg, #ff5722 0%, #f44336 100%);
|
||
color: #fff;
|
||
font-size: 11px;
|
||
font-weight: bold;
|
||
padding: 4px 10px;
|
||
border-bottom-left-radius: 10px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<button class="refresh-btn" onclick="fetchAndRenderServers()">🔄 刷新</button>
|
||
<div class="container" id="server-list"></div>
|
||
|
||
<script>
|
||
const cycleNameMap = {
|
||
'hour': '小时',
|
||
'day': '天',
|
||
'monthly': '月',
|
||
'quarterly': '季度',
|
||
'semiannually': '半年',
|
||
'annually': '年',
|
||
'biennially': '两年',
|
||
'triennially': '三年',
|
||
'fourly': '四年',
|
||
'fively': '五年',
|
||
'sixly': '六年',
|
||
'sevenly': '七年',
|
||
'eightly': '八年',
|
||
'ninely': '九年',
|
||
'tenly': '十年',
|
||
'onetime': '一次性'
|
||
};
|
||
|
||
const apiUrl = 'https://py.szhdy.com/api/public/market-products?page=1&page_size=12&order_by=latest&_t=' + new Date().getTime();
|
||
|
||
function fetchAndRenderServers() {
|
||
fetch(apiUrl)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
const servers = data.data.list.filter(server =>
|
||
server.product_name.includes('日本') ||
|
||
(server.billing_cycle.includes('annually') && server.price < 100) ||
|
||
(server.billing_cycle === 'biennially' && server.price < 121)
|
||
);
|
||
renderServers(servers);
|
||
})
|
||
.catch(error => console.error('Error fetching data:', error));
|
||
}
|
||
|
||
function renderServers(servers) {
|
||
const container = document.getElementById('server-list');
|
||
container.innerHTML = '';
|
||
|
||
servers.forEach(server => {
|
||
const card = document.createElement('div');
|
||
const isHighlight = server.product_name.includes('日本') && String(server.total_cost).includes('120');
|
||
card.className = 'server-card' + (isHighlight ? ' highlight' : '');
|
||
|
||
const cycleLabel = cycleNameMap[server.billing_cycle] || server.billing_cycle;
|
||
|
||
card.innerHTML = `
|
||
${isHighlight ? '<div class="highlight-badge">推荐</div>' : ''}
|
||
<div class="card-header">
|
||
<span class="server-title">${server.product_name}</span>
|
||
<a href="https://py.szhdy.com/buy/${server.id}.html" class="buy-link" target="_blank">购买 ›</a>
|
||
</div>
|
||
<div class="badges">
|
||
<span class="badge badge-orange">${cycleLabel}</span>
|
||
<span class="badge badge-green">剩余${server.remaining_days}天</span>
|
||
${server.description ? `<span class="description-text">${server.description}</span>` : '<span class="description-text"> </span>'}
|
||
</div>
|
||
<div class="info-grid">
|
||
<div class="info-item">
|
||
<span class="info-label">实例配置</span>
|
||
<span class="info-value">${server.cpu_cores} ${server.memory_size}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">存储</span>
|
||
<span class="info-value">${server.disk_size}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">网络</span>
|
||
<span class="info-value">${server.bandwidth} ${server.ip_count}IP</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">月流量</span>
|
||
<span class="info-value">${server.bwlimit_label}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">Windows</span>
|
||
<span class="info-value">${server.windows_support ? '支持' : '不支持'}</span>
|
||
</div>
|
||
</div>
|
||
<div class="date-row">
|
||
<span>${server.purchase_time} ~ ${server.expire_time}</span>
|
||
<span class="icon">
|
||
<span>👁 ${server.views}</span>
|
||
<span>🤍 ${server.want}</span>
|
||
</span>
|
||
</div>
|
||
<div class="progress-section">
|
||
<div class="progress-bar">
|
||
<span class="progress-text">${server.total_days}天/${server.remaining_days}天 剩余${server.remaining_percent}%</span>
|
||
</div>
|
||
</div>
|
||
<div class="price-section">
|
||
<span class="current-price">¥${server.price} <span class="unit">元</span></span>
|
||
<span class="original-price">¥${server.original_price}</span>
|
||
</div>
|
||
`;
|
||
|
||
container.appendChild(card);
|
||
});
|
||
}
|
||
|
||
// Initial fetch and render
|
||
fetchAndRenderServers();
|
||
|
||
// Fetch and render every 3 minutes
|
||
setInterval(fetchAndRenderServers, 3 * 60 * 1000);
|
||
</script>
|
||
</body>
|
||
</html>
|