- 用户菜单中根据 isDeveloper 字段条件展示“申请成为开发者”或“进入开发者中心” - 已审核通过用户菜单显示“进入开发者中心”,并设置高亮样式 - 去除冗余的独立“开发者中心”菜单条目,简化菜单结构 - 重新设计开发者中心页面UI,统一为门店中心风格 - 顶部展示开发者头像及昵称手机号信息 - 功能卡片展示“我的应用”、“API Key”和“我的工单”,异步加载数量角标 - 底部添加“开发者帮助与支持”入口,替代门店订阅消息卡片 - 未登录或非开发者状态显示相应空态提示及操作按钮 - 优化登录状态与权限校验逻辑,防止页面闪烁和无权限内容显示
229 lines
7.9 KiB
TypeScript
229 lines
7.9 KiB
TypeScript
import React, { useState, useEffect, useCallback } from 'react'
|
||
import { View, Text, Image } from '@tarojs/components'
|
||
import Taro from '@tarojs/taro'
|
||
import Badge from '@/components/common/Badge'
|
||
import { useUser } from '@/hooks/useUser'
|
||
import { getMyApps } from '@/api/app/appProduct'
|
||
import { getAppApiKeyStats } from '@/api/app/apikey'
|
||
import { getMyTickets } from '@/api/app/ticket'
|
||
import { getPageTotal } from '@/utils/devcenter'
|
||
|
||
definePageConfig({
|
||
navigationBarTitleText: '开发者中心',
|
||
})
|
||
|
||
// 功能卡片定义(未来新增功能只需在这里加一项)
|
||
const FEATURE_CARDS = [
|
||
{
|
||
key: 'apps',
|
||
icon: '📦',
|
||
title: '我的应用',
|
||
desc: '管理你开发并上架的应用',
|
||
url: '/pages/developer/apps/index',
|
||
color: '#3b82f6',
|
||
bgColor: '#dbeafe',
|
||
showBadge: true,
|
||
},
|
||
{
|
||
key: 'apikeys',
|
||
icon: '🔑',
|
||
title: 'API Key',
|
||
desc: '查看与管理你的接口密钥',
|
||
url: '/pages/developer/apikeys/index',
|
||
color: '#10b981',
|
||
bgColor: '#dcfce7',
|
||
showBadge: true,
|
||
},
|
||
{
|
||
key: 'tickets',
|
||
icon: '🎫',
|
||
title: '我的工单',
|
||
desc: '提交与跟踪你的工单',
|
||
url: '/pages/developer/tickets/index',
|
||
color: '#f59e0b',
|
||
bgColor: '#fef3c7',
|
||
showBadge: true,
|
||
},
|
||
]
|
||
|
||
export default function DeveloperCenterPage() {
|
||
const { user, isLoggedIn, loading: userLoading } = useUser()
|
||
const isDeveloper = !!(user as any)?.isDeveloper
|
||
const [stats, setStats] = useState({ apps: 0, keys: 0, tickets: 0 })
|
||
|
||
useEffect(() => {
|
||
if (isLoggedIn && isDeveloper) {
|
||
load()
|
||
}
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
}, [isLoggedIn, isDeveloper])
|
||
|
||
/** 加载我的应用 / API Key / 工单数量 */
|
||
const load = useCallback(async () => {
|
||
try {
|
||
const [appsR, keysR, ticketsR] = await Promise.allSettled([
|
||
getMyApps({ page: 1, limit: 1 }),
|
||
getAppApiKeyStats(),
|
||
getMyTickets({ page: 1, limit: 1 }),
|
||
])
|
||
const apps = appsR.status === 'fulfilled' ? getPageTotal(appsR.value) : 0
|
||
const keys = keysR.status === 'fulfilled' ? getPageTotal(keysR.value) : 0
|
||
const tickets = ticketsR.status === 'fulfilled' ? getPageTotal(ticketsR.value) : 0
|
||
setStats({ apps, keys, tickets })
|
||
} catch {
|
||
// ignore
|
||
}
|
||
}, [])
|
||
|
||
/** 获取卡片角标数字 */
|
||
const getBadgeCount = (key: string) => {
|
||
if (key === 'apps') return stats.apps
|
||
if (key === 'apikeys') return stats.keys
|
||
if (key === 'tickets') return stats.tickets
|
||
return 0
|
||
}
|
||
|
||
if (userLoading) {
|
||
return (
|
||
<View className='min-h-full bg-gray-50 flex items-center justify-center'>
|
||
<Text className='text-gray-400'>加载中...</Text>
|
||
</View>
|
||
)
|
||
}
|
||
|
||
if (!isLoggedIn) {
|
||
return (
|
||
<View className='min-h-full bg-gray-50 flex flex-col items-center justify-center py-24'>
|
||
<Text className='text-5xl mb-3'>🔐</Text>
|
||
<Text className='text-base text-gray-700 mb-2'>请先登录</Text>
|
||
<Text className='text-xs text-gray-400 text-center'>登录后方可进入开发者中心</Text>
|
||
</View>
|
||
)
|
||
}
|
||
|
||
if (!isDeveloper) {
|
||
return (
|
||
<View className='min-h-full bg-gray-50 flex flex-col items-center justify-center py-20 px-10'>
|
||
<Text className='text-5xl mb-3'>🛠️</Text>
|
||
<Text className='text-base text-gray-700 mb-2'>尚未加入开发者中心</Text>
|
||
<Text className='text-xs text-gray-400 text-center mb-5 leading-relaxed'>
|
||
开发者中心提供应用管理、API Key、工单等能力,请先申请开发者资质
|
||
</Text>
|
||
<View
|
||
className='px-6 py-2 rounded-full'
|
||
style={{ background: '#2563eb' }}
|
||
onClick={() => Taro.navigateTo({ url: '/pages/user/vip-upgrade/index' })}
|
||
>
|
||
<Text className='text-white text-sm'>申请成为开发者</Text>
|
||
</View>
|
||
</View>
|
||
)
|
||
}
|
||
|
||
// 头部展示信息
|
||
const header = {
|
||
avatar: (user as any)?.avatar,
|
||
title: '开发者中心',
|
||
subtitle: `${((user as any)?.nickname || (user as any)?.username || '')}${((user as any)?.phone) ? ` · ${(user as any).phone}` : ''}`,
|
||
}
|
||
|
||
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'>
|
||
{header.avatar ? (
|
||
<Image
|
||
className='w-full h-full'
|
||
src={header.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'>
|
||
{header.title}
|
||
</Text>
|
||
<Text className='text-white text-opacity-80 text-sm mt-1 block truncate'>
|
||
{header.subtitle}
|
||
</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 && (
|
||
<Badge count={getBadgeCount(card.key)} className='absolute -top-1 -right-1' size={20} fontSize={11} fontWeight='bold' />
|
||
)}
|
||
|
||
{/* 箭头 */}
|
||
<Text className='text-gray-300 text-lg flex-shrink-0'>›</Text>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</View>
|
||
|
||
{/* 底部提示 */}
|
||
<View className='mx-3 mt-6 mb-6'>
|
||
{/* 开发者帮助 */}
|
||
<View
|
||
className='bg-white rounded-xl p-4 flex items-center gap-3 active:opacity-80'
|
||
onClick={() => Taro.navigateTo({ url: '/pages/user/help-center/index' })}
|
||
>
|
||
<View className='w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0'
|
||
style={{ background: '#dbeafe' }}>
|
||
<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'>
|
||
查看接口文档、SDK 与常见问题
|
||
</Text>
|
||
</View>
|
||
<Text className='text-blue-500 text-sm flex-shrink-0'>查看</Text>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
)
|
||
}
|