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
@@ -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(`