This commit is contained in:
Your Name
2026-05-08 14:13:19 +08:00
parent 43110e015d
commit 7473a3e03d
9 changed files with 1324 additions and 268 deletions
@@ -883,6 +883,21 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
}
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;
}
$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 {
@@ -909,6 +924,35 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
}
}
/**
* 业绩看板侧栏:只保留「业绩归属医助」落在给定 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;
}
$poTbl = (new PrescriptionOrder())->getTable();
$diagTbl = (new Diagnosis())->getTable();
$rxTbl = (new Prescription())->getTable();
$inList = implode(',', $adminIds);
$query->whereRaw(
"EXISTS (SELECT 1 FROM `{$diagTbl}` dg "
. "LEFT JOIN `{$rxTbl}` rx ON rx.`id` = `{$poTbl}`.`prescription_id` AND rx.`delete_time` IS NULL "
. "WHERE dg.`id` = `{$poTbl}`.`diagnosis_id` AND dg.`delete_time` IS NULL AND `{$poTbl}`.`diagnosis_id` > 0 AND "
. '(CASE WHEN dg.`assistant_id` > 0 THEN dg.`assistant_id` '
. "WHEN `{$poTbl}`.`creator_id` > 0 AND (rx.`id` IS NULL OR NOT (`{$poTbl}`.`creator_id` <=> rx.`creator_id`)) THEN `{$poTbl}`.`creator_id` "
. 'ELSE 0 END) IN (' . $inList . '))'
);
}
/**
* 按诊单患者姓名 / 手机号模糊检索(关联 diagnosis_id
*/
File diff suppressed because it is too large Load Diff
@@ -1000,6 +1000,11 @@ class PrescriptionOrderLogic
}
}
$channelDictValue = null;
if ($chSrc !== '' && is_numeric($chSrc)) {
$channelDictValue = (int) $chSrc;
}
return [
'id' => $apptId,
'appointment_date' => (string) ($row['appointment_date'] ?? ''),
@@ -1012,6 +1017,8 @@ class PrescriptionOrderLogic
'doctor_name' => $doctorName,
'channel_source' => $chSrc,
'channel_source_desc' => $chDesc,
/** 字典 type_value=channels 的 value(整型);与业绩看板挂号 channels 收窄、进线统计所用字典为同套 */
'channel_dict_value' => $channelDictValue,
'remark' => (string) ($row['remark'] ?? ''),
];
}
+4 -1
View File
@@ -17,6 +17,9 @@ use think\console\Output;
*
* 配置 crontab(每 10 分钟):拉快递 100 + 按履约「已发货/已签收」核对释放诊单医助(与是否甘草单无关)
* 0,10,20,30,40,50 * * * * cd /path/to/server && php think express:auto-update >> /dev/null 2>&1
*
* 已对非二中心医助执行发货/签收自动释放的诊单会写入 tcm_diagnosis.shipped_non_er_assistant_cleared_at
* 后续履约核对不再重复扫描(需先执行 sql/1.9.20260507/add_diagnosis_shipped_non_er_assistant_cleared_at.sql)。
*/
class ExpressAutoUpdate extends Command
{
@@ -34,7 +37,7 @@ class ExpressAutoUpdate extends Command
try {
$result = ExpressTrackingService::autoUpdateBatch(500);
$recon = ExpressTrackingService::reconcileAssistantReleaseForShippedPrescriptionOrders(200);
$recon = ExpressTrackingService::reconcileAssistantReleaseForShippedPrescriptionOrders(500);
$duration = round(microtime(true) - $startTime, 2);
@@ -28,6 +28,9 @@ use think\console\Output;
*
* 建议 crontab(每 30 分钟执行一次):
* 0,30 * * * * cd /path/to/server && php think gancao:sync-logistics --limit=200 >> runtime/log/gancao_sync.log 2>&1
*
* 已对非二中心医助执行发货/签收自动释放的诊单会写入 tcm_diagnosis.shipped_non_er_assistant_cleared_at
* 后续履约核对不再重复扫描(需先执行 sql/1.9.20260507/add_diagnosis_shipped_non_er_assistant_cleared_at.sql)。
*/
class GancaoSyncLogisticsRoute extends Command
{
@@ -13,6 +13,7 @@ use app\common\model\ExpressStateLog;
use app\common\model\ExpressQueryLog;
use app\common\model\tcm\Diagnosis;
use app\common\model\tcm\DiagnosisAssignLog;
use app\common\model\tcm\Prescription;
use app\common\model\tcm\PrescriptionOrder;
use app\common\model\tcm\PrescriptionOrderLog;
use think\facade\Db;
@@ -250,6 +251,7 @@ class ExpressTrackingService
* 快递 100 定时拉轨迹、甘草路由、甘草回调与履约核对共用同一规则。
* 例外:指派日志中若存在「从某医助改派到另一医助」(原、新医助 ID 均大于 0)的记录,视为人工指派链,自动释放跳过。
* 例外:患者当前医助在「二中心」及其全部子部门(与后台部门树一致)下任职时,不自动清空医助(按 admin_dept 与 dept 树判定)。
* 非二中心且已自动释放:诊单写入 shipped_non_er_assistant_cleared_atassistant_id 已为 0 时后续履约核对不再重复扫描(重新指派医助后可再次处理)。
*
* @param array{tracking_id?:int,tracking_number?:string,source?:string} $meta
* @return array{
@@ -288,7 +290,26 @@ class ExpressTrackingService
if (!$diag) {
return null;
}
$shippedClearedAt = (int) ($diag->getAttr('shipped_non_er_assistant_cleared_at') ?? 0);
$diagAssistantIdNow = (int) ($diag->getAttr('assistant_id') ?? 0);
if ($shippedClearedAt > 0 && $diagAssistantIdNow === 0) {
return null;
}
// 诊单 assistant_id 与列表「医助」筛选一致:医助常代建单但诊单未写 assistant_id,此时用创建人作为待释放身份(创建人即开方医生时不采用,避免误记指派日志)
$fromAssistantId = (int) ($diag->getAttr('assistant_id') ?? 0);
if ($fromAssistantId <= 0) {
$creatorId = (int) ($order->getAttr('creator_id') ?? 0);
if ($creatorId > 0) {
$rxId = (int) ($order->getAttr('prescription_id') ?? 0);
$rxCreator = 0;
if ($rxId > 0) {
$rxCreator = (int) Prescription::where('id', $rxId)->whereNull('delete_time')->value('creator_id');
}
if ($rxId <= 0 || $creatorId !== $rxCreator) {
$fromAssistantId = $creatorId;
}
}
}
if ($fromAssistantId <= 0) {
return null;
}
@@ -328,7 +349,10 @@ class ExpressTrackingService
Db::startTrans();
try {
Diagnosis::where('id', $diagnosisId)->whereNull('delete_time')->update(['assistant_id' => 0]);
Diagnosis::where('id', $diagnosisId)->whereNull('delete_time')->update([
'assistant_id' => 0,
'shipped_non_er_assistant_cleared_at' => time(),
]);
DiagnosisAssignLog::create([
'diagnosis_id' => $diagnosisId,
@@ -624,19 +648,29 @@ class ExpressTrackingService
/**
* 按处方订单履约核对:已发货(5)/已签收(6) 时诊单仍挂在医助的,一律释放并写指派日志。
* 与快递 100 / 甘草来自哪个物流渠道无关,保障「已发货」后患者侧医助被清掉。
* 已对非二中心医助做过发货/签收释放且 assistant_id=0 的诊单(shipped_non_er_assistant_cleared_at>0)不再纳入本扫描,避免重复命中 creator 分支。
*
* @return array{scanned: int, cleared: int, lines: list<string>}
*/
public static function reconcileAssistantReleaseForShippedPrescriptionOrders(int $limit = 200): array
{
$dTable = (new Diagnosis())->getTable();
$rxTable = (new Prescription())->getTable();
$orders = PrescriptionOrder::alias('po')
->join($dTable . ' d', 'd.id = po.diagnosis_id')
->leftJoin($rxTable . ' rx', 'rx.id = po.prescription_id AND rx.delete_time IS NULL')
->whereNull('po.delete_time')
->whereNull('d.delete_time')
->whereRaw('(IFNULL(d.shipped_non_er_assistant_cleared_at, 0) = 0 OR d.assistant_id > 0)')
->whereIn('po.fulfillment_status', [5, 6])
->where('po.diagnosis_id', '>', 0)
->where('d.assistant_id', '>', 0)
->where(function ($w) {
$w->where('d.assistant_id', '>', 0)
->whereOr(function ($w2) {
$w2->where('po.creator_id', '>', 0)
->whereRaw('(rx.id IS NULL OR po.creator_id <> rx.creator_id)');
});
})
->order('po.id', 'asc')
->limit($limit)
->field('po.*')