feat: server api

- tcb: work
- bidv: not work
This commit is contained in:
tiennm99 committed 2025-06-27 00:12:33 +07:00
1 parent 59d8625952
commit f3debe9cd9
2 files changed
+179 -140

No files matched your search

+43 -140
View File
@@ -14,165 +14,68 @@
let results = []; let results = [];
let showTable = false; let showTable = false;
// Format date for display // Format date for display
const formatDisplayDate = (dateStr) => { const formatDisplayDate = (dateStr) => {
const [year, month, day] = dateStr.split('-'); try {
return `${day}/${month}/${year}`; // Handle both yyyy-MM-dd and dd/MM/yyyy formats
}; let date;
if (dateStr.includes('/')) {
// Get date range between start and end dates const [day, month, year] = dateStr.split('/');
const getDateRange = (start, end) => { date = new Date(`${year}-${month}-${day}`);
const dates = []; } else {
let current = new Date(start); date = new Date(dateStr);
const last = new Date(end); }
return format(date, 'dd/MM/yyyy');
while (current <= last) { } catch (e) {
dates.push(new Date(current)); return dateStr; // Return as is if parsing fails
current.setDate(current.getDate() + 1);
} }
return dates;
}; };
// Format date for API requests // Handle form submission
const formatDateForApi = (date) => {
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}`;
};
// Fetch BIDV exchange rates
const fetchBIDVRates = async (dateObj) => {
const dateStr = format(dateObj, 'dd/MM/yyyy');
// First API call to get namerecord
const timeRes = await fetch('https://bidv.com.vn/ServicesBIDV/ExchangeDetailSearchTimeServlet', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `date=${encodeURIComponent(dateStr)}`
});
if (!timeRes.ok) throw new Error('Failed to fetch BIDV time data');
const timeData = await timeRes.json();
if (timeData.status !== 1 || !timeData.data?.length) return null;
// Get the latest record
const latest = timeData.data.reduce((latest, current) =>
current.time > latest.time ? current : latest, timeData.data[0]);
// Second API call to get exchange rates
const rateRes = await fetch('https://bidv.com.vn/ServicesBIDV/ExchangeDetailServlet', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `date=${encodeURIComponent(dateStr)}&time=${latest.namerecord}`
});
if (!rateRes.ok) throw new Error('Failed to fetch BIDV rate data');
const rateData = await rateRes.json();
if (rateData.status !== 1 || !rateData.data) return null;
// Find USD data
const usd = rateData.data.find(item => item.currency === 'USD');
if (!usd) return null;
return {
date: dateStr,
nameVI: usd.nameVI || '',
muaTm: usd.muaTm || '',
muaCk: usd.muaCk || '',
currency: usd.currency || 'USD',
nameEN: usd.nameEN || '',
ban: usd.ban || ''
};
};
// Fetch TCB exchange rates
const fetchTCBRates = async (dateObj) => {
const dateStr = format(dateObj, 'yyyy-MM-dd');
const url = `https://techcombank.com/content/techcombank/web/vn/vi/cong-cu-tien-ich/ty-gia/_jcr_content.exchange-rates.${dateStr}.integration.json`;
const res = await fetch(url);
if (!res.ok) throw new Error('Failed to fetch TCB data');
const data = await res.json();
if (!data.exchangeRate?.data) return null;
// Find USD data
const usd = data.exchangeRate.data.find(item => item.label === 'USD (50,100)');
if (!usd) return null;
return {
date: formatDisplayDate(dateStr),
label: usd.label || '',
askRate: usd.askRate || '',
bidRateCK: usd.bidRateCK || '',
bidRateTM: usd.bidRateTM || '',
askRateTM: usd.askRateTM || '',
sourceCurrency: usd.sourceCurrency || 'USD',
targetCurrency: usd.targetCurrency || 'VND'
};
};
// Handle fetch button click
const handleFetch = async () => { const handleFetch = async () => {
if (!startDate || !endDate) { if (!startDate || !endDate) {
error = 'Please select both start and end dates'; error = 'Please select both start and end dates';
return; return;
} }
const start = new Date(startDate);
const end = new Date(endDate);
if (start > end) {
error = 'Start date must be before end date';
return;
}
const dateRange = getDateRange(start, end);
if (dateRange.length > 31) {
error = 'Date range cannot exceed 31 days';
return;
}
isLoading = true;
error = ''; error = '';
isLoading = true;
results = []; results = [];
showTable = false; showTable = false;
try { try {
const fetchPromises = dateRange.map(async (date) => { const start = new Date(startDate);
try { const end = new Date(endDate);
if (selectedBank === 'bidv') {
return await fetchBIDVRates(date); if (start > end) {
} else { error = 'Start date cannot be after end date';
return await fetchTCBRates(date); return;
} }
} catch (e) {
console.error(`Error fetching data for ${date}:`, e); // Call our server endpoint
return null; const response = await fetch('/api/exchange-rates', {
} method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
startDate: start.toISOString().split('T')[0],
endDate: end.toISOString().split('T')[0],
bank: selectedBank
})
}); });
const fetchedResults = await Promise.all(fetchPromises); if (!response.ok) {
results = fetchedResults.filter(Boolean); const errorData = await response.json();
showTable = results.length > 0; throw new Error(errorData.error || 'Failed to fetch exchange rates');
if (results.length === 0) {
error = 'No data found for the selected date range';
} }
} catch (e) {
console.error('Error fetching data:', e); const data = await response.json();
error = 'An error occurred while fetching data. Please try again.'; results = data.data || [];
showTable = true;
} catch (err) {
error = `An error occurred while fetching exchange rates: ${err.message}`;
console.error(err);
} finally { } finally {
isLoading = false; isLoading = false;
} }
+136
View File
@@ -0,0 +1,136 @@
import { json } from '@sveltejs/kit';
import { format, parse } from 'date-fns';
// Helper function to fetch BIDV exchange rates
async function fetchBIDVRates(dateObj) {
const dateStr = format(dateObj, 'dd/MM/yyyy');
try {
// First API call to get namerecord
const timeRes = await fetch('https://bidv.com.vn/ServicesBIDV/ExchangeDetailSearchTimeServlet', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `date=${encodeURIComponent(dateStr)}`
});
if (!timeRes.ok) throw new Error('Failed to fetch BIDV time data');
const timeData = await timeRes.json();
if (timeData.status !== 1 || !timeData.data?.length) return null;
// Get the latest record
const latest = timeData.data.reduce((latest, current) =>
current.time > latest.time ? current : latest, timeData.data[0]);
// Second API call to get exchange rates
const rateRes = await fetch('https://bidv.com.vn/ServicesBIDV/ExchangeDetailServlet', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `date=${encodeURIComponent(dateStr)}&time=${latest.namerecord}`
});
if (!rateRes.ok) throw new Error('Failed to fetch BIDV rate data');
const rateData = await rateRes.json();
if (rateData.status !== 1 || !rateData.data) return null;
// Find USD data
const usd = rateData.data.find(item => item.currency === 'USD');
if (!usd) return null;
return {
date: dateStr,
nameVI: usd.nameVI || '',
muaTm: usd.muaTm || '',
muaCk: usd.muaCk || '',
currency: usd.currency || 'USD',
nameEN: usd.nameEN || '',
ban: usd.ban || ''
};
} catch (error) {
console.error('Error fetching BIDV rates:', error);
return null;
}
}
// Helper function to fetch TCB exchange rates
async function fetchTCBRates(dateObj) {
const dateStr = format(dateObj, 'yyyy-MM-dd');
const url = `https://techcombank.com/content/techcombank/web/vn/vi/cong-cu-tien-ich/ty-gia/_jcr_content.exchange-rates.${dateStr}.integration.json`;
const res = await fetch(url);
if (!res.ok) throw new Error('Failed to fetch TCB data');
const data = await res.json();
if (!data.exchangeRate?.data) return null;
// Find USD data
const usd = data.exchangeRate.data.find(item => item.label === 'USD (50,100)');
if (!usd) return null;
return {
date: dateStr,
label: usd.label || '',
askRate: usd.askRate || '',
bidRateCK: usd.bidRateCK || '',
bidRateTM: usd.bidRateTM || '',
askRateTM: usd.askRateTM || '',
sourceCurrency: usd.sourceCurrency || 'USD',
targetCurrency: usd.targetCurrency || 'VND'
};
};
// Get date range between start and end dates
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;
}
export async function POST({ request }) {
try {
const { startDate, endDate, bank } = await request.json();
if (!startDate || !endDate || !bank) {
return json({ error: 'Missing required parameters' }, { status: 400 });
}
const dates = getDateRange(new Date(startDate), new Date(endDate));
const results = [];
for (const date of dates) {
let rate = null;
try {
if (bank === 'bidv') {
rate = await fetchBIDVRates(date);
} else if (bank === 'tcb') {
rate = await fetchTCBRates(date);
}
if (rate) {
results.push(rate);
}
} catch (error) {
console.error(`Error fetching rates for ${date}:`, error);
// Continue with next date even if one fails
}
}
return json({ data: results });
} catch (error) {
console.error('Server error:', error);
return json({ error: 'Internal server error' }, { status: 500 });
}
}