Appearance
导出中心
MineShop 的导出中心以插件形式提供,支持大数据量异步导出、多种格式输出、下载中心管理等功能。
🎯 系统架构
┌─────────────────────────────────────────────────────────────┐
│ 导出中心插件 │
├─────────────────────────────────────────────────────────────┤
│ ExportService │ DtoHydrator │ Writer │ 下载中心 │
├─────────────────────────────────────────────────────────────┤
│ 异步队列 (export-queue) │
├─────────────────────────────────────────────────────────────┤
│ PhpSpreadsheet Writer │ XlsWriter Writer │ CSV Writer │
└─────────────────────────────────────────────────────────────┘✨ 核心特性
1. 注解驱动
使用 @ExportColumn 注解定义导出字段:
php
// OrderExportDto.php
class OrderExportDto
{
#[ExportColumn(name: '订单号', width: 20)]
public string $orderNo;
#[ExportColumn(name: '会员昵称', width: 15)]
public string $memberNickname;
#[ExportColumn(name: '商品名称', width: 30)]
public string $productName;
#[ExportColumn(name: '订单金额', width: 12, format: 'money')]
public int $totalAmount;
#[ExportColumn(name: '订单状态', width: 10)]
public string $statusText;
#[ExportColumn(name: '下单时间', width: 20, format: 'datetime')]
public ?string $createdAt;
}2. 异步导出
php
// ExportService.php
public function export(string $dtoClass, iterable $dataSource, array $options = []): ExportTask
{
// 1. 创建导出任务
$task = $this->createTask($dtoClass, $options);
// 2. 投递到异步队列
$this->queueDriver->push(new ExportJob(
taskId: $task->id,
dtoClass: $dtoClass,
dataSource: $dataSource,
options: $options,
));
return $task;
}3. 分批处理
php
// AbstractExportWriter.php
protected function writeInBatches(iterable $data, int $batchSize = 1000): void
{
$batch = [];
$count = 0;
foreach ($data as $row) {
$batch[] = $row;
$count++;
if ($count >= $batchSize) {
$this->writeBatch($batch);
$batch = [];
$count = 0;
// 更新进度
$this->updateProgress();
}
}
// 写入剩余数据
if (!empty($batch)) {
$this->writeBatch($batch);
}
}4. 多种 Writer
php
// PhpSpreadsheetWriter - 兼容性好
class PhpSpreadsheetWriter extends AbstractExportWriter
{
protected function createWorkbook(): void
{
$this->spreadsheet = new Spreadsheet();
$this->sheet = $this->spreadsheet->getActiveSheet();
}
}
// XlsWriterWriter - 高性能
class XlsWriterWriter extends AbstractExportWriter
{
protected function createWorkbook(): void
{
$this->excel = new \Vtiful\Kernel\Excel(['path' => $this->tempPath]);
$this->excel->fileName($this->filename);
}
}📦 插件配置
plugin.json
json
{
"name": "since/export-center",
"version": "1.0.0",
"description": "导出中心插件",
"namespace": "Plugin\\ExportCenter",
"configProvider": "Plugin\\ExportCenter\\ConfigProvider"
}ConfigProvider
php
// ConfigProvider.php
class ConfigProvider
{
public function __invoke()
{
return [
'async_queue' => [
'export' => [
'driver' => RedisDriver::class,
'channel' => '{export-queue}',
'timeout' => 2,
'retry_seconds' => 10,
'handle_timeout' => 600, // 10分钟超时
'processes' => 1,
'concurrent' => [
'limit' => 5,
],
],
],
'processes' => [
ExportConsumerProcess::class,
],
];
}
}🔄 导出流程
┌──────────┐ 创建任务 ┌──────────┐ 队列消费 ┌──────────┐
│ 请求导出 │ ───────────→ │ pending │ ───────────→ │ processing│
└──────────┘ └──────────┘ └──────────┘
│
┌─────────────────────────┤
│ │
↓ ↓
┌──────────┐ ┌──────────┐
│ completed│ │ failed │
│ 已完成 │ │ 失败 │
└──────────┘ └──────────┘💻 使用示例
后台导出订单
php
// OrderController.php
public function export(ExportRequest $request): ResponseInterface
{
$query = $this->queryService->buildExportQuery($request->all());
$task = $this->exportService->export(
dtoClass: OrderExportDto::class,
dataSource: $query->cursor(),
options: [
'filename' => '订单导出_' . date('YmdHis'),
'format' => 'xlsx',
]
);
return $this->success([
'task_id' => $task->id,
'message' => '导出任务已创建,请在下载中心查看',
]);
}自定义 DTO
php
// ProductExportDto.php
class ProductExportDto
{
#[ExportColumn(name: '商品ID', width: 10)]
public int $id;
#[ExportColumn(name: '商品名称', width: 30)]
public string $name;
#[ExportColumn(name: '分类', width: 15)]
public string $categoryName;
#[ExportColumn(name: '价格', width: 12, format: 'money')]
public int $price;
#[ExportColumn(name: '库存', width: 10)]
public int $stock;
#[ExportColumn(name: '状态', width: 10)]
public string $statusText;
}📊 下载中心
任务列表
| 接口 | 方法 | 说明 |
|---|---|---|
/admin/export/tasks | GET | 导出任务列表 |
/admin/export/tasks/{id} | GET | 任务详情 |
/admin/export/download/{id} | GET | 下载文件 |
/admin/export/tasks/{id} | DELETE | 删除任务 |
任务状态
| 状态 | 说明 |
|---|---|
pending | 等待处理 |
processing | 处理中 |
completed | 已完成 |
failed | 失败 |
expired | 已过期 |
🔧 格式化器
php
// 内置格式化器
'money' => fn($v) => number_format($v / 100, 2),
'datetime' => fn($v) => $v ? date('Y-m-d H:i:s', strtotime($v)) : '',
'date' => fn($v) => $v ? date('Y-m-d', strtotime($v)) : '',
'boolean' => fn($v) => $v ? '是' : '否',⚠️ 注意事项
- 内存管理: 使用 cursor() 或 chunk() 避免内存溢出
- 超时设置: 大数据量导出需要增加超时时间
- 文件清理: 定期清理过期的导出文件
- 并发控制: 限制同时进行的导出任务数量