import React, { useState, useEffect } from 'react' import { View, Text, Button, Input } from '@tarojs/components' import Taro, { useRouter } from '@tarojs/taro' import { usePullDownRefresh } from '@tarojs/taro' import { pageVersion, createVersion } from '@/api/developer/developer' import type { Version, VersionParam, VersionStatus, PublishEnv } from '@/types/developer' import './version.scss' // 状态配置 const STATUS_CONFIG: Record = { 0: { label: '构建中', color: '#faad14', bgColor: '#fffbe6' }, 1: { label: '已发布', color: '#52c41a', bgColor: '#f6ffed' }, 2: { label: '已回滚', color: '#ff4d4f', bgColor: '#fff1f0' }, 3: { label: '构建失败', color: '#f5222d', bgColor: '#fff1f0' }, } // 环境配置 const ENV_CONFIG: Record = { development: { label: '开发环境', color: '#722ed1' }, staging: { label: '预发布环境', color: '#1890ff' }, production: { label: '生产环境', color: '#52c41a' }, } const VersionPage: React.FC = () => { const router = useRouter() const appId = Number(router.params.id) const [loading, setLoading] = useState(false) const [refreshing, setRefreshing] = useState(false) const [list, setList] = useState([]) const [page, setPage] = useState(1) const [hasMore, setHasMore] = useState(true) const [showCreate, setShowCreate] = useState(false) const [createForm, setCreateForm] = useState({ versionName: '', versionNo: '', changelog: '', env: 'staging' as PublishEnv, }) const [creating, setCreating] = useState(false) const [currentTab, setCurrentTab] = useState('all') // 加载数据 const loadData = async (pageNum: number = 1, isRefresh = false) => { if (loading) return setLoading(true) if (isRefresh) setRefreshing(true) try { const params: VersionParam = { page: pageNum, limit: 20, websiteId: appId, env: currentTab === 'all' ? undefined : currentTab, } const data = await pageVersion(params) if (pageNum === 1) { setList(data?.records || []) } else { setList(prev => [...prev, ...(data?.records || [])]) } const total = data?.total || 0 const records = data?.records || [] setHasMore(records.length > 0 && (pageNum * 20) < total) setPage(pageNum) } catch (err) { console.error('加载失败', err) Taro.showToast({ title: '加载失败', icon: 'none' }) } finally { setLoading(false) setRefreshing(false) } } useEffect(() => { loadData(1) }, [appId, currentTab]) // 下拉刷新 usePullDownRefresh(() => { loadData(1, true) }) // 加载更多 const onReachBottom = () => { if (hasMore && !loading) { loadData(page + 1) } } // 创建版本 const handleCreate = async () => { if (!createForm.versionName.trim()) { Taro.showToast({ title: '请输入版本名称', icon: 'none' }) return } if (!createForm.versionNo.trim()) { Taro.showToast({ title: '请输入版本号', icon: 'none' }) return } setCreating(true) try { await createVersion({ websiteId: appId, versionName: createForm.versionName, versionNo: createForm.versionNo, changelog: createForm.changelog, env: createForm.env, } as Partial) Taro.showToast({ title: '发布成功', icon: 'success' }) setShowCreate(false) setCreateForm({ versionName: '', versionNo: '', changelog: '', env: 'staging' }) loadData(1) } catch (err) { console.error('发布失败', err) Taro.showToast({ title: '发布失败', icon: 'none' }) } finally { setCreating(false) } } // 发布新版本 const handlePublish = () => { if (list.some(v => v.status === 0)) { Taro.showToast({ title: '有版本正在构建中', icon: 'none' }) return } setShowCreate(true) } // 格式化日期 const formatDate = (dateStr?: string) => { if (!dateStr) return '-' const date = new Date(dateStr) return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}` } // 格式化文件大小 const formatSize = (size?: string) => { if (!size) return '-' if (size.length < 4) return size const num = parseFloat(size) if (num >= 1024 * 1024) { return (num / (1024 * 1024)).toFixed(2) + ' MB' } else if (num >= 1024) { return (num / 1024).toFixed(2) + ' KB' } return size + ' B' } // Tab 配置 const tabs: { key: PublishEnv | 'all'; label: string }[] = [ { key: 'all', label: '全部' }, { key: 'development', label: '开发' }, { key: 'staging', label: '预发布' }, { key: 'production', label: '生产' }, ] return ( {/* 头部 */} 📦 版本管理 {/* 环境 Tab */} {tabs.map((tab) => ( setCurrentTab(tab.key)} > {tab.label} ))} {/* 列表 */} {list.length === 0 && !loading ? ( 暂无版本记录 点击「发布版本」创建新版本 ) : ( list.map((item) => ( {item.versionName || `v${item.versionNo}`} {STATUS_CONFIG[item.status as VersionStatus]?.label} {ENV_CONFIG[item.env as PublishEnv]?.label} {item.isCurrent && ( 当前版本 )} {item.versionNo && ( 版本号: {item.versionNo} )} {item.packageSize && ( 包大小: {formatSize(item.packageSize)} )} {item.publishBy && ( 发布人: {item.publishBy} )} {item.publishTime && ( 发布时间: {formatDate(item.publishTime)} )} {item.changelog && ( 更新日志: {item.changelog} )} 创建于 {formatDate(item.createTime)} )) )} {/* 加载状态 */} {loading && list.length > 0 && ( 加载中... )} {!hasMore && list.length > 0 && ( 没有更多了 )} {/* 发布弹窗 */} {showCreate && ( setShowCreate(false)} /> 发布新版本 版本名称 * setCreateForm(prev => ({ ...prev, versionName: e.detail.value }))} /> 版本号 * setCreateForm(prev => ({ ...prev, versionNo: e.detail.value }))} /> 发布环境 {(['staging', 'production'] as const).map((env) => ( setCreateForm(prev => ({ ...prev, env }))} > {ENV_CONFIG[env].label} ))} 更新日志