更新
This commit is contained in:
@@ -552,7 +552,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
|
||||
unset($item);
|
||||
|
||||
if ((int) ($this->params['yeji_order_drawer'] ?? 0) === 1) {
|
||||
PrescriptionOrderLogic::appendLinkedAppointmentsToListRows($lists);
|
||||
PrescriptionOrderLogic::appendLinkedAppointmentsToListRows($lists, $this->params);
|
||||
}
|
||||
|
||||
return $lists;
|
||||
|
||||
@@ -28,6 +28,20 @@ use think\facade\Log;
|
||||
*/
|
||||
class AppointmentLogic extends BaseLogic
|
||||
{
|
||||
/** 仅这些字典名称需填写 channel_source_detail(与 admin 预约弹窗白名单一致,按 name 全等) */
|
||||
private const CHANNEL_NAMES_REQUIRING_SOURCE_DETAIL = [
|
||||
'自媒体4H',
|
||||
'自媒体3Q',
|
||||
'自媒体3H',
|
||||
'自媒体2H',
|
||||
'自媒体2Q',
|
||||
];
|
||||
|
||||
private static function channelDictNameRequiresSourceDetail(string $name): bool
|
||||
{
|
||||
return in_array($name, self::CHANNEL_NAMES_REQUIRING_SOURCE_DETAIL, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 获取可用时间段
|
||||
* @param array $params
|
||||
@@ -233,6 +247,21 @@ class AppointmentLogic extends BaseLogic
|
||||
Db::rollback();
|
||||
return false;
|
||||
}
|
||||
|
||||
$chSrc = trim((string) ($params['channel_source'] ?? ''));
|
||||
$chDetail = trim((string) ($params['channel_source_detail'] ?? ''));
|
||||
$channelDictName = trim((string) (DictData::where('type_value', 'channels')
|
||||
->where('value', $chSrc)
|
||||
->value('name') ?? ''));
|
||||
if ($channelDictName !== '' && self::channelDictNameRequiresSourceDetail($channelDictName)) {
|
||||
if ($chDetail === '') {
|
||||
self::setError('请填写自媒体渠道补充信息');
|
||||
Db::rollback();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'patient_id' => $params['patient_id'],
|
||||
'assistant_id'=>$params['assistant_id'],
|
||||
@@ -244,7 +273,8 @@ class AppointmentLogic extends BaseLogic
|
||||
'appointment_type' => $params['appointment_type'] ?? 'video',
|
||||
'remark' => $params['remark'] ?? '',
|
||||
// 表字段为 channel_source(与字典 type_value=channels 的 value 一致);勿再写入不存在的 channels 列
|
||||
'channel_source' => trim((string) ($params['channel_source'] ?? '')),
|
||||
'channel_source' => $chSrc,
|
||||
'channel_source_detail' => $chDetail,
|
||||
'status' => 1,
|
||||
'create_time' => time(),
|
||||
'update_time' => time(),
|
||||
|
||||
@@ -4701,7 +4701,8 @@ class YejiStatsLogic
|
||||
}
|
||||
|
||||
/**
|
||||
* 业绩看板业务订单侧栏:按 channel_code 收窄(与 overview「{渠道}业绩」同患者判定;含 ap.channels 与 ap.channel_source)
|
||||
* 业绩看板业务订单侧栏:按 channel_code 收窄(与 overview「{渠道}业绩」同患者判定;含 ap.channels 与 ap.channel_source);
|
||||
* **二中心及其组织下级**展示部门与看板一致:选定渠道收窄时本条无渠道订单(表中渠道业绩已为 0)。
|
||||
*
|
||||
* @param Query $query PrescriptionOrder 主表查询
|
||||
* @param array<string, mixed> $params
|
||||
@@ -4715,6 +4716,16 @@ class YejiStatsLogic
|
||||
if ($channelCode === '') {
|
||||
return;
|
||||
}
|
||||
/** @see excludeErCenterSubtreeFromChannelMetrics 看板选定渠道时对二中心子树渠道列置 0,侧栏须同步 */
|
||||
$assistantDeptForDrawer = (int) ($params['assistant_dept_id'] ?? 0);
|
||||
if ($assistantDeptForDrawer > 0) {
|
||||
$erCenterSubtree = DeptLogic::getErCenterSubtreeDeptIdSet();
|
||||
if (isset($erCenterSubtree[$assistantDeptForDrawer])) {
|
||||
$query->whereRaw('0 = 1');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
$startDate = '';
|
||||
$endDate = '';
|
||||
$st = trim((string) ($params['start_time'] ?? ''));
|
||||
@@ -4803,4 +4814,110 @@ class YejiStatsLogic
|
||||
$query->whereRaw('0 = 1');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 业绩看板业务订单侧栏:在「渠道筛选」模式下,为每个诊单挑一条用于「关联挂号」展示的预约行——
|
||||
* 须为已完成(status=3)、挂号助理为医助(role_id=2),且 channels/channel_source 与当前 channel_code 同源命中(与 {@see applyYejiDrawerChannelFilterToPrescriptionOrderQuery} 的 dict 收窄一致)。
|
||||
* 若为 tag 等未走 channels 表达式的情况则返回空图,交由列表沿用处方/最近挂号。
|
||||
*
|
||||
* @param int[] $diagnosisIds doctor_appointment.patient_id(与本系统诊单 id 一致)
|
||||
* @param array<string, mixed> $params 与列表同源:yeji_order_drawer、channel_code、start_time、end_time
|
||||
*
|
||||
* @return array<int, int> diagnosis_id => appointment_id
|
||||
*/
|
||||
public static function batchResolveYejiChannelDrawerHighlightAppointmentIds(array $diagnosisIds, array $params): array
|
||||
{
|
||||
$diagnosisIds = array_values(array_unique(array_filter(array_map('intval', $diagnosisIds), static fn (int $x): bool => $x > 0)));
|
||||
if ($diagnosisIds === []) {
|
||||
return [];
|
||||
}
|
||||
if ((int) ($params['yeji_order_drawer'] ?? 0) !== 1) {
|
||||
return [];
|
||||
}
|
||||
$channelCode = trim((string) ($params['channel_code'] ?? ''));
|
||||
if ($channelCode === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$startDate = '';
|
||||
$endDate = '';
|
||||
$st = trim((string) ($params['start_time'] ?? ''));
|
||||
if (preg_match('/^(\d{4}-\d{2}-\d{2})/', $st, $m)) {
|
||||
$startDate = $m[1];
|
||||
}
|
||||
$et = trim((string) ($params['end_time'] ?? ''));
|
||||
if (preg_match('/^(\d{4}-\d{2}-\d{2})/', $et, $m)) {
|
||||
$endDate = $m[1];
|
||||
}
|
||||
if ($startDate === '' || $endDate === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$ctx = self::resolveYejiContext([
|
||||
'start_date' => $startDate,
|
||||
'end_date' => $endDate,
|
||||
'channel_code' => $channelCode,
|
||||
'dept_ids' => null,
|
||||
]);
|
||||
if (!$ctx['channelFilterActive'] || $ctx['channelInfo'] === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$norm = self::normalizeAppointmentChannelValues($ctx['appointmentChannelValues']);
|
||||
$srcStrings = self::appointmentChannelDictStringValuesForDrawer($ctx['channelInfo']);
|
||||
if ($norm === [] && $srcStrings === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$apTable = self::tableWithPrefix('doctor_appointment');
|
||||
$arTable = self::tableWithPrefix('admin_role');
|
||||
|
||||
$hasCh = self::doctorAppointmentHasChannelsColumn();
|
||||
$orParts = [];
|
||||
$channelBind = [];
|
||||
if ($norm !== [] && $hasCh) {
|
||||
$strVals = array_values(array_unique(array_map(static fn (int $v): string => (string) $v, $norm)));
|
||||
$ph = implode(',', array_fill(0, count($strVals), '?'));
|
||||
$orParts[] = "ap.`channels` IN ({$ph})";
|
||||
foreach ($strVals as $sv) {
|
||||
$channelBind[] = $sv;
|
||||
}
|
||||
}
|
||||
if ($srcStrings !== [] && self::doctorAppointmentHasChannelSourceColumn()) {
|
||||
$ph = implode(',', array_fill(0, count($srcStrings), '?'));
|
||||
$orParts[] = "ap.`channel_source` IN ({$ph})";
|
||||
foreach ($srcStrings as $s) {
|
||||
$channelBind[] = $s;
|
||||
}
|
||||
}
|
||||
if ($orParts === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$inPh = implode(',', array_fill(0, count($diagnosisIds), '?'));
|
||||
$bind = array_merge($diagnosisIds, $channelBind);
|
||||
|
||||
$orSql = '(' . implode(' OR ', $orParts) . ')';
|
||||
$sql = "SELECT ap.`patient_id` AS dg, MAX(ap.`id`) AS aid FROM `{$apTable}` ap "
|
||||
. "INNER JOIN `{$arTable}` ar ON ar.`admin_id` = ap.`assistant_id` AND ar.`role_id` = 2 "
|
||||
. "WHERE ap.`patient_id` IN ({$inPh}) AND ap.`status` = 3 AND {$orSql} "
|
||||
. 'GROUP BY ap.`patient_id`';
|
||||
|
||||
try {
|
||||
$rows = Db::query($sql, $bind);
|
||||
} catch (\Throwable) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$out = [];
|
||||
foreach ($rows as $r) {
|
||||
$dg = (int) ($r['dg'] ?? $r['DG'] ?? 0);
|
||||
$aid = (int) ($r['aid'] ?? $r['AID'] ?? 0);
|
||||
if ($dg > 0 && $aid > 0) {
|
||||
$out[$dg] = $aid;
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace app\adminapi\logic\tcm;
|
||||
|
||||
use app\adminapi\logic\stats\YejiStatsLogic;
|
||||
use app\adminapi\logic\auth\AuthLogic;
|
||||
use app\adminapi\logic\order\OrderLogic;
|
||||
use app\common\model\Order;
|
||||
@@ -1049,11 +1050,13 @@ class PrescriptionOrderLogic
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务订单列表行批量附加 linked_appointment(解析规则与详情一致:优先处方 appointment_id,否则诊单最近一条预约)
|
||||
* 业务订单列表行批量附加 linked_appointment(解析规则与详情一致:优先处方 appointment_id,否则诊单最近一条预约;
|
||||
* 业绩侧栏且带 channel_code 时优先展示与渠道收窄同源的已完成挂号,避免列表行属自媒体2Q 但展示关联为自媒体1)
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $lists
|
||||
* @param array<string, mixed> $listsParams PrescriptionOrderLists 请求参数(可选)
|
||||
*/
|
||||
public static function appendLinkedAppointmentsToListRows(array &$lists): void
|
||||
public static function appendLinkedAppointmentsToListRows(array &$lists, array $listsParams = []): void
|
||||
{
|
||||
if ($lists === []) {
|
||||
return;
|
||||
@@ -1063,6 +1066,23 @@ class PrescriptionOrderLogic
|
||||
}
|
||||
unset($item);
|
||||
|
||||
$yejiChannelHighlightByDiag = [];
|
||||
if (
|
||||
(int) ($listsParams['yeji_order_drawer'] ?? 0) === 1
|
||||
&& trim((string) ($listsParams['channel_code'] ?? '')) !== ''
|
||||
) {
|
||||
$allDiagIdsForYeji = array_values(array_unique(array_filter(
|
||||
array_map(static fn ($x): int => (int) ($x['diagnosis_id'] ?? 0), $lists),
|
||||
static fn (int $id): bool => $id > 0
|
||||
)));
|
||||
if ($allDiagIdsForYeji !== []) {
|
||||
$yejiChannelHighlightByDiag = YejiStatsLogic::batchResolveYejiChannelDrawerHighlightAppointmentIds(
|
||||
$allDiagIdsForYeji,
|
||||
$listsParams
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$rxIds = array_values(array_unique(array_filter(array_map(
|
||||
static fn ($x) => (int) ($x['prescription_id'] ?? 0),
|
||||
$lists
|
||||
@@ -1113,6 +1133,10 @@ class PrescriptionOrderLogic
|
||||
if ($resolved <= 0 && $dgId > 0) {
|
||||
$resolved = (int) ($latestApptByDiag[$dgId] ?? 0);
|
||||
}
|
||||
$preferredYeji = $dgId > 0 ? (int) ($yejiChannelHighlightByDiag[$dgId] ?? 0) : 0;
|
||||
if ($preferredYeji > 0) {
|
||||
$resolved = $preferredYeji;
|
||||
}
|
||||
if ($resolved > 0) {
|
||||
$resolvedPairs[$idx] = [$resolved, $rxApptId];
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ class AppointmentValidate extends BaseValidate
|
||||
'appointment_time' => 'require',
|
||||
'appointment_type' => 'in:video,text,phone',
|
||||
'channel_source' => 'require',
|
||||
'channel_source_detail' => 'max:128',
|
||||
'note_id' => 'require|integer',
|
||||
'image_type' => 'require|in:tongue_images,report_files',
|
||||
'image_path' => 'require',
|
||||
@@ -44,6 +45,7 @@ class AppointmentValidate extends BaseValidate
|
||||
'appointment_time' => '预约时间',
|
||||
'appointment_type' => '预约类型',
|
||||
'channel_source' => '渠道来源',
|
||||
'channel_source_detail' => '渠道补充说明',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -52,7 +54,7 @@ class AppointmentValidate extends BaseValidate
|
||||
*/
|
||||
public function sceneCreate()
|
||||
{
|
||||
return $this->only(['patient_id', 'doctor_id', 'appointment_date', 'period', 'appointment_time', 'appointment_type', 'channel_source']);
|
||||
return $this->only(['patient_id', 'doctor_id', 'appointment_date', 'period', 'appointment_time', 'appointment_type', 'channel_source', 'channel_source_detail']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user