- 设计并实现了开发者中心与企业控制台两大模块 - 按用户角色区分开发者和企业客户,支持多项目类型及成员管理 - 新增项目管理、应用管理、API Key管理及成员邀请等多功能页面 - 实现应用版本发布、消息通知中心、权限审批与开发者申请流程 - 完成CI/CD流水线、运营监控、发票管理、SSO单点登录功能 - 搭建SDK下载中心、工单系统、FAQ系统、数据导入导出等模块 - 优化后端API,支持已登录和未注册用户不同加入应用流程 - 前端按钮统一采用微信手机号授权,完善用户授权体验 - 修复多个页面的JSX语法错误及依赖导入问题,替换部分组件库 - 增加详细的类型定义文件,提升项目类型安全 - 新增超过55个页面及60个API接口,扩展应用功能和服务体系 - 完成全面的样式设计,实现一致的视觉风格和交互体验
179 lines
6.1 KiB
TypeScript
179 lines
6.1 KiB
TypeScript
import React, { useState, useEffect } from 'react'
|
||
import { View, Text, ScrollView } from '@tarojs/components'
|
||
import Taro from '@tarojs/taro'
|
||
import { Button, Empty, Tabs, PullToRefresh } from '@nutui/nutui-react-taro'
|
||
import './index.scss'
|
||
|
||
const ProjectList: React.FC = () => {
|
||
const [activeTab, setActiveTab] = useState('all')
|
||
const [projects, setProjects] = useState<any[]>([])
|
||
const [loading, setLoading] = useState(true)
|
||
const [refreshing, setRefreshing] = useState(false)
|
||
|
||
// 模拟数据
|
||
const mockProjects = [
|
||
{
|
||
id: 1,
|
||
name: '我的企业官网',
|
||
type: 'pro',
|
||
description: '企业品牌展示官网',
|
||
appCount: 2,
|
||
memberCount: 3,
|
||
apiCallCount: 12580,
|
||
status: 'active',
|
||
updatedAt: '2026-04-10',
|
||
},
|
||
{
|
||
id: 2,
|
||
name: '电商小程序',
|
||
type: 'enterprise',
|
||
description: '多端电商解决方案',
|
||
appCount: 5,
|
||
memberCount: 8,
|
||
apiCallCount: 98650,
|
||
status: 'active',
|
||
updatedAt: '2026-04-12',
|
||
},
|
||
{
|
||
id: 3,
|
||
name: '内部管理系统',
|
||
type: 'basic',
|
||
description: 'OA办公系统',
|
||
appCount: 1,
|
||
memberCount: 5,
|
||
apiCallCount: 3200,
|
||
status: 'active',
|
||
updatedAt: '2026-04-08',
|
||
},
|
||
]
|
||
|
||
// 加载数据
|
||
const loadData = async () => {
|
||
try {
|
||
setLoading(true)
|
||
// TODO: 替换为真实 API 调用
|
||
// const result = await pageMyProject({ type: activeTab === 'all' ? undefined : activeTab })
|
||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||
setProjects(mockProjects)
|
||
} catch (error) {
|
||
console.error('加载失败', error)
|
||
Taro.showToast({ title: '加载失败', icon: 'none' })
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
// 下拉刷新
|
||
const onRefresh = async () => {
|
||
setRefreshing(true)
|
||
await loadData()
|
||
setRefreshing(false)
|
||
}
|
||
|
||
useEffect(() => {
|
||
loadData()
|
||
}, [activeTab])
|
||
|
||
// 获取项目类型标签
|
||
const getTypeBadge = (type: string) => {
|
||
const badges: Record<string, { text: string; color: string }> = {
|
||
basic: { text: '基础', color: '#6b7280' },
|
||
pro: { text: '专业', color: '#3b82f6' },
|
||
enterprise: { text: '企业', color: '#f59e0b' },
|
||
}
|
||
return badges[type] || badges.basic
|
||
}
|
||
|
||
// 跳转创建页面
|
||
const handleCreate = () => {
|
||
Taro.navigateTo({ url: '/developer/project/create' })
|
||
}
|
||
|
||
// 跳转项目详情
|
||
const handleProjectClick = (id: number) => {
|
||
Taro.navigateTo({ url: `/developer/project/${id}` })
|
||
}
|
||
|
||
return (
|
||
<View className="project-list-page">
|
||
<PullToRefresh refreshing={refreshing} onRefresh={onRefresh}>
|
||
{/* 标签页 */}
|
||
<View className="tabs-wrapper">
|
||
<Tabs value={activeTab} onChange={(v) => setActiveTab(v as string)}>
|
||
<Tabs.TabPane title="全部项目" value="all" />
|
||
<Tabs.TabPane title="基础版" value="basic" />
|
||
<Tabs.TabPane title="专业版" value="pro" />
|
||
<Tabs.TabPane title="企业版" value="enterprise" />
|
||
</Tabs>
|
||
</View>
|
||
|
||
<ScrollView scrollY className="project-list-page__scroll">
|
||
{/* 项目列表 */}
|
||
<View className="project-list">
|
||
{loading ? (
|
||
<View className="project-list__loading">
|
||
<Text>加载中...</Text>
|
||
</View>
|
||
) : projects.length === 0 ? (
|
||
<Empty description="暂无项目" />
|
||
) : (
|
||
<View className="project-list__content">
|
||
{projects.map((project) => {
|
||
const badge = getTypeBadge(project.type)
|
||
return (
|
||
<View key={project.id} className="project-card" onClick={() => handleProjectClick(project.id)}>
|
||
<View className="project-card__header">
|
||
<View className="project-card__title-row">
|
||
<Text className="project-card__name">{project.name}</Text>
|
||
<View className="project-card__badge" style={{ backgroundColor: `${badge.color}15`, color: badge.color }}>
|
||
<Text className="project-card__badgeText">{badge.text}</Text>
|
||
</View>
|
||
</View>
|
||
<Text className="project-card__desc">{project.description}</Text>
|
||
</View>
|
||
|
||
<View className="project-card__stats">
|
||
<View className="project-card__stat">
|
||
<Text className="project-card__statValue">{project.appCount}</Text>
|
||
<Text className="project-card__statLabel">应用</Text>
|
||
</View>
|
||
<View className="project-card__stat">
|
||
<Text className="project-card__statValue">{project.memberCount}</Text>
|
||
<Text className="project-card__statLabel">成员</Text>
|
||
</View>
|
||
<View className="project-card__stat">
|
||
<Text className="project-card__statValue">{project.apiCallCount}</Text>
|
||
<Text className="project-card__statLabel">API调用</Text>
|
||
</View>
|
||
</View>
|
||
|
||
<View className="project-card__footer">
|
||
<Text className="project-card__time">更新于 {project.updatedAt}</Text>
|
||
<View className="project-card__action">
|
||
<Text className="project-card__actionText">查看详情 ›</Text>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
)
|
||
})}
|
||
</View>
|
||
)}
|
||
</View>
|
||
|
||
{/* 底部安全区域 */}
|
||
<View className="safe-area-bottom" />
|
||
</ScrollView>
|
||
|
||
{/* 创建按钮 */}
|
||
<View className="create-btn-wrapper">
|
||
<Button type="primary" block onClick={handleCreate}>
|
||
创建新项目
|
||
</Button>
|
||
</View>
|
||
</PullToRefresh>
|
||
</View>
|
||
)
|
||
}
|
||
|
||
export default ProjectList
|