Compare commits
4 Commits
main
...
release1.
| Author | SHA1 | Date |
|---|---|---|
|
|
2195e44429 | |
|
|
9a5a399818 | |
|
|
8008ec8b35 | |
|
|
5e59f350b6 |
|
|
@ -8,3 +8,6 @@ BASE_DOMAIN=
|
||||||
# 项目端口范围
|
# 项目端口范围
|
||||||
PROJECT_PORT_START=9000
|
PROJECT_PORT_START=9000
|
||||||
PROJECT_PORT_END=9100
|
PROJECT_PORT_END=9100
|
||||||
|
|
||||||
|
# JWT密钥(生产环境请修改为安全的随机字符串)
|
||||||
|
JWT_SECRET=your-secure-secret-key-change-this
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,16 @@ cd ..
|
||||||
cat > .env << EOF
|
cat > .env << EOF
|
||||||
PORT=8888
|
PORT=8888
|
||||||
JWT_SECRET=your-secure-secret-key-change-this
|
JWT_SECRET=your-secure-secret-key-change-this
|
||||||
HOST=your-server-ip
|
BASE_DOMAIN=your-domain.com
|
||||||
|
PROJECT_PORT_START=9000
|
||||||
|
PROJECT_PORT_END=9100
|
||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
|
默认登录账号:
|
||||||
|
- 用户名: admin
|
||||||
|
- 密码: 1221xian
|
||||||
|
|
||||||
### 4. 启动服务
|
### 4. 启动服务
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
16
README.md
16
README.md
|
|
@ -73,7 +73,7 @@ npm start
|
||||||
### 默认账号
|
### 默认账号
|
||||||
|
|
||||||
- 用户名: `admin`
|
- 用户名: `admin`
|
||||||
- 密码: `admin123`
|
- 密码: `1221xian`
|
||||||
|
|
||||||
## 使用指南
|
## 使用指南
|
||||||
|
|
||||||
|
|
@ -81,8 +81,18 @@ npm start
|
||||||
|
|
||||||
1. 点击右上角「新建项目」按钮
|
1. 点击右上角「新建项目」按钮
|
||||||
2. 填写项目名称和描述
|
2. 填写项目名称和描述
|
||||||
3. 拖拽或点击上传项目文件
|
3. (可选)填写项目路径,例如 `/demo/lot-demo`
|
||||||
4. 点击「创建项目」完成
|
4. 拖拽或点击上传项目文件
|
||||||
|
5. 点击「创建项目」完成
|
||||||
|
|
||||||
|
### 项目路径说明
|
||||||
|
|
||||||
|
项目路径用于自定义项目的访问URL:
|
||||||
|
|
||||||
|
- 格式:以 `/` 开头的相对路径,如 `/demo/lot-demo`
|
||||||
|
- 访问URL格式:`http://域名:端口/项目路径`
|
||||||
|
- 示例:项目路径 `/demo/lot-demo`,端口 `9000`,则访问地址为 `http://localhost:9000/demo/lot-demo`
|
||||||
|
- 用途:支持同一域名下部署多个项目,通过不同路径区分
|
||||||
|
|
||||||
### 部署项目
|
### 部署项目
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,18 @@
|
||||||
></textarea>
|
></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">项目路径</label>
|
||||||
|
<input
|
||||||
|
v-model="form.path"
|
||||||
|
type="text"
|
||||||
|
class="input"
|
||||||
|
placeholder="例如:/demo/lot-demo"
|
||||||
|
/>
|
||||||
|
<p class="text-xs text-gray-500 mt-1">以"/"开头的相对路径,用于生成完整访问URL</p>
|
||||||
|
<p v-if="form.path && pathPreview" class="text-xs text-primary-600 mt-1">预览: {{ pathPreview }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">项目文件 *</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">项目文件 *</label>
|
||||||
|
|
||||||
|
|
@ -137,7 +149,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive, computed } from 'vue'
|
||||||
import { useProjectStore } from '../stores/project'
|
import { useProjectStore } from '../stores/project'
|
||||||
|
|
||||||
const emit = defineEmits(['close', 'success'])
|
const emit = defineEmits(['close', 'success'])
|
||||||
|
|
@ -152,9 +164,20 @@ const uploadProgress = ref(0)
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
|
path: '',
|
||||||
files: []
|
files: []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const pathPreview = computed(() => {
|
||||||
|
if (!form.path) return ''
|
||||||
|
let path = form.path.trim()
|
||||||
|
if (!path.startsWith('/')) {
|
||||||
|
path = '/' + path
|
||||||
|
}
|
||||||
|
const baseUrl = window.location.origin
|
||||||
|
return `${baseUrl}${path}`
|
||||||
|
})
|
||||||
|
|
||||||
const triggerFileInput = () => {
|
const triggerFileInput = () => {
|
||||||
fileInput.value?.click()
|
fileInput.value?.click()
|
||||||
}
|
}
|
||||||
|
|
@ -188,6 +211,11 @@ const handleSubmit = async () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let projectPath = form.path.trim()
|
||||||
|
if (projectPath && !projectPath.startsWith('/')) {
|
||||||
|
projectPath = '/' + projectPath
|
||||||
|
}
|
||||||
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
error.value = ''
|
error.value = ''
|
||||||
uploadProgress.value = 0
|
uploadProgress.value = 0
|
||||||
|
|
@ -196,6 +224,7 @@ const handleSubmit = async () => {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('name', form.name)
|
formData.append('name', form.name)
|
||||||
formData.append('description', form.description)
|
formData.append('description', form.description)
|
||||||
|
formData.append('path', projectPath)
|
||||||
|
|
||||||
form.files.forEach(file => {
|
form.files.forEach(file => {
|
||||||
formData.append('files', file)
|
formData.append('files', file)
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,10 @@
|
||||||
<dt class="text-sm text-gray-500">更新时间</dt>
|
<dt class="text-sm text-gray-500">更新时间</dt>
|
||||||
<dd class="text-sm font-medium text-gray-900 mt-1">{{ formatDateTime(project.updatedAt) }}</dd>
|
<dd class="text-sm font-medium text-gray-900 mt-1">{{ formatDateTime(project.updatedAt) }}</dd>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="project.path">
|
||||||
|
<dt class="text-sm text-gray-500">项目路径</dt>
|
||||||
|
<dd class="text-sm font-medium text-gray-900 mt-1 font-mono">{{ project.path }}</dd>
|
||||||
|
</div>
|
||||||
<div v-if="project.lastDeployed">
|
<div v-if="project.lastDeployed">
|
||||||
<dt class="text-sm text-gray-500">最后部署</dt>
|
<dt class="text-sm text-gray-500">最后部署</dt>
|
||||||
<dd class="text-sm font-medium text-gray-900 mt-1">{{ formatDateTime(project.lastDeployed) }}</dd>
|
<dd class="text-sm font-medium text-gray-900 mt-1">{{ formatDateTime(project.lastDeployed) }}</dd>
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T04:58:11.547Z",
|
|
||||||
"message": "Extracted dist.zip",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T04:58:11.965Z",
|
|
||||||
"message": "Project \"loT-demo\" created with 4 file(s)",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T04:58:19.431Z",
|
|
||||||
"message": "Project started on port 9000",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T04:58:36.076Z",
|
|
||||||
"message": "Project stopped",
|
|
||||||
"type": "info"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:04:00.097Z",
|
|
||||||
"message": "Project started on port 9001",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:04:56.824Z",
|
|
||||||
"message": "Project stopped",
|
|
||||||
"type": "info"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:43:59.981Z",
|
|
||||||
"message": "Project started on port 9000",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:48:32.620Z",
|
|
||||||
"message": "Project stopped",
|
|
||||||
"type": "info"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:48:33.171Z",
|
|
||||||
"message": "Project started on port 9000",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:57:37.014Z",
|
|
||||||
"message": "Project stopped",
|
|
||||||
"type": "info"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:03:36.023Z",
|
|
||||||
"message": "Extracted dist.zip",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:03:36.120Z",
|
|
||||||
"message": "Project \"rushe-demo\" created with 3 file(s)",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:03:44.138Z",
|
|
||||||
"message": "Project started on port 9000",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:05:11.825Z",
|
|
||||||
"message": "Project stopped",
|
|
||||||
"type": "info"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:09:33.720Z",
|
|
||||||
"message": "Project started on port 9000",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:28:22.481Z",
|
|
||||||
"message": "Project stopped",
|
|
||||||
"type": "info"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:28:23.286Z",
|
|
||||||
"message": "Project started on port 9000",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:28:28.136Z",
|
|
||||||
"message": "Project stopped",
|
|
||||||
"type": "info"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:44:04.885Z",
|
|
||||||
"message": "Project started on port 9001",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:48:30.005Z",
|
|
||||||
"message": "Project stopped",
|
|
||||||
"type": "info"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:48:37.640Z",
|
|
||||||
"message": "Project started on port 9001",
|
|
||||||
"type": "success"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"timestamp": "2026-02-23T05:57:34.667Z",
|
|
||||||
"message": "Project stopped",
|
|
||||||
"type": "info"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
@ -1,63 +1 @@
|
||||||
[
|
[]
|
||||||
{
|
|
||||||
"id": "1771822691510",
|
|
||||||
"name": "loT-demo",
|
|
||||||
"description": "智慧楼宇demo演示",
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"name": "assets\\index-csziwVZn.css",
|
|
||||||
"size": 28375,
|
|
||||||
"hash": "6e9e99cb0161d7c6ca05aa04d421c424"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "assets\\index-Ii3hNxW3.js",
|
|
||||||
"size": 2046014,
|
|
||||||
"hash": "3cd425f9f0c4e0540ac6c2d63280f821"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "index.html",
|
|
||||||
"size": 787,
|
|
||||||
"hash": "907b8098cc7855605955cddd567f7c74"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "vite.svg",
|
|
||||||
"size": 633,
|
|
||||||
"hash": "3208e1714d3d4aff82769f80952b2960"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"status": "stopped",
|
|
||||||
"port": null,
|
|
||||||
"url": null,
|
|
||||||
"createdAt": "2026-02-23T04:58:11.965Z",
|
|
||||||
"updatedAt": "2026-02-23T04:58:11.965Z",
|
|
||||||
"lastDeployed": "2026-02-23T05:48:33.170Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "1771823016002",
|
|
||||||
"name": "rushe-demo",
|
|
||||||
"description": "入舍家装改造demo",
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"name": "assets\\index-DtArR4F6.js",
|
|
||||||
"size": 416147,
|
|
||||||
"hash": "9c55c3f179e1bc5bf03baf01ccaa7479"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "assets\\index-gvDC5mON.css",
|
|
||||||
"size": 25321,
|
|
||||||
"hash": "7da89693bde15e541205dbc19aee46a5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "index.html",
|
|
||||||
"size": 572,
|
|
||||||
"hash": "831e97d4a3f00617843c3c797098842b"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"status": "stopped",
|
|
||||||
"port": null,
|
|
||||||
"url": null,
|
|
||||||
"createdAt": "2026-02-23T05:03:36.120Z",
|
|
||||||
"updatedAt": "2026-02-23T05:03:36.120Z",
|
|
||||||
"lastDeployed": "2026-02-23T05:48:37.640Z"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
@ -120,7 +120,7 @@ curl http://localhost:8888
|
||||||
|
|
||||||
- **主系统**: http://ashai.com.cn:8888 或 http://49.232.209.156:8888
|
- **主系统**: http://ashai.com.cn:8888 或 http://49.232.209.156:8888
|
||||||
- **默认账号**: admin
|
- **默认账号**: admin
|
||||||
- **默认密码**: admin123
|
- **默认密码**: 1221xian
|
||||||
|
|
||||||
## 常用命令
|
## 常用命令
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,6 @@ echo 访问地址: http://%DOMAIN%:8888
|
||||||
echo 或者: http://%SERVER_IP%:8888
|
echo 或者: http://%SERVER_IP%:8888
|
||||||
echo.
|
echo.
|
||||||
echo 默认账号: admin
|
echo 默认账号: admin
|
||||||
echo 默认密码: admin123
|
echo 默认密码: 1221xian
|
||||||
echo.
|
echo.
|
||||||
pause
|
pause
|
||||||
|
|
|
||||||
|
|
@ -5,109 +5,88 @@ $DEPLOY_DIR = "/home/ai-auto/auto-deploy-demo"
|
||||||
$DOMAIN = "ashai.com.cn"
|
$DOMAIN = "ashai.com.cn"
|
||||||
|
|
||||||
Write-Host "=========================================="
|
Write-Host "=========================================="
|
||||||
Write-Host " 自动部署脚本 - 快速Demo演示系统"
|
Write-Host " Auto Deploy Script - Demo System"
|
||||||
Write-Host "=========================================="
|
Write-Host "=========================================="
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
|
||||||
Write-Host "[提示] 请确保已安装OpenSSH客户端"
|
Write-Host "[Tip] Make sure OpenSSH client is installed"
|
||||||
Write-Host "Windows 10/11 可在 '设置 > 应用 > 可选功能' 中安装"
|
Write-Host "Windows 10/11: Settings > Apps > Optional Features"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "即将开始部署,请准备好输入服务器密码: $SERVER_PASS"
|
Write-Host "Server password: $SERVER_PASS"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Read-Host "按Enter键继续..."
|
Read-Host "Press Enter to continue..."
|
||||||
|
|
||||||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||||||
Set-Location $projectRoot
|
Set-Location $projectRoot
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "[1/8] 测试SSH连接..."
|
Write-Host "[1/8] Testing SSH connection..."
|
||||||
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$SERVER_USER@$SERVER_IP" "echo 'SSH连接成功'"
|
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$SERVER_USER@$SERVER_IP" "echo 'SSH connected'"
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Write-Host "[错误] 无法连接到服务器" -ForegroundColor Red
|
Write-Host "[Error] Cannot connect to server" -ForegroundColor Red
|
||||||
Read-Host "按Enter键退出"
|
Read-Host "Press Enter to exit"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "[2/8] 安装Node.js环境..."
|
Write-Host "[2/8] Installing Node.js..."
|
||||||
ssh "$SERVER_USER@$SERVER_IP" @"
|
$installNodeCmd = "if ! command -v node &> /dev/null; then echo 'Installing Node.js...'; curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -; sudo yum install -y nodejs; fi; echo 'Node version:' `$(`node -v); echo 'NPM version:' `$(`npm -v)"
|
||||||
if ! command -v node &> /dev/null; then
|
ssh "$SERVER_USER@$SERVER_IP" $installNodeCmd
|
||||||
echo '正在安装Node.js...'
|
|
||||||
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
|
|
||||||
sudo yum install -y nodejs
|
|
||||||
fi
|
|
||||||
echo 'Node.js版本:' `$(node -v)
|
|
||||||
echo 'NPM版本:' `$(npm -v)
|
|
||||||
"@
|
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "[3/8] 安装PM2进程管理器..."
|
Write-Host "[3/8] Installing PM2..."
|
||||||
ssh "$SERVER_USER@$SERVER_IP" @"
|
$installPm2Cmd = "if ! command -v pm2 &> /dev/null; then sudo npm install -g pm2; fi; echo 'PM2 version:' `$(`pm2 -v)"
|
||||||
if ! command -v pm2 &> /dev/null; then
|
ssh "$SERVER_USER@$SERVER_IP" $installPm2Cmd
|
||||||
sudo npm install -g pm2
|
|
||||||
fi
|
|
||||||
echo 'PM2版本:' `$(pm2 -v)
|
|
||||||
"@
|
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "[4/8] 创建项目目录..."
|
Write-Host "[4/8] Creating project directory..."
|
||||||
ssh "$SERVER_USER@$SERVER_IP" "mkdir -p $DEPLOY_DIR"
|
ssh "$SERVER_USER@$SERVER_IP" "mkdir -p $DEPLOY_DIR"
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "[5/8] 上传项目文件..."
|
Write-Host "[5/8] Uploading project files..."
|
||||||
Write-Host "上传server目录..."
|
Write-Host "Uploading server directory..."
|
||||||
scp -r "$projectRoot\server" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
scp -r "$projectRoot\server" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
||||||
|
|
||||||
Write-Host "上传projects目录..."
|
Write-Host "Uploading projects directory..."
|
||||||
scp -r "$projectRoot\projects" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
scp -r "$projectRoot\projects" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
||||||
|
|
||||||
Write-Host "上传client/dist目录..."
|
Write-Host "Uploading client/dist directory..."
|
||||||
ssh "$SERVER_USER@$SERVER_IP" "mkdir -p $DEPLOY_DIR/client"
|
ssh "$SERVER_USER@$SERVER_IP" "mkdir -p $DEPLOY_DIR/client/dist"
|
||||||
scp -r "$projectRoot\client\dist\*" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/client/dist/"
|
scp -r "$projectRoot\client\dist\*" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/client/dist/"
|
||||||
|
|
||||||
Write-Host "上传配置文件..."
|
Write-Host "Uploading config files..."
|
||||||
scp "$projectRoot\package.json" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
scp "$projectRoot\package.json" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
||||||
scp "$projectRoot\package-lock.json" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
scp "$projectRoot\package-lock.json" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
||||||
scp "$projectRoot\.env" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
scp "$projectRoot\.env" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "[6/8] 安装项目依赖..."
|
Write-Host "[6/8] Installing dependencies..."
|
||||||
ssh "$SERVER_USER@$SERVER_IP" "cd $DEPLOY_DIR && npm install --production"
|
ssh "$SERVER_USER@$SERVER_IP" "cd $DEPLOY_DIR && npm install --production"
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "[7/8] 配置防火墙..."
|
Write-Host "[7/8] Configuring firewall..."
|
||||||
ssh "$SERVER_USER@$SERVER_IP" @"
|
$firewallCmd = "sudo firewall-cmd --permanent --add-port=8888/tcp; sudo firewall-cmd --permanent --add-port=9000-9100/tcp; sudo firewall-cmd --reload; echo 'Firewall configured'"
|
||||||
sudo firewall-cmd --permanent --add-port=8888/tcp
|
ssh "$SERVER_USER@$SERVER_IP" $firewallCmd
|
||||||
sudo firewall-cmd --permanent --add-port=9000-9100/tcp
|
|
||||||
sudo firewall-cmd --reload
|
|
||||||
echo '防火墙配置完成'
|
|
||||||
"@
|
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "[8/8] 启动服务..."
|
Write-Host "[8/8] Starting service..."
|
||||||
ssh "$SERVER_USER@$SERVER_IP" @"
|
$startCmd = "cd $DEPLOY_DIR; pm2 delete all 2>/dev/null; pm2 start server/index.js --name 'auto-deploy-demo'; pm2 save; pm2 startup | tail -n 1 | sudo bash 2>/dev/null; echo 'Service started'"
|
||||||
cd $DEPLOY_DIR
|
ssh "$SERVER_USER@$SERVER_IP" $startCmd
|
||||||
pm2 delete all 2>/dev/null || true
|
|
||||||
pm2 start server/index.js --name 'auto-deploy-demo'
|
|
||||||
pm2 save
|
|
||||||
pm2 startup | tail -n 1 | sudo bash 2>/dev/null || true
|
|
||||||
echo '服务启动完成'
|
|
||||||
"@
|
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "=========================================="
|
Write-Host "=========================================="
|
||||||
Write-Host " 部署完成!"
|
Write-Host " Deployment Complete!"
|
||||||
Write-Host "=========================================="
|
Write-Host "=========================================="
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "访问地址: http://$DOMAIN`:8888" -ForegroundColor Green
|
Write-Host "URL: http://$DOMAIN`:8888" -ForegroundColor Green
|
||||||
Write-Host "或者: http://$SERVER_IP`:8888" -ForegroundColor Green
|
Write-Host "Or: http://$SERVER_IP`:8888" -ForegroundColor Green
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "默认账号: admin"
|
Write-Host "Username: admin"
|
||||||
Write-Host "默认密码: admin123"
|
Write-Host "Password: 1221xian"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "常用命令:"
|
Write-Host "Useful commands:"
|
||||||
Write-Host " 查看日志: ssh $SERVER_USER@$SERVER_IP 'pm2 logs auto-deploy-demo'"
|
Write-Host " View logs: ssh $SERVER_USER@$SERVER_IP 'pm2 logs auto-deploy-demo'"
|
||||||
Write-Host " 重启服务: ssh $SERVER_USER@$SERVER_IP 'pm2 restart auto-deploy-demo'"
|
Write-Host " Restart: ssh $SERVER_USER@$SERVER_IP 'pm2 restart auto-deploy-demo'"
|
||||||
Write-Host " 停止服务: ssh $SERVER_USER@$SERVER_IP 'pm2 stop auto-deploy-demo'"
|
Write-Host " Stop: ssh $SERVER_USER@$SERVER_IP 'pm2 stop auto-deploy-demo'"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Read-Host "按Enter键退出"
|
Read-Host "Press Enter to exit"
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ echo "访问地址: http://$DOMAIN:8888"
|
||||||
echo "或者: http://$SERVER_IP:8888"
|
echo "或者: http://$SERVER_IP:8888"
|
||||||
echo ""
|
echo ""
|
||||||
echo "默认账号: admin"
|
echo "默认账号: admin"
|
||||||
echo "默认密码: admin123"
|
echo "默认密码: 1221xian"
|
||||||
echo ""
|
echo ""
|
||||||
echo "常用命令:"
|
echo "常用命令:"
|
||||||
echo " 查看日志: ssh $SERVER_USER@$SERVER_IP 'pm2 logs auto-deploy-demo'"
|
echo " 查看日志: ssh $SERVER_USER@$SERVER_IP 'pm2 logs auto-deploy-demo'"
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
"crypto": "^1.0.1",
|
"crypto": "^1.0.1",
|
||||||
"dotenv": "^17.3.1",
|
"dotenv": "^17.3.1",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"http-proxy-middleware": "^3.0.5",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"multer": "^1.4.5-lts.1"
|
"multer": "^1.4.5-lts.1"
|
||||||
},
|
},
|
||||||
|
|
@ -32,6 +33,24 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/http-proxy": {
|
||||||
|
"version": "1.17.17",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/http-proxy/-/http-proxy-1.17.17.tgz",
|
||||||
|
"integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "25.3.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/node/-/node-25.3.2.tgz",
|
||||||
|
"integrity": "sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~7.18.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
"version": "1.3.8",
|
"version": "1.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||||
|
|
@ -191,6 +210,18 @@
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/braces": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fill-range": "^7.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/buffer-crc32": {
|
"node_modules/buffer-crc32": {
|
||||||
"version": "0.2.13",
|
"version": "0.2.13",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||||
|
|
@ -620,6 +651,12 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eventemitter3": {
|
||||||
|
"version": "4.0.7",
|
||||||
|
"resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
|
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/events-universal": {
|
"node_modules/events-universal": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
|
||||||
|
|
@ -678,6 +715,18 @@
|
||||||
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
|
||||||
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="
|
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/fill-range": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"to-regex-range": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/finalhandler": {
|
"node_modules/finalhandler": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
|
||||||
|
|
@ -695,6 +744,26 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.11",
|
||||||
|
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||||
|
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/forwarded": {
|
"node_modules/forwarded": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
|
|
@ -853,6 +922,60 @@
|
||||||
"url": "https://opencollective.com/express"
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/http-proxy": {
|
||||||
|
"version": "1.18.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||||
|
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"eventemitter3": "^4.0.0",
|
||||||
|
"follow-redirects": "^1.0.0",
|
||||||
|
"requires-port": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-proxy-middleware": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/http-proxy-middleware/-/http-proxy-middleware-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/http-proxy": "^1.17.15",
|
||||||
|
"debug": "^4.3.6",
|
||||||
|
"http-proxy": "^1.18.1",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"is-plain-object": "^5.0.0",
|
||||||
|
"micromatch": "^4.0.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-proxy-middleware/node_modules/debug": {
|
||||||
|
"version": "4.4.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz",
|
||||||
|
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-proxy-middleware/node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
|
@ -887,6 +1010,15 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-extglob": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-fullwidth-code-point": {
|
"node_modules/is-fullwidth-code-point": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
|
@ -896,6 +1028,36 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-glob": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-extglob": "^2.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-plain-object": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/isarray": {
|
"node_modules/isarray": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
|
|
@ -1056,6 +1218,19 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/micromatch": {
|
||||||
|
"version": "4.0.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
|
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"braces": "^3.0.3",
|
||||||
|
"picomatch": "^2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mime": {
|
"node_modules/mime": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
|
|
@ -1206,6 +1381,18 @@
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
|
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/process-nextick-args": {
|
"node_modules/process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
|
|
@ -1289,6 +1476,12 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/requires-port": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/rxjs": {
|
"node_modules/rxjs": {
|
||||||
"version": "7.8.2",
|
"version": "7.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||||
|
|
@ -1559,6 +1752,18 @@
|
||||||
"b4a": "^1.6.4"
|
"b4a": "^1.6.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/to-regex-range": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-number": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/toidentifier": {
|
"node_modules/toidentifier": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
|
|
@ -1599,6 +1804,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
|
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "7.18.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.18.2.tgz",
|
||||||
|
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/unpipe": {
|
"node_modules/unpipe": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
"crypto": "^1.0.1",
|
"crypto": "^1.0.1",
|
||||||
"dotenv": "^17.3.1",
|
"dotenv": "^17.3.1",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
|
"http-proxy-middleware": "^3.0.5",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"multer": "^1.4.5-lts.1"
|
"multer": "^1.4.5-lts.1"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,18 @@ const config = {
|
||||||
projectPortStart: parseInt(process.env.PROJECT_PORT_START, 10) || 9000,
|
projectPortStart: parseInt(process.env.PROJECT_PORT_START, 10) || 9000,
|
||||||
projectPortEnd: parseInt(process.env.PROJECT_PORT_END, 10) || 9100,
|
projectPortEnd: parseInt(process.env.PROJECT_PORT_END, 10) || 9100,
|
||||||
|
|
||||||
getProjectUrl(port) {
|
getProjectUrl(port, projectPath = '') {
|
||||||
|
let baseUrl;
|
||||||
if (this.baseDomain) {
|
if (this.baseDomain) {
|
||||||
return `http://${this.baseDomain}:${port}`;
|
baseUrl = `http://${this.baseDomain}:${port}`;
|
||||||
|
} else {
|
||||||
|
baseUrl = `http://localhost:${port}`;
|
||||||
}
|
}
|
||||||
return `http://localhost:${port}`;
|
|
||||||
|
if (projectPath) {
|
||||||
|
return `${baseUrl}${projectPath}`;
|
||||||
|
}
|
||||||
|
return baseUrl;
|
||||||
},
|
},
|
||||||
|
|
||||||
getBaseUrl() {
|
getBaseUrl() {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ const express = require('express');
|
||||||
const { authMiddleware } = require('../middleware/auth');
|
const { authMiddleware } = require('../middleware/auth');
|
||||||
const projectService = require('../services/projectService');
|
const projectService = require('../services/projectService');
|
||||||
const processManager = require('../services/processManager');
|
const processManager = require('../services/processManager');
|
||||||
|
const config = require('../config');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
|
@ -18,11 +19,13 @@ router.post('/:id/start', authMiddleware, async (req, res) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await processManager.startProject(project);
|
const result = await processManager.startProject(project);
|
||||||
projectService.updateProjectStatus(project.id, 'running', result.port, result.url);
|
const url = config.getProjectUrl(result.port, project.path);
|
||||||
|
|
||||||
|
projectService.updateProjectStatus(project.id, 'running', result.port, url);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
message: 'Project started successfully',
|
message: 'Project started successfully',
|
||||||
url: result.url,
|
url: url,
|
||||||
port: result.port
|
port: result.port
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ router.get('/:id', authMiddleware, (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/', authMiddleware, upload.array('files'), (req, res) => {
|
router.post('/', authMiddleware, upload.array('files'), (req, res) => {
|
||||||
const { name, description } = req.body;
|
const { name, description, path: projectPath } = req.body;
|
||||||
const files = req.files;
|
const files = req.files;
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
|
|
@ -51,9 +51,15 @@ router.post('/', authMiddleware, upload.array('files'), (req, res) => {
|
||||||
return res.status(400).json({ error: 'At least one file is required' });
|
return res.status(400).json({ error: 'At least one file is required' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let normalizedPath = projectPath ? projectPath.trim() : '';
|
||||||
|
if (normalizedPath && !normalizedPath.startsWith('/')) {
|
||||||
|
normalizedPath = '/' + normalizedPath;
|
||||||
|
}
|
||||||
|
|
||||||
const project = projectService.createProject({
|
const project = projectService.createProject({
|
||||||
name,
|
name,
|
||||||
description: description || '',
|
description: description || '',
|
||||||
|
path: normalizedPath,
|
||||||
files
|
files
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,19 +73,33 @@ const detectProjectType = (projectDir) => {
|
||||||
return 'static';
|
return 'static';
|
||||||
};
|
};
|
||||||
|
|
||||||
const startStaticServer = (projectDir, port) => {
|
const startStaticServer = (projectDir, port, projectPath = '') => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(express.static(projectDir));
|
|
||||||
|
|
||||||
app.get('*', (req, res) => {
|
if (projectPath) {
|
||||||
const indexPath = path.join(projectDir, 'index.html');
|
app.use(projectPath, express.static(projectDir));
|
||||||
if (fs.existsSync(indexPath)) {
|
|
||||||
res.sendFile(indexPath);
|
app.get(`${projectPath}/*`, (req, res) => {
|
||||||
} else {
|
const indexPath = path.join(projectDir, 'index.html');
|
||||||
res.status(404).send('index.html not found');
|
if (fs.existsSync(indexPath)) {
|
||||||
}
|
res.sendFile(indexPath);
|
||||||
});
|
} else {
|
||||||
|
res.status(404).send('index.html not found');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
app.use(express.static(projectDir));
|
||||||
|
|
||||||
|
app.get('*', (req, res) => {
|
||||||
|
const indexPath = path.join(projectDir, 'index.html');
|
||||||
|
if (fs.existsSync(indexPath)) {
|
||||||
|
res.sendFile(indexPath);
|
||||||
|
} else {
|
||||||
|
res.status(404).send('index.html not found');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const server = app.listen(port, () => {
|
const server = app.listen(port, () => {
|
||||||
resolve({ server, port });
|
resolve({ server, port });
|
||||||
|
|
@ -110,12 +124,13 @@ const startProject = async (project) => {
|
||||||
|
|
||||||
const port = await findAvailablePort();
|
const port = await findAvailablePort();
|
||||||
const projectType = detectProjectType(projectDir);
|
const projectType = detectProjectType(projectDir);
|
||||||
|
const projectPath = project.path || '';
|
||||||
|
|
||||||
let processInfo = null;
|
let processInfo = null;
|
||||||
|
|
||||||
switch (projectType) {
|
switch (projectType) {
|
||||||
case 'static':
|
case 'static':
|
||||||
const { server } = await startStaticServer(projectDir, port);
|
const { server } = await startStaticServer(projectDir, port, projectPath);
|
||||||
processInfo = {
|
processInfo = {
|
||||||
type: 'static',
|
type: 'static',
|
||||||
server,
|
server,
|
||||||
|
|
@ -162,7 +177,7 @@ const startProject = async (project) => {
|
||||||
|
|
||||||
runningProcesses.set(project.id, processInfo);
|
runningProcesses.set(project.id, processInfo);
|
||||||
|
|
||||||
const url = config.getProjectUrl(port);
|
const url = config.getProjectUrl(port, projectPath);
|
||||||
|
|
||||||
return { port, url };
|
return { port, url };
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ const getProjectById = (id) => {
|
||||||
return projects.find(p => p.id === id);
|
return projects.find(p => p.id === id);
|
||||||
};
|
};
|
||||||
|
|
||||||
const createProject = ({ name, description, files }) => {
|
const createProject = ({ name, description, path: projectPath, files }) => {
|
||||||
const projects = getProjects();
|
const projects = getProjects();
|
||||||
const id = Date.now().toString();
|
const id = Date.now().toString();
|
||||||
|
|
||||||
|
|
@ -100,6 +100,7 @@ const createProject = ({ name, description, files }) => {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
|
path: projectPath || '',
|
||||||
files: allFiles.map(f => ({
|
files: allFiles.map(f => ({
|
||||||
name: path.relative(projectDir, f),
|
name: path.relative(projectDir, f),
|
||||||
size: fs.statSync(f).size,
|
size: fs.statSync(f).size,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue