refactor(api): 规范前端API接口地址并统一路径前缀

- 修正开发者、小程序和企业相关API的基础URL,避免重复添加/api前缀
- 统一调整developer、enterprise、invite等模块接口路径,保持与后端Controller一致
- 新增权限申请及消息通知相关API,并完善相关函数实现
- 规范请求参数传递,移除多余包装,改用直接传递对象方式
- 新增API Key重置、版本发布/回滚等接口支持

feat(invite): 重构邀请登录流程支持未注册快速加入

- 完整重写invite页,分离已注册用户和未注册用户的按钮显示和交互
- 实现未注册用户微信手机号授权后自动注册登录及自动加入应用
- 已注册用户直接确认加入应用,无需手机号授权弹窗
- 统一使用getPhoneNumber按钮处理两种状态并修复“授权码不能为空”报错
- 前端配合后端改造,支持已登录用户可直接通过Authorization头加入应用

fix(developer): 修复开发者中心应用加载问题

- 修复只查询创建的应用导致邀请加入的应用不显示的问题
- 同时请求创建应用和参与应用接口,合并并去重应用列表
- 新增pageJoinedApp接口调用及合并逻辑,提高应用列表完整性和体验
This commit is contained in:
2026-04-13 15:30:32 +08:00
parent d11d64469c
commit 611b488af3
6 changed files with 419 additions and 72 deletions

View File

@@ -18,22 +18,23 @@ import type {
ApplyParam,
} from '@/types/developer'
// ==================== 项目相关 ====================
// ==================== 项目/应用相关 ====================
// 注意:后端使用 AppProduct 作为项目/应用的概念,路径为 /app/product
/**
* 获取我的项目列表
* 获取我的项目列表(我创建的应用)
*/
export async function pageMyProject(params?: ProjectParam) {
const res = await request.get<ApiResult<PageResult<Project>>>('/project/my/page', { params })
const res = await request.get<ApiResult<PageResult<Project>>>('/app/product/my/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
/**
* 获取项目列表
* 获取项目列表(分页查询应用列表)
*/
export async function pageProject(params?: ProjectParam) {
const res = await request.get<ApiResult<PageResult<Project>>>('/project/page', { params })
const res = await request.get<ApiResult<PageResult<Project>>>('/app/product/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -42,7 +43,7 @@ export async function pageProject(params?: ProjectParam) {
* 获取项目详情
*/
export async function getProject(id: number) {
const res = await request.get<ApiResult<Project>>(`/project/${id}`)
const res = await request.get<ApiResult<Project>>(`/app/product/detail/${id}`)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -51,7 +52,7 @@ export async function getProject(id: number) {
* 创建项目
*/
export async function createProject(data: Partial<Project>) {
const res = await request.post<ApiResult<unknown>>('/project', data)
const res = await request.post<ApiResult<unknown>>('/app/product/create', data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -60,7 +61,7 @@ export async function createProject(data: Partial<Project>) {
* 更新项目
*/
export async function updateProject(data: Partial<Project>) {
const res = await request.put<ApiResult<unknown>>(`/project/${data.id}`, data)
const res = await request.put<ApiResult<unknown>>('/app/product/update', data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -69,16 +70,16 @@ export async function updateProject(data: Partial<Project>) {
* 删除项目
*/
export async function deleteProject(id: number) {
const res = await request.del<ApiResult<unknown>>(`/project/${id}`)
const res = await request.del<ApiResult<unknown>>(`/app/product/delete/${id}`)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
/**
* 获取项目成员列表
* 获取项目成员列表(使用应用用户服务)
*/
export async function listProjectMember(projectId: number) {
const res = await request.get<ApiResult<ProjectMember[]>>(`/project/${projectId}/members`)
const res = await request.get<ApiResult<ProjectMember[]>>(`/app/app-user/page`, { appId: projectId })
if (res.code === 0 && res.data) return res.data
return Promise.reject(new Error(res.message))
}
@@ -87,7 +88,7 @@ export async function listProjectMember(projectId: number) {
* 添加项目成员
*/
export async function addProjectMember(projectId: number, data: Partial<ProjectMember>) {
const res = await request.post<ApiResult<unknown>>(`/project/${projectId}/members`, data)
const res = await request.post<ApiResult<unknown>>(`/app/app-user`, { ...data, appId: projectId })
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -96,18 +97,27 @@ export async function addProjectMember(projectId: number, data: Partial<ProjectM
* 移除项目成员
*/
export async function removeProjectMember(projectId: number, memberId: number) {
const res = await request.del<ApiResult<unknown>>(`/project/${projectId}/members/${memberId}`)
const res = await request.del<ApiResult<unknown>>(`/app/app-user/${memberId}`)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
// ==================== 应用相关 ====================
// ==================== 应用相关(别名,与项目共用)====================
/**
* 分页查询我的应用
* 分页查询我的应用(创建的应用)
*/
export async function pageMyApp(params?: AppParam) {
const res = await request.get<ApiResult<PageResult<App>>>('/app/product/my/page', { params })
const res = await request.get<ApiResult<PageResult<App>>>('/app/product/my/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
/**
* 分页查询我参与的应用(通过邀请加入的应用)
*/
export async function pageJoinedApp(params?: AppParam) {
const res = await request.get<ApiResult<PageResult<App>>>('/app/product/joined/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -116,7 +126,7 @@ export async function pageMyApp(params?: AppParam) {
* 获取应用列表
*/
export async function pageApp(params?: AppParam) {
const res = await request.get<ApiResult<PageResult<App>>>('/app/product/page', { params })
const res = await request.get<ApiResult<PageResult<App>>>('/app/product/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -125,7 +135,7 @@ export async function pageApp(params?: AppParam) {
* 获取应用详情
*/
export async function getApp(id: number) {
const res = await request.get<ApiResult<App>>(`/app/product/${id}`)
const res = await request.get<ApiResult<App>>(`/app/product/detail/${id}`)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -134,7 +144,7 @@ export async function getApp(id: number) {
* 创建应用
*/
export async function createApp(data: Partial<App>) {
const res = await request.post<ApiResult<unknown>>('/app/product', data)
const res = await request.post<ApiResult<unknown>>('/app/product/create', data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -143,7 +153,7 @@ export async function createApp(data: Partial<App>) {
* 更新应用
*/
export async function updateApp(data: Partial<App>) {
const res = await request.put<ApiResult<unknown>>(`/app/product/${data.id}`, data)
const res = await request.put<ApiResult<unknown>>('/app/product/update', data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -152,18 +162,19 @@ export async function updateApp(data: Partial<App>) {
* 删除应用
*/
export async function deleteApp(id: number) {
const res = await request.del<ApiResult<unknown>>(`/app/product/${id}`)
const res = await request.del<ApiResult<unknown>>(`/app/product/delete/${id}`)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
// ==================== API Key 相关 ====================
// 对应后端 AppCredentialController路径为 /app/app-credential
/**
* 获取 API Key 列表
*/
export async function pageApiKey(params?: ApiKeyParam) {
const res = await request.get<ApiResult<PageResult<ApiKey>>>('/app/app-credential/page', { params })
const res = await request.get<ApiResult<PageResult<ApiKey>>>('/app/app-credential/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -204,13 +215,23 @@ export async function deleteApiKey(id: number) {
return Promise.reject(new Error(res.message))
}
/**
* 重置 API Key Secret
*/
export async function resetApiKeySecret(id: number) {
const res = await request.post<ApiResult<unknown>>(`/app/app-credential/resetSecret/${id}`)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
// ==================== 版本发布相关 ====================
// 对应后端 AppVersionController路径为 /app/app-version
/**
* 获取版本列表
*/
export async function pageVersion(params?: VersionParam) {
const res = await request.get<ApiResult<PageResult<Version>>>('/app/app-version/page', { params })
const res = await request.get<ApiResult<PageResult<Version>>>('/app/app-version/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -233,42 +254,80 @@ export async function createVersion(data: Partial<Version>) {
return Promise.reject(new Error(res.message))
}
// ==================== 开发者相关 ====================
/**
* 发布版本
*/
export async function publishVersion(id: number) {
const res = await request.post<ApiResult<unknown>>(`/app/app-version/publish/${id}`)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
/**
* 获取开发者信息
* 回滚版本
*/
export async function rollbackVersion(id: number) {
const res = await request.post<ApiResult<unknown>>(`/app/app-version/rollback/${id}`)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
// ==================== 开发者相关 ====================
// 对应后端 GitAccountController路径为 /app/developer
/**
* 获取开发者信息Git账号绑定状态
*/
export async function getDeveloperInfo() {
const res = await request.get<ApiResult<Developer>>('/developer/info')
const res = await request.get<ApiResult<Developer>>('/app/developer/git-account')
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
/**
* 申请成为开发者
* 申请成为开发者绑定Git账号
*/
export async function applyDeveloper(data: DeveloperApplyParam) {
const res = await request.post<ApiResult<unknown>>('/developer/apply', data)
const res = await request.post<ApiResult<unknown>>('/app/developer/git-account', data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
/**
* 更新开发者信息
* 更新开发者信息更新Git账号
*/
export async function updateDeveloperInfo(data: Partial<Developer>) {
const res = await request.put<ApiResult<unknown>>('/developer/info', data)
const res = await request.put<ApiResult<unknown>>('/app/developer/git-account', data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
/**
* 获取Gitea服务器信息
*/
export async function getGiteaInfo() {
const res = await request.get<ApiResult<{ url: string; version: string; registrationEnabled: boolean }>>('/app/developer/gitea-info')
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
// ==================== 消息通知相关 ====================
// 对应后端 AppNotificationController路径为 /app/notification
/**
* 获取通知列表
*/
export async function pageNotification(params?: NotificationParam) {
const res = await request.get<ApiResult<PageResult<Notification>>>('/notification/page', { params })
const res = await request.get<ApiResult<PageResult<Notification>>>('/app/notification/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
/**
* 获取最近通知(铃铛下拉)
*/
export async function getRecentNotifications(type?: string, limit?: number) {
const res = await request.get<ApiResult<Notification[]>>('/app/notification/recent', { type, limit })
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -277,7 +336,7 @@ export async function pageNotification(params?: NotificationParam) {
* 获取未读通知数量
*/
export async function getUnreadCount() {
const res = await request.get<ApiResult<{ count: number }>>('/notification/unread-count')
const res = await request.get<ApiResult<{ count: number }>>('/app/notification/unread-count')
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -286,7 +345,7 @@ export async function getUnreadCount() {
* 标记通知为已读
*/
export async function markAsRead(id: number) {
const res = await request.put<ApiResult<unknown>>(`/notification/${id}/read`)
const res = await request.put<ApiResult<unknown>>(`/app/notification/read/${id}`)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -294,8 +353,8 @@ export async function markAsRead(id: number) {
/**
* 标记所有通知为已读
*/
export async function markAllAsRead() {
const res = await request.put<ApiResult<unknown>>('/notification/read-all')
export async function markAllAsRead(type?: string) {
const res = await request.put<ApiResult<unknown>>('/app/notification/read-all', { type })
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -304,18 +363,28 @@ export async function markAllAsRead() {
* 删除通知
*/
export async function deleteNotification(id: number) {
const res = await request.del<ApiResult<unknown>>(`/notification/${id}`)
const res = await request.del<ApiResult<unknown>>(`/app/notification/${id}`)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
/**
* 清空已读通知
*/
export async function clearReadNotifications(type?: string) {
const res = await request.del<ApiResult<unknown>>('/app/notification/clear-read', { type })
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
// ==================== 权限审批相关 ====================
// 对应后端 AppPermissionRequestController路径为 /app/developer/permission-requests
/**
* 获取申请列表
*/
export async function pageApply(params?: ApplyParam) {
const res = await request.get<ApiResult<PageResult<Apply>>>('/apply/page', { params })
const res = await request.get<ApiResult<PageResult<Apply>>>('/app/developer/permission-requests/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -324,7 +393,25 @@ export async function pageApply(params?: ApplyParam) {
* 获取我的申请列表
*/
export async function pageMyApply(params?: ApplyParam) {
const res = await request.get<ApiResult<PageResult<Apply>>>('/apply/my/page', { params })
const res = await request.get<ApiResult<PageResult<Apply>>>('/app/developer/permission-requests', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
/**
* 获取权限申请统计
*/
export async function getApplyStats() {
const res = await request.get<ApiResult<{ [key: string]: number }>>('/app/developer/permission-requests/stats')
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
/**
* 获取可申请的仓库列表
*/
export async function getAvailableRepos() {
const res = await request.get<ApiResult<Array<{ name: string; fullName: string }>>>('/app/developer/permission-requests/available-repos')
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -332,17 +419,26 @@ export async function pageMyApply(params?: ApplyParam) {
/**
* 创建申请
*/
export async function createApply(data: Partial<Apply>) {
const res = await request.post<ApiResult<unknown>>('/apply', data)
export async function createApply(data: { repo: string; reason: string; gitUsername?: string }) {
const res = await request.post<ApiResult<unknown>>('/app/developer/permission-requests', data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
/**
* 审批申请
* 审批申请-通过
*/
export async function reviewApply(id: number, status: 'approved' | 'rejected', remark?: string) {
const res = await request.put<ApiResult<unknown>>(`/apply/${id}/review`, { status, remark })
export async function approveApply(id: number, note?: string) {
const res = await request.put<ApiResult<unknown>>(`/app/developer/permission-requests/${id}/approve`, { note })
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
/**
* 审批申请-拒绝
*/
export async function rejectApply(id: number, reason: string) {
const res = await request.put<ApiResult<unknown>>(`/app/developer/permission-requests/${id}/reject`, { reason })
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}

View File

@@ -2,13 +2,13 @@ import request from '@/utils/request'
import type { ApiResult, PageResult } from '@/api'
import type { Enterprise, EnterpriseMember, EnterpriseMemberParam, Order, Bill, BillParam, App, AppParam } from '@/types/developer'
// ==================== 企业相关 ====================
// ==================== 企业/租户相关 ====================
/**
* 获取企业信息
*/
export async function getEnterpriseInfo() {
const res = await request.get<ApiResult<Enterprise>>('/enterprise/info')
const res = await request.get<ApiResult<Enterprise>>('/system/tenant/info')
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -17,18 +17,18 @@ export async function getEnterpriseInfo() {
* 更新企业信息
*/
export async function updateEnterpriseInfo(data: Partial<Enterprise>) {
const res = await request.put<ApiResult<unknown>>('/enterprise/info', data)
const res = await request.put<ApiResult<unknown>>('/system/tenant', data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
// ==================== 企业成员相关 ====================
// ==================== 企业成员/用户相关 ====================
/**
* 获取企业成员列表
*/
export async function pageEnterpriseMember(params?: EnterpriseMemberParam) {
const res = await request.get<ApiResult<PageResult<EnterpriseMember>>>('/enterprise/member/page', { params })
const res = await request.get<ApiResult<PageResult<EnterpriseMember>>>('/system/user/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -37,7 +37,7 @@ export async function pageEnterpriseMember(params?: EnterpriseMemberParam) {
* 获取企业成员列表(不分页)
*/
export async function listEnterpriseMember(params?: EnterpriseMemberParam) {
const res = await request.get<ApiResult<EnterpriseMember[]>>('/enterprise/member', params)
const res = await request.get<ApiResult<EnterpriseMember[]>>('/system/user', params)
if (res.code === 0 && res.data) return res.data
return Promise.reject(new Error(res.message))
}
@@ -46,7 +46,7 @@ export async function listEnterpriseMember(params?: EnterpriseMemberParam) {
* 邀请企业成员
*/
export async function inviteEnterpriseMember(enterpriseId: number, data: Partial<EnterpriseMember>) {
const res = await request.post<ApiResult<unknown>>(`/enterprise/member/${enterpriseId}/invite`, data)
const res = await request.post<ApiResult<unknown>>(`/app/developer/invite/${enterpriseId}/invite`, data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -55,7 +55,7 @@ export async function inviteEnterpriseMember(enterpriseId: number, data: Partial
* 更新企业成员
*/
export async function updateEnterpriseMember(data: Partial<EnterpriseMember>) {
const res = await request.put<ApiResult<unknown>>(`/enterprise/member/${data.id}`, data)
const res = await request.put<ApiResult<unknown>>(`/system/user`, data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -64,7 +64,7 @@ export async function updateEnterpriseMember(data: Partial<EnterpriseMember>) {
* 移除企业成员
*/
export async function removeEnterpriseMember(memberId: number) {
const res = await request.del<ApiResult<unknown>>(`/enterprise/member/${memberId}`)
const res = await request.del<ApiResult<unknown>>(`/system/user/${memberId}`)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
@@ -75,7 +75,7 @@ export async function removeEnterpriseMember(memberId: number) {
* 获取订单列表
*/
export async function pageOrder(params?: { page?: number; limit?: number; status?: number }) {
const res = await request.get<ApiResult<PageResult<Order>>>('/enterprise/order/page', { params })
const res = await request.get<ApiResult<PageResult<Order>>>('/system/order/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -84,18 +84,27 @@ export async function pageOrder(params?: { page?: number; limit?: number; status
* 获取订单详情
*/
export async function getOrder(id: number) {
const res = await request.get<ApiResult<Order>>(`/enterprise/order/${id}`)
const res = await request.get<ApiResult<Order>>(`/system/order/${id}`)
if (res.code === 0 && res.data) return res.data
return Promise.reject(new Error(res.message))
}
// ==================== 账单相关 ====================
/**
* 创建订单
*/
export async function createOrder(data: any) {
const res = await request.post<ApiResult<unknown>>('/system/order', data)
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}
// ==================== 充值/账单相关 ====================
/**
* 获取账单列表
*/
export async function pageBill(params?: BillParam) {
const res = await request.get<ApiResult<PageResult<Bill>>>('/enterprise/bill/page', { params })
const res = await request.get<ApiResult<PageResult<Bill>>>('/sys/recharge-order/page', params)
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -104,7 +113,7 @@ export async function pageBill(params?: BillParam) {
* 获取账单概览
*/
export async function getBillOverview() {
const res = await request.get<ApiResult<{ balance: number; totalConsume: number; totalRecharge: number }>>('/enterprise/bill/overview')
const res = await request.get<ApiResult<{ balance: number; totalConsume: number; totalRecharge: number }>>('/sys/user-balance-log/overview')
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -115,7 +124,7 @@ export async function getBillOverview() {
* 获取企业应用列表
*/
export async function pageEnterpriseApp(params?: AppParam) {
const res = await request.get<ApiResult<PageResult<App>>>('/enterprise/app/page', { params })
const res = await request.get<ApiResult<PageResult<App>>>('/app/product/page', { params })
if (res.code === 0) return res.data
return Promise.reject(new Error(res.message))
}
@@ -124,7 +133,7 @@ export async function pageEnterpriseApp(params?: AppParam) {
* 获取企业应用详情
*/
export async function getEnterpriseApp(id: number) {
const res = await request.get<ApiResult<App>>(`/enterprise/app/${id}`)
const res = await request.get<ApiResult<App>>(`/app/product/${id}`)
if (res.code === 0 && res.data) return res.data
return Promise.reject(new Error(res.message))
}
@@ -133,7 +142,7 @@ export async function getEnterpriseApp(id: number) {
* 购买应用
*/
export async function purchaseApp(productId: number) {
const res = await request.post<ApiResult<unknown>>('/enterprise/app/purchase', { productId })
const res = await request.post<ApiResult<unknown>>('/api/system/order/createOrder', { productId })
if (res.code === 0) return res.message
return Promise.reject(new Error(res.message))
}

View File

@@ -3,7 +3,7 @@ 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 { pageMyApp, pageJoinedApp } from '@/api/developer'
import type { App } from '@/types/developer'
import { APP_TYPE_NAME } from '@/types/developer'
import './index.scss'
@@ -18,19 +18,45 @@ const DeveloperIndex: React.FC = () => {
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,
})
}
// 同时调用两个接口:创建的应用 + 参与的应用(通过邀请加入)
const [myAppsResult, joinedAppsResult] = await Promise.all([
pageMyApp({ current: 1, size: 10 }),
pageJoinedApp({ current: 1, size: 10 }),
])
// 合并两个列表,去重(根据 productId
const myApps = myAppsResult?.records || []
const joinedApps = joinedAppsResult?.records || []
// 使用 Map 去重,优先保留创建的应用(排在前面)
const appMap = new Map<number, App>()
// 先加入创建的应用
myApps.forEach((app) => {
if (app.productId) {
appMap.set(app.productId, { ...app, isOwner: true })
}
})
// 再加入参与的应用(如果已存在则跳过)
joinedApps.forEach((app) => {
if (app.productId && !appMap.has(app.productId)) {
appMap.set(app.productId, { ...app, isOwner: false })
}
})
const mergedApps = Array.from(appMap.values())
setApps(mergedApps)
setStats({
totalApps: mergedApps.length,
runningApps: mergedApps.filter((a) => a.status === 1).length,
totalCalls: 0,
})
} catch (error) {
console.error('加载数据失败', error)
Taro.showToast({ title: '加载失败', icon: 'none' })