diff --git a/app.json b/app.json
index 2351f27..2aaa0f5 100644
--- a/app.json
+++ b/app.json
@@ -19,7 +19,8 @@
"pages/profile/favorites/index",
"pages/profile/posts/index",
"pages/profile/about/index",
- "pages/profile/exchange/index"
+ "pages/profile/exchange/index",
+ "pages/profile/exchange/orders/index"
],
"window": {
"backgroundTextStyle": "light",
diff --git a/pages/profile/exchange/index.js b/pages/profile/exchange/index.js
index 560d44d..5427a03 100644
--- a/pages/profile/exchange/index.js
+++ b/pages/profile/exchange/index.js
@@ -1 +1,196 @@
-Page({});
+import request from '../../../utils/request';
+
+Page({
+ data: {
+ items: [],
+ currentSunlight: 0,
+ isLoading: true,
+ hasMore: true,
+ current: 1,
+ pageSize: 10,
+ activeType: 'PHYSICAL',
+ // Redeem popup
+ showRedeemPopup: false,
+ selectedItem: null,
+ redeemForm: {
+ recipientName: '',
+ phone: '',
+ address: ''
+ }
+ },
+
+ onLoad() {
+ this.fetchProfile();
+ this.fetchItems();
+ },
+
+ onShow() {
+ this.fetchProfile();
+ },
+
+ async fetchProfile() {
+ try {
+ const res = await request.get('/profile/detail');
+ if (res) {
+ this.setData({ currentSunlight: res.currentSunlight || 0 });
+ }
+ } catch (e) {
+ // Silent
+ }
+ },
+
+ async fetchItems(append = false) {
+ if (!append) {
+ this.setData({ isLoading: true, current: 1, items: [] });
+ }
+ try {
+ const res = await request.get('/exchange/list', {
+ current: this.data.current,
+ pageSize: this.data.pageSize,
+ type: this.data.activeType
+ });
+ const rawList = (res && res.list) ? res.list : [];
+ const total = (res && res.total) ? res.total : 0;
+
+ const now = Date.now();
+ const list = rawList.map(item => {
+ const hasStart = !!item.startTime;
+ const hasEnd = !!item.endTime;
+ const startTs = hasStart ? new Date(item.startTime).getTime() : 0;
+ const endTs = hasEnd ? new Date(item.endTime).getTime() : 0;
+
+ const notStarted = hasStart && now < startTs;
+ const hasEnded = hasEnd && now > endTs;
+ const isActive = !notStarted && !hasEnded;
+
+ let timeLabel = '';
+ if (hasStart && hasEnd) {
+ timeLabel = this.formatDate(item.startTime) + ' ~ ' + this.formatDate(item.endTime);
+ } else if (hasStart) {
+ timeLabel = this.formatDate(item.startTime) + ' 起';
+ } else if (hasEnd) {
+ timeLabel = '截止 ' + this.formatDate(item.endTime);
+ }
+
+ return {
+ ...item,
+ hasTimeLimit: hasStart || hasEnd,
+ timeLabel,
+ notStarted,
+ hasEnded,
+ isActive
+ };
+ });
+
+ this.setData({
+ items: append ? [...this.data.items, ...list] : list,
+ hasMore: this.data.items.length + list.length < total
+ });
+ } catch (e) {
+ console.error('Fetch exchange items failed', e);
+ } finally {
+ this.setData({ isLoading: false });
+ wx.stopPullDownRefresh();
+ }
+ },
+
+ onReachBottom() {
+ if (!this.data.hasMore || this.data.isLoading) return;
+ this.setData({ current: this.data.current + 1 });
+ this.fetchItems(true);
+ },
+
+ onPullDownRefresh() {
+ this.fetchProfile();
+ this.fetchItems();
+ },
+
+ switchType(e) {
+ const key = e.currentTarget.dataset.key;
+ if (key === this.data.activeType) return;
+ this.setData({ activeType: key });
+ this.fetchItems();
+ },
+
+ // Redeem Flow
+ onItemTap(e) {
+ const item = e.currentTarget.dataset.item;
+ if (item.notStarted) {
+ wx.showToast({ title: '活动尚未开始', icon: 'none' });
+ return;
+ }
+ if (item.hasEnded) {
+ wx.showToast({ title: '活动已结束', icon: 'none' });
+ return;
+ }
+ if (item.stock === 0) {
+ wx.showToast({ title: '已兑完', icon: 'none' });
+ return;
+ }
+ this.setData({
+ selectedItem: item,
+ showRedeemPopup: true,
+ redeemForm: { recipientName: '', phone: '', address: '' }
+ });
+ },
+
+ onPopupClose() {
+ this.setData({ showRedeemPopup: false });
+ },
+
+ onFormInput(e) {
+ const field = e.currentTarget.dataset.field;
+ this.setData({ [`redeemForm.${field}`]: e.detail.value });
+ },
+
+ async confirmRedeem() {
+ const item = this.data.selectedItem;
+ if (!item) return;
+
+ // Check sunlight
+ if (this.data.currentSunlight < item.costSunlight) {
+ wx.showToast({ title: '阳光值不足', icon: 'none' });
+ return;
+ }
+
+ // Physical items require address
+ if (item.type === 'PHYSICAL') {
+ const { recipientName, phone, address } = this.data.redeemForm;
+ if (!recipientName || !phone || !address) {
+ wx.showToast({ title: '请填写完整收货信息', icon: 'none' });
+ return;
+ }
+ }
+
+ wx.showLoading({ title: '兑换中...', mask: true });
+ try {
+ await request.post('/exchange/redeem', {
+ itemId: item.id,
+ quantity: 1,
+ ...this.data.redeemForm
+ });
+ wx.hideLoading();
+ wx.showToast({ title: '兑换成功!', icon: 'success' });
+ this.setData({ showRedeemPopup: false });
+ // Refresh data
+ this.fetchProfile();
+ this.fetchItems();
+ } catch (e) {
+ wx.hideLoading();
+ wx.showToast({ title: e.message || '兑换失败', icon: 'none' });
+ }
+ },
+
+ goToOrders() {
+ wx.navigateTo({ url: '/pages/profile/exchange/orders/index' });
+ },
+
+ formatDate(dateStr) {
+ if (!dateStr) return '';
+ const d = new Date(dateStr);
+ const m = (d.getMonth() + 1).toString().padStart(2, '0');
+ const day = d.getDate().toString().padStart(2, '0');
+ return m + '.' + day;
+ }
+});
+
diff --git a/pages/profile/exchange/index.json b/pages/profile/exchange/index.json
index b250e0f..a346a68 100644
--- a/pages/profile/exchange/index.json
+++ b/pages/profile/exchange/index.json
@@ -1,6 +1,11 @@
{
"navigationBarTitleText": "兑换中心",
+ "disableScroll": true,
"usingComponents": {
- "t-empty": "tdesign-miniprogram/empty/empty"
+ "t-empty": "tdesign-miniprogram/empty/empty",
+ "t-icon": "tdesign-miniprogram/icon/icon",
+ "t-loading": "tdesign-miniprogram/loading/loading",
+ "t-tag": "tdesign-miniprogram/tag/tag",
+ "t-popup": "tdesign-miniprogram/popup/popup"
}
}
\ No newline at end of file
diff --git a/pages/profile/exchange/index.wxml b/pages/profile/exchange/index.wxml
index 44bef42..2a41fa0 100644
--- a/pages/profile/exchange/index.wxml
+++ b/pages/profile/exchange/index.wxml
@@ -1,3 +1,141 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 仅剩 {{item.stock}}
+
+
+
+ 已兑完
+
+
+ 未开始
+
+
+ 已结束
+
+
+
+ {{item.name}}
+
+ ☀️
+ {{item.costSunlight}}
+
+
+
+ {{item.timeLabel}}
+
+
+
+
+
+
+
+
+ 🎁
+ 暂无可兑换商品
+ 新的好礼正在路上,敬请期待
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/profile/exchange/index.wxss b/pages/profile/exchange/index.wxss
index b1ffcd0..32878ad 100644
--- a/pages/profile/exchange/index.wxss
+++ b/pages/profile/exchange/index.wxss
@@ -1,9 +1,447 @@
page {
- background: #F4F6F0;
+ background: #F4F6F0;
}
+
.exchange-page {
- display: flex;
- align-items: center;
- justify-content: center;
- height: 100vh;
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.page-scroll {
+ flex: 1;
+ height: 0;
+}
+
+/* ========== Balance Header ========== */
+.balance-header {
+ background: linear-gradient(180deg, #E8F5E9 0%, #F4F6F0 100%);
+ padding: 32rpx 32rpx 24rpx;
+ flex-shrink: 0;
+}
+
+.balance-card {
+ background: #fff;
+ border-radius: 24rpx;
+ padding: 32rpx 36rpx;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
+}
+
+.balance-label {
+ font-size: 22rpx;
+ color: #9CA3AF;
+ display: block;
+ margin-bottom: 8rpx;
+ font-weight: 500;
+}
+
+.balance-value-row {
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+}
+
+.balance-emoji {
+ font-size: 36rpx;
+}
+
+.balance-value {
+ font-size: 48rpx;
+ font-weight: 800;
+ color: #558B2F;
+ line-height: 1;
+}
+
+.balance-right {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 6rpx;
+ padding: 16rpx 24rpx;
+ border-radius: 20rpx;
+ background: #F1F8E9;
+}
+
+.orders-text {
+ font-size: 20rpx;
+ color: #558B2F;
+ font-weight: 600;
+}
+
+/* ========== Type Tabs ========== */
+.type-tabs {
+ display: flex;
+ white-space: nowrap;
+ padding: 20rpx 32rpx;
+ gap: 16rpx;
+ flex-shrink: 0;
+}
+
+.type-tab {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 10rpx 28rpx;
+ background: #fff;
+ border: 2rpx solid #E5E7EB;
+ border-radius: 40rpx;
+ font-size: 26rpx;
+ color: #6B7280;
+ font-weight: 600;
+ flex-shrink: 0;
+ margin-right: 0;
+ transition: all 0.2s;
+}
+
+.type-tab.active {
+ background: #333;
+ color: #fff;
+ border-color: #333;
+}
+
+/* ========== Items Grid ========== */
+.items-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ padding: 0 32rpx;
+ gap: 20rpx;
+}
+
+.item-card {
+ background: #fff;
+ border-radius: 20rpx;
+ overflow: hidden;
+ box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.03);
+ transition: transform 0.15s;
+}
+
+.item-card:active {
+ transform: scale(0.97);
+}
+
+.item-image-wrap {
+ position: relative;
+ width: 100%;
+ aspect-ratio: 1;
+ background: #F8FAF5;
+ overflow: hidden;
+}
+
+.item-img {
+ width: 100%;
+ height: 100%;
+ display: block;
+}
+
+.item-img-placeholder {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: linear-gradient(135deg, #F1F8E9, #E8F5E9);
+}
+
+.stock-badge {
+ position: absolute;
+ top: 12rpx;
+ right: 12rpx;
+ background: rgba(239, 83, 80, 0.85);
+ color: #fff;
+ font-size: 20rpx;
+ font-weight: 700;
+ padding: 4rpx 14rpx;
+ border-radius: 14rpx;
+}
+
+.sold-out-mask {
+ position: absolute;
+ top: 0; left: 0; right: 0; bottom: 0;
+ background: rgba(0,0,0,0.45);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+ font-size: 30rpx;
+ font-weight: 800;
+ letter-spacing: 4rpx;
+}
+
+.sold-out-mask.not-started {
+ background: rgba(33, 150, 243, 0.5);
+}
+
+.sold-out-mask.ended {
+ background: rgba(0, 0, 0, 0.5);
+}
+
+.item-card.inactive {
+ opacity: 0.7;
+}
+
+.item-info {
+ padding: 16rpx 20rpx 20rpx;
+}
+
+.item-name {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #1F2937;
+ display: block;
+ margin-bottom: 10rpx;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.item-price-row {
+ display: flex;
+ align-items: center;
+ gap: 6rpx;
+}
+
+.price-sun {
+ font-size: 24rpx;
+}
+
+.price-val {
+ font-size: 30rpx;
+ font-weight: 800;
+ color: #E65100;
+}
+
+.item-time {
+ display: flex;
+ align-items: center;
+ gap: 6rpx;
+ margin-top: 8rpx;
+ font-size: 22rpx;
+ color: #9CA3AF;
+ font-weight: 500;
+}
+
+/* ========== Empty & Footer States ========== */
+.empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 120rpx 40rpx 80rpx;
+}
+
+.empty-icon {
+ font-size: 100rpx;
+ margin-bottom: 24rpx;
+}
+
+.empty-title {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #374151;
+ margin-bottom: 12rpx;
+}
+
+.empty-desc {
+ font-size: 24rpx;
+ color: #9CA3AF;
+ font-weight: 500;
+}
+
+.state-footer {
+ padding: 40rpx;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.no-more {
+ font-size: 24rpx;
+ color: #D1D5DB;
+ font-weight: 500;
+}
+
+/* ========== Redeem Popup ========== */
+.redeem-popup {
+ background: #fff;
+ border-radius: 32rpx 32rpx 0 0;
+ padding: 36rpx;
+ padding-bottom: calc(36rpx + env(safe-area-inset-bottom));
+}
+
+.popup-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 28rpx;
+}
+
+.popup-title {
+ font-size: 34rpx;
+ font-weight: 700;
+ color: #1F2937;
+}
+
+.popup-close {
+ padding: 8rpx;
+}
+
+/* Item Preview in Popup */
+.redeem-item-preview {
+ display: flex;
+ gap: 24rpx;
+ padding: 24rpx;
+ background: #F8FAF5;
+ border-radius: 20rpx;
+ margin-bottom: 28rpx;
+}
+
+.preview-img-wrap {
+ width: 140rpx;
+ height: 140rpx;
+ border-radius: 16rpx;
+ overflow: hidden;
+ flex-shrink: 0;
+ background: #E8F5E9;
+}
+
+.preview-img {
+ width: 100%;
+ height: 100%;
+}
+
+.preview-img-placeholder {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.preview-info {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 8rpx;
+}
+
+.preview-name {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #1F2937;
+}
+
+.preview-desc {
+ font-size: 24rpx;
+ color: #9CA3AF;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ line-height: 1.5;
+}
+
+.preview-cost {
+ display: flex;
+ align-items: center;
+ gap: 6rpx;
+ margin-top: 4rpx;
+}
+
+.cost-sun { font-size: 24rpx; }
+.cost-val { font-size: 32rpx; font-weight: 800; color: #E65100; }
+.cost-unit { font-size: 22rpx; color: #9CA3AF; margin-left: 2rpx; }
+
+/* Address Form */
+.address-form {
+ margin-bottom: 24rpx;
+}
+
+.form-title {
+ font-size: 28rpx;
+ font-weight: 700;
+ color: #374151;
+ margin-bottom: 16rpx;
+}
+
+.form-item {
+ display: flex;
+ align-items: center;
+ background: #F9FAFB;
+ border: 2rpx solid #F3F4F6;
+ border-radius: 16rpx;
+ padding: 20rpx 24rpx;
+ margin-bottom: 12rpx;
+ gap: 16rpx;
+}
+
+.form-label {
+ font-size: 26rpx;
+ color: #6B7280;
+ font-weight: 600;
+ flex-shrink: 0;
+ width: 60rpx;
+}
+
+.form-item input {
+ flex: 1;
+ font-size: 26rpx;
+ color: #1F2937;
+}
+
+/* Balance Check */
+.balance-check {
+ padding: 20rpx 24rpx;
+ background: #F1F8E9;
+ border-radius: 16rpx;
+ margin-bottom: 20rpx;
+ font-size: 26rpx;
+ color: #558B2F;
+ font-weight: 600;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.balance-check.insufficient {
+ background: #FFF3E0;
+ color: #E65100;
+}
+
+.insufficient-tip {
+ color: #EF5350;
+ font-weight: 700;
+}
+
+/* Redeem Button */
+.redeem-btn {
+ width: 100%;
+ height: 92rpx;
+ background: linear-gradient(135deg, #558B2F, #689F38);
+ border-radius: 46rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+ font-size: 30rpx;
+ font-weight: 700;
+ transition: all 0.2s;
+ box-shadow: 0 8rpx 24rpx rgba(85, 139, 47, 0.25);
+}
+
+.redeem-btn:active {
+ transform: scale(0.97);
+ opacity: 0.9;
+}
+
+.redeem-btn.disabled {
+ background: #E5E7EB;
+ color: #9CA3AF;
+ pointer-events: none;
}
diff --git a/pages/profile/exchange/orders/index.js b/pages/profile/exchange/orders/index.js
new file mode 100644
index 0000000..c8ace9b
--- /dev/null
+++ b/pages/profile/exchange/orders/index.js
@@ -0,0 +1,80 @@
+import request from '../../../../utils/request';
+
+const STATUS_MAP = {
+ 1: { text: '待处理', theme: 'warning' },
+ 2: { text: '处理中', theme: 'primary' },
+ 3: { text: '已发货', theme: 'primary' },
+ 4: { text: '已完成', theme: 'success' },
+ 5: { text: '已取消', theme: 'default' }
+};
+
+Page({
+ data: {
+ orders: [],
+ isLoading: true,
+ hasMore: true,
+ current: 1,
+ pageSize: 10,
+ activeStatus: 0,
+ statusTabs: [
+ { key: 0, label: '全部' },
+ { key: 1, label: '待处理' },
+ { key: 4, label: '已完成' },
+ { key: 5, label: '已取消' }
+ ]
+ },
+
+ onLoad() {
+ this.fetchOrders();
+ },
+
+ onShow() {
+ this.fetchOrders();
+ },
+
+ async fetchOrders(append = false) {
+ if (!append) {
+ this.setData({ isLoading: true, current: 1, orders: [] });
+ }
+ try {
+ const params = {
+ current: this.data.current,
+ pageSize: this.data.pageSize
+ };
+ if (this.data.activeStatus) {
+ params.status = this.data.activeStatus;
+ }
+ const res = await request.get('/exchange/orders', params);
+ let list = (res && res.list) ? res.list : [];
+ const total = (res && res.total) ? res.total : 0;
+
+ // Enrich with status display info
+ list = list.map(order => ({
+ ...order,
+ statusInfo: STATUS_MAP[order.status] || { text: '未知', theme: 'default' }
+ }));
+
+ this.setData({
+ orders: append ? [...this.data.orders, ...list] : list,
+ hasMore: this.data.orders.length + list.length < total
+ });
+ } catch (e) {
+ console.error('Fetch orders failed', e);
+ } finally {
+ this.setData({ isLoading: false });
+ }
+ },
+
+ switchStatus(e) {
+ const key = e.currentTarget.dataset.key;
+ if (key === this.data.activeStatus) return;
+ this.setData({ activeStatus: key });
+ this.fetchOrders();
+ },
+
+ onReachBottom() {
+ if (!this.data.hasMore || this.data.isLoading) return;
+ this.setData({ current: this.data.current + 1 });
+ this.fetchOrders(true);
+ }
+});
diff --git a/pages/profile/exchange/orders/index.json b/pages/profile/exchange/orders/index.json
new file mode 100644
index 0000000..c036be4
--- /dev/null
+++ b/pages/profile/exchange/orders/index.json
@@ -0,0 +1,10 @@
+{
+ "navigationBarTitleText": "兑换记录",
+ "disableScroll": true,
+ "usingComponents": {
+ "t-empty": "tdesign-miniprogram/empty/empty",
+ "t-icon": "tdesign-miniprogram/icon/icon",
+ "t-loading": "tdesign-miniprogram/loading/loading",
+ "t-tag": "tdesign-miniprogram/tag/tag"
+ }
+}
\ No newline at end of file
diff --git a/pages/profile/exchange/orders/index.wxml b/pages/profile/exchange/orders/index.wxml
new file mode 100644
index 0000000..07dda79
--- /dev/null
+++ b/pages/profile/exchange/orders/index.wxml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+ {{item.label}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.itemName}}
+ {{item.itemType === 'PHYSICAL' ? '实物' : (item.itemType === 'VIRTUAL' ? '虚拟' : '优惠券')}}
+
+ ☀️
+ -{{item.costSunlight}}
+ x{{item.quantity}}
+
+
+
+
+
+
+
+ 快递单号: {{item.trackingNo}}
+
+
+
+
+
+
+
+ 📦
+ 暂无兑换记录
+ 去兑换中心挑选心仪好礼吧
+
+
+
+
+
+
+
+
diff --git a/pages/profile/exchange/orders/index.wxss b/pages/profile/exchange/orders/index.wxss
new file mode 100644
index 0000000..37b8023
--- /dev/null
+++ b/pages/profile/exchange/orders/index.wxss
@@ -0,0 +1,224 @@
+page {
+ background: #F4F6F0;
+}
+
+.orders-page {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.page-scroll {
+ flex: 1;
+ height: 0;
+}
+
+/* ========== Status Tabs ========== */
+.status-tabs-wrap {
+ flex-shrink: 0;
+ background: #F4F6F0;
+ padding: 20rpx 0 12rpx;
+}
+
+.status-tabs {
+ display: flex;
+ white-space: nowrap;
+ padding-left: 32rpx;
+ height: 88rpx;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+.status-tab {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0 28rpx;
+ height: 72rpx;
+ background: #fff;
+ border-radius: 36rpx;
+ margin-right: 16rpx;
+ font-size: 26rpx;
+ color: #546E7A;
+ font-weight: 600;
+ box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04);
+ transition: all 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);
+ flex-shrink: 0;
+ border: 2rpx solid transparent;
+}
+
+.status-tab:active {
+ transform: scale(0.95);
+}
+
+.status-tab.active {
+ background: #558B2F;
+ color: #fff;
+ font-weight: 700;
+ box-shadow: 0 8rpx 20rpx rgba(85, 139, 47, 0.3);
+ border-color: #558B2F;
+}
+
+/* ========== Orders List ========== */
+.orders-list {
+ padding: 12rpx 32rpx;
+}
+
+.order-card {
+ background: #fff;
+ border-radius: 20rpx;
+ padding: 28rpx;
+ margin-bottom: 16rpx;
+ box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.03);
+}
+
+.order-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20rpx;
+ padding-bottom: 16rpx;
+ border-bottom: 1rpx solid #F3F4F6;
+}
+
+.order-time {
+ font-size: 24rpx;
+ color: #9CA3AF;
+ font-weight: 500;
+}
+
+.order-body {
+ display: flex;
+ gap: 20rpx;
+}
+
+.order-img-wrap {
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 16rpx;
+ overflow: hidden;
+ flex-shrink: 0;
+ background: #F8FAF5;
+}
+
+.order-img {
+ width: 100%;
+ height: 100%;
+}
+
+.order-img-placeholder {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: linear-gradient(135deg, #F1F8E9, #E8F5E9);
+}
+
+.order-info {
+ flex: 1;
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 8rpx;
+}
+
+.order-item-name {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #1F2937;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.order-type-tag {
+ display: inline-block;
+ width: fit-content;
+ font-size: 20rpx;
+ color: #6B7280;
+ background: #F3F4F6;
+ padding: 2rpx 14rpx;
+ border-radius: 10rpx;
+ font-weight: 500;
+}
+
+.order-cost-row {
+ display: flex;
+ align-items: center;
+ gap: 6rpx;
+}
+
+.order-cost-sun {
+ font-size: 22rpx;
+}
+
+.order-cost-val {
+ font-size: 28rpx;
+ font-weight: 800;
+ color: #E65100;
+}
+
+.order-qty {
+ font-size: 22rpx;
+ color: #9CA3AF;
+ margin-left: 4rpx;
+}
+
+/* Shipping */
+.order-shipping {
+ margin-top: 16rpx;
+ padding-top: 16rpx;
+ border-top: 1rpx solid #F3F4F6;
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+}
+
+.tracking-text {
+ font-size: 24rpx;
+ color: #558B2F;
+ font-weight: 600;
+}
+
+/* ========== Empty & Footer States ========== */
+.empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 120rpx 40rpx 80rpx;
+}
+
+.empty-icon {
+ font-size: 100rpx;
+ margin-bottom: 24rpx;
+}
+
+.empty-title {
+ font-size: 30rpx;
+ font-weight: 700;
+ color: #374151;
+ margin-bottom: 12rpx;
+}
+
+.empty-desc {
+ font-size: 24rpx;
+ color: #9CA3AF;
+ font-weight: 500;
+}
+
+.state-footer {
+ padding: 40rpx;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.no-more {
+ font-size: 24rpx;
+ color: #D1D5DB;
+ font-weight: 500;
+}
diff --git a/pages/profile/favorites/index.json b/pages/profile/favorites/index.json
index 35afdfc..e8652c1 100644
--- a/pages/profile/favorites/index.json
+++ b/pages/profile/favorites/index.json
@@ -1,5 +1,6 @@
{
"navigationBarTitleText": "我的收藏",
+ "disableScroll": true,
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-image": "tdesign-miniprogram/image/image",
diff --git a/pages/profile/index.wxml b/pages/profile/index.wxml
index 15020e5..5d97c12 100644
--- a/pages/profile/index.wxml
+++ b/pages/profile/index.wxml
@@ -46,7 +46,6 @@