### Task 7: 实现 `install.sh` Nuxt 启动（GREEN）

**Files:**
- Modify: `deploy/baota/install.sh`（`setup_queue_and_cron` 邻近；`main` 成功输出）
- Test: `tests/deploy/baota/test-install-nuxt-supervisor.sh`

**Interfaces:**
- Consumes: 包内 `web/.output/server/index.mjs`
- Produces: `/etc/supervisor.d/ecshopx-nuxt.conf`（或 conf.d）；成功日志含 `/web/`

- [ ] **Step 1: 增加 `require_node20` 与 `_write_nuxt_conf`**

```bash
require_node20() {
    command -v node >/dev/null 2>&1 || { err "未找到 node，请安装 Node ≥20 后重试。"; exit 1; }
    local major
    major="$(node -p "process.versions.node.split('.')[0]" 2>/dev/null || echo 0)"
    if [ "${major:-0}" -lt 20 ]; then
        err "PC 端需要 Node ≥20，当前: $(node -v 2>/dev/null || echo unknown)"
        exit 1
    fi
}

_write_nuxt_conf() {
    local file="$1" user="$2"
    cat > "$file" <<EOF
[program:ecshopx-nuxt]
command=node .output/server/index.mjs
directory=${SITE_ROOT}/web
environment=NITRO_HOST=127.0.0.1,NITRO_PORT=3000,PORT=3000,NUXT_PUBLIC_API_BASE="/api/h5app",NUXT_INTERNAL_API_BASE="http://127.0.0.1/api/h5app"
stdout_logfile=${SITE_ROOT}/storage/logs/supervisor-nuxt.log
redirect_stderr=true
autostart=true
autorestart=true
numprocs=1
user=${user}
startsecs=3
EOF
}
```

- [ ] **Step 2: 在 `setup_queue_and_cron`（或新函数 `setup_nuxt`，由 `main` 在 `fix_permissions` 之后调用）**

1. `require_node20`
2. `[ -f "$SITE_ROOT/web/.output/server/index.mjs" ] || { err "..."; exit 1; }`
3. 与队列相同探测 `conf_dir`；写入 `ecshopx-nuxt.conf`；`supervisorctl reread && update`
4. 无 Supervisor 时 `err` 提示（与队列一致，不静默跳过 PC——若产品选择与队列同级警告，至少 err）

- [ ] **Step 3: 成功横幅增加** `PC 商城: /web/`

- [ ] **Step 4: Run 契约测试** → PASS

---

