# zhctapp v2.0 安装部署文档

本文档面向第一次接触本项目的人，目标是下载 `zhctapp_v2.0-node14-current-20260507_114848_arm64.tar.gz`，完成镜像导入、容器启动、代码拉取，并通过本机 IP 访问项目。

## 1. 目录结构

`zhct` 是每位同事在自己电脑上自行选择的整体目录。目录结构如下：

```text
zhct
├── zhctprompt
│   ├── work
│   ├── work_store
│   ├── work_ai_api
│   ├── work_ai_store
│   ├── work_ai_app
│   └── docker
└── zhctproject
    ├── store
    ├── store20
    ├── ai_api
    ├── ai_store
    └── ai_app
```

容器内路径对应关系：

| 宿主机相对目录 | 容器内目录 |
| --- | --- |
| `zhct` | `/workspace/zhct` |
| `zhct/zhctproject/store` | `/workspace/zhct/zhctproject/store` |
| `zhct/zhctproject/store20` | `/workspace/zhct/zhctproject/store20` |
| `zhct/zhctproject/ai_api` | `/workspace/zhct/zhctproject/ai_api` |
| `zhct/zhctlogs/wwwlogs` | `/workspace/wwwlogs` |

## 2. 准备内容

部署前需要准备：

- Docker Desktop
- Git
- 启动脚本：`start_zhct.sh`
- 云效仓库 SSH 权限

镜像包信息：

```text
文件名：zhctapp_v2.0-node14-current-20260507_114848_arm64.tar.gz
本地包路径：zhct/zhctprompt/docker/zhctapp_v2.0-node14-current-20260507_114848_arm64.tar.gz
资源服务器分发地址（上传后使用）：https://img.kxunpt.cn/zhct/resource/zhctapp_v2.0-node14-current-20260507_114848_arm64.tar.gz
下载目录：zhct/zhctprompt/docker
SHA256：a84aa9aa4518000dfb39f2b60f18dda1a434935545248ee9ad0007937e757211
```

说明：该镜像在 `zhctapp:v2.0` 基础上补充了 Node 14、npm、Python 2 等前端开发环境，并内置本地启动自愈所需的 `node-sass` arm64 binding 缓存；配合 `start_zhct.sh` 可自动启动 Redis 并启动默认 `store` 的 `public/static`、`public/mobile`、`public/screen` 三个前端项目。`store20` 使用同一容器内的 `nvm` 安装 Node 20 后启动。

仓库地址：

```text
g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/store.git
g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/store.git  # 克隆为 store20，分支 master20
g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/ai_api.git
g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/ai_store.git
g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/ai_app.git
```

## 3. 下载并导入镜像

进入下载目录：

```bash
cd zhct/zhctprompt/docker
```

下载镜像包：

```bash
curl -fL -o zhctapp_v2.0-node14-current-20260507_114848_arm64.tar.gz https://img.kxunpt.cn/zhct/resource/zhctapp_v2.0-node14-current-20260507_114848_arm64.tar.gz
```

如果镜像包已经随 `zhctprompt/docker` 目录提供，则无需下载，直接使用本地文件导入。

导入镜像：

```bash
docker load -i zhctapp_v2.0-node14-current-20260507_114848_arm64.tar.gz
docker images | grep zhctapp
```

预期能看到：

```text
zhctapp   v2.0-node14-current-20260507_114848
```

说明：`zhctapp_v2.0-node14-current-20260507_114848_arm64.tar.gz` 是大文件，已加入 Git 忽略规则，不提交到代码仓库。

## 4. 拉取代码

进入整体目录下的代码目录：

```bash
cd zhct/zhctproject
```

拉取五个仓库：

```bash
git clone g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/store.git store
git clone g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/store.git store20
cd store20
git checkout master20
cd ..
git clone g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/ai_api.git ai_api
git clone g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/ai_store.git ai_store
git clone g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/ai_app.git ai_app
```

如果目录已经存在且不是空目录，不要重复 `git clone`，先检查本地内容。

如果 `store20` 已经存在，切换到 Node 20 对应分支：

```bash
cd zhct/zhctproject/store20
git fetch origin --prune
git checkout master20
git pull --ff-only origin master20
```

## 5. 配置本地配置文件

首次启动容器前，必须先配置好 `store` 和 `ai_api` 的本地配置文件。容器挂载的是宿主机 `zhct` 整体目录，业务运行时会直接读取这些文件。

