Files
zyt/server/app/adminapi/lists/tcm/PrescriptionOrderLists.php
T
2026-05-18 16:56:00 +08:00

1264 lines
53 KiB
PHP
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\adminapi\logic\dept\DeptLogic;
use app\adminapi\logic\stats\YejiStatsLogic;
use app\adminapi\logic\tcm\PrescriptionOrderLogic;
use app\common\enum\ExportEnum;
use app\common\lists\ListsExcelInterface;
use app\common\lists\ListsExtendInterface;
use app\common\lists\ListsSearchInterface;
use app\common\lists\Traits\HasDataScopeFilter;
use app\common\model\Order;
use app\common\model\tcm\Diagnosis;
use app\common\model\auth\AdminDept;
use app\common\model\tcm\Prescription;
use app\common\model\tcm\PrescriptionOrder;
use app\common\model\tcm\PrescriptionOrderPayOrder;
use app\common\model\ExpressTracking;
use app\common\service\gancao\GancaoScmRecipelService;
use think\facade\Config;
use think\facade\Db;
use think\db\Query;
class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchInterface, ListsExtendInterface, ListsExcelInterface
{
use HasDataScopeFilter;
private const SCENE_DIAGNOSIS_EDIT = 'diagnosis_edit';
public function setSearch(): array
{
return [
'=' => ['prescription_id', 'diagnosis_id', 'fulfillment_status', 'prescription_audit_status', 'payment_slip_audit_status'],
'%like%' => ['order_no'],
'between_time' => 'create_time',
];
}
/**
* 列表/统计条数:含全部搜索条件(含创建时间区间)
*/
private function buildFilteredQuery(): Query
{
$query = PrescriptionOrder::where($this->searchWhere)->whereNull('delete_time');
$this->applyPermissionAndExtraFilters($query);
return $query;
}
/**
* 今日汇总:与列表相同的「非时间」条件(医生/医助/患者/状态/单号等),不含创建时间区间,避免与「今日」语义重复
*
* @return array<int, array{0: string, 1: string, 2: mixed}>
*/
private function searchWhereWithoutCreateTimeRange(): array
{
return array_values(array_filter(
$this->searchWhere,
static function ($w): bool {
if (!\is_array($w) || \count($w) < 2) {
return true;
}
if (($w[0] ?? '') === 'create_time' && ($w[1] ?? '') === 'between') {
return false;
}
return true;
}
));
}
/**
* 重点看板统计:去掉审核/履约状态筛选,保留其它筛选(时间、医生、医助、患者、供货方式等)
*
* @return array<int, array{0: string, 1: string, 2: mixed}>
*/
private function searchWhereWithoutStatusFilters(): array
{
return array_values(array_filter(
$this->searchWhere,
static function ($w): bool {
if (!\is_array($w) || \count($w) < 2) {
return true;
}
$field = (string) ($w[0] ?? '');
if (!in_array($field, ['prescription_audit_status', 'payment_slip_audit_status', 'fulfillment_status'], true)) {
return true;
}
$op = strtolower((string) ($w[1] ?? ''));
return $op !== '=';
}
));
}
private function applyPermissionAndExtraFilters($query): void
{
$this->applyDoctorAssistantFilters($query);
$this->applyPatientKeywordFilter($query);
$this->applyPatientIdFilter($query);
$this->applyExpressCompanyFilter($query);
$this->applyExpressKeywordFilter($query);
$this->applyServiceChannelFilter($query);
$this->applySupplyModeFilter($query);
if (!$this->shouldBypassListVisibilityForDiagnosisEdit()) {
$this->applyCreatorOrOwnPrescriptionVisibility($query);
$this->applyDataScopeForPrescriptionOrder($query);
}
// 业绩看板侧栏等:不展示履约 4/9/10,与 stats 业绩口径一致
if ((int) ($this->params['exclude_fulfillment_cancelled'] ?? 0) === 1) {
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($query, '');
}
$this->applyYejiErCenterRevisitOrderFilter($query);
YejiStatsLogic::applyYejiDrawerChannelFilterToPrescriptionOrderQuery($query, $this->params);
}
/**
* 业绩看板:仅列出二中心复诊口径下的业务订单(须同时传 assistant_id、start_time、end_timerevisit_slot=0 为全部复诊分项合计)。
* admin 维度按订单创建人 o.creator_id(与部门表复诊列、排行榜复诊列同口径)。
*/
private function applyYejiErCenterRevisitOrderFilter($query): void
{
if ((int) ($this->params['yeji_er_center_revisit_only'] ?? 0) !== 1) {
return;
}
$assistantId = (int) ($this->params['assistant_id'] ?? 0);
$slot = (int) ($this->params['yeji_er_center_revisit_slot'] ?? 0);
if ($assistantId <= 0) {
return;
}
$st = trim((string) ($this->params['start_time'] ?? ''));
$et = trim((string) ($this->params['end_time'] ?? ''));
if ($st === '' || $et === '') {
return;
}
$t0 = strtotime($st);
$t1 = strtotime($et);
if ($t0 === false || $t1 === false) {
return;
}
$ids = DeptLogic::listErCenterRevisitOrderIdsForCreator(
$assistantId,
$slot,
(int) $t0,
(int) $t1
);
if ($ids === []) {
$query->whereRaw('0 = 1');
return;
}
$query->whereIn('id', $ids);
}
/**
* 按快递公司筛选(点击快捷标签:顺丰 / 京东)
*
* 说明:主表 express_company 常为 auto/空;快递100 回写承运商在 zyt_express_tracking,需一并匹配。
*/
private function applyExpressCompanyFilter($query): void
{
$company = strtolower(trim((string) ($this->params['express_company'] ?? '')));
if (!in_array($company, ['sf', 'jd'], true)) {
return;
}
$poTbl = (new PrescriptionOrder())->getTable();
$etTbl = (new ExpressTracking())->getTable();
if ($company === 'sf') {
$po = "(LOWER(TRIM(IFNULL(`{$poTbl}`.`express_company`,''))) IN ('sf','shunfeng')"
. " OR `{$poTbl}`.`express_company` LIKE '%顺丰%'"
. " OR (TRIM(IFNULL(`{$poTbl}`.`tracking_number`,'')) <> ''"
. " AND (`{$poTbl}`.`tracking_number` LIKE 'SF%' OR `{$poTbl}`.`tracking_number` LIKE 'sf%')))";
$et = "EXISTS (SELECT 1 FROM `{$etTbl}` et WHERE et.`delete_time` IS NULL"
. " AND et.`order_id` = `{$poTbl}`.`id` AND et.`order_type` = 'prescription'"
. " AND (LOWER(TRIM(IFNULL(et.`express_company`,''))) IN ('sf','shunfeng')"
. " OR et.`express_company_name` LIKE '%顺丰%'"
. " OR (TRIM(IFNULL(et.`tracking_number`,'')) <> ''"
. " AND (et.`tracking_number` LIKE 'SF%' OR et.`tracking_number` LIKE 'sf%'))))";
$query->whereRaw("(($po) OR ($et))");
return;
}
$po = "(LOWER(TRIM(IFNULL(`{$poTbl}`.`express_company`,''))) IN ('jd','jingdong')"
. " OR `{$poTbl}`.`express_company` LIKE '%京东%'"
. " OR (TRIM(IFNULL(`{$poTbl}`.`tracking_number`,'')) <> ''"
. " AND (`{$poTbl}`.`tracking_number` LIKE 'JD%' OR `{$poTbl}`.`tracking_number` LIKE 'jd%'"
. " OR `{$poTbl}`.`tracking_number` LIKE 'JDVB%' OR `{$poTbl}`.`tracking_number` LIKE 'jdvb%')))";
$et = "EXISTS (SELECT 1 FROM `{$etTbl}` et WHERE et.`delete_time` IS NULL"
. " AND et.`order_id` = `{$poTbl}`.`id` AND et.`order_type` = 'prescription'"
. " AND (LOWER(TRIM(IFNULL(et.`express_company`,''))) IN ('jd','jingdong')"
. " OR et.`express_company_name` LIKE '%京东%'"
. " OR (TRIM(IFNULL(et.`tracking_number`,'')) <> ''"
. " AND (et.`tracking_number` LIKE 'JD%' OR et.`tracking_number` LIKE 'jd%'"
. " OR et.`tracking_number` LIKE 'JDVB%' OR et.`tracking_number` LIKE 'jdvb%'))))";
$query->whereRaw("(($po) OR ($et))");
}
/**
* 服务渠道:未指派传 service_channel=0 时命中「空串」或「0」(varchar)
*/
private function applyServiceChannelFilter(Query $query): void
{
$raw = $this->params['service_channel'] ?? '';
if ($raw === '' || $raw === null) {
return;
}
$v = trim((string) $raw);
if ($v === '0') {
$query->whereRaw("(TRIM(IFNULL(`service_channel`,'')) = '' OR `service_channel` = '0')");
return;
}
$query->where('service_channel', '=', $v);
}
/**
* 供货方式:甘草(已上传甘草药方单号)/ 自营(无甘草单号,走药房直发等)
*
* 入参 supply_modegancao | self,空表示不限
*/
private function applySupplyModeFilter($query): void
{
$mode = strtolower(trim((string) ($this->params['supply_mode'] ?? '')));
if ($mode === '') {
return;
}
if ($mode === 'gancao') {
$query->whereRaw("TRIM(IFNULL(`gancao_reciperl_order_no`,'')) <> ''");
return;
}
if ($mode === 'self') {
$query->whereRaw("TRIM(IFNULL(`gancao_reciperl_order_no`,'')) = ''");
return;
}
}
/**
* 非「业务订单全量」角色:默认仅本人创建;若持有 viewOrdersForOwnPrescription 则包含关联处方开方人为本人的订单;
* 另含「关联诊单医助为本人」以便医助跟进出单与履约。
* 显式筛选 assistant_id 时:若该医助落在当前账号数据域内,则允许按「诊单医助 / 订单创建人」命中(与 applyDoctorAssistantFilters 一致)。
*/
private function applyCreatorOrOwnPrescriptionVisibility($query): void
{
if (PrescriptionOrderLogic::canSeeAllPrescriptionOrders($this->adminInfo)) {
return;
}
$adminId = (int) $this->adminId;
$poTbl = (new PrescriptionOrder())->getTable();
$rxTbl = (new Prescription())->getTable();
$diagTbl = (new Diagnosis())->getTable();
$explicitAssistant = (int) ($this->params['assistant_id'] ?? 0);
$allowExplicitAssistantVisibility = false;
if ($explicitAssistant > 0) {
if (!$this->dataScopeShouldApply()) {
$allowExplicitAssistantVisibility = true;
} else {
$visibleIds = $this->getDataScopeVisibleAdminIds();
if ($visibleIds === null || in_array($explicitAssistant, $visibleIds, true)) {
$allowExplicitAssistantVisibility = true;
}
}
}
$query->where(function ($q) use (
$poTbl,
$rxTbl,
$diagTbl,
$adminId,
$explicitAssistant,
$allowExplicitAssistantVisibility
) {
if (PrescriptionOrderLogic::canViewOrdersForOwnPrescription($this->adminInfo)) {
$q->where(function ($qq) use ($poTbl, $rxTbl, $diagTbl, $adminId) {
$qq->where('creator_id', $adminId);
$qq->whereOrRaw(
"EXISTS (SELECT 1 FROM `{$rxTbl}` rx WHERE rx.`id` = `{$poTbl}`.`prescription_id`"
. " AND rx.`delete_time` IS NULL AND rx.`creator_id` = {$adminId})"
);
$qq->whereOrRaw(
"EXISTS (SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id`"
. " AND dg.`delete_time` IS NULL AND dg.`assistant_id` = {$adminId})"
);
});
} else {
$q->where(function ($qq) use ($poTbl, $diagTbl, $adminId) {
$qq->where('creator_id', $adminId);
$qq->whereOrRaw(
"EXISTS (SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id`"
. " AND dg.`delete_time` IS NULL AND dg.`assistant_id` = {$adminId})"
);
});
}
if ($allowExplicitAssistantVisibility) {
$q->whereOr('creator_id', $explicitAssistant);
$q->whereOrRaw(
"EXISTS (SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id`"
. " AND dg.`delete_time` IS NULL AND dg.`assistant_id` = {$explicitAssistant})"
);
}
});
}
/**
* 数据隔离:创建者 ∈ 可见 admin,或 关联诊单医助 ∈ 可见 admin
*/
private function applyDataScopeForPrescriptionOrder($query): void
{
if (!$this->dataScopeShouldApply()) {
return;
}
$ids = $this->getDataScopeVisibleAdminIds();
if ($ids === null) {
return;
}
if ($ids === []) {
$query->whereRaw('0 = 1');
return;
}
$poTbl = (new PrescriptionOrder())->getTable();
$diagTbl = (new Diagnosis())->getTable();
$inList = implode(',', $ids);
$query->where(function ($q) use ($poTbl, $diagTbl, $inList) {
$q->whereIn('creator_id', explode(',', $inList));
$q->whereOrRaw(
"EXISTS (SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id` "
. "AND dg.`delete_time` IS NULL AND dg.`assistant_id` IN ({$inList}))"
);
});
}
/**
* 仅诊单编辑页内的患者订单查询可跳过列表页权限,但必须显式带场景且保留患者/诊单范围收敛。
*/
private function shouldBypassListVisibilityForDiagnosisEdit(): bool
{
$scene = trim((string) ($this->params['scene'] ?? ''));
if ($scene !== self::SCENE_DIAGNOSIS_EDIT) {
return false;
}
$patientId = (int) ($this->params['patient_id'] ?? 0);
$contextDiagnosisId = (int) ($this->params['context_diagnosis_id'] ?? 0);
if ($patientId <= 0 || $contextDiagnosisId <= 0) {
return false;
}
$diagnosisPatientId = (int) Diagnosis::where('id', $contextDiagnosisId)
->whereNull('delete_time')
->value('patient_id');
return $diagnosisPatientId > 0 && $diagnosisPatientId === $patientId;
}
/**
* 医助:仅「诊单医助=本人」的订单计业绩
*/
private function applyAssistantDiagnosisOnlyFilter($query): void
{
$poTbl = (new PrescriptionOrder())->getTable();
$diagTbl = (new Diagnosis())->getTable();
$aid = (int) $this->adminId;
$query->whereExists(
"SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id` AND dg.`delete_time` IS NULL AND dg.`assistant_id` = {$aid}"
);
}
/**
* 统计用查询骨架:不含 create_time 区间;其它筛选项 + 统计专用数据域(不重复 where)
*
* @param bool $applyYejiDrawerChannel 是否应用业绩侧栏渠道收窄(合计业绩统计须传 false)
*/
private function buildBaseQueryForStats(bool $applyYejiDrawerChannel = true): Query
{
$query = PrescriptionOrder::where($this->searchWhereWithoutCreateTimeRange())->whereNull('delete_time');
$this->applyDoctorAssistantFilters($query);
$this->applyPatientKeywordFilter($query);
if (PrescriptionOrderLogic::canViewOrderListStatsAllScope($this->adminInfo)) {
$this->applyDataScopeForPrescriptionOrder($query);
} else {
$assistantRid = (int) Config::get('project.prescription_order_stats_assistant_role_id', 2);
$myRoles = array_map('intval', $this->adminInfo['role_id'] ?? []);
if ($assistantRid > 0 && in_array($assistantRid, $myRoles, true)) {
$this->applyAssistantDiagnosisOnlyFilter($query);
$this->applyDataScopeForPrescriptionOrder($query);
} else {
if (!PrescriptionOrderLogic::canSeeAllPrescriptionOrders($this->adminInfo)) {
$this->applyCreatorOrOwnPrescriptionVisibility($query);
}
$this->applyDataScopeForPrescriptionOrder($query);
}
}
// 与看板「合计业绩」一致:NULL 安全剔除履约 4/9/10
if ((int) ($this->params['exclude_fulfillment_cancelled'] ?? 0) === 1) {
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($query, '');
}
if ($applyYejiDrawerChannel) {
YejiStatsLogic::applyYejiDrawerChannelFilterToPrescriptionOrderQuery($query, $this->params);
}
return $query;
}
/**
* 统计所对应的时间:与入参 start_time / end_time 一致;未传则按自然日「今天」
*
* @return array{0: int, 1: int, 2: string, 3: string}
*/
private function resolveStatsTimeWindow(): array
{
$st = trim((string) ($this->params['start_time'] ?? ''));
$et = trim((string) ($this->params['end_time'] ?? ''));
if ($st !== '' && $et !== '') {
$t0 = strtotime($st);
$t1 = strtotime($et);
if ($t0 !== false && $t1 !== false) {
return [(int) $t0, (int) $t1, $st, $et];
}
}
$t0 = strtotime(date('Y-m-d 00:00:00'));
$t1 = strtotime(date('Y-m-d 23:59:59'));
if ($t0 === false || $t1 === false) {
return [0, 0, '', ''];
}
return [
(int) $t0,
(int) $t1,
date('Y-m-d 00:00:00'),
date('Y-m-d 23:59:59'),
];
}
public function lists(): array
{
$query = $this->buildFilteredQuery();
$lists = $query
->order('id', 'desc')
->limit($this->limitOffset, $this->limitLength)
->select()
->toArray();
$poIds = array_values(array_filter(array_map('intval', array_column($lists, 'id'))));
$paidSumByPo = [];
if ($poIds !== []) {
$links = PrescriptionOrderPayOrder::whereIn('prescription_order_id', $poIds)
->field(['prescription_order_id', 'pay_order_id'])
->select()
->toArray();
$byPo = [];
foreach ($links as $l) {
$poid = (int) ($l['prescription_order_id'] ?? 0);
$oid = (int) ($l['pay_order_id'] ?? 0);
if ($poid > 0 && $oid > 0) {
$byPo[$poid][] = $oid;
}
}
$allOids = [];
foreach ($byPo as $oids) {
$allOids = array_merge($allOids, $oids);
}
$allOids = array_values(array_unique($allOids));
$amountByOid = [];
if ($allOids !== []) {
$amountByOid = Order::whereIn('id', $allOids)->whereNull('delete_time')->column('amount', 'id');
}
foreach ($poIds as $pid) {
$s = 0.0;
foreach ($byPo[$pid] ?? [] as $oid) {
$s += (float) ($amountByOid[$oid] ?? 0);
}
$paidSumByPo[$pid] = round($s, 2);
}
}
// 获取创建人姓名
$creatorIds = array_values(array_unique(array_filter(array_map('intval', array_column($lists, 'creator_id')))));
$creatorNames = [];
if ($creatorIds !== []) {
$creatorNames = \app\common\model\auth\Admin::whereIn('id', $creatorIds)->column('name', 'id');
}
// 获取处方ID对应的开方人姓名
$prescriptionIds = array_values(array_unique(array_filter(array_map('intval', array_column($lists, 'prescription_id')))));
$prescriptionCreators = [];
if ($prescriptionIds !== []) {
$prescriptions = \app\common\model\tcm\Prescription::whereIn('id', $prescriptionIds)
->whereNull('delete_time')
->field(['id', 'creator_id', 'doctor_name', 'phone', 'assistant_id'])
->select()
->toArray();
$doctorIds = [];
foreach ($prescriptions as $rx) {
$rxId = (int) ($rx['id'] ?? 0);
$doctorId = (int) ($rx['creator_id'] ?? 0);
$doctorName = (string) ($rx['doctor_name'] ?? '');
if ($rxId > 0) {
$prescriptionCreators[$rxId] = [
'doctor_id' => $doctorId,
'doctor_name' => $doctorName,
'phone' => (string) ($rx['phone'] ?? ''),
'assistant_id' => (int) ($rx['assistant_id'] ?? 0),
];
if ($doctorId > 0) {
$doctorIds[] = $doctorId;
}
}
}
// 如果 doctor_name 为空,从 Admin 表获取
$doctorIds = array_values(array_unique($doctorIds));
if ($doctorIds !== []) {
$doctorNamesFromAdmin = \app\common\model\auth\Admin::whereIn('id', $doctorIds)->column('name', 'id');
foreach ($prescriptionCreators as &$pc) {
if (empty($pc['doctor_name']) && $pc['doctor_id'] > 0) {
$pc['doctor_name'] = $doctorNamesFromAdmin[$pc['doctor_id']] ?? '';
}
}
unset($pc);
}
}
$depMin = PrescriptionOrderLogic::depositMinAmount();
$diagIdsForAssist = array_values(array_unique(array_filter(array_map('intval', array_column($lists, 'diagnosis_id')))));
$assistantByDiag = [];
if ($diagIdsForAssist !== []) {
$assistantByDiag = Diagnosis::whereIn('id', $diagIdsForAssist)->whereNull('delete_time')->column('assistant_id', 'id');
}
$assistantIds = [];
foreach (array_values($assistantByDiag) as $v) {
$vid = (int) $v;
if ($vid > 0) {
$assistantIds[] = $vid;
}
}
foreach ($prescriptionCreators as $pc) {
$aid = (int) ($pc['assistant_id'] ?? 0);
if ($aid > 0) {
$assistantIds[] = $aid;
}
}
$assistantIds = array_values(array_unique($assistantIds));
$assistantNames = $assistantIds !== []
? \app\common\model\auth\Admin::whereIn('id', $assistantIds)->column('name', 'id')
: [];
foreach ($lists as &$item) {
PrescriptionOrderLogic::maskInternalCostIfNeeded($item, $this->adminInfo);
PrescriptionOrderLogic::maskRemarkExtraIfNeeded($item, $this->adminInfo);
$pid = (int) ($item['id'] ?? 0);
$item['linked_pay_order_count'] = (int) PrescriptionOrderPayOrder::where(
'prescription_order_id',
$pid
)->count();
$item['linked_pay_paid_total'] = $paidSumByPo[$pid] ?? 0.0;
$item['deposit_min_amount'] = $depMin;
$item['can_upload_gancao_reciperl'] = PrescriptionOrderLogic::canUploadGancaoRecipel(
$item,
$this->adminId,
$this->adminInfo,
$assistantByDiag
);
// 添加创建人姓名
$creatorId = (int) ($item['creator_id'] ?? 0);
$item['creator_name'] = $creatorId > 0 ? ($creatorNames[$creatorId] ?? '') : '';
// 医助:与处方列表一致优先关联处方 assistant_id,否则诊单 assistant_id(见 PrescriptionOrderLogic::resolveAssistantAdminIdForPrescriptionOrderRow
$diagIdForAssist = (int) ($item['diagnosis_id'] ?? 0);
$diagAst = (int) ($assistantByDiag[$diagIdForAssist] ?? 0);
$rxId = (int) ($item['prescription_id'] ?? 0);
$rxAst = $rxId > 0 ? (int) (($prescriptionCreators[$rxId] ?? [])['assistant_id'] ?? 0) : 0;
$assistantIdForItem = PrescriptionOrderLogic::resolveAssistantAdminIdForPrescriptionOrderRow($rxAst, $diagAst);
$item['assistant_id'] = $assistantIdForItem;
$item['assistant_name'] = $assistantIdForItem > 0
? ($assistantNames[$assistantIdForItem] ?? '')
: '';
// 添加开方人姓名、处方登记手机(与业务订单收货手机比对用)
$item['doctor_name'] = $rxId > 0 ? ($prescriptionCreators[$rxId]['doctor_name'] ?? '') : '';
$item['prescription_phone'] = $rxId > 0 ? ($prescriptionCreators[$rxId]['phone'] ?? '') : '';
}
unset($item);
$this->appendPrescriptionOrderAssignSnapshotErCenterFlags($lists);
if ((int) ($this->params['yeji_order_drawer'] ?? 0) === 1) {
PrescriptionOrderLogic::appendLinkedAppointmentsToListRows($lists, $this->params);
}
if ((int) $this->export === ExportEnum::EXPORT) {
PrescriptionOrderLogic::appendPrescriptionOrderListExportRows($lists, $this->adminInfo, $this->params);
}
return $lists;
}
public function extend(): array
{
$s = $this->computeListStatsForExtend();
$focus = $this->computeFocusCountsForExtend();
$base = [
'deposit_min_amount' => PrescriptionOrderLogic::depositMinAmount(),
'gancao_scm_enabled' => GancaoScmRecipelService::isConfigured(),
'stats_order_amount' => $s['order_amount'],
'stats_order_amount_not_cancelled' => $s['order_amount_not_cancelled'],
'stats_order_amount_cancelled' => $s['order_amount_cancelled'],
/** 业绩:业务订单金额,剔除履约已取消/拒收/退款(4/9/10),NULL 与其它状态计入 */
'stats_order_amount_performance' => $s['order_amount_performance'] ?? $s['order_amount_not_cancelled'],
'stats_linked_pay_amount' => $s['linked_pay_amount'],
'stats_linked_pay_amount_not_cancelled' => $s['linked_pay_amount_not_cancelled'],
'stats_linked_pay_amount_cancelled' => $s['linked_pay_amount_cancelled'],
/** 业绩-关联实付:剔除履约 4/9/10 订单的关联支付金额 */
'stats_linked_pay_amount_performance' => $s['linked_pay_amount_performance'] ?? $s['linked_pay_amount_not_cancelled'],
'stats_time_start' => $s['label_start'],
'stats_time_end' => $s['label_end'],
/** 统计口径:all=支付审核白名单全量;assistant=医助仅诊单协助业绩;restricted=与列表同域 */
'stats_scope' => $s['scope'],
'focus_pending_rx_count' => $focus['pending_rx'],
'focus_pending_pay_count' => $focus['pending_pay'],
'focus_pending_ship_count' => $focus['pending_ship'],
'focus_risk_count' => $focus['risk'],
];
$yejiConsult = $this->computeYejiDrawerConsultCountIfRequested();
if ($yejiConsult !== null) {
$base['stats_yeji_consult_count'] = $yejiConsult;
}
$yejiDrawerTotal = $this->computeYejiDrawerPerformanceTotalForExtend();
if ($yejiDrawerTotal !== null) {
$base['stats_yeji_drawer_total_performance_amount'] = $yejiDrawerTotal['amount'];
$base['stats_yeji_drawer_total_performance_order_count'] = $yejiDrawerTotal['order_count'];
}
return $base;
}
public function setFileName(): string
{
return '处方业务订单';
}
public function setExcelFields(): array
{
return [
'export_fulfillment_status_text' => '履约状态',
'export_order_time' => '创建时间',
'doctor_name' => '医生姓名',
'export_patient_name' => '患者姓名',
'export_patient_gender' => '性别',
'export_patient_age' => '年龄',
'export_patient_phone' => '手机号',
'assistant_name' => '医助名字',
'export_center_label' => '一中心还是二中心',
'export_assistant_dept' => '医助部门',
'export_channel' => '渠道',
'export_guahao_channel_source' => '自媒体渠道(挂号渠道来源)',
'export_medication_form' => '药品形态',
'export_medication_days' => '天数',
'export_amount' => '总金额',
'export_paid_amount' => '已付金额',
'export_agency_collect' => '代收金额',
'export_tracking_number' => '快递单号',
'export_supply_mode' => '甘草还是自营',
'export_gancao_prescription_cost' => '处方成本',
'export_first_visit_assistant' => '初诊医助',
'export_rx_audit_time' => '审核时间',
'export_rx_auditor' => '审核人',
];
}
/**
* 业绩看板侧栏专用:约诊/接诊条数,与 YejiStatsLogic::applyConsultFiltersAlignedWithAppointmentLists 同口径
* doctor_appointment.status=3appointment_date 落入区间,有效医助 COALESCE(挂号.assistant_id,诊单.assistant_id))。
* 请求须带 yeji_order_drawer=1,且 assistant_id 或 assistant_dept_id 与起止时间有效。
*/
private function computeYejiDrawerConsultCountIfRequested(): ?int
{
if ((int) ($this->params['yeji_order_drawer'] ?? 0) !== 1) {
return null;
}
$assistantId = (int) ($this->params['assistant_id'] ?? 0);
$deptRootId = (int) ($this->params['assistant_dept_id'] ?? 0);
if ($assistantId <= 0 && $deptRootId <= 0) {
return null;
}
[$startDate, $endDate] = $this->resolveYejiConsultAppointmentDateRange();
if ($startDate === '' || $endDate === '') {
return null;
}
$eff = 'COALESCE(NULLIF(a.assistant_id, 0), NULLIF(u.assistant_id, 0))';
$query = Db::name('doctor_appointment')->alias('a')
->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id')
->where('a.status', 3)
->whereBetween('a.appointment_date', [$startDate, $endDate])
->whereRaw('(u.id IS NULL OR u.delete_time IS NULL)');
if ($assistantId > 0) {
$query->whereRaw("({$eff}) = " . $assistantId);
} else {
$deptIds = DeptLogic::getSelfAndDescendantIds($deptRootId);
$deptIds = array_values(array_filter(array_map('intval', $deptIds), static function (int $id): bool {
return $id > 0;
}));
if ($deptIds === []) {
return 0;
}
$adTbl = (new AdminDept())->getTable();
$inList = implode(',', $deptIds);
$query->whereRaw(
"EXISTS (SELECT 1 FROM `{$adTbl}` ad WHERE ad.admin_id = {$eff} AND ad.dept_id IN ({$inList}))"
);
}
return (int) $query->count();
}
/**
* @return array{0: string, 1: string} Y-m-d
*/
private function resolveYejiConsultAppointmentDateRange(): array
{
$st = trim((string) ($this->params['start_time'] ?? ''));
$et = trim((string) ($this->params['end_time'] ?? ''));
if ($st === '' || $et === '') {
return ['', ''];
}
$t0 = strtotime($st);
$t1 = strtotime($et);
if ($t0 === false || $t1 === false) {
return ['', ''];
}
if ($t1 < $t0) {
$tmp = $t0;
$t0 = $t1;
$t1 = $tmp;
}
return [date('Y-m-d', $t0), date('Y-m-d', $t1)];
}
/**
* 侧栏已选渠道时:「合计业绩」金额与订单数(与看板列同口径,不限渠道收窄)
*
* @return array{amount: float, order_count: int}|null
*/
private function computeYejiDrawerPerformanceTotalForExtend(): ?array
{
if ((int) ($this->params['yeji_order_drawer'] ?? 0) !== 1) {
return null;
}
if (trim((string) ($this->params['channel_code'] ?? '')) === '') {
return null;
}
[$t0, $t1] = $this->resolveStatsTimeWindow();
if ($t0 <= 0 || $t1 <= 0) {
return null;
}
if ($t1 < $t0) {
$tmp = $t0;
$t0 = $t1;
$t1 = $tmp;
}
$q = $this->buildBaseQueryForStats(false)->whereBetween('create_time', [$t0, $t1]);
// 全量「合计业绩」与看板列同口径:始终剔除履约 4/9/10,不依赖 exclude 参数
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($q, '');
$amount = round((float) (clone $q)->sum('amount'), 2);
$count = (int) (clone $q)->count();
return ['amount' => $amount, 'order_count' => $count];
}
/**
* 重点看板计数(基于“当前筛选(去除审核/履约状态)”后的全量命中)
*
* @return array{pending_rx:int,pending_pay:int,pending_ship:int,risk:int}
*/
private function computeFocusCountsForExtend(): array
{
$query = PrescriptionOrder::where($this->searchWhereWithoutStatusFilters())->whereNull('delete_time');
$this->applyPermissionAndExtraFilters($query);
$pendingRxQuery = clone $query;
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($pendingRxQuery, '');
return [
// 处方审核待处理(不含履约 4/9/10)
'pending_rx' => (int) $pendingRxQuery->where('prescription_audit_status', 0)->count(),
// 支付审核待处理(前提:处方已通过)
'pending_pay' => (int) (clone $query)->where('prescription_audit_status', 1)->where('payment_slip_audit_status', 0)->count(),
// 履约待发货
'pending_ship' => (int) (clone $query)->where('fulfillment_status', 2)->count(),
// 重点异常:支付审核驳回(与前端「重点异常」快捷筛选口径一致)
'risk' => (int) (clone $query)->where('payment_slip_audit_status', 2)->count(),
];
}
/**
* 关联实付按业务订单 id 列表汇总
*
* @param array<int> $poIds
*/
private function sumLinkedPayForPrescriptionOrderIds(array $poIds): float
{
if ($poIds === []) {
return 0.0;
}
$sum = (float) PrescriptionOrderPayOrder::alias('l')
->join('order o', 'l.pay_order_id = o.id')
->whereIn('l.prescription_order_id', $poIds)
->whereNull('o.delete_time')
->sum('o.amount');
return round($sum, 2);
}
/**
* @return array{order_amount: float, order_amount_not_cancelled: float, order_amount_cancelled: float, linked_pay_amount: float, linked_pay_amount_not_cancelled: float, linked_pay_amount_cancelled: float, label_start: string, label_end: string, scope: string}
*/
private function computeListStatsForExtend(): array
{
[$t0, $t1, $l0, $l1] = $this->resolveStatsTimeWindow();
if ($t0 <= 0 || $t1 <= 0) {
return $this->statsZeroPayload();
}
if ($t1 < $t0) {
$tmp = $t0;
$t0 = $t1;
$t1 = $tmp;
}
$q = $this->buildBaseQueryForStats()->whereBetween('create_time', [$t0, $t1]);
$orderTotal = round((float) (clone $q)->sum('amount'), 2);
$orderCancelled = round((float) (clone $q)->where('fulfillment_status', 4)->sum('amount'), 2);
$orderNotCancelled = round($orderTotal - $orderCancelled, 2);
$idsAll = (clone $q)->column('id');
$idsAll = array_values(array_filter(array_map('intval', $idsAll), static function (int $id): bool {
return $id > 0;
}));
if ($idsAll === []) {
$empty = $this->statsExtendPayload(
$orderTotal,
$orderNotCancelled,
$orderCancelled,
0.0,
0.0,
0.0,
$l0,
$l1
);
$qPerfEmpty = clone $q;
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($qPerfEmpty, '');
$empty['order_amount_performance'] = round((float) $qPerfEmpty->sum('amount'), 2);
$empty['linked_pay_amount_performance'] = 0.0;
return $empty;
}
$idsCancel = (clone $q)->where('fulfillment_status', 4)->column('id');
$idsCancel = array_values(array_filter(array_map('intval', $idsCancel), static function (int $id): bool {
return $id > 0;
}));
$idsNotCancelled = array_values(array_diff($idsAll, $idsCancel));
$linkedTotal = $this->sumLinkedPayForPrescriptionOrderIds($idsAll);
$linkedNotCancelled = $this->sumLinkedPayForPrescriptionOrderIds($idsNotCancelled);
$linkedCancelled = $this->sumLinkedPayForPrescriptionOrderIds($idsCancel);
$base = $this->statsExtendPayload(
$orderTotal,
$orderNotCancelled,
$orderCancelled,
$linkedTotal,
$linkedNotCancelled,
$linkedCancelled,
$l0,
$l1
);
$qPerf = clone $q;
YejiStatsLogic::applyPrescriptionOrderNotCancelledForPerformanceQuery($qPerf, '');
$base['order_amount_performance'] = round((float) $qPerf->sum('amount'), 2);
$idsExcludedPerf = (clone $q)
->whereIn('fulfillment_status', YejiStatsLogic::PRESCRIPTION_ORDER_FULFILLMENT_EXCLUDED_FROM_PERFORMANCE)
->column('id');
$idsExcludedPerf = array_values(array_filter(array_map('intval', $idsExcludedPerf), static function (int $id): bool {
return $id > 0;
}));
$idsPerf = array_values(array_diff($idsAll, $idsExcludedPerf));
$base['linked_pay_amount_performance'] = $this->sumLinkedPayForPrescriptionOrderIds($idsPerf);
return $base;
}
/**
* @return array{order_amount: float, order_amount_not_cancelled: float, order_amount_cancelled: float, linked_pay_amount: float, linked_pay_amount_not_cancelled: float, linked_pay_amount_cancelled: float, label_start: string, label_end: string, scope: string}
*/
private function statsZeroPayload(): array
{
$z = $this->statsExtendPayload(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, '', '');
$z['order_amount_performance'] = 0.0;
$z['linked_pay_amount_performance'] = 0.0;
return $z;
}
/**
* @return array{order_amount: float, order_amount_not_cancelled: float, order_amount_cancelled: float, linked_pay_amount: float, linked_pay_amount_not_cancelled: float, linked_pay_amount_cancelled: float, label_start: string, label_end: string, scope: string}
*/
private function statsExtendPayload(
float $orderTotal,
float $orderNotCancelled,
float $orderCancelled,
float $linkedTotal,
float $linkedNotCancelled,
float $linkedCancelled,
string $l0,
string $l1
): array {
$scope = 'restricted';
if (PrescriptionOrderLogic::canViewOrderListStatsAllScope($this->adminInfo)) {
$scope = 'all';
} else {
$ar = (int) Config::get('project.prescription_order_stats_assistant_role_id', 2);
if ($ar > 0 && in_array($ar, array_map('intval', $this->adminInfo['role_id'] ?? []), true)) {
$scope = 'assistant';
} elseif (PrescriptionOrderLogic::canViewOrdersForOwnPrescription($this->adminInfo)) {
$scope = 'own_rx';
}
}
return [
'order_amount' => $orderTotal,
'order_amount_not_cancelled' => $orderNotCancelled,
'order_amount_cancelled' => $orderCancelled,
'linked_pay_amount' => $linkedTotal,
'linked_pay_amount_not_cancelled' => $linkedNotCancelled,
'linked_pay_amount_cancelled' => $linkedCancelled,
'label_start' => $l0,
'label_end' => $l1,
'scope' => $scope,
];
}
public function count(): int
{
$query = $this->buildFilteredQuery();
return (int) $query->count();
}
/**
* 按开方医生(关联处方 creator_id)/ 诊单医助筛选
*
* 医助:诊单 assistant_id 与业务订单 creator_id 并举——医助常代建单但诊单未写 assistant_id。
*/
private function applyDoctorAssistantFilters($query): void
{
$poTbl = (new PrescriptionOrder())->getTable();
if (isset($this->params['doctor_id']) && (int) $this->params['doctor_id'] > 0) {
$doctorId = (int) $this->params['doctor_id'];
$rxTbl = (new Prescription())->getTable();
$query->whereExists("SELECT 1 FROM {$rxTbl} rx WHERE rx.id = {$poTbl}.prescription_id AND rx.delete_time IS NULL AND rx.creator_id = {$doctorId}");
}
/** 业绩看板入口(yeji_order_drawer=1)所有筛选统一按订单创建人;其它入口(处方订单列表 / 患者跟进等)保留旧口径(创建人 ∪ 诊单医助) */
$yejiPanel = (int) ($this->params['yeji_order_drawer'] ?? 0) === 1;
if (isset($this->params['assistant_id']) && (int) $this->params['assistant_id'] > 0) {
$assistantId = (int) $this->params['assistant_id'];
if ($yejiPanel) {
$query->where('creator_id', $assistantId);
} else {
$diagTbl = (new Diagnosis())->getTable();
$query->where(function ($q) use ($poTbl, $diagTbl, $assistantId) {
$q->where('creator_id', $assistantId);
$q->whereOrRaw(
"EXISTS (SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id`"
. " AND dg.`delete_time` IS NULL AND dg.`assistant_id` = {$assistantId})"
);
});
}
}
if (isset($this->params['assistant_dept_id']) && $this->params['assistant_dept_id'] !== '' && (int) $this->params['assistant_dept_id'] > 0) {
if ((int) ($this->params['yeji_drawer_match_table_performance'] ?? 0) === 1) {
$rowDeptId = (int) $this->params['assistant_dept_id'];
$adminIds = YejiStatsLogic::collectAdminIdsAttributedToYejiTableRow(
$rowDeptId,
$this->params['dept_ids'] ?? null
);
if ($adminIds === []) {
$query->whereRaw('0 = 1');
return;
}
$this->applyPerformanceAttributionAdminInFilter($query, $adminIds);
return;
}
$yejiTableRowDeptIds = [];
if (isset($this->params['yeji_table_row_dept_ids']) && trim((string) $this->params['yeji_table_row_dept_ids']) !== '') {
foreach (explode(',', (string) $this->params['yeji_table_row_dept_ids']) as $p) {
$v = (int) trim((string) $p);
if ($v > 0) {
$yejiTableRowDeptIds[] = $v;
}
}
}
if ((int) ($this->params['yeji_order_drawer'] ?? 0) === 1 && $yejiTableRowDeptIds !== []) {
YejiStatsLogic::applyPrescriptionOrderListAlignedWinnerDeptFilter(
$query,
(int) $this->params['assistant_dept_id'],
$yejiTableRowDeptIds,
$this->params['dept_ids'] ?? null
);
return;
}
$rootDeptId = (int) $this->params['assistant_dept_id'];
$deptIds = DeptLogic::getSelfAndDescendantIds($rootDeptId);
$deptIds = array_values(array_filter(array_map('intval', $deptIds), static function (int $id): bool {
return $id > 0;
}));
if ($deptIds === []) {
$query->whereRaw('0 = 1');
return;
}
$inList = implode(',', $deptIds);
$adTbl = (new AdminDept())->getTable();
if ($yejiPanel) {
/** 业绩看板部门侧栏:仅订单创建人人事部门 ∈ 子树(与「合计业绩」/「接诊诊单」/「复诊」聚合同口径) */
$query->whereExists(
"SELECT 1 FROM `{$adTbl}` adc WHERE adc.`admin_id` = `{$poTbl}`.`creator_id` AND adc.`dept_id` IN ({$inList})"
);
} else {
$diagTbl = (new Diagnosis())->getTable();
$query->where(function ($q) use ($poTbl, $diagTbl, $adTbl, $inList) {
$q->whereExists(
"SELECT 1 FROM `{$adTbl}` ad INNER JOIN `{$diagTbl}` dg ON ad.admin_id = dg.assistant_id AND dg.delete_time IS NULL "
. "WHERE dg.`id` = `{$poTbl}`.`diagnosis_id` AND ad.dept_id IN ({$inList})"
);
$q->whereExists(
"SELECT 1 FROM `{$adTbl}` adc WHERE adc.`admin_id` = `{$poTbl}`.`creator_id` AND adc.`dept_id` IN ({$inList})",
'OR'
);
});
}
}
}
/**
* 业绩看板侧栏:只保留「业绩归属医助」落在给定 admin_id 集合的订单
* (与 YejiStatsLogic::sqlPerformanceAttributionAdminExpr 一致——按订单创建人)。
*
* @param int[] $adminIds
*/
private function applyPerformanceAttributionAdminInFilter($query, array $adminIds): void
{
$adminIds = array_values(array_unique(array_filter(array_map('intval', $adminIds), static function (int $x): bool {
return $x > 0;
})));
if ($adminIds === []) {
$query->whereRaw('0 = 1');
return;
}
$query->whereIn('creator_id', $adminIds);
}
/**
* 按诊单患者姓名 / 手机号模糊检索(关联 diagnosis_id
*/
private function applyPatientKeywordFilter($query): void
{
$kw = trim((string) ($this->params['patient_keyword'] ?? ''));
if ($kw === '') {
return;
}
$poTbl = (new PrescriptionOrder())->getTable();
$diagTbl = (new Diagnosis())->getTable();
$likeInner = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $kw);
$like = '%' . $likeInner . '%';
$likeSql = str_replace("'", "''", $like);
$query->whereExists(
"SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id` AND dg.`delete_time` IS NULL "
. "AND (dg.`patient_name` LIKE '{$likeSql}' OR dg.`phone` LIKE '{$likeSql}')"
);
}
/**
* 按真实患者ID精确过滤(tcm_diagnosis.patient_id 是跨诊单的患者唯一ID
* 用于诊单编辑抽屉「业务订单」tab 列出该患者所有诊单产生的处方业务订单。
*/
private function applyPatientIdFilter($query): void
{
$patientId = (int) ($this->params['patient_id'] ?? 0);
if ($patientId <= 0) {
return;
}
$poTbl = (new PrescriptionOrder())->getTable();
$diagTbl = (new Diagnosis())->getTable();
$query->whereExists(
"SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id` "
. "AND dg.`delete_time` IS NULL AND dg.`patient_id` = {$patientId}"
);
}
/**
* 按快递单号 / 快递公司 模糊检索
*/
private function applyExpressKeywordFilter($query): void
{
$kw = trim((string) ($this->params['express_keyword'] ?? ''));
if ($kw === '') {
return;
}
$likeInner = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $kw);
$like = '%' . $likeInner . '%';
$likeSql = str_replace("'", "''", $like);
$poTbl = (new PrescriptionOrder())->getTable();
$etTbl = (new ExpressTracking())->getTable();
$query->whereRaw(
"(IFNULL(`{$poTbl}`.`tracking_number`,'') LIKE '{$likeSql}'"
. " OR IFNULL(`{$poTbl}`.`express_company`,'') LIKE '{$likeSql}'"
. " OR EXISTS (SELECT 1 FROM `{$etTbl}` et WHERE et.`delete_time` IS NULL"
. " AND et.`order_id` = `{$poTbl}`.`id` AND et.`order_type` = 'prescription'"
. " AND (IFNULL(et.`tracking_number`,'') LIKE '{$likeSql}'"
. " OR IFNULL(et.`express_company`,'') LIKE '{$likeSql}'"
. " OR IFNULL(et.`express_company_name`,'') LIKE '{$likeSql}'))"
. ")"
);
}
/**
* 列表行标注:指派日志快照(related_po_creator_id + related_po_create_time)是否指向本业务单,
* 以及该次操作的新医助(to_assistant_id)是否归属「二中心」部门子树(与 DeptLogic / 业绩看板一致)。
*
* @param array<int, array<string, mixed>> $lists
*/
private function appendPrescriptionOrderAssignSnapshotErCenterFlags(array &$lists): void
{
if ($lists === []) {
return;
}
$diagIds = [];
foreach ($lists as $row) {
$d = (int) ($row['diagnosis_id'] ?? 0);
if ($d > 0) {
$diagIds[$d] = true;
}
}
$diagIdList = array_keys($diagIds);
$latestSnapLogByTriple = [];
if ($diagIdList !== []) {
$logRows = Db::name('tcm_diagnosis_assign_log')
->whereIn('diagnosis_id', $diagIdList)
->field(['id', 'diagnosis_id', 'to_assistant_id', 'related_po_creator_id', 'related_po_create_time'])
->order('id', 'desc')
->select()
->toArray();
foreach ($logRows as $log) {
$d = (int) ($log['diagnosis_id'] ?? 0);
$rcp = (int) ($log['related_po_creator_id'] ?? 0);
$rpct = (int) ($log['related_po_create_time'] ?? 0);
if ($d <= 0 || $rcp <= 0 || $rpct <= 0) {
continue;
}
$tripleKey = $d . ':' . $rcp . ':' . $rpct;
if (!isset($latestSnapLogByTriple[$tripleKey])) {
$latestSnapLogByTriple[$tripleKey] = $log;
}
}
}
$toAssistantIdsHit = [];
foreach ($lists as $item) {
$diagId = (int) ($item['diagnosis_id'] ?? 0);
$creatorId = (int) ($item['creator_id'] ?? 0);
$poCt = (int) ($item['create_time'] ?? 0);
$tripleKey = $diagId . ':' . $creatorId . ':' . $poCt;
$log = $latestSnapLogByTriple[$tripleKey] ?? null;
if (\is_array($log)) {
$tid = (int) ($log['to_assistant_id'] ?? 0);
if ($tid > 0) {
$toAssistantIdsHit[$tid] = true;
}
}
}
$toAssistantIdList = array_keys($toAssistantIdsHit);
$erDeptSet = DeptLogic::getErCenterSubtreeDeptIdSet();
$adminErCenter = [];
if ($toAssistantIdList !== [] && $erDeptSet !== []) {
$adRows = AdminDept::whereIn('admin_id', $toAssistantIdList)
->field(['admin_id', 'dept_id'])
->select()
->toArray();
foreach ($adRows as $ad) {
$aid = (int) ($ad['admin_id'] ?? 0);
$did = (int) ($ad['dept_id'] ?? 0);
if ($aid > 0 && $did > 0 && isset($erDeptSet[$did])) {
$adminErCenter[$aid] = true;
}
}
}
$nameMap = [];
if ($toAssistantIdList !== []) {
$nameMap = \app\common\model\auth\Admin::whereIn('id', $toAssistantIdList)->column('name', 'id');
}
foreach ($lists as &$item) {
$diagId = (int) ($item['diagnosis_id'] ?? 0);
$creatorId = (int) ($item['creator_id'] ?? 0);
$poCt = (int) ($item['create_time'] ?? 0);
$item['po_assign_snapshot_hit'] = 0;
$item['po_assign_to_assistant_id'] = 0;
$item['po_assign_to_assistant_name'] = '';
$item['po_assign_to_er_center'] = 0;
$item['po_assign_is_release'] = 0;
if ($diagId <= 0 || $creatorId <= 0 || $poCt <= 0) {
continue;
}
$tripleKey = $diagId . ':' . $creatorId . ':' . $poCt;
$log = $latestSnapLogByTriple[$tripleKey] ?? null;
if (!\is_array($log)) {
continue;
}
$item['po_assign_snapshot_hit'] = 1;
$toId = (int) ($log['to_assistant_id'] ?? 0);
$item['po_assign_to_assistant_id'] = $toId;
if ($toId <= 0) {
$item['po_assign_is_release'] = 1;
continue;
}
$item['po_assign_to_assistant_name'] = (string) ($nameMap[$toId] ?? '');
$item['po_assign_to_er_center'] = isset($adminErCenter[$toId]) ? 1 : 0;
}
unset($item);
}
}