Files
2026-09-08 11:40:15 +08:00

474 lines
17 KiB
PHP

<?php
declare(strict_types=1);
namespace app\adminapi\controller\firstvisit;
use app\adminapi\controller\BaseAdminController;
use app\adminapi\lists\firstvisit\MyPatientLists;
use app\adminapi\lists\firstvisit\MyPatientOrderLists;
use app\adminapi\lists\firstvisit\MyPatientProgressLists;
use app\adminapi\logic\auth\AuthLogic;
use app\adminapi\logic\doctor\AppointmentLogic;
use app\adminapi\logic\firstvisit\MyPatientLogic;
use app\adminapi\logic\tcm\DiagnosisLogic;
use app\adminapi\logic\tcm\PrescriptionOrderLogic;
use app\adminapi\validate\doctor\AppointmentValidate;
use app\adminapi\validate\tcm\DiagnosisValidate;
use app\adminapi\validate\tcm\PrescriptionOrderValidate;
use app\common\model\doctor\Appointment;
use app\common\model\tcm\PrescriptionOrder;
class MyPatientController extends BaseAdminController
{
private const LIST_PERMISSION = 'firstvisit.myPatient/lists';
private string $orderGuardError = '订单不存在或无权操作';
public function lists()
{
if (!$this->hasPagePermission()) {
return $this->fail('权限不足,无法访问我的患者');
}
return $this->dataLists(new MyPatientLists());
}
/** 当前角色/部门患者范围内的处方业务订单。 */
public function orders()
{
if (!$this->hasPagePermission()) {
return $this->fail('权限不足,无法查看患者订单');
}
return $this->dataLists(new MyPatientOrderLists());
}
/** 当前角色/部门患者范围内的挂号面诊进度。 */
public function progress()
{
if (!$this->hasPagePermission()) {
return $this->fail('权限不足,无法查看面诊进度');
}
return $this->dataLists(new MyPatientProgressLists());
}
/** 当前账号数据范围内可被指派的医助。 */
public function assistants()
{
if (!$this->hasPagePermission() || !$this->hasOriginalPermission('tcm.diagnosis/assign')) {
return $this->fail('权限不足,无法获取医助列表');
}
return $this->data(DiagnosisLogic::getAssistants($this->adminId, $this->adminInfo));
}
/** 从“我的患者”指派医助,先校验患者行级数据范围和目标医助范围。 */
public function assign()
{
if (!$this->hasPagePermission() || !$this->hasOriginalPermission('tcm.diagnosis/assign')) {
return $this->fail('权限不足,无法指派患者');
}
$params = $this->request->post();
$diagnosisId = (int) ($params['id'] ?? 0);
$assistantId = (int) ($params['assistant_id'] ?? 0);
if (!MyPatientLogic::canAccessDiagnosis($diagnosisId, $this->adminId, $this->adminInfo)) {
return $this->fail('患者不存在或无权操作');
}
if ($assistantId <= 0 || !$this->canAssignToAssistant($assistantId)) {
return $this->fail('所选医助不在当前可指派范围内');
}
$result = DiagnosisLogic::assign([
'id' => $diagnosisId,
'assistant_id' => $assistantId,
'is_inherit' => (int) ($params['is_inherit'] ?? 0) === 1 ? 1 : 0,
]);
if ($result === false) {
return $this->fail(DiagnosisLogic::getError());
}
return $this->success('指派成功');
}
/** 从“我的患者”补全身份证,复用诊单身份证校验和年龄计算。 */
public function fillIdCard()
{
if (!$this->hasPagePermission() || !$this->hasOriginalPermission('tcm.diagnosis/edit')) {
return $this->fail('权限不足,无法补全身份证');
}
$params = (new DiagnosisValidate())->post()->goCheck('fillIdCard');
$diagnosisId = (int) ($params['id'] ?? 0);
if (!MyPatientLogic::canAccessDiagnosis($diagnosisId, $this->adminId, $this->adminInfo)) {
return $this->fail('患者不存在或无权操作');
}
$duplicate = DiagnosisLogic::checkIdCard([
'id' => $diagnosisId,
'id_card' => trim((string) ($params['id_card'] ?? '')),
]);
if (!empty($duplicate['exists'])) {
return $this->fail((string) ($duplicate['message'] ?? '该身份证号已存在'));
}
$result = DiagnosisLogic::fillIdCard($params);
if ($result === false) {
return $this->fail(DiagnosisLogic::getError());
}
return $this->success('补全成功,年龄已自动更新');
}
/** 当前患者范围内的订单详情;仍要求原订单详情权限。 */
public function orderDetail()
{
$params = (new PrescriptionOrderValidate())->get()->goCheck('detail');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/detail') === null) {
return $this->fail($this->orderGuardError);
}
$detail = PrescriptionOrderLogic::detail((int) $params['id'], $this->adminId, $this->adminInfo);
if ($detail === null) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->data($detail);
}
/** 编辑当前患者范围内的订单,参数只允许原编辑表单支持的字段。 */
public function orderEdit()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('edit');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/edit') === null) {
return $this->fail($this->orderGuardError);
}
if ((float) ($params['amount'] ?? 0) < 0) {
return $this->fail('订单金额不能为负数');
}
$params = $this->onlyParams($params, [
'id', 'recipient_name', 'recipient_phone', 'shipping_province', 'shipping_city',
'shipping_district', 'shipping_address', 'is_follow_up', 'medication_days',
'dose_unit', 'dose_count', 'prev_staff', 'service_channel', 'service_package',
'tracking_number', 'express_company', 'fee_type', 'amount', 'remark_extra',
'remark_assistant', 'pay_order_ids', 'internal_cost',
]);
$result = PrescriptionOrderLogic::edit($params, $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('保存成功', $result);
}
public function orderAuditPrescription()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('auditPrescription');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/auditPrescription') === null) {
return $this->fail($this->orderGuardError);
}
$result = PrescriptionOrderLogic::auditPrescription(
(int) $params['id'],
(string) $params['action'],
(string) ($params['remark'] ?? ''),
$this->adminId,
$this->adminInfo
);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('操作成功', $result);
}
public function orderRevokeRxAudit()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('detail');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/auditPrescription') === null) {
return $this->fail($this->orderGuardError);
}
$result = PrescriptionOrderLogic::revokeRxAudit((int) $params['id'], $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('处方审核已撤回', $result);
}
public function orderAuditPayment()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('auditPayment');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/auditPayment') === null) {
return $this->fail($this->orderGuardError);
}
$result = PrescriptionOrderLogic::auditPaymentSlip(
(int) $params['id'],
(string) $params['action'],
(string) ($params['remark'] ?? ''),
$this->adminId,
$this->adminInfo
);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('操作成功', $result);
}
public function orderRevokePayAudit()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('detail');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/auditPayment') === null) {
return $this->fail($this->orderGuardError);
}
$result = PrescriptionOrderLogic::revokePayAudit((int) $params['id'], $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('支付单审核已撤回', $result);
}
public function orderDdcode()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('ddcode');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/ddcode') === null) {
return $this->fail($this->orderGuardError);
}
$result = PrescriptionOrderLogic::ddcode(
(int) $params['id'],
(string) ($params['express_company'] ?? 'auto'),
(string) $params['tracking_number'],
$this->adminId,
$this->adminInfo
);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('快递单号已保存', $result);
}
public function orderShip()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('ship');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/ship') === null) {
return $this->fail($this->orderGuardError);
}
$result = PrescriptionOrderLogic::ship(
(int) $params['id'],
(string) ($params['express_company'] ?? 'auto'),
(string) ($params['tracking_number'] ?? ''),
(string) ($params['ship_mode'] ?? 'gancao'),
$this->adminId,
$this->adminInfo
);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('发货成功', $result);
}
public function orderAddPayOrder()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('addPayOrder');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/addPayOrder') === null) {
return $this->fail($this->orderGuardError);
}
$params = $this->onlyParams($params, [
'id', 'order_type', 'pay_amount', 'pay_remark', 'completion_request', 'pay_create_type',
]);
$result = PrescriptionOrderLogic::addPayOrder($params, $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('新增支付单成功', $result);
}
public function orderComplete()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('complete');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/complete') === null) {
return $this->fail($this->orderGuardError);
}
$result = PrescriptionOrderLogic::complete(
(int) $params['id'],
$this->adminId,
$this->adminInfo,
(int) $params['fulfillment_status']
);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('操作成功', $result);
}
public function orderRefund()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('refund');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/refund') === null) {
return $this->fail($this->orderGuardError);
}
$rawRefundAmount = $params['refund_amount'] ?? null;
$refundAmount = ($rawRefundAmount === null || $rawRefundAmount === '')
? null
: round((float) $rawRefundAmount, 2);
$result = PrescriptionOrderLogic::refund(
(int) $params['id'],
(string) ($params['reason'] ?? ''),
$this->adminId,
$this->adminInfo,
$refundAmount
);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('退款成功', $result);
}
public function orderWithdraw()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('withdraw');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/withdraw') === null) {
return $this->fail($this->orderGuardError);
}
$result = PrescriptionOrderLogic::withdraw((int) $params['id'], $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('已撤回', $result);
}
public function orderUploadToPharmacy()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('uploadToPharmacy');
if ($this->guardOrder((int) $params['id'], 'tcm.prescriptionOrder/uploadToPharmacy') === null) {
return $this->fail($this->orderGuardError);
}
$result = PrescriptionOrderLogic::uploadToPharmacy((int) $params['id'], $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('药方上传成功', $result);
}
/** 从“我的患者”页面创建挂号,写操作复用原逻辑但先做患者行级校验。 */
public function createAppointment()
{
if (!$this->hasPagePermission()) {
return $this->fail('权限不足,无法创建挂号');
}
$params = (new AppointmentValidate())->post()->goCheck('create');
$diagnosisId = (int) ($params['patient_id'] ?? 0);
if (!MyPatientLogic::canAccessDiagnosis($diagnosisId, $this->adminId, $this->adminInfo)) {
return $this->fail('患者不存在或无权操作');
}
$params['assistant_id'] = $this->adminId;
$result = AppointmentLogic::create($params, $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(AppointmentLogic::getError());
}
return $this->success('挂号成功', $result);
}
/** 从“我的患者”页面取消挂号,按挂号所属诊单再次校验数据范围。 */
public function cancelAppointment()
{
if (!$this->hasPagePermission()) {
return $this->fail('权限不足,无法取消挂号');
}
$params = (new AppointmentValidate())->post()->goCheck('cancel');
$appointment = Appointment::findOrEmpty((int) ($params['id'] ?? 0));
if ($appointment->isEmpty()) {
return $this->fail('挂号记录不存在');
}
if (!MyPatientLogic::canAccessDiagnosis((int) $appointment->patient_id, $this->adminId, $this->adminInfo)) {
return $this->fail('患者不存在或无权操作');
}
$result = AppointmentLogic::cancel($params, $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(AppointmentLogic::getError());
}
return $this->success('取消挂号成功');
}
private function hasPagePermission(): bool
{
if ((int) ($this->adminInfo['root'] ?? 0) === 1) {
return true;
}
return in_array(self::LIST_PERMISSION, AuthLogic::getAuthByAdminId($this->adminId), true);
}
private function hasOriginalPermission(string $permission): bool
{
if ((int) ($this->adminInfo['root'] ?? 0) === 1) {
return true;
}
return in_array($permission, AuthLogic::getAuthByAdminId($this->adminId), true);
}
private function guardOrder(int $orderId, string $permission): ?PrescriptionOrder
{
$this->orderGuardError = '订单不存在或无权操作';
if (!$this->hasPagePermission() || !$this->hasOriginalPermission($permission) || $orderId <= 0) {
return null;
}
$order = PrescriptionOrder::where('id', $orderId)->whereNull('delete_time')->find();
if ($order === null) {
return null;
}
if (!MyPatientLogic::canAccessDiagnosis((int) $order->diagnosis_id, $this->adminId, $this->adminInfo)) {
return null;
}
return $order;
}
private function canAssignToAssistant(int $assistantId): bool
{
foreach (DiagnosisLogic::getAssistants($this->adminId, $this->adminInfo) as $assistant) {
if ((int) ($assistant['id'] ?? 0) === $assistantId) {
return true;
}
}
return false;
}
/** @param array<string,mixed> $params @param array<int,string> $keys */
private function onlyParams(array $params, array $keys): array
{
return array_intersect_key($params, array_flip($keys));
}
}