仓库会拉到的入口文件：

| 文件 | 用途 |
| --- | --- |
| `zhct/zhctproject/store/env.php` | 指定 `TP_ENV=local` 和本地业务标识。 |
| `zhct/zhctproject/ai_api/env.php` | 指定 `TP_ENV=local`、`BUSINESS=aizhct` 和默认企业编号。 |

以下三份是 git 忽略的本地配置文件，拉业务代码不会自动出现，首次启动前必须从 `zhctprompt/docker/local-config-templates/` 复制真实可用配置。

`store`：

| 文件 | 用途 |
| --- | --- |
| `zhct/zhctproject/store/application/config/local/config.php` | 本地应用配置、日志路径、Redis、域名和业务开关等。 |
| `zhct/zhctproject/store/application/config/local/database.php` | 本地数据库连接配置。 |

`ai_api`：

| 文件 | 用途 |
| --- | --- |
| `zhct/zhctproject/ai_api/.env.local` | 本地数据库、Redis、日志路径、接口域名和第三方服务配置。 |

复制真实配置：

```bash
ZHCT_ROOT=/path/to/zhct
CONFIG_SOURCE="$ZHCT_ROOT/zhctprompt/docker/local-config-templates"

mkdir -p "$ZHCT_ROOT/zhctproject/store/application/config/local"
cp "$CONFIG_SOURCE/store/application/config/local/config.php" \
  "$ZHCT_ROOT/zhctproject/store/application/config/local/config.php"
cp "$CONFIG_SOURCE/store/application/config/local/database.php" \
  "$ZHCT_ROOT/zhctproject/store/application/config/local/database.php"
cp "$CONFIG_SOURCE/ai_api/.env.local" \
  "$ZHCT_ROOT/zhctproject/ai_api/.env.local"

rg -n "__[A-Z0-9_]+__" \
  "$ZHCT_ROOT/zhctproject/store/application/config/local" \
  "$ZHCT_ROOT/zhctproject/ai_api/.env.local"
```

检查命令：

```bash
ZHCT_ROOT=/path/to/zhct
cd "$ZHCT_ROOT"
test -f zhctproject/store/env.php
test -f zhctproject/store/application/config/local/config.php
test -f zhctproject/store/application/config/local/database.php
test -f zhctproject/ai_api/env.php
test -f zhctproject/ai_api/.env.local
```

注意：

- `local-config-templates` 是企业内部仓库里的真实配置源，复制后通常不需要再补占位符。
- 占位符检查命令有输出时，说明配置文件里仍有未替换项，需要先补齐再启动。
- 上述三份文件是目标业务仓库里的 git 忽略文件，不要提交到 `store` 或 `ai_api` 业务仓库。
- 不要把上述三份 git 忽略文件提交到业务仓库。
- 新机器缺少这些文件时，先从团队确认的本地配置来源获取，再按当前机器和 Docker 路径调整。
- 日志路径统一落到 `zhct/zhctlogs/log/zhct/` 和 `zhct/zhctlogs/log/aizhct/`。启动脚本的容器入口会把已知旧路径 `/workspace/wwwroot/log/...` 自动替换为 `/workspace/zhct/zhctlogs/log/...`，但配置文件必须先存在。
- 不同同事本地绝对路径见 `../control/local-paths.md`。

## 6. 启动容器

推荐使用随镜像资料提供的脚本：

```bash
cd zhct/zhctprompt/docker
chmod +x start_zhct.sh
./start_zhct.sh
```

当前机器常用启动命令：

```bash
cd /Users/lqt/work/zhct/zhctprompt/docker
HOST_PORT=80 ./start_zhct.sh
```

默认配置：

```text
容器名：zhctapp_v2_0
镜像：zhctapp:v2.0-node14-current-20260507_114848
端口：80:80、8080:8080、8081:8081、8082:8082
挂载：zhct -> /workspace/zhct
日志：zhct/zhctlogs/wwwlogs -> /workspace/wwwlogs
```

默认端口可通过环境变量覆盖：

```bash
HOST_PORT=80 PC_PORT=8080 MOBILE_PORT=8081 SCREEN_PORT=8082 ./start_zhct.sh
```

启动脚本会自动启动三端前台 npm dev server，并等待编译成功：

