签入版本

This commit is contained in:
2026-10-10 19:17:02 +08:00
parent 3423dea03f
commit 32f941b631
232 changed files with 4264 additions and 6251 deletions
@@ -109,9 +109,9 @@ php think db:migrate [选项]
# --drop-target-first → 迁移前先删除目标库中的同名表(避免表已存在报错)
php think db:migrate \
--src-type=mysql --src-host=127.0.0.1 --src-hostport=3306 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=root --src-password=root \
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=root --src-password=root \
--dst-type=pgsql --dst-host=127.0.0.1 --dst-hostport=5432 \
--dst-database=rxthinkcmf.thinkphp6.elevue --dst-username=postgres --dst-password=123456 \
--dst-database=rxthinkcmf.thinkphp6.naivevue --dst-username=postgres --dst-password=123456 \
--drop-target-first
```
@@ -125,9 +125,9 @@ php think db:migrate \
# --dst-hostport=1433 → SQL Server 默认端口
php think db:migrate \
--src-type=mysql --src-host=127.0.0.1 --src-hostport=3306 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=root --src-password=root \
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=root --src-password=root \
--dst-type=sqlsrv --dst-host=127.0.0.1 --dst-hostport=1433 \
--dst-database=rxthinkcmf.thinkphp6.elevue --dst-username=sa --dst-password=123456 \
--dst-database=rxthinkcmf.thinkphp6.naivevue --dst-username=sa --dst-password=123456 \
--drop-target-first
```
@@ -141,8 +141,8 @@ php think db:migrate \
# --dst-database → SQLite 文件路径(文件不存在时自动创建)
php think db:migrate \
--src-type=mysql --src-host=127.0.0.1 --src-hostport=3306 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=root --src-password=root \
--dst-type=sqlite --dst-database=runtime/rxthinkcmf.thinkphp6.elevue.db
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=root --src-password=root \
--dst-type=sqlite --dst-database=runtime/rxthinkcmf.thinkphp6.naivevue.db
```
### MySQL → MySQL(同库复制)
@@ -167,9 +167,9 @@ php think db:migrate \
# -----------------------------------------------------------------------------
php think db:migrate \
--src-type=pgsql --src-host=127.0.0.1 --src-hostport=5432 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=postgres --src-password=123456 \
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=postgres --src-password=123456 \
--dst-type=mysql --dst-host=127.0.0.1 --dst-hostport=3306 \
--dst-database=rxthinkcmf.thinkphp6.elevue --dst-username=root --dst-password=root \
--dst-database=rxthinkcmf.thinkphp6.naivevue --dst-username=root --dst-password=root \
--drop-target-first
```
@@ -181,9 +181,9 @@ php think db:migrate \
# -----------------------------------------------------------------------------
php think db:migrate \
--src-type=sqlsrv --src-host=127.0.0.1 --src-hostport=1433 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=sa --src-password=123456 \
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=sa --src-password=123456 \
--dst-type=mysql --dst-host=127.0.0.1 --dst-hostport=3306 \
--dst-database=rxthinkcmf.thinkphp6.elevue --dst-username=root --dst-password=root \
--dst-database=rxthinkcmf.thinkphp6.naivevue --dst-username=root --dst-password=root \
--drop-target-first
```
@@ -196,9 +196,9 @@ php think db:migrate \
# --tables=think_user,think_role,think_menu → 只迁移这 3 张表
php think db:migrate \
--src-type=mysql --src-host=127.0.0.1 --src-hostport=3306 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=root --src-password=root \
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=root --src-password=root \
--dst-type=pgsql --dst-host=127.0.0.1 --dst-hostport=5432 \
--dst-database=rxthinkcmf.thinkphp6.elevue --dst-username=postgres --dst-password=123456 \
--dst-database=rxthinkcmf.thinkphp6.naivevue --dst-username=postgres --dst-password=123456 \
--tables=think_user,think_role,think_menu \
--drop-target-first
```
@@ -210,17 +210,17 @@ php think db:migrate \
```bash
$ php think db:migrate \
--src-type=mysql --src-host=127.0.0.1 --src-hostport=3306 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=root --src-password=root \
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=root --src-password=root \
--dst-type=pgsql --dst-host=127.0.0.1 --dst-hostport=5432 \
--dst-database=rxthinkcmf.thinkphp6.elevue --dst-username=postgres --dst-password=123456 \
--dst-database=rxthinkcmf.thinkphp6.naivevue --dst-username=postgres --dst-password=123456 \
--drop-target-first
==============================================================
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.elevue → 目标: pgsql:rxthinkcmf.thinkphp6.elevue
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.naivevue → 目标: pgsql:rxthinkcmf.thinkphp6.naivevue
[迁移开始] 待迁移 25 张表
==============================================================
[·] [1/5] 建目标库...
· 目标库 "rxthinkcmf.thinkphp6.elevue" 已就绪
· 目标库 "rxthinkcmf.thinkphp6.naivevue" 已就绪
[✓] [1/5] 建目标库 完成(耗时 0ms)
[·] [2/5] 建表结构(25 张表)...
[✓] [2/5] 建表结构 完成(耗时 440ms),25 张表,118 个索引,0 个外键
@@ -266,17 +266,17 @@ $ php think db:migrate \
```bash
$ php think db:migrate \
--src-type=mysql --src-host=127.0.0.1 --src-hostport=3306 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=root --src-password=root \
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=root --src-password=root \
--dst-type=sqlsrv --dst-host=127.0.0.1 --dst-hostport=1433 \
--dst-database=rxthinkcmf.thinkphp6.elevue --dst-username=sa --dst-password=123456 \
--dst-database=rxthinkcmf.thinkphp6.naivevue --dst-username=sa --dst-password=123456 \
--drop-target-first
==============================================================
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.elevue → 目标: sqlsrv:rxthinkcmf.thinkphp6.elevue
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.naivevue → 目标: sqlsrv:rxthinkcmf.thinkphp6.naivevue
[迁移开始] 待迁移 25 张表
==============================================================
[·] [1/5] 建目标库...
· 目标库 "rxthinkcmf.thinkphp6.elevue" 已就绪
· 目标库 "rxthinkcmf.thinkphp6.naivevue" 已就绪
[✓] [1/5] 建目标库 完成(耗时 0ms)
[·] [2/5] 建表结构(25 张表)...
[✓] [2/5] 建表结构 完成(耗时 1.5s),25 张表,118 个索引,0 个外键
@@ -298,13 +298,13 @@ $ php think db:migrate \
```bash
$ php think db:migrate \
--src-type=mysql --src-host=127.0.0.1 --src-hostport=3306 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=root --src-password=root \
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=root --src-password=root \
--dst-type=oracle --dst-host=127.0.0.1 --dst-hostport=1521 \
--dst-database=rxthinkcmf --dst-username=system --dst-password=123456 \
--drop-target-first
==============================================================
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.elevue → 目标: oracle:rxthinkcmf.thinkphp6.elevue
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.naivevue → 目标: oracle:rxthinkcmf.thinkphp6.naivevue
[迁移开始] 待迁移 25 张表
==============================================================
[·] [1/5] 建目标库...
@@ -347,15 +347,15 @@ $ php think db:migrate \
```bash
$ php think db:migrate \
--src-type=mysql --src-host=127.0.0.1 --src-hostport=3306 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=root --src-password=root \
--dst-type=sqlite --dst-database=runtime/rxthinkcmf.thinkphp6.elevue.db
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=root --src-password=root \
--dst-type=sqlite --dst-database=runtime/rxthinkcmf.thinkphp6.naivevue.db
==============================================================
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.elevue → 目标: sqlite:runtime/rxthinkcmf.thinkphp6.elevue.db
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.naivevue → 目标: sqlite:runtime/rxthinkcmf.thinkphp6.naivevue.db
[迁移开始] 待迁移 25 张表
==============================================================
[·] [1/5] 建目标库...
· 目标库 "runtime/rxthinkcmf.thinkphp6.elevue.db" 已就绪
· 目标库 "runtime/rxthinkcmf.thinkphp6.naivevue.db" 已就绪
[✓] [1/5] 建目标库 完成(耗时 0ms)
[·] [2/5] 建表结构(25 张表)...
[✓] [2/5] 建表结构 完成(耗时 1s),25 张表,118 个索引,0 个外键
@@ -378,18 +378,18 @@ $ php think db:migrate \
```bash
$ php think db:migrate \
--src-type=mysql --src-host=127.0.0.1 --src-hostport=3306 \
--src-database=rxthinkcmf.thinkphp6.elevue --src-username=root --src-password=root \
--src-database=rxthinkcmf.thinkphp6.naivevue --src-username=root --src-password=root \
--dst-type=pgsql --dst-host=127.0.0.1 --dst-hostport=5432 \
--dst-database=rxthinkcmf.thinkphp6.elevue --dst-username=postgres --dst-password=123456 \
--dst-database=rxthinkcmf.thinkphp6.naivevue --dst-username=postgres --dst-password=123456 \
--tables=think_user,think_role,think_menu \
--drop-target-first
==============================================================
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.elevue → 目标: pgsql:rxthinkcmf.thinkphp6.elevue
[迁移开始] 源: mysql:rxthinkcmf.thinkphp6.naivevue → 目标: pgsql:rxthinkcmf.thinkphp6.naivevue
[迁移开始] 待迁移 3 张表
==============================================================
[·] [1/5] 建目标库...
· 目标库 "rxthinkcmf.thinkphp6.elevue" 已就绪
· 目标库 "rxthinkcmf.thinkphp6.naivevue" 已就绪
[✓] [1/5] 建目标库 完成(耗时 0ms)
[·] [2/5] 建表结构(3 张表)...
· 已删除目标表: think_user
@@ -789,7 +789,7 @@ D:\xampp8.2\php\php.exe -m | findstr sqlite
5. `--drop-target-first` 会删除目标表的全部数据(含索引、外键和注释),请谨慎使用
6. 大表迁移建议调大 `--batch-size`(如 5000)以提高效率
7. 迁移过程中如遇中断,已提交的 `--batch-size` 批次数据不会回滚,建议使用 `--drop-target-first` 重试
8. 含点号的数据库名(如 `rxthinkcmf.thinkphp6.elevue`)各驱动均已适配
8. 含点号的数据库名(如 `rxthinkcmf.thinkphp6.naivevue`)各驱动均已适配
9. 索引、外键和注释在建表阶段同步迁移,使用 `--drop-target-first` 重建时会一并重建
10. 外键约束在所有表创建后统一添加,避免引用顺序问题
11. 命令退出码:成功返回 0,失败或行数校验未通过返回 1(可用于 CI/CD 判断)
@@ -850,7 +850,7 @@ A: Oracle 没有原生自增语法。迁移工具会自动为自增列创建序
### Q: 含点号的数据库名支持吗?
A: 支持。如 `rxthinkcmf.thinkphp6.elevue` 这类含点号的库名,各驱动均已适配。
A: 支持。如 `rxthinkcmf.thinkphp6.naivevue` 这类含点号的库名,各驱动均已适配。
### Q: SQLite 作为目标有什么限制?
@@ -378,28 +378,37 @@ public function export(array $params = []): string
```vue
<template>
<el-upload
<n-upload
:action="'/api/example/import'"
:headers="{ Authorization: `Bearer ${token}` }"
:on-success="handleImportSuccess"
:on-error="handleImportError"
:headers="uploadHeaders"
@change="handleImportChange"
accept=".xls,.xlsx"
>
<el-button type="primary">导入</el-button>
</el-upload>
<n-button type="primary">导入</n-button>
</n-upload>
</template>
<script setup>
const handleImportSuccess = (response) => {
import { useMessage } from 'naive-ui';
const message = useMessage();
const token = localStorage.getItem('access_token');
const uploadHeaders = { Authorization: `Bearer ${token}` };
const handleImportChange = (data) => {
if (data.file.status !== 'finished') return;
const response = JSON.parse(data.file.event.target.response);
if (response.code === 0) {
const { count, errors } = response.data;
if (errors.length === 0) {
ElMessage.success(`成功导入 ${count} 条数据`);
message.success(`成功导入 ${count} 条数据`);
} else {
ElMessage.warning(`成功 ${count} 条,失败 ${errors.length} 条`);
message.warning(`成功 ${count} 条,失败 ${errors.length} 条`);
// 可以展示错误详情
}
refreshTable(); // 刷新列表
} else {
message.error(response.msg || '导入失败');
}
};
</script>
@@ -35,7 +35,7 @@ return [
```ini
; .env
[FILE]
UPLOAD_DIR = D:/uploads/rxthinkcmf
UPLOAD_DIR = D:\xampp8.2\htdocs\RXThinkCMF_ThinkPhp6_NaiveVue\uploads
```
**要求:**
@@ -47,10 +47,10 @@ UPLOAD_DIR = D:/uploads/rxthinkcmf
| 环境 | 路径示例 |
|------|---------|
| Windows 开发 | `D:/uploads/rxthinkcmf` |
| Linux 开发 | `/home/www/uploads/rxthinkcmf` |
| Linux 生产 | `/data/uploads/rxthinkcmf` |
| Docker | `/uploads/rxthinkcmf`(挂载卷) |
| Windows 开发 | `D:\xampp8.2\htdocs\RXThinkCMF_ThinkPhp6_NaiveVue\uploads` |
| Linux 开发 | `/home/www/uploads` |
| Linux 生产 | `/opt/data/uploads` |
| Docker | `/data/apps/uploads`(挂载卷) |
### domain_url — 文件访问域名
@@ -70,7 +70,7 @@ DOMAIN_URL = https://cdn.example.com
| 环境 | 域名示例 |
|------|---------|
| 本地开发 | (留空,使用相对路径) |
| 测试环境 | `https://test-cdn.example.com` |
| 测试环境 | `http://file.thinkphp6.naivevue` |
| 生产环境 | `https://cdn.example.com` |
| 对象存储 | `https://bucket-name.oss-cn-hangzhou.aliyuncs.com` |
@@ -124,7 +124,7 @@ FILE_EXT = gif,jpg,jpeg,png,bmp,webp,svg,doc,docx,xls,xlsx,ppt,pptx,pdf,zip,rar,
```ini
[FILE]
UPLOAD_DIR = D:/uploads/rxthinkcmf
UPLOAD_DIR = D:\xampp8.2\htdocs\RXThinkCMF_ThinkPhp6_NaiveVue\uploads
DOMAIN_URL =
MAX_SIZE = 10
```
@@ -133,8 +133,8 @@ MAX_SIZE = 10
```ini
[FILE]
UPLOAD_DIR = /home/www/uploads/rxthinkcmf
DOMAIN_URL = https://test-cdn.example.com
UPLOAD_DIR = /home/www/uploads
DOMAIN_URL = http://file.thinkphp6.naivevue
MAX_SIZE = 10
```
@@ -142,7 +142,7 @@ MAX_SIZE = 10
```ini
[FILE]
UPLOAD_DIR = /data/uploads/rxthinkcmf
UPLOAD_DIR = /opt/data/uploads
DOMAIN_URL = https://cdn.example.com
MAX_SIZE = 10
IMAGE_EXT = jpg,jpeg,png,gif,bmp,webp
@@ -154,7 +154,7 @@ FILE_EXT = jpg,jpeg,png,gif,bmp,webp,doc,docx,xls,xlsx,pdf,zip,rar
```ini
; 如果使用阿里云 OSS 等对象存储,domain_url 设为 OSS 域名
[FILE]
UPLOAD_DIR = /data/uploads/rxthinkcmf
UPLOAD_DIR = /opt/data/uploads
DOMAIN_URL = https://your-bucket.oss-cn-hangzhou.aliyuncs.com
MAX_SIZE = 50
```
@@ -235,12 +235,12 @@ class ArticleLogic extends BaseTenantLogic
```text
配置:
upload_dir = /data/uploads/rxthinkcmf
upload_dir = /opt/data/uploads
fileSaveDir = article
结果:
临时文件: /data/uploads/rxthinkcmf/temp/20260920/abc.jpg
正式文件: /data/uploads/rxthinkcmf/article/20260920/abc.jpg
临时文件: /opt/data/uploads/temp/20260920/abc.jpg
正式文件: /opt/data/uploads/article/20260920/abc.jpg
数据库存: /uploads/article/20260920/abc.jpg
前端显示: https://cdn.example.com/uploads/article/20260920/abc.jpg
```
@@ -252,7 +252,7 @@ class ArticleLogic extends BaseTenantLogic
```nginx
# 配置 Nginx 直接处理文件请求,不经过 PHP
location /uploads/ {
alias /data/uploads/rxthinkcmf/;
alias /opt/data/uploads/;
expires 30d;
add_header Cache-Control "public, immutable";
}
@@ -285,8 +285,8 @@ location ~ /\. {
```bash
# Linux
chmod -R 755 /data/uploads/rxthinkcmf
chown -R www:www /data/uploads/rxthinkcmf
chmod -R 755 /opt/data/uploads
chown -R www:www /opt/data/uploads
```
### 问题 2:上传后图片不显示
@@ -319,7 +319,7 @@ max_execution_time = 300
```bash
# 定时任务:每天凌晨清理 1 天前的临时文件
find /data/uploads/rxthinkcmf/temp/ -type f -mtime +1 -delete
find /opt/data/uploads/temp/ -type f -mtime +1 -delete
```
## 安全建议
@@ -363,35 +363,46 @@ file: <二进制图片>
## 前端集成
### Element Plus 上传组件
### NaiveUI 上传组件
```vue
<template>
<el-upload
<n-upload
:action="'/api/upload/uploadFile'"
:headers="{ Authorization: `Bearer ${token}` }"
:on-success="handleUploadSuccess"
:before-upload="beforeUpload"
:headers="uploadHeaders"
@before-upload="beforeUpload"
@change="handleUploadChange"
>
<el-button type="primary">上传文件</el-button>
</el-upload>
<n-button type="primary">上传文件</n-button>
</n-upload>
</template>
<script setup>
const token = localStorage.getItem('access_token');
import { useMessage } from 'naive-ui';
const beforeUpload = (file) => {
const isLt10M = file.size / 1024 / 1024 < 10;
const message = useMessage();
const token = localStorage.getItem('access_token');
const uploadHeaders = { Authorization: `Bearer ${token}` };
const beforeUpload = ({ file }) => {
const isLt10M = file.file.size / 1024 / 1024 < 10;
if (!isLt10M) {
ElMessage.error('文件大小不能超过 10MB');
message.error('文件大小不能超过 10MB');
return false;
}
return isLt10M;
return true;
};
const handleUploadSuccess = (response) => {
// response.data.fileUrl 是完整 URL
// 提交表单时使用此 URL
form.value.avatar = response.data.fileUrl;
const handleUploadChange = (data) => {
if (data.file.status === 'finished') {
const res = JSON.parse(data.file.event.target.response);
if (res.code === 0) {
// res.data.fileUrl 是完整 URL,提交表单时使用此 URL
form.value.avatar = res.data.fileUrl;
} else {
message.error(res.msg || '上传失败');
}
}
};
</script>
```