344 lines
12 KiB
PHP
344 lines
12 KiB
PHP
<?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_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();
|
||
}
|
||
}
|