| 端 | 目录 | 命令 | 端口 | 日志 |
| --- | --- | --- | --- | --- |
| PC 端 | `zhctproject/store/public/static` | `npm run dev` | `8080` | `/tmp/store-static.log` |
| 移动端 | `zhctproject/store/public/mobile` | `npm run serve` | `8081` | `/tmp/store-mobile.log` |
| 大屏端 | `zhctproject/store/public/screen` | `npm run dev` | `8082` | `/tmp/store-screen.log` |

首次启动或 `node_modules` 依赖不完整时，脚本默认会自动执行 `npm install --no-save --package-lock=false`，只补本地 `node_modules`，不改业务仓库的 `package-lock.json`。常用控制参数：

```bash
AUTO_START_FRONTENDS=0 ./start_zhct.sh     # 不自动启动 PC/移动端/大屏端
AUTO_NPM_INSTALL=0 ./start_zhct.sh         # 不自动安装 npm 依赖
FORCE_RESTART_FRONTENDS=1 ./start_zhct.sh  # 强制重启三端前台 dev server
FRONTEND_READY_TIMEOUT=300 ./start_zhct.sh # 前台编译等待时间，单位秒
```

查看三端前端编译日志有两种方式。

先进入容器，再查看日志：

```bash
docker exec -it zhctapp_v2_0 bash
tail -n 200 /tmp/store-static.log
tail -n 200 /tmp/store-mobile.log
tail -n 200 /tmp/store-screen.log
tail -n 200 /tmp/store-static.log.install
tail -n 200 /tmp/store-mobile.log.install
tail -n 200 /tmp/store-screen.log.install
tail -f /tmp/store-static.log
tail -f /tmp/store-mobile.log
tail -f /tmp/store-screen.log
exit
```

不进入容器，直接在宿主机查看日志：

```bash
docker exec zhctapp_v2_0 bash -lc 'tail -n 200 /tmp/store-static.log'
docker exec zhctapp_v2_0 bash -lc 'tail -n 200 /tmp/store-mobile.log'
docker exec zhctapp_v2_0 bash -lc 'tail -n 200 /tmp/store-screen.log'
docker exec zhctapp_v2_0 bash -lc 'tail -n 200 /tmp/store-static.log.install'
docker exec zhctapp_v2_0 bash -lc 'tail -n 200 /tmp/store-mobile.log.install'
docker exec zhctapp_v2_0 bash -lc 'tail -n 200 /tmp/store-screen.log.install'
docker exec zhctapp_v2_0 bash -lc 'tail -f /tmp/store-static.log'
docker exec zhctapp_v2_0 bash -lc 'tail -f /tmp/store-mobile.log'
docker exec zhctapp_v2_0 bash -lc 'tail -f /tmp/store-screen.log'
docker exec zhctapp_v2_0 bash -lc "grep -aE 'Failed to compile|ERROR|Module not found|This dependency was not found' /tmp/store-*.log"
```

也可以手动启动：

```bash
cd zhct
mkdir -p zhctlogs/wwwlogs

docker run -d \
  --name zhctapp_v2_0 \
  -p 80:80 \
  -p 8080:8080 \
  -p 8081:8081 \
  -p 8082:8082 \
  -v "$PWD:[REDACTED_SECRET]] \
  -v "$PWD/zhctlogs/wwwlogs:/workspace/wwwlogs" \
  zhctapp:v2.0-node14-current-20260507_114848
```

## 7. 访问项目

v2.0 不再要求配置本地域名或 `hosts`。

本机访问：

```text
http://127.0.0.1
http://127.0.0.1/aizhct
http://127.0.0.1:8080/#/login
http://127.0.0.1:8080/#/restaurantManagement/restaurantManagement
http://127.0.0.1:8081
http://127.0.0.1:8082
```

PC 端使用 Vue hash 路由，页面入口必须包含 `/#/`。`http://127.0.0.1:8080/p/Restaurant/index` 是后端接口代理地址，不是页面入口；未登录返回 JSON `code=100` 是正常鉴权结果。

局域网访问时，把 `127.0.0.1` 换成本机 IP：

```text
http://本机IP/
http://本机IP/aizhct/
```

## 8. 启动前台 PC 端

前台 PC 端项目在 `store/public/static`，本地开发需要 Node 14。当前容器内使用 `nvm` 安装 Node，不安装 `yarn`，依赖安装和启动都使用 `npm`。

宿主机代码路径：

```text
zhct/zhctproject/store/public/static
```

容器内代码路径：

```text
/workspace/zhct/zhctproject/store/public/static
```

### 8.1 容器端口

