- 新增 useNewOrderDetector Hook,实现30秒轮询检测新订单 - 订单管理页集成该 Hook,新增订单时震动+Toast提醒 - “全部”Tab 显示新订单红点,切换Tab清空未读计数 - 门店中心页增加待处理订单角标,统一待审核和待处理显示逻辑 - 底部新增“接收新订单提醒”订阅消息授权入口,调用微信接口申请授权 - 文档中补充订阅消息模板ID及字段说明,待后端配合公众号推送消息
227 lines
7.8 KiB
TypeScript
227 lines
7.8 KiB
TypeScript
import React, { useState, useEffect, useCallback } from 'react'
|
||
import { View, Text, Image } from '@tarojs/components'
|
||
import Taro from '@tarojs/taro'
|
||
import { getMyClerk } from '@/api/shop/shopStoreUser'
|
||
import { listShopDealerApply } from '@/api/shop/shopDealerApply'
|
||
import { pageShopOrder } from '@/api/shop/shopOrder'
|
||
|
||
definePageConfig({
|
||
navigationBarTitleText: '门店中心',
|
||
})
|
||
|
||
// 功能卡片定义(未来新增功能只需在这里加一项)
|
||
const FEATURE_CARDS = [
|
||
{
|
||
key: 'orders',
|
||
icon: '📦',
|
||
title: '订单管理',
|
||
desc: '查看和处理门店订单',
|
||
url: '/pages/store/orders/index',
|
||
color: '#15803d',
|
||
bgColor: '#dcfce7',
|
||
// 显示待处理订单数量角标
|
||
showBadge: true,
|
||
},
|
||
{
|
||
key: 'vip-review',
|
||
icon: '👑',
|
||
title: 'VIP会员审核',
|
||
desc: '审核客户VIP会员申请',
|
||
url: '/pages/user/vip-review/index',
|
||
color: '#7c3aed',
|
||
bgColor: '#ede9fe',
|
||
showBadge: true,
|
||
},
|
||
]
|
||
|
||
// 订阅消息模板 ID
|
||
const SUBSCRIBE_TMPL_IDS = [
|
||
'sh1K9iK7vZjebUNFu6OsMsnsJxm4whThWGrhN7I4zVg', // 交易提醒:订单号、商品名称、联系人、联系电话、送货地址
|
||
]
|
||
|
||
export default function StoreCenterPage() {
|
||
const [storeInfo, setStoreInfo] = useState<any>(null)
|
||
const [pendingVipCount, setPendingVipCount] = useState(0)
|
||
const [pendingOrderCount, setPendingOrderCount] = useState(0)
|
||
const [loading, setLoading] = useState(true)
|
||
|
||
useEffect(() => {
|
||
// 验证店员身份
|
||
getMyClerk()
|
||
.then(data => {
|
||
if (!data) {
|
||
Taro.showToast({ title: '仅门店店员可访问', icon: 'none' })
|
||
setTimeout(() => Taro.navigateBack(), 1500)
|
||
return
|
||
}
|
||
setStoreInfo(data)
|
||
// 加载待审核数量
|
||
loadBadgeCounts()
|
||
})
|
||
.catch(() => {
|
||
Taro.showToast({ title: '仅门店店员可访问', icon: 'none' })
|
||
setTimeout(() => Taro.navigateBack(), 1500)
|
||
})
|
||
.finally(() => setLoading(false))
|
||
}, [])
|
||
|
||
/** 加载各类待处理角标数量 */
|
||
const loadBadgeCounts = async () => {
|
||
try {
|
||
// VIP 待审核
|
||
const vipData = await listShopDealerApply({ applyStatus: 10 })
|
||
setPendingVipCount((vipData || []).length)
|
||
} catch { /* ignore */ }
|
||
|
||
try {
|
||
// 待处理订单:未付款/待发货/待收货
|
||
const orderData = await pageShopOrder({ statusFilter: 1, page: 1, limit: 1 })
|
||
setPendingOrderCount(orderData?.total || 0)
|
||
} catch { /* ignore */ }
|
||
}
|
||
|
||
/** 获取卡片角标数字 */
|
||
const getBadgeCount = (key: string) => {
|
||
if (key === 'orders') return pendingOrderCount
|
||
if (key === 'vip-review') return pendingVipCount
|
||
return 0
|
||
}
|
||
|
||
/** 请求订阅消息授权 */
|
||
const handleSubscribe = useCallback(() => {
|
||
if (SUBSCRIBE_TMPL_IDS.length === 0) {
|
||
Taro.showToast({ title: '暂无可订阅的消息模板', icon: 'none' })
|
||
return
|
||
}
|
||
Taro.requestSubscribeMessage({
|
||
tmplIds: SUBSCRIBE_TMPL_IDS,
|
||
success: (res) => {
|
||
// res[templateId] === 'accept' 表示用户同意订阅
|
||
const accepted = SUBSCRIBE_TMPL_IDS.filter(id => res[id] === 'accept')
|
||
if (accepted.length > 0) {
|
||
Taro.showToast({ title: '订阅成功', icon: 'success' })
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
console.error('订阅失败:', err)
|
||
},
|
||
})
|
||
}, [])
|
||
|
||
if (loading) {
|
||
return (
|
||
<View className='min-h-full bg-gray-50 flex items-center justify-center'>
|
||
<Text className='text-gray-400'>加载中...</Text>
|
||
</View>
|
||
)
|
||
}
|
||
|
||
if (!storeInfo) return null
|
||
|
||
return (
|
||
<View className='min-h-full bg-gray-50'>
|
||
|
||
{/* 顶部信息区:店员头像 + 门店名称 */}
|
||
<View
|
||
className='pt-8 pb-12 px-5 rounded-b-3xl relative overflow-hidden'
|
||
style={{ background: 'linear-gradient(135deg, #15803d 0%, #22c55e 60%, #4ade80 100%)' }}
|
||
>
|
||
<View className='absolute -top-10 -right-10 w-40 h-40 rounded-full opacity-10'
|
||
style={{ background: 'radial-gradient(circle, #ffffff, transparent)' }} />
|
||
<View className='absolute -bottom-6 -left-6 w-24 h-24 rounded-full opacity-15'
|
||
style={{ background: 'radial-gradient(circle, #ffffff, transparent)' }} />
|
||
<View className='relative z-10 flex items-center gap-4'>
|
||
{/* 店员头像 */}
|
||
<View className='w-16 h-16 rounded-full bg-white/20 border-2 border-white/40 overflow-hidden flex-shrink-0'>
|
||
{storeInfo.avatar ? (
|
||
<Image
|
||
className='w-full h-full'
|
||
src={storeInfo.avatar}
|
||
mode='aspectFill'
|
||
/>
|
||
) : (
|
||
<View className='w-full h-full flex items-center justify-center'>
|
||
<Text className='text-2xl'>👤</Text>
|
||
</View>
|
||
)}
|
||
</View>
|
||
|
||
{/* 门店信息 */}
|
||
<View className='flex-1 min-w-0'>
|
||
<Text className='text-white text-lg font-bold block truncate'>
|
||
{storeInfo.storeName || '门店中心'}
|
||
</Text>
|
||
<Text className='text-white text-opacity-80 text-sm mt-1 block truncate'>
|
||
{storeInfo.name} {storeInfo.phone ? `· ${storeInfo.phone}` : ''}
|
||
</Text>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 功能卡片区 */}
|
||
<View className='mx-3 -mt-6 relative z-20'>
|
||
|
||
<View className='flex flex-col gap-3'>
|
||
{FEATURE_CARDS.map(card => (
|
||
<View
|
||
key={card.key}
|
||
className='bg-white rounded-xl p-4 flex items-center gap-4 active:opacity-80 relative'
|
||
onClick={() => Taro.navigateTo({ url: card.url })}
|
||
>
|
||
{/* 图标 */}
|
||
<View
|
||
className='w-12 h-12 rounded-xl flex items-center justify-center flex-shrink-0'
|
||
style={{ background: card.bgColor }}
|
||
>
|
||
<Text className='text-2xl'>{card.icon}</Text>
|
||
</View>
|
||
|
||
{/* 文字 */}
|
||
<View className='flex-1 min-w-0'>
|
||
<Text className='text-gray-800 text-base font-medium block'>{card.title}</Text>
|
||
<Text className='text-gray-400 text-xs mt-0.5 block'>{card.desc}</Text>
|
||
</View>
|
||
|
||
{/* 待处理角标 */}
|
||
{card.showBadge && getBadgeCount(card.key) > 0 && (
|
||
<View className='absolute -top-1 -right-1 min-w-[20px] h-[20px] rounded-full bg-red-500 flex items-center justify-center px-1.5'>
|
||
<Text className='text-white text-[11px] font-bold'>
|
||
{getBadgeCount(card.key) > 99 ? '99+' : getBadgeCount(card.key)}
|
||
</Text>
|
||
</View>
|
||
)}
|
||
|
||
{/* 箭头 */}
|
||
<Text className='text-gray-300 text-lg flex-shrink-0'>›</Text>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</View>
|
||
|
||
{/* 底部提示 */}
|
||
<View className='mx-3 mt-6 mb-4'>
|
||
{/* 订阅消息提醒 */}
|
||
<View
|
||
className='bg-white rounded-xl p-4 flex items-center gap-3 active:opacity-80 mb-3'
|
||
onClick={handleSubscribe}
|
||
>
|
||
<View className='w-10 h-10 rounded-full bg-orange-50 flex items-center justify-center flex-shrink-0'>
|
||
<Text className='text-xl'>🔔</Text>
|
||
</View>
|
||
<View className='flex-1 min-w-0'>
|
||
<Text className='text-gray-800 text-sm font-medium block'>接收新订单提醒</Text>
|
||
<Text className='text-gray-400 text-xs mt-0.5 block'>
|
||
开启后新订单将通过微信服务通知提醒您
|
||
</Text>
|
||
</View>
|
||
<Text className='text-orange-500 text-sm flex-shrink-0'>去开启</Text>
|
||
</View>
|
||
|
||
<Text className='text-gray-300 text-xs text-center block'>
|
||
未来更多功能将持续上线
|
||
</Text>
|
||
</View>
|
||
</View>
|
||
)
|
||
}
|