diff --git a/.backups/autodeploy-1769232500/index.jsx b/.backups/autodeploy-1769232500/index.jsx index 52f2e0dc..9c223a72 100644 --- a/.backups/autodeploy-1769232500/index.jsx +++ b/.backups/autodeploy-1769232500/index.jsx @@ -29,11 +29,7 @@ const Sidebar = ({ config, setConfig, isDeploying, onStart, onReset, onCancel, e
- setConfig({ ...config, distDir: e.target.value })} - /> + setConfig({ ...config, distDir: e.target.value })} /> {errors.distDir &&
{errors.distDir}
}
@@ -73,14 +69,18 @@ const Sidebar = ({ config, setConfig, isDeploying, onStart, onReset, onCancel, e
- ); -}; + ) +} // 主应用组件 export default function AutoDeploy() { - const [isDeploying, setIsDeploying] = useState(false); - const [activeStep, setActiveStep] = useState(-1); - const [showResult, setShowResult] = useState(false); - const [statusText, setStatusText] = useState('系统就绪'); - const [statusType, setStatusType] = useState('idle'); // idle, warning, success - const [toast, setToast] = useState({ show: false, msg: '' }); + const [isDeploying, setIsDeploying] = useState(false) + const [activeStep, setActiveStep] = useState(-1) + const [showResult, setShowResult] = useState(false) + const [statusText, setStatusText] = useState('系统就绪') + const [statusType, setStatusType] = useState('idle') // idle, warning, success + const [toast, setToast] = useState({ show: false, msg: '' }) const [logs, setLogs] = useState([ { time: new Date().toLocaleTimeString(), message: 'AutoDeploy CLI v1.0.0 initialized...', type: 'logInfo' }, - { time: new Date().toLocaleTimeString(), message: 'Waiting for configuration...', type: 'logInfo' } - ]); + { time: new Date().toLocaleTimeString(), message: 'Waiting for configuration...', type: 'logInfo' }, + ]) const [config, setConfig] = useState({ repo: 'https://github.com/wkylin/pro-react-admin.git', @@ -168,206 +168,215 @@ export default function AutoDeploy() { distDir: 'dist', nginxPath: '/var/www/html/pro-react-admin', sshKey: '', - envVars: '' - }); + envVars: '', + }) - const [errors, setErrors] = useState({}); - const [currentJobId, setCurrentJobId] = useState(null); - const jobUnsubRef = useRef(null); + const [errors, setErrors] = useState({}) + const [currentJobId, setCurrentJobId] = useState(null) + const jobUnsubRef = useRef(null) - const [history, setHistory] = useState([]); + const [history, setHistory] = useState([]) // 工具函数:添加日志 const addLog = (message, type = 'logInfo') => { - setLogs(prev => [...prev, { - time: new Date().toLocaleTimeString(), - message, - type - }]); - }; + setLogs((prev) => [ + ...prev, + { + time: new Date().toLocaleTimeString(), + message, + type, + }, + ]) + } // 工具函数:延迟 - const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); + const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) useEffect(() => { try { - const saved = localStorage.getItem('autodeploy_config'); + const saved = localStorage.getItem('autodeploy_config') if (saved) { - const parsed = JSON.parse(saved); - setConfig(prev => ({ ...prev, ...parsed })); - addLog('Loaded saved configuration from localStorage', 'logInfo'); + const parsed = JSON.parse(saved) + setConfig((prev) => ({ ...prev, ...parsed })) + addLog('Loaded saved configuration from localStorage', 'logInfo') } } catch (e) { // ignore } try { - const h = localStorage.getItem('autodeploy_history'); - if (h) setHistory(JSON.parse(h)); + const h = localStorage.getItem('autodeploy_history') + if (h) setHistory(JSON.parse(h)) } catch (e) {} - }, []); + }, []) useEffect(() => { try { - localStorage.setItem('autodeploy_config', JSON.stringify({ - repo: config.repo, - buildCmd: config.buildCmd, - distDir: config.distDir, - nginxPath: config.nginxPath, - sshKey: config.sshKey, - envVars: config.envVars - })); + localStorage.setItem( + 'autodeploy_config', + JSON.stringify({ + repo: config.repo, + buildCmd: config.buildCmd, + distDir: config.distDir, + nginxPath: config.nginxPath, + sshKey: config.sshKey, + envVars: config.envVars, + }) + ) } catch (e) { // ignore } - }, [config]); + }, [config]) // persist history useEffect(() => { - try { localStorage.setItem('autodeploy_history', JSON.stringify(history)); } catch (e) {} - }, [history]); + try { + localStorage.setItem('autodeploy_history', JSON.stringify(history)) + } catch (e) {} + }, [history]) // 配置校验 const validateConfig = (c) => { - const errs = {}; - if (!c.repo || c.repo.trim() === '') errs.repo = '仓库地址不能为空'; - else if (!/^((git|https?):)|git@/.test(c.repo)) errs.repo = '仓库地址看起来不正确'; - if (!c.buildCmd || c.buildCmd.trim() === '') errs.buildCmd = '构建命令不能为空'; - if (!c.distDir || c.distDir.trim() === '') errs.distDir = '输出目录不能为空'; - if (!c.nginxPath || c.nginxPath.trim() === '') errs.nginxPath = 'Nginx 部署路径不能为空'; - return errs; - }; + const errs = {} + if (!c.repo || c.repo.trim() === '') errs.repo = '仓库地址不能为空' + else if (!/^((git|https?):)|git@/.test(c.repo)) errs.repo = '仓库地址看起来不正确' + if (!c.buildCmd || c.buildCmd.trim() === '') errs.buildCmd = '构建命令不能为空' + if (!c.distDir || c.distDir.trim() === '') errs.distDir = '输出目录不能为空' + if (!c.nginxPath || c.nginxPath.trim() === '') errs.nginxPath = 'Nginx 部署路径不能为空' + return errs + } const isConfigValid = useMemo(() => { - const errs = validateConfig(config); - setErrors(errs); - return Object.keys(errs).length === 0; + const errs = validateConfig(config) + setErrors(errs) + return Object.keys(errs).length === 0 // eslint-disable-next-line react-hooks/exhaustive-deps - }, [config.repo, config.buildCmd, config.distDir, config.nginxPath]); + }, [config.repo, config.buildCmd, config.distDir, config.nginxPath]) // 显示 Toast const showToast = (msg) => { - setToast({ show: true, msg }); - setTimeout(() => setToast({ show: false, msg: '' }), 3000); - }; + setToast({ show: true, msg }) + setTimeout(() => setToast({ show: false, msg: '' }), 3000) + } // 部署逻辑(通过 mockApi) const startDeployment = async () => { - if (isDeploying) return; + if (isDeploying) return - const validation = validateConfig(config); + const validation = validateConfig(config) if (Object.keys(validation).length > 0) { - setErrors(validation); - Object.values(validation).forEach(msg => addLog(msg, 'logError')); - showToast('请修正表单错误后再开始部署'); - return; + setErrors(validation) + Object.values(validation).forEach((msg) => addLog(msg, 'logError')) + showToast('请修正表单错误后再开始部署') + return } - setIsDeploying(true); - setShowResult(false); - setStatusText('正在部署...'); - setStatusType('warning'); - setLogs([]); + setIsDeploying(true) + setShowResult(false) + setStatusText('正在部署...') + setStatusType('warning') + setLogs([]) - const res = await mockApi.createJob(config); - const jobId = res.jobId; - setCurrentJobId(jobId); + const res = await mockApi.createJob(config) + const jobId = res.jobId + setCurrentJobId(jobId) // add history entry - const entry = { jobId, config: { ...config }, status: 'running', startedAt: Date.now(), logs: [] }; - setHistory(prev => [entry, ...prev]); + const entry = { jobId, config: { ...config }, status: 'running', startedAt: Date.now(), logs: [] } + setHistory((prev) => [entry, ...prev]) // subscribe - if (jobUnsubRef.current) jobUnsubRef.current(); + if (jobUnsubRef.current) jobUnsubRef.current() jobUnsubRef.current = mockApi.subscribe(jobId, (evt) => { if (evt.type === 'log') { - addLog(evt.payload.message, evt.payload.type); + addLog(evt.payload.message, evt.payload.type) // push to history latest - setHistory(prev => { - const copy = prev.slice(); - const idx = copy.findIndex(h => h.jobId === jobId); - if (idx >= 0) copy[idx] = { ...copy[idx], logs: [...copy[idx].logs, evt.payload] }; - return copy; - }); + setHistory((prev) => { + const copy = prev.slice() + const idx = copy.findIndex((h) => h.jobId === jobId) + if (idx >= 0) copy[idx] = { ...copy[idx], logs: [...copy[idx].logs, evt.payload] } + return copy + }) } if (evt.type === 'step') { - setActiveStep(evt.payload.step); + setActiveStep(evt.payload.step) } if (evt.type === 'status') { - const st = evt.payload.status; - setStatusText(st === 'success' ? '部署成功' : st === 'cancelled' ? '已取消' : '失败'); - setStatusType(st === 'success' ? 'success' : st === 'cancelled' ? 'idle' : 'warning'); - setIsDeploying(false); - setCurrentJobId(null); - setActiveStep(-1); - if (st === 'success') setShowResult(true); + const st = evt.payload.status + setStatusText(st === 'success' ? '部署成功' : st === 'cancelled' ? '已取消' : '失败') + setStatusType(st === 'success' ? 'success' : st === 'cancelled' ? 'idle' : 'warning') + setIsDeploying(false) + setCurrentJobId(null) + setActiveStep(-1) + if (st === 'success') setShowResult(true) // update history - setHistory(prev => { - const copy = prev.slice(); - const idx = copy.findIndex(h => h.jobId === jobId); - if (idx >= 0) copy[idx] = { ...copy[idx], status: st, finishedAt: Date.now() }; - return copy; - }); - if (jobUnsubRef.current) { jobUnsubRef.current(); jobUnsubRef.current = null; } + setHistory((prev) => { + const copy = prev.slice() + const idx = copy.findIndex((h) => h.jobId === jobId) + if (idx >= 0) copy[idx] = { ...copy[idx], status: st, finishedAt: Date.now() } + return copy + }) + if (jobUnsubRef.current) { + jobUnsubRef.current() + jobUnsubRef.current = null + } } - }); - }; + }) + } const cancelDeployment = async () => { - if (!currentJobId) return; - await mockApi.cancelJob(currentJobId); - showToast('已发送取消请求'); - }; + if (!currentJobId) return + await mockApi.cancelJob(currentJobId) + showToast('已发送取消请求') + } const retryDeployment = async (jobId) => { - const res = await mockApi.retryJob(jobId); + const res = await mockApi.retryJob(jobId) // reuse start flow by subscribing to new job - const newJobId = res.jobId; - setCurrentJobId(newJobId); - const entry = { jobId: newJobId, config: { ...config }, status: 'running', startedAt: Date.now(), logs: [] }; - setHistory(prev => [entry, ...prev]); - if (jobUnsubRef.current) jobUnsubRef.current(); + const newJobId = res.jobId + setCurrentJobId(newJobId) + const entry = { jobId: newJobId, config: { ...config }, status: 'running', startedAt: Date.now(), logs: [] } + setHistory((prev) => [entry, ...prev]) + if (jobUnsubRef.current) jobUnsubRef.current() jobUnsubRef.current = mockApi.subscribe(newJobId, (evt) => { - if (evt.type === 'log') addLog(evt.payload.message, evt.payload.type); - if (evt.type === 'step') setActiveStep(evt.payload.step); + if (evt.type === 'log') addLog(evt.payload.message, evt.payload.type) + if (evt.type === 'step') setActiveStep(evt.payload.step) if (evt.type === 'status') { - setIsDeploying(false); - setCurrentJobId(null); - setActiveStep(-1); - setHistory(prev => { - const copy = prev.slice(); - const idx = copy.findIndex(h => h.jobId === newJobId); - if (idx >= 0) copy[idx] = { ...copy[idx], status: evt.payload.status, finishedAt: Date.now() }; - return copy; - }); + setIsDeploying(false) + setCurrentJobId(null) + setActiveStep(-1) + setHistory((prev) => { + const copy = prev.slice() + const idx = copy.findIndex((h) => h.jobId === newJobId) + if (idx >= 0) copy[idx] = { ...copy[idx], status: evt.payload.status, finishedAt: Date.now() } + return copy + }) } - }); - setIsDeploying(true); - setStatusText('正在部署...'); - setStatusType('warning'); - }; + }) + setIsDeploying(true) + setStatusText('正在部署...') + setStatusType('warning') + } const viewHistoryLogs = (jobId) => { - const h = history.find(h => h.jobId === jobId); - if (!h) return; - setLogs(h.logs || []); - setStatusText(`查看历史 ${jobId}`); - }; + const h = history.find((h) => h.jobId === jobId) + if (!h) return + setLogs(h.logs || []) + setStatusText(`查看历史 ${jobId}`) + } const resetDeployment = () => { - if (isDeploying) return; - setActiveStep(-1); - setShowResult(false); - setLogs([ - { time: new Date().toLocaleTimeString(), message: 'Ready to start new deployment.', type: 'logInfo' } - ]); - setStatusText('系统就绪'); - setStatusType('idle'); - }; + if (isDeploying) return + setActiveStep(-1) + setShowResult(false) + setLogs([{ time: new Date().toLocaleTimeString(), message: 'Ready to start new deployment.', type: 'logInfo' }]) + setStatusText('系统就绪') + setStatusType('idle') + } const openProject = () => { - showToast("正在在新标签页打开应用..."); + showToast('正在在新标签页打开应用...') setTimeout(() => { - const win = window.open('', '_blank'); + const win = window.open('', '_blank') if (win) { win.document.write(`