Files
currency-converter/miniprogram/pages/index/index.js
manpengan 2516cc2085 ui: 暗色金融风重构 + 自定义货币选择器
- 深色主题:深蓝背景 + 毛玻璃卡片 + 金色结果数字
- 自定义底部弹窗货币选择器,替换原生白色 Picker
- 换算卡片内容居中竖排布局
- 汇率信息条改为竖排独立卡片
- 实时脉冲徽章 + 蓝紫渐变互换按钮

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 18:19:02 +08:00

107 lines
2.6 KiB
JavaScript

const { CURRENCIES, getPickerData } = require('../../utils/currencies');
const { getRates, convert, formatAmount, formatRate } = require('../../utils/rate');
const pickerData = getPickerData();
const DEFAULT_FROM = 0;
const DEFAULT_TO = 1;
Page({
data: {
pickerData,
fromIndex: DEFAULT_FROM,
toIndex: DEFAULT_TO,
amount: '100',
result: '',
unitRate: '',
reverseRate: '',
updatedAt: '',
loading: true,
error: '',
rates: null,
// picker state
showPicker: false,
pickerTarget: '', // 'from' or 'to'
},
onLoad() {
this.loadRates();
},
onPullDownRefresh() {
this.loadRates().then(() => {
wx.stopPullDownRefresh();
});
},
async loadRates() {
this.setData({ loading: true, error: '' });
try {
const { rates, updatedAt } = await getRates('CNY');
this.setData({ rates, baseCurrency: 'CNY', updatedAt, loading: false });
this.calculate();
} catch (e) {
this.setData({ loading: false, error: '汇率获取失败,请下拉刷新重试' });
}
},
calculate() {
const { rates, fromIndex, toIndex, amount } = this.data;
if (!rates) return;
const num = parseFloat(amount);
if (isNaN(num) || num <= 0) {
this.setData({ result: '', unitRate: '', reverseRate: '' });
return;
}
const fromCode = CURRENCIES[fromIndex].code;
const toCode = CURRENCIES[toIndex].code;
const converted = convert(num, fromCode, toCode, rates);
const unitForward = convert(1, fromCode, toCode, rates);
const unitReverse = convert(1, toCode, fromCode, rates);
this.setData({
result: formatAmount(converted, toCode),
unitRate: `1 ${fromCode} = ${formatRate(unitForward)} ${toCode}`,
reverseRate: `1 ${toCode} = ${formatRate(unitReverse)} ${fromCode}`,
});
},
handleAmountInput(e) {
this.setData({ amount: e.detail.value });
this.calculate();
},
openFromPicker() {
this.setData({ showPicker: true, pickerTarget: 'from' });
},
openToPicker() {
this.setData({ showPicker: true, pickerTarget: 'to' });
},
handlePickerSelect(e) {
const index = e.detail.value;
if (this.data.pickerTarget === 'from') {
this.setData({ fromIndex: index, showPicker: false });
} else {
this.setData({ toIndex: index, showPicker: false });
}
this.calculate();
},
handlePickerClose() {
this.setData({ showPicker: false });
},
handleSwap() {
const { fromIndex, toIndex } = this.data;
this.setData({ fromIndex: toIndex, toIndex: fromIndex });
this.calculate();
},
goOverview() {
wx.navigateTo({ url: '/pages/overview/overview' });
},
});