# 多站点管理后台

前后端分离的多站点管理系统。

## 项目结构

```
yh_web/
├── admin/     # 管理后台前端 (Vue 3 + Element Plus) - 端口 3000
├── web/       # 前台页面 (Vue 3) - 端口 3001
├── server/    # 后端 API (Go + Gin) - 端口 8080
└── README.md
```

## 快速启动

### 0. 本地开发：先启动 MongoDB

后端依赖 MongoDB，二选一即可：

**方式一：本机已安装 MongoDB**  
启动 MongoDB 服务后，在 `server/.env` 中设置 `MONGODB_URI=mongodb://localhost:27017`（复制 `.env.example` 为 `.env` 后改此项即可）。

**方式二：只用 Docker 跑一个 MongoDB（推荐，无需本机安装）**

```bash
docker run -d --name yh_mongo -p 27017:27017 mongo:7
```

同样在 `server/.env` 中保持 `MONGODB_URI=mongodb://localhost:27017`。停止：`docker stop yh_mongo`，再启：`docker start yh_mongo`。

### 1. 启动后端

```bash
cd server
go mod tidy
go run main.go
```

### 2. 启动管理后台

```bash
cd admin
npm install
npm run dev
```

### 3. 启动前台

```bash
cd web
npm install
npm run dev
```

## 访问地址

- 管理后台: http://localhost:3000
- 前台: http://localhost:3001
- API: http://localhost:8080

## 用 Docker 一键跑起来（推荐）

在项目根目录执行，用 Docker 拉镜像并启动全部服务（API、Web、Admin、MongoDB）：

**1. 准备环境变量**  
若还没有 `server/.env`，复制一份并可按需修改：
```bash
cp server/.env.example server/.env
```

**2. 国内网络可设镜像再拉镜像（避免超时）**
```bash
# Windows PowerShell
$env:REGISTRY_MIRROR="docker.m.daocloud.io/library/"
docker compose up -d --build

# Linux / Mac / Git Bash
export REGISTRY_MIRROR=docker.m.daocloud.io/library/
docker compose up -d --build
```

不设 `REGISTRY_MIRROR` 时直连 Docker Hub；若拉取超时再按上面设置镜像后重试。

**3. 访问**  
- 当前 compose 仅暴露 443，由 Nginx 反代；API 容器内监听 8088，通过 https 访问 /api。

停止：`docker compose down`。

## 线上部署（项目根目录：~/project/yh_web）

线上路径为 `yxd@server1:~/project/yh_web`（即 `/home/yxd/project/yh_web`）。

### 线上跑起来（以 Gitea 为准）

1. **本地**：提交并推送含「镜像加速」的代码（`docker-compose.yml`、各 `Dockerfile`、若已改脚本也同步到服务器）。
2. **服务器**：进入项目目录，**以 Gitea 为准**，直接执行拉取并重启脚本（脚本内会 `git fetch` + `git reset --hard origin/master`，本地修改会被覆盖）。
   ```bash
   cd /www/yh_web   # 或你的项目路径
   ./pull-and-restart.sh
   ```
   **重要**：`deploy/` 下构建产物（web/admin 静态文件、api 二进制）**不在仓库里**，仅靠 `git pull` 不会生成。拉取后**必须执行** `./pull-and-restart.sh`（或 `./restart.sh`）才会构建并启动，否则访问会 403/404。脚本已记录可执行权限，拉取后可直接 `./pull-and-restart.sh`，无需 chmod。
   若你已手动执行过 `git pull` 且报错 `Your local changes would be overwritten`，先以远程为准：`git fetch origin && git reset --hard origin/master`，再执行 `./pull-and-restart.sh`。

采用**挂目录 + 替换文件**部署：脚本将 web/admin 构建到 `deploy/web/dist`、`deploy/admin/dist`，api 二进制到 `deploy/api/server`，容器挂载这些目录；更新时只重新构建产物并重启，无需重建前端镜像，仅 api 使用轻量运行时镜像。详见 `deploy/README.md`。构建会从 DaoCloud 等镜像拉取 node、nginx、golang、alpine、mongo，启动后**对外仅 443**，由 compose 内 Nginx 反代到 api/web/admin，证书按脚本自动处理。