前台 PC 端开发服务使用 8080 端口。若还需要同时启动移动端和大屏端，本地统一使用：

```text
PC 端：  8080
移动端：8081
大屏端：8082
```

创建容器时建议同时映射 80、8080、8081、8082：

```bash
cd zhct
mkdir -p zhctlogs/wwwlogs

docker run -d \
  --name zhctapp_v2_0 \
  -p 80:80 \
  -p 8080:8080 \
  -p 8081:8081 \
  -p 8082:8082 \
  -v "$PWD:[REDACTED_SECRET]] \
  -v "$PWD/zhctlogs/wwwlogs:/workspace/wwwlogs" \
  zhctapp:v2.0-node14-current-20260507_114848
```

如果已经存在 `zhctapp_v2_0`，先确认是否可以删除再重建：

```bash
docker rm -f zhctapp_v2_0
```

### 8.2 Node 14 环境

当前可直接使用已提交过 Node 14 环境的镜像：

```text
zhctapp:v2.0-node14-current-20260507_114848
```

容器内检查：

```bash
docker exec zhctapp_v2_0 bash -lc 'node -v && npm -v && command -v yarn || true'
```

预期：

```text
v14.21.3
6.14.18
```

`command -v yarn` 不应输出路径。

如需在原始 `zhctapp:v2.0` 容器中重新安装 Node 14，使用 `nvm`：

```bash
docker exec -it zhctapp_v2_0 bash

export NVM_DIR=/usr/local/nvm
mkdir -p "$NVM_DIR"
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
. "$NVM_DIR/nvm.sh"
nvm install 14.21.3
nvm alias default 14.21.3

ln -sf "$NVM_DIR/versions/node/v14.21.3/bin/node" /usr/local/bin/node
ln -sf "$NVM_DIR/versions/node/v14.21.3/bin/npm" /usr/local/bin/npm
ln -sf "$NVM_DIR/versions/node/v14.21.3/bin/npx" /usr/local/bin/npx

npm uninstall -g yarn || true
rm -f /usr/local/bin/yarn /usr/local/bin/yarnpkg
```

### 8.3 node-sass 说明

项目依赖 `node-sass@4.14.1`。在 arm64 容器中通常没有可直接下载的预编译包，需要 Python 2 编译，不要为了启动前台大改 Sass 代码或替换构建链。

检查 Python 2：

```bash
docker exec zhctapp_v2_0 bash -lc 'python --version'
```

预期：

```text
Python 2.7.18
```

如果容器缺少 Python 2，需要先安装或编译 Python 2.7，并让 npm 使用它：

```bash
npm config set python /usr/local/bin/python2
```

### 8.4 安装依赖并启动

进入前台目录：

```bash
docker exec -it zhctapp_v2_0 bash
cd /workspace/zhct/zhctproject/store/public/static
```

安装依赖：

```bash
npm install
```

检查 `node-sass`：

```bash
./node_modules/.bin/node-sass --version
```

预期包含：

```text
node-sass 4.14.1
libsass 3.5.5
```

后台启动前台开发服务：

```bash
cd /workspace/zhct/zhctproject/store/public/static
nohup env HOST=0.0.0.0 PORT=8080 NODE_OPTIONS=--max_old_space_size=4096 \
  npm run dev > /tmp/store-static.log 2>&1 &
echo $! > /tmp/store-static.pid
```

查看日志：

```bash
tail -f /tmp/store-static.log
```

出现以下内容表示启动成功：

```text
Compiled successfully
Your application is running here: http://0.0.0.0:8080
```

停止前台开发服务：

```bash
kill "$(cat /tmp/store-static.pid)"
```

### 8.5 本地后台代理

前台本地开发环境应指向本机已启动的后台：

```text
http://127.0.0.1/
```

需要确认 `zhctproject/store/public/static/src/util/globalAPI.js` 中开发环境地址为：

```js
const devHttp = 'http://127.0.0.1'
```

`zhctproject/store/public/static/config/index.js` 中 `proxyTable` 使用 `globalAPI.dev`，同时需要保留前端自身页面、热更新和静态资源不被代理到后台。

验证：

```bash
curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/app.js
curl -i http://127.0.0.1:8080/p/Restaurant/index
```

预期：

- `http://127.0.0.1:8080/` 返回前台页面。
- `http://127.0.0.1:8080/#/restaurantManagement/restaurantManagement` 是餐厅管理页面入口。
- `http://127.0.0.1:8080/app.js` 返回前台打包脚本。
- `http://127.0.0.1:8080/p/Restaurant/index` 返回后端接口 JSON；未登录时 `code=100`。

