*/ private const FIELD_LABELS = [ 'courier' => '快递名称', 'scope' => '快递归属', 'reconciler' => '对账人', 'supplier' => '供应商', 'types' => '附加费类型', 'mode' => '结算方式', 'standard' => '计价标准', 'condition' => '生效条件', 'effective_at' => '生效日期', 'remark' => '备注', 'status' => '状态', 'name' => '类型名称', ]; /** @var array */ private const ACTION_LABELS = [ CourierSurchargeAuditLog::ACTION_CREATED => '新增', CourierSurchargeAuditLog::ACTION_UPDATED => '更改', CourierSurchargeAuditLog::ACTION_ACTIVATED => '启用', CourierSurchargeAuditLog::ACTION_DEACTIVATED => '停用', ]; /** @var array */ private const TARGET_LABELS = [ CourierSurchargeAuditLog::TARGET_QUOTE => '报价规则', CourierSurchargeAuditLog::TARGET_TYPE => '附加费类型', ]; public function ready(): bool { try { return Schema::hasTable((new CourierSurchargeAuditLog())->getTable()); } catch (QueryException) { return false; } } /** @param array $changes */ public function record( string $action, string $targetType, ?int $targetId, string $targetLabel, array $changes, int $actorId, ): CourierSurchargeAuditLog { abort_unless($this->ready(), 503, '附加费操作日志数据表尚未完成迁移。'); abort_unless(array_key_exists($action, self::ACTION_LABELS), 422, '附加费日志动作不合法。'); abort_unless(array_key_exists($targetType, self::TARGET_LABELS), 422, '附加费日志对象不合法。'); return CourierSurchargeAuditLog::query()->create([ 'company_id' => company_id(), 'actor_id' => $actorId ?: null, 'action' => $action, 'target_type' => $targetType, 'target_id' => $targetId, 'target_label' => mb_substr(trim($targetLabel), 0, 191), 'changes' => $changes, ]); } /** * @return Collection> */ public function recent(int $limit = 50): Collection { if (! $this->ready()) { return collect(); } try { return CourierSurchargeAuditLog::query() ->with('actor') ->orderByDesc('id') ->limit(max(1, min($limit, 200))) ->get() ->map(fn (CourierSurchargeAuditLog $log): array => [ 'id' => $log->id, 'occurred_at' => optional($log->created_at)->format('Y-m-d H:i:s') ?: '', 'actor_name' => $log->actor?->name ?: '系统', 'action' => $log->action, 'action_label' => self::ACTION_LABELS[$log->action] ?? $log->action, 'target_type' => $log->target_type, 'target_id' => $log->target_id, 'target_type_label' => self::TARGET_LABELS[$log->target_type] ?? $log->target_type, 'target_label' => $log->target_label, 'changes_label' => $this->changesLabel($log), ]) ->values(); } catch (QueryException) { return collect(); } } private function changesLabel(CourierSurchargeAuditLog $log): string { $changes = (array) $log->changes; if ($log->action === CourierSurchargeAuditLog::ACTION_CREATED) { return '新增记录'; } if (in_array($log->action, [CourierSurchargeAuditLog::ACTION_ACTIVATED, CourierSurchargeAuditLog::ACTION_DEACTIVATED], true)) { $before = data_get($changes, 'before.status'); $after = data_get($changes, 'after.status'); return sprintf('状态:%s → %s', $before ?: '—', $after ?: '—'); } $before = (array) ($changes['before'] ?? []); $after = (array) ($changes['after'] ?? []); $parts = []; foreach (array_unique(array_merge(array_keys($before), array_keys($after))) as $field) { $old = $this->valueLabel($before[$field] ?? null); $new = $this->valueLabel($after[$field] ?? null); if ($old !== $new) { $parts[] = sprintf('%s:%s → %s', self::FIELD_LABELS[$field] ?? $field, $old, $new); } } return $parts === [] ? '未改变字段' : implode(';', $parts); } private function valueLabel(mixed $value): string { if (is_array($value)) { return implode('、', array_map(static fn (mixed $item): string => (string) $item, $value)); } $value = trim((string) $value); return $value === '' ? '—' : $value; } }