ensureTable(); $this->bootstrapDefaults(); } public function list(bool $enabledOnly = false): array { $query = Db::name('express_companies') ->order('is_default', 'desc') ->order('sort_order', 'asc') ->order('id', 'asc'); if ($enabledOnly) { $query->where('status', 'enabled'); } return array_map(fn (array $item) => $this->format($item), $query->select()->toArray()); } public function save(array $payload, int $id = 0): int { $now = date('Y-m-d H:i:s'); $companyName = trim((string)($payload['company_name'] ?? '')); $companyCode = trim((string)($payload['company_code'] ?? '')); $status = trim((string)($payload['status'] ?? 'enabled')); $isDefault = !empty($payload['is_default']); if ($companyName === '') { throw new \RuntimeException('快递公司名称不能为空'); } if (!in_array($status, ['enabled', 'disabled'], true)) { throw new \RuntimeException('快递公司状态无效'); } if ($isDefault && $status !== 'enabled') { throw new \RuntimeException('默认快递公司必须保持启用'); } if ($companyCode === '') { $companyCode = $this->generateCompanyCode($companyName); } $existsByName = Db::name('express_companies') ->where('company_name', $companyName) ->when($id > 0, fn ($query) => $query->where('id', '<>', $id)) ->find(); if ($existsByName) { throw new \RuntimeException('快递公司名称已存在'); } $existsByCode = Db::name('express_companies') ->where('company_code', $companyCode) ->when($id > 0, fn ($query) => $query->where('id', '<>', $id)) ->find(); if ($existsByCode) { throw new \RuntimeException('快递公司编码已存在'); } $data = [ 'company_name' => $companyName, 'company_code' => $companyCode, 'status' => $status, 'is_default' => $isDefault ? 1 : 0, 'sort_order' => (int)($payload['sort_order'] ?? 0), 'remark' => trim((string)($payload['remark'] ?? '')), 'updated_at' => $now, ]; Db::startTrans(); try { if ($isDefault) { Db::name('express_companies')->update([ 'is_default' => 0, 'updated_at' => $now, ]); } if ($id > 0) { Db::name('express_companies')->where('id', $id)->update($data); $companyId = $id; } else { $data['created_at'] = $now; $companyId = (int)Db::name('express_companies')->insertGetId($data); } $this->ensureEnabledDefault($now); Db::commit(); } catch (\Throwable $e) { Db::rollback(); throw $e; } return $companyId; } public function defaultName(): string { $row = Db::name('express_companies') ->where('status', 'enabled') ->where('is_default', 1) ->find(); if (!$row) { $row = Db::name('express_companies') ->where('status', 'enabled') ->order('sort_order', 'asc') ->order('id', 'asc') ->find(); } return trim((string)($row['company_name'] ?? '')); } private function format(array $item): array { $status = (string)($item['status'] ?? 'enabled'); return [ 'id' => (int)$item['id'], 'company_name' => (string)$item['company_name'], 'company_code' => (string)$item['company_code'], 'status' => $status, 'status_text' => $status === 'enabled' ? '启用中' : '已停用', 'is_default' => (bool)$item['is_default'], 'sort_order' => (int)$item['sort_order'], 'remark' => (string)($item['remark'] ?? ''), 'created_at' => (string)($item['created_at'] ?? ''), 'updated_at' => (string)($item['updated_at'] ?? ''), ]; } private function bootstrapDefaults(): void { $now = date('Y-m-d H:i:s'); $exists = Db::name('express_companies')->where('company_name', '顺丰速运')->find(); if (!$exists) { Db::name('express_companies')->insert([ 'company_name' => '顺丰速运', 'company_code' => 'sf_express', 'status' => 'enabled', 'is_default' => 1, 'sort_order' => 1, 'remark' => '系统默认快递公司', 'created_at' => $now, 'updated_at' => $now, ]); } $this->ensureEnabledDefault($now); } private function ensureEnabledDefault(string $now): void { $default = Db::name('express_companies') ->where('status', 'enabled') ->where('is_default', 1) ->find(); if ($default) { return; } $firstEnabled = Db::name('express_companies') ->where('status', 'enabled') ->order('sort_order', 'asc') ->order('id', 'asc') ->find(); if ($firstEnabled) { Db::name('express_companies')->where('id', $firstEnabled['id'])->update([ 'is_default' => 1, 'updated_at' => $now, ]); } } private function generateCompanyCode(string $companyName): string { return 'express_' . substr(hash('sha256', $companyName), 0, 12); } private function ensureTable(): void { Db::execute(<<<'SQL' CREATE TABLE IF NOT EXISTS express_companies ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, company_name VARCHAR(64) NOT NULL DEFAULT '', company_code VARCHAR(64) NOT NULL DEFAULT '', status VARCHAR(32) NOT NULL DEFAULT 'enabled', is_default TINYINT(1) NOT NULL DEFAULT 0, sort_order INT NOT NULL DEFAULT 0, remark VARCHAR(255) NOT NULL DEFAULT '', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_express_companies_name (company_name), UNIQUE KEY uk_express_companies_code (company_code), KEY idx_express_companies_status (status), KEY idx_express_companies_default (is_default) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='快递公司字典' SQL); } }