注意：`/#/...` 是浏览器端 hash 路由，`curl` 不会把 `#` 后面的部分发送给服务器，页面路由需要在浏览器里验证。

## 9. 启动移动端

移动端项目在 `store/public/mobile`，本地开发使用 Node 14 和 npm，不安装 `yarn`。

宿主机代码路径：

```text
zhct/zhctproject/store/public/mobile
```

容器内代码路径：

```text
/workspace/zhct/zhctproject/store/public/mobile
```

### 9.1 本地端口和后台地址

移动端开发服务使用 8081 端口，后台接口应指向本机已启动的 `store` 后台：

```text
开发服务：http://127.0.0.1:8081/
后台地址：http://127.0.0.1/
```

需要确认 `zhctproject/store/public/mobile/globalApi.js` 中本地开发配置为：

```js
const domain = 'http'
const devHost = '127.0.0.1'
const localHost = '0.0.0.0'
const localPort = '8081'
```

### 9.2 安装依赖

```bash
docker exec -it zhctapp_v2_0 bash
cd /workspace/zhct/zhctproject/store/public/mobile
npm install
```

移动端依赖 `node-sass@4.14.1`，arm64 容器中通常会使用 Python 2 编译，保持原依赖即可，不需要替换 Sass 构建链。

检查：

```bash
npm ls node-sass --depth=0
```

预期包含：

```text
node-sass@4.14.1
```

### 9.3 启动移动端

```bash
cd /workspace/zhct/zhctproject/store/public/mobile
nohup env HOST=0.0.0.0 PORT=8081 NODE_OPTIONS=--max_old_space_size=4096 \
  npm run serve > /tmp/store-mobile.log 2>&1 &
echo $! > /tmp/store-mobile.pid
```

查看日志：

```bash
tail -f /tmp/store-mobile.log
```

出现以下内容表示启动成功：

```text
Compiled successfully
App running at:
Local: http://localhost:8081/
```

停止移动端：

```bash
kill "$(cat /tmp/store-mobile.pid)"
```

验证：

```bash
curl -i http://127.0.0.1:8081/
curl -i http://127.0.0.1:8081/static/js/app.js
```

预期：

- `http://127.0.0.1:8081/` 返回移动端页面。
- `http://127.0.0.1:8081/static/js/app.js` 返回移动端脚本。

## 10. 启动大屏端

大屏端项目在 `store/public/screen`，本地开发使用 Node 14 和 npm，不安装 `yarn`。

宿主机代码路径：

```text
zhct/zhctproject/store/public/screen
```

容器内代码路径：

```text
/workspace/zhct/zhctproject/store/public/screen
```

### 10.1 本地端口和后台地址

大屏端开发服务使用 8082 端口，后台接口应指向本机已启动的 `store` 后台：

```text
开发服务：http://127.0.0.1:8082/
后台地址：http://127.0.0.1/
```

需要确认 `zhctproject/store/public/screen/src/request/globalApi.js` 中本地开发配置为：

```js
const devHost = '127.0.0.1'
const localHost = '0.0.0.0'
const localPort = '8082'
```

需要确认 `zhctproject/store/public/screen/src/main.js` 中开发环境使用 `globalApi.devUrl`，不要写死线上域名：

```js
Vue.prototype.$baseUrl = process.env.NODE_ENV === 'production' ? globalApi.proUrl + '/' : globalApi.devUrl + '/'
```

`zhctproject/store/public/screen/config/index.js` 中 `proxyTable` 使用 `globalApi.devUrl`，同时需要保留 `index.html`、`app.js`、`/static/`、`/sockjs-node/` 等前端自身资源不被代理到后台。

### 10.2 安装依赖

```bash
docker exec -it zhctapp_v2_0 bash
cd /workspace/zhct/zhctproject/store/public/screen
npm install
```

大屏端当前使用 Dart Sass：

```bash
npm ls sass --depth=0
```

预期包含：

```text
sass
```

### 10.3 启动大屏端

```bash
cd /workspace/zhct/zhctproject/store/public/screen
nohup env HOST=0.0.0.0 PORT=8082 NODE_OPTIONS=--max_old_space_size=4096 \
  npm run dev > /tmp/store-screen.log 2>&1 &
echo $! > /tmp/store-screen.pid
```

