Files
zyt/server/app/adminapi/lists/tcm/PrescriptionLists.php
T
2026-05-11 17:49:38 +08:00

344 lines
12 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace app\adminapi\lists\tcm;
use app\adminapi\lists\BaseAdminDataLists;
use app\common\lists\ListsSearchInterface;
use app\common\lists\Traits\HasDataScopeFilter;
use app\adminapi\logic\tcm\PrescriptionLogic;
use app\common\model\tcm\Prescription;
use app\common\model\tcm\PrescriptionOrder;
/**
* 处方列表
*/
class PrescriptionLists extends BaseAdminDataLists implements ListsSearchInterface
{
use HasDataScopeFilter;
/**
* 识别「有业务订单且处方药材为空白/重复」的处方 ID(用于全局置顶排序)
*
* @param array<int,int|string> $candidateIds
* @return array<int,int>
*/
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_filterpassed=已通过,not_passed=未通过(待审+驳回),pendingrejected
*/
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();
}
}