Compare commits

...

16 Commits

Author SHA1 Message Date
lzh
3c6a92b1d4 docs: cicd文档 2025-12-18 15:45:59 +08:00
lzh
3260ec0e99 chore: ensure app joins 1panel-network"
All checks were successful
Web UI CI/CD / build-and-deploy (push) Successful in 5m22s
2025-12-18 15:05:45 +08:00
lzh
179afea2e1 fix: 使用aiot-server容器名
All checks were successful
Web UI CI/CD / build-and-deploy (push) Successful in 3m9s
2025-12-18 14:41:21 +08:00
lzh
ac76faacc4 fix: 使用后端容器ip
Some checks failed
Web UI CI/CD / build-and-deploy (push) Has been cancelled
2025-12-18 14:37:41 +08:00
lzh
7773b1dc88 fix: 修复后端接口连接不上问题
All checks were successful
Web UI CI/CD / build-and-deploy (push) Successful in 3m40s
2025-12-18 14:20:06 +08:00
lzh
874c06fa51 fix: 优化构建速度,后端容器名
All checks were successful
Web UI CI/CD / build-and-deploy (push) Successful in 3m31s
2025-12-18 14:03:54 +08:00
lzh
1c04ff0d7b fix: 解决后端服务跨域的问题
All checks were successful
Web UI CI/CD / build-and-deploy (push) Successful in 3m23s
2025-12-18 13:57:00 +08:00
lzh
4dc00ec35d fix: 修复构建错误
All checks were successful
Web UI CI/CD / build-and-deploy (push) Successful in 3m34s
2025-12-18 13:47:15 +08:00
lzh
772258adbb fix: 修复构建错误 catalog 解析错误
Some checks failed
Web UI CI/CD / build-and-deploy (push) Failing after 46s
2025-12-18 13:45:29 +08:00
lzh
5fcb011bd1 fix: 修改配置文件172.17.16.14
Some checks failed
Web UI CI/CD / build-and-deploy (push) Failing after 8s
2025-12-18 13:43:55 +08:00
lzh
7a57d43459 perf: 优化构建速度 2025-12-18 13:36:13 +08:00
lzh
924b66f836 fix: 修改后端地址为172.17.16.14
All checks were successful
Web UI CI/CD / build-and-deploy (push) Successful in 4m3s
2025-12-18 13:33:36 +08:00
lzh
3c89e81de8 fix: 容器内 = 80,宿主机 = 9090
All checks were successful
Web UI CI/CD / build-and-deploy (push) Successful in 3m33s
映射 = -p 9090:80(把外部 9090 转发到内部 80)
2025-12-18 13:25:01 +08:00
lzh
e6b1d7400d Merge branch 'master' of http://124.221.55.225:3000/XW-AIOT/aiot-platform-ui
Some checks failed
Web UI CI/CD / build-and-deploy (push) Failing after 3m49s
2025-12-18 12:05:15 +08:00
lzh
b2e831155c feat: 构建cicd | docke部署 | nginx 配置文件 2025-12-18 12:04:23 +08:00
lzh
14dfa79477 Merge pull request 'fix: 名称修改' (#1) from feature/cleaning into master
Some checks failed
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
Reviewed-on: http://124.221.55.225:3000/XW-AIOT/aiot-platform-ui/pulls/1
2025-12-17 17:35:43 +08:00
6 changed files with 329 additions and 8 deletions

View File

@@ -0,0 +1,103 @@
name: Web UI CI/CD
on:
push:
branches:
- master
paths:
# 仅当以下文件变动时触发构建,避免改个 README 也重新发版
- 'apps/web-antd/**'
- 'packages/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'Dockerfile'
- '.gitea/workflows/deploy-web.yaml'
jobs:
build-and-deploy:
runs-on: xw-runner
# 使用包含 Docker 客户端的镜像,这样我们可以在容器内构建镜像 (Docker-in-Docker 模式)
container:
image: catthehacker/ubuntu:act-latest
# 这里的 options 很重要,有时候 Runner 需要特权才能操作宿主机的 Docker
# 如果遇到 permission denied尝试取消注释下一行
# options: --privileged --user root
steps:
# 1. 检出代码
- name: Checkout Code
run: |
# 清理当前目录,防止旧文件干扰
ls -A1 | xargs rm -rf
# 拼接 Clone URL (支持 http 和 https)
SERVER_DOMAIN=$(echo "${{ gitea.server_url }}" | sed -E 's|https?://||')
PROTO="http"
if [[ "${{ gitea.server_url }}" == https* ]]; then PROTO="https"; fi
# 使用 Gitea Token 进行认证
GIT_URL="${PROTO}://${{ gitea.actor }}:${{ gitea.token }}@${SERVER_DOMAIN}/${{ gitea.repository }}.git"
echo "Cloning..."
git clone --depth 1 "$GIT_URL" .
git log -1 --format='%h - %s'
# 2. 准备 Docker 网络
# 使用 1Panel 的默认网络,确保所有服务在同一个网络下,方便互相访问
- name: Check Docker Network
run: |
# 检查 1panel-network 是否存在,如果不存在则创建
docker network inspect 1panel-network > /dev/null 2>&1 || docker network create 1panel-network || true
# 3. 构建并部署
- name: Build & Deploy Web UI
env:
# 镜像名称
IMAGE_NAME: 'aiot-web-antd'
# 容器名称
CONTAINER_NAME: aiot-web-antd
# 宿主机端口
HOST_PORT: 9090
run: |
# --- 构建阶段 ---
SHORT_SHA=$(git log -1 --format='%h')
FULL_IMAGE_NAME="${IMAGE_NAME}:${SHORT_SHA}"
echo "Building Docker Image: $FULL_IMAGE_NAME..."
# 使用根目录的 Dockerfile 进行构建
# Dockerfile 内部使用了多阶段构建,不需要 Runner 安装 Node
# 启用 BuildKit 以支持缓存挂载(加速依赖安装)
DOCKER_BUILDKIT=1 docker build -t "$FULL_IMAGE_NAME" -f Dockerfile .
# 打上 latest 标签
docker tag "$FULL_IMAGE_NAME" "${IMAGE_NAME}:latest"
# --- 部署阶段 ---
echo "Deploying Container: $CONTAINER_NAME..."
# 停止并删除旧容器
docker stop $CONTAINER_NAME || true
docker rm $CONTAINER_NAME || true
# 检查端口占用,如果有其他容器占用,先停止它
PORT_CONTAINER=$(docker ps --filter "publish=${HOST_PORT}" --format "{{.Names}}" | head -1)
if [ ! -z "$PORT_CONTAINER" ]; then
echo "⚠️ Port ${HOST_PORT} is occupied by container: $PORT_CONTAINER"
echo "Stopping conflicting container..."
docker stop $PORT_CONTAINER || true
fi
# 启动新容器
# -d: 后台运行
# --restart always: 开机自启
# -p: 端口映射 宿主机:容器
docker run -d \
--name $CONTAINER_NAME \
--network 1panel-network \
--restart always \
-p ${HOST_PORT}:80 \
"${IMAGE_NAME}:latest"
echo "✅ Deployment Successful! Access at port ${HOST_PORT}"

61
Dockerfile Normal file
View File

@@ -0,0 +1,61 @@
# 1. 构建阶段
FROM node:20-alpine AS builder
# 设置 npm 和 pnpm 镜像源为淘宝源(加速下载)
RUN npm config set registry https://registry.npmmirror.com && \
echo "registry=https://registry.npmmirror.com" > ~/.npmrc
WORKDIR /app
# 启用 pnpm (使用 corepack)
# 设置环境变量让 Corepack 也从镜像源下载
ENV COREPACK_NPM_REGISTRY=https://registry.npmmirror.com
# 设置 pnpm store 路径,便于缓存
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && corepack prepare pnpm@10.22.0 --activate
# 配置 pnpm 使用淘宝镜像源和自定义 store 路径(便于缓存)
RUN pnpm config set registry https://registry.npmmirror.com && \
pnpm config set store-dir /pnpm/store
# 单独复制依赖描述文件,利用 Docker 缓存层
# 先只复制这些文件如果它们没变Docker 会复用缓存,跳过后续步骤
# pnpm-workspace.yaml 包含 catalog 配置pnpm 需要它来解析 catalog: 引用
COPY package.json pnpm-lock.yaml turbo.json pnpm-workspace.yaml ./
# 复制所有 package.jsonMonorepo 需要)
# internal 目录包含构建工具包(@vben/tsconfig, @vben/vite-config 等),构建时需要
COPY packages packages
COPY apps apps
COPY internal internal
# 安装依赖
# 使用 BuildKit 缓存挂载加速依赖安装
# 缓存 pnpm store即使 package.json 变了,已下载的包也能复用
# 使用明确的缓存路径和 ID确保缓存持久化
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store \
pnpm install --frozen-lockfile
# 构建指定项目 (根据 package.json 里的 scripts)
# 这里我们构建 antd 版本
RUN pnpm build:antd
# 2. 运行阶段
FROM nginx:alpine
# 移除默认配置
RUN rm /etc/nginx/conf.d/default.conf
# 复制自定义 Nginx 配置
COPY apps/web-antd/nginx.conf /etc/nginx/conf.d/default.conf
# 复制构建产物
# 注意Vben 5 的产物目录通常在 apps/web-antd/dist
COPY --from=builder /app/apps/web-antd/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -4,7 +4,7 @@ VITE_PORT=5666
VITE_BASE=/
# 请求路径
VITE_BASE_URL=http://127.0.0.1:48080
VITE_BASE_URL=http://172.17.16.14:48080
# 接口地址
VITE_GLOB_API_URL=/admin-api
# 文件上传类型server - 后端上传, client - 前端直连上传仅支持S3服务

View File

@@ -1,20 +1,19 @@
VITE_BASE=/
# 请求路径
VITE_BASE_URL=http://127.0.0.1:48080
VITE_BASE_URL=/admin-api
# 接口地址
VITE_GLOB_API_URL=http://127.0.0.1:48080/admin-api
# 文件上传类型server - 后端上传 client - 前端直连上传仅支持S3服务
VITE_GLOB_API_URL=/admin-api
# 文件上传类型server - 后端上传<EFBFBD><EFBFBD>?client - 前端直连上传仅支持S3服务
VITE_UPLOAD_TYPE=server
# 是否开启压缩,可以设置none, brotli, gzip
# 是否开启压缩,可以设置<EFBFBD><EFBFBD>?none, brotli, gzip
VITE_COMPRESS=none
# 是否开PWA
# 是否开<EFBFBD><EFBFBD>?PWA
VITE_PWA=false
# vue-router 的模
VITE_ROUTER_HISTORY=hash
# vue-router 的模<EFBFBD><EFBFBD>?VITE_ROUTER_HISTORY=hash
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true

77
apps/web-antd/nginx.conf Normal file
View File

@@ -0,0 +1,77 @@
# 配置 DNS 解析器(使用 Docker 内置 DNS
resolver 127.0.0.11 valid=30s;
server {
listen 80;
server_name localhost; # 通配符,匹配所有域名(适用于反向代理场景)
# 开启 gzip 压缩
gzip on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
root /usr/share/nginx/html;
index index.html;
# API 反向代理到后端服务
# 后端服务在 Docker 容器中,使用容器名访问(都在 1panel-network 网络中)
# 如果后端在宿主机上改为http://172.17.0.1:48080/admin-api
location /admin-api {
# 后端服务地址
# 方案1使用容器名推荐自动 DNS 解析)- 如果后端监听 0.0.0.0
proxy_pass http://aiot-server:48080/admin-api;
# 方案2直接使用后端容器 IP当前后端 IP: 172.22.0.3
# 如果方案1不行取消注释下面这行注释掉上面那行
# proxy_pass http://172.22.0.3:48080/admin-api;
# 方案3通过宿主机网关访问如果后端只监听 127.0.0.1
# proxy_pass http://172.22.0.1:48080/admin-api;
# 代理超时设置
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 错误处理:如果后端不可用,返回友好的错误信息
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_next_upstream_tries 2;
# 代理请求头
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 解决跨域问题
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
# 处理 OPTIONS 预检请求
if ($request_method = 'OPTIONS') {
return 204;
}
}
# 解决 SPA 路由刷新 404 问题
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源缓存配置
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
# 错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

81
docs/DEPLOY.md Normal file
View File

@@ -0,0 +1,81 @@
# Gitea CI/CD 部署指南
本文档描述了 `aiot-platform-ui` (Web Antd 端) 的自动化构建与部署流程。
## 1. 架构说明
项目采用 **Gitea Actions + Docker** 进行部署。
- **构建方式**Docker 多阶段构建 (Multi-stage Build)。
- Stage 1: `node:20-alpine` -> 安装依赖 -> `pnpm build:web-antd` -> 生成 `dist`
- Stage 2: `nginx:alpine` -> 复制 `dist` -> 启动 Web 服务。
- **运行环境**:目标服务器 (安装了 Gitea Runner 和 Docker)。
- **网络模式**:容器加入 `aiot-net` 网络,端口映射到宿主机。
## 2. 前置准备
在使用 CI/CD 前,请确保目标服务器满足以下条件:
1. **安装 Docker**: `docker -v` 可用。
2. **配置 Gitea Runner**:
- Runner 已注册到 Gitea。
- Runner 有权限访问 Docker Socket (`/var/run/docker.sock`)。
3. **Docker 网络**:
- 项目使用 1Panel 的默认网络 `1panel-network`
- CI/CD 会自动检查网络是否存在,如果不存在则创建
- 确保前端和后端容器都在同一个网络中
## 3. 端口规划
| 服务名称 | 容器端口 | 宿主机端口 (Host Port) | 说明 |
| :-- | :-- | :-- | :-- |
| **aiot-web-antd** | 80 | **9090** | 前端 Web 服务,请在 1Panel 中反代此端口 |
| aiot-server | 48080 | 48080 | 后端 API 服务 (参考) |
> **注意**:如果 9090 端口已被占用,请修改 `.gitea/workflows/deploy-web.yaml` 中的 `HOST_PORT` 变量。
### 部署失败:端口已被占用 (`port is already allocated`)
- **原因**:宿主机端口被其他容器或服务占用。
- **解法**
1. 修改 workflow 中的 `HOST_PORT` 为其他端口(如 8082、8083
2. 或者手动停止占用端口的容器:`docker ps | grep <端口号>` 然后 `docker stop <容器名>`
## 4. 1Panel 配置指南
由于容器运行在 `127.0.0.1:8080`,需要在 1Panel (或 Nginx) 中配置反向代理以通过域名访问。
1. **进入 1Panel** -> **网站** -> **创建网站**
2. **域名**: 填写你的域名 (e.g., `admin.example.com`)。
3. **类型**: `反向代理`
4. **代理地址**: `http://127.0.0.1:9090`
5. **提交**
## 5. 常见问题排查
### 构建失败:`pnpm install` 很慢或超时
- **原因**:网络问题。
- **解法**Dockerfile 中已配置 npm 淘宝源。如果依然慢,考虑在 Runner 机器上配置透明代理。
### 部署失败:`Permission denied` 访问 Docker
- **原因**Gitea Runner 用户没有 Docker 组权限。
- **解法**
1. 在服务器执行:`sudo usermod -aG docker <runner-user>`
2. 或者在 workflow yaml 中开启 `privileged: true` (不推荐)。
### 页面刷新 404
- **原因**Nginx 未配置 SPA 重定向。
- **解法**:检查 `apps/web-antd/nginx.conf` 是否包含 `try_files $uri $uri/ /index.html;`
## 6. 如何触发部署
- 修改代码后,推送到 `master` 分支:
```bash
git add .
git commit -m "feat: 更新功能"
git push origin master
```
- 前往 Gitea 仓库页面 -> **Actions** 查看构建进度。