# RuoYi-Thinkphp **Repository Path**: wangweili/RuoYi-Thinkphp ## Basic Information - **Project Name**: RuoYi-Thinkphp - **Description**: 基于 ThinkPHP 8 的若依后台,配套 Vue3 前端与微信小程序。 - **Primary Language**: PHP - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2026-11-13 - **Last Updated**: 2026-11-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # RuoYi-ThinkPHP 若依管理系统的 ThinkPHP 8 版本,包含 Vue3 管理后台和原生微信小程序。后端使用 MySQL、JWT 和 RBAC;小程序用户存放在独立 `mp_user` 表,与后台管理员 `sys_user` 分开鉴权。 本文按“本地启动 → 配置说明 → 服务器部署 → 小程序发布”说明操作步骤。项目命令默认从仓库根目录执行;代码块进入子目录时会明确写出 `cd`。示例域名、路径、密码和证书必须换成自己的值。 ## 目录与环境 ```text RuoYi-Thinkphp/ ├── backend/ # ThinkPHP API │ ├── .example.env # 后端环境配置模板 │ ├── app/ # 控制器、服务、模型和中间件(service 按 auth/system/monitor/mp 分模块) │ ├── docs/ # 后端架构说明(architecture.md) │ ├── public/ # 后端 Nginx 站点根目录 │ │ └── storage/ # 上传文件,需持久保存 │ ├── runtime/ # 缓存、日志、运行时文件 │ └── sql/ # 全量初始化 SQL 和增量补丁 ├── web/ # Vue3 管理后台,构建产物 web/dist ├── miniprogram/ # 微信开发者工具导入此目录 └── docker-compose.yml # 只包含 MySQL、Redis ``` 环境要求: - PHP >= 8.2,部署示例使用 PHP 8.3;CLI 与 PHP-FPM 都要满足扩展要求。 - PHP 扩展:`pdo_mysql`、`mbstring`、`openssl`、`gd`、`fileinfo`、`curl`、`zip`、`dom`、`xml`、`xmlreader`、`xmlwriter`;完整要求以 Composer 检查结果为准。使用回归测试还需 `pdo_sqlite`。 - Composer 2;MySQL 8;缓存支持 Redis 或文件。Redis 可使用 PHP Redis 扩展或项目内的 Predis。 - Node.js 22 LTS 与 npm 可用于当前前端构建;Node 只负责构建,不负责生产环境运行后端。 - 本地可选 Docker Compose;生产示例使用 Linux、Nginx、PHP-FPM 和有效 HTTPS 证书。 - 微信开发者工具用于编译、预览和发布小程序。 ## 一、本地启动 ### 1. 准备数据库和缓存 任选下面一种方式。 **方式 A:已有本机 MySQL。** 从仓库根目录执行: ```bash mysql -h 127.0.0.1 -P 3306 -u root -p -e 'CREATE DATABASE IF NOT EXISTS `ry-thinkphp` DEFAULT CHARACTER SET utf8mb4;' mysql -h 127.0.0.1 -P 3306 -u root -p ry-thinkphp < backend/sql/ry_20260417.sql ``` 全量 SQL 只用于新库,包含系统表、小程序表和菜单。已有业务数据库不要重复导入全量 SQL;按下文“已有库升级”操作。 **方式 B:用项目 Docker Compose 启动 MySQL、Redis。** 在仓库根目录复制环境模板并填入自己的密码: ```bash cp .env.example .env ``` ```dotenv MYSQL_ROOT_PASSWORD=替换为数据库密码 MYSQL_DATABASE=ry-thinkphp REDIS_PASSWORD=替换为Redis密码 ``` 然后执行: ```bash docker compose up -d mysql redis docker compose ps docker compose logs --tail=50 mysql ``` 宿主机连接地址分别为 `127.0.0.1:3307`、`127.0.0.1:6380`。**只有 MySQL 数据卷首次初始化时,Docker 才自动导入全量 SQL**;修改密码环境变量也不会自动修改已有数据卷中的 MySQL 账号密码。 根目录 `.env` 是 Docker Compose 配置,`backend/.env` 是 PHP 应用配置,二者不会自动同步。两份文件含密码,都不要提交到版本库;`.gitignore` 已同时忽略根目录 `.env` 与 `backend/.env`。当前 Compose 未包含 PHP、Nginx 或后台前端,仍需完成下面步骤。 ### 2. 配置并启动后端 ```bash cd backend # 已有 .env 时保留原文件,只编辑需要修改的配置 [ -f .env ] || cp .example.env .env composer install composer check-platform-reqs ``` 编辑 `backend/.env`。使用上面 Docker 方式时,至少修改: ```dotenv APP_DEBUG = true APP_ENV = local DB_TYPE = mysql DB_HOST = 127.0.0.1 DB_PORT = 3307 DB_NAME = ry-thinkphp DB_USER = root DB_PASS = 与根目录MYSQL_ROOT_PASSWORD一致 DB_PREFIX = CACHE_DRIVER = redis REDIS_HOST = 127.0.0.1 REDIS_PORT = 6380 REDIS_PASSWORD = 与根目录REDIS_PASSWORD一致 REDIS_SELECT = 3 ``` 使用本机 MySQL/Redis 时,端口通常改为 `3306`/`6379`,密码填实际值。如果本地不启动 Redis,设置 `CACHE_DRIVER=file`;队列保持 `QUEUE_CONNECTION=sync`。 `JWT_SECRET` 必须替换成自己的随机字符串。可执行下面命令生成,再将输出填入 `.env`: ```bash php -r 'echo bin2hex(random_bytes(32)), PHP_EOL;' ``` 启动后端,保持该终端运行: ```bash php think run -p 8080 ``` 另一个终端可验证公开接口: ```bash curl http://127.0.0.1:8080/captchaImage ``` 预期返回包含 `code`、`captchaEnabled` 的 JSON。验证码关闭时不返回图片,也属于正常结果。`php think run` 用于本地开发,生产部署使用 PHP-FPM。 ### 3. 启动管理后台 在新的终端中,从仓库根目录执行: ```bash cd web npm ci npm run dev ``` 浏览器访问 `http://localhost:5173`。后台开发配置使用 `/dev-api`,Vite 将该前缀去掉后转发到 `http://127.0.0.1:8080`。 后端端口改变时,同步修改 `web/vite.config.js` 中的 `baseUrl`。例如使用 `php think run -p 8081` 时,改成 `http://127.0.0.1:8081`。 新库默认管理员为 `admin` / `admin123`。先在本地登录并修改管理员密码,再切换生产配置。本地可用 `CAPTCHA_ENABLED=false` 显式关闭验证码;未显式关闭时,优先读取数据库参数 `sys.account.captchaEnabled`,参数不存在时使用默认配置。 API 文档需要登录和 `tool:swagger:list` 权限,可从后台“系统工具 → 系统接口”打开;直接匿名访问 `/swagger-ui` 会被鉴权拦截。 ### 4. 启动小程序 完整步骤见 [小程序配置与发布说明](miniprogram/README.md)。最短启动流程: ```bash cd miniprogram npm ci npm run build:npm npm run typecheck ``` 微信开发者工具导入仓库里的 **`miniprogram` 目录**,不是它下面的同名目录。开发接口地址在 `miniprogram/miniprogram/utils/config.ts`,默认 `http://127.0.0.1:8080`。 真实登录配置后端的 `WECHAT_MP_APPID`、`WECHAT_MP_SECRET`,并使 `miniprogram/project.config.json` 的 AppID 与后端一致。仅联调接口时可在后端显式设置 `APP_ENV=local`、`WECHAT_MP_MOCK=true`。开发者工具本地 HTTP 联调需要关闭合法域名校验;真机不能用手机自身的 `127.0.0.1` 访问电脑服务。 ## 二、环境配置说明 所有后端配置写在 `backend/.env`。模板是 `backend/.example.env`;修改后重启开发服务器、PHP-FPM 和相关常驻任务进程。前端环境变量在构建时生效,修改后需重新构建。 ### 数据库和缓存 - `DB_TYPE=mysql`、`DB_HOST`、`DB_PORT`、`DB_NAME`、`DB_USER`、`DB_PASS`:实际数据库连接。使用默认初始化 SQL 时 `DB_PREFIX` 保持空。 - `CACHE_DRIVER=redis|file`:缓存驱动。改驱动或清空缓存会使登录会话失效。 - `REDIS_HOST`、`REDIS_PORT`、`REDIS_PASSWORD`、`REDIS_SELECT`:Redis 连接;缓存和 Redis 队列共用这些配置。 - `CACHE_PREFIX`:缓存键前缀。多个部署共用 Redis 时使用不同数据库编号或独立 Redis,避免会话及微信缓存混用。 - `QUEUE_CONNECTION=sync`:默认同步执行。改为 `redis` 后,另外运行 `php think queue:listen` 并管理该常驻进程。 ### 后台认证、文件与跨域 - `APP_ENV=local` 用于开发,线上改成 `production`;`APP_DEBUG` 线上设为 `false`。 - `JWT_SECRET`:独立随机签名密钥,保持各后端实例一致;更换密钥会使已签发令牌失效。 - `JWT_EXPIRE=30`:后台 Access Token 有效期,单位分钟。 - `JWT_REFRESH_EXPIRE=10080`:后台 Refresh Token 有效期,单位分钟,默认 7 天。 - `USER_PASSWORD_DEFAULT=admin123`:用于初始密码识别,非 local/testing 环境禁止使用此默认密码登录。不要通过改这个配置绕过初始化密码限制,应先修改管理员实际密码。 - `CORS_ORIGINS`:允许的浏览器来源,逗号分隔,如 `https://admin.example.com`。同域部署按下面示例即可;独立前端域名要填写实际来源。 - `STORAGE_DRIVER=local`:当前已实现本地存储。`minio/oss/cos` 是扩展预留,配置名称本身不会接入云存储。 - 上传文件位于 `backend/public/storage`,运行时日志和缓存位于 `backend/runtime`;这两个目录需允许 PHP-FPM 用户写入。上传文件不需要另建 storage 软链接。 ### 微信小程序 - `WECHAT_MP_APPID`:微信小程序 AppID,与开发者工具项目 AppID 一致。 - `WECHAT_MP_SECRET`:微信小程序 AppSecret,只放后端。 - `WECHAT_MP_MOCK=false`:真实微信登录。模拟模式必须显式开启,且仅允许 local/testing 环境。 - `WECHAT_MP_TOKEN_EXPIRE=1440`:小程序登录令牌有效期,单位分钟,默认 24 小时,与后台 Access Token 配置分开。 - `WECHAT_MP_LOGIN_LIMIT=30`:当前小程序登录限流中间件的每分钟单 IP 请求上限。 ## 三、生产服务器部署 下面示例将后台和小程序 API 部署到同一个 HTTPS 域名: - 管理后台:`https://admin.example.com/`。 - 后台接口:`https://admin.example.com/prod-api/`,Nginx 去掉 `/prod-api` 后转给后端。 - 小程序接口:`https://admin.example.com/mp/`,保留 `/mp` 路径。 - 上传文件:`https://admin.example.com/storage/`。 仓库路径示例为 `/srv/ruoyi/RuoYi-Thinkphp`。Nginx 内部后端监听 `127.0.0.1:8080`,PHP-FPM 示例监听 `127.0.0.1:9000`。按实际服务配置修改;部署前停止占用 8080 的开发服务器。 ### 1. 安装依赖、初始化数据库 先将代码上传到服务器并安装 PHP-FPM、Nginx、MySQL、Redis。PHP-FPM 扩展和 CLI 扩展都要齐全。 ```bash cd /srv/ruoyi/RuoYi-Thinkphp/backend [ -f .env ] || cp .example.env .env composer install --no-dev --prefer-dist --optimize-autoloader composer check-platform-reqs --no-dev ``` 新库按第一节导入 `sql/ry_20260417.sql`;已有库按“已有库升级”处理。部署配置中的数据库账号应具有应用表的正常读写权限,初始化/升级时另需建表、修改表和写菜单权限。 填写 `backend/.env` 的生产值,例如: ```dotenv APP_DEBUG = false APP_ENV = production DB_TYPE = mysql DB_HOST = 127.0.0.1 DB_PORT = 3306 DB_NAME = ry-thinkphp DB_USER = ruoyi DB_PASS = 替换为应用数据库密码 DB_PREFIX = CACHE_DRIVER = redis REDIS_HOST = 127.0.0.1 REDIS_PORT = 6379 REDIS_PASSWORD = 替换为Redis密码 REDIS_SELECT = 3 JWT_SECRET = 替换为生成的随机密钥 USER_PASSWORD_DEFAULT = admin123 CORS_ORIGINS = https://admin.example.com STORAGE_DRIVER = local QUEUE_CONNECTION = sync WECHAT_MP_APPID = 替换为小程序AppID WECHAT_MP_SECRET = 替换为小程序AppSecret WECHAT_MP_MOCK = false WECHAT_MP_TOKEN_EXPIRE = 1440 ``` 新库管理员需先在隔离的本地环境修改初始密码,再使用生产环境配置上线,否则 `admin123` 登录会被后端拒绝。 准备可写目录。以下 `www-data` 是示例,宝塔等环境可能使用 `www`,应以 PHP-FPM 的运行用户为准: ```bash cd /srv/ruoyi/RuoYi-Thinkphp mkdir -p backend/runtime backend/public/storage sudo chown -R www-data:www-data backend/runtime backend/public/storage ``` PHP 设置 `upload_max_filesize=10M`、`post_max_size=12M`,并重启 PHP-FPM。应用自身还有文件大小限制:头像 2MB,通用上传 5MB,这些限制不会因 PHP 配置提高而自动改变。 ### 2. 构建后台 ```bash cd /srv/ruoyi/RuoYi-Thinkphp/web npm ci npm run build ``` 默认 `web/.env.production` 使用 `VITE_APP_BASE_API='/prod-api'`,与下面 Nginx 示例一致。构建产物是 `web/dist`;只部署源码或只启动 Vite 开发服务器都不会得到生产静态站点。 ### 3. 配置 Nginx 将以下配置放入服务器的 Nginx 站点配置文件。替换域名、仓库路径、证书文件和 PHP-FPM 地址。证书需已申请并存在;本示例不会自动签发证书。 ```nginx # 只监听本机的后端入口 server { listen 127.0.0.1:8080; server_name localhost; root /srv/ruoyi/RuoYi-Thinkphp/backend/public; index index.php; client_max_body_size 12m; location / { try_files $uri $uri/ /index.php?s=$uri&$query_string; } # 上传目录只提供静态文件,不进入 PHP 执行器 location ^~ /storage/ { try_files $uri =404; add_header X-Content-Type-Options nosniff always; } # 仅允许执行 ThinkPHP 入口文件 location = /index.php { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root/index.php; fastcgi_param HTTP_AUTHORIZATION $http_authorization; fastcgi_pass 127.0.0.1:9000; } location ~ \.php$ { return 404; } location ~ /\. { deny all; } } server { listen 80; server_name admin.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name admin.example.com; ssl_certificate /etc/nginx/certs/admin.example.com/fullchain.pem; ssl_certificate_key /etc/nginx/certs/admin.example.com/privkey.pem; root /srv/ruoyi/RuoYi-Thinkphp/web/dist; index index.html; client_max_body_size 12m; # 末尾 / 用于去掉 /prod-api/ 前缀 location /prod-api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; } # 小程序保持 /mp 路径;proxy_pass 不带末尾 / location /mp/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; } location /storage/ { proxy_pass http://127.0.0.1:8080; } # 后台系统接口页面使用的文档和静态资源 location /swagger-ui { proxy_pass http://127.0.0.1:8080; } location /v3/api-docs { proxy_pass http://127.0.0.1:8080; } location /vendor/swagger-ui/ { proxy_pass http://127.0.0.1:8080; } # Vue Router 页面刷新时回退到 index.html location / { try_files $uri $uri/ /index.html; } location ~ /\. { deny all; } } ``` `/prod-api/` 的 `proxy_pass` 带 URI `/`,替换匹配的前缀;`/mp/` 的 `proxy_pass` 不带 URI,保留原请求路径。规则依据 [Nginx proxy_pass 文档](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass);`^~ /storage/` 的匹配依据 [Nginx location 文档](https://nginx.org/en/docs/http/ngx_http_core_module.html#location)。不要把两个代理写成相同的尾斜杠形式。 后端默认信任本机代理 `127.0.0.1` / `::1` 传入的 `X-Real-IP` / `X-Forwarded-For`(见 `backend/.example.env` 的 `TRUSTED_PROXIES`)。若 PHP 不经本机 Nginx、或前置还有一层代理,请按实际代理地址修改该配置;留空表示不采信任何代理头。 如果 PHP-FPM 使用 Unix Socket,替换为实际地址,例如 `fastcgi_pass unix:/run/php/php8.3-fpm.sock;`。 检查配置并重新加载: ```bash sudo nginx -t sudo systemctl reload nginx sudo systemctl restart php8.3-fpm ``` 以上服务名适用于对应的 Linux 安装方式;面板或其他系统通过其服务管理方式重启。服务器只需对外开放站点的 80/443,内部后端 8080、数据库和 Redis 不需要暴露到公网。 ### 4. 定时任务和队列 如果使用后台“定时任务”模块,需持续运行调度器,进程运行用户应具有项目读权限和运行目录写权限: ```bash cd /srv/ruoyi/RuoYi-Thinkphp/backend php think job:schedule ``` 该进程每秒扫描任务,适合由 Supervisor/systemd 管理。`php think job:schedule --once` 只扫描一轮;每分钟调用一次不能覆盖秒级调度。 使用 Redis 队列时,设置 `QUEUE_CONNECTION=redis`,再用进程管理器保持 `php think queue:listen` 运行。未使用队列时保留 `sync`。 导出和代码生成临时文件可由 crontab 清理,以下使用示例 PHP 路径、以应用运行用户执行: ```cron 0 3 * * * cd /srv/ruoyi/RuoYi-Thinkphp/backend && /usr/bin/php think runtime:clean --hours=24 >> /srv/ruoyi/RuoYi-Thinkphp/backend/runtime/cleanup.log 2>&1 ``` ## 四、小程序发布与已有库升级 ### 小程序生产配置 1. 完成 HTTPS 站点部署,后端配置真实 AppID/AppSecret,`WECHAT_MP_MOCK=false`。 2. 将小程序 `baseUrl` 改为 `https://admin.example.com`,**不加 `/prod-api` 或 `/mp`,不带末尾斜杠**,请求工具会自行拼接 `/mp/login` 等路径。 3. 在微信公众平台配置对应 HTTPS 域名为 `request` 和 `uploadFile` 合法域名;头像走上传接口。域名/账号能力等以公众平台实际校验结果为准。 4. 将 `project.config.json` 中的 `touristappid` 改成自己的小程序 AppID,执行 `npm ci`、`npm run build:npm`,在开发者工具编译并真机预览。 5. 测试登录、昵称保存、头像上传与显示、手机号授权、退出;在后台停用用户后确认小程序无法继续访问。 6. 在开发者工具上传代码,再在微信公众平台按版本管理流程提交审核、发布。项目没有自动发布命令。 详细配置、接口与排查见 [小程序 README](miniprogram/README.md)。 ### 已有数据库升级 先备份数据库和 `backend/public/storage`。全量 SQL 包含建表和初始化数据,仅用于新库,不作为已有库的升级脚本。 新增小程序模块时执行: ```bash cd backend php think mp:install ``` 该命令创建小程序表和菜单,旧 `mp_user` 缺少 `token_version` 时也会补列。要求 MySQL、空 `DB_PREFIX` 和相应数据库权限;可重复执行,不迁移 Laravel 用户数据。后台重新登录后加载新菜单。 更早的数据库如缺少 `sys_user.user_name_active`、`uk_user_name_active` 或任务日志的 `job_id` 索引,应核对后应用 `backend/sql/patch_20261004_integrity.sql`。该补丁不是幂等脚本,已存在相应字段/索引时不要重复执行;最新全量 SQL 已包含这些结构。 后续更新代码时保留 `.env`、数据库和上传目录,重新安装锁定依赖、构建后台,并重启 PHP-FPM、队列、调度器。修改小程序接口地址需重新编译上传小程序,不会通过后端重启更新客户端配置。 ## 五、验证与常见问题 可重复执行的代码验证: ```bash # 仓库根目录 cd backend php tests/mp_regression.php php tests/auth_regression.php php tests/user_gen_regression.php php tests/login_guard_regression.php cd ../miniprogram npm ci npm run typecheck npm run build:npm cd ../web npm ci npm run build ``` 部署后检查:后台能登录和刷新页面;`/prod-api/captchaImage` 返回 JSON;小程序真实登录成功;头像 URL 可通过 HTTPS 打开;后台具有小程序用户管理菜单。回归测试使用 SQLite 内存库和独立临时缓存,不代替真实微信和服务器联调。`auth_regression.php` 覆盖密码重置、会话刷新和在线列表并发;安装 `pcntl` 时验证真实进程竞争,系统存在 `redis-server` 时启动不持久化的独立临时实例验证 Redis 原子锁。 - **数据库连接失败**:核对 `DB_PORT`,本机通常 3306,项目 Docker 映射 3307;Docker 根目录密码必须与 `backend/.env` 一致。 - **Redis 认证失败**:核对实际密码。当前 Compose 默认要求密码,后端示例里的空密码不能直接连接它。 - **默认管理员登录被拒绝**:生产环境拒绝默认密码;先在隔离开发环境改密码,再切回 production。 - **后台请求 404 或返回 HTML**:确认 `/prod-api/` 去前缀,后端根目录为 `backend/public`,接口请求没有落入 Vue 的 `index.html`。 - **Swagger 返回 401/403**:需后台登录和 `tool:swagger:list` 权限;也要保留文档与资源代理路径。 - **上传 413**:核对 Nginx `client_max_body_size`、PHP 上传设置和应用限制;头像上限仍为 2MB。 - **头像无法显示**:检查 `backend/public/storage` 写权限、`/storage/` 静态访问,以及小程序 HTTPS 地址和合法域名。 - **小程序提示组件不存在**:在外层 `miniprogram` 目录执行 `npm ci && npm run build:npm` 后重新编译。 - **微信登录凭证无效**:核对小程序与后端 AppID 一致、AppSecret 正确、模拟开关关闭;重新获取 code 再登录。 - **手机号授权失败**:确认该小程序账号具有微信手机号能力,授权返回的是 `getPhoneNumber` 的 code,不是 `wx.login` 的 code。 ## 当前功能边界 小程序已包含微信登录、昵称修改、头像上传、微信手机号绑定、个人中心和退出;管理后台提供小程序用户查询、编辑、停用和删除。首页演示统计、任务/看板/设置入口、部分个人中心入口和协议内容仍是占位内容,发布前按业务补全。 本地文件存储已实现;MinIO/OSS/COS、WebSocket、Swoole 属于扩展能力,需要另行实现和部署,不能仅修改环境变量就启用。 ## 许可证与致谢 - 本仓库代码默认采用 [MIT](LICENSE)。 - 基于 [RuoYi / RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)(MIT)与 [ThinkPHP](https://www.thinkphp.cn/)(Apache-2.0)构建;第三方版权说明见 [NOTICE](NOTICE)。 - 安全问题反馈见 [SECURITY.md](SECURITY.md)。 开源仓库中的小程序 `project.config.json` 使用占位 AppID `touristappid`,本地开发请改成自己的 AppID,并与后端 `WECHAT_MP_APPID` 保持一致。