refactor(user): 将VIP身份统一改为开发者标记

- 审核通过时不再新增角色,而是更新用户isDeveloper布尔标记
- 后端UserService新增markAsDeveloper方法,通过updateById设置isDeveloper
- UserController新增PUT接口更新开发者标记,权限使用sys:userRole:save
- 前端api新增setUserDeveloper调用新的审核接口
- vip-review页面移除角色相关代码,改为调用setUserDeveloper方法
- 约定开发者身份即sys_user.is_developer字段,不再依赖角色表记录
- app.config.ts追加开发者中心与平台管理相关页面路由
- 新增开发者中心、平台管理的多个API模块(apikey、appProduct、appDomain、developer请求等)
- 添加公共工具方法和复用组件用于开发者中心及平台管理功能
- 统一品牌名称为“威数谱软件”,更新文案及界面展现一致性
This commit is contained in:
2026-07-22 14:57:03 +08:00
parent 2ea16e22cf
commit 39d3b59434
24 changed files with 2015 additions and 95 deletions

View File

@@ -0,0 +1,114 @@
import React, { useState, useEffect, useCallback } from 'react'
import { View, Text, ScrollView } from '@tarojs/components'
import Taro from '@tarojs/taro'
import NavBar from '@/components/NavBar'
import StatCard from '@/components/common/StatCard'
import EntryGrid from '@/components/common/EntryGrid'
import Loading from '@/components/common/Loading'
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 DeveloperCenterPage: React.FC = () => {
const { user, isLoggedIn } = useUser()
const isDeveloper = !!(user as any)?.isDeveloper
const [loading, setLoading] = useState(true)
const [stats, setStats] = useState({ apps: 0, keys: 0, tickets: 0 })
const load = useCallback(async () => {
setLoading(true)
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 (e) {
// ignore
} finally {
setLoading(false)
}
}, [])
useEffect(() => {
if (isLoggedIn) load()
}, [isLoggedIn, load])
if (!isLoggedIn) {
return (
<View className='min-h-screen bg-gray-100'>
<NavBar title='开发者中心' />
<View className='flex flex-col items-center justify-center py-24'>
<Text className='text-gray-400 text-sm'></Text>
<View
className='mt-4 px-6 py-2 rounded-full'
style={{ background: '#0e932e' }}
onClick={() => Taro.navigateTo({ url: '/passport/login' })}
>
<Text className='text-white text-sm'></Text>
</View>
</View>
</View>
)
}
if (!isDeveloper) {
return (
<View className='min-h-screen bg-gray-100'>
<NavBar title='开发者中心' />
<View className='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>
</View>
)
}
const entries = [
{ icon: '📦', label: '我的应用', url: '/pages/developer/apps/index' },
{ icon: '🔑', label: 'API Key', url: '/pages/developer/apikeys/index' },
{ icon: '🎫', label: '我的工单', url: '/pages/developer/tickets/index' },
]
return (
<View className='min-h-screen bg-gray-100'>
<NavBar title='开发者中心' />
<ScrollView scrollY>
{loading ? (
<Loading />
) : (
<View className='p-4'>
<View className='grid grid-cols-3 gap-3 mb-3'>
<StatCard label='我的应用' value={stats.apps} color='#3b82f6' />
<StatCard label='API Key' value={stats.keys} color='#10b981' />
<StatCard label='我的工单' value={stats.tickets} color='#f59e0b' />
</View>
<Text className='text-base font-medium mb-2 block'></Text>
<EntryGrid items={entries} columns={3} />
<View className='h-6' />
</View>
)}
</ScrollView>
</View>
)
}
export default DeveloperCenterPage