master
lion 2 days ago
parent d8f4556ccd
commit 528f6b18d7

@ -30,6 +30,9 @@ class VenueImportService
/** @var array<string, string>|null 主题item_label => item_value与数据字典 venue_type 同步,按请求缓存) */
private ?array $themeLabelToValueMapCache = null;
/** @var array<string, string>|null 开放模式item_label => item_value与数据字典 venue_open_mode 同步,按请求缓存) */
private ?array $openModeLabelToValueMapCache = null;
private const TICKET_TYPE_LABEL = [
'免费' => 'free',
'收费' => 'paid',
@ -46,12 +49,6 @@ class VenueImportService
'个人不需预约团队需预约' => 'team_required',
];
private const OPEN_MODE_LABEL = [
'常态化全时开放' => 'fulltime',
'常态化定时开放' => 'scheduled',
'预约开放' => 'appointment',
];
/**
* @return array<string, string> 中文标签 => item_value
*/
@ -73,6 +70,27 @@ class VenueImportService
return $this->themeLabelToValueMapCache;
}
/**
* @return array<string, string> 中文标签 => item_value与后台数据字典「场馆开放模式」一致勿硬编码以免改文案后导入失败
*/
private function openModeLabelToValueMap(): array
{
if ($this->openModeLabelToValueMapCache !== null) {
return $this->openModeLabelToValueMapCache;
}
$this->openModeLabelToValueMapCache = DictItem::query()
->where('dict_type', 'venue_open_mode')
->where('is_active', true)
->orderBy('sort')
->orderBy('id')
->get(['item_label', 'item_value'])
->mapWithKeys(fn ($r) => [trim((string) $r->item_label) => (string) $r->item_value])
->all();
return $this->openModeLabelToValueMapCache;
}
public function buildTemplateSpreadsheet(): Spreadsheet
{
$spreadsheet = new Spreadsheet();
@ -153,9 +171,12 @@ class VenueImportService
$opt->setCellValue('E4', '个人不需预约团队需预约');
$opt->setCellValue('F1', '开放模式');
$opt->setCellValue('F2', '常态化全时开放');
$opt->setCellValue('F3', '常态化定时开放');
$opt->setCellValue('F4', '预约开放');
$fr = 2;
foreach (array_keys($this->openModeLabelToValueMap()) as $openLabel) {
$opt->setCellValue('F' . $fr, $openLabel);
$fr++;
}
$lastF = max(2, $fr - 1);
$opt->setCellValue('G1', '是否');
$opt->setCellValue('G2', '是');
@ -167,7 +188,7 @@ class VenueImportService
$this->applyListValidation($sheet, 'D2:D5000', '=选项!$D$2:$D$3'); // 预约类型
$this->applyListValidation($sheet, 'E2:E5000', '=选项!$C$2:$C$3'); // 门票类型
$this->applyListValidation($sheet, 'F2:F5000', '=选项!$E$2:$E$4'); // 预约模式
$this->applyListValidation($sheet, 'G2:G5000', '=选项!$F$2:$F$4'); // 开放模式
$this->applyListValidation($sheet, 'G2:G5000', '=选项!$F$2:$F$' . $lastF); // 开放模式(与字典 label 一致)
$this->applyListValidation($sheet, 'O2:O5000', '=选项!$G$2:$G$3'); // 启用
$this->applyListValidation($sheet, 'P2:P5000', '=选项!$G$2:$G$3'); // 纳入人数统计
@ -272,7 +293,8 @@ class VenueImportService
$ticketType = $rawTicket === '' ? null : (self::TICKET_TYPE_LABEL[$rawTicket] ?? null);
$appointmentType = $rawApp === '' ? null : (self::APPOINTMENT_LABEL[$rawApp] ?? null);
$bookingMode = $rawBookingMode === '' ? null : (self::BOOKING_MODE_LABEL[$rawBookingMode] ?? null);
$openMode = $rawOpen === '' ? null : (self::OPEN_MODE_LABEL[$rawOpen] ?? null);
$openModeMap = $this->openModeLabelToValueMap();
$openMode = $rawOpen === '' ? null : ($openModeMap[$rawOpen] ?? null);
$lng = $this->parseFloat($g(17));
$lat = $this->parseFloat($g(18));
@ -295,8 +317,9 @@ class VenueImportService
'consultation_hours' => $this->squishPlain($g(11) === '' ? null : $g(11)),
'contact_phone' => $this->squishPlain($g(12) === '' ? null : $g(12)),
'sort' => $sort,
'is_active' => $this->parseBool($g(14)),
'is_included_in_stats' => $this->parseBool($g(15)),
// 启用:留空按「是」与常见新建习惯;纳入人数统计:留空须为「否」,否则全表空单元格会全部被 parse 成 true
'is_active' => $this->parseYesNoWithEmptyDefault($g(14), true),
'is_included_in_stats' => $this->parseYesNoWithEmptyDefault($g(15), false),
'address' => $this->squishPlain($g(16) === '' ? null : $g(16)),
'lng' => $lng,
'lat' => $lat,
@ -339,7 +362,7 @@ class VenueImportService
$errors[] = '预约类型须为「仅团队」「个人团队均可」或留空';
}
if (($data['_raw_open_mode_label'] ?? '') !== '' && ($data['open_mode'] ?? null) === null) {
$errors[] = '开放模式须为三种选项之一或留空';
$errors[] = '开放模式须与数据字典「场馆开放模式」中的选项名称一致,或留空(可重新下载模板查看当前选项)';
}
if (($data['_raw_booking_mode_label'] ?? '') !== '' && ($data['booking_mode'] ?? null) === null) {
$errors[] = '预约模式须为三种选项之一或留空';
@ -485,16 +508,22 @@ class VenueImportService
return is_finite($n) ? $n : null;
}
private function parseBool(string $s): bool
/**
* 解析「是/否」类单元格。空串或无法识别时由 $defaultWhenEmpty 决定,避免与「启用」不同列共用同一套默认导致误纳入统计。
*/
private function parseYesNoWithEmptyDefault(string $s, bool $defaultWhenEmpty): bool
{
$t = mb_strtolower(trim($s));
if ($t === '' || in_array($t, ['1', '是', 'y', 'yes', 'true', '启用'], true)) {
$t = mb_strtolower(trim($s), 'UTF-8');
if ($t === '') {
return $defaultWhenEmpty;
}
if (in_array($t, ['1', '是', 'y', 'yes', 'true', '启用'], true)) {
return true;
}
if (in_array($t, ['0', '否', 'n', 'no', 'false', '禁用'], true)) {
return false;
}
return true;
return $defaultWhenEmpty;
}
}

Loading…
Cancel
Save