0; } /** * 是否可查看该处方(列表/详情) * * @param Prescription|array $row */ public static function canViewPrescription($row, int $adminId, array $adminInfo): bool { // 超级管理员 if (!empty($adminInfo['root']) && (int) $adminInfo['root'] === 1) { return true; } // 创建人 $creatorId = is_array($row) ? (int) ($row['creator_id'] ?? 0) : (int) $row->creator_id; if ($creatorId === $adminId) { return true; } // 医助 $assistantId = is_array($row) ? (int) ($row['assistant_id'] ?? 0) : (int) ($row->assistant_id ?? 0); if ($assistantId > 0 && $assistantId === $adminId) { return true; } // 共享处方 $isShared = is_array($row) ? (int) ($row['is_shared'] ?? 0) : (int) $row->is_shared; if ($isShared === 1) { return true; } // 可见角色 $vis = is_array($row) ? (string) ($row['visible_role_ids'] ?? '') : (string) ($row->visible_role_ids ?? ''); $allowed = array_filter(array_map('intval', explode(',', $vis))); $myRoles = array_map('intval', $adminInfo['role_id'] ?? []); if (count(array_intersect($myRoles, $allowed)) > 0) { return true; } // 有开方权限的医生可以查看所有处方(只读) // 这样其他医生可以查看患者的历史处方记录 $permissions = $adminInfo['permissions'] ?? []; if (in_array('tcm.diagnosis/kaifang', $permissions, true)) { return true; } // 有业务订单管理权限的角色(如药师)可以查看处方(只读) // 这样药师可以在业务订单中查看关联的处方信息 $orderEditAllRoles = Config::get('project.order_edit_all_roles', [0, 3]); $myRoles = array_map('intval', $adminInfo['role_id'] ?? []); $allowedRoles = array_map('intval', is_array($orderEditAllRoles) ? $orderEditAllRoles : []); if (count(array_intersect($myRoles, $allowedRoles)) > 0) { return true; } return false; } private static function generateSn(): string { return 'RX' . date('Ymd') . str_pad((string)mt_rand(1, 9999), 4, '0', STR_PAD_LEFT); } /** * 处方日期统一为 Y-m-d(与库表 prescription_date 一致) * * @param mixed $raw */ private static function normalizePrescriptionDate($raw): string { if ($raw === null || $raw === '') { return date('Y-m-d'); } if (is_numeric($raw) && (float) $raw > 1e9) { return date('Y-m-d', (int) $raw); } $s = (string) $raw; if (preg_match('/^\d{4}-\d{2}-\d{2}/', $s)) { return substr($s, 0, 10); } $ts = strtotime($s); return $ts ? date('Y-m-d', $ts) : date('Y-m-d'); } private static function normalizeDosageBagCount($raw): int { $count = (int) $raw; if ($count < 1) { return 1; } if ($count > 5) { return 5; } return $count; } /** * 同一诊单、同一开方人、同一处方日期:仅允许一张「未作废」的未删除记录;已作废的可再新开一张。 * * @param int|null $excludeId 编辑时排除自身 id */ private static function assertUniquePrescriptionPerDiagnosisDay(int $diagnosisId, int $creatorId, string $prescriptionDateYmd, ?int $excludeId): bool { if ($diagnosisId <= 0 || $creatorId <= 0) { return true; } $q = Prescription::where('diagnosis_id', $diagnosisId) ->where('creator_id', $creatorId) ->where('prescription_date', $prescriptionDateYmd) ->where('void_status', 0) ->whereNull('delete_time'); if ($excludeId !== null && $excludeId > 0) { $q->where('id', '<>', $excludeId); } if ($q->count() > 0) { self::setError('同一诊单同一天已存在未作废处方,请先作废后再新开'); return false; } return true; } /** * 添加处方 */ public static function add(array $params, int $adminId): ?int { // 如果没有诊单ID,允许直接创建处方模板 if (!empty($params['diagnosis_id'])) { $diagnosis = Diagnosis::find($params['diagnosis_id']); if (!$diagnosis) { self::setError('诊单不存在'); return null; } } $dateYmd = self::normalizePrescriptionDate($params['prescription_date'] ?? date('Y-m-d')); $diagnosisIdRule = (int) ($params['diagnosis_id'] ?? 0); if ($diagnosisIdRule > 0 && !self::assertUniquePrescriptionPerDiagnosisDay($diagnosisIdRule, $adminId, $dateYmd, null)) { return null; } $herbs = $params['herbs'] ?? []; if (empty($herbs) || !is_array($herbs)) { self::setError('请添加中药'); return null; } foreach ($herbs as $h) { if (empty($h['name'])) { self::setError('中药名称不能为空'); return null; } } $sn = self::generateSn(); while (Prescription::where('sn', $sn)->find()) { $sn = self::generateSn(); } $assistantIdForRx = 0; if ($diagnosisIdRule > 0) { $diagAssistant = Diagnosis::where('id', $diagnosisIdRule)->value('assistant_id'); $assistantIdForRx = (int) ($diagAssistant ?? 0); } $data = [ 'sn' => $sn, 'prescription_name' => $params['prescription_name'] ?? '', 'prescription_type' => $params['prescription_type'] ?? '浓缩水丸', 'dosage_amount' => isset($params['dosage_amount']) ? (float)$params['dosage_amount'] : null, 'dosage_unit' => $params['dosage_unit'] ?? '', 'dosage_bag_count' => self::normalizeDosageBagCount($params['dosage_bag_count'] ?? 1), 'need_decoction' => (int)($params['need_decoction'] ?? 0), 'bags_per_dose' => isset($params['bags_per_dose']) ? (int)$params['bags_per_dose'] : 1, 'diagnosis_id' => (int)($params['diagnosis_id'] ?? 0), 'appointment_id' => (int)($params['appointment_id'] ?? 0), 'patient_id' => (int)($params['patient_id'] ?? 0), 'patient_name' => $params['patient_name'] ?? '', 'gender' => (int)($params['gender'] ?? 1), 'age' => (int)($params['age'] ?? 0), 'phone' => $params['phone'] ?? '', 'visit_no' => $params['visit_no'] ?? $sn, 'prescription_date' => $dateYmd, 'pulse' => $params['pulse'] ?? '', 'pulse_condition' => $params['pulse_condition'] ?? '', 'tongue' => $params['tongue'] ?? '', 'tongue_image' => $params['tongue_image'] ?? '', 'clinical_diagnosis' => $params['clinical_diagnosis'] ?? '', 'case_record' => $params['case_record'] ?? null, 'herbs' => $herbs, 'dose_count' => (int)($params['dose_count'] ?? 1), 'dose_unit' => $params['dose_unit'] ?? '剂', 'usage_days' => (int)($params['usage_days'] ?? 7), 'times_per_day' => (int)($params['times_per_day'] ?? 2), 'usage_instruction' => $params['usage_instruction'] ?? '水煎服一日二次', 'usage_time' => $params['usage_time'] ?? '饭前', 'usage_way' => $params['usage_way'] ?? '温水送服', 'dietary_taboo' => is_array($params['dietary_taboo'] ?? null) ? implode(',', $params['dietary_taboo']) : ($params['dietary_taboo'] ?? ''), 'usage_notes' => $params['usage_notes'] ?? '', 'amount' => (float)($params['amount'] ?? 0), 'doctor_name' => $params['doctor_name'] ?? '', 'doctor_signature' => $params['doctor_signature'] ?? '', 'template_id' => (int)($params['template_id'] ?? 0), 'is_shared' => (int)($params['is_shared'] ?? 0), 'visible_role_ids' => self::normalizeVisibleRoleIds($params['visible_role_ids'] ?? []), // 新开方一律待审核(忽略客户端传入的 audit_status,防止绕过审核) 'audit_status' => 0, 'audit_time' => null, 'audit_by' => null, 'audit_by_name' => '', 'audit_remark' => '', 'creator_id' => $adminId, 'assistant_id' => $assistantIdForRx, ]; $prescription = new Prescription(); $prescription->save($data); return (int) $prescription->id; } /** * 编辑处方 */ public static function edit(array $params, int $adminId): bool { try { $prescription = Prescription::find($params['id']); if (!$prescription) { self::setError('处方不存在'); return false; } // 已通过且未作废:不可编辑 if ((int) ($prescription->audit_status ?? 1) === 1 && (int) ($prescription->void_status ?? 0) === 0) { self::setError('该处方已通过审核,不可编辑'); return false; } // 已驳回:仅当该诊单+当天+同一创建人下没有另一条「已通过且未作废」的处方时允许重新编辑(改后待审核、作废一并清除) if ((int) ($prescription->audit_status ?? 1) === 2) { $rejDiagnosisId = (int) ($params['diagnosis_id'] ?? $prescription->diagnosis_id); $rejDateYmd = self::normalizePrescriptionDate($params['prescription_date'] ?? $prescription->prescription_date); if ($rejDiagnosisId > 0) { $hasOtherApproved = Prescription::where('diagnosis_id', $rejDiagnosisId) ->where('creator_id', (int) $prescription->creator_id) ->where('prescription_date', $rejDateYmd) ->where('audit_status', 1) ->where('void_status', 0) ->whereNull('delete_time') ->where('id', '<>', (int) $params['id']) ->count() > 0; if ($hasOtherApproved) { self::setError('该诊单当天已有审核通过的处方,不可再编辑本条已驳回记录'); return false; } } } // 检查权限:只有创建者或共享的处方才能编辑 if ($prescription->creator_id != $adminId && $prescription->is_shared != 1) { self::setError('无权限编辑此处方'); return false; } $herbs = $params['herbs'] ?? []; if (empty($herbs) || !is_array($herbs)) { self::setError('请添加中药'); return false; } foreach ($herbs as $h) { if (empty($h['name'])) { self::setError('中药名称不能为空'); return false; } } $newDiagnosisId = (int) ($params['diagnosis_id'] ?? $prescription->diagnosis_id); $newDateYmd = self::normalizePrescriptionDate($params['prescription_date'] ?? $prescription->prescription_date); if ($newDiagnosisId > 0 && !self::assertUniquePrescriptionPerDiagnosisDay($newDiagnosisId, (int) $prescription->creator_id, $newDateYmd, (int) $params['id'])) { return false; } $wasVoid = (int) ($prescription->void_status ?? 0) === 1; $assistantIdForRx = (int) ($prescription->assistant_id ?? 0); if ($newDiagnosisId > 0) { $diagAssistant = Diagnosis::where('id', $newDiagnosisId)->value('assistant_id'); $assistantIdForRx = (int) ($diagAssistant ?? 0); } else { $assistantIdForRx = 0; } $data = [ 'diagnosis_id' => $newDiagnosisId, 'assistant_id' => $assistantIdForRx, 'prescription_name' => $params['prescription_name'] ?? $prescription->prescription_name, 'prescription_type' => $params['prescription_type'] ?? $prescription->prescription_type, 'dosage_amount' => isset($params['dosage_amount']) ? (float)$params['dosage_amount'] : $prescription->dosage_amount, 'dosage_unit' => $params['dosage_unit'] ?? $prescription->dosage_unit, 'dosage_bag_count' => self::normalizeDosageBagCount($params['dosage_bag_count'] ?? ($prescription->dosage_bag_count ?? 1)), 'need_decoction' => isset($params['need_decoction']) ? (int)$params['need_decoction'] : (int)($prescription->need_decoction ?? 0), 'bags_per_dose' => isset($params['bags_per_dose']) ? (int)$params['bags_per_dose'] : (int)($prescription->bags_per_dose ?? 1), 'patient_name' => $params['patient_name'] ?? $prescription->patient_name, 'gender' => (int)($params['gender'] ?? $prescription->gender), 'age' => (int)($params['age'] ?? $prescription->age), 'visit_no' => $params['visit_no'] ?? $prescription->visit_no, 'prescription_date' => $newDateYmd, 'tongue' => $params['tongue'] ?? $prescription->tongue, 'tongue_image' => $params['tongue_image'] ?? $prescription->tongue_image, 'pulse' => $params['pulse'] ?? $prescription->pulse, 'pulse_condition' => $params['pulse_condition'] ?? $prescription->pulse_condition, 'clinical_diagnosis' => $params['clinical_diagnosis'] ?? $prescription->clinical_diagnosis, 'herbs' => $herbs, 'dose_count' => (int)($params['dose_count'] ?? $prescription->dose_count), 'dose_unit' => $params['dose_unit'] ?? $prescription->dose_unit, 'usage_days' => (int)($params['usage_days'] ?? $prescription->usage_days), 'times_per_day' => (int)($params['times_per_day'] ?? $prescription->times_per_day ?? 2), 'usage_instruction' => $params['usage_instruction'] ?? $prescription->usage_instruction, 'usage_time' => $params['usage_time'] ?? $prescription->usage_time, 'usage_way' => $params['usage_way'] ?? $prescription->usage_way, 'dietary_taboo' => is_array($params['dietary_taboo'] ?? null) ? implode(',', $params['dietary_taboo']) : ($params['dietary_taboo'] ?? $prescription->dietary_taboo), 'usage_notes' => $params['usage_notes'] ?? $prescription->usage_notes, 'doctor_name' => $params['doctor_name'] ?? $prescription->doctor_name, 'doctor_signature' => $params['doctor_signature'] ?? $prescription->doctor_signature, 'is_shared' => (int)($params['is_shared'] ?? $prescription->is_shared), 'visible_role_ids' => array_key_exists('visible_role_ids', $params) ? self::normalizeVisibleRoleIds($params['visible_role_ids']) : (string) ($prescription->visible_role_ids ?? ''), // 后台编辑保存后视为手工处方(原系统代开标记清除) 'is_system_auto' => 0, // 开方医生修改后重新进入待审核 'audit_status' => 0, 'audit_time' => null, 'audit_by' => null, 'audit_by_name' => '', 'audit_remark' => '', ]; if ($wasVoid) { $data['void_status'] = 0; $data['void_time'] = null; $data['void_by'] = null; $data['void_by_name'] = ''; } $prescription->save($data); PrescriptionOrderLogic::onConsumerPrescriptionSaved((int) $params['id']); return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * 删除处方 */ public static function delete(int $id): bool { try { $prescription = Prescription::find($id); if (!$prescription) { self::setError('处方不存在'); return false; } if ((int) ($prescription->audit_status ?? 1) === 1 && (int) ($prescription->void_status ?? 0) === 0) { self::setError('该处方已通过审核,不可删除'); return false; } $prescription->delete(); return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * 处方详情(带查看权限校验,供后台管理端) */ public static function detail(int $id, int $viewerAdminId, array $viewerAdminInfo): ?array { self::$error = ''; $row = Prescription::find($id); if (!$row) { return null; } if (!self::canViewPrescription($row, $viewerAdminId, $viewerAdminInfo)) { self::setError('无权限查看此处方'); return null; } $arr = $row->toArray(); $arr['gender_desc'] = $arr['gender'] == 1 ? '男' : '女'; $arr['visible_role_ids'] = self::visibleRoleIdsToArray($arr['visible_role_ids'] ?? ''); $bizPo = PrescriptionOrder::where('prescription_id', $id) ->where('prescription_audit_status', 2) ->whereNull('delete_time') ->where('fulfillment_status', '<>', 4) ->order('id', 'desc') ->find(); $arr['business_prescription_audit_rejected'] = $bizPo ? 1 : 0; $arr['business_prescription_audit_remark'] = $bizPo ? (string) ($bizPo->prescription_audit_remark ?? '') : ''; // 与 PrescriptionLists「业务订单」角标一致:未删除且非已取消(4) 即视为存在有效业务订单 $hasBizOrder = PrescriptionOrder::where('prescription_id', $id) ->whereNull('delete_time') ->where('fulfillment_status', '<>', 4) ->count() > 0; $arr['has_prescription_order'] = $hasBizOrder ? 1 : 0; /** * 处方笺展示所需的"收件信息/订单号/合计"等字段, * 来源是该处方关联的「业务处方订单」(zyt_tcm_prescription_order)。 * 取最近一条未删除且未取消的订单: * - recipient_name / recipient_phone / shipping_address 用于「收件信息」一行 * - order_no 用于处方笺右上角「编号」 * - amount 作为「合计」金额回填(前端再做 0 兜底展示) */ $latestPo = PrescriptionOrder::where('prescription_id', $id) ->whereNull('delete_time') ->where('fulfillment_status', '<>', 4) ->order('id', 'desc') ->find(); if ($latestPo) { $arr['recipient_name'] = (string) ($latestPo->recipient_name ?? ''); $arr['recipient_phone'] = (string) ($latestPo->recipient_phone ?? ''); $arr['shipping_address'] = (string) ($latestPo->shipping_address ?? ''); $arr['order_no'] = (string) ($latestPo->order_no ?? ''); $arr['order_amount'] = round((float) ($latestPo->amount ?? 0), 2); } return $arr; } /** * 业务订单「处方审核」通过时:消费者处方仍为待审核则一并记为已通过, * 避免消费者处方列表筛选「未通过」仍包含该条、与业务侧已通过不一致。 */ public static function syncApproveConsumerPrescriptionIfPending( int $prescriptionId, int $adminId, array $adminInfo, string $remark ): void { if ($prescriptionId <= 0) { return; } $row = Prescription::find($prescriptionId); if (!$row) { return; } if ((int) ($row->void_status ?? 0) === 1) { return; } if ((int) ($row->audit_status ?? 1) !== 0) { return; } self::$lastAuditWecomNotify = null; $name = (string) ($adminInfo['name'] ?? ''); $now = time(); $finalRemark = trim($remark) !== '' ? trim($remark) : '业务订单处方审核通过'; $finalRemark = mb_substr($finalRemark, 0, 500); $row->audit_status = 1; $row->audit_time = $now; $row->audit_by = $adminId; $row->audit_by_name = $name; $row->audit_remark = $finalRemark; try { if ($row->save()) { self::$lastAuditWecomNotify = self::notifyCreatorAuditResult($row, 'approve', $finalRemark, $adminInfo); } } catch (\Throwable $e) { Log::error('syncApproveConsumerPrescriptionIfPending: ' . $e->getMessage()); } } /** * @return int[] */ public static function visibleRoleIdsToArray(string $csv): array { if ($csv === '') { return []; } return array_values(array_unique(array_filter(array_map('intval', explode(',', $csv))))); } /** * 审核:通过 / 驳回(驳回同时作废处方) */ public static function audit(int $id, string $action, string $remark, int $adminId, array $adminInfo): bool { self::$error = ''; self::$lastAuditWecomNotify = null; if (!self::canAuditPrescription($adminId, $adminInfo)) { self::setError('无审核权限'); return false; } $row = Prescription::find($id); if (!$row) { self::setError('处方不存在'); return false; } if (!self::canViewPrescription($row, $adminId, $adminInfo)) { self::setError('无权限查看此处方,无法审核'); return false; } if ((int) ($row->audit_status ?? 1) !== 0) { self::setError('当前状态不可审核'); return false; } $name = (string) ($adminInfo['name'] ?? ''); $now = time(); if ($action === 'approve') { $row->audit_status = 1; $row->audit_time = $now; $row->audit_by = $adminId; $row->audit_by_name = $name; $row->audit_remark = $remark; $ok = (bool) $row->save(); if ($ok) { self::$lastAuditWecomNotify = self::notifyCreatorAuditResult($row, 'approve', $remark, $adminInfo); } return $ok; } if ($action === 'reject') { if (trim($remark) === '') { self::setError('驳回时请填写审核意见'); return false; } $row->audit_status = 2; $row->audit_time = $now; $row->audit_by = $adminId; $row->audit_by_name = $name; $row->audit_remark = $remark; $row->void_status = 1; $row->void_time = $now; $row->void_by = $adminId; $row->void_by_name = $name; $ok = (bool) $row->save(); if ($ok) { self::$lastAuditWecomNotify = self::notifyCreatorAuditResult($row, 'reject', $remark, $adminInfo); } return $ok; } self::setError('无效的审核操作'); return false; } /** * 审核通过/驳回后,给企业微信中的开方人发一条应用消息(需绑定 work_wechat_userid) * * @return array{ok: bool, message?: string, errcode?: int} */ private static function notifyCreatorAuditResult(Prescription $rx, string $action, string $remark, array $auditorInfo): array { try { $creatorId = (int) ($rx->creator_id ?? 0); if ($creatorId <= 0) { return ['ok' => false, 'message' => '无法通知:处方无开方人信息']; } $creator = Admin::whereNull('delete_time')->find($creatorId); if (!$creator) { return ['ok' => false, 'message' => '无法通知:开方人账号不存在']; } $wxId = trim((string) ($creator->work_wechat_userid ?? '')); if ($wxId === '') { Log::warning("处方审核企业微信通知跳过: 开方人 admin_id={$creatorId} 未绑定 work_wechat_userid"); return [ 'ok' => false, 'message' => '开方人未绑定企业微信账号,无法推送消息(请其在后台「扫码绑定企业微信」后再试)', ]; } $sn = (string) ($rx->sn ?? ''); $patient = (string) ($rx->patient_name ?? ''); $auditorName = (string) ($auditorInfo['name'] ?? ''); if ($action === 'approve') { $text = "【处方审核】您开具的处方已通过审核。\n编号:{$sn}\n患者:{$patient}\n审核人:{$auditorName}"; if (trim($remark) !== '') { $text .= "\n备注:" . trim($remark); } } else { $text = "【处方审核】您开具的处方已被驳回并已作废。\n编号:{$sn}\n患者:{$patient}\n审核人:{$auditorName}\n意见:" . trim($remark); } $result = WechatWorkAppMessageService::sendTextToUser($wxId, $text); if (empty($result['ok'])) { Log::warning('处方审核企业微信通知失败: ' . ($result['message'] ?? '')); } return $result; } catch (\Throwable $e) { Log::error('处方审核企业微信通知异常: ' . $e->getMessage()); return ['ok' => false, 'message' => '企业微信通知异常:' . $e->getMessage()]; } } /** * 取出并清空最近一次审核后的企微通知结果(供接口返回给前端提示) * * @return array{ok: bool, message?: string, errcode?: int}|null */ public static function consumeLastAuditWecomNotify(): ?array { $v = self::$lastAuditWecomNotify; self::$lastAuditWecomNotify = null; return $v; } /** * 根据诊单ID获取处方列表 */ public static function listByDiagnosis(int $diagnosisId): array { return Prescription::where('diagnosis_id', $diagnosisId) ->whereNull('delete_time') ->order('id', 'desc') ->select() ->toArray(); } /** * 根据预约ID获取处方(带权限检查) */ public static function getByAppointment(int $appointmentId, int $viewerAdminId, array $viewerAdminInfo): ?array { self::$error = ''; $row = Prescription::where('appointment_id', $appointmentId) ->where('creator_id',$viewerAdminId) ->whereNull('delete_time') ->order('id', 'desc') ->find(); if (!$row) { return null; } // 权限检查:只返回当前用户有权限查看的处方 if (!self::canViewPrescription($row, $viewerAdminId, $viewerAdminInfo)) { self::setError('无权限查看此处方'); return null; } return $row->toArray(); } /** * 挂号标记「完成」后自动生成处方:无药材配方,is_system_auto=1,其余字段与常规开方一致(患者/诊单来自预约关联诊单)。 * 若该预约已有未作废处方、或同日同诊单同医师已存在未作废处方,则跳过(不抛错)。 * * @return int|null 新建处方 id;跳过返回 null */ public static function createSystemAutoFromCompletedAppointment(int $appointmentId): ?int { if ($appointmentId <= 0) { return null; } $appointment = Appointment::find($appointmentId); if (!$appointment) { return null; } $diagnosisId = (int) ($appointment->patient_id ?? 0); if ($diagnosisId <= 0) { Log::info('createSystemAutoFromCompletedAppointment: no diagnosis (patient_id), skip appt=' . $appointmentId); return null; } $doctorId = (int) ($appointment->doctor_id ?? 0); if ($doctorId <= 0) { return null; } $dupAppt = Prescription::where('appointment_id', $appointmentId) ->where('void_status', 0) ->whereNull('delete_time') ->find(); if ($dupAppt) { return null; } $diagnosis = Diagnosis::find($diagnosisId); if (!$diagnosis) { self::setError('诊单不存在'); return null; } $apptDateRaw = $appointment->appointment_date ?? ''; $dateYmd = is_string($apptDateRaw) && preg_match('/^\d{4}-\d{2}-\d{2}/', trim($apptDateRaw)) ? substr(trim($apptDateRaw), 0, 10) : self::normalizePrescriptionDate(date('Y-m-d')); if (!self::assertUniquePrescriptionPerDiagnosisDay($diagnosisId, $doctorId, $dateYmd, null)) { Log::info("createSystemAutoFromCompletedAppointment: unique rule skip diagnosis={$diagnosisId} doctor={$doctorId} date={$dateYmd}"); return null; } $sn = self::generateSn(); while (Prescription::where('sn', $sn)->find()) { $sn = self::generateSn(); } $clinical = trim((string) ($diagnosis->symptoms ?? '')); if ($clinical === '') { $clinical = '就诊完成系统生成(暂无药材配方,请医师补充诊断与药材)'; } $doctorName = (string) (Admin::where('id', $doctorId)->value('name') ?? ''); $assistantIdForRx = (int) ($diagnosis->assistant_id ?? 0); $visitNo = '1K' . str_pad((string) $diagnosisId, 8, '0', STR_PAD_LEFT); $herbs = []; $data = [ 'sn' => $sn, 'prescription_name' => '系统代开', 'prescription_type' => '浓缩水丸', 'dosage_amount' => 1.0, 'dosage_unit' => 'g', 'dosage_bag_count' => 1, 'need_decoction' => 0, 'bags_per_dose' => 1, 'diagnosis_id' => $diagnosisId, 'appointment_id' => $appointmentId, 'patient_id' => 0, 'patient_name' => (string) ($diagnosis->patient_name ?? ''), 'gender' => (int) ($diagnosis->gender ?? 0), 'age' => (int) ($diagnosis->age ?? 0), 'phone' => (string) ($diagnosis->phone ?? ''), 'visit_no' => $visitNo, 'prescription_date' => $dateYmd, 'pulse' => (string) ($diagnosis->pulse ?? ''), 'pulse_condition' => '', 'tongue' => (string) ($diagnosis->tongue ?? ''), 'tongue_image' => '', 'clinical_diagnosis' => $clinical, 'case_record' => [], 'herbs' => $herbs, 'dose_count' => 1, 'dose_unit' => '剂', 'usage_days' => 7, 'times_per_day' => 2, 'usage_instruction' => '', 'usage_time' => '饭后', 'usage_way' => '温水送服', 'dietary_taboo' => '', 'usage_notes' => '', 'amount' => 0.0, 'doctor_name' => $doctorName, 'doctor_signature' => '', 'template_id' => 0, 'is_shared' => 0, 'is_system_auto' => 1, 'visible_role_ids' => self::normalizeVisibleRoleIds([]), 'audit_status' => 0, 'audit_time' => null, 'audit_by' => null, 'audit_by_name' => '', 'audit_remark' => '', 'creator_id' => $doctorId, 'assistant_id' => $assistantIdForRx, ]; $prescription = new Prescription(); $prescription->save($data); return (int) $prescription->id; } /** * 作废处方 */ public static function void(int $id, int $adminId, string $adminName): bool { $row = Prescription::find($id); if (!$row) { self::setError('处方不存在'); return false; } if ((int)($row->void_status ?? 0) === 1) { self::setError('该处方已作废'); return false; } $rxId = (int) ($row->id ?? 0); $bizCount = (int) PrescriptionOrder::where('prescription_id', $rxId) ->whereNull('delete_time') ->where('fulfillment_status', '<>', 4) ->count(); if ($bizCount > 0) { self::setError('该处方已存在业务订单,无法作废'); return false; } $row->void_status = 1; $row->void_time = time(); $row->void_by = $adminId; $row->void_by_name = $adminName; return $row->save(); } }