Files
websopy-taro/src/developer/index.tsx
赵忠林 ffab0ec25c feat(developer): 完成小程序开发者中心和企业控制台改造
- 设计并实现了开发者中心与企业控制台两大模块
- 按用户角色区分开发者和企业客户,支持多项目类型及成员管理
- 新增项目管理、应用管理、API Key管理及成员邀请等多功能页面
- 实现应用版本发布、消息通知中心、权限审批与开发者申请流程
- 完成CI/CD流水线、运营监控、发票管理、SSO单点登录功能
- 搭建SDK下载中心、工单系统、FAQ系统、数据导入导出等模块
- 优化后端API,支持已登录和未注册用户不同加入应用流程
- 前端按钮统一采用微信手机号授权,完善用户授权体验
- 修复多个页面的JSX语法错误及依赖导入问题,替换部分组件库
- 增加详细的类型定义文件,提升项目类型安全
- 新增超过55个页面及60个API接口,扩展应用功能和服务体系
- 完成全面的样式设计,实现一致的视觉风格和交互体验
2026-04-13 02:26:46 +08:00

198 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react'
import { View, Text, ScrollView } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { Button, Empty } from '@nutui/nutui-react-taro'
import { useThemeStyles } from '@/hooks/useTheme'
import { pageMyApp } from '@/api/developer'
import type { App } from '@/types/developer'
import { APP_TYPE_NAME } from '@/types/developer'
import './index.scss'
const DeveloperIndex: React.FC = () => {
const themeStyles = useThemeStyles()
const [apps, setApps] = useState<App[]>([])
const [loading, setLoading] = useState(true)
const [stats, setStats] = useState({
totalApps: 0,
runningApps: 0,
totalCalls: 0,
})
// 加载数据
const loadData = async () => {
try {
setLoading(true)
const result = await pageMyApp({ current: 1, size: 10 })
if (result) {
setApps(result.list || [])
setStats({
totalApps: result.count || 0,
runningApps: result.list?.filter((a) => a.status === 1).length || 0,
totalCalls: 0,
})
}
} catch (error) {
console.error('加载数据失败', error)
Taro.showToast({ title: '加载失败', icon: 'none' })
} finally {
setLoading(false)
}
}
useEffect(() => {
loadData()
}, [])
// 跳转页面
const navigateTo = (url: string) => {
Taro.navigateTo({ url })
}
// 获取状态颜色
const getStatusColor = (status?: number) => {
const colors: Record<number, string> = {
0: '#6b7280',
1: '#10b981',
2: '#f59e0b',
3: '#ef4444',
4: '#ef4444',
5: '#ef4444',
}
return colors[status || 0] || '#6b7280'
}
// 获取状态文本
const getStatusText = (status?: number) => {
const texts: Record<number, string> = {
0: '未开通',
1: '运行中',
2: '维护中',
3: '已关闭',
4: '已欠费',
5: '违规停机',
}
return texts[status || 0] || '未知'
}
return (
<View className="developer-page">
<ScrollView scrollY className="developer-page__scroll">
{/* 头部区域 */}
<View className="developer-header" style={themeStyles.primaryBackground}>
<View className="developer-header__glow" />
<View className="developer-header__content">
<View className="developer-header__title">
<Text className="developer-header__titleText">🛠 </Text>
</View>
<Text className="developer-header__subtitle"></Text>
</View>
</View>
{/* 统计卡片 */}
<View className="stats-card">
<View className="stats-card__row">
<View className="stats-card__item">
<Text className="stats-card__value">{stats.totalApps}</Text>
<Text className="stats-card__label"></Text>
</View>
<View className="stats-card__divider" />
<View className="stats-card__item">
<Text className="stats-card__value">{stats.runningApps}</Text>
<Text className="stats-card__label"></Text>
</View>
<View className="stats-card__divider" />
<View className="stats-card__item">
<Text className="stats-card__value">{stats.totalCalls}</Text>
<Text className="stats-card__label">API </Text>
</View>
</View>
</View>
{/* 快捷操作 */}
<View className="quick-actions">
<View className="quick-actions__title">
<Text className="quick-actions__titleText"></Text>
</View>
<View className="quick-actions__grid">
<View className="quick-actions__item" onClick={() => navigateTo('/developer/project/index')}>
<View className="quick-actions__icon quick-actions__icon--blue">
<Text>📁</Text>
</View>
<Text className="quick-actions__text"></Text>
</View>
<View className="quick-actions__item" onClick={() => navigateTo('/developer/app/index')}>
<View className="quick-actions__icon quick-actions__icon--green">
<Text>📱</Text>
</View>
<Text className="quick-actions__text"></Text>
</View>
<View className="quick-actions__item" onClick={() => navigateTo('/developer/app/api-keys')}>
<View className="quick-actions__icon quick-actions__icon--purple">
<Text>🔑</Text>
</View>
<Text className="quick-actions__text">API Key</Text>
</View>
<View className="quick-actions__item" onClick={() => navigateTo('/developer/docs/index')}>
<View className="quick-actions__icon quick-actions__icon--orange">
<Text>📖</Text>
</View>
<Text className="quick-actions__text"></Text>
</View>
</View>
</View>
{/* 应用列表 */}
<View className="app-list">
<View className="app-list__header">
<Text className="app-list__title"></Text>
<View className="app-list__more" onClick={() => navigateTo('/developer/app/index')}>
<Text className="app-list__moreText"> </Text>
</View>
</View>
{loading ? (
<View className="app-list__loading">
<Text>...</Text>
</View>
) : apps.length === 0 ? (
<Empty description="暂无应用" />
) : (
<View className="app-list__content">
{apps.map((app) => (
<View key={app.productId} className="app-item" onClick={() => navigateTo(`/developer/app/${app.productId}`)}>
<View className="app-item__icon">
{app.icon ? (
<img src={app.icon} alt={app.productName} />
) : (
<Text>📱</Text>
)}
</View>
<View className="app-item__info">
<Text className="app-item__name">{app.productName}</Text>
<Text className="app-item__type">{APP_TYPE_NAME[app.appType as keyof typeof APP_TYPE_NAME] || '未知'}</Text>
</View>
<View className="app-item__status" style={{ color: getStatusColor(app.status) }}>
<View className="app-item__statusDot" style={{ backgroundColor: getStatusColor(app.status) }} />
<Text className="app-item__statusText">{getStatusText(app.status)}</Text>
</View>
</View>
))}
</View>
)}
<View className="app-list__footer">
<Button type="primary" block onClick={() => navigateTo('/developer/app/create')}>
</Button>
</View>
</View>
{/* 底部安全区域 */}
<View className="safe-area-bottom" />
</ScrollView>
</View>
)
}
export default DeveloperIndex