$candidateIds * @return array */ private function collectRiskPrescriptionIds(array $candidateIds): array { $candidateIds = array_values(array_unique(array_filter(array_map('intval', $candidateIds), static function (int $id): bool { return $id > 0; }))); if ($candidateIds === []) { return []; } // 仅在「存在有效业务订单」的处方里做风险判定 $orderRxIds = PrescriptionOrder::whereIn('prescription_id', $candidateIds) ->whereNull('delete_time') ->where('fulfillment_status', '<>', 4) ->column('prescription_id'); $orderRxIds = array_values(array_unique(array_filter(array_map('intval', $orderRxIds), static function (int $id): bool { return $id > 0; }))); if ($orderRxIds === []) { return []; } $rows = Prescription::whereIn('id', $orderRxIds) ->whereNull('delete_time') ->field(['id', 'herbs']) ->select() ->toArray(); $riskIds = []; foreach ($rows as $row) { $rid = (int) ($row['id'] ?? 0); if ($rid <= 0) { continue; } if ($this->isRiskHerbs($row['herbs'] ?? null)) { $riskIds[] = $rid; } } return array_values(array_unique($riskIds)); } /** * 药材风险判定:空白 or 重复(按名称,忽略空格与大小写) */ private function isRiskHerbs($herbsRaw): bool { $herbs = []; if (is_array($herbsRaw)) { $herbs = $herbsRaw; } elseif (is_string($herbsRaw) && $herbsRaw !== '') { $decoded = json_decode($herbsRaw, true); if (is_array($decoded)) { $herbs = $decoded; } } $names = []; foreach ($herbs as $h) { if (!is_array($h)) { continue; } $name = trim((string) ($h['name'] ?? '')); if ($name !== '') { $names[] = $name; } } // 空白药材 if ($names === []) { return true; } // 重复药材 $seen = []; foreach ($names as $name) { $key = strtolower(preg_replace('/\s+/', '', $name) ?? ''); if ($key === '') { continue; } if (isset($seen[$key])) { return true; } $seen[$key] = true; } return false; } /** * @notes 搜索条件 */ public function setSearch(): array { return [ '%like%' => ['patient_name', 'sn'], 'between_time' => 'create_time', ]; } /** 创建人(医师账号)多选,参数 creator_ids:数组或逗号分隔 ID */ private function applyCreatorIdsFilter($query): void { $raw = $this->params['creator_ids'] ?? null; if ($raw === null || $raw === '') { return; } $ids = \is_array($raw) ? $raw : explode(',', (string) $raw); $ids = array_values(array_filter(array_map('intval', $ids), static function (int $id): bool { return $id > 0; })); if ($ids === []) { return; } $query->whereIn('creator_id', $ids); } /** * audit_filter:passed=已通过,not_passed=未通过(待审+驳回),pending,rejected */ private function applyAuditFilter($query): void { $af = (string) ($this->params['audit_filter'] ?? ''); if ($af === '' || $af === 'all') { return; } switch ($af) { case 'passed': $query->where('audit_status', '=', 1); break; case 'not_passed': $query->whereIn('audit_status', [0, 2]); break; case 'pending': $query->where('audit_status', '=', 0); break; case 'rejected': $query->where('audit_status', '=', 2); break; default: break; } } /** * 来源:system=系统代开(is_system_auto=1),manual=手工(0 或空) */ private function applySourceFilter($query): void { $sf = (string) ($this->params['source_filter'] ?? ''); if ($sf === '' || $sf === 'all') { return; } if ($sf === 'system') { $query->where('is_system_auto', 1); return; } if ($sf === 'manual') { $query->where('is_system_auto', 0); } } private function applyVisibilityScope($query): void { $query->where(function ($query) { // 超级管理员可查看全部 if (!empty($this->adminInfo['root']) && (int) $this->adminInfo['root'] === 1) { return; } // 检查是否属于可查看全部处方的角色 $manageAllRoles = config('project.prescription_library_manage_all_roles', [0, 3]); $roleIds = array_values(array_unique(array_map('intval', $this->adminInfo['role_id'] ?? []))); $canSeeAll = false; foreach ($roleIds as $rid) { if (in_array($rid, $manageAllRoles, true)) { $canSeeAll = true; break; } } // 如果属于可查看全部的角色,不添加任何限制 if ($canSeeAll) { return; } // 其他用户只能查看:共享的、自己创建的、自己是医助的、或指定给自己角色的 $adminId = $this->adminId; $query->where(function ($q) use ($adminId, $roleIds) { $q->whereOr('is_shared', '=', 1); $q->whereOr('creator_id', '=', $adminId); $q->whereOr('assistant_id', '=', $adminId); foreach ($roleIds as $rid) { if ($rid > 0) { $q->whereOrRaw('FIND_IN_SET(?, `visible_role_ids`)', [(string) $rid]); } } }); }); } /** * @notes 获取列表 */ public function lists(): array { $query = Prescription::where($this->searchWhere); $this->applyAuditFilter($query); $this->applySourceFilter($query); $this->applyVisibilityScope($query); $this->applyCreatorIdsFilter($query); $this->applyDataScopeByOwnerColumns($query, ['creator_id', 'assistant_id']); // 全局置顶:有业务订单且处方药材为空白/重复 $candidateIds = (clone $query)->whereNull('delete_time')->column('id'); $riskIds = $this->collectRiskPrescriptionIds(is_array($candidateIds) ? $candidateIds : []); $listQuery = $query->whereNull('delete_time'); if ($riskIds !== []) { $riskIdStr = implode(',', array_map('intval', $riskIds)); $listQuery->orderRaw("CASE WHEN id IN ({$riskIdStr}) THEN 0 ELSE 1 END ASC"); } $lists = $listQuery ->order('id', 'desc') ->limit($this->limitOffset, $this->limitLength) ->select() ->toArray(); $rxIds = array_column($lists, 'id'); $rxIds = array_map('intval', $rxIds); $rejectedRx = []; $bizRejectRemark = []; $hasBizOrderRx = []; if ($rxIds !== []) { $bizRejectRows = PrescriptionOrder::whereIn('prescription_id', $rxIds) ->where('prescription_audit_status', 2) ->whereNull('delete_time') ->where('fulfillment_status', '<>', 4) ->field(['prescription_id', 'prescription_audit_remark', 'id']) ->order('id', 'desc') ->select() ->toArray(); foreach ($bizRejectRows as $br) { $pid = (int) ($br['prescription_id'] ?? 0); if ($pid <= 0) { continue; } $rejectedRx[$pid] = true; if (!isset($bizRejectRemark[$pid])) { $bizRejectRemark[$pid] = (string) ($br['prescription_audit_remark'] ?? ''); } } $orderRxIds = array_unique(array_map( 'intval', PrescriptionOrder::whereIn('prescription_id', $rxIds) ->whereNull('delete_time') ->where('fulfillment_status', '<>', 4) ->column('prescription_id') )); $hasBizOrderRx = array_fill_keys($orderRxIds, true); } // 获取医助姓名 $assistantIds = array_unique(array_filter(array_map('intval', array_column($lists, 'assistant_id')))); $assistantNames = []; if (!empty($assistantIds)) { $assistantNames = \app\common\model\auth\Admin::whereIn('id', $assistantIds) ->column('name', 'id'); } // 处理字段格式 foreach ($lists as &$item) { // 设置默认值 $item['usage_time'] = $item['usage_time'] ?? '饭前'; $item['usage_way'] = $item['usage_way'] ?? '温水送服'; $item['usage_notes'] = $item['usage_notes'] ?? ''; $item['usage_days'] = $item['usage_days'] ?? 7; $item['is_shared'] = $item['is_shared'] ?? 0; $item['is_system_auto'] = (int) ($item['is_system_auto'] ?? 0); $item['audit_status'] = (int) ($item['audit_status'] ?? 1); $item['void_status'] = (int) ($item['void_status'] ?? 0); $item['visible_role_ids'] = PrescriptionLogic::visibleRoleIdsToArray((string) ($item['visible_role_ids'] ?? '')); $rid = (int) ($item['id'] ?? 0); $item['business_prescription_audit_rejected'] = !empty($rejectedRx[$rid]) ? 1 : 0; $item['business_prescription_audit_remark'] = (string) ($bizRejectRemark[$rid] ?? ''); $item['has_prescription_order'] = !empty($hasBizOrderRx[$rid]) ? 1 : 0; // 添加医助姓名 $assistantId = (int) ($item['assistant_id'] ?? 0); $item['assistant_name'] = $assistantId > 0 ? ($assistantNames[$assistantId] ?? '') : ''; // 将 dietary_taboo 从逗号分隔的字符串转换为数组(前端需要数组格式) if (!empty($item['dietary_taboo']) && is_string($item['dietary_taboo'])) { $item['dietary_taboo'] = array_filter(explode(',', $item['dietary_taboo'])); } else { $item['dietary_taboo'] = []; } } return $lists; } /** * @notes 获取数量 */ public function count(): int { $query = Prescription::where($this->searchWhere); $this->applyAuditFilter($query); $this->applySourceFilter($query); $this->applyVisibilityScope($query); $this->applyCreatorIdsFilter($query); $this->applyDataScopeByOwnerColumns($query, ['creator_id', 'assistant_id']); return $query->whereNull('delete_time')->count(); } }