Appearance
导出中心插件
导出中心是 MineShop 的通用数据导出解决方案,支持大数据量异步导出、多种格式、进度追踪等功能。
🎯 系统架构
┌─────────────────────────────────────────────────────────────┐
│ ExportService │
│ 导出服务层 │
├─────────────────────────────────────────────────────────────┤
│ ExportJob │ ExportWriter │ DtoHydrator │
│ 异步任务 │ 文件写入器 │ DTO 解析器 │
├─────────────────────────────────────────────────────────────┤
│ Redis Queue │
│ 异步队列 │
└─────────────────────────────────────────────────────────────┘✨ 核心特性
1. 注解驱动
使用 @ExportColumn 注解定义导出列:
php
// OrderExportDto.php
#[ExportColumn(name: '订单编号', index: 1)]
public string $orderNo;
#[ExportColumn(name: '下单时间', index: 2)]
public string $createdAt;
#[ExportColumn(name: '订单金额', index: 3)]
public float $totalAmount;
#[ExportColumn(name: '订单状态', index: 4)]
public string $statusText;2. 多种写入器
| 写入器 | 说明 | 适用场景 |
|---|---|---|
| PhpSpreadsheetWriter | 基于 PhpSpreadsheet | 小数据量、复杂格式 |
| XlsWriterWriter | 基于 xlswriter 扩展 | 大数据量、高性能 |
3. 异步队列
通过 ConfigProvider 自动注册队列配置:
php
// ConfigProvider.php
'async_queue' => [
'export' => [
'driver' => RedisDriver::class,
'channel' => '{export-queue}',
'handle_timeout' => 600, // 10分钟超时
'processes' => 1,
'concurrent' => ['limit' => 5],
],
],4. 进度追踪
php
// AbstractExportWriter.php
protected function updateProgress(int $current, int $total): void
{
$progress = $total > 0 ? round($current / $total * 100, 2) : 0;
// 每处理 100 条或进度变化超过 1% 时更新
if ($current % 100 === 0 || $progress - $this->lastProgress >= 1) {
$this->task->update(['progress' => $progress]);
$this->lastProgress = $progress;
}
}🔄 导出流程
┌──────────┐ 创建任务 ┌──────────┐ 推送队列 ┌──────────┐
│ 发起导出 │ ───────────→ │ 任务记录 │ ───────────→ │ 异步处理 │
└──────────┘ └──────────┘ └──────────┘
│
┌─────────────────────────┤
│ │
↓ ↓
┌──────────┐ ┌──────────┐
│ 导出完成 │ │ 导出失败 │
└──────────┘ └──────────┘📦 使用示例
1. 定义导出 DTO
php
namespace App\Application\Admin\Trade\Dto;
use Plugin\ExportCenter\Annotation\ExportColumn;
class OrderExportDto
{
#[ExportColumn(name: '订单编号', index: 1)]
public string $orderNo;
#[ExportColumn(name: '收货人', index: 2)]
public string $receiverName;
#[ExportColumn(name: '订单金额', index: 3)]
public float $totalAmount;
}2. Repository 实现导出方法
php
// OrderRepository.php
public function export(array $params): Generator
{
$query = $this->buildExportQuery($params);
foreach ($query->cursor() as $order) {
yield $this->toExportDto($order);
}
}3. 控制器调用
php
// OrderController.php
public function export(ExportRequest $request): ResponseInterface
{
return $this->exportService->create(
name: '订单导出',
dtoClass: OrderExportDto::class,
generator: fn() => $this->repository->export($request->all()),
);
}💻 API 接口
| 接口 | 方法 | 说明 |
|---|---|---|
/export/task | GET | 任务列表 |
/export/task/{id} | GET | 任务详情 |
/export/task/{id}/download | GET | 下载文件 |
/export/task/{id} | DELETE | 删除任务 |
⚠️ 注意事项
- 内存控制: 使用 Generator 避免内存溢出
- 超时设置: 大数据量导出需调整 handle_timeout
- 文件清理: 定期清理过期导出文件
- 并发限制: 通过 concurrent.limit 控制并发数