buildQuery() ->field([ 'po.id', 'po.order_no', 'po.prescription_id', 'po.diagnosis_id', 'po.creator_id', 'po.recipient_name', 'po.recipient_phone', 'po.fee_type', 'po.amount', 'po.prescription_audit_status', 'po.payment_slip_audit_status', 'po.fulfillment_status', 'po.express_company', 'po.tracking_number', 'po.ship_mode', 'po.gancao_reciperl_order_no', 'po.ej_pharmacy_order_no', 'po.gancao_submit_time', 'po.ej_pharmacy_submit_time', 'po.ej_pharmacy_status', 'po.ej_pharmacy_review_status', 'po.refund_amount', 'po.create_time', 'd.patient_name', 'd.phone AS patient_phone', 'd.assistant_id', ]) ->order('po.id', 'desc') ->limit($this->limitOffset, $this->limitLength) ->select() ->toArray(); return $this->appendRelations($rows); } public function count(): int { return (int) $this->buildQuery()->count('po.id'); } public function extend(): array { $query = $this->buildQuery(); $pendingQuery = clone $query; $effectiveAmountQuery = clone $query; YejiStatsLogic::applyPrescriptionOrderEffectiveAmountQuery($effectiveAmountQuery, 'po'); return [ 'summary' => [ 'orders' => (int) (clone $query)->count('po.id'), 'amount' => round((float) $effectiveAmountQuery->sum('po.amount'), 2), 'pending' => (int) $pendingQuery ->where(function ($q) { $q->where('po.prescription_audit_status', 0) ->whereOr('po.payment_slip_audit_status', 0); }) ->count('po.id'), 'completed' => (int) (clone $query)->whereIn('po.fulfillment_status', [3, 6])->count('po.id'), ], 'scope' => MyPatientLogic::scopeMeta($this->adminId, $this->adminInfo), ]; } private function buildQuery(): Query { $query = PrescriptionOrder::alias('po') ->join('tcm_diagnosis d', 'po.diagnosis_id = d.id') ->whereNull('po.delete_time') ->whereNull('d.delete_time') ->where('d.status', 1); MyPatientLogic::applyScope($query, $this->adminId, $this->adminInfo); $this->applyKeyword($query); $this->applyStatusFilters($query); $this->applyDateFilter($query); return $query; } private function applyKeyword(Query $query): void { $keyword = trim((string) ($this->params['keyword'] ?? '')); if ($keyword === '') { return; } $query->where(function ($q) use ($keyword) { $like = '%' . $keyword . '%'; $q->whereLike('po.order_no', $like) ->whereOr('d.patient_name', 'like', $like) ->whereOr('d.phone', 'like', $like) ->whereOr('po.recipient_name', 'like', $like) ->whereOr('po.recipient_phone', 'like', $like); if (preg_match('/^\d+$/', $keyword)) { $id = (int) $keyword; if ($id > 0) { $q->whereOr('po.id', $id) ->whereOr('po.prescription_id', $id) ->whereOr('po.diagnosis_id', $id); } } }); } private function applyStatusFilters(Query $query): void { foreach (['prescription_audit_status', 'payment_slip_audit_status', 'fulfillment_status'] as $field) { $raw = $this->params[$field] ?? ''; if ($raw === '' || $raw === null) { continue; } $query->where('po.' . $field, (int) $raw); } } private function applyDateFilter(Query $query): void { [$startDate, $endDate] = $this->dateRange(); if ($startDate !== '') { $query->where('po.create_time', '>=', strtotime($startDate . ' 00:00:00')); } if ($endDate !== '') { $query->where('po.create_time', '<=', strtotime($endDate . ' 23:59:59')); } } /** @return array{0:string,1:string} */ private function dateRange(): array { $startDate = $this->normalizeDate($this->params['start_date'] ?? ''); $endDate = $this->normalizeDate($this->params['end_date'] ?? ''); if ($startDate === '' && $endDate !== '') { $startDate = $endDate; } if ($endDate === '' && $startDate !== '') { $endDate = $startDate; } if ($startDate !== '' && $endDate !== '' && $startDate > $endDate) { [$startDate, $endDate] = [$endDate, $startDate]; } return [$startDate, $endDate]; } private function normalizeDate($value): string { $value = trim((string) $value); return preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) ? $value : ''; } /** * @param array> $rows * @return array> */ private function appendRelations(array $rows): array { if ($rows === []) { return []; } $orderIds = array_values(array_unique(array_filter(array_map('intval', array_column($rows, 'id'))))); $prescriptionIds = array_values(array_unique(array_filter(array_map('intval', array_column($rows, 'prescription_id'))))); $creatorIds = array_values(array_unique(array_filter(array_map('intval', array_column($rows, 'creator_id'))))); $assistantIds = array_values(array_unique(array_filter(array_map('intval', array_column($rows, 'assistant_id'))))); $prescriptionMap = []; $doctorIds = []; if ($prescriptionIds !== []) { $prescriptions = Prescription::whereIn('id', $prescriptionIds) ->whereNull('delete_time') ->field(['id', 'creator_id', 'doctor_name']) ->select() ->toArray(); foreach ($prescriptions as $prescription) { $prescriptionId = (int) ($prescription['id'] ?? 0); $doctorId = (int) ($prescription['creator_id'] ?? 0); if ($prescriptionId > 0) { $prescriptionMap[$prescriptionId] = $prescription; } if ($doctorId > 0) { $doctorIds[] = $doctorId; } } } $adminIds = array_values(array_unique(array_merge($creatorIds, $assistantIds, $doctorIds))); $adminNames = $adminIds === [] ? [] : Admin::whereIn('id', $adminIds)->whereNull('delete_time')->column('name', 'id'); $linkCounts = []; $paidTotals = []; if ($orderIds !== []) { $linkRows = PrescriptionOrderPayOrder::whereIn('prescription_order_id', $orderIds) ->field(['prescription_order_id', 'pay_order_id']) ->select() ->toArray(); $payOrderIds = array_values(array_unique(array_filter(array_map('intval', array_column($linkRows, 'pay_order_id'))))); $payOrders = $payOrderIds === [] ? [] : Order::whereIn('id', $payOrderIds) ->whereNull('delete_time') ->field(['id', 'amount', 'status']) ->select() ->toArray(); $payOrderMap = []; foreach ($payOrders as $payOrder) { $payOrderMap[(int) ($payOrder['id'] ?? 0)] = $payOrder; } foreach ($linkRows as $linkRow) { $orderId = (int) ($linkRow['prescription_order_id'] ?? 0); if ($orderId > 0) { $linkCounts[$orderId] = ($linkCounts[$orderId] ?? 0) + 1; } $payOrder = $payOrderMap[(int) ($linkRow['pay_order_id'] ?? 0)] ?? []; if ($orderId > 0 && in_array((int) ($payOrder['status'] ?? 0), [2, 5], true)) { $paidTotals[$orderId] = round( (float) ($paidTotals[$orderId] ?? 0) + (float) ($payOrder['amount'] ?? 0), 2 ); } } } $assistantByDiagnosis = []; foreach ($rows as $row) { $diagnosisId = (int) ($row['diagnosis_id'] ?? 0); if ($diagnosisId > 0) { $assistantByDiagnosis[$diagnosisId] = (int) ($row['assistant_id'] ?? 0); } } $claimByOrder = []; if ($orderIds !== []) { $claimRows = Db::name('pharmacy_submission_claim') ->whereIn('prescription_order_id', $orderIds) ->field(['prescription_order_id', 'target', 'status', 'lease_expires_at']) ->order('source_revision', 'desc') ->select() ->toArray(); foreach ($claimRows as $claimRow) { $orderId = (int) ($claimRow['prescription_order_id'] ?? 0); if ($orderId > 0 && !isset($claimByOrder[$orderId])) { $claimByOrder[$orderId] = $claimRow; } } } foreach ($rows as &$row) { $prescription = $prescriptionMap[(int) ($row['prescription_id'] ?? 0)] ?? []; $doctorId = (int) ($prescription['creator_id'] ?? 0); $doctorName = trim((string) ($prescription['doctor_name'] ?? '')); $creatorId = (int) ($row['creator_id'] ?? 0); $assistantId = (int) ($row['assistant_id'] ?? 0); $row['patient_phone_masked'] = $this->maskPhone((string) ($row['patient_phone'] ?? '')); $row['recipient_phone_masked'] = $this->maskPhone((string) ($row['recipient_phone'] ?? '')); unset($row['patient_phone'], $row['recipient_phone']); $row['creator_name'] = (string) ($adminNames[$creatorId] ?? '—'); $row['assistant_name'] = (string) ($adminNames[$assistantId] ?? '未分配'); $row['doctor_name'] = $doctorName !== '' ? $doctorName : (string) ($adminNames[$doctorId] ?? '—'); $row['linked_pay_order_count'] = (int) ($linkCounts[(int) $row['id']] ?? 0); $row['linked_pay_paid_total'] = (float) ($paidTotals[(int) $row['id']] ?? 0); $claim = $claimByOrder[(int) $row['id']] ?? []; $row['pharmacy_claim_target'] = (string) ($claim['target'] ?? ''); $row['pharmacy_claim_status'] = (string) ($claim['status'] ?? ''); $row['pharmacy_claim_lease_expires_at'] = (int) ($claim['lease_expires_at'] ?? 0); $row['can_upload_pharmacy'] = PrescriptionOrderLogic::canUploadToPharmacy( $row, $this->adminId, $this->adminInfo, $assistantByDiagnosis ); $row['create_time_text'] = $this->formatTimestamp($row['create_time'] ?? 0); $row['fee_type_text'] = $this->feeTypeText((int) ($row['fee_type'] ?? 0)); $row['prescription_audit_text'] = $this->auditStatusText((int) ($row['prescription_audit_status'] ?? 0)); $row['payment_slip_audit_text'] = $this->auditStatusText((int) ($row['payment_slip_audit_status'] ?? 0)); $row['fulfillment_text'] = $this->fulfillmentStatusText((int) ($row['fulfillment_status'] ?? 0)); $fulfillmentStatus = (int) ($row['fulfillment_status'] ?? 0); $refundAmount = round((float) ($row['refund_amount'] ?? 0), 2); $amountIncluded = !in_array( $fulfillmentStatus, YejiStatsLogic::PRESCRIPTION_ORDER_FULFILLMENT_EXCLUDED_FROM_PERFORMANCE, true ) && $refundAmount <= 0; $row['amount_included'] = $amountIncluded; $row['effective_amount'] = $amountIncluded ? round((float) ($row['amount'] ?? 0), 2) : 0.0; $row['amount_exclusion_text'] = $amountIncluded ? '' : ($refundAmount > 0 || $fulfillmentStatus === 10 ? '退款不计入' : $row['fulfillment_text'] . '不计入'); } unset($row); return $rows; } private function maskPhone(string $phone): string { return preg_replace('/^(\d{3})\d{4}(\d{4})$/', '$1****$2', $phone) ?: $phone; } private function formatTimestamp($value): string { return is_numeric($value) && (int) $value > 0 ? date('Y-m-d H:i', (int) $value) : ''; } private function auditStatusText(int $status): string { return [0 => '待审核', 1 => '已通过', 2 => '已驳回'][$status] ?? '未知'; } private function feeTypeText(int $type): string { return [1 => '挂号', 2 => '问诊', 3 => '药品', 4 => '首付', 5 => '尾款', 6 => '其他', 7 => '全部'][$type] ?? '其他'; } private function fulfillmentStatusText(int $status): string { return [ 1 => '待双审通过', 2 => '待发货', 3 => '已完成', 4 => '已取消', 5 => '已发货', 6 => '已签收', 7 => '进行中', 8 => '暂不制药', 9 => '拒收', 10 => '退款', 11 => '保留药方', 12 => '制药缓发', ][$status] ?? '未知'; } }