修改小程序bug

This commit is contained in:
2026-03-24 00:21:19 +08:00
parent 9efd2bc3a3
commit ca8794ea3a
28 changed files with 3169 additions and 986 deletions

View File

@@ -41,7 +41,38 @@
</view>
</view>
<view class="content-area">
<!-- 骨架屏:数据首次加载中 -->
<view v-if="!isPageReady" class="ske-body">
<view class="ske-card-wrap">
<view class="ske-row ske-mb16"><view class="ske-bar ske-w30 ske-h28"></view></view>
<view class="ske-grid-row">
<view v-for="n in 4" :key="n" class="ske-cell25">
<view class="ske-icon-sq"></view>
<view class="ske-bar ske-w40 ske-mt8 ske-h32"></view>
<view class="ske-bar ske-w60 ske-mt6 ske-h20"></view>
</view>
</view>
</view>
<view class="ske-card-wrap">
<view class="ske-row ske-mb16"><view class="ske-bar ske-w30 ske-h28"></view></view>
<view class="ske-grid-row">
<view v-for="n in 8" :key="n" class="ske-cell25">
<view class="ske-icon-sq"></view>
<view class="ske-bar ske-w60 ske-mt8 ske-h20"></view>
</view>
</view>
</view>
<view class="ske-card-wrap">
<view v-for="n in 3" :key="n" class="ske-order-row">
<view class="ske-order-img"></view>
<view class="ske-order-info">
<view class="ske-bar ske-w70 ske-h26 ske-mb8"></view>
<view class="ske-bar ske-w40 ske-h22"></view>
</view>
</view>
</view>
</view>
<view v-if="isPageReady" class="content-area">
<!-- 今日数据卡片 -->
<view class="stats-card">
<view class="stats-header">
@@ -332,7 +363,8 @@
} as PendingCountsType,
recentOrders: [] as OrderType[],
unreadCount: 0,
refreshing: false
refreshing: false,
isPageReady: false
}
},
@@ -348,6 +380,32 @@
},
onShow() {
// 先从缓存恢复数据,消除白屏
try {
const raw = uni.getStorageSync('merchant_idx_cache')
if (raw != null && raw !== '') {
const c = JSON.parse(raw as string) as UTSJSONObject
this.shopInfo.shop_name = c.getString('shop_name') ?? null
this.shopInfo.shop_logo = c.getString('shop_logo') ?? null
this.shopInfo.rating_avg = c.getNumber('rating_avg') ?? null
this.shopInfo.total_sales = c.getNumber('total_sales') ?? null
this.todayStats = {
orders: c.getNumber('c_orders'),
sales: c.getNumber('c_sales'),
visitors: c.getNumber('c_visitors'),
conversion: c.getNumber('c_conversion')
}
this.pendingCounts = {
pending_shipment: c.getNumber('c_pship') ?? 0,
refund_requests: c.getNumber('c_refund') ?? 0,
low_stock: c.getNumber('c_lstock') ?? 0,
pending_reviews: c.getNumber('c_reviews') ?? 0
}
this.unreadCount = c.getNumber('c_unread') ?? 0
this.isPageReady = true
}
} catch(e) {}
// 后台刷新数据
if (this.merchantId) {
this.loadAllData()
this.startRealtimeSubscription()
@@ -424,6 +482,25 @@
await this.loadPendingCounts()
await this.loadRecentOrders()
await this.loadUnreadCount()
this.isPageReady = true
// 保存缓存
try {
uni.setStorageSync('merchant_idx_cache', JSON.stringify({
shop_name: this.shopInfo.shop_name ?? '',
shop_logo: this.shopInfo.shop_logo ?? '',
rating_avg: this.shopInfo.rating_avg ?? 5.0,
total_sales: this.shopInfo.total_sales ?? 0,
c_orders: this.todayStats.orders ?? 0,
c_sales: this.todayStats.sales ?? 0,
c_visitors: this.todayStats.visitors ?? 0,
c_conversion: this.todayStats.conversion ?? 0,
c_pship: this.pendingCounts.pending_shipment ?? 0,
c_refund: this.pendingCounts.refund_requests ?? 0,
c_lstock: this.pendingCounts.low_stock ?? 0,
c_reviews: this.pendingCounts.pending_reviews ?? 0,
c_unread: this.unreadCount
}))
} catch(e) {}
},
formatNumber(value: number | null): string {
@@ -900,6 +977,22 @@
.mp-tab-navbar { height: calc(88rpx + var(--status-bar-height)); padding-top: var(--status-bar-height); background-color: #ffffff; display: flex; flex-direction: row; align-items: center; justify-content: center; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #f0f0f0; }
.mp-tab-title { font-size: 34rpx; font-weight: bold; color: #333333; }
.safe-bottom { height: 160rpx; }
/* ===== 骨架屏 ===== */
@keyframes ske-pulse { 0% { opacity: 1; } 50% { opacity: 0.45; } 100% { opacity: 1; } }
.ske-body { padding: 24rpx; }
.ske-card-wrap { background: #fff; border-radius: 24rpx; padding: 28rpx; margin-bottom: 24rpx; }
.ske-bar { border-radius: 8rpx; background-color: #e8e8e8; animation: ske-pulse 1.4s ease-in-out infinite; }
.ske-icon-sq { width: 64rpx; height: 64rpx; border-radius: 16rpx; background-color: #e8e8e8; margin-bottom: 12rpx; animation: ske-pulse 1.4s ease-in-out infinite; }
.ske-grid-row { display: flex; flex-direction: row; flex-wrap: wrap; }
.ske-cell25 { width: 25%; display: flex; flex-direction: column; align-items: center; padding-top: 16rpx; padding-bottom: 16rpx; }
.ske-row { display: flex; flex-direction: row; }
.ske-order-row { display: flex; flex-direction: row; align-items: center; margin-bottom: 20rpx; }
.ske-order-img { width: 100rpx; height: 100rpx; border-radius: 12rpx; background-color: #e8e8e8; margin-right: 16rpx; flex-shrink: 0; animation: ske-pulse 1.4s ease-in-out infinite; }
.ske-order-info { flex: 1; }
.ske-w30 { width: 30%; } .ske-w40 { width: 40%; } .ske-w60 { width: 60%; } .ske-w70 { width: 70%; }
.ske-h20 { height: 20rpx; } .ske-h22 { height: 22rpx; } .ske-h26 { height: 26rpx; } .ske-h28 { height: 28rpx; } .ske-h32 { height: 32rpx; }
.ske-mt6 { margin-top: 6rpx; } .ske-mt8 { margin-top: 8rpx; } .ske-mb8 { margin-bottom: 8rpx; } .ske-mb16 { margin-bottom: 16rpx; }
</style>

View File

@@ -13,9 +13,17 @@
</view>
<scroll-view class="messages-list" direction="vertical" :refresher-enabled="true" :refresher-triggered="refreshing" @refresherrefresh="onRefresh">
<view v-if="loading && conversations.length === 0" class="loading-container">
<text class="loading-icon">⏳</text>
<text class="loading-text">加载中...</text>
<view v-if="loading && conversations.length === 0" class="ske-msg-list">
<view v-for="n in 5" :key="n" class="ske-conv-item">
<view class="ske-avatar-circle"></view>
<view class="ske-conv-info">
<view class="ske-conv-top">
<view class="ske-bar ske-w50 ske-h28"></view>
<view class="ske-bar ske-w20 ske-h22"></view>
</view>
<view class="ske-bar ske-w75 ske-h22 ske-mt10"></view>
</view>
</view>
</view>
<view v-else-if="conversations.length === 0" class="empty-container">
@@ -87,7 +95,8 @@
conversations: [] as ConversationType[],
loading: false,
refreshing: false,
merchantId: ''
merchantId: '',
isPageReady: false
}
},
@@ -96,6 +105,17 @@
},
onShow() {
// 先从缓存恢复会话列表,消除白屏
try {
const raw = uni.getStorageSync('merchant_msg_cache')
if (raw != null && raw !== '') {
const arr = JSON.parse(raw as string) as ConversationType[]
if (arr != null && (arr as any[]).length > 0) {
this.conversations = arr
this.isPageReady = true
}
}
} catch(e) {}
this.loadMessages()
},
@@ -173,12 +193,17 @@
}
this.conversations = Array.from(sessionMap.values()).sort((a, b) => b.unread - a.unread)
// 保存缓存
try {
uni.setStorageSync('merchant_msg_cache', JSON.stringify(this.conversations))
} catch(e) {}
} catch (e) {
console.error('加载消息失败:', e)
} finally {
this.loading = false
this.refreshing = false
this.isPageReady = true
}
},
@@ -248,4 +273,15 @@
.conv-arrow { font-size: 40rpx; color: #ccc; margin-left: 10rpx; }
.safe-bottom { height: 160rpx; }
</style>
/* ===== 骨架屏 ===== */
@keyframes ske-pulse { 0% { opacity: 1; } 50% { opacity: 0.45; } 100% { opacity: 1; } }
.ske-msg-list { padding: 20rpx; }
.ske-conv-item { display: flex; flex-direction: row; align-items: center; padding-top: 24rpx; padding-bottom: 24rpx; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #f5f5f5; }
.ske-avatar-circle { width: 88rpx; height: 88rpx; border-radius: 44rpx; background-color: #e8e8e8; margin-right: 20rpx; flex-shrink: 0; animation: ske-pulse 1.4s ease-in-out infinite; }
.ske-conv-info { flex: 1; }
.ske-conv-top { display: flex; flex-direction: row; justify-content: space-between; align-items: center; margin-bottom: 10rpx; }
.ske-bar { border-radius: 8rpx; background-color: #e8e8e8; animation: ske-pulse 1.4s ease-in-out infinite; }
.ske-w20 { width: 20%; } .ske-w50 { width: 50%; } .ske-w75 { width: 75%; }
.ske-h22 { height: 22rpx; } .ske-h28 { height: 28rpx; } .ske-mt10 { margin-top: 10rpx; }
</style>

View File

@@ -2,9 +2,8 @@
<template>
<view class="orders-page">
<!-- #ifdef MP-WEIXIN -->
<!-- Tab 页无返回按鈕,展示顶部安全区 + 页面标题 -->
<view class="mp-tab-navbar">
<text class="mp-tab-title">订单管理</text>
<text class="mp-tab-title">订单</text>
</view>
<!-- #endif -->
<!-- 标签页切换 -->
@@ -38,14 +37,30 @@
<!-- 订单列表 -->
<scroll-view
class="orders-list"
scroll-y
direction="vertical"
:refresher-enabled="true"
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
@scrolltolower="loadMore"
>
<view v-if="loading && orders.length === 0" class="loading-container">
<text class="loading-text">加载中...</text>
<view v-if="loading && orders.length === 0" class="ske-orders-wrap">
<view v-for="n in 4" :key="n" class="ske-order-card">
<view class="ske-order-hd">
<view class="ske-bar ske-w50 ske-h26"></view>
<view class="ske-bar ske-w22 ske-h26"></view>
</view>
<view class="ske-order-product">
<view class="ske-product-img"></view>
<view class="ske-product-info">
<view class="ske-bar ske-w70 ske-h28 ske-mb10"></view>
<view class="ske-bar ske-w40 ske-h22"></view>
</view>
</view>
<view class="ske-order-ft">
<view class="ske-bar ske-w30 ske-h22"></view>
<view class="ske-bar ske-w25 ske-h30"></view>
</view>
</view>
</view>
<view v-else-if="orders.length === 0" class="empty-container">
@@ -134,6 +149,8 @@
<view v-if="!hasMore && orders.length > 0" class="no-more">
<text class="no-more-text">没有更多了</text>
</view>
<!-- 底部占位tabbar高度 + safeAreaInsets.bottom动态计算 -->
<view class="safe-bottom" :style="{ height: safeBottomHeight }"></view>
</scroll-view>
<!-- 发货弹窗 -->
@@ -257,7 +274,10 @@
{ name: '京东物流', code: 'JD' }
] as LogisticsType[],
selectedLogistics: null as LogisticsType | null,
trackingNumber: ''
trackingNumber: '',
isPageReady: false,
// 动态计算的底部安全却高度tabbar高度 + safeAreaInsets.bottom
safeBottomHeight: '160rpx' as string
}
},
@@ -273,6 +293,7 @@
this.currentTab = statusMap[type] ?? -2
}
this.initMerchantId()
this.initSafeArea()
},
onShow() {
@@ -288,6 +309,23 @@
},
methods: {
// 计算底部安全區: tabbar自身高度(~56px) + 底部制安全区高度
initSafeArea() {
// #ifdef MP-WEIXIN
try {
const info = wx.getWindowInfo()
const safeObj = info.safeArea
if (safeObj != null) {
const bottomInset = info.screenHeight - safeObj.bottom
// tabbar内容区域约60px + 底部安剨覆盖
this.safeBottomHeight = (60 + bottomInset) + 'px'
}
} catch(_e : any) {
this.safeBottomHeight = '160rpx'
}
// #endif
},
async initMerchantId() {
try {
const session = supa.getSession()
@@ -415,7 +453,6 @@
this.hasMore = rawData.length >= this.limit
} catch (e) {
console.error('获取订单异常:', e)
uni.showToast({ title: '加载失败,请检查网络连接', icon: 'none' })
} finally {
this.loading = false
this.refreshing = false
@@ -636,21 +673,42 @@
<style>
.orders-page {
background-color: #f5f5f5;
min-height: 100vh;
/* 使用严格高度而非 min-height确保 flex:1 的 scroll-view 正确被限制在视口内 */
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
}
.mp-tab-navbar { height: calc(88rpx + var(--status-bar-height)); padding-top: var(--status-bar-height); background-color: #ffffff; display: flex; flex-direction: row; align-items: center; justify-content: center; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #f0f0f0; }
.mp-tab-title { font-size: 34rpx; font-weight: bold; color: #333333; }
.mp-tab-navbar {
height: calc(88rpx + var(--status-bar-height));
padding-top: var(--status-bar-height);
background-color: #ffffff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #f0f0f0;
}
.mp-tab-title {
font-size: 34rpx;
font-weight: bold;
color: #333333;
}
.tabs-container {
background-color: #fff;
position: sticky;
top: 0;
z-index: 100;
/* 去除 sticky+z-index在小程序中两者结合会创建茂叠上下文层
导致兴弟节点 merchant-tabbar (position:fixed) 被层叠侧改而隐藏 */
flex-shrink: 0;
}
.tabs-scroll {
display: flex;
flex-direction: row;
overflow-x: auto;
white-space: nowrap;
padding: 0 20rpx;
@@ -728,7 +786,14 @@
.orders-list {
padding: 0 20rpx;
height: calc(100vh - 460rpx);
flex: 1;
overflow: hidden;
}
.safe-bottom {
/* 高度通过 :style=" {height: safeBottomHeight}" 动态设置,
不再写死 160rpx */
background-color: transparent;
}
.loading-container, .empty-container {
@@ -1058,4 +1123,18 @@
color: #007AFF;
font-weight: bold;
}
/* ===== 骨架屏 ===== */
@keyframes ske-pulse { 0% { opacity: 1; } 50% { opacity: 0.45; } 100% { opacity: 1; } }
.ske-orders-wrap { padding: 24rpx; }
.ske-order-card { background-color: #fff; border-radius: 20rpx; padding: 24rpx; margin-bottom: 24rpx; }
.ske-order-hd { display: flex; flex-direction: row; justify-content: space-between; align-items: center; margin-bottom: 20rpx; }
.ske-order-product { display: flex; flex-direction: row; align-items: center; margin-bottom: 20rpx; }
.ske-product-img { width: 100rpx; height: 100rpx; border-radius: 12rpx; background-color: #e8e8e8; margin-right: 16rpx; flex-shrink: 0; animation: ske-pulse 1.4s ease-in-out infinite; }
.ske-product-info { flex: 1; }
.ske-order-ft { display: flex; flex-direction: row; justify-content: space-between; align-items: center; border-top-width: 1rpx; border-top-style: solid; border-top-color: #f5f5f5; padding-top: 16rpx; }
.ske-bar { border-radius: 8rpx; background-color: #e8e8e8; animation: ske-pulse 1.4s ease-in-out infinite; }
.ske-w22 { width: 22%; } .ske-w25 { width: 25%; } .ske-w30 { width: 30%; } .ske-w40 { width: 40%; } .ske-w50 { width: 50%; } .ske-w70 { width: 70%; }
.ske-h22 { height: 22rpx; } .ske-h26 { height: 26rpx; } .ske-h28 { height: 28rpx; } .ske-h30 { height: 30rpx; }
.ske-mb10 { margin-bottom: 10rpx; }
</style>

File diff suppressed because it is too large Load Diff