You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
4.8 KiB

1 week ago
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Models\Venue;
use App\Support\VenueAdminCredentials;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
class BatchCreateVenueAdminAccountsCommand extends Command
{
protected $signature = 'venues:create-admin-accounts
{--output= : 导出 xlsx 绝对或相对路径(默认 storage/app/exports/venue_admins_时间戳.xlsx}
1 week ago
{--dry-run : 仅生成 Excel不向 users / user_venue 写入(预览或离线存档)}';
1 week ago
protected $description = '为每个场馆创建一个场馆管理员账号(姓名=馆名,用户名=拼音首字母缩写,密码按规则),并绑定该场馆;导出含明文密码的 Excel';
public function handle(): int
{
$venues = Venue::query()->orderBy('id')->get(['id', 'name']);
if ($venues->isEmpty()) {
$this->warn('数据库中暂无场馆。');
return self::FAILURE;
}
$this->info("将处理 {$venues->count()} 个场馆。");
$rows = [];
$reservedNames = User::query()->pluck('username')->all();
$reservedSet = array_fill_keys($reservedNames, true);
$batchUsed = [];
foreach ($venues as $venue) {
$name = (string) $venue->name;
$base = VenueAdminCredentials::acronymFromVenueName($name);
$plainPassword = VenueAdminCredentials::passwordFromAcronym($base);
$username = $base;
$suffix = 2;
while (isset($reservedSet[$username]) || isset($batchUsed[$username])) {
$username = $base.$suffix;
$suffix++;
}
$batchUsed[$username] = true;
$rows[] = [
'venue_id' => $venue->id,
'name' => $name,
'username' => $username,
'password_plain' => $plainPassword,
'role' => '场馆管理员',
'venue_name' => $name,
];
}
$defaultDir = storage_path('app/exports');
if (! is_dir($defaultDir)) {
mkdir($defaultDir, 0755, true);
}
$outPath = $this->option('output');
if (! $outPath) {
$outPath = $defaultDir.'/venue_admins_'.now()->format('Ymd_His').'.xlsx';
} elseif (! str_starts_with((string) $outPath, '/')) {
$outPath = base_path($outPath);
}
1 week ago
$dryRun = (bool) $this->option('dry-run');
if ($dryRun) {
$this->warn('当前为 --dry-run只生成 Excel不会写入 users / user_venue。去掉 --dry-run 才会入库。');
} else {
$this->info('即将写入数据库users、user_venue随后生成 Excel…');
DB::transaction(function () use ($rows) {
foreach ($rows as $row) {
$user = User::updateOrCreate(
['username' => $row['username']],
[
'name' => $row['name'],
'email' => null,
'password' => $row['password_plain'],
'role' => 'venue_admin',
'is_active' => true,
]
);
$user->venues()->sync([$row['venue_id']]);
}
});
$this->info('数据库写入完成:已创建/更新 '.count($rows).' 个场馆管理员并完成场馆绑定。');
}
1 week ago
$this->writeXlsx($outPath, $rows);
$this->info("Excel 已生成:{$outPath}");
1 week ago
if ($dryRun) {
$this->warn('本次未写入数据库。若需要入库请执行php artisan venues:create-admin-accounts不要带 --dry-run');
1 week ago
return self::SUCCESS;
}
return self::SUCCESS;
}
/**
* @param array<int, array{venue_id:int, name:string, username:string, password_plain:string, role:string, venue_name:string}> $rows
*/
private function writeXlsx(string $path, array $rows): void
{
$sheetRows = [
['场馆ID', '姓名', '用户名', '密码(明文)', '角色', '绑定场馆'],
];
foreach ($rows as $r) {
$sheetRows[] = [
$r['venue_id'],
$r['name'],
$r['username'],
$r['password_plain'],
$r['role'],
$r['venue_name'],
];
}
$spreadsheet = new Spreadsheet;
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle('场馆管理员账号');
$sheet->fromArray($sheetRows, null, 'A1');
$writer = new Xlsx($spreadsheet);
$writer->save($path);
}
}