查看日志：

```bash
tail -f /tmp/store-screen.log
```

出现以下内容表示启动成功：

```text
Compiled successfully
Your application is running here: http://0.0.0.0:8082
```

停止大屏端：

```bash
kill "$(cat /tmp/store-screen.pid)"
```

验证：

```bash
curl -i http://127.0.0.1:8082/
curl -i http://127.0.0.1:8082/app.js
```

预期：

- `http://127.0.0.1:8082/` 返回大屏端页面。
- `http://127.0.0.1:8082/app.js` 返回大屏端脚本。

## 11. 三端启动状态检查

三端全部启动后，容器内可以检查进程和日志：

```bash
docker exec zhctapp_v2_0 bash -lc '
for f in /tmp/store-static.pid /tmp/store-mobile.pid /tmp/store-screen.pid; do
  echo "$f=$(cat $f 2>/dev/null)"
done
ps -ef | grep -E "webpack-dev-server|vue-cli-service" | grep -v grep
'
```

宿主机验证：

```bash
curl -i http://127.0.0.1/
curl -i http://127.0.0.1/aizhct/
curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/p/Restaurant/index
curl -i http://127.0.0.1:8081/
curl -i http://127.0.0.1:8082/
```

`http://127.0.0.1:8080/#/restaurantManagement/restaurantManagement` 是 PC 餐厅管理页面入口，需要在浏览器中验证；`http://127.0.0.1:8080/p/Restaurant/index` 是接口路径，未登录返回 JSON `code=100` 属于正常鉴权结果。

## 12. 切换启动 store20

`store20` 是第五个仓库，代码目录为 `zhctproject/store20`，分支必须是 `master20`。它和默认 `store` 复用同一个容器、同一组端口，但使用 Node 20。

切换规则：

- 默认启动 `store`，使用 Node 14，三端端口仍是 8080、8081、8082。
- 当需要启动 `store20` 时，先停止默认 `store` 的 Node 14 前端进程，再通过 `nvm use 20` 启动 `store20` 三端。
- 两套代码可以在同一容器内共存；同一时刻同一组端口只跑一套前端。
- 不安装 `yarn`，依赖安装和启动都使用 `npm`。

确认分支：

```bash
cd zhct/zhctproject/store20
git status --short --branch
```

预期分支：

```text
## master20...origin/master20
```

默认启动 Node 14 的 `store` 三端：

```bash
cd zhct/zhctprompt/docker
chmod +x scripts/start_store_frontends.sh
./scripts/start_store_frontends.sh
```

切换启动 Node 20 的 `store20` 三端：

```bash
cd zhct/zhctprompt/docker
chmod +x scripts/start_store20_frontends.sh
./scripts/start_store20_frontends.sh
```

脚本会在容器内执行：

```bash
export NVM_DIR=/usr/local/nvm
. "$NVM_DIR/nvm.sh"
nvm install 20
nvm use 20
```

`store20` 三端路径和启动命令：

| 端 | 容器内路径 | Node | 端口 | 启动方式 |
| --- | --- | --- | --- | --- |
| PC | `/workspace/zhct/zhctproject/store20/public/static` | 20 | 8080 | `npm run dev` |
| 移动端 | `/workspace/zhct/zhctproject/store20/public/mobile` | 20 | 8081 | `npx vue-cli-service serve` |
| 大屏端 | `/workspace/zhct/zhctproject/store20/public/screen` | 20 | 8082 | `npm run dev` |

说明：`store20/public/mobile/package.json` 的 `serve` 脚本是 Windows 风格的 `set NODE_OPTIONS=...`，容器里直接用 Linux 环境变量加 `npx vue-cli-service serve` 启动，不改 Sass 代码。

查看 `store20` 日志：

```bash
docker exec -it zhctapp_v2_0 bash -lc 'tail -f /tmp/store20-static.log'
docker exec -it zhctapp_v2_0 bash -lc 'tail -f /tmp/store20-mobile.log'
docker exec -it zhctapp_v2_0 bash -lc 'tail -f /tmp/store20-screen.log'
```

切回默认 `store`：

```bash
cd zhct/zhctprompt/docker
./scripts/start_store_frontends.sh
```

## 13. 检查容器

```bash
docker ps | grep zhctapp_v2_0
docker logs --tail 100 zhctapp_v2_0
docker exec -it zhctapp_v2_0 /bin/bash
```

容器内检查：

