Files
2025-06-26 18:21:57 +07:00

266 lines
9.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exchange Rate Export</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
background: #f7f7f7;
}
.container {
background: #fff;
padding: 24px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.07);
max-width: 700px;
margin: auto;
}
h1 {
text-align: center;
}
label {
margin-right: 8px;
}
input[type="date"] {
margin-right: 16px;
padding: 4px 8px;
}
button {
padding: 8px 16px;
margin-right: 8px;
border: none;
border-radius: 4px;
background: #007bff;
color: #fff;
cursor: pointer;
font-size: 1rem;
}
button:disabled {
background: #aaa;
cursor: not-allowed;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 24px;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
th {
background: #007bff;
color: #fff;
}
.loading {
text-align: center;
margin-top: 20px;
color: #007bff;
}
.error {
color: red;
text-align: center;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>Exchange Rate Export (USD)</h1>
<div style="margin-bottom: 20px;">
<label for="start-date">Start Date:</label>
<input type="date" id="start-date">
<label for="end-date">End Date:</label>
<input type="date" id="end-date">
<button id="fetch-btn">Fetch</button>
<button id="export-btn" disabled>Export CSV</button>
</div>
<div id="status"></div>
<table id="result-table" style="display:none;">
<thead>
<tr>
<th>Date</th>
<th>nameVI</th>
<th>muaTm</th>
<th>muaCk</th>
<th>currency</th>
<th>nameEN</th>
<th>ban</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<script>
const fetchBtn = document.getElementById('fetch-btn');
const exportBtn = document.getElementById('export-btn');
const startDateInput = document.getElementById('start-date');
const endDateInput = document.getElementById('end-date');
const statusDiv = document.getElementById('status');
const table = document.getElementById('result-table');
const tbody = table.querySelector('tbody');
let results = [];
function formatDate(date) {
// Format as dd/MM/yyyy
const d = new Date(date);
const day = String(d.getDate()).padStart(2, '0');
const month = String(d.getMonth() + 1).padStart(2, '0');
const year = d.getFullYear();
return `${day}/${month}/${year}`;
}
function getDateRange(start, end) {
const dates = [];
let current = new Date(start);
const last = new Date(end);
while (current <= last) {
dates.push(new Date(current));
current.setDate(current.getDate() + 1);
}
return dates;
}
async function fetchNamerecord(dateStr) {
const url = 'https://bidv.com.vn/ServicesBIDV/ExchangeDetailSearchTimeServlet';
const payload = `date=${encodeURIComponent(dateStr)}`;
try {
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: payload
});
if (!res.ok) throw new Error('API 1 error');
const data = await res.json();
if (data.status !== 1 || !data.data || !data.data.length) return null;
// Get the latest (max time) record
let latest = data.data[0];
for (const rec of data.data) {
if (rec.time > latest.time) latest = rec;
}
return latest.namerecord;
} catch (e) {
return null;
}
}
async function fetchUSD(dateStr, namerecord) {
const url = 'https://bidv.com.vn/ServicesBIDV/ExchangeDetailServlet';
const payload = `date=${encodeURIComponent(dateStr)}&time=${namerecord}`;
try {
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: payload
});
if (!res.ok) throw new Error('API 2 error');
const data = await res.json();
if (data.status !== 1 || !data.data) return null;
// Find USD (currency === 'USD')
const usd = data.data.find(item => item.currency === 'USD');
if (!usd) return null;
return {
nameVI: usd.nameVI,
muaTm: usd.muaTm,
muaCk: usd.muaCk,
currency: usd.currency,
nameEN: usd.nameEN,
ban: usd.ban
};
} catch (e) {
return null;
}
}
function renderTable(data) {
tbody.innerHTML = '';
for (const row of data) {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${row.date}</td>
<td>${row.nameVI}</td>
<td>${row.muaTm}</td>
<td>${row.muaCk}</td>
<td>${row.currency}</td>
<td>${row.nameEN}</td>
<td>${row.ban}</td>
`;
tbody.appendChild(tr);
}
table.style.display = data.length ? '' : 'none';
}
function exportCSV(data) {
const header = ['Date', 'nameVI', 'muaTm', 'muaCk', 'currency', 'nameEN', 'ban'];
const rows = [header];
for (const row of data) {
rows.push([
row.date,
row.nameVI,
row.muaTm,
row.muaCk,
row.currency,
row.nameEN,
row.ban
]);
}
const csvContent = rows.map(r => r.map(cell => '"' + String(cell).replace(/"/g, '""') + '"').join(',')).join('\r\n');
const blob = new Blob([csvContent], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'usd_exchange_rates.csv';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
fetchBtn.onclick = async () => {
const start = startDateInput.value;
const end = endDateInput.value;
if (!start || !end) {
statusDiv.innerHTML = '<div class="error">Please select both start and end dates.</div>';
return;
}
if (start > end) {
statusDiv.innerHTML = '<div class="error">Start date must be before or equal to end date.</div>';
return;
}
statusDiv.innerHTML = '<div class="loading">Fetching data, please wait...</div>';
fetchBtn.disabled = true;
exportBtn.disabled = true;
results = [];
renderTable([]);
const dates = getDateRange(start, end);
for (let i = 0; i < dates.length; i++) {
const dateObj = dates[i];
const dateStr = formatDate(dateObj);
statusDiv.innerHTML = `<div class=\"loading\">Fetching: ${dateStr} (${i+1}/${dates.length})</div>`;
const namerecord = await fetchNamerecord(dateStr);
if (!namerecord) continue;
const usd = await fetchUSD(dateStr, namerecord);
if (usd) {
results.push({ date: dateStr, ...usd });
renderTable(results);
}
}
statusDiv.innerHTML = results.length ? '' : '<div class="error">No data found for the selected range.</div>';
fetchBtn.disabled = false;
exportBtn.disabled = results.length === 0;
};
exportBtn.onclick = () => {
if (results.length) exportCSV(results);
};
</script>
</body>
</html>