Compare commits
No commits in common. "release1.0" and "main" have entirely different histories.
release1.
...
main
|
|
@ -8,6 +8,3 @@ BASE_DOMAIN=
|
|||
# 项目端口范围
|
||||
PROJECT_PORT_START=9000
|
||||
PROJECT_PORT_END=9100
|
||||
|
||||
# JWT密钥(生产环境请修改为安全的随机字符串)
|
||||
JWT_SECRET=your-secure-secret-key-change-this
|
||||
|
|
|
|||
|
|
@ -71,16 +71,10 @@ cd ..
|
|||
cat > .env << EOF
|
||||
PORT=8888
|
||||
JWT_SECRET=your-secure-secret-key-change-this
|
||||
BASE_DOMAIN=your-domain.com
|
||||
PROJECT_PORT_START=9000
|
||||
PROJECT_PORT_END=9100
|
||||
HOST=your-server-ip
|
||||
EOF
|
||||
```
|
||||
|
||||
默认登录账号:
|
||||
- 用户名: admin
|
||||
- 密码: 1221xian
|
||||
|
||||
### 4. 启动服务
|
||||
|
||||
```bash
|
||||
|
|
|
|||
16
README.md
16
README.md
|
|
@ -73,7 +73,7 @@ npm start
|
|||
### 默认账号
|
||||
|
||||
- 用户名: `admin`
|
||||
- 密码: `1221xian`
|
||||
- 密码: `admin123`
|
||||
|
||||
## 使用指南
|
||||
|
||||
|
|
@ -81,18 +81,8 @@ npm start
|
|||
|
||||
1. 点击右上角「新建项目」按钮
|
||||
2. 填写项目名称和描述
|
||||
3. (可选)填写项目路径,例如 `/demo/lot-demo`
|
||||
4. 拖拽或点击上传项目文件
|
||||
5. 点击「创建项目」完成
|
||||
|
||||
### 项目路径说明
|
||||
|
||||
项目路径用于自定义项目的访问URL:
|
||||
|
||||
- 格式:以 `/` 开头的相对路径,如 `/demo/lot-demo`
|
||||
- 访问URL格式:`http://域名:端口/项目路径`
|
||||
- 示例:项目路径 `/demo/lot-demo`,端口 `9000`,则访问地址为 `http://localhost:9000/demo/lot-demo`
|
||||
- 用途:支持同一域名下部署多个项目,通过不同路径区分
|
||||
3. 拖拽或点击上传项目文件
|
||||
4. 点击「创建项目」完成
|
||||
|
||||
### 部署项目
|
||||
|
||||
|
|
|
|||
|
|
@ -34,18 +34,6 @@
|
|||
></textarea>
|
||||
</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>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">项目文件 *</label>
|
||||
|
||||
|
|
@ -149,7 +137,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { useProjectStore } from '../stores/project'
|
||||
|
||||
const emit = defineEmits(['close', 'success'])
|
||||
|
|
@ -164,20 +152,9 @@ const uploadProgress = ref(0)
|
|||
const form = reactive({
|
||||
name: '',
|
||||
description: '',
|
||||
path: '',
|
||||
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 = () => {
|
||||
fileInput.value?.click()
|
||||
}
|
||||
|
|
@ -211,11 +188,6 @@ const handleSubmit = async () => {
|
|||
return
|
||||
}
|
||||
|
||||
let projectPath = form.path.trim()
|
||||
if (projectPath && !projectPath.startsWith('/')) {
|
||||
projectPath = '/' + projectPath
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
uploadProgress.value = 0
|
||||
|
|
@ -224,7 +196,6 @@ const handleSubmit = async () => {
|
|||
const formData = new FormData()
|
||||
formData.append('name', form.name)
|
||||
formData.append('description', form.description)
|
||||
formData.append('path', projectPath)
|
||||
|
||||
form.files.forEach(file => {
|
||||
formData.append('files', file)
|
||||
|
|
|
|||
|
|
@ -150,10 +150,6 @@
|
|||
<dt class="text-sm text-gray-500">更新时间</dt>
|
||||
<dd class="text-sm font-medium text-gray-900 mt-1">{{ formatDateTime(project.updatedAt) }}</dd>
|
||||
</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">
|
||||
<dt class="text-sm text-gray-500">最后部署</dt>
|
||||
<dd class="text-sm font-medium text-gray-900 mt-1">{{ formatDateTime(project.lastDeployed) }}</dd>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
[
|
||||
{
|
||||
"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 +1,63 @@
|
|||
[]
|
||||
[
|
||||
{
|
||||
"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
|
||||
- **默认账号**: admin
|
||||
- **默认密码**: 1221xian
|
||||
- **默认密码**: admin123
|
||||
|
||||
## 常用命令
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,6 @@ echo 访问地址: http://%DOMAIN%:8888
|
|||
echo 或者: http://%SERVER_IP%:8888
|
||||
echo.
|
||||
echo 默认账号: admin
|
||||
echo 默认密码: 1221xian
|
||||
echo 默认密码: admin123
|
||||
echo.
|
||||
pause
|
||||
|
|
|
|||
|
|
@ -5,88 +5,109 @@ $DEPLOY_DIR = "/home/ai-auto/auto-deploy-demo"
|
|||
$DOMAIN = "ashai.com.cn"
|
||||
|
||||
Write-Host "=========================================="
|
||||
Write-Host " Auto Deploy Script - Demo System"
|
||||
Write-Host " 自动部署脚本 - 快速Demo演示系统"
|
||||
Write-Host "=========================================="
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "[Tip] Make sure OpenSSH client is installed"
|
||||
Write-Host "Windows 10/11: Settings > Apps > Optional Features"
|
||||
Write-Host "[提示] 请确保已安装OpenSSH客户端"
|
||||
Write-Host "Windows 10/11 可在 '设置 > 应用 > 可选功能' 中安装"
|
||||
Write-Host ""
|
||||
Write-Host "Server password: $SERVER_PASS"
|
||||
Write-Host "即将开始部署,请准备好输入服务器密码: $SERVER_PASS"
|
||||
Write-Host ""
|
||||
Read-Host "Press Enter to continue..."
|
||||
Read-Host "按Enter键继续..."
|
||||
|
||||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||||
Set-Location $projectRoot
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[1/8] Testing SSH connection..."
|
||||
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$SERVER_USER@$SERVER_IP" "echo 'SSH connected'"
|
||||
Write-Host "[1/8] 测试SSH连接..."
|
||||
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$SERVER_USER@$SERVER_IP" "echo 'SSH连接成功'"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[Error] Cannot connect to server" -ForegroundColor Red
|
||||
Read-Host "Press Enter to exit"
|
||||
Write-Host "[错误] 无法连接到服务器" -ForegroundColor Red
|
||||
Read-Host "按Enter键退出"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[2/8] Installing Node.js..."
|
||||
$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)"
|
||||
ssh "$SERVER_USER@$SERVER_IP" $installNodeCmd
|
||||
Write-Host "[2/8] 安装Node.js环境..."
|
||||
ssh "$SERVER_USER@$SERVER_IP" @"
|
||||
if ! command -v node &> /dev/null; then
|
||||
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 "[3/8] Installing PM2..."
|
||||
$installPm2Cmd = "if ! command -v pm2 &> /dev/null; then sudo npm install -g pm2; fi; echo 'PM2 version:' `$(`pm2 -v)"
|
||||
ssh "$SERVER_USER@$SERVER_IP" $installPm2Cmd
|
||||
Write-Host "[3/8] 安装PM2进程管理器..."
|
||||
ssh "$SERVER_USER@$SERVER_IP" @"
|
||||
if ! command -v pm2 &> /dev/null; then
|
||||
sudo npm install -g pm2
|
||||
fi
|
||||
echo 'PM2版本:' `$(pm2 -v)
|
||||
"@
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[4/8] Creating project directory..."
|
||||
Write-Host "[4/8] 创建项目目录..."
|
||||
ssh "$SERVER_USER@$SERVER_IP" "mkdir -p $DEPLOY_DIR"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[5/8] Uploading project files..."
|
||||
Write-Host "Uploading server directory..."
|
||||
Write-Host "[5/8] 上传项目文件..."
|
||||
Write-Host "上传server目录..."
|
||||
scp -r "$projectRoot\server" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
||||
|
||||
Write-Host "Uploading projects directory..."
|
||||
Write-Host "上传projects目录..."
|
||||
scp -r "$projectRoot\projects" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/"
|
||||
|
||||
Write-Host "Uploading client/dist directory..."
|
||||
ssh "$SERVER_USER@$SERVER_IP" "mkdir -p $DEPLOY_DIR/client/dist"
|
||||
Write-Host "上传client/dist目录..."
|
||||
ssh "$SERVER_USER@$SERVER_IP" "mkdir -p $DEPLOY_DIR/client"
|
||||
scp -r "$projectRoot\client\dist\*" "$SERVER_USER@$SERVER_IP`:$DEPLOY_DIR/client/dist/"
|
||||
|
||||
Write-Host "Uploading config files..."
|
||||
Write-Host "上传配置文件..."
|
||||
scp "$projectRoot\package.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/"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[6/8] Installing dependencies..."
|
||||
Write-Host "[6/8] 安装项目依赖..."
|
||||
ssh "$SERVER_USER@$SERVER_IP" "cd $DEPLOY_DIR && npm install --production"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[7/8] Configuring firewall..."
|
||||
$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'"
|
||||
ssh "$SERVER_USER@$SERVER_IP" $firewallCmd
|
||||
Write-Host "[7/8] 配置防火墙..."
|
||||
ssh "$SERVER_USER@$SERVER_IP" @"
|
||||
sudo firewall-cmd --permanent --add-port=8888/tcp
|
||||
sudo firewall-cmd --permanent --add-port=9000-9100/tcp
|
||||
sudo firewall-cmd --reload
|
||||
echo '防火墙配置完成'
|
||||
"@
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[8/8] Starting service..."
|
||||
$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'"
|
||||
ssh "$SERVER_USER@$SERVER_IP" $startCmd
|
||||
Write-Host "[8/8] 启动服务..."
|
||||
ssh "$SERVER_USER@$SERVER_IP" @"
|
||||
cd $DEPLOY_DIR
|
||||
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 " Deployment Complete!"
|
||||
Write-Host " 部署完成!"
|
||||
Write-Host "=========================================="
|
||||
Write-Host ""
|
||||
Write-Host "URL: http://$DOMAIN`:8888" -ForegroundColor Green
|
||||
Write-Host "Or: http://$SERVER_IP`:8888" -ForegroundColor Green
|
||||
Write-Host "访问地址: http://$DOMAIN`:8888" -ForegroundColor Green
|
||||
Write-Host "或者: http://$SERVER_IP`:8888" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "Username: admin"
|
||||
Write-Host "Password: 1221xian"
|
||||
Write-Host "默认账号: admin"
|
||||
Write-Host "默认密码: admin123"
|
||||
Write-Host ""
|
||||
Write-Host "Useful commands:"
|
||||
Write-Host " View logs: ssh $SERVER_USER@$SERVER_IP 'pm2 logs auto-deploy-demo'"
|
||||
Write-Host " Restart: ssh $SERVER_USER@$SERVER_IP 'pm2 restart auto-deploy-demo'"
|
||||
Write-Host " Stop: ssh $SERVER_USER@$SERVER_IP 'pm2 stop auto-deploy-demo'"
|
||||
Write-Host "常用命令:"
|
||||
Write-Host " 查看日志: ssh $SERVER_USER@$SERVER_IP 'pm2 logs auto-deploy-demo'"
|
||||
Write-Host " 重启服务: ssh $SERVER_USER@$SERVER_IP 'pm2 restart auto-deploy-demo'"
|
||||
Write-Host " 停止服务: ssh $SERVER_USER@$SERVER_IP 'pm2 stop auto-deploy-demo'"
|
||||
Write-Host ""
|
||||
Read-Host "Press Enter to exit"
|
||||
Read-Host "按Enter键退出"
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ echo "访问地址: http://$DOMAIN:8888"
|
|||
echo "或者: http://$SERVER_IP:8888"
|
||||
echo ""
|
||||
echo "默认账号: admin"
|
||||
echo "默认密码: 1221xian"
|
||||
echo "默认密码: admin123"
|
||||
echo ""
|
||||
echo "常用命令:"
|
||||
echo " 查看日志: ssh $SERVER_USER@$SERVER_IP 'pm2 logs auto-deploy-demo'"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
"crypto": "^1.0.1",
|
||||
"dotenv": "^17.3.1",
|
||||
"express": "^4.18.2",
|
||||
"http-proxy-middleware": "^3.0.5",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"multer": "^1.4.5-lts.1"
|
||||
},
|
||||
|
|
@ -33,24 +32,6 @@
|
|||
"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": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
|
|
@ -210,18 +191,6 @@
|
|||
"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": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
|
|
@ -651,12 +620,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": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
|
||||
|
|
@ -715,18 +678,6 @@
|
|||
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
|
||||
"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": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
|
||||
|
|
@ -744,26 +695,6 @@
|
|||
"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": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
|
|
@ -922,60 +853,6 @@
|
|||
"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": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
|
|
@ -1010,15 +887,6 @@
|
|||
"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": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
|
|
@ -1028,36 +896,6 @@
|
|||
"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": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
|
|
@ -1218,19 +1056,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": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
|
|
@ -1381,18 +1206,6 @@
|
|||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"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": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
|
|
@ -1476,12 +1289,6 @@
|
|||
"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": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
|
|
@ -1752,18 +1559,6 @@
|
|||
"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": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
|
|
@ -1804,12 +1599,6 @@
|
|||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"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": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
"crypto": "^1.0.1",
|
||||
"dotenv": "^17.3.1",
|
||||
"express": "^4.18.2",
|
||||
"http-proxy-middleware": "^3.0.5",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"multer": "^1.4.5-lts.1"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,18 +6,11 @@ const config = {
|
|||
projectPortStart: parseInt(process.env.PROJECT_PORT_START, 10) || 9000,
|
||||
projectPortEnd: parseInt(process.env.PROJECT_PORT_END, 10) || 9100,
|
||||
|
||||
getProjectUrl(port, projectPath = '') {
|
||||
let baseUrl;
|
||||
getProjectUrl(port) {
|
||||
if (this.baseDomain) {
|
||||
baseUrl = `http://${this.baseDomain}:${port}`;
|
||||
} else {
|
||||
baseUrl = `http://localhost:${port}`;
|
||||
return `http://${this.baseDomain}:${port}`;
|
||||
}
|
||||
|
||||
if (projectPath) {
|
||||
return `${baseUrl}${projectPath}`;
|
||||
}
|
||||
return baseUrl;
|
||||
return `http://localhost:${port}`;
|
||||
},
|
||||
|
||||
getBaseUrl() {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ const express = require('express');
|
|||
const { authMiddleware } = require('../middleware/auth');
|
||||
const projectService = require('../services/projectService');
|
||||
const processManager = require('../services/processManager');
|
||||
const config = require('../config');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -19,13 +18,11 @@ router.post('/:id/start', authMiddleware, async (req, res) => {
|
|||
|
||||
try {
|
||||
const result = await processManager.startProject(project);
|
||||
const url = config.getProjectUrl(result.port, project.path);
|
||||
|
||||
projectService.updateProjectStatus(project.id, 'running', result.port, url);
|
||||
projectService.updateProjectStatus(project.id, 'running', result.port, result.url);
|
||||
|
||||
res.json({
|
||||
message: 'Project started successfully',
|
||||
url: url,
|
||||
url: result.url,
|
||||
port: result.port
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ router.get('/:id', authMiddleware, (req, res) => {
|
|||
});
|
||||
|
||||
router.post('/', authMiddleware, upload.array('files'), (req, res) => {
|
||||
const { name, description, path: projectPath } = req.body;
|
||||
const { name, description } = req.body;
|
||||
const files = req.files;
|
||||
|
||||
if (!name) {
|
||||
|
|
@ -51,15 +51,9 @@ router.post('/', authMiddleware, upload.array('files'), (req, res) => {
|
|||
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({
|
||||
name,
|
||||
description: description || '',
|
||||
path: normalizedPath,
|
||||
files
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -73,22 +73,9 @@ const detectProjectType = (projectDir) => {
|
|||
return 'static';
|
||||
};
|
||||
|
||||
const startStaticServer = (projectDir, port, projectPath = '') => {
|
||||
const startStaticServer = (projectDir, port) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const app = express();
|
||||
|
||||
if (projectPath) {
|
||||
app.use(projectPath, express.static(projectDir));
|
||||
|
||||
app.get(`${projectPath}/*`, (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');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
app.use(express.static(projectDir));
|
||||
|
||||
app.get('*', (req, res) => {
|
||||
|
|
@ -99,7 +86,6 @@ const startStaticServer = (projectDir, port, projectPath = '') => {
|
|||
res.status(404).send('index.html not found');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const server = app.listen(port, () => {
|
||||
resolve({ server, port });
|
||||
|
|
@ -124,13 +110,12 @@ const startProject = async (project) => {
|
|||
|
||||
const port = await findAvailablePort();
|
||||
const projectType = detectProjectType(projectDir);
|
||||
const projectPath = project.path || '';
|
||||
|
||||
let processInfo = null;
|
||||
|
||||
switch (projectType) {
|
||||
case 'static':
|
||||
const { server } = await startStaticServer(projectDir, port, projectPath);
|
||||
const { server } = await startStaticServer(projectDir, port);
|
||||
processInfo = {
|
||||
type: 'static',
|
||||
server,
|
||||
|
|
@ -177,7 +162,7 @@ const startProject = async (project) => {
|
|||
|
||||
runningProcesses.set(project.id, processInfo);
|
||||
|
||||
const url = config.getProjectUrl(port, projectPath);
|
||||
const url = config.getProjectUrl(port);
|
||||
|
||||
return { port, url };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ const getProjectById = (id) => {
|
|||
return projects.find(p => p.id === id);
|
||||
};
|
||||
|
||||
const createProject = ({ name, description, path: projectPath, files }) => {
|
||||
const createProject = ({ name, description, files }) => {
|
||||
const projects = getProjects();
|
||||
const id = Date.now().toString();
|
||||
|
||||
|
|
@ -100,7 +100,6 @@ const createProject = ({ name, description, path: projectPath, files }) => {
|
|||
id,
|
||||
name,
|
||||
description,
|
||||
path: projectPath || '',
|
||||
files: allFiles.map(f => ({
|
||||
name: path.relative(projectDir, f),
|
||||
size: fs.statSync(f).size,
|
||||
|
|
|
|||
Loading…
Reference in New Issue