const { Client } = require('ssh2'); const fs = require('fs'); const path = require('path'); const conn = new Client(); const uploadDir = (sftp, localDir, remoteDir) => { return new Promise((resolve, reject) => { fs.readdir(localDir, (err, files) => { if (err) return reject(err); sftp.mkdir(remoteDir, { recursive: true }, (mkdirErr) => { if (mkdirErr && mkdirErr.code !== 4) return reject(mkdirErr); let completed = 0; if (files.length === 0) return resolve(); files.forEach(file => { const localPath = path.join(localDir, file); const remotePath = remoteDir + '/' + file; fs.stat(localPath, (statErr, stats) => { if (statErr) return reject(statErr); if (stats.isDirectory()) { uploadDir(sftp, localPath, remotePath) .then(() => { completed++; if (completed === files.length) resolve(); }) .catch(reject); } else { fs.readFile(localPath, (readErr, data) => { if (readErr) return reject(readErr); const writeStream = sftp.createWriteStream(remotePath); writeStream.write(data); writeStream.end(); writeStream.on('close', () => { completed++; if (completed === files.length) resolve(); }); writeStream.on('error', reject); }); } }); }); }); }); }); }; conn.on('ready', () => { console.log('=== 上传H5文件 ==='); conn.sftp((err, sftp) => { if (err) { console.log('SFTP ERR:', err); conn.end(); return; } const localH5Dir = 'dist/build/h5'; const remoteH5Dir = '/www/huishou/dist/build/h5'; uploadDir(sftp, localH5Dir, remoteH5Dir) .then(() => { console.log('H5文件上传成功'); console.log('\n=== 上传site_users.json ==='); const siteUsersContent = fs.readFileSync('server/data/site_users.json', 'utf-8'); const siteUsersStream = sftp.createWriteStream('/www/huishou/server/data/site_users.json'); siteUsersStream.write(siteUsersContent); siteUsersStream.end(); siteUsersStream.on('close', () => { console.log('site_users.json上传成功'); sftp.end(); console.log('\n=== 重新启动容器 ==='); conn.exec('cd /www/huishou && docker-compose restart', (err2, stream2) => { if (err2) { console.log('ERR2:', err2); conn.end(); return; } stream2.on('data', (d) => console.log(d.toString())); stream2.on('close', () => { setTimeout(() => { console.log('\n=== 检查服务状态 ==='); conn.exec('curl -s -o /dev/null -w "%{http_code}" https://hs.yifenbao.cn/h5/', (err3, stream3) => { if (err3) { console.log('ERR3:', err3); conn.end(); return; } stream3.on('data', (d) => { const code = d.toString().trim(); console.log('H5页面状态码:', code); if (code === '200') { console.log('\n✅ 部署成功!'); } else { console.log('\n⚠️ H5页面状态异常:', code); } }); stream3.on('close', () => conn.end()); }); }, 5000); }); }); }); }) .catch((uploadErr) => { console.log('上传失败:', uploadErr); sftp.end(); conn.end(); }); }); }); conn.connect({ host: 'hs.yifenbao.cn', port: 22, username: 'root', password: 'Torch1112' });