```bash
nginx -t
/usr/local/php7.3/bin/php -v
/usr/local/php7.4/bin/php -v
```

启动脚本会自动验证：

```bash
curl -i http://127.0.0.1/
curl -i http://127.0.0.1/aizhct/
curl -i 'http://127.0.0.1/aizhct/index.php?s=api/dishes.dishes/cate'
```

其中 `aizhct` 菜品分类接口预期返回：

```json
{"status":200,"message":"success"}
```

## 14. 路径说明

主项目：

```text
宿主机：zhct/zhctproject/store
容器内：/workspace/zhct/zhctproject/store
访问：  http://127.0.0.1/
PHP：   7.3
```

store20 前端项目：

```text
宿主机：zhct/zhctproject/store20
容器内：/workspace/zhct/zhctproject/store20
分支：  master20
Node：  20
访问：  http://127.0.0.1:8080/、http://127.0.0.1:8081/、http://127.0.0.1:8082/
```

AI API：

```text
宿主机：zhct/zhctproject/ai_api
容器内：/workspace/zhct/zhctproject/ai_api
访问：  http://127.0.0.1/aizhct/
PHP：   7.4
```

## 15. 给 AI 或同事的从零启动提示词

需要让 AI 或新同事在一台新机器上自动安装并启动项目时，可以直接复制下面这段：

```text
请在本机从零启动 zhct 项目。

要求：
1. 工作目录统一放在 ~/Documents/zhct。
2. 阅读 zhctprompt/README.md 和 zhctprompt/docker/安装部署.md。
3. 下载 Docker 镜像：
   https://img.kxunpt.cn/zhct/resource/zhctapp_v2.0-node14-current-20260507_114848_arm64.tar.gz
4. 导入镜像，镜像标签应为：
   zhctapp:v2.0-node14-current-20260507_114848
5. 拉取五个业务仓库到 zhctproject：
   store、store20、ai_api、ai_store、ai_app。
6. store20 的拉取命令是：
   git clone g***@codeup.aliyun.com:60069db88deaa14d9e02b875/zhct/store.git store20
   然后切换分支：
   git checkout master20
7. 从 zhctprompt/docker/local-config-templates 复制本地配置文件到对应业务项目。
8. 使用 zhctprompt/docker/start_zhct.sh 启动容器。
9. 确认容器 zhctapp_v2_0 映射端口：
   80、8080、8081、8082。
10. 不安装 yarn，只使用 npm。
11. 默认启动 store 三个前端，Node 14：
   - PC：zhctproject/store/public/static，端口 8080，npm run dev
   - 移动端：zhctproject/store/public/mobile，端口 8081，npm run serve
   - 大屏端：zhctproject/store/public/screen，端口 8082，npm run dev
12. 如果要求启动 store20，则停止 store 的 Node14 前端进程，使用 nvm use 20 后启动 store20 三个前端：
   - PC：zhctproject/store20/public/static，端口 8080，npm run dev
   - 移动端：zhctproject/store20/public/mobile，端口 8081，npx vue-cli-service serve
   - 大屏端：zhctproject/store20/public/screen，端口 8082，npm run dev
13. 验证以下地址可访问：
   - http://127.0.0.1/
   - http://127.0.0.1/aizhct/
   - http://127.0.0.1:8080/
   - http://127.0.0.1:8081/
   - http://127.0.0.1:8082/
14. 如果 node-sass 在 arm64 上安装失败，不要改 Sass 代码，默认 store 使用容器内 Python2 编译 node-sass。
15. 最后输出安装过程、访问地址、容器名、镜像名、关键本地路径。
```

如果机器上已有旧容器但配置不一致，可以删除旧容器后按当前文档重建：

```bash
docker rm -f zhctapp_v2_0
cd ~/Documents/zhct/zhctprompt/docker
./start_zhct.sh
```

不要删除 `zhctproject` 里的业务代码目录。

## 16. 说明

- 当前容器启动不依赖 `hosts`。
- 如果代码目录为空，访问时可能返回 `File not found`，这表示 Nginx 和 PHP 已响应，但业务代码尚未拉取或入口文件不存在。
- 如果端口冲突，新建容器时可以换 `HOST_PORT`；如果同名容器已经存在，Docker 不会修改已有端口映射，脚本会停止并提示处理方式。需要保留旧容器并换端口并行启动时，同时指定新的 `CONTAINER_NAME` 和 `HOST_PORT`。
