332 lines
13 KiB
PHP
332 lines
13 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace app\adminapi\lists\firstvisit;
|
|
|
|
use app\adminapi\lists\BaseAdminDataLists;
|
|
use app\adminapi\logic\firstvisit\MyPatientLogic;
|
|
use app\adminapi\logic\tcm\PrescriptionOrderLogic;
|
|
use app\common\lists\ListsExtendInterface;
|
|
use app\common\lists\ListsSearchInterface;
|
|
use app\common\model\Order;
|
|
use app\common\model\auth\Admin;
|
|
use app\common\model\tcm\Prescription;
|
|
use app\common\model\tcm\PrescriptionOrder;
|
|
use app\common\model\tcm\PrescriptionOrderPayOrder;
|
|
use think\db\Query;
|
|
use think\facade\Db;
|
|
|
|
/**
|
|
* “我的患者”内嵌订单列表。
|
|
*
|
|
* 订单可见性始终锚定 diagnosis 别名 d,并复用 MyPatientLogic;订单创建人仅用于展示,
|
|
* 不能作为患者归属或数据范围条件。
|
|
*/
|
|
class MyPatientOrderLists extends BaseAdminDataLists implements ListsSearchInterface, ListsExtendInterface
|
|
{
|
|
public function setSearch(): array
|
|
{
|
|
return [];
|
|
}
|
|
|
|
public function lists(): array
|
|
{
|
|
$rows = $this->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;
|
|
|
|
return [
|
|
'summary' => [
|
|
'orders' => (int) (clone $query)->count('po.id'),
|
|
'amount' => round((float) (clone $query)->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<int, array<string, mixed>> $rows
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
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));
|
|
}
|
|
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] ?? '未知';
|
|
}
|
|
}
|