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,47 @@
import { View, Text } from '@tarojs/components'
interface CellRowProps {
title: string
subtitle?: string
extra?: string
statusText?: string
statusColor?: string
showArrow?: boolean
onClick?: () => void
}
export default function CellRow({
title,
subtitle,
extra,
statusText,
statusColor,
showArrow = true,
onClick,
}: CellRowProps) {
return (
<View
className='flex items-center justify-between px-4 py-3 bg-white border-b border-gray-50'
onClick={onClick}
>
<View className='flex-1 mr-2'>
<View className='flex items-center gap-2 flex-wrap'>
<Text className='text-sm text-gray-800'>{title}</Text>
{statusText && (
<Text
className='text-xs px-1.5 py-0.5 rounded-full'
style={{ color: statusColor, background: (statusColor || '#999') + '22' }}
>
{statusText}
</Text>
)}
</View>
{subtitle && (
<Text className='text-xs text-gray-400 mt-1 block'>{subtitle}</Text>
)}
</View>
{extra && <Text className='text-sm text-gray-500 mr-2'>{extra}</Text>}
{showArrow && <Text className='text-gray-300'></Text>}
</View>
)
}

View File

@@ -0,0 +1,43 @@
import { View, Text } from '@tarojs/components'
import Taro from '@tarojs/taro'
interface EntryItem {
icon: string
label: string
url?: string
onClick?: () => void
badge?: string
}
interface EntryGridProps {
items: EntryItem[]
columns?: number
}
export default function EntryGrid({ items, columns = 3 }: EntryGridProps) {
return (
<View className='bg-white rounded-xl p-2'>
<View className='flex flex-wrap'>
{items.map((it, i) => (
<View
key={i}
className='flex flex-col items-center justify-center py-3 relative'
style={{ width: `${100 / columns}%` }}
onClick={() => {
if (it.onClick) it.onClick()
else if (it.url) Taro.navigateTo({ url: it.url })
}}
>
<Text className='text-2xl mb-1'>{it.icon}</Text>
<Text className='text-xs text-gray-600'>{it.label}</Text>
{it.badge && (
<View className='absolute top-1 right-6 px-1 rounded-full' style={{ background: '#ef4444' }}>
<Text className='text-white text-xs'>{it.badge}</Text>
</View>
)}
</View>
))}
</View>
</View>
)
}

View File

@@ -0,0 +1,25 @@
import { View, Text } from '@tarojs/components'
interface StatCardProps {
label: string
value: string | number
sub?: string
subColor?: string
color?: string
}
export default function StatCard({ label, value, sub, subColor, color = '#3b82f6' }: StatCardProps) {
return (
<View className='bg-white rounded-lg p-4'>
<Text className='text-sm text-gray-500 mb-2 block'>{label}</Text>
<Text className='text-2xl font-bold block' style={{ color }}>
{value}
</Text>
{sub && (
<Text className='text-xs mt-1 block' style={{ color: subColor || '#52c41a' }}>
{sub}
</Text>
)}
</View>
)
}