diff --git a/miniprogram/app.json b/miniprogram/app.json
index 17cef4e..40a733c 100644
--- a/miniprogram/app.json
+++ b/miniprogram/app.json
@@ -4,10 +4,10 @@
"pages/overview/overview"
],
"window": {
- "navigationBarTitleText": "汇率换算",
- "navigationBarBackgroundColor": "#FFFFFF",
- "navigationBarTextStyle": "black",
- "backgroundColor": "#F5F5F5",
+ "navigationBarTitleText": "",
+ "navigationBarBackgroundColor": "#0B1120",
+ "navigationBarTextStyle": "white",
+ "backgroundColor": "#0B1120",
"backgroundTextStyle": "dark"
},
"style": "v2",
diff --git a/miniprogram/app.wxss b/miniprogram/app.wxss
index e1b7f2a..d2d7a6e 100644
--- a/miniprogram/app.wxss
+++ b/miniprogram/app.wxss
@@ -1,19 +1,23 @@
page {
- background: linear-gradient(180deg, #EEF2FF 0%, #F5F5F5 320rpx);
- color: #1E293B;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ background: #0B1120;
+ color: #E2E8F0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
font-size: 28rpx;
line-height: 1.6;
}
.container {
- padding: 32rpx;
- padding-top: 24rpx;
+ min-height: 100vh;
+ padding: 24rpx 28rpx;
+ background:
+ radial-gradient(ellipse at 20% 0%, rgba(59, 130, 246, 0.08) 0%, transparent 50%),
+ radial-gradient(ellipse at 80% 100%, rgba(168, 85, 247, 0.06) 0%, transparent 50%),
+ #0B1120;
}
.card {
- background-color: #FFFFFF;
- border-radius: 24rpx;
+ background: rgba(30, 41, 59, 0.7);
+ border: 2rpx solid rgba(148, 163, 184, 0.1);
+ border-radius: 28rpx;
margin-bottom: 24rpx;
- box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.06);
}
diff --git a/miniprogram/components/currency-picker/currency-picker.js b/miniprogram/components/currency-picker/currency-picker.js
new file mode 100644
index 0000000..989fdbe
--- /dev/null
+++ b/miniprogram/components/currency-picker/currency-picker.js
@@ -0,0 +1,24 @@
+Component({
+ properties: {
+ show: { type: Boolean, value: false },
+ list: { type: Array, value: [] },
+ current: { type: Number, value: 0 },
+ },
+
+ methods: {
+ handleSelect(e) {
+ const index = e.currentTarget.dataset.index;
+ this.triggerEvent('select', { value: index });
+ },
+
+ handleClose() {
+ this.triggerEvent('close');
+ },
+
+ handleMaskTap() {
+ this.triggerEvent('close');
+ },
+
+ preventBubble() {},
+ },
+});
diff --git a/miniprogram/components/currency-picker/currency-picker.json b/miniprogram/components/currency-picker/currency-picker.json
new file mode 100644
index 0000000..a89ef4d
--- /dev/null
+++ b/miniprogram/components/currency-picker/currency-picker.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
diff --git a/miniprogram/components/currency-picker/currency-picker.wxml b/miniprogram/components/currency-picker/currency-picker.wxml
new file mode 100644
index 0000000..d50ff2f
--- /dev/null
+++ b/miniprogram/components/currency-picker/currency-picker.wxml
@@ -0,0 +1,20 @@
+
+
+
+
+
+ {{item}}
+ ✓
+
+
+
+
diff --git a/miniprogram/components/currency-picker/currency-picker.wxss b/miniprogram/components/currency-picker/currency-picker.wxss
new file mode 100644
index 0000000..51d6e31
--- /dev/null
+++ b/miniprogram/components/currency-picker/currency-picker.wxss
@@ -0,0 +1,84 @@
+.picker-mask {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.6);
+ z-index: 1000;
+ display: flex;
+ align-items: flex-end;
+}
+
+.picker-sheet {
+ width: 100%;
+ max-height: 70vh;
+ background: #1E293B;
+ border-top-left-radius: 36rpx;
+ border-top-right-radius: 36rpx;
+ border-top: 2rpx solid rgba(148, 163, 184, 0.15);
+ padding-bottom: env(safe-area-inset-bottom);
+}
+
+.sheet-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 36rpx 40rpx 24rpx;
+ border-bottom: 2rpx solid rgba(148, 163, 184, 0.08);
+}
+
+.sheet-title {
+ font-size: 34rpx;
+ font-weight: 700;
+ color: #F1F5F9;
+ letter-spacing: 2rpx;
+}
+
+.sheet-close {
+ font-size: 32rpx;
+ color: #64748B;
+ width: 64rpx;
+ height: 64rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ background: rgba(148, 163, 184, 0.08);
+}
+
+.sheet-scroll {
+ max-height: 56vh;
+ padding: 12rpx 0;
+}
+
+.sheet-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 28rpx 40rpx;
+ margin: 0 16rpx;
+ border-radius: 16rpx;
+}
+
+.sheet-item-active {
+ background: rgba(99, 102, 241, 0.12);
+ border: 2rpx solid rgba(99, 102, 241, 0.25);
+}
+
+.item-text {
+ font-size: 30rpx;
+ color: #CBD5E1;
+ font-weight: 500;
+}
+
+.sheet-item-active .item-text {
+ color: #A5B4FC;
+ font-weight: 600;
+}
+
+.item-check {
+ font-size: 30rpx;
+ color: #818CF8;
+ font-weight: 700;
+}
diff --git a/miniprogram/pages/index/index.js b/miniprogram/pages/index/index.js
index 397d820..ca43564 100644
--- a/miniprogram/pages/index/index.js
+++ b/miniprogram/pages/index/index.js
@@ -2,8 +2,8 @@ const { CURRENCIES, getPickerData } = require('../../utils/currencies');
const { getRates, convert, formatAmount, formatRate } = require('../../utils/rate');
const pickerData = getPickerData();
-const DEFAULT_FROM = 0; // CNY
-const DEFAULT_TO = 1; // USD
+const DEFAULT_FROM = 0;
+const DEFAULT_TO = 1;
Page({
data: {
@@ -18,7 +18,9 @@ Page({
loading: true,
error: '',
rates: null,
- baseCurrency: 'CNY',
+ // picker state
+ showPicker: false,
+ pickerTarget: '', // 'from' or 'to'
},
onLoad() {
@@ -35,23 +37,15 @@ Page({
this.setData({ loading: true, error: '' });
try {
const { rates, updatedAt } = await getRates('CNY');
- this.setData({
- rates,
- baseCurrency: 'CNY',
- updatedAt,
- loading: false,
- });
+ this.setData({ rates, baseCurrency: 'CNY', updatedAt, loading: false });
this.calculate();
} catch (e) {
- this.setData({
- loading: false,
- error: '汇率获取失败,请检查网络后下拉刷新',
- });
+ this.setData({ loading: false, error: '汇率获取失败,请下拉刷新重试' });
}
},
calculate() {
- const { rates, fromIndex, toIndex, amount, baseCurrency } = this.data;
+ const { rates, fromIndex, toIndex, amount } = this.data;
if (!rates) return;
const num = parseFloat(amount);
@@ -74,33 +68,39 @@ Page({
},
handleAmountInput(e) {
- const value = e.detail.value;
- this.setData({ amount: value });
+ this.setData({ amount: e.detail.value });
this.calculate();
},
- handleFromChange(e) {
- this.setData({ fromIndex: Number(e.detail.value) });
+ 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();
},
- handleToChange(e) {
- this.setData({ toIndex: Number(e.detail.value) });
- this.calculate();
+ handlePickerClose() {
+ this.setData({ showPicker: false });
},
handleSwap() {
const { fromIndex, toIndex } = this.data;
- this.setData({
- fromIndex: toIndex,
- toIndex: fromIndex,
- });
+ this.setData({ fromIndex: toIndex, toIndex: fromIndex });
this.calculate();
},
goOverview() {
- wx.navigateTo({
- url: '/pages/overview/overview',
- });
+ wx.navigateTo({ url: '/pages/overview/overview' });
},
});
diff --git a/miniprogram/pages/index/index.json b/miniprogram/pages/index/index.json
index 9fa0b64..65abfd9 100644
--- a/miniprogram/pages/index/index.json
+++ b/miniprogram/pages/index/index.json
@@ -1,5 +1,7 @@
{
- "navigationBarTitleText": "汇率换算",
+ "navigationBarTitleText": "",
"enablePullDownRefresh": true,
- "usingComponents": {}
+ "usingComponents": {
+ "currency-picker": "/components/currency-picker/currency-picker"
+ }
}
diff --git a/miniprogram/pages/index/index.wxml b/miniprogram/pages/index/index.wxml
index a20aec9..05f41c5 100644
--- a/miniprogram/pages/index/index.wxml
+++ b/miniprogram/pages/index/index.wxml
@@ -1,76 +1,84 @@
-
+
- 💱 汇率换算
- {{updatedAt}} 更新
- 正在获取最新汇率...
+
+ 汇率换算
+
+
+ 实时
+
+
+ {{updatedAt}}
+ 正在同步汇率数据...
-
-
- {{pickerData[fromIndex]}}
- ▼
-
-
+ 从
+
+ {{pickerData[fromIndex]}}
+ ›
+
-
-
-
-
+
+
+
+
⇅
-
+
-
-
- {{pickerData[toIndex]}}
- ▼
-
-
- {{result || '—'}}
+ 到
+
+ {{pickerData[toIndex]}}
+ ›
+
+ {{result || '0.00'}}
-
-
-
-
+
+
+
{{unitRate}}
-
-
+
{{reverseRate}}
-
+
- ⚠
{{error}}
-
-
-
- 📊
- 查看汇率总览
+
+
+
+ 查看全部汇率
+ →
- ›
+
+
diff --git a/miniprogram/pages/index/index.wxss b/miniprogram/pages/index/index.wxss
index 36ee0cf..d5dfa41 100644
--- a/miniprogram/pages/index/index.wxss
+++ b/miniprogram/pages/index/index.wxss
@@ -1,192 +1,225 @@
-/* ===== 顶部标题 ===== */
+/* ===== HERO ===== */
.hero {
- padding: 16rpx 8rpx 24rpx;
+ padding: 12rpx 4rpx 28rpx;
+}
+
+.hero-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
}
.hero-title {
- font-size: 48rpx;
+ font-size: 50rpx;
font-weight: 800;
- color: #1E293B;
- letter-spacing: 2rpx;
+ color: #F8FAFC;
+ letter-spacing: 3rpx;
+}
+
+.hero-badge {
+ display: flex;
+ align-items: center;
+ background: rgba(16, 185, 129, 0.1);
+ border: 2rpx solid rgba(16, 185, 129, 0.2);
+ border-radius: 40rpx;
+ padding: 8rpx 20rpx;
+}
+
+.badge-dot {
+ width: 12rpx;
+ height: 12rpx;
+ border-radius: 50%;
+ background: #10B981;
+ margin-right: 10rpx;
+ animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.3; }
+}
+
+.badge-text {
+ font-size: 22rpx;
+ color: #10B981;
+ font-weight: 600;
}
.hero-desc {
font-size: 24rpx;
- color: #94A3B8;
+ color: #475569;
margin-top: 8rpx;
}
-/* ===== 换算主卡片 ===== */
+/* ===== CONVERTER ===== */
.converter-card {
- padding: 40rpx 36rpx;
+ padding: 32rpx;
+ background: linear-gradient(160deg, rgba(30, 41, 59, 0.95) 0%, rgba(15, 23, 42, 0.98) 100%);
+ border: 2rpx solid rgba(148, 163, 184, 0.1);
}
.currency-block {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 24rpx;
border-radius: 20rpx;
- padding: 28rpx;
}
.from-block {
- background: #F8FAFC;
- border: 2rpx solid #E2E8F0;
+ background: rgba(148, 163, 184, 0.04);
+ border: 2rpx solid rgba(148, 163, 184, 0.06);
}
.to-block {
- background: linear-gradient(135deg, #EEF2FF 0%, #E0E7FF 100%);
- border: 2rpx solid #C7D2FE;
+ background: rgba(251, 191, 36, 0.03);
+ border: 2rpx solid rgba(251, 191, 36, 0.08);
}
-.currency-tag {
+.block-label {
+ font-size: 22rpx;
+ color: #475569;
+ font-weight: 700;
+ letter-spacing: 6rpx;
+ margin-bottom: 16rpx;
+}
+
+.currency-chip {
display: inline-flex;
align-items: center;
- background: #FFFFFF;
- border-radius: 12rpx;
- padding: 10rpx 20rpx;
- box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+ background: rgba(148, 163, 184, 0.06);
+ border: 2rpx solid rgba(148, 163, 184, 0.12);
+ border-radius: 14rpx;
+ padding: 14rpx 24rpx;
+ margin-bottom: 24rpx;
}
-.currency-tag-text {
- font-size: 26rpx;
- font-weight: 500;
- color: #334155;
+.chip-text {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #CBD5E1;
}
-.tag-arrow {
- font-size: 18rpx;
- color: #94A3B8;
- margin-left: 10rpx;
+.chip-arrow {
+ font-size: 28rpx;
+ color: #475569;
+ margin-left: 12rpx;
}
.amount-input {
width: 100%;
- margin-top: 20rpx;
- font-size: 56rpx;
+ font-size: 64rpx;
font-weight: 800;
- color: #1E293B;
- text-align: right;
+ color: #F1F5F9;
+ text-align: center;
+ letter-spacing: 2rpx;
}
.amount-placeholder {
- color: #CBD5E1;
- font-weight: 400;
+ color: #1E293B;
+ font-weight: 600;
}
-.result-display {
- margin-top: 20rpx;
- font-size: 56rpx;
+.result-amount {
+ font-size: 64rpx;
font-weight: 800;
- color: #4F46E5;
- text-align: right;
+ color: #FBBF24;
+ text-align: center;
+ letter-spacing: 2rpx;
+ text-shadow: 0 0 48rpx rgba(251, 191, 36, 0.12);
}
-/* ===== 互换按钮 ===== */
-.swap-wrapper {
+/* ===== SWAP ===== */
+.swap-zone {
display: flex;
align-items: center;
- justify-content: center;
- padding: 12rpx 0;
+ padding: 16rpx 0;
}
-.swap-line {
+.swap-track {
flex: 1;
height: 2rpx;
- background: #E2E8F0;
+ background: linear-gradient(90deg, transparent, rgba(148, 163, 184, 0.1), transparent);
}
.swap-btn {
- width: 80rpx;
- height: 80rpx;
+ width: 84rpx;
+ height: 84rpx;
border-radius: 50%;
- background: #4F46E5;
+ background: linear-gradient(140deg, #3B82F6 0%, #6366F1 100%);
display: flex;
align-items: center;
justify-content: center;
margin: 0 24rpx;
- box-shadow: 0 6rpx 20rpx rgba(79, 70, 229, 0.3);
+ box-shadow:
+ 0 8rpx 28rpx rgba(99, 102, 241, 0.3),
+ inset 0 2rpx 4rpx rgba(255, 255, 255, 0.1);
}
.swap-icon {
- font-size: 36rpx;
+ font-size: 38rpx;
color: #FFFFFF;
+ font-weight: 700;
}
-/* ===== 单位汇率 ===== */
-.rate-card {
- padding: 28rpx 36rpx;
-}
-
-.rate-row {
+/* ===== RATE LIST (竖排) ===== */
+.rate-list {
display: flex;
- align-items: center;
- padding: 8rpx 0;
+ flex-direction: column;
+ gap: 12rpx;
+ margin-bottom: 28rpx;
}
-.rate-dot {
- width: 14rpx;
- height: 14rpx;
- border-radius: 50%;
- margin-right: 16rpx;
- flex-shrink: 0;
-}
-
-.from-dot {
- background: #64748B;
-}
-
-.to-dot {
- background: #4F46E5;
+.rate-item {
+ padding: 24rpx 32rpx;
+ text-align: center;
}
.rate-text {
font-size: 26rpx;
color: #64748B;
- font-weight: 500;
+ font-weight: 600;
+ letter-spacing: 1rpx;
}
-/* ===== 错误提示 ===== */
+/* ===== ERROR ===== */
.error-card {
- display: flex;
- align-items: center;
- padding: 28rpx 36rpx;
- background: #FEF2F2;
-}
-
-.error-icon {
- font-size: 32rpx;
- margin-right: 16rpx;
+ padding: 28rpx 32rpx;
+ background: rgba(239, 68, 68, 0.08);
+ border: 2rpx solid rgba(239, 68, 68, 0.15);
+ text-align: center;
}
.error-text {
font-size: 26rpx;
- color: #DC2626;
+ color: #FCA5A5;
}
-/* ===== 汇率总览入口 ===== */
-.overview-entry {
+/* ===== OVERVIEW ENTRY ===== */
+.overview-btn {
+ margin-top: 8rpx;
+ margin-bottom: 48rpx;
+}
+
+.overview-inner {
display: flex;
align-items: center;
- justify-content: space-between;
- padding: 36rpx;
-}
-
-.overview-left {
- display: flex;
- align-items: center;
-}
-
-.overview-icon {
- font-size: 36rpx;
- margin-right: 16rpx;
+ justify-content: center;
+ gap: 12rpx;
+ padding: 34rpx;
+ border-radius: 20rpx;
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.08) 0%, rgba(99, 102, 241, 0.06) 100%);
+ border: 2rpx solid rgba(99, 102, 241, 0.15);
}
.overview-label {
font-size: 30rpx;
- font-weight: 500;
- color: #334155;
+ font-weight: 600;
+ color: #93C5FD;
+ letter-spacing: 2rpx;
}
.overview-arrow {
- font-size: 40rpx;
- color: #CBD5E1;
- font-weight: 300;
+ font-size: 30rpx;
+ color: #93C5FD;
}
diff --git a/miniprogram/pages/overview/overview.js b/miniprogram/pages/overview/overview.js
index eed7de0..7354488 100644
--- a/miniprogram/pages/overview/overview.js
+++ b/miniprogram/pages/overview/overview.js
@@ -6,13 +6,14 @@ const pickerData = getPickerData();
Page({
data: {
pickerData,
- baseIndex: 0, // CNY
+ baseIndex: 0,
amount: '100',
list: [],
updatedAt: '',
loading: true,
error: '',
rates: null,
+ showPicker: false,
},
onLoad() {
@@ -30,17 +31,10 @@ Page({
try {
const baseCode = CURRENCIES[this.data.baseIndex].code;
const { rates, updatedAt } = await getRates(baseCode);
- this.setData({
- rates,
- updatedAt,
- loading: false,
- });
+ this.setData({ rates, updatedAt, loading: false });
this.buildList();
} catch (e) {
- this.setData({
- loading: false,
- error: '汇率获取失败,请检查网络后下拉刷新',
- });
+ this.setData({ loading: false, error: '汇率获取失败,请下拉刷新重试' });
}
},
@@ -72,11 +66,19 @@ Page({
this.setData({ list });
},
- handleBaseChange(e) {
- this.setData({ baseIndex: Number(e.detail.value) });
+ openBasePicker() {
+ this.setData({ showPicker: true });
+ },
+
+ handlePickerSelect(e) {
+ this.setData({ baseIndex: e.detail.value, showPicker: false });
this.loadRates();
},
+ handlePickerClose() {
+ this.setData({ showPicker: false });
+ },
+
handleAmountInput(e) {
this.setData({ amount: e.detail.value });
this.buildList();
diff --git a/miniprogram/pages/overview/overview.json b/miniprogram/pages/overview/overview.json
index 4100ccf..65abfd9 100644
--- a/miniprogram/pages/overview/overview.json
+++ b/miniprogram/pages/overview/overview.json
@@ -1,5 +1,7 @@
{
- "navigationBarTitleText": "汇率总览",
+ "navigationBarTitleText": "",
"enablePullDownRefresh": true,
- "usingComponents": {}
+ "usingComponents": {
+ "currency-picker": "/components/currency-picker/currency-picker"
+ }
}
diff --git a/miniprogram/pages/overview/overview.wxml b/miniprogram/pages/overview/overview.wxml
index 1c6c274..0600324 100644
--- a/miniprogram/pages/overview/overview.wxml
+++ b/miniprogram/pages/overview/overview.wxml
@@ -1,64 +1,73 @@
-
-