feat(fsgx): 管理后台与部署相关更新
- admin: 路由守卫修复空白页、addRoute、devServer 端口与代理 - admin: package.json 生产构建去掉 NODE_OPTIONS openssl - ajcaptcha: 滑块验证码改用 file 缓存避免 Redis NOAUTH - nginx-crmeb: 增加 81 端口站点 - docs: deploy 补充 NOAUTH/Redis 说明,新增 H5 部署脚本与 nginx 示例 - 其他: database、start-api、swoole ini、uniapp 资源等 Made-with: Cursor
This commit is contained in:
24
docs/deploy-h5-diagnose.sh
Executable file
24
docs/deploy-h5-diagnose.sh
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 诊断 H5 部署问题(Unexpected token '<')
|
||||||
|
# 在服务器上检查:文件是否存在、index.html 引用、Nginx root
|
||||||
|
set -e
|
||||||
|
REMOTE="root@182.92.142.158"
|
||||||
|
REMOTE_PUBLIC="/www/wwwroot/hjf.suzhouyuqi.com/public"
|
||||||
|
|
||||||
|
echo "=== 1. 检查 index.html 引用的 JS 文件 ==="
|
||||||
|
ssh "$REMOTE" "grep -oE 'src=[^>]+\.js' $REMOTE_PUBLIC/index.html 2>/dev/null || echo 'index.html 不存在或无法读取'"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== 2. 检查 static/js 下实际存在的文件 ==="
|
||||||
|
ssh "$REMOTE" "ls $REMOTE_PUBLIC/static/js/index.*.js $REMOTE_PUBLIC/static/js/chunk-vendors.*.js 2>/dev/null || echo '文件不存在'"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== 3. 直接请求 JS 看返回类型(应为 application/javascript) ==="
|
||||||
|
curl -sI "https://hjf.suzhouyuqi.com/static/js/chunk-vendors.54d49a5a.js" | head -5
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== 4. 若上面 Content-Type 不是 javascript,说明 Nginx 未正确提供静态文件 ==="
|
||||||
|
echo "请在宝塔/面板中检查站点配置:"
|
||||||
|
echo " - root 必须为: $REMOTE_PUBLIC"
|
||||||
|
echo " - 添加 location ~ ^/(static|assets|pages)/ { try_files \$uri =404; }"
|
||||||
|
echo "参考: docs/nginx-hjf-cloud.conf.example"
|
||||||
35
docs/deploy-h5.sh
Executable file
35
docs/deploy-h5.sh
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# H5 前端一键部署到云服务器(需 sshpass,或已配置 SSH 免密)
|
||||||
|
# 支持 HBuilder 导出 web 或 h5 路径
|
||||||
|
set -e
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
REMOTE="root@182.92.142.158"
|
||||||
|
REMOTE_PUBLIC="/www/wwwroot/hjf.suzhouyuqi.com/public"
|
||||||
|
BACKUP_DIR="/www/wwwroot/backup"
|
||||||
|
|
||||||
|
# 优先使用 web,其次 h5
|
||||||
|
if [ -d "pro_v3.5.1/view/uniapp/unpackage/dist/build/web" ]; then
|
||||||
|
H5_SRC="pro_v3.5.1/view/uniapp/unpackage/dist/build/web"
|
||||||
|
elif [ -d "pro_v3.5.1/view/uniapp/unpackage/dist/build/h5" ]; then
|
||||||
|
H5_SRC="pro_v3.5.1/view/uniapp/unpackage/dist/build/h5"
|
||||||
|
else
|
||||||
|
echo "错误:未找到 H5 构建产物(web 或 h5),请先用 HBuilder 或 npm run build:h5 打包"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "备份云服务器 public 目录(上一版本)..."
|
||||||
|
ssh "$REMOTE" "mkdir -p $BACKUP_DIR && tar -czf $BACKUP_DIR/hjf_public_\$(date +%Y%m%d_%H%M%S).tar.gz -C /www/wwwroot/hjf.suzhouyuqi.com public && echo '备份完成'"
|
||||||
|
|
||||||
|
echo "上传 H5 到 $REMOTE:$REMOTE_PUBLIC ..."
|
||||||
|
# 先删除旧的 index.html、static、assets、pages,避免 /h5/ 路径残留
|
||||||
|
ssh "$REMOTE" "cd $REMOTE_PUBLIC && rm -f index.html && rm -rf static assets pages 2>/dev/null; true"
|
||||||
|
tar czf - -C "$H5_SRC" . | ssh "$REMOTE" "cd $REMOTE_PUBLIC && tar xzf -"
|
||||||
|
|
||||||
|
echo "修改权限 ..."
|
||||||
|
ssh "$REMOTE" "chown -R www:www $REMOTE_PUBLIC && chmod -R 755 $REMOTE_PUBLIC"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "验证 index.html 引用路径(应为 /static/ 而非 /h5/static/):"
|
||||||
|
ssh "$REMOTE" "grep -oE 'src=[^>]+\.js' $REMOTE_PUBLIC/index.html 2>/dev/null | head -3"
|
||||||
|
echo ""
|
||||||
|
echo "部署完成。访问 https://hjf.suzhouyuqi.com/ 验证。若仍报 Unexpected token '<',见 docs/deploy.md 4.7 节"
|
||||||
233
docs/deploy.md
233
docs/deploy.md
@@ -17,7 +17,49 @@
|
|||||||
|--------|----------|----------------|
|
|--------|----------|----------------|
|
||||||
| 服务器 API | `pro_v3.5.1/`(排除 view、public/admin) | `/www/wwwroot/hjf.suzhouyuqi.com/` |
|
| 服务器 API | `pro_v3.5.1/`(排除 view、public/admin) | `/www/wwwroot/hjf.suzhouyuqi.com/` |
|
||||||
| 管理后台前端 | `pro_v3.5.1/view/admin/dist/` | `/www/wwwroot/hjf.suzhouyuqi.com/public/admin/` |
|
| 管理后台前端 | `pro_v3.5.1/view/admin/dist/` | `/www/wwwroot/hjf.suzhouyuqi.com/public/admin/` |
|
||||||
| H5 前端 | `pro_v3.5.1/view/uniapp/unpackage/dist/build/h5/` | `/www/wwwroot/hjf.suzhouyuqi.com/public/` |
|
| H5 前端 | `pro_v3.5.1/view/uniapp/unpackage/dist/build/web/` 或 `.../h5/` | `/www/wwwroot/hjf.suzhouyuqi.com/public/` |
|
||||||
|
|
||||||
|
### 云服务器 Nginx 配置要求(H5 根路径访问必备)
|
||||||
|
|
||||||
|
域名根路径 `https://hjf.suzhouyuqi.com/` 需正确返回 H5 页面。若出现 `Unexpected token '<'`(请求 JS 时返回 HTML),通常是 Nginx 未正确提供静态文件。
|
||||||
|
|
||||||
|
**必须满足:**
|
||||||
|
|
||||||
|
1. **站点 root 指向 public**:`root /www/wwwroot/hjf.suzhouyuqi.com/public;`
|
||||||
|
2. **index 顺序**:`index index.html index.php;`(优先 index.html)
|
||||||
|
3. **静态文件优先**:对 `/static/`、`/assets/`、`/pages/` 等路径,Nginx 应先尝试本地文件,**仅当文件不存在**时才转发到 PHP/Swoole。
|
||||||
|
|
||||||
|
**推荐配置示例**(宝塔/ LNMP 站点):
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name hjf.suzhouyuqi.com;
|
||||||
|
root /www/wwwroot/hjf.suzhouyuqi.com/public;
|
||||||
|
index index.html index.php;
|
||||||
|
|
||||||
|
# 静态资源:直接由 Nginx 提供,不转发到 PHP
|
||||||
|
location ~ ^/(static|assets|pages)/ {
|
||||||
|
try_files $uri =404;
|
||||||
|
expires 7d;
|
||||||
|
}
|
||||||
|
|
||||||
|
# PHP 请求
|
||||||
|
location ~ \.php$ {
|
||||||
|
# 转发到 Swoole 或 php-fpm,按现有配置
|
||||||
|
}
|
||||||
|
|
||||||
|
# 其余请求:先找静态文件,再走 PHP
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
若使用 `if (!-e $request_filename) { proxy_pass ... }`,需确保**文件存在时不会进入 proxy**,否则 `/static/js/xxx.js` 会被错误地返回 HTML。
|
||||||
|
|
||||||
|
完整示例见 `docs/nginx-hjf-cloud.conf.example`。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -152,6 +194,8 @@ tar -czvf /www/backup/hjf_admin_$(date +%Y%m%d_%H%M%S).tar.gz \
|
|||||||
|
|
||||||
### 3.3 上传(本地)
|
### 3.3 上传(本地)
|
||||||
|
|
||||||
|
**方式 A:rsync**(服务器需已安装 rsync)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/apple/scott2026/huangjingfen
|
cd /Users/apple/scott2026/huangjingfen
|
||||||
|
|
||||||
@@ -160,6 +204,15 @@ rsync -avz --delete \
|
|||||||
root@182.92.142.158:/www/wwwroot/hjf.suzhouyuqi.com/public/admin/
|
root@182.92.142.158:/www/wwwroot/hjf.suzhouyuqi.com/public/admin/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**方式 B:tar + ssh**(服务器无 rsync 时使用)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/apple/scott2026/huangjingfen
|
||||||
|
|
||||||
|
tar czf - -C pro_v3.5.1/view/admin/dist . | \
|
||||||
|
ssh root@182.92.142.158 "cd /www/wwwroot/hjf.suzhouyuqi.com/public && rm -rf admin && mkdir -p admin && tar xzf - -C admin"
|
||||||
|
```
|
||||||
|
|
||||||
### 3.4 上传后修改权限(服务器)
|
### 3.4 上传后修改权限(服务器)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -173,13 +226,56 @@ chmod -R 775 /www/wwwroot/hjf.suzhouyuqi.com/public/admin
|
|||||||
|
|
||||||
浏览器访问 `http://hjf.suzhouyuqi.com/admin/login`,确认页面正常。
|
浏览器访问 `http://hjf.suzhouyuqi.com/admin/login`,确认页面正常。
|
||||||
|
|
||||||
|
### 3.6 本地环境部署
|
||||||
|
|
||||||
|
将管理后台前端打包并部署到本机,配合 `nginx-crmeb.conf` 与 Swoole 使用。
|
||||||
|
|
||||||
|
**前置条件:**
|
||||||
|
|
||||||
|
- Nginx 已加载 `pro_v3.5.1/nginx-crmeb.conf`(`root` 指向 `pro_v3.5.1/public`,80 反代到 20199)
|
||||||
|
- Swoole API 已启动:`./help/start-api.sh` 或 `php -d memory_limit=300M think swoole`
|
||||||
|
|
||||||
|
**步骤:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 本地构建(同 3.1)
|
||||||
|
cd /Users/apple/scott2026/huangjingfen/pro_v3.5.1/view/admin
|
||||||
|
npm install # 依赖有变更时执行
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# 2. 将构建产物复制到 public/admin(覆盖旧文件)
|
||||||
|
cd /Users/apple/scott2026/huangjingfen
|
||||||
|
rm -rf pro_v3.5.1/public/admin
|
||||||
|
cp -r pro_v3.5.1/view/admin/dist pro_v3.5.1/public/admin
|
||||||
|
```
|
||||||
|
|
||||||
|
或使用 rsync(保留权限、便于增量更新):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/apple/scott2026/huangjingfen
|
||||||
|
rsync -av --delete pro_v3.5.1/view/admin/dist/ pro_v3.5.1/public/admin/
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证:**
|
||||||
|
|
||||||
|
浏览器访问 `http://127.0.0.1/admin/` 或 `http://127.0.0.1/admin/login`,确认管理后台页面正常。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 四、子项目三:H5 前端
|
## 四、子项目三:H5 前端
|
||||||
|
|
||||||
仅部署 H5 构建产物到 `public/`(站点根目录)。
|
仅部署 H5 构建产物到 `public/`(站点根目录)。部署时仅覆盖 H5 相关文件,不删除 `admin/`、`index.php` 等。
|
||||||
|
|
||||||
### 4.1 本地构建
|
### 4.1 本地打包(HBuilder 或 npm)
|
||||||
|
|
||||||
|
**方式 A:HBuilder 打包(推荐)**
|
||||||
|
|
||||||
|
1. 用 HBuilderX 打开 `pro_v3.5.1/view/uniapp` 项目
|
||||||
|
2. 确认 `config/app.js` 中 `BASE_HOST` 已设为云服务器域名(如 `hjf.suzhouyuqi.com`)
|
||||||
|
3. 菜单:发行 → 网站-H5 手机版(或 Web) → 填写网站标题 → 发行
|
||||||
|
4. 构建产物在 `view/uniapp/unpackage/dist/build/web/` 或 `.../build/h5/`
|
||||||
|
|
||||||
|
**方式 B:命令行构建**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/apple/scott2026/huangjingfen/pro_v3.5.1/view/uniapp
|
cd /Users/apple/scott2026/huangjingfen/pro_v3.5.1/view/uniapp
|
||||||
@@ -190,18 +286,24 @@ npm run build:h5
|
|||||||
|
|
||||||
构建产物在 `view/uniapp/unpackage/dist/build/h5/`。
|
构建产物在 `view/uniapp/unpackage/dist/build/h5/`。
|
||||||
|
|
||||||
### 4.2 备份(服务器)
|
### 4.2 备份(服务器,上传前执行)
|
||||||
|
|
||||||
|
上传前在服务器备份 `public` 目录,便于回滚:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh root@182.92.142.158
|
ssh root@182.92.142.158
|
||||||
|
|
||||||
mkdir -p /www/backup
|
mkdir -p /www/wwwroot/backup
|
||||||
tar -czvf /www/backup/hjf_public_$(date +%Y%m%d_%H%M%S).tar.gz \
|
tar -czvf /www/wwwroot/backup/hjf_public_$(date +%Y%m%d_%H%M%S).tar.gz \
|
||||||
-C /www/wwwroot/hjf.suzhouyuqi.com public
|
-C /www/wwwroot/hjf.suzhouyuqi.com public
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 一键部署脚本 `deploy-h5.sh` 会自动执行此备份后再上传。
|
||||||
|
|
||||||
### 4.3 上传(本地)
|
### 4.3 上传(本地)
|
||||||
|
|
||||||
|
**方式 A:rsync**(服务器需已安装 rsync)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/apple/scott2026/huangjingfen
|
cd /Users/apple/scott2026/huangjingfen
|
||||||
|
|
||||||
@@ -212,9 +314,122 @@ rsync -avz \
|
|||||||
|
|
||||||
> 不使用 `--delete`,避免覆盖或删除 `admin/`、`index.php` 等文件。
|
> 不使用 `--delete`,避免覆盖或删除 `admin/`、`index.php` 等文件。
|
||||||
|
|
||||||
### 4.4 验证
|
**方式 B:tar + ssh**(服务器无 rsync 时使用)
|
||||||
|
|
||||||
浏览器访问 `http://hjf.suzhouyuqi.com/`,确认 H5 页面正常。
|
```bash
|
||||||
|
cd /Users/apple/scott2026/huangjingfen
|
||||||
|
|
||||||
|
tar czf - -C pro_v3.5.1/view/uniapp/unpackage/dist/build/h5 . | \
|
||||||
|
ssh root@182.92.142.158 "cd /www/wwwroot/hjf.suzhouyuqi.com/public && tar xzf -"
|
||||||
|
```
|
||||||
|
|
||||||
|
> 仅解压覆盖 H5 文件(index.html、static/ 等),不删除 `admin/`。
|
||||||
|
|
||||||
|
**方式 C:scp**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/apple/scott2026/huangjingfen
|
||||||
|
|
||||||
|
scp -r pro_v3.5.1/view/uniapp/unpackage/dist/build/h5/* \
|
||||||
|
root@182.92.142.158:/www/wwwroot/hjf.suzhouyuqi.com/public/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 上传后修改权限(服务器)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh root@182.92.142.158
|
||||||
|
|
||||||
|
chown -R www:www /www/wwwroot/hjf.suzhouyuqi.com/public
|
||||||
|
chmod -R 755 /www/wwwroot/hjf.suzhouyuqi.com/public
|
||||||
|
```
|
||||||
|
|
||||||
|
> 若仅更新 H5 根目录下的 index.html、static 等,可只对相关路径执行:
|
||||||
|
> `chown -R www:www /www/wwwroot/hjf.suzhouyuqi.com/public/index.html /www/wwwroot/hjf.suzhouyuqi.com/public/static`
|
||||||
|
|
||||||
|
### 4.5 一键部署脚本(本地执行)
|
||||||
|
|
||||||
|
脚本 `docs/deploy-h5.sh` 会依次执行:**备份上一版本 → 上传 → 修改权限**。执行前确保已打包好 H5(`unpackage/dist/build/web/` 或 `h5/` 存在):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# H5 前端一键部署到云服务器(需 sshpass,或已配置 SSH 免密)
|
||||||
|
# 支持 HBuilder 导出 web 或 h5 路径
|
||||||
|
set -e
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
REMOTE="root@182.92.142.158"
|
||||||
|
REMOTE_PUBLIC="/www/wwwroot/hjf.suzhouyuqi.com/public"
|
||||||
|
BACKUP_DIR="/www/wwwroot/backup"
|
||||||
|
|
||||||
|
# 优先使用 web,其次 h5
|
||||||
|
if [ -d "pro_v3.5.1/view/uniapp/unpackage/dist/build/web" ]; then
|
||||||
|
H5_SRC="pro_v3.5.1/view/uniapp/unpackage/dist/build/web"
|
||||||
|
elif [ -d "pro_v3.5.1/view/uniapp/unpackage/dist/build/h5" ]; then
|
||||||
|
H5_SRC="pro_v3.5.1/view/uniapp/unpackage/dist/build/h5"
|
||||||
|
else
|
||||||
|
echo "错误:未找到 H5 构建产物,请先用 HBuilder 或 npm run build:h5 打包"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "备份云服务器 public 目录(上一版本)..."
|
||||||
|
ssh "$REMOTE" "mkdir -p $BACKUP_DIR && tar -czf $BACKUP_DIR/hjf_public_\$(date +%Y%m%d_%H%M%S).tar.gz -C /www/wwwroot/hjf.suzhouyuqi.com public && echo '备份完成'"
|
||||||
|
|
||||||
|
echo "上传 H5 到 $REMOTE:$REMOTE_PUBLIC ..."
|
||||||
|
tar czf - -C "$H5_SRC" . | ssh "$REMOTE" "cd $REMOTE_PUBLIC && tar xzf -"
|
||||||
|
|
||||||
|
echo "修改权限 ..."
|
||||||
|
ssh "$REMOTE" "chown -R www:www $REMOTE_PUBLIC && chmod -R 755 $REMOTE_PUBLIC"
|
||||||
|
|
||||||
|
echo "部署完成,请访问 https://hjf.suzhouyuqi.com/ 验证"
|
||||||
|
```
|
||||||
|
|
||||||
|
用法:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/apple/scott2026/huangjingfen
|
||||||
|
chmod +x docs/deploy-h5.sh
|
||||||
|
./docs/deploy-h5.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
若需密码,可安装 `sshpass` 后使用:`SSHPASS='A@123456' sshpass -e ./docs/deploy-h5.sh`
|
||||||
|
|
||||||
|
### 4.6 验证
|
||||||
|
|
||||||
|
浏览器访问 `http://hjf.suzhouyuqi.com/` 或 `https://hjf.suzhouyuqi.com/`,确认 H5 页面正常。
|
||||||
|
|
||||||
|
### 4.7 H5 报错 `Unexpected token '<'` 排查
|
||||||
|
|
||||||
|
**现象**:访问根路径时控制台报 `index.xxx.js:1 Uncaught SyntaxError: Unexpected token '<'`。
|
||||||
|
|
||||||
|
**原因**:请求 JS 时服务器返回了 HTML(404 页或 index.php 输出)。常见情况:
|
||||||
|
- **index.html 引用 `/h5/static/...`**:旧版 index 与当前部署路径不一致,`/h5/static/js/xxx.js` 返回 404 → HTML
|
||||||
|
- **Nginx 未正确提供静态文件**:root 未指向 `.../public` 或缺少 `location ~ ^/(static|assets|pages)/`
|
||||||
|
|
||||||
|
**排查步骤**:
|
||||||
|
|
||||||
|
1. **检查 index.html 引用路径**:
|
||||||
|
```bash
|
||||||
|
curl -s "https://hjf.suzhouyuqi.com/" | grep -oE 'src=[^>]+\.js'
|
||||||
|
```
|
||||||
|
若出现 `/h5/static/`,说明服务器 index.html 为旧版,需重新部署。
|
||||||
|
2. **重新构建并部署**(部署脚本会先清理旧 index.html、static 等):
|
||||||
|
```bash
|
||||||
|
# 本地:HBuilder 发行 H5 或 npm run build:h5
|
||||||
|
./docs/deploy-h5.sh
|
||||||
|
```
|
||||||
|
3. **确认 Nginx root**:站点 root 必须为 `.../public`,见上文「云服务器 Nginx 配置要求」。
|
||||||
|
4. **清除浏览器缓存**:强制刷新(Ctrl+Shift+R)或无痕模式访问。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四(补充)、管理后台登录滑块:`NOAUTH Authentication required`
|
||||||
|
|
||||||
|
若访问 `/adminapi/ajcaptcha` 或 `/adminapi/is_captcha` 返回 `{"msg":"NOAUTH Authentication required."}`,说明 **Redis 需要密码但 `.env` 中 `[REDIS]` 的 `PASSWORD` 与服务器 Redis 不一致**(或 Redis 开启了 `requirepass` 而 `.env` 为空)。
|
||||||
|
|
||||||
|
**处理:**
|
||||||
|
|
||||||
|
1. 在服务器上核对 Redis:`redis-cli -h <主机> -p 6379 -a '<实际密码>' ping`,将正确密码写入站点根目录 `.env` 的 `PASSWORD = ...`。
|
||||||
|
2. 重启 Swoole / PHP 进程使配置生效。
|
||||||
|
3. 项目已把 **滑块验证码(ajcaptcha)缓存改为本地 file**,不依赖 Redis 认证;部署后请同步更新 `config/ajcaptcha.php`。登录次数统计等仍走 Redis,**长期仍须修正 Redis 配置**。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -247,5 +462,5 @@ tar -xzvf /www/backup/hjf_admin_YYYYMMDD_HHMMSS.tar.gz -C /www/wwwroot/hjf.suzho
|
|||||||
|
|
||||||
# 回滚 H5(恢复 public/ 目录)
|
# 回滚 H5(恢复 public/ 目录)
|
||||||
rm -rf /www/wwwroot/hjf.suzhouyuqi.com/public
|
rm -rf /www/wwwroot/hjf.suzhouyuqi.com/public
|
||||||
tar -xzvf /www/backup/hjf_public_YYYYMMDD_HHMMSS.tar.gz -C /www/wwwroot/hjf.suzhouyuqi.com
|
tar -xzvf /www/wwwroot/backup/hjf_public_YYYYMMDD_HHMMSS.tar.gz -C /www/wwwroot/hjf.suzhouyuqi.com
|
||||||
```
|
```
|
||||||
|
|||||||
289
docs/execution-plan.md
Normal file
289
docs/execution-plan.md
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
# 黄精粉健康商城 · 剩余开发任务执行方案
|
||||||
|
|
||||||
|
> 基于 PRD_V2.md + openclaw-frontend-tasks.md 的现状分析
|
||||||
|
> 制定日期:2026-03-15
|
||||||
|
> 当前分支:claude/hjf-queue-admin-apis-hsymG
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、现状盘点(已完成 vs 待完成)
|
||||||
|
|
||||||
|
### ✅ 已完成的任务
|
||||||
|
|
||||||
|
| 阶段 | 任务 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| Phase 0 | P0-01, P0-02 | UniApp + Admin Mock 数据文件 |
|
||||||
|
| Stage 1A | P1A-01~06 | 全部6个 API 模块(uniapp + admin) |
|
||||||
|
| Stage 1B | P1B-01~04 | 全部4个公共组件(QueueProgress / AssetCard / MemberBadge / RefundNotice) |
|
||||||
|
| Stage 1C | P1C-01~06 | 全部6个新 UniApp 页面(公排状态/历史/规则 + 资产总览/积分明细 + 引导页) |
|
||||||
|
| Stage 1D | P1D-02 | 商品详情页:`is_queue_goods` 角标 + 公排提示条 |
|
||||||
|
| Stage 1D | P1D-03 | 购买确认页:多单拆分提示 + 公排入队说明 |
|
||||||
|
| Stage 1D | P1D-04 | 支付结果页:公排入队成功提示 + 查看公排入口 |
|
||||||
|
| Stage 1D | P1D-06 | 提现页:7% 手续费动态计算 + 提示文案 |
|
||||||
|
| Stage 1E | P1E-01~06 | 全部6个 Admin 新页面(公排订单/财务/配置 + 会员管理/配置 + 积分日志) |
|
||||||
|
| Stage 1F | P1F-01~07 | 全部路由注册(pages.json + Admin hjfQueue.js 路由模块 + index.js 导入) |
|
||||||
|
| Stage 1G | P1G-01 | Admin 用户管理列表:`member_level`、`no_assess` 列和筛选项 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ⏳ 待完成的任务(本方案覆盖范围)
|
||||||
|
|
||||||
|
```
|
||||||
|
Phase 1 尾单(4项)
|
||||||
|
├── P1D-01 首页:报单商品角标 + 公排入口Banner
|
||||||
|
├── P1D-05 推荐收益页:积分替换佣金显示
|
||||||
|
├── P1D-07 个人中心:HjfMemberBadge等级徽章嵌入
|
||||||
|
└── P1G-02 Admin商品编辑:报单标记 + 积分支付白名单
|
||||||
|
|
||||||
|
Phase 2 数据库迁移(5项)
|
||||||
|
Phase 3 后端 API 开发(16项)
|
||||||
|
Phase 4 前后端联调集成(5项)
|
||||||
|
Phase 5 完整测试(8项)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、执行方案
|
||||||
|
|
||||||
|
### 阶段 A:Phase 1 收尾(前端,可立即执行)
|
||||||
|
|
||||||
|
> 依赖:无。可在当前 Mock 模式下独立完成。
|
||||||
|
> 目标:让 Phase 1 所有38个任务全部 `[x]`,解锁 CP-01 评审检查点。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 任务 A1 — P1D-01:首页报单商品角标
|
||||||
|
|
||||||
|
**文件**:`pro_v3.5.1/view/uniapp/pages/index/index.vue`
|
||||||
|
|
||||||
|
**改造内容**:
|
||||||
|
1. 在商品列表卡片的商品名/图片处,检查 `item.is_queue_goods == 1`,叠加渲染 `报单` 角标(红色标签,参考 goods_details 中已有的 `.queue-goods-tag` 样式)。
|
||||||
|
2. 在首页 Banner 区或活动专区下方,增加"公排进度"快捷入口行(复用 `HjfQueueProgress` 组件缩略版,或仅放文字按钮跳转 `/pages/queue/status`)。
|
||||||
|
3. 无需新增 API 调用,角标从商品列表字段 `is_queue_goods` 读取即可。
|
||||||
|
|
||||||
|
**验收标准**:报单商品卡片右上角出现红色"报单"角标;点击公排入口可跳转公排状态页。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 任务 A2 — P1D-05:推荐收益页积分替换佣金
|
||||||
|
|
||||||
|
**文件**:`pro_v3.5.1/view/uniapp/pages/users/user_spread_money/index.vue`
|
||||||
|
|
||||||
|
**改造内容**:
|
||||||
|
1. 将列表中"佣金"字样统一替换为"积分",金额字段从 `money`/`commission` 改为读取 `points`。
|
||||||
|
2. 展示积分类型标签:`reward_direct`(直推奖励)/ `reward_umbrella`(伞下奖励)。
|
||||||
|
3. 导入 `import { getTeamIncome } from '@/api/hjfMember.js'`,替换原有 API 调用。
|
||||||
|
4. 数值格式:整数积分,不保留小数;去掉 `¥` 符号,改为"积分"后缀。
|
||||||
|
|
||||||
|
**验收标准**:推荐收益列表显示积分数量而非金额,类型标签正确区分直推/伞下。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 任务 A3 — P1D-07:个人中心会员等级徽章
|
||||||
|
|
||||||
|
**文件**:`pro_v3.5.1/view/uniapp/pages/user/index.vue`
|
||||||
|
|
||||||
|
**改造内容**:
|
||||||
|
1. 引入 `HjfMemberBadge` 组件,在用户头像/昵称旁嵌入等级徽章。
|
||||||
|
```js
|
||||||
|
import HjfMemberBadge from '@/components/HjfMemberBadge.vue'
|
||||||
|
```
|
||||||
|
2. 从 `getMemberInfo` API(已有 Mock)获取 `member_level`,传入组件 `:level` prop。
|
||||||
|
3. 在资产快捷入口区域已有的 `hjf-nav-row` 基础上,补充"待释放积分"数值预览(展示 `frozen_points`,不换页即可看到大数字)。
|
||||||
|
4. 已有的公排查询 + 资产入口导航行保持不变,不重复建设。
|
||||||
|
|
||||||
|
**验收标准**:昵称旁出现对应等级的彩色徽章;资产行显示待释放积分数。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 任务 A4 — P1G-02:Admin 商品编辑-报单标记与支付方式
|
||||||
|
|
||||||
|
**文件**:`pro_v3.5.1/view/admin/src/pages/product/creatProduct/index.vue`
|
||||||
|
|
||||||
|
**改造内容**:
|
||||||
|
1. 在商品基本信息 Tab 中增加"报单商品"开关(iView `i-switch`),绑定 `formValidate.is_queue_goods`,默认 `false`。
|
||||||
|
2. 在支付方式 Tab / 销售设置区域,增加复选框组"允许积分支付"(`allow_pay_types`),选项:`待释放积分`、`已释放积分`;报单商品开关开启时,此项置灰并强制清空。
|
||||||
|
3. 表单提交时将 `is_queue_goods`(0/1)和 `allow_pay_types`(数组序列化)一并提交。
|
||||||
|
4. 编辑回显时正确反填两个字段。
|
||||||
|
|
||||||
|
**验收标准**:新建/编辑商品可设置报单标记;报单商品自动禁用积分支付选项。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段 B:Phase 2 数据库迁移
|
||||||
|
|
||||||
|
> 依赖:后端开发环境就绪(ThinkPHP 8 + MySQL 8.0)。
|
||||||
|
> 建议由后端工程师执行,前端工程师无需等待此阶段。
|
||||||
|
|
||||||
|
| 任务 | 操作 | 目标 |
|
||||||
|
|------|------|------|
|
||||||
|
| P2-01 | CREATE TABLE | `eb_queue_pool`(公排池,9个字段,含复合索引) |
|
||||||
|
| P2-02 | CREATE TABLE | `eb_points_release_log`(积分释放日志,7个字段) |
|
||||||
|
| P2-03 | ALTER TABLE | `eb_user` 增加4字段:`member_level`、`no_assess`、`frozen_points`、`available_points` |
|
||||||
|
| P2-04 | ALTER TABLE | `eb_store_product` 增加2字段:`is_queue_goods`、`allow_pay_types` |
|
||||||
|
| P2-05 | INSERT | `eb_system_config` 插入9项系统配置键值对(公排倍数、释放比例、手续费率、各等级门槛和奖励) |
|
||||||
|
|
||||||
|
**关键索引(P2-01)**:
|
||||||
|
```sql
|
||||||
|
INDEX idx_uid (uid),
|
||||||
|
INDEX idx_status_add_time (status, add_time),
|
||||||
|
INDEX idx_queue_no (queue_no),
|
||||||
|
INDEX idx_trigger_batch (trigger_batch)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段 C:Phase 3 后端 API 开发
|
||||||
|
|
||||||
|
> 依赖:Phase 2 完成。
|
||||||
|
> 开发顺序:先核心引擎,再外围接口,最后定时任务。
|
||||||
|
|
||||||
|
#### C1 — 公排引擎(优先级最高)
|
||||||
|
|
||||||
|
| 任务 | 文件/类 | 内容 |
|
||||||
|
|------|---------|------|
|
||||||
|
| P3-01 | `QueuePool` Service | 入队逻辑(写 `eb_queue_pool`,Redis 分布式锁防并发) |
|
||||||
|
| P3-02 | `QueueRefund` Service | 退款触发逻辑(每入N单检查退款,使用 think-queue 异步处理) |
|
||||||
|
| P3-03 | `QueueController` | 用户端接口:`GET /hjf/queue/status`、`GET /hjf/queue/history` |
|
||||||
|
| P3-04 | `AdminQueueController` | Admin接口:`GET /hjf/queue/order`、`GET /hjf/queue/config`、`POST /hjf/queue/config`、`GET /hjf/queue/finance` |
|
||||||
|
|
||||||
|
**核心逻辑要点**:
|
||||||
|
- 支付回调成功后:判断 `is_queue_goods` → 多单拆分 → 逐单调用 `QueuePool::enqueue()` → 检查触发条件
|
||||||
|
- Redis Key:`hjf:queue:lock`(分布式锁),`hjf:queue:pending_count`(待触发计数)
|
||||||
|
- 退款写入 `eb_user.now_money`(复用 CRMEB 余额字段),记录 `eb_user_bill`
|
||||||
|
|
||||||
|
#### C2 — 积分奖励引擎
|
||||||
|
|
||||||
|
| 任务 | 文件/类 | 内容 |
|
||||||
|
|------|---------|------|
|
||||||
|
| P3-05 | `PointsReward` Service | 级差计算:按会员等级发放直推/伞下积分,写入 `frozen_points` |
|
||||||
|
| P3-06 | `PointsRelease` Job | 每日凌晨定时任务:`frozen_points × 0.4‰ → available_points`,写 `eb_points_release_log` |
|
||||||
|
| P3-07 | `PointsController` | 用户端接口:`GET /hjf/points/detail`(5类型筛选,分页) |
|
||||||
|
| P3-08 | `AdminPointsController` | Admin接口:`GET /hjf/points/release-log` |
|
||||||
|
|
||||||
|
**每日释放公式**:`release_amount = FLOOR(frozen_points × rate / 1000)`,`rate` 取系统配置 `hjf_release_rate`(默认 4)。
|
||||||
|
|
||||||
|
#### C3 — 会员等级体系
|
||||||
|
|
||||||
|
| 任务 | 文件/类 | 内容 |
|
||||||
|
|------|---------|------|
|
||||||
|
| P3-09 | `MemberLevel` Service | 升级判断:直推单数 / 伞下业绩单数达标后自动升级;伞下业绩分离逻辑 |
|
||||||
|
| P3-10 | `AdminMemberController` | Admin接口:`GET /hjf/member/list`、`PUT /hjf/member/level/:uid`、`GET/POST /hjf/member/config` |
|
||||||
|
|
||||||
|
**升级触发时机**:每次订单支付回调完成后,对推荐链上的所有上级异步检查升级条件。
|
||||||
|
|
||||||
|
#### C4 — 资产接口
|
||||||
|
|
||||||
|
| 任务 | 文件/类 | 内容 |
|
||||||
|
|------|---------|------|
|
||||||
|
| P3-11 | `AssetsController` | `GET /hjf/assets/overview`:返回余额 + 积分汇总(复用 `eb_user` 字段) |
|
||||||
|
| P3-12 | `AssetsController` | `GET /hjf/assets/cash/detail`:现金流水(分页,复用 `eb_user_bill`) |
|
||||||
|
|
||||||
|
#### C5 — 路由注册
|
||||||
|
|
||||||
|
| 任务 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| P3-13 | `route/api.php`:注册用户端全部 hjf 路由(含鉴权中间件) |
|
||||||
|
| P3-14 | `route/admin.php`:注册 Admin 端全部 hjf 路由(含权限中间件) |
|
||||||
|
|
||||||
|
#### C6 — 单元测试桩
|
||||||
|
|
||||||
|
| 任务 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| P3-15 | 公排引擎单元测试:入队/触发退款/分布式锁 |
|
||||||
|
| P3-16 | 积分计算单元测试:级差计算/每日释放精度(bcmath) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段 D:Phase 4 前后端联调集成
|
||||||
|
|
||||||
|
> 依赖:Phase 2 + Phase 3 完成,测试环境可访问真实 API。
|
||||||
|
|
||||||
|
| 任务 | 内容 | 操作 |
|
||||||
|
|------|------|------|
|
||||||
|
| P4-01 | 关闭 Mock 开关 | 将所有 `const USE_MOCK = true` 改为 `false`(UniApp + Admin 共8个文件) |
|
||||||
|
| P4-02 | UniApp 冒烟测试 | 登录 → 查看公排状态 → 资产总览 → 积分明细 → 推荐收益 |
|
||||||
|
| P4-03 | Admin 冒烟测试 | 公排订单列表 → 公排配置保存 → 会员等级调整 → 积分日志查询 |
|
||||||
|
| P4-04 | 支付回调联调 | 测试购买报单商品 → 公排入队 → 积分发放 → 等级升级完整链路 |
|
||||||
|
| P4-05 | 定时任务验证 | 手动触发每日积分释放任务,验证 `release_log` 记录正确 |
|
||||||
|
|
||||||
|
**Mock 关闭检查清单**:
|
||||||
|
```
|
||||||
|
uniapp/api/hjfQueue.js USE_MOCK → false
|
||||||
|
uniapp/api/hjfAssets.js USE_MOCK → false
|
||||||
|
uniapp/api/hjfMember.js USE_MOCK → false
|
||||||
|
admin/src/api/hjfQueue.js USE_MOCK → false
|
||||||
|
admin/src/api/hjfMember.js USE_MOCK → false
|
||||||
|
admin/src/api/hjfPoints.js USE_MOCK → false
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 阶段 E:Phase 5 完整测试
|
||||||
|
|
||||||
|
> 依赖:Phase 4 联调通过。
|
||||||
|
|
||||||
|
| 任务 | 类型 | 内容 |
|
||||||
|
|------|------|------|
|
||||||
|
| P5-01 | 前端渲染测试 | 所有新页面在3个Mock场景(A/B/C)下截图验收 |
|
||||||
|
| P5-02 | 后端接口测试 | 用 Postman/Apifox 验证所有 P3 接口的响应格式和边界值 |
|
||||||
|
| P5-03 | 公排边界测试 | 精确触发:第4单入队时退款到第1单;多人同时入队(并发锁) |
|
||||||
|
| P5-04 | 积分精度测试 | bcmath 计算:`1000000 × 4 / 1000 = 4000`(无浮点误差) |
|
||||||
|
| P5-05 | 会员升级测试 | 直推3单后自动升级创客;伞下30单升云店;业绩分离逻辑 |
|
||||||
|
| P5-06 | 并发压测 | 1000并发用户同时访问公排状态页;公排入队 200 TPS |
|
||||||
|
| P5-07 | E2E 全流程 | 新用户注册 → 引导页 → 购买报单商品 → 等待公排退款 → 申请提现 |
|
||||||
|
| P5-08 | 回归测试 | CRMEB 原有功能(登录/商品/订单/支付)未被改造影响 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、执行优先级与分工建议
|
||||||
|
|
||||||
|
```
|
||||||
|
立即可执行(无依赖,Agent 可直接实施)
|
||||||
|
├── A1 首页报单角标 ← 最简单,约30分钟
|
||||||
|
├── A2 推荐收益页积分替换 ← 约45分钟
|
||||||
|
├── A3 个人中心等级徽章 ← 约30分钟
|
||||||
|
└── A4 Admin商品编辑改造 ← 约60分钟
|
||||||
|
|
||||||
|
等待后端就绪(并行推进)
|
||||||
|
├── B 数据库迁移 ← DBA/后端工程师
|
||||||
|
├── C 后端API开发 ← 后端工程师(C1优先)
|
||||||
|
└── D 联调集成 ← 前后端协作
|
||||||
|
|
||||||
|
最终验收
|
||||||
|
└── E 完整测试 ← 测试工程师
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键路径**:`A1~A4 完成` → `CP-01 评审` → `B+C 并行` → `D 联调` → `E 测试`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、风险点与注意事项
|
||||||
|
|
||||||
|
| 风险 | 描述 | 应对措施 |
|
||||||
|
|------|------|---------|
|
||||||
|
| 公排并发竞争 | 多单同时入队可能重复触发退款 | Redis `SET NX EX` 分布式锁,退款前二次检查状态 |
|
||||||
|
| 积分浮点误差 | `3600 × 0.4‰` 在 PHP 中存在精度问题 | 全程使用 `bcmath`:`bcmul($points, '4', 0)` → `bcdiv(..., '1000', 0)` |
|
||||||
|
| 伞下业绩分离 | 下级升级后业绩需从上级扣除 | 升级事件写入消息队列,异步重算上级业绩;加数据库事务 |
|
||||||
|
| Admin 路由权限 | hjf 新路由需配置到角色权限表 | P3-14 后端路由注册时同步写 `eb_system_menus` |
|
||||||
|
| CRMEB 原生字段冲突 | `eb_user` 新增字段可能影响原有查询 | ALTER TABLE 使用 `DEFAULT 0`,不破坏现有 NULL 约束 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、当前可立即下达的指令(Agent 参考)
|
||||||
|
|
||||||
|
按优先级排序,每条指令对应一个独立任务,完成后 `git commit` 即可:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. feat(P1D-01): 首页报单商品角标与公排快捷入口
|
||||||
|
文件: pages/index/index.vue
|
||||||
|
|
||||||
|
2. feat(P1D-05): 推荐收益页积分替换佣金
|
||||||
|
文件: pages/users/user_spread_money/index.vue
|
||||||
|
|
||||||
|
3. feat(P1D-07): 个人中心嵌入HjfMemberBadge等级徽章
|
||||||
|
文件: pages/user/index.vue
|
||||||
|
|
||||||
|
4. feat(P1G-02): Admin商品编辑报单标记与积分支付配置
|
||||||
|
文件: admin/src/pages/product/creatProduct/index.vue
|
||||||
|
```
|
||||||
34
docs/nginx-hjf-cloud.conf.example
Normal file
34
docs/nginx-hjf-cloud.conf.example
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# 云服务器 hjf.suzhouyuqi.com 站点 Nginx 配置示例
|
||||||
|
# 用于宝塔/LNMP:复制到站点配置或 include 使用
|
||||||
|
# 关键:root 指向 public,静态文件 /static/、/assets/、/pages/ 由 Nginx 直接提供
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name hjf.suzhouyuqi.com;
|
||||||
|
root /www/wwwroot/hjf.suzhouyuqi.com/public;
|
||||||
|
index index.html index.php;
|
||||||
|
|
||||||
|
# SSL 证书(宝塔通常自动配置)
|
||||||
|
# ssl_certificate ...
|
||||||
|
# ssl_certificate_key ...
|
||||||
|
|
||||||
|
# H5 静态资源:直接由 Nginx 提供,避免返回 HTML 导致 "Unexpected token '<'"
|
||||||
|
location ~ ^/(static|assets|pages)/ {
|
||||||
|
try_files $uri =404;
|
||||||
|
expires 7d;
|
||||||
|
}
|
||||||
|
|
||||||
|
# PHP 请求(按现有 Swoole/php-fpm 配置)
|
||||||
|
location ~ \.php$ {
|
||||||
|
proxy_pass http://127.0.0.1:20199;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 其余请求:先找静态文件,再走入口
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.php?$query_string;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -322,7 +322,7 @@ php think swoole
|
|||||||
|
|
||||||
5. 后台登录:
|
5. 后台登录:
|
||||||
http://域名/admin
|
http://域名/admin
|
||||||
默认账号:admin 密码:A@123456
|
默认账号:admin 密码:A@123456 或 A123456
|
||||||
|
|
||||||
|
|
||||||
## 启动命令
|
## 启动命令
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ class InstallMiddleware implements MiddlewareInterface
|
|||||||
|
|
||||||
public function handle(Request $request, \Closure $next)
|
public function handle(Request $request, \Closure $next)
|
||||||
{
|
{
|
||||||
|
// CORS 预检请求不重定向,交给后续 AllowOriginMiddleware 返回 200 + CORS 头
|
||||||
|
if (strtoupper($request->method()) === 'OPTIONS') {
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
//检测是否已安装CRMEB系统
|
//检测是否已安装CRMEB系统
|
||||||
if (!is_dir(root_path() . "public/install/") || !is_file(root_path() . "public/install/install.lock")) {
|
if (!is_dir(root_path() . "public/install/") || !is_file(root_path() . "public/install/install.lock")) {
|
||||||
return redirect('/install/index');
|
return redirect('/install/index');
|
||||||
|
|||||||
@@ -35,8 +35,10 @@ return [
|
|||||||
'text' => ''
|
'text' => ''
|
||||||
],
|
],
|
||||||
'cache' => [
|
'cache' => [
|
||||||
//若您使用了框架,并且想使用类似于redis这样的缓存驱动,则应换成框架的中的缓存驱动
|
// file 存储:生产环境 Redis 密码错误时避免 ajcaptcha 报 NOAUTH;业务主缓存仍用 config/cache.php
|
||||||
'constructor' => app()->make(\think\Cache::class),
|
'constructor' => static function ($options) {
|
||||||
|
return app()->make(\think\Cache::class)->store('file');
|
||||||
|
},
|
||||||
'method' => [
|
'method' => [
|
||||||
//遵守PSR-16规范不需要设置此项(tp6, laravel,hyperf)。如tp5就不支持(tp5缓存方法是rm,所以要配置为"delete" => "rm")
|
//遵守PSR-16规范不需要设置此项(tp6, laravel,hyperf)。如tp5就不支持(tp5缓存方法是rm,所以要配置为"delete" => "rm")
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ return [
|
|||||||
'type' => env('DATABASE_TYPE', 'mysql'),
|
'type' => env('DATABASE_TYPE', 'mysql'),
|
||||||
// 服务器地址
|
// 服务器地址
|
||||||
'hostname' => env('DATABASE_HOSTNAME', '127.0.0.1'),
|
'hostname' => env('DATABASE_HOSTNAME', '127.0.0.1'),
|
||||||
// 数据库名
|
// 数据库名(直接写死,避免 .env 路径问题)
|
||||||
'database' => env('DATABASE_DATABASE', ''),
|
'database' => 'fsgx-shop',
|
||||||
// 用户名
|
// 用户名
|
||||||
'username' => env('DATABASE_USERNAME', 'root'),
|
'username' => env('DATABASE_USERNAME', 'root'),
|
||||||
// 密码
|
// 密码
|
||||||
|
|||||||
@@ -4,4 +4,6 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
php -d memory_limit=300M think swoole
|
# 使用 PHP 8.0(Swoole Loader 仅支持 8.0)
|
||||||
|
PHP_BIN="${PHP_BIN:-/usr/local/opt/php@8.0/bin/php}"
|
||||||
|
"$PHP_BIN" -d memory_limit=300M think swoole
|
||||||
|
|||||||
6
pro_v3.5.1/help/swoole-loader-php80.ini
Normal file
6
pro_v3.5.1/help/swoole-loader-php80.ini
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
; 供 PHP 8.0 加载 Swoole Loader(在 conf.d 中软链或复制此文件,或 php.ini 中 include 此路径)
|
||||||
|
; 使用方式(任选其一):
|
||||||
|
; 1. 复制到 PHP 8.0 conf.d:cp help/swoole-loader-php80.ini /usr/local/etc/php/8.0/conf.d/99-swoole-loader.ini
|
||||||
|
; 并确保 extension= 指向的 .so 路径存在(如下方为项目内绝对路径,需按本机修改)。
|
||||||
|
; 2. 或将 .so 复制到 PHP 8.0 的 extension_dir 后,改为:extension = swoole_loader_80_nts.so
|
||||||
|
extension = /Users/apple/scott2026/huangjingfen/pro_v3.5.1/help/swoole_loader_mac/swoole_loader_80_nts.so
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
# 站点1:默认 80 端口
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name 127.0.0.1;
|
server_name 127.0.0.1;
|
||||||
@@ -31,3 +32,38 @@ server {
|
|||||||
expires 12h;
|
expires 12h;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 站点2:81 端口(远程 MySQL: fsgx-shop)
|
||||||
|
server {
|
||||||
|
listen 81;
|
||||||
|
server_name 127.0.0.1;
|
||||||
|
|
||||||
|
root /Users/apple/scott2026/huangjingfen/pro_v3.5.1/public;
|
||||||
|
index index.html index.php;
|
||||||
|
|
||||||
|
location ~* \.(php|jsp|cgi|asp|aspx)$ {
|
||||||
|
proxy_pass http://127.0.0.1:20199;
|
||||||
|
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 REMOTE-HOST $remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
if (!-e $request_filename) {
|
||||||
|
proxy_pass http://127.0.0.1:20199;
|
||||||
|
}
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_read_timeout 360s;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
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 REMOTE-HOST $remote_addr;
|
||||||
|
add_header X-Cache $upstream_cache_status;
|
||||||
|
add_header Cache-Control no-cache;
|
||||||
|
expires 12h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ define('DS', DIRECTORY_SEPARATOR);
|
|||||||
|
|
||||||
require __DIR__ . '/../vendor/autoload.php';
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
// 执行HTTP应用并响应
|
// 显式指定应用根目录,确保 .env 正确加载(避免 getDefaultRootPath 返回上级目录)
|
||||||
$http = (new App())->http;
|
$rootPath = dirname(__DIR__) . DIRECTORY_SEPARATOR;
|
||||||
|
$http = (new App($rootPath))->http;
|
||||||
|
|
||||||
$response = $http->run();
|
$response = $http->run();
|
||||||
|
|
||||||
|
|||||||
@@ -15,5 +15,6 @@ namespace think;
|
|||||||
// 加载基础文件
|
// 加载基础文件
|
||||||
require __DIR__ . '/vendor/autoload.php';
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
// 应用初始化
|
// 显式指定应用根目录,确保 .env 正确加载(避免 getDefaultRootPath 返回上级目录)
|
||||||
(new App())->console->run();
|
$rootPath = __DIR__ . DIRECTORY_SEPARATOR;
|
||||||
|
(new App($rootPath))->console->run();
|
||||||
@@ -5,6 +5,6 @@ VUE_APP_ENV='production'
|
|||||||
# 页面 title
|
# 页面 title
|
||||||
VUE_APP_TITLE=CRMEB
|
VUE_APP_TITLE=CRMEB
|
||||||
# socket 系统连接地址 (ws)或(wss)://www.crmeb.com(换成你的域名)/ws 非独立部署默认为空
|
# socket 系统连接地址 (ws)或(wss)://www.crmeb.com(换成你的域名)/ws 非独立部署默认为空
|
||||||
VUE_APP_WS_ADMIN_URL='ws://hjf.suzhouyuqi.com/ws'
|
VUE_APP_WS_ADMIN_URL='ws://fsgx.uj345.com/ws'
|
||||||
# 接口请求地址 (http)或 (https)://www.crmeb.com(换成你的域名)/adminapi 非独立部署默认为空
|
# 接口请求地址 (http)或 (https)://www.crmeb.com(换成你的域名)/adminapi 非独立部署默认为空
|
||||||
VUE_APP_API_URL='http://hjf.suzhouyuqi.com/adminapi'
|
VUE_APP_API_URL='http://fsgx.uj345.com/adminapi'
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "node src/libs/start.js && vue-cli-service serve --open --mode=dev",
|
"serve": "node src/libs/start.js && vue-cli-service serve --open --mode=dev",
|
||||||
"dev": "node src/libs/start.js && vue-cli-service serve --open --mode=dev",
|
"dev": "node src/libs/start.js && vue-cli-service serve --open --mode=dev",
|
||||||
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build --mode=production"
|
"build": "vue-cli-service build --mode=production"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/polyfill": "^7.12.1",
|
"@babel/polyfill": "^7.12.1",
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ const router = new VueRouter({
|
|||||||
routes: [...routes],
|
routes: [...routes],
|
||||||
mode: Setting.routerMode,
|
mode: Setting.routerMode,
|
||||||
});
|
});
|
||||||
router.addRoutes(supplierRoutes);
|
supplierRoutes.forEach((route) => router.addRoute(route));
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
console.log(router, "11");
|
console.log(router, "11");
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@@ -140,6 +140,8 @@ function handlePublicRoute(to, next) {
|
|||||||
if (hasMenus || isLoginPage) {
|
if (hasMenus || isLoginPage) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
// 无菜单且非登录页时,重定向到登录页(修复空白页:此前未调用 next() 导致导航挂起)
|
||||||
|
next({ path: `${Setting.roterPre}/login`, query: { redirect: to.fullPath } });
|
||||||
}
|
}
|
||||||
router.afterEach((to) => {
|
router.afterEach((to) => {
|
||||||
// if (Setting.showProgressBar) iView.LoadingBar.finish();
|
// if (Setting.showProgressBar) iView.LoadingBar.finish();
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ module.exports = {
|
|||||||
productionSourceMap: false, //关闭生产环境下的SourceMap映射文件
|
productionSourceMap: false, //关闭生产环境下的SourceMap映射文件
|
||||||
devServer: {
|
devServer: {
|
||||||
publicPath: Setting.publicPath,
|
publicPath: Setting.publicPath,
|
||||||
port: 8080,
|
port: 8085,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/adminapi': { target: 'http://127.0.0.1:20199', changeOrigin: true },
|
'/adminapi': { target: process.env.VUE_APP_API_URL ? new URL(process.env.VUE_APP_API_URL).origin : 'http://127.0.0.1:20199', changeOrigin: true },
|
||||||
'/api': { target: 'http://127.0.0.1:20199', changeOrigin: true },
|
'/api': { target: process.env.VUE_APP_API_URL ? new URL(process.env.VUE_APP_API_URL).origin : 'http://127.0.0.1:20199', changeOrigin: true },
|
||||||
'/kefuapi': { target: 'http://127.0.0.1:20199', changeOrigin: true },
|
'/kefuapi': { target: process.env.VUE_APP_API_URL ? new URL(process.env.VUE_APP_API_URL).origin : 'http://127.0.0.1:20199', changeOrigin: true },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name" : "crmeb",
|
"name" : "黄精粉",
|
||||||
"appid" : "__UNI__70A74E1",
|
"appid" : "__UNI__6691FE3",
|
||||||
"description" : "crmeb商城",
|
"description" : "黄精粉商城",
|
||||||
"versionName" : "3.5.1",
|
"versionName" : "3.5.1",
|
||||||
"versionCode" : 351,
|
"versionCode" : 351,
|
||||||
"transformPx" : false,
|
"transformPx" : false,
|
||||||
@@ -125,13 +125,13 @@
|
|||||||
},
|
},
|
||||||
"icons" : {
|
"icons" : {
|
||||||
"android" : {
|
"android" : {
|
||||||
"hdpi" : "unpackage/res/icons/72x72.png",
|
"hdpi" : "",
|
||||||
"xhdpi" : "unpackage/res/icons/96x96.png",
|
"xhdpi" : "",
|
||||||
"xxhdpi" : "unpackage/res/icons/144x144.png",
|
"xxhdpi" : "",
|
||||||
"xxxhdpi" : "unpackage/res/icons/192x192.png"
|
"xxxhdpi" : ""
|
||||||
},
|
},
|
||||||
"ios" : {
|
"ios" : {
|
||||||
"appstore" : "unpackage/res/icons/1024x1024.png",
|
"appstore" : "",
|
||||||
"ipad" : {
|
"ipad" : {
|
||||||
"app" : "unpackage/res/icons/76x76.png",
|
"app" : "unpackage/res/icons/76x76.png",
|
||||||
"app@2x" : "unpackage/res/icons/152x152.png",
|
"app@2x" : "unpackage/res/icons/152x152.png",
|
||||||
@@ -144,14 +144,14 @@
|
|||||||
"spotlight@2x" : "unpackage/res/icons/80x80.png"
|
"spotlight@2x" : "unpackage/res/icons/80x80.png"
|
||||||
},
|
},
|
||||||
"iphone" : {
|
"iphone" : {
|
||||||
"app@2x" : "unpackage/res/icons/120x120.png",
|
"app@2x" : "",
|
||||||
"app@3x" : "unpackage/res/icons/180x180.png",
|
"app@3x" : "",
|
||||||
"notification@2x" : "unpackage/res/icons/40x40.png",
|
"notification@2x" : "",
|
||||||
"notification@3x" : "unpackage/res/icons/60x60.png",
|
"notification@3x" : "unpackage/res/icons/60x60.png",
|
||||||
"settings@2x" : "unpackage/res/icons/58x58.png",
|
"settings@2x" : "",
|
||||||
"settings@3x" : "unpackage/res/icons/87x87.png",
|
"settings@3x" : "",
|
||||||
"spotlight@2x" : "unpackage/res/icons/80x80.png",
|
"spotlight@2x" : "",
|
||||||
"spotlight@3x" : "unpackage/res/icons/120x120.png"
|
"spotlight@3x" : ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,11 +214,11 @@
|
|||||||
},
|
},
|
||||||
"h5" : {
|
"h5" : {
|
||||||
"devServer" : {
|
"devServer" : {
|
||||||
"https" : false
|
"https" : true
|
||||||
},
|
},
|
||||||
"router" : {
|
"router" : {
|
||||||
"mode" : "history",
|
"mode" : "history",
|
||||||
"base" : "/h5/"
|
"base" : "/"
|
||||||
},
|
},
|
||||||
"domain" : "",
|
"domain" : "",
|
||||||
"sdkConfigs" : {
|
"sdkConfigs" : {
|
||||||
@@ -251,7 +251,8 @@
|
|||||||
"statusbar" : {
|
"statusbar" : {
|
||||||
"immersed" : true
|
"immersed" : true
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"fallbackLocale" : "zh-Hans"
|
||||||
}
|
}
|
||||||
/* "lazyCodeLoading" : "requiredComponents", */// "optimization" : {
|
/* "lazyCodeLoading" : "requiredComponents", */// "optimization" : {
|
||||||
// "subPackages" : true
|
// "subPackages" : true
|
||||||
|
|||||||
BIN
pro_v3.5.1/view/uniapp/static/images/support.png
Normal file
BIN
pro_v3.5.1/view/uniapp/static/images/support.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Reference in New Issue
Block a user