231 lines
7.1 KiB
PHP
231 lines
7.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace app\adminapi\logic\stats;
|
|
|
|
use app\adminapi\logic\dept\DeptLogic;
|
|
use app\common\service\tcm\RevisitVisitSlotService;
|
|
use think\facade\Db;
|
|
|
|
/** 新报表独立读取方法,保持原复诊率 Logic 源码及调用链不变。 */
|
|
trait RevisitCohortDataSource
|
|
{
|
|
private static function fetchRollbackKeySet(int $startTs, int $endTs): array
|
|
{
|
|
$rows = Db::name('tcm_diagnosis_auto_assign_log')
|
|
->where('rollback_time', '>=', $startTs)
|
|
->where('rollback_time', '<=', $endTs)
|
|
->where('diagnosis_id', '>', 0)
|
|
->field(['diagnosis_id', 'rollback_time', 'rollback_admin_id'])
|
|
->select()
|
|
->toArray();
|
|
$out = [];
|
|
foreach ($rows as $r) {
|
|
$out[RevisitRateCalculator::rollbackKey(
|
|
(int) ($r['diagnosis_id'] ?? 0),
|
|
(int) ($r['rollback_time'] ?? 0),
|
|
(int) ($r['rollback_admin_id'] ?? 0)
|
|
)] = true;
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
private static function iterateOrderSeqRows(array $diagIds, array $fields): \Generator
|
|
{
|
|
foreach (array_chunk($diagIds, 2000) as $chunk) {
|
|
foreach (self::fetchOrderSeqRows($chunk, $fields) as $r) {
|
|
yield $r;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static function buildAssistantDeptIndex(array $adminIds): array
|
|
{
|
|
if ($adminIds === []) {
|
|
return [[], []];
|
|
}
|
|
// admin_dept 为 (admin_id, dept_id) 联合主键、无自增 id;取最小 dept_id 作为归属部门保证确定性
|
|
$relRows = Db::name('admin_dept')
|
|
->whereIn('admin_id', $adminIds)
|
|
->order(['admin_id' => 'asc', 'dept_id' => 'asc'])
|
|
->field(['admin_id', 'dept_id'])
|
|
->select()
|
|
->toArray();
|
|
|
|
$deptNames = Db::name('dept')
|
|
->whereNull('delete_time')
|
|
->column('name', 'id');
|
|
|
|
$canonical = [];
|
|
foreach ($relRows as $r) {
|
|
$aid = (int) ($r['admin_id'] ?? 0);
|
|
$deptId = (int) ($r['dept_id'] ?? 0);
|
|
if ($aid <= 0 || $deptId <= 0 || isset($canonical[$aid])) {
|
|
continue;
|
|
}
|
|
if (!isset($deptNames[$deptId])) {
|
|
continue;
|
|
}
|
|
$canonical[$aid] = $deptId;
|
|
}
|
|
|
|
$names = [];
|
|
foreach ($deptNames as $id => $name) {
|
|
$names[(int) $id] = (string) $name;
|
|
}
|
|
|
|
return [$canonical, $names];
|
|
}
|
|
|
|
private static function resolveDeptFilterSet(mixed $raw): array
|
|
{
|
|
$erSet = DeptLogic::getErCenterSubtreeDeptIdSet();
|
|
if ($erSet === []) {
|
|
return [];
|
|
}
|
|
$deptFilterIds = self::parseDeptIds($raw);
|
|
if ($deptFilterIds === []) {
|
|
return $erSet;
|
|
}
|
|
$allowedRoots = [];
|
|
foreach ($deptFilterIds as $id) {
|
|
if (isset($erSet[$id])) {
|
|
$allowedRoots[] = $id;
|
|
}
|
|
}
|
|
if ($allowedRoots === []) {
|
|
return [];
|
|
}
|
|
$expanded = self::expandDeptSubtreeSet($allowedRoots);
|
|
$out = [];
|
|
foreach ($expanded as $id => $_) {
|
|
if (isset($erSet[$id])) {
|
|
$out[$id] = true;
|
|
}
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
private static function parseDeptIds(mixed $raw): array
|
|
{
|
|
if ($raw === null || $raw === '' || $raw === []) {
|
|
return [];
|
|
}
|
|
$list = \is_array($raw) ? $raw : explode(',', (string) $raw);
|
|
|
|
return array_values(array_unique(array_filter(
|
|
array_map('intval', $list),
|
|
static fn (int $v): bool => $v > 0
|
|
)));
|
|
}
|
|
|
|
private static function expandDeptSubtreeSet(array $deptIds): array
|
|
{
|
|
$rows = Db::name('dept')
|
|
->whereNull('delete_time')
|
|
->field(['id', 'pid'])
|
|
->select()
|
|
->toArray();
|
|
$childrenByPid = [];
|
|
foreach ($rows as $r) {
|
|
$childrenByPid[(int) $r['pid']][] = (int) $r['id'];
|
|
}
|
|
|
|
$set = [];
|
|
$queue = $deptIds;
|
|
while ($queue !== []) {
|
|
$id = (int) array_shift($queue);
|
|
if ($id <= 0 || isset($set[$id])) {
|
|
continue;
|
|
}
|
|
$set[$id] = true;
|
|
foreach ($childrenByPid[$id] ?? [] as $childId) {
|
|
$queue[] = $childId;
|
|
}
|
|
}
|
|
|
|
return $set;
|
|
}
|
|
|
|
private static function fetchRefundOrRejectDiagnosisSet(array $diagIds): array
|
|
{
|
|
if ($diagIds === []) {
|
|
return [];
|
|
}
|
|
$out = [];
|
|
foreach (array_chunk($diagIds, 2000) as $chunk) {
|
|
$ids = Db::name('tcm_prescription_order')
|
|
->whereIn('diagnosis_id', $chunk)
|
|
->whereNull('delete_time')
|
|
->whereIn('fulfillment_status', [9, 10])
|
|
->group('diagnosis_id')
|
|
->column('diagnosis_id');
|
|
foreach ($ids as $id) {
|
|
$out[(int) $id] = true;
|
|
}
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
private static function fetchOrderSeqRows(array $diagIds, array $fields): array
|
|
{
|
|
// 实现已搬至 RevisitVisitSlotService(诊次口径单点维护),此处保留委托以减少 diff
|
|
return RevisitVisitSlotService::fetchOrderSeqRows($diagIds, $fields);
|
|
}
|
|
|
|
private static function fetchRevisitSlotStartOffsetMap(array $diagIds): array
|
|
{
|
|
// 实现已搬至 RevisitVisitSlotService(诊次口径单点维护),此处保留委托以减少 diff
|
|
return RevisitVisitSlotService::fetchRevisitSlotStartOffsetMap($diagIds);
|
|
}
|
|
|
|
private static function fetchDiagnosisInfo(array $diagIds): array
|
|
{
|
|
if ($diagIds === []) {
|
|
return [];
|
|
}
|
|
$rows = Db::name('tcm_diagnosis')
|
|
->whereIn('id', $diagIds)
|
|
->field(['id', 'patient_name', 'phone'])
|
|
->select()
|
|
->toArray();
|
|
$out = [];
|
|
foreach ($rows as $r) {
|
|
$out[(int) $r['id']] = [
|
|
'patient_name' => trim((string) ($r['patient_name'] ?? '')),
|
|
'phone' => trim((string) ($r['phone'] ?? '')),
|
|
];
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
private static function cohortDeptOptions(): array
|
|
{
|
|
$erSet = DeptLogic::getErCenterSubtreeDeptIdSet();
|
|
if ($erSet === []) {
|
|
return ['rows' => []];
|
|
}
|
|
$rows = Db::name('dept')
|
|
->whereNull('delete_time')
|
|
->whereIn('id', array_keys($erSet))
|
|
->field(['id', 'pid', 'name'])
|
|
->order('sort', 'desc')
|
|
->order('id', 'asc')
|
|
->select()
|
|
->toArray();
|
|
|
|
return [
|
|
'rows' => array_map(static fn (array $r): array => [
|
|
'id' => (int) $r['id'],
|
|
'pid' => (int) $r['pid'],
|
|
'name' => (string) $r['name'],
|
|
], $rows),
|
|
];
|
|
}
|
|
}
|