/** * 构建列表页面 */ import { useState, useEffect } from 'react' import { View, Text, ScrollView, Input } from '@tarojs/components' import Taro from '@tarojs/taro' import { AtButton, AtTabs, AtTabsPane, AtTag, AtActivityIndicator } from 'taro-ui' import { pageBuild, triggerBuild, cancelBuild } from '../../../../api/cicd' import type { Build, BuildStatus } from '../../../../types/cicd' import './builds.scss' // 状态映射 const STATUS_MAP: Record = { pending: { text: '等待中', color: '#FFC107' }, running: { text: '构建中', color: '#2196F3' }, success: { text: '构建成功', color: '#4CAF50' }, failed: { text: '构建失败', color: '#F44336' }, cancelled: { text: '已取消', color: '#9E9E9E' }, } export default function Builds() { const [loading, setLoading] = useState(true) const [builds, setBuilds] = useState([]) const [total, setTotal] = useState(0) const [page, setPage] = useState(1) const [hasMore, setHasMore] = useState(true) const [status, setStatus] = useState('') const [keyword, setKeyword] = useState('') const [appId, setAppId] = useState('') // 获取构建列表 const fetchBuilds = async (pageNum = 1, reset = false) => { try { const res = await pageBuild({ page: pageNum, limit: 20, websiteId: Number(appId), status: status || undefined, }) if (res.data) { if (reset) { setBuilds(res.data.list || []) } else { setBuilds(prev => [...prev, ...(res.data?.list || [])]) } setTotal(res.data.total || 0) setHasMore((res.data.list || []).length === 20) setPage(pageNum) } } catch (err) { console.error('获取构建列表失败', err) } finally { setLoading(false) } } useEffect(() => { const pages = Taro.getCurrentPages() const current = pages[pages.length - 1] if (current?.options?.appId) { setAppId(current.options.appId) } }, []) useEffect(() => { if (appId) { fetchBuilds(1, true) } }, [appId, status]) // 触发构建 const handleTriggerBuild = async () => { if (!appId) return Taro.showModal({ title: '提示', content: '确定要触发新的构建吗?', success: async (res) => { if (res.confirm) { try { Taro.showLoading({ title: '触发中...' }) await triggerBuild({ websiteId: Number(appId) }) Taro.showToast({ title: '构建已触发', icon: 'success' }) fetchBuilds(1, true) } catch (err) { Taro.showToast({ title: '触发失败', icon: 'none' }) } finally { Taro.hideLoading() } } }, }) } // 取消构建 const handleCancelBuild = async (buildId: number) => { Taro.showModal({ title: '提示', content: '确定要取消该构建吗?', success: async (res) => { if (res.confirm) { try { Taro.showLoading({ title: '取消中...' }) await cancelBuild(buildId) Taro.showToast({ title: '已取消', icon: 'success' }) fetchBuilds(page, true) } catch (err) { Taro.showToast({ title: '取消失败', icon: 'none' }) } finally { Taro.hideLoading() } } }, }) } // 查看构建详情 const goToBuildDetail = (buildId: number) => { Taro.navigateTo({ url: `/developer/app/${appId}/build/${buildId}`, }) } // 加载更多 const handleLoadMore = () => { if (hasMore && !loading) { fetchBuilds(page + 1) } } // 格式化时间 const formatTime = (time?: string) => { if (!time) return '-' const date = new Date(time) return `${date.getMonth() + 1}/${date.getDate()} ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}` } // 格式化时长 const formatDuration = (seconds?: number) => { if (!seconds) return '-' if (seconds < 60) return `${seconds}s` const mins = Math.floor(seconds / 60) const secs = seconds % 60 return `${mins}m ${secs}s` } const tabs = [ { title: '全部' }, { title: '等待中' }, { title: '构建中' }, { title: '成功' }, { title: '失败' }, ] return ( {/* 搜索栏 */} setKeyword(e.detail.value)} /> 触发构建 {/* 状态筛选 */} { if (status === '') return t.title === '全部' return STATUS_MAP[status]?.text === t.title })} tabList={tabs} scroll onClick={(index) => { const statusMap: (BuildStatus | '')[] = ['', 'pending', 'running', 'success', 'failed'] setStatus(statusMap[index]) }} > {loading && builds.length === 0 ? ( 加载中... ) : builds.length === 0 ? ( 暂无构建记录 ) : ( builds.map((build) => ( build.id && goToBuildDetail(build.id)} > #{build.buildNo || build.id} {STATUS_MAP[build.status || 'pending'].text} {build.branch || 'main'} {build.commitId?.slice(0, 7)} {build.commitMessage} {build.author} {formatTime(build.createTime)} {formatDuration(build.duration)} {build.status === 'pending' || build.status === 'running' ? ( { e.stopPropagation() build.id && handleCancelBuild(build.id) }} > 取消 ) : null} )) )} {loading && builds.length > 0 && ( )} {!hasMore && builds.length > 0 && ( 没有更多了 )} ) }