This commit is contained in:
Your Name
2026-06-01 18:34:50 +08:00
parent 0a781bda54
commit be15531ab3
2 changed files with 130 additions and 86 deletions
@@ -293,7 +293,7 @@
:fetch-fun="prescriptionOrderExport"
:params="prescriptionOrderExportParams"
:page-size="pager.size"
export-hint="导出范围与上方筛选一致(履约状态、创建时间及其他条件均会生效)。含「自媒体渠道(挂号渠道来源)」:优先取该单关联处方登记的挂号;无则诊单下同患者挂号取 id 最大的一条(与前台挂号选择的记录一致);业绩侧栏带渠道筛选导出时与同页列表高亮挂号同源。「服务套餐」按字典 server_order 解析展示「签收日期」与详情/业绩看板提成口径一致:以快递主表 sign_time 为主,无效时回退至签收类轨迹时间或已签收状态下的最新轨迹时间。"
export-hint="导出范围与上方筛选一致(履约状态、创建时间及其他条件均会生效)。含「自媒体渠道(挂号渠道来源)」:优先取该单关联处方登记的挂号;无则诊单下同患者挂号取 id 最大的一条(与前台挂号选择的记录一致);业绩侧栏带渠道筛选导出时与同页列表高亮挂号同源。「服务套餐」按字典 server_order 解析展示「签收日期」与详情/业绩看板同源:优先库表轨迹;库内无轨迹时导出会按 logisticsTrace 口径补查快递100 并落库(如 PO 单在详情已签收但库内为空)。"
/>
</el-form-item>
</el-form>
@@ -19,6 +19,7 @@ use app\common\model\doctor\Appointment;
use app\common\model\auth\Admin;
use app\common\service\DataScope\DataScopeService;
use app\common\service\ExpressTrackService;
use app\common\service\ExpressTrackingService;
use app\common\service\gancao\GancaoScmRecipelService;
use think\db\Query;
use think\facade\Config;
@@ -2672,6 +2673,94 @@ class PrescriptionOrderLogic
return 0;
}
/**
* 复诊导出「初诊医助」:同 diagnosis_id 下最早 is_follow_up=0 的业务单医助(非 prev_staff 医生名)
*
* @param array<int, array<string, mixed>> $diagById
* @return array<int, string> diagnosis_id => 医助姓名
*/
private static function batchFirstVisitAssistantNameByDiagnosis(array $diagIds, array $diagById): array
{
if ($diagIds === []) {
return [];
}
$firstRows = PrescriptionOrder::whereIn('diagnosis_id', $diagIds)
->whereNull('delete_time')
->where('is_follow_up', 0)
->field(['id', 'diagnosis_id', 'prescription_id', 'creator_id', 'create_time'])
->order('create_time', 'asc')
->order('id', 'asc')
->select()
->toArray();
$firstByDiag = [];
$rxIds = [];
foreach ($firstRows as $row) {
$did = (int) ($row['diagnosis_id'] ?? 0);
if ($did <= 0 || isset($firstByDiag[$did])) {
continue;
}
$firstByDiag[$did] = $row;
$rxId = (int) ($row['prescription_id'] ?? 0);
if ($rxId > 0) {
$rxIds[$rxId] = true;
}
}
$rxAssistantById = [];
if ($rxIds !== []) {
$rxAssistantById = Prescription::whereIn('id', array_keys($rxIds))
->whereNull('delete_time')
->column('assistant_id', 'id');
}
$adminIds = [];
foreach ($firstByDiag as $did => $row) {
$diag = $diagById[$did] ?? [];
$rxId = (int) ($row['prescription_id'] ?? 0);
$rxAst = $rxId > 0 ? (int) ($rxAssistantById[$rxId] ?? 0) : 0;
$aid = self::resolveAssistantAdminIdForPrescriptionOrderRow(
$rxAst,
(int) ($diag['assistant_id'] ?? 0)
);
if ($aid <= 0) {
$aid = (int) ($row['creator_id'] ?? 0);
}
if ($aid > 0) {
$adminIds[$aid] = true;
}
}
$nameByAdminId = [];
if ($adminIds !== []) {
$admins = Admin::whereIn('id', array_keys($adminIds))
->field(['id', 'name'])
->select()
->toArray();
foreach ($admins as $a) {
$nameByAdminId[(int) $a['id']] = trim((string) ($a['name'] ?? ''));
}
}
$out = [];
foreach ($firstByDiag as $did => $row) {
$diag = $diagById[$did] ?? [];
$rxId = (int) ($row['prescription_id'] ?? 0);
$rxAst = $rxId > 0 ? (int) ($rxAssistantById[$rxId] ?? 0) : 0;
$aid = self::resolveAssistantAdminIdForPrescriptionOrderRow(
$rxAst,
(int) ($diag['assistant_id'] ?? 0)
);
if ($aid <= 0) {
$aid = (int) ($row['creator_id'] ?? 0);
}
$out[$did] = $aid > 0 ? (string) ($nameByAdminId[$aid] ?? '') : '';
}
return $out;
}
/**
* 导出用:管理员在 admin_dept 中的部门路径(多部门「;」、路径内「 / 」;业务订单导出取 creator_id
*/
@@ -2997,94 +3086,48 @@ class PrescriptionOrderLogic
}
}
// 签收时间批量解析:与 ExpressTrackingService::effectiveSignUnixFromTrackingDetail 同口径,
// 取 GREATEST(sign_time, max 签收类轨迹 trace_time_stamp, 已签收主表时的最新轨迹 trace_time_stamp)
// 与详情/业绩看板提成「签收时间」语义一致,避免历史数据 sign_time=0 但实际已签收时被当作「未签收」。
/** @var array<string, int> $signTsByTracking trim 后的 tracking_number => Unix 秒 */
$signTsByTracking = [];
$trackingNumbers = [];
// 签收时间:与详情 logisticsTrace / 业绩提成同源;库内无轨迹时导出阶段补查快递100 并落库。
/** @var array<int, int> $signTsByPoId order_id => Unix 秒 */
$signTsByPoId = [];
if ($poIds !== []) {
$signItems = [];
foreach ($lists as $row) {
$tn = trim((string) ($row['tracking_number'] ?? ''));
if ($tn !== '') {
$trackingNumbers[$tn] = true;
}
}
$trackingNumbers = array_keys($trackingNumbers);
if ($trackingNumbers !== []) {
try {
$etRows = Db::name('express_tracking')
->whereIn('tracking_number', $trackingNumbers)
->whereNull('delete_time')
->field(['id', 'tracking_number', 'sign_time', 'current_state', 'is_signed'])
->select()
->toArray();
$etIdToNum = [];
$signedEtIds = [];
$allEtIds = [];
foreach ($etRows as $r) {
$tn = trim((string) ($r['tracking_number'] ?? ''));
$eid = (int) ($r['id'] ?? 0);
if ($tn === '' || $eid <= 0) {
$oid = (int) ($row['id'] ?? 0);
if ($oid <= 0) {
continue;
}
$etIdToNum[$eid] = $tn;
$allEtIds[] = $eid;
$st = (int) ($r['sign_time'] ?? 0);
if ($st > 0) {
$signTsByTracking[$tn] = max($signTsByTracking[$tn] ?? 0, $st);
$signItems[] = [
'order_id' => $oid,
'tracking_number' => trim((string) ($row['tracking_number'] ?? '')),
];
}
if ((string) ($r['current_state'] ?? '') === '3' || (int) ($r['is_signed'] ?? 0) === 1) {
$signedEtIds[$eid] = true;
}
}
if ($allEtIds !== []) {
$sigCond = "(`status_code` IN ('3','301','302','304') "
. "OR `status` LIKE '%签收%' "
. "OR `trace_context` LIKE '%签收%' "
. "OR `trace_context` LIKE '%妥投%' "
. "OR `trace_context` LIKE '%已送达%' "
. "OR `trace_context` LIKE '%本人签收%')";
$sigTraces = Db::name('express_trace')
->whereIn('tracking_id', $allEtIds)
->where('trace_time_stamp', '>', 0)
->whereRaw($sigCond)
->fieldRaw('tracking_id, MAX(trace_time_stamp) AS max_ts')
->group('tracking_id')
->select()
->toArray();
foreach ($sigTraces as $t) {
$eid = (int) ($t['tracking_id'] ?? 0);
$tn = $etIdToNum[$eid] ?? '';
$ts = (int) ($t['max_ts'] ?? 0);
if ($tn !== '' && $ts > 0) {
$signTsByTracking[$tn] = max($signTsByTracking[$tn] ?? 0, $ts);
}
}
$signedIdList = array_keys($signedEtIds);
if ($signedIdList !== []) {
$anyTraces = Db::name('express_trace')
->whereIn('tracking_id', $signedIdList)
->where('trace_time_stamp', '>', 0)
->fieldRaw('tracking_id, MAX(trace_time_stamp) AS max_ts')
->group('tracking_id')
->select()
->toArray();
foreach ($anyTraces as $t) {
$eid = (int) ($t['tracking_id'] ?? 0);
$tn = $etIdToNum[$eid] ?? '';
$ts = (int) ($t['max_ts'] ?? 0);
if ($tn !== '' && $ts > 0) {
$signTsByTracking[$tn] = max($signTsByTracking[$tn] ?? 0, $ts);
try {
$signTsByPoId = ExpressTrackingService::batchResolveSignUnixFromDbForOrders($signItems);
} catch (\Throwable $e) {
Log::warning('appendPrescriptionOrderListExportRows batch sign_time failed: ' . $e->getMessage());
$signTsByPoId = [];
}
foreach ($lists as $row) {
$oid = (int) ($row['id'] ?? 0);
if ($oid <= 0 || (int) ($signTsByPoId[$oid] ?? 0) > 0) {
continue;
}
if (trim((string) ($row['tracking_number'] ?? '')) === '') {
continue;
}
try {
$synced = ExpressTrackingService::syncSignUnixFromLogisticsForPrescriptionOrder($oid, true);
if ($synced > 0) {
$signTsByPoId[$oid] = $synced;
}
} catch (\Throwable $e) {
Log::warning('appendPrescriptionOrderListExportRows resolve sign_time failed: ' . $e->getMessage());
$signTsByTracking = [];
Log::warning('appendPrescriptionOrderListExportRows sync sign_time order ' . $oid . ': ' . $e->getMessage());
}
}
}
$firstVisitAssistantByDiag = self::batchFirstVisitAssistantNameByDiagnosis($diagIdList, $diagById);
$assistantDeptCache = [];
foreach ($lists as &$item) {
@@ -3145,8 +3188,7 @@ class PrescriptionOrderLogic
$item['export_agency_collect'] = number_format(round($amt - $paid, 2), 2, '.', '');
$item['export_tracking_number'] = (string) ($item['tracking_number'] ?? '');
$tnTrim = trim((string) ($item['tracking_number'] ?? ''));
$signTs = $tnTrim !== '' ? (int) ($signTsByTracking[$tnTrim] ?? 0) : 0;
$signTs = $poId > 0 ? (int) ($signTsByPoId[$poId] ?? 0) : 0;
$item['export_sign_time'] = $signTs > 0 ? date('Y-m-d', $signTs) : '';
$isGc = trim((string) ($item['gancao_reciperl_order_no'] ?? '')) !== '';
$item['export_supply_mode'] = $isGc ? '甘草' : '自营';
@@ -3161,7 +3203,9 @@ class PrescriptionOrderLogic
}
$isFu = (int) ($item['is_follow_up'] ?? 0) === 1;
$item['export_first_visit_assistant'] = $isFu ? (string) ($item['prev_staff'] ?? '') : '';
$item['export_first_visit_assistant'] = $isFu
? (string) ($firstVisitAssistantByDiag[(int) ($item['diagnosis_id'] ?? 0)] ?? '')
: '';
$hit = (int) ($item['po_assign_snapshot_hit'] ?? 0);
$rel = (int) ($item['po_assign_is_release'] ?? 0);