star-cloud/app/Services/StaffCardImportService.php
sky121113 cc03572dd9 [FEAT] 實作員工識別卡 Excel 批量匯入功能與範例下載
1. 新增 StaffCardImportService,整合 OpenSpout 5.x 處理解析與批量更新邏輯。
2. 在 StaffCardController 加入匯入與範例下載 API 端點。
3. 更新員工識別卡 index 視圖,新增「匯入 Excel」按鈕與 Alpine.js 異步匯入彈窗。
4. 註冊相關 Web 路由。
5. 補全繁中、日文、英文多語系翻譯,並修復重複鍵值。
6. 修復 OpenSpout 5.x 相容性問題 (Row::getCells -> Row::toArray)。
2026-05-14 14:26:35 +08:00

137 lines
4.1 KiB
PHP

<?php
namespace App\Services;
use App\Models\StaffCard;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use OpenSpout\Reader\XLSX\Reader;
use OpenSpout\Writer\XLSX\Writer;
use OpenSpout\Common\Entity\Row;
use OpenSpout\Common\Entity\Cell;
class StaffCardImportService
{
/**
* Import staff cards from Excel file
*
* @param string $filePath
* @param int|null $companyId
* @return array
*/
public function import(string $filePath, ?int $companyId = null): array
{
$reader = new Reader();
$reader->open($filePath);
$results = [
'success_count' => 0,
'error_count' => 0,
'errors' => [],
];
$rowCount = 0;
foreach ($reader->getSheetIterator() as $sheet) {
foreach ($sheet->getRowIterator() as $row) {
$rowCount++;
// Skip heading row (Row 1)
if ($rowCount === 1) {
continue;
}
$cells = $row->toArray();
// Expecting: 0:employee_id, 1:name, 2:card_uid, 3:notes
$data = [
'employee_id' => isset($cells[0]) ? (string)$cells[0] : null,
'name' => isset($cells[1]) ? (string)$cells[1] : null,
'card_uid' => isset($cells[2]) ? (string)$cells[2] : null,
'notes' => isset($cells[3]) ? (string)$cells[3] : null,
'company_id' => $companyId,
];
// Basic validation
if (empty($data['employee_id']) && empty($data['name']) && empty($data['card_uid'])) {
continue; // Skip empty rows
}
$validator = Validator::make($data, [
'employee_id' => 'required|string|max:50',
'name' => 'required|string|max:100',
'card_uid' => 'required|string|max:100',
]);
if ($validator->fails()) {
$results['error_count']++;
$results['errors'][] = [
'row' => $rowCount,
'messages' => $validator->errors()->all(),
];
continue;
}
try {
// Update or create based on card_uid and company_id
StaffCard::updateOrCreate(
[
'company_id' => $data['company_id'],
'card_uid' => $data['card_uid'],
],
[
'employee_id' => $data['employee_id'],
'name' => $data['name'],
'notes' => $data['notes'],
'status' => 'active',
]
);
$results['success_count']++;
} catch (\Exception $e) {
$results['error_count']++;
$results['errors'][] = [
'row' => $rowCount,
'messages' => [$e->getMessage()],
];
}
}
}
$reader->close();
return $results;
}
/**
* Download Excel template for staff cards
*
* @return void
*/
public function downloadTemplate()
{
$writer = new Writer();
$fileName = 'staff_cards_template.xlsx';
$writer->openToBrowser($fileName);
// Header Row
$headerRow = Row::fromValues([
'Employee ID (必填)',
'Staff Name (必填)',
'IC Card UID (必填)',
'Notes (選填)'
]);
$writer->addRow($headerRow);
// Example Row
$exampleRow = Row::fromValues([
'S001',
'王小明',
'12345678',
'這是備註範例'
]);
$writer->addRow($exampleRow);
$writer->close();
}
}