feat: 汇率换算功能完整实现

- 首页双向换算:30种主流货币,实时计算,一键互换
- 汇率总览页:一对多查看所有货币换算结果
- 数据源 open.er-api.com,4小时本地缓存 + 失败兜底
- UI 美化:渐变背景、分色货币块、紫色互换按钮

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
manpengan
2026-03-18 17:26:53 +08:00
parent 6b60379b0c
commit 92304d4fa2
15 changed files with 922 additions and 47 deletions

View File

@@ -1,7 +1,84 @@
const { CURRENCIES, getPickerData } = require('../../utils/currencies');
const { getRates, convert, formatAmount, formatRate } = require('../../utils/rate');
const pickerData = getPickerData();
Page({
data: {},
data: {
pickerData,
baseIndex: 0, // CNY
amount: '100',
list: [],
updatedAt: '',
loading: true,
error: '',
rates: null,
},
onLoad() {
console.log('Overview page loaded');
this.loadRates();
},
onPullDownRefresh() {
this.loadRates().then(() => {
wx.stopPullDownRefresh();
});
},
async loadRates() {
this.setData({ loading: true, error: '' });
try {
const baseCode = CURRENCIES[this.data.baseIndex].code;
const { rates, updatedAt } = await getRates(baseCode);
this.setData({
rates,
updatedAt,
loading: false,
});
this.buildList();
} catch (e) {
this.setData({
loading: false,
error: '汇率获取失败,请检查网络后下拉刷新',
});
}
},
buildList() {
const { rates, baseIndex, amount } = this.data;
if (!rates) return;
const num = parseFloat(amount);
if (isNaN(num) || num <= 0) {
this.setData({ list: [] });
return;
}
const baseCode = CURRENCIES[baseIndex].code;
const list = CURRENCIES
.filter((c) => c.code !== baseCode)
.map((c) => {
const converted = convert(num, baseCode, c.code, rates);
const unitRate = convert(1, baseCode, c.code, rates);
return {
flag: c.flag,
code: c.code,
name: c.name,
converted: formatAmount(converted, c.code),
unitRate: formatRate(unitRate),
};
});
this.setData({ list });
},
handleBaseChange(e) {
this.setData({ baseIndex: Number(e.detail.value) });
this.loadRates();
},
handleAmountInput(e) {
this.setData({ amount: e.detail.value });
this.buildList();
},
});