**脚本说明**：仅保留两个脚本，均会检测 Docker 并在未安装时一键安装（apt 或 yum/dnf）。
- **拉取代码并重启**：`./pull-and-restart.sh` — 若无 Git 仓库会提示设置 `GIT_REPO_URL` 后自动克隆；然后拉取并构建、启动。
- **仅重启**：`./restart.sh` — 不拉代码，仅 `docker compose down` 后 `up -d`。

**Permission denied**：拉取后脚本可能无可执行权限，任选其一即可：
```bash
chmod +x pull-and-restart.sh restart.sh
# 或直接用 bash 执行（脚本内会自修复权限供下次使用）
bash pull-and-restart.sh
```
若报错 `bash\r`，先执行 `sed -i 's/\r$//' pull-and-restart.sh restart.sh`。
首次部署若目录为空，可先放入两个脚本，设置 `export GIT_REPO_URL='https://用户:Token@gitea.../web.git'` 后执行 `./pull-and-restart.sh` 完成克隆与启动。配置好 `server/.env` 后再次运行即可。

- **拉取并重启**：`cd ~/project/yh_web && ./pull-and-restart.sh`
- **仅重启**：`cd ~/project/yh_web && ./restart.sh`
- **对外域名**：https://yuheng.yuxindazhineng.com（所有请求均通过该域名，见下）

**所有请求通过域名**：前台/后台生产环境使用同一域名，API 也走同域 `/api`。

- **有 Nginx Proxy Manager 时**：在 NPM 中配置反代即可：
  - `https://yuheng.yuxindazhineng.com/` → 本机 9528（web）
  - `https://yuheng.yuxindazhineng.com/admin/` → 本机 9529（admin）
  - `https://yuheng.yuxindazhineng.com/api` → 本机 8088（api）
- **新服务器无 NPM、自建 Nginx 时**：使用项目内 **`nginx/`** 配置，强制 HTTPS，SSL 证书按域名单独目录存放。详见 **`nginx/README.md`**（证书目录：`/etc/ssl/yh_web/yuheng.yuxindazhineng.com/`，复制 `nginx/yuheng.yuxindazhineng.com.conf` 到 `/etc/nginx/conf.d/` 后重载 Nginx）。

前端 `VITE_API_BASE` 留空即请求同域 `/api`；后端 `server/.env` 中 `ALLOWED_ORIGINS=https://yuheng.yuxindazhineng.com` 用于 CORS。

**服务器无法访问 Docker Hub 时**（报错 `dial tcp ... i/o timeout`）：一键脚本会自动写入 Podman 镜像配置到 `/etc/containers/registries.conf.d/99-docker-mirror.conf`（DaoCloud / 1ms / 徐轩辕等镜像）。若仍拉取失败：
- **Podman**：确认主配置会加载该目录。若无效，可把 `99-docker-mirror.conf` 中的 `[[registry]]` 段合并进 `/etc/containers/registries.conf`。
- **Docker**：编辑 `/etc/docker/daemon.json` 添加 `"registry-mirrors": ["https://docker.1ms.run"]` 后 `sudo systemctl restart docker`。
然后重新运行启动脚本。

**报错 `listen tcp4 :8088: bind: address already in use`**：当前 `docker-compose.yml` 中 **api 未映射任何宿主机端口**，`PORT=8088` 仅容器内监听。该错误多为服务器上曾用旧版 compose 映射过 8088，或宿主机其他进程占用。处理：确认已 `git pull` 到最新（compose 无 api 的 `ports`），执行 `docker compose down`（或直接再次执行 `./pull-and-restart.sh`，脚本内已先 down 再 up）后重试；若仍报错，在服务器上执行 `ss -tlnp | grep 8088` 或 `lsof -i :8088` 查看占用进程并结束。
