From b57304d9917beab4671442a0018c1c3a2d681640 Mon Sep 17 00:00:00 2001
From: liusheng <337615773@qq.com>
Date: 星期四, 23 四月 2026 15:09:09 +0800
Subject: [PATCH] 提交

---
 smartor/src/main/java/com/smartor/statemachine/handler/InhospStateHandler.java           |   26 
 smartor/src/main/java/com/smartor/statemachine/handler/impl/DischargeHandler.java        |  103 +++
 smartor/src/main/java/com/smartor/statemachine/handler/impl/InHospitalHandler.java       |   94 ++
 smartor/src/main/java/com/smartor/statemachine/InhospStateMachineService.java            |   91 ++
 ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap_BindingStub.java         |  138 ++++
 smartor/src/main/java/com/smartor/service/impl/SubtaskSmsServiceImpl.java                |   31 
 ruoyi-system/src/main/resources/mapper/system/SysUserDeptMapper.xml                      |  279 ++++++++
 smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java            |    2 
 smartor/src/main/java/com/smartor/statemachine/InhospStateMachineExample.java            |  182 +++++
 ruoyi-system/src/main/java/WebServiceClient/MessagingInsert.asmx                         |   66 +
 ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap12Stub.java               |  136 ++++
 smartor/src/main/java/com/smartor/common/enums/InhospStateEnum.java                      |  112 +++
 ruoyi-system/src/main/java/WebServiceClient/MessagingInsertLocator.java                  |  202 +++++
 ruoyi-system/src/main/java/WebServiceClient/MessagingInsert.java                         |   21 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserDeptMapper.java                |   78 ++
 smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java                    |    4 
 smartor/src/main/java/com/smartor/domain/ServiceSubtaskCountReq.java                     |    6 
 smartor/src/main/java/com/smartor/common/exception/StateTransitionException.java         |   23 
 smartor/src/main/java/com/smartor/statemachine/InhospStateMachine.java                   |  202 +++++
 smartor/src/main/java/com/smartor/statemachine/handler/impl/PreAdmissionHandler.java     |   67 +
 smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml                       |   23 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java |   14 
 ruoyi-system/src/main/java/WebServiceClient/MessagingInsertTestCase.java                 |   65 +
 smartor/src/main/java/com/smartor/domain/entity/ServiceSubtaskEntity.java                |   13 
 ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java          |    8 
 ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap_PortType.java            |   12 
 26 files changed, 1,981 insertions(+), 17 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java
index 92bfa3d..1c889c2 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java
@@ -515,17 +515,23 @@
     @ApiOperation("鑾峰彇闅忚缁熻姣斾緥")
     @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid")
     @PostMapping("/getSfStatistics")
-    public AjaxResult getSfStatistics(@RequestBody ServiceSubtaskCountReq serviceSubtaskCountReq) {
+    public Map<String, Object> getSfStatistics(@RequestBody ServiceSubtaskCountReq serviceSubtaskCountReq) {
         if (CollectionUtils.isEmpty(serviceSubtaskCountReq.getServiceType())) {
             return error("鏈嶅姟绫诲瀷涓嶈兘涓虹┖");
         }
+        Integer offset = PageUtils.getOffset(serviceSubtaskCountReq.getPageNum(), serviceSubtaskCountReq.getPageSize());
+        serviceSubtaskCountReq.setPageNum(offset);
+
         String followUpCountStyle = configService.selectConfigByKey("followUpCountStyle", serviceSubtaskCountReq.getOrgid());
         if (ObjectUtils.isNotEmpty(followUpCountStyle)) {
             serviceSubtaskCountReq.setFollowUpCountStyle(followUpCountStyle);
         } else {
             serviceSubtaskCountReq.setFollowUpCountStyle("1");
         }
-        return success(serviceSubtaskService.getSfStatistics(serviceSubtaskCountReq));
+        serviceSubtaskCountReq.setPageNum(null);
+        serviceSubtaskCountReq.setPageSize(null);
+        List<ServiceSubtaskStatistic> sfStatistics = serviceSubtaskService.getSfStatistics(serviceSubtaskCountReq);
+        return getDataTable4(CollectionUtils.isEmpty(sfStatistics) ? sfStatistics.size() : 0, serviceSubtaskService.getSfStatistics(serviceSubtaskCountReq));
     }
 
     /**
@@ -589,7 +595,6 @@
     }
 
 
-
     /**
      * 寤剁画鎶ょ悊缁熻
      */
@@ -607,9 +612,6 @@
         }
         return success(serviceSubtaskService.getContinueNurseCount(serviceSubtaskCotinueCountVO));
     }
-
-
-
 
 
     /**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
index b94b50f..598c620 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
@@ -105,6 +105,14 @@
         rspData.put("total", total);
         return rspData;
     }
+    protected Map<String, Object> getDataTable4(long total, Object object) {
+        Map<String, Object> rspData = new TreeMap<>();
+        rspData.put("code", HttpStatus.SUCCESS);
+        rspData.put("msg", "鏌ヨ鎴愬姛");
+        rspData.put("data", object);
+        rspData.put("total", total);
+        return rspData;
+    }
 
     /**
      * 杩斿洖鎴愬姛
diff --git a/ruoyi-system/src/main/java/WebServiceClient/MessagingInsert.asmx b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsert.asmx
new file mode 100644
index 0000000..423cb09
--- /dev/null
+++ b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsert.asmx
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wsdl:definitions xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
+  <wsdl:types>
+    <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
+      <s:element name="SMSMessageAccept">
+        <s:complexType>
+          <s:sequence>
+            <s:element minOccurs="0" maxOccurs="1" name="xmlReq" type="s:string" />
+          </s:sequence>
+        </s:complexType>
+      </s:element>
+      <s:element name="SMSMessageAcceptResponse">
+        <s:complexType>
+          <s:sequence>
+            <s:element minOccurs="1" maxOccurs="1" name="SMSMessageAcceptResult" type="s:int" />
+            <s:element minOccurs="0" maxOccurs="1" name="xmlResp" type="s:string" />
+          </s:sequence>
+        </s:complexType>
+      </s:element>
+    </s:schema>
+  </wsdl:types>
+  <wsdl:message name="SMSMessageAcceptSoapIn">
+    <wsdl:part name="parameters" element="tns:SMSMessageAccept" />
+  </wsdl:message>
+  <wsdl:message name="SMSMessageAcceptSoapOut">
+    <wsdl:part name="parameters" element="tns:SMSMessageAcceptResponse" />
+  </wsdl:message>
+  <wsdl:portType name="MessagingInsertSoap">
+    <wsdl:operation name="SMSMessageAccept">
+      <wsdl:input message="tns:SMSMessageAcceptSoapIn" />
+      <wsdl:output message="tns:SMSMessageAcceptSoapOut" />
+    </wsdl:operation>
+  </wsdl:portType>
+  <wsdl:binding name="MessagingInsertSoap" type="tns:MessagingInsertSoap">
+    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
+    <wsdl:operation name="SMSMessageAccept">
+      <soap:operation soapAction="http://tempuri.org/SMSMessageAccept" style="document" />
+      <wsdl:input>
+        <soap:body use="literal" />
+      </wsdl:input>
+      <wsdl:output>
+        <soap:body use="literal" />
+      </wsdl:output>
+    </wsdl:operation>
+  </wsdl:binding>
+  <wsdl:binding name="MessagingInsertSoap12" type="tns:MessagingInsertSoap">
+    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
+    <wsdl:operation name="SMSMessageAccept">
+      <soap12:operation soapAction="http://tempuri.org/SMSMessageAccept" style="document" />
+      <wsdl:input>
+        <soap12:body use="literal" />
+      </wsdl:input>
+      <wsdl:output>
+        <soap12:body use="literal" />
+      </wsdl:output>
+    </wsdl:operation>
+  </wsdl:binding>
+  <wsdl:service name="MessagingInsert">
+    <wsdl:port name="MessagingInsertSoap" binding="tns:MessagingInsertSoap">
+      <soap:address location="http://218.108.11.29:8081/MessagingInsert.asmx" />
+    </wsdl:port>
+    <wsdl:port name="MessagingInsertSoap12" binding="tns:MessagingInsertSoap12">
+      <soap12:address location="http://218.108.11.29:8081/MessagingInsert.asmx" />
+    </wsdl:port>
+  </wsdl:service>
+</wsdl:definitions>
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/WebServiceClient/MessagingInsert.java b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsert.java
new file mode 100644
index 0000000..bf446d3
--- /dev/null
+++ b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsert.java
@@ -0,0 +1,21 @@
+/**
+ * MessagingInsert.java
+ *
+ * This file was auto-generated from WSDL
+ * by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
+ */
+
+package WebServiceClient;
+
+public interface MessagingInsert extends javax.xml.rpc.Service {
+    public String getMessagingInsertSoap12Address();
+
+    public MessagingInsertSoap_PortType getMessagingInsertSoap12() throws javax.xml.rpc.ServiceException;
+
+    public MessagingInsertSoap_PortType getMessagingInsertSoap12(java.net.URL portAddress) throws javax.xml.rpc.ServiceException;
+    public String getMessagingInsertSoapAddress();
+
+    public MessagingInsertSoap_PortType getMessagingInsertSoap() throws javax.xml.rpc.ServiceException;
+
+    public MessagingInsertSoap_PortType getMessagingInsertSoap(java.net.URL portAddress) throws javax.xml.rpc.ServiceException;
+}
diff --git a/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertLocator.java b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertLocator.java
new file mode 100644
index 0000000..2c52b13
--- /dev/null
+++ b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertLocator.java
@@ -0,0 +1,202 @@
+/**
+ * MessagingInsertLocator.java
+ *
+ * This file was auto-generated from WSDL
+ * by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
+ */
+
+package WebServiceClient;
+
+public class MessagingInsertLocator extends org.apache.axis.client.Service implements MessagingInsert {
+
+    public MessagingInsertLocator() {
+    }
+
+
+    public MessagingInsertLocator(org.apache.axis.EngineConfiguration config) {
+        super(config);
+    }
+
+    public MessagingInsertLocator(String wsdlLoc, javax.xml.namespace.QName sName) throws javax.xml.rpc.ServiceException {
+        super(wsdlLoc, sName);
+    }
+
+    // Use to get a proxy class for MessagingInsertSoap12
+    private String MessagingInsertSoap12_address = "http://218.108.11.29:8081/MessagingInsert.asmx";
+
+    public String getMessagingInsertSoap12Address() {
+        return MessagingInsertSoap12_address;
+    }
+
+    // The WSDD service name defaults to the port name.
+    private String MessagingInsertSoap12WSDDServiceName = "MessagingInsertSoap12";
+
+    public String getMessagingInsertSoap12WSDDServiceName() {
+        return MessagingInsertSoap12WSDDServiceName;
+    }
+
+    public void setMessagingInsertSoap12WSDDServiceName(String name) {
+        MessagingInsertSoap12WSDDServiceName = name;
+    }
+
+    public MessagingInsertSoap_PortType getMessagingInsertSoap12() throws javax.xml.rpc.ServiceException {
+       java.net.URL endpoint;
+        try {
+            endpoint = new java.net.URL(MessagingInsertSoap12_address);
+        }
+        catch (java.net.MalformedURLException e) {
+            throw new javax.xml.rpc.ServiceException(e);
+        }
+        return getMessagingInsertSoap12(endpoint);
+    }
+
+    public MessagingInsertSoap_PortType getMessagingInsertSoap12(java.net.URL portAddress) throws javax.xml.rpc.ServiceException {
+        try {
+            MessagingInsertSoap12Stub _stub = new MessagingInsertSoap12Stub(portAddress, this);
+            _stub.setPortName(getMessagingInsertSoap12WSDDServiceName());
+            return _stub;
+        }
+        catch (org.apache.axis.AxisFault e) {
+            return null;
+        }
+    }
+
+    public void setMessagingInsertSoap12EndpointAddress(String address) {
+        MessagingInsertSoap12_address = address;
+    }
+
+
+    // Use to get a proxy class for MessagingInsertSoap
+    private String MessagingInsertSoap_address = "http://218.108.11.29:8081/MessagingInsert.asmx";
+
+    public String getMessagingInsertSoapAddress() {
+        return MessagingInsertSoap_address;
+    }
+
+    // The WSDD service name defaults to the port name.
+    private String MessagingInsertSoapWSDDServiceName = "MessagingInsertSoap";
+
+    public String getMessagingInsertSoapWSDDServiceName() {
+        return MessagingInsertSoapWSDDServiceName;
+    }
+
+    public void setMessagingInsertSoapWSDDServiceName(String name) {
+        MessagingInsertSoapWSDDServiceName = name;
+    }
+
+    public MessagingInsertSoap_PortType getMessagingInsertSoap() throws javax.xml.rpc.ServiceException {
+       java.net.URL endpoint;
+        try {
+            endpoint = new java.net.URL(MessagingInsertSoap_address);
+        }
+        catch (java.net.MalformedURLException e) {
+            throw new javax.xml.rpc.ServiceException(e);
+        }
+        return getMessagingInsertSoap(endpoint);
+    }
+
+    public MessagingInsertSoap_PortType getMessagingInsertSoap(java.net.URL portAddress) throws javax.xml.rpc.ServiceException {
+        try {
+            MessagingInsertSoap_BindingStub _stub = new MessagingInsertSoap_BindingStub(portAddress, this);
+            _stub.setPortName(getMessagingInsertSoapWSDDServiceName());
+            return _stub;
+        }
+        catch (org.apache.axis.AxisFault e) {
+            return null;
+        }
+    }
+
+    public void setMessagingInsertSoapEndpointAddress(String address) {
+        MessagingInsertSoap_address = address;
+    }
+
+    /**
+     * For the given interface, get the stub implementation.
+     * If this service has no port for the given interface,
+     * then ServiceException is thrown.
+     * This service has multiple ports for a given interface;
+     * the proxy implementation returned may be indeterminate.
+     */
+    public java.rmi.Remote getPort(Class serviceEndpointInterface) throws javax.xml.rpc.ServiceException {
+        try {
+            if (MessagingInsertSoap_PortType.class.isAssignableFrom(serviceEndpointInterface)) {
+                MessagingInsertSoap12Stub _stub = new MessagingInsertSoap12Stub(new java.net.URL(MessagingInsertSoap12_address), this);
+                _stub.setPortName(getMessagingInsertSoap12WSDDServiceName());
+                return _stub;
+            }
+            if (MessagingInsertSoap_PortType.class.isAssignableFrom(serviceEndpointInterface)) {
+                MessagingInsertSoap_BindingStub _stub = new MessagingInsertSoap_BindingStub(new java.net.URL(MessagingInsertSoap_address), this);
+                _stub.setPortName(getMessagingInsertSoapWSDDServiceName());
+                return _stub;
+            }
+        }
+        catch (Throwable t) {
+            throw new javax.xml.rpc.ServiceException(t);
+        }
+        throw new javax.xml.rpc.ServiceException("There is no stub implementation for the interface:  " + (serviceEndpointInterface == null ? "null" : serviceEndpointInterface.getName()));
+    }
+
+    /**
+     * For the given interface, get the stub implementation.
+     * If this service has no port for the given interface,
+     * then ServiceException is thrown.
+     */
+    public java.rmi.Remote getPort(javax.xml.namespace.QName portName, Class serviceEndpointInterface) throws javax.xml.rpc.ServiceException {
+        if (portName == null) {
+            return getPort(serviceEndpointInterface);
+        }
+        String inputPortName = portName.getLocalPart();
+        if ("MessagingInsertSoap12".equals(inputPortName)) {
+            return getMessagingInsertSoap12();
+        }
+        else if ("MessagingInsertSoap".equals(inputPortName)) {
+            return getMessagingInsertSoap();
+        }
+        else  {
+            java.rmi.Remote _stub = getPort(serviceEndpointInterface);
+            ((org.apache.axis.client.Stub) _stub).setPortName(portName);
+            return _stub;
+        }
+    }
+
+    public javax.xml.namespace.QName getServiceName() {
+        return new javax.xml.namespace.QName("http://tempuri.org/", "MessagingInsert");
+    }
+
+    private java.util.HashSet ports = null;
+
+    public java.util.Iterator getPorts() {
+        if (ports == null) {
+            ports = new java.util.HashSet();
+            ports.add(new javax.xml.namespace.QName("http://tempuri.org/", "MessagingInsertSoap12"));
+            ports.add(new javax.xml.namespace.QName("http://tempuri.org/", "MessagingInsertSoap"));
+        }
+        return ports.iterator();
+    }
+
+    /**
+    * Set the endpoint address for the specified port name.
+    */
+    public void setEndpointAddress(String portName, String address) throws javax.xml.rpc.ServiceException {
+
+if ("MessagingInsertSoap12".equals(portName)) {
+            setMessagingInsertSoap12EndpointAddress(address);
+        }
+        else
+if ("MessagingInsertSoap".equals(portName)) {
+            setMessagingInsertSoapEndpointAddress(address);
+        }
+        else
+{ // Unknown Port Name
+            throw new javax.xml.rpc.ServiceException(" Cannot set Endpoint Address for Unknown Port" + portName);
+        }
+    }
+
+    /**
+    * Set the endpoint address for the specified port name.
+    */
+    public void setEndpointAddress(javax.xml.namespace.QName portName, String address) throws javax.xml.rpc.ServiceException {
+        setEndpointAddress(portName.getLocalPart(), address);
+    }
+
+}
diff --git a/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap12Stub.java b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap12Stub.java
new file mode 100644
index 0000000..496334e
--- /dev/null
+++ b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap12Stub.java
@@ -0,0 +1,136 @@
+/**
+ * MessagingInsertSoap12Stub.java
+ * <p>
+ * This file was auto-generated from WSDL
+ * by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
+ */
+
+package WebServiceClient;
+
+public class MessagingInsertSoap12Stub extends org.apache.axis.client.Stub implements MessagingInsertSoap_PortType {
+    private java.util.Vector cachedSerClasses = new java.util.Vector();
+    private java.util.Vector cachedSerQNames = new java.util.Vector();
+    private java.util.Vector cachedSerFactories = new java.util.Vector();
+    private java.util.Vector cachedDeserFactories = new java.util.Vector();
+
+    static org.apache.axis.description.OperationDesc[] _operations;
+
+    static {
+        _operations = new org.apache.axis.description.OperationDesc[1];
+        _initOperationDesc1();
+    }
+
+    private static void _initOperationDesc1() {
+        org.apache.axis.description.OperationDesc oper;
+        org.apache.axis.description.ParameterDesc param;
+        oper = new org.apache.axis.description.OperationDesc();
+        oper.setName("SMSMessageAccept");
+        param = new org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("http://tempuri.org/", "xmlReq"), org.apache.axis.description.ParameterDesc.IN, new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"), String.class, false, false);
+        param.setOmittable(true);
+        oper.addParameter(param);
+        param = new org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("http://tempuri.org/", "SMSMessageAcceptResult"), org.apache.axis.description.ParameterDesc.OUT, new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "int"), int.class, false, false);
+        oper.addParameter(param);
+        param = new org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("http://tempuri.org/", "xmlResp"), org.apache.axis.description.ParameterDesc.OUT, new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"), String.class, false, false);
+        param.setOmittable(true);
+        oper.addParameter(param);
+        oper.setReturnType(org.apache.axis.encoding.XMLType.AXIS_VOID);
+        oper.setStyle(org.apache.axis.constants.Style.WRAPPED);
+        oper.setUse(org.apache.axis.constants.Use.LITERAL);
+        _operations[0] = oper;
+
+    }
+
+    public MessagingInsertSoap12Stub() throws org.apache.axis.AxisFault {
+        this(null);
+    }
+
+    public MessagingInsertSoap12Stub(java.net.URL endpointURL, javax.xml.rpc.Service service) throws org.apache.axis.AxisFault {
+        this(service);
+        super.cachedEndpoint = endpointURL;
+    }
+
+    public MessagingInsertSoap12Stub(javax.xml.rpc.Service service) throws org.apache.axis.AxisFault {
+        if (service == null) {
+            super.service = new org.apache.axis.client.Service();
+        } else {
+            super.service = service;
+        }
+        ((org.apache.axis.client.Service) super.service).setTypeMappingVersion("1.1");
+    }
+
+    protected org.apache.axis.client.Call createCall() throws java.rmi.RemoteException {
+        try {
+            org.apache.axis.client.Call _call = super._createCall();
+            if (super.maintainSessionSet) {
+                _call.setMaintainSession(super.maintainSession);
+            }
+            if (super.cachedUsername != null) {
+                _call.setUsername(super.cachedUsername);
+            }
+            if (super.cachedPassword != null) {
+                _call.setPassword(super.cachedPassword);
+            }
+            if (super.cachedEndpoint != null) {
+                _call.setTargetEndpointAddress(super.cachedEndpoint);
+            }
+            if (super.cachedTimeout != null) {
+                _call.setTimeout(super.cachedTimeout);
+            }
+            if (super.cachedPortName != null) {
+                _call.setPortName(super.cachedPortName);
+            }
+            java.util.Enumeration keys = super.cachedProperties.keys();
+            while (keys.hasMoreElements()) {
+                String key = (String) keys.nextElement();
+                _call.setProperty(key, super.cachedProperties.get(key));
+            }
+            return _call;
+        } catch (Throwable _t) {
+            throw new org.apache.axis.AxisFault("Failure trying to get the Call object", _t);
+        }
+    }
+
+    public Integer SMSMessageAccept(String xmlReq, javax.xml.rpc.holders.IntHolder SMSMessageAcceptResult, javax.xml.rpc.holders.StringHolder xmlResp) throws java.rmi.RemoteException {
+        Integer success = null;
+        if (super.cachedEndpoint == null) {
+            throw new org.apache.axis.NoEndPointException();
+        }
+        org.apache.axis.client.Call _call = createCall();
+        _call.setOperation(_operations[0]);
+        _call.setUseSOAPAction(true);
+        _call.setSOAPActionURI("http://tempuri.org/SMSMessageAccept");
+        _call.setEncodingStyle(null);
+        _call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
+        _call.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
+        _call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP12_CONSTANTS);
+        _call.setOperationName(new javax.xml.namespace.QName("http://tempuri.org/", "SMSMessageAccept"));
+
+        setRequestHeaders(_call);
+        setAttachments(_call);
+        try {
+            Object _resp = _call.invoke(new Object[]{xmlReq});
+
+            if (_resp instanceof java.rmi.RemoteException) {
+                throw (java.rmi.RemoteException) _resp;
+            } else {
+                extractAttachments(_call);
+                java.util.Map _output;
+                _output = _call.getOutputParams();
+                try {
+                    success = ((Integer) _output.get(new javax.xml.namespace.QName("http://tempuri.org/", "SMSMessageAcceptResult"))).intValue();
+                } catch (Exception _exception) {
+                    success = ((Integer) org.apache.axis.utils.JavaUtils.convert(_output.get(new javax.xml.namespace.QName("http://tempuri.org/", "SMSMessageAcceptResult")), int.class)).intValue();
+                }
+                try {
+                    xmlResp.value = (String) _output.get(new javax.xml.namespace.QName("http://tempuri.org/", "xmlResp"));
+                } catch (Exception _exception) {
+                    xmlResp.value = (String) org.apache.axis.utils.JavaUtils.convert(_output.get(new javax.xml.namespace.QName("http://tempuri.org/", "xmlResp")), String.class);
+                }
+            }
+        } catch (org.apache.axis.AxisFault axisFaultException) {
+            throw axisFaultException;
+        }
+        return success;
+    }
+
+}
diff --git a/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap_BindingStub.java b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap_BindingStub.java
new file mode 100644
index 0000000..1d6f833
--- /dev/null
+++ b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap_BindingStub.java
@@ -0,0 +1,138 @@
+/**
+ * MessagingInsertSoap_BindingStub.java
+ * <p>
+ * This file was auto-generated from WSDL
+ * by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
+ */
+
+package WebServiceClient;
+
+import org.apache.axis.client.Stub;
+
+public class MessagingInsertSoap_BindingStub extends Stub implements MessagingInsertSoap_PortType {
+    private java.util.Vector cachedSerClasses = new java.util.Vector();
+    private java.util.Vector cachedSerQNames = new java.util.Vector();
+    private java.util.Vector cachedSerFactories = new java.util.Vector();
+    private java.util.Vector cachedDeserFactories = new java.util.Vector();
+
+    static org.apache.axis.description.OperationDesc[] _operations;
+
+    static {
+        _operations = new org.apache.axis.description.OperationDesc[1];
+        _initOperationDesc1();
+    }
+
+    private static void _initOperationDesc1() {
+        org.apache.axis.description.OperationDesc oper;
+        org.apache.axis.description.ParameterDesc param;
+        oper = new org.apache.axis.description.OperationDesc();
+        oper.setName("SMSMessageAccept");
+        param = new org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("http://tempuri.org/", "xmlReq"), org.apache.axis.description.ParameterDesc.IN, new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"), String.class, false, false);
+        param.setOmittable(true);
+        oper.addParameter(param);
+        param = new org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("http://tempuri.org/", "SMSMessageAcceptResult"), org.apache.axis.description.ParameterDesc.OUT, new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "int"), int.class, false, false);
+        oper.addParameter(param);
+        param = new org.apache.axis.description.ParameterDesc(new javax.xml.namespace.QName("http://tempuri.org/", "xmlResp"), org.apache.axis.description.ParameterDesc.OUT, new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"), String.class, false, false);
+        param.setOmittable(true);
+        oper.addParameter(param);
+        oper.setReturnType(org.apache.axis.encoding.XMLType.AXIS_VOID);
+        oper.setStyle(org.apache.axis.constants.Style.WRAPPED);
+        oper.setUse(org.apache.axis.constants.Use.LITERAL);
+        _operations[0] = oper;
+
+    }
+
+    public MessagingInsertSoap_BindingStub() throws org.apache.axis.AxisFault {
+        this(null);
+    }
+
+    public MessagingInsertSoap_BindingStub(java.net.URL endpointURL, javax.xml.rpc.Service service) throws org.apache.axis.AxisFault {
+        this(service);
+        super.cachedEndpoint = endpointURL;
+    }
+
+    public MessagingInsertSoap_BindingStub(javax.xml.rpc.Service service) throws org.apache.axis.AxisFault {
+        if (service == null) {
+            super.service = new org.apache.axis.client.Service();
+        } else {
+            super.service = service;
+        }
+        ((org.apache.axis.client.Service) super.service).setTypeMappingVersion("1.1");
+    }
+
+    protected org.apache.axis.client.Call createCall() throws java.rmi.RemoteException {
+        try {
+            org.apache.axis.client.Call _call = super._createCall();
+            if (super.maintainSessionSet) {
+                _call.setMaintainSession(super.maintainSession);
+            }
+            if (super.cachedUsername != null) {
+                _call.setUsername(super.cachedUsername);
+            }
+            if (super.cachedPassword != null) {
+                _call.setPassword(super.cachedPassword);
+            }
+            if (super.cachedEndpoint != null) {
+                _call.setTargetEndpointAddress(super.cachedEndpoint);
+            }
+            if (super.cachedTimeout != null) {
+                _call.setTimeout(super.cachedTimeout);
+            }
+            if (super.cachedPortName != null) {
+                _call.setPortName(super.cachedPortName);
+            }
+            java.util.Enumeration keys = super.cachedProperties.keys();
+            while (keys.hasMoreElements()) {
+                String key = (String) keys.nextElement();
+                _call.setProperty(key, super.cachedProperties.get(key));
+            }
+            return _call;
+        } catch (Throwable _t) {
+            throw new org.apache.axis.AxisFault("Failure trying to get the Call object", _t);
+        }
+    }
+
+    public Integer SMSMessageAccept(String xmlReq, javax.xml.rpc.holders.IntHolder SMSMessageAcceptResult, javax.xml.rpc.holders.StringHolder xmlResp) throws java.rmi.RemoteException {
+        Integer success = null;
+        if (super.cachedEndpoint == null) {
+            throw new org.apache.axis.NoEndPointException();
+        }
+        org.apache.axis.client.Call _call = createCall();
+        _call.setOperation(_operations[0]);
+        _call.setUseSOAPAction(true);
+        _call.setSOAPActionURI("http://tempuri.org/SMSMessageAccept");
+        _call.setEncodingStyle(null);
+        _call.setProperty(org.apache.axis.client.Call.SEND_TYPE_ATTR, Boolean.FALSE);
+        _call.setProperty(org.apache.axis.AxisEngine.PROP_DOMULTIREFS, Boolean.FALSE);
+        _call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
+        _call.setOperationName(new javax.xml.namespace.QName("http://tempuri.org/", "SMSMessageAccept"));
+
+        setRequestHeaders(_call);
+        setAttachments(_call);
+        try {
+            Object _resp = _call.invoke(new Object[]{xmlReq});
+
+            if (_resp instanceof java.rmi.RemoteException) {
+                throw (java.rmi.RemoteException) _resp;
+            } else {
+                extractAttachments(_call);
+                java.util.Map _output;
+                _output = _call.getOutputParams();
+                try {
+                    success = ((Integer) _output.get(new javax.xml.namespace.QName("http://tempuri.org/", "SMSMessageAcceptResult"))).intValue();
+                } catch (Exception _exception) {
+                    success = ((Integer) org.apache.axis.utils.JavaUtils.convert(_output.get(new javax.xml.namespace.QName("http://tempuri.org/", "SMSMessageAcceptResult")), int.class)).intValue();
+                }
+                try {
+                    xmlResp.value = (String) _output.get(new javax.xml.namespace.QName("http://tempuri.org/", "xmlResp"));
+                } catch (Exception _exception) {
+                    xmlResp.value = (String) org.apache.axis.utils.JavaUtils.convert(_output.get(new javax.xml.namespace.QName("http://tempuri.org/", "xmlResp")), String.class);
+                }
+            }
+        } catch (org.apache.axis.AxisFault axisFaultException) {
+            throw axisFaultException;
+        }
+        return success;
+    }
+
+}
diff --git a/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap_PortType.java b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap_PortType.java
new file mode 100644
index 0000000..d1068ed
--- /dev/null
+++ b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertSoap_PortType.java
@@ -0,0 +1,12 @@
+/**
+ * MessagingInsertSoap_PortType.java
+ *
+ * This file was auto-generated from WSDL
+ * by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
+ */
+
+package WebServiceClient;
+
+public interface MessagingInsertSoap_PortType extends java.rmi.Remote {
+    public Integer SMSMessageAccept(String xmlReq, javax.xml.rpc.holders.IntHolder SMSMessageAcceptResult, javax.xml.rpc.holders.StringHolder xmlResp) throws java.rmi.RemoteException;
+}
diff --git a/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertTestCase.java b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertTestCase.java
new file mode 100644
index 0000000..283acb2
--- /dev/null
+++ b/ruoyi-system/src/main/java/WebServiceClient/MessagingInsertTestCase.java
@@ -0,0 +1,65 @@
+///**
+// * MessagingInsertTestCase.java
+// * <p>
+// * This file was auto-generated from WSDL
+// * by the Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
+// */
+//
+//package WebServiceClient;
+//
+//public class MessagingInsertTestCase extends junit.framework.TestCase {
+//    public MessagingInsertTestCase(String name) {
+//        super(name);
+//    }
+//
+//    public void testMessagingInsertSoap12WSDL() throws Exception {
+//        javax.xml.rpc.ServiceFactory serviceFactory = javax.xml.rpc.ServiceFactory.newInstance();
+//        java.net.URL url = new java.net.URL(new MessagingInsertLocator().getMessagingInsertSoap12Address() + "?WSDL");
+//        javax.xml.rpc.Service service = serviceFactory.createService(url, new MessagingInsertLocator().getServiceName());
+//        assertTrue(service != null);
+//    }
+//
+//    public void test1MessagingInsertSoap12SMSMessageAccept() throws Exception {
+//        MessagingInsertSoap12Stub binding;
+//        try {
+//            binding = (MessagingInsertSoap12Stub) new MessagingInsertLocator().getMessagingInsertSoap12();
+//        } catch (javax.xml.rpc.ServiceException jre) {
+//            if (jre.getLinkedCause() != null) jre.getLinkedCause().printStackTrace();
+//            throw new junit.framework.AssertionFailedError("JAX-RPC ServiceException caught: " + jre);
+//        }
+//        assertNotNull("binding is null", binding);
+//
+//        // Time out after a minute
+//        binding.setTimeout(60000);
+//
+//        // Test operation
+//        binding.SMSMessageAccept(new String(), new javax.xml.rpc.holders.IntHolder(), new javax.xml.rpc.holders.StringHolder());
+//        // TBD - validate results
+//    }
+//
+//    public void testMessagingInsertSoapWSDL() throws Exception {
+//        javax.xml.rpc.ServiceFactory serviceFactory = javax.xml.rpc.ServiceFactory.newInstance();
+//        java.net.URL url = new java.net.URL(new MessagingInsertLocator().getMessagingInsertSoapAddress() + "?WSDL");
+//        javax.xml.rpc.Service service = serviceFactory.createService(url, new MessagingInsertLocator().getServiceName());
+//        assertTrue(service != null);
+//    }
+//
+//    public void test2MessagingInsertSoapSMSMessageAccept() throws Exception {
+//        MessagingInsertSoap_BindingStub binding;
+//        try {
+//            binding = (MessagingInsertSoap_BindingStub) new MessagingInsertLocator().getMessagingInsertSoap();
+//        } catch (javax.xml.rpc.ServiceException jre) {
+//            if (jre.getLinkedCause() != null) jre.getLinkedCause().printStackTrace();
+//            throw new junit.framework.AssertionFailedError("JAX-RPC ServiceException caught: " + jre);
+//        }
+//        assertNotNull("binding is null", binding);
+//
+//        // Time out after a minute
+//        binding.setTimeout(60000);
+//
+//        // Test operation
+//        binding.SMSMessageAccept(new String(), new javax.xml.rpc.holders.IntHolder(), new javax.xml.rpc.holders.StringHolder());
+//        // TBD - validate results
+//    }
+//
+//}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserDeptMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserDeptMapper.java
new file mode 100644
index 0000000..020091d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserDeptMapper.java
@@ -0,0 +1,78 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.common.core.domain.entity.SysDept;
+import com.ruoyi.common.core.domain.entity.SysUserDept;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 銆愯濉啓鍔熻兘鍚嶇О銆慚apper鎺ュ彛
+ *
+ * @author lihu
+ * @date 2024-08-29
+ */
+@Mapper
+@Component("sysUserDeptSystemMapper")
+public interface SysUserDeptMapper {
+    /**
+     * 鏌ヨ銆愯濉啓鍔熻兘鍚嶇О銆�
+     *
+     * @param id 銆愯濉啓鍔熻兘鍚嶇О銆戜富閿�
+     * @return 銆愯濉啓鍔熻兘鍚嶇О銆�
+     */
+    public SysUserDept selectSysUserDeptById(Long id);
+
+    /**
+     * 鏌ヨ銆愯濉啓鍔熻兘鍚嶇О銆戝垪琛�
+     *
+     * @param sysUserDept 銆愯濉啓鍔熻兘鍚嶇О銆�
+     * @return 銆愯濉啓鍔熻兘鍚嶇О銆戦泦鍚�
+     */
+    public List<SysUserDept> selectSysUserDeptList(SysUserDept sysUserDept);
+
+    /**
+     * 鏂板銆愯濉啓鍔熻兘鍚嶇О銆�
+     *
+     * @param sysUserDept 銆愯濉啓鍔熻兘鍚嶇О銆�
+     * @return 缁撴灉
+     */
+    public int insertSysUserDept(SysUserDept sysUserDept);
+
+    /**
+     * 淇敼銆愯濉啓鍔熻兘鍚嶇О銆�
+     *
+     * @param sysUserDept 銆愯濉啓鍔熻兘鍚嶇О銆�
+     * @return 缁撴灉
+     */
+    public int updateSysUserDept(SysUserDept sysUserDept);
+
+    /**
+     * 鍒犻櫎銆愯濉啓鍔熻兘鍚嶇О銆�
+     *
+     * @param id 銆愯濉啓鍔熻兘鍚嶇О銆戜富閿�
+     * @return 缁撴灉
+     */
+    public int deleteSysUserDeptById(Long id);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ閮ㄩ棬淇℃伅
+     *
+     * @param id
+     * @return
+     */
+    public List<SysDept> selectDeptListByUserId(Long id);
+
+    /**
+     * 鎵归噺鍒犻櫎銆愯濉啓鍔熻兘鍚嶇О銆�
+     *
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteSysUserDeptByIds(Long[] ids);
+
+    public int deleteSysUserDeptByCode(SysUserDept sysUserDept);
+
+    public int updateSysUserDeptForSync(SysUserDept sysUserDept);
+}
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserDeptMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserDeptMapper.xml
new file mode 100644
index 0000000..3ebd0e5
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysUserDeptMapper.xml
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.system.mapper.SysUserDeptMapper">
+
+    <resultMap type="com.ruoyi.common.core.domain.entity.SysUserDept" id="SysUserDeptResult">
+        <result property="id" column="id"/>
+        <result property="orgid" column="orgid"/>
+        <result property="userId" column="user_id"/>
+        <result property="deptId" column="dept_id"/>
+        <result property="delFlag" column="del_flag"/>
+        <result property="deptCode" column="dept_code"/>
+        <result property="deptName" column="dept_name"/>
+        <result property="deptType" column="dept_type"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateTime" column="update_time"/>
+        <result property="campusid" column="campusid"/>
+    </resultMap>
+
+    <resultMap id="deptResult" type="com.ruoyi.common.core.domain.entity.SysDept">
+        <id property="deptId" column="dept_id"/>
+        <result property="parentId" column="parent_id"/>
+        <result property="deptName" column="dept_name"/>
+        <result property="ancestors" column="ancestors"/>
+        <result property="orderNum" column="order_num"/>
+        <result property="leader" column="leader"/>
+        <result property="status" column="dept_status"/>
+        <result property="campusid" column="campusid"/>
+    </resultMap>
+
+    <sql id="selectSysUserDeptVo">
+        select id,
+               user_id,
+               dept_id,
+               del_flag,
+               campusid,
+               orgid,
+               create_time,
+               update_time,
+               dept_code,
+               dept_name,
+               dept_type
+        from sys_user_dept
+    </sql>
+
+    <select id="selectSysUserDeptList" parameterType="com.ruoyi.common.core.domain.entity.SysUserDept"
+            resultMap="SysUserDeptResult">
+        <include refid="selectSysUserDeptVo"/>
+        where 1=1
+            and del_flag = 0
+            and orgid=#{orgid}
+            <if test="userId != null ">
+                and user_id = #{userId}
+            </if>
+            <if test="deptId != null ">
+                and dept_id = #{deptId}
+            </if>
+            <if test="delFlag != null ">
+                and del_flag = #{delFlag}
+            </if>
+            <if test="createTime != null ">
+                and create_time = #{createTime}
+            </if>
+            <if test="updateTime != null ">
+                and update_time = #{updateTime}
+            </if>
+            <if test="deptType != null ">
+                and dept_type = #{deptType}
+            </if>
+            <if test="deptCode != null ">
+                and dept_code = #{deptCode}
+            </if>
+            <if test="campusid != null ">
+                and campusid = #{campusid}
+            </if>
+    </select>
+
+    <select id="selectSysUserDeptById" parameterType="Long"
+            resultMap="SysUserDeptResult">
+        <include refid="selectSysUserDeptVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertSysUserDept" parameterType="com.ruoyi.common.core.domain.entity.SysUserDept"
+            useGeneratedKeys="true" keyProperty="id">
+        insert into sys_user_dept
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="userId != null">user_id,
+            </if>
+            <if test="deptId != null">dept_id,
+            </if>
+            <if test="delFlag != null ">
+                del_flag,
+            </if>
+            <if test="createTime != null ">
+                create_time,
+            </if>
+            <if test="updateTime != null ">
+                update_time,
+            </if>
+            <if test="deptType != null ">
+                dept_type,
+            </if>
+            <if test="deptCode != null ">
+                dept_code,
+            </if>
+            <if test="deptName != null ">
+                dept_name,
+            </if>
+            <if test="orgid != null ">
+                orgid,
+            </if>
+            <if test="userCode != null ">
+                user_code,
+            </if>
+            <if test="campusid != null ">
+                campusid,
+            </if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="userId != null">#{userId},
+            </if>
+            <if test="deptId != null">#{deptId},
+            </if>
+            <if test="delFlag != null ">
+                #{delFlag},
+            </if>
+            <if test="createTime != null ">
+                #{createTime},
+            </if>
+            <if test="updateTime != null ">
+                #{updateTime},
+            </if>
+            <if test="deptType != null ">
+                #{deptType},
+            </if>
+            <if test="deptCode != null ">
+                #{deptCode},
+            </if>
+            <if test="deptName != null ">
+                #{deptName},
+            </if>
+            <if test="orgid != null ">
+                #{orgid},
+            </if>
+            <if test="userCode != null ">
+                #{userCode},
+            </if>
+            <if test="campusid != null ">
+                #{campusid},
+            </if>
+        </trim>
+    </insert>
+
+    <update id="updateSysUserDept" parameterType="com.ruoyi.common.core.domain.entity.SysUserDept">
+        update sys_user_dept
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="userId != null">user_id =
+                #{userId},
+            </if>
+            <if test="deptId != null">dept_id =
+                #{deptId},
+            </if>
+            <if test="delFlag != null ">
+                del_flag = #{delFlag},
+            </if>
+            <if test="createTime != null ">
+                create_time = #{createTime},
+            </if>
+            <if test="updateTime != null ">
+                update_time = #{updateTime},
+            </if>
+            <if test="deptType != null ">
+                dept_type = #{deptType},
+            </if>
+            <if test="deptCode != null ">
+                dept_code = #{deptCode},
+            </if>
+            <if test="deptName != null ">
+                dept_name = #{deptName},
+            </if>
+            <if test="orgid != null ">
+                orgid = #{orgid},
+            </if>
+            <if test="campusid != null ">
+                campusid = #{campusid},
+            </if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <update id="deleteSysUserDeptById" parameterType="Long">
+        update sys_user_dept
+        <trim prefix="SET" suffixOverrides=",">
+            del_flag =1
+        </trim>
+        where id = #{id}
+    </update>
+
+    <select id="selectDeptListByUserId" resultMap="deptResult">
+        select d.dept_id,
+               d.dept_name,
+               d.parent_id,
+               d.ancestors,
+               d.dept_name,
+               d.order_num,
+               d.campusid,
+               d.leader,
+               d.orgid,
+               d.status as dept_status
+        from sys_dept d
+                 left join sys_user_dept ud on d.dept_code = ud.dept_code
+        where ud.user_id = #{userId}
+          and ud.del_flag = 0
+          and d.del_flag = 0
+    </select>
+
+    <update id="deleteSysUserDeptByIds" parameterType="String">
+        update sys_user_dept
+        <trim prefix="SET" suffixOverrides=",">
+            del_flag =1,
+            update_time = sysdate()
+        </trim>
+        where user_id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </update>
+
+    <update id="deleteSysUserDeptByCode" parameterType="String">
+        update sys_user_dept
+        <trim prefix="SET" suffixOverrides=",">
+            del_flag =1,
+            update_time = sysdate()
+        </trim>
+        where user_id =#{userId} and dept_code=#{deptCode}
+    </update>
+
+    <update id="updateSysUserDeptForSync" parameterType="com.ruoyi.common.core.domain.entity.SysUserDept">
+        update sys_user_dept
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="deptId != null">dept_id =
+                #{deptId},
+            </if>
+            <if test="delFlag != null ">
+                del_flag = #{delFlag},
+            </if>
+            <if test="createTime != null ">
+                create_time = #{createTime},
+            </if>
+            <if test="updateTime != null ">
+                update_time = #{updateTime},
+            </if>
+            <if test="deptType != null ">
+                dept_type = #{deptType},
+            </if>
+            <if test="deptCode != null ">
+                dept_code = #{deptCode},
+            </if>
+            <if test="deptName != null ">
+                dept_name = #{deptName},
+            </if>
+            <if test="orgid != null ">
+                orgid = #{orgid},
+            </if>
+            <if test="campusid != null ">
+                campusid = #{campusid},
+            </if>
+        </trim>
+        where user_id =#{userId}
+        <if test="orgid != null and orgid != ''">
+            and orgid = #{orgid}
+        </if>
+        <if test="campusid != null and campusid != ''">
+            and campusid = #{campusid}
+        </if>
+    </update>
+</mapper>
diff --git a/smartor/src/main/java/com/smartor/common/enums/InhospStateEnum.java b/smartor/src/main/java/com/smartor/common/enums/InhospStateEnum.java
new file mode 100644
index 0000000..6791191
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/common/enums/InhospStateEnum.java
@@ -0,0 +1,112 @@
+package com.smartor.common.enums;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 浣忛櫌鐘舵�佹灇涓�
+ * 
+ * @author smartor
+ */
+public enum InhospStateEnum {
+    
+    /**
+     * 棰勫叆闄㈢姸鎬�
+     */
+    PRE_ADMISSION("3", "棰勫叆闄�", new String[]{"0"}),
+    
+    /**
+     * 鍦ㄩ櫌鐘舵��
+     */
+    IN_HOSPITAL("0", "鍦ㄩ櫌", new String[]{"1"}),
+    
+    /**
+     * 鍑洪櫌鐘舵��
+     */
+    DISCHARGED("1", "鍑洪櫌", new String[]{});
+
+    /**
+     * 鐘舵�佺爜
+     */
+    private final String code;
+    
+    /**
+     * 鐘舵�佹弿杩�
+     */
+    private final String description;
+    
+    /**
+     * 鍏佽杞崲鐨勪笅涓�鐘舵�佺爜闆嗗悎
+     */
+    private final Set<String> allowedNextStates;
+
+    InhospStateEnum(String code, String description, String[] allowedNextStates) {
+        this.code = code;
+        this.description = description;
+        this.allowedNextStates = new HashSet<>(Arrays.asList(allowedNextStates));
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鍏佽杞崲鍒扮洰鏍囩姸鎬�
+     * 
+     * @param targetStateCode 鐩爣鐘舵�佺爜
+     * @return 鏄惁鍏佽杞崲
+     */
+    public boolean canTransitionTo(String targetStateCode) {
+        return allowedNextStates.contains(targetStateCode);
+    }
+
+    /**
+     * 鏍规嵁鐘舵�佺爜鑾峰彇鏋氫妇
+     * 
+     * @param code 鐘舵�佺爜
+     * @return 瀵瑰簲鐨勬灇涓�,濡傛灉涓嶅瓨鍦ㄨ繑鍥瀗ull
+     */
+    public static InhospStateEnum fromCode(String code) {
+        for (InhospStateEnum state : values()) {
+            if (state.getCode().equals(code)) {
+                return state;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 楠岃瘉鐘舵�佽浆鎹㈡槸鍚﹀悎娉�
+     * 
+     * @param currentStateCode 褰撳墠鐘舵�佺爜
+     * @param targetStateCode 鐩爣鐘舵�佺爜
+     * @return 鏄惁鍏佽杞崲
+     */
+    public static boolean isValidTransition(String currentStateCode, String targetStateCode) {
+        if (currentStateCode == null) {
+            // 鍒濆鐘舵�侊紝鍙厑璁稿垱寤洪鍏ラ櫌鎴栧湪闄�
+            return "3".equals(targetStateCode) || "0".equals(targetStateCode);
+        }
+        
+        InhospStateEnum currentState = fromCode(currentStateCode);
+        if (currentState == null) {
+            return false;
+        }
+        
+        return currentState.canTransitionTo(targetStateCode);
+    }
+
+    /**
+     * 鑾峰彇鎵�鏈夊厑璁哥殑涓嬩竴鐘舵��
+     * 
+     * @return 鍏佽鐨勪笅涓�鐘舵�侀泦鍚�
+     */
+    public Set<String> getAllowedNextStates() {
+        return new HashSet<>(allowedNextStates);
+    }
+}
diff --git a/smartor/src/main/java/com/smartor/common/exception/StateTransitionException.java b/smartor/src/main/java/com/smartor/common/exception/StateTransitionException.java
new file mode 100644
index 0000000..0dface5
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/common/exception/StateTransitionException.java
@@ -0,0 +1,23 @@
+package com.smartor.common.exception;
+
+/**
+ * 鐘舵�佽浆鎹㈠紓甯�
+ * 
+ * @author smartor
+ */
+public class StateTransitionException extends RuntimeException {
+    
+    private static final long serialVersionUID = 1L;
+
+    public StateTransitionException(String message) {
+        super(message);
+    }
+
+    public StateTransitionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public StateTransitionException(String currentState, String targetState) {
+        super(String.format("闈炴硶鐨勭姸鎬佽浆鎹�: 浠� [%s] 鍒� [%s]", currentState, targetState));
+    }
+}
diff --git a/smartor/src/main/java/com/smartor/domain/ServiceSubtaskCountReq.java b/smartor/src/main/java/com/smartor/domain/ServiceSubtaskCountReq.java
index 71d72c3..3ffd606 100644
--- a/smartor/src/main/java/com/smartor/domain/ServiceSubtaskCountReq.java
+++ b/smartor/src/main/java/com/smartor/domain/ServiceSubtaskCountReq.java
@@ -26,6 +26,12 @@
 
     private Integer visitCount;
 
+    /**
+     * rateDay 浠h〃鍑犲ぉ鍙婃椂鐜�
+     */
+    @ApiModelProperty(value = "鍑犲ぉ鍙婃椂鐜�")
+    private Integer rateDay;
+
     private Integer isVisitAgain;
 
     @ApiModelProperty(value = "寮傚父棰勮锛�0缁胯壊锛�1绾㈣壊锛�2榛勮壊")
diff --git a/smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java b/smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java
index 69e9f56..5f62fea 100644
--- a/smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java
+++ b/smartor/src/main/java/com/smartor/domain/ServiceSubtaskStatistic.java
@@ -167,6 +167,10 @@
     @Excel(name = " 鍙婃椂鐜� ")
     private Double rate = 0.0;
 
+    @ApiModelProperty(value = "瀹屾垚鐜�")
+    @Excel(name = " 瀹屾垚鐜� ")
+    private Double finishRate = 0.0;
+
     @ApiModelProperty(value = "棣栨闅忚鐜�")
     @Excel(name = " 棣栨闅忚鐜� ")
     private String followUpRate;
diff --git a/smartor/src/main/java/com/smartor/domain/entity/ServiceSubtaskEntity.java b/smartor/src/main/java/com/smartor/domain/entity/ServiceSubtaskEntity.java
index bf85d05..2a85c3d 100644
--- a/smartor/src/main/java/com/smartor/domain/entity/ServiceSubtaskEntity.java
+++ b/smartor/src/main/java/com/smartor/domain/entity/ServiceSubtaskEntity.java
@@ -97,6 +97,14 @@
     @ApiModelProperty(value = "鏈嶅姟绫诲瀷(1銆佺洃娴嬭瘎浼帮紱2銆佸嚭闄㈤殢璁匡紱3銆侀棬璇婇殢璁匡紱4銆佸鏁欏叧鎬�锛�5銆佸璇婄鐞嗭紱6銆佹弧鎰忓害璋冩煡锛�7銆佹偅鑰呮姤鍛婏紱 8銆佸叾浠栭�氱煡 9浣撴闅忚 10.鍖绘妧闅忚  11锛屽奖鍍忎笓绉戦殢璁�  12銆佸績鐢典笓绉戦殢璁匡紝 13涓撶闅忚)")
     private String serviceType;
 
+    @ApiModelProperty(value = "鏈嶅姟绫诲瀷闆嗗悎")
+    private List<Long> serviceTypeList;
+
+    /**
+     * rateDay 浠h〃鍑犲ぉ鍙婃椂鐜�
+     */
+    @ApiModelProperty(value = "鍑犲ぉ鍙婃椂鐜�")
+    private Integer rateDay;
     /**
      * 鎬у埆
      */
@@ -773,9 +781,4 @@
     @ApiModelProperty(value = "鍒嗙粍code闆嗗悎")
     private List<String> groupKeyList;
 
-//    /**
-//     * 鏃ユ湡闄愬埗 鐩墠鐢卞墠绔帶鍒�
-//     */
-//    @ApiModelProperty(value = "鏃ユ湡闄愬埗锛�0鍏ㄩ儴鏈嶅姟    1鎴褰撳墠鏃ユ湡")
-//    private String dateLimit;
 }
diff --git a/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
index 3cf792e..53b97f1 100644
--- a/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
+++ b/smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
@@ -2461,11 +2461,13 @@
         ssRate.setStarttime(serviceSubtaskCountReq.getStartTime());
         ssRate.setEndtime(serviceSubtaskCountReq.getEndTime());
         ssRate.setVisitCount(serviceSubtaskCountReq.getVisitCount());
+        ssRate.setServiceTypeList(serviceSubtaskCountReq.getServiceType());
         if (serviceSubtaskCountReq.getEndTime() != null && new Date().before(serviceSubtaskCountReq.getEndTime())) {
             ssRate.setEndtime(new Date());
         }
         ssRate.setGroupKey(groupKey);
         ssRate.setGroupKeyList(groupKeyList);
+        ssRate.setRateDay(serviceSubtaskCountReq.getRateDay());
         Map<String, Map<String, Object>> jsRates = new HashMap<>();
         if (!collect.isEmpty()) {
             jsRates = serviceSubtaskMapper.selectTimelyRateBatch(ssRate);
diff --git a/smartor/src/main/java/com/smartor/service/impl/SubtaskSmsServiceImpl.java b/smartor/src/main/java/com/smartor/service/impl/SubtaskSmsServiceImpl.java
new file mode 100644
index 0000000..2baadda
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/service/impl/SubtaskSmsServiceImpl.java
@@ -0,0 +1,31 @@
+package com.smartor.service.impl;
+
+import com.ruoyi.common.core.service.ISubtaskSmsService;
+import com.smartor.common.LSHospTokenUtil;
+import com.smartor.domain.ServiceSubtask;
+import com.smartor.mapper.ServiceSubtaskMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 鐭俊鍙戦�佽法妯″潡鏈嶅姟瀹炵幇锛堜緵 ruoyi-system 閫氳繃 SpringUtils 璋冪敤锛�
+ */
+@Service
+public class SubtaskSmsServiceImpl implements ISubtaskSmsService {
+
+    @Autowired
+    private ServiceSubtaskMapper serviceSubtaskMapper;
+
+    @Override
+    public void updateSubtaskVisitNotice(Long subId, Integer visitNotice) {
+        ServiceSubtask serviceSubtask = new ServiceSubtask();
+        serviceSubtask.setId(subId);
+        serviceSubtask.setVisitNotice(visitNotice);
+        serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
+    }
+
+    @Override
+    public String getLSHospToken(String orgid, String tokenUrl) {
+        return LSHospTokenUtil.getToken(orgid, tokenUrl);
+    }
+}
diff --git a/smartor/src/main/java/com/smartor/statemachine/InhospStateMachine.java b/smartor/src/main/java/com/smartor/statemachine/InhospStateMachine.java
new file mode 100644
index 0000000..644a2d2
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/statemachine/InhospStateMachine.java
@@ -0,0 +1,202 @@
+ package com.smartor.statemachine;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.smartor.common.enums.InhospStateEnum;
+import com.smartor.common.exception.StateTransitionException;
+import com.smartor.domain.PatMedInhosp;
+import com.smartor.service.IPatMedInhospService;
+import com.smartor.statemachine.handler.InhospStateHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 浣忛櫌鐘舵�佹満绠$悊鍣�
+ * 璐熻矗鐘舵�佽浆鎹㈢殑鍗忚皟鍜屽垎甯冨紡閿佺鐞�
+ *
+ * @author smartor
+ */
+@Slf4j
+@Component
+public class InhospStateMachine {
+
+    @Autowired
+    private IPatMedInhospService patMedInhospService;
+
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
+    @Autowired
+    private List<InhospStateHandler> handlers;
+
+    /**
+     * 鐘舵�佸鐞嗗櫒鏄犲皠琛�
+     */
+    private final Map<String, InhospStateHandler> handlerMap = new ConcurrentHashMap<>();
+
+    /**
+     * 鍒嗗竷寮忛攣瓒呮椂鏃堕棿锛堢锛�
+     */
+    private static final int LOCK_TIMEOUT = 10;
+
+    /**
+     * 鍒嗗竷寮忛攣鍓嶇紑
+     */
+    private static final String LOCK_KEY_PREFIX = "inhosp:state:lock:";
+
+    @PostConstruct
+    public void init() {
+        // 鍒濆鍖栧鐞嗗櫒鏄犲皠
+        if (CollectionUtils.isNotEmpty(handlers)) {
+            for (InhospStateHandler handler : handlers) {
+                handlerMap.put(handler.getStateCode(), handler);
+                log.info("銆怚nhospStateMachine銆戞敞鍐岀姸鎬佸鐞嗗櫒锛歿} -> {}",
+                        handler.getStateCode(), handler.getClass().getSimpleName());
+            }
+        }
+    }
+
+    /**
+     * 鎵ц鐘舵�佽浆鎹紙甯﹀垎甯冨紡閿侊級
+     *
+     * @param patMedInhosp 浣忛櫌璁板綍瀵硅薄
+     * @param targetState 鐩爣鐘舵��
+     * @return 鏄惁鎴愬姛
+     */
+    public boolean transitionState(PatMedInhosp patMedInhosp, String targetState) {
+        String serialnum = StringUtils.trim(patMedInhosp.getSerialnum());
+        String orgid = StringUtils.trim(patMedInhosp.getOrgid());
+
+        if (StringUtils.isEmpty(serialnum) || StringUtils.isEmpty(orgid)) {
+            log.error("銆怚nhospStateMachine銆憇erialnum鎴杘rgid涓虹┖锛屾棤娉曟墽琛岀姸鎬佽浆鎹�");
+            return false;
+        }
+
+        // 鐢熸垚鍒嗗竷寮忛攣key锛堜笉鍖呭惈state锛岄攣浣忔暣涓偅鑰呰褰曪級
+        String lockKey = LOCK_KEY_PREFIX + serialnum + ":" + orgid;
+        Boolean locked = false;
+
+        try {
+            // 灏濊瘯鑾峰彇鍒嗗竷寮忛攣
+            locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", LOCK_TIMEOUT, TimeUnit.SECONDS);
+
+            if (locked == null) {
+                log.warn("銆怚nhospStateMachine銆慠edis涓嶅彲鐢紝闄嶇骇涓烘棤閿佹墽琛岋紝serialnum={}, orgid={}", serialnum, orgid);
+                return executeStateTransition(patMedInhosp, targetState);
+            }
+
+            if (!Boolean.TRUE.equals(locked)) {
+                log.warn("銆怚nhospStateMachine銆戣幏鍙栧垎甯冨紡閿佸け璐ワ紝鍏朵粬绾跨▼姝e湪澶勭悊锛宻erialnum={}, orgid={}", serialnum, orgid);
+                return false;
+            }
+
+            // 鑾峰彇閿佹垚鍔燂紝鎵ц鐘舵�佽浆鎹�
+            return executeStateTransition(patMedInhosp, targetState);
+
+        } catch (Exception e) {
+            log.error("銆怚nhospStateMachine銆戠姸鎬佽浆鎹㈠紓甯革細serialnum={}, orgid={}, targetState={}, 閿欒锛歿}",
+                    serialnum, orgid, targetState, e.getMessage(), e);
+            return false;
+        } finally {
+            // 閲婃斁閿�
+            if (Boolean.TRUE.equals(locked)) {
+                try {
+                    redisTemplate.delete(lockKey);
+                    log.debug("銆怚nhospStateMachine銆戦噴鏀惧垎甯冨紡閿佹垚鍔燂紝lockKey={}", lockKey);
+                } catch (Exception e) {
+                    log.warn("銆怚nhospStateMachine銆戦噴鏀惧垎甯冨紡閿佸け璐ワ細lockKey={}, 閿欒锛歿}", lockKey, e.getMessage());
+                }
+            }
+        }
+    }
+
+    /**
+     * 鎵ц鐘舵�佽浆鎹㈤�昏緫
+     *
+     * @param patMedInhosp 浣忛櫌璁板綍瀵硅薄
+     * @param targetState 鐩爣鐘舵��
+     * @return 鏄惁鎴愬姛
+     */
+    private boolean executeStateTransition(PatMedInhosp patMedInhosp, String targetState) {
+        String serialnum = patMedInhosp.getSerialnum();
+        String orgid = patMedInhosp.getOrgid();
+
+        log.info("銆怚nhospStateMachine銆戝紑濮嬫墽琛岀姸鎬佽浆鎹細serialnum={}, orgid={}, targetState={}",
+                serialnum, orgid, targetState);
+
+        // 1. 鏌ヨ褰撳墠鐘舵��
+        PatMedInhosp query = new PatMedInhosp();
+        query.setSerialnum(StringUtils.trim(serialnum));
+        query.setOrgid(StringUtils.trim(orgid));
+        query.setPatno(StringUtils.trim(patMedInhosp.getPatno()));
+        query.setInhospstate(null); // 鏌ヨ鎵�鏈夌姸鎬�
+
+        List<PatMedInhosp> existingRecords = patMedInhospService.selectPatMedInhosp(query);
+        String currentState = null;
+
+        if (CollectionUtils.isNotEmpty(existingRecords)) {
+            // 濡傛灉瀛樺湪澶氭潯璁板綍锛屽彇鏈�鏂扮殑涓�鏉★紙鐞嗚涓婄粡杩囩姸鎬佹満鍚庝笉搴旇鏈夊鏉★級
+            currentState = existingRecords.get(0).getInhospstate();
+            log.info("銆怚nhospStateMachine銆戝綋鍓嶇姸鎬侊細{}", currentState);
+        }
+
+        // 2. 楠岃瘉鐘舵�佽浆鎹㈡槸鍚﹀悎娉�
+        if (!InhospStateEnum.isValidTransition(currentState, targetState)) {
+            log.error("銆怚nhospStateMachine銆戦潪娉曠殑鐘舵�佽浆鎹細浠� [{}] 鍒� [{}]锛宻erialnum={}, orgid={}",
+                    currentState, targetState, serialnum, orgid);
+            throw new StateTransitionException(currentState, targetState);
+        }
+
+        // 3. 鑾峰彇瀵瑰簲鐨勭姸鎬佸鐞嗗櫒
+        InhospStateHandler handler = handlerMap.get(targetState);
+        if (handler == null) {
+            log.error("銆怚nhospStateMachine銆戞湭鎵惧埌鐘舵�佸鐞嗗櫒锛歵argetState={}", targetState);
+            return false;
+        }
+
+        // 4. 鎵ц鐘舵�佸鐞�
+        boolean result = handler.handle(patMedInhosp);
+
+        if (result) {
+            log.info("銆怚nhospStateMachine銆戠姸鎬佽浆鎹㈡垚鍔燂細serialnum={}, orgid={}, {} -> {}",
+                    serialnum, orgid, currentState, targetState);
+        } else {
+            log.warn("銆怚nhospStateMachine銆戠姸鎬佽浆鎹㈠け璐ワ細serialnum={}, orgid={}, {} -> {}",
+                    serialnum, orgid, currentState, targetState);
+        }
+
+        return result;
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐘舵��
+     *
+     * @param serialnum 娴佹按鍙�
+     * @param orgid 鏈烘瀯ID
+     * @param patno 鎮h�呯紪鍙�
+     * @return 褰撳墠鐘舵�佺爜锛屽鏋滀笉瀛樺湪杩斿洖null
+     */
+    public String getCurrentState(String serialnum, String orgid, String patno) {
+        PatMedInhosp query = new PatMedInhosp();
+        query.setSerialnum(StringUtils.trim(serialnum));
+        query.setOrgid(StringUtils.trim(orgid));
+        query.setPatno(StringUtils.trim(patno));
+        query.setInhospstate(null);
+
+        List<PatMedInhosp> records = patMedInhospService.selectPatMedInhosp(query);
+
+        if (CollectionUtils.isEmpty(records)) {
+            return null;
+        }
+
+        return records.get(0).getInhospstate();
+    }
+}
diff --git a/smartor/src/main/java/com/smartor/statemachine/InhospStateMachineExample.java b/smartor/src/main/java/com/smartor/statemachine/InhospStateMachineExample.java
new file mode 100644
index 0000000..1d5f50a
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/statemachine/InhospStateMachineExample.java
@@ -0,0 +1,182 @@
+package com.smartor.statemachine;
+
+/**
+ * 浣忛櫌鐘舵�佹満浣跨敤绀轰緥
+ * 
+ * 鏈被灞曠ず濡備綍鍦ㄧ幇鏈変唬鐮佷腑闆嗘垚鐘舵�佹満锛屼粎渚涘弬鑰冿紝涓嶉渶瑕佽繍琛�
+ * 
+ * @author smartor
+ */
+public class InhospStateMachineExample {
+
+    /**
+     * 绀轰緥1: 鍦⊿erviceSLTDHealthcareRecordServiceImpl涓娇鐢ㄧ姸鎬佹満
+     * 
+     * 鍘熸柟娉曠鍚嶏細
+     * private void processPatientInhospInfo(ServiceSLTDInhospResDTO dto, PatArchive patArchive, String cry)
+     * 
+     * 鏀归�犳柟妗堬細鐢ㄧ姸鎬佹満鏇挎崲鍘熸湁鐨刬f-else閫昏緫
+     */
+    public void exampleUsageInService() {
+        /*
+        // 鍘熶唬鐮侊紙561-677琛岋級鏀归�犱负锛�
+        
+        @Autowired
+        private InhospStateMachineService stateMachineService;
+        
+        private void processPatientInhospInfo(ServiceSLTDInhospResDTO dto, PatArchive patArchive, String cry) {
+            // 鏋勫缓浣忛櫌璁板綍瀵硅薄锛堜繚鎸佸師鏈夐�昏緫锛�
+            PatMedInhosp patMedInhosp = buildPatientInhospInfo(dto, patArchive, cry);
+            
+            // 浣跨敤鐘舵�佹満澶勭悊鐘舵�佽浆鎹紙鏇挎崲鍘熸湁鐨勫ぇ娈礽f-else锛�
+            boolean success = stateMachineService.processStateChange(patMedInhosp, cry);
+            
+            if (success) {
+                log.info("銆恜rocessPatientInhospInfo銆戠姸鎬佽浆鎹㈡垚鍔燂細serialnum={}, cry={}", 
+                        patMedInhosp.getSerialnum(), cry);
+            } else {
+                log.warn("銆恜rocessPatientInhospInfo銆戠姸鎬佽浆鎹㈠け璐ユ垨璺宠繃锛歴erialnum={}, cry={}", 
+                        patMedInhosp.getSerialnum(), cry);
+            }
+        }
+        
+        // 浼樼偣锛�
+        // 1. 浠g爜浠�100+琛屽噺灏戝埌10琛�
+        // 2. 鐘舵�佽浆鎹㈤�昏緫娓呮櫚锛屾槗浜庣淮鎶�
+        // 3. 鑷姩鍔犲垎甯冨紡閿侊紝瑙e喅骞跺彂闂
+        // 4. 鐘舵�佹牎楠岃鍒欓泦涓鐞�
+        */
+    }
+
+    /**
+     * 绀轰緥2: 鐩存帴浣跨敤鐘舵�佹満鏈嶅姟API
+     */
+    public void exampleDirectUsage() {
+        /*
+        @Autowired
+        private InhospStateMachineService stateMachineService;
+        
+        // 澶勭悊棰勫叆闄�
+        PatMedInhosp preAdmission = new PatMedInhosp();
+        preAdmission.setSerialnum("202601290001");
+        preAdmission.setOrgid("HOS001");
+        preAdmission.setPatno("P001");
+        // ... 璁剧疆鍏朵粬瀛楁
+        
+        boolean result1 = stateMachineService.processPreAdmission(preAdmission);
+        
+        // 澶勭悊鍏ラ櫌锛堜細鑷姩浠庨鍏ラ櫌鐘舵�佽浆鎹級
+        PatMedInhosp inHospital = new PatMedInhosp();
+        inHospital.setSerialnum("202601290001");
+        inHospital.setOrgid("HOS001");
+        inHospital.setPatno("P001");
+        // ... 璁剧疆鍏朵粬瀛楁
+        
+        boolean result2 = stateMachineService.processInHospital(inHospital);
+        
+        // 澶勭悊鍑洪櫌锛堜細鑷姩浠庡叆闄㈢姸鎬佽浆鎹級
+        PatMedInhosp discharge = new PatMedInhosp();
+        discharge.setSerialnum("202601290001");
+        discharge.setOrgid("HOS001");
+        discharge.setPatno("P001");
+        // ... 璁剧疆鍏朵粬瀛楁
+        
+        boolean result3 = stateMachineService.processDischarge(discharge);
+        
+        // 鏌ヨ褰撳墠鐘舵��
+        String currentState = stateMachineService.getCurrentState("202601290001", "HOS001", "P001");
+        // currentState = "1" (鍑洪櫌鐘舵��)
+        */
+    }
+
+    /**
+     * 绀轰緥3: 鐘舵�佽浆鎹㈡牎楠�
+     */
+    public void exampleStateValidation() {
+        /*
+        // 闈炴硶杞崲绀轰緥1锛氶鍏ラ櫌鐩存帴鍒板嚭闄紙浼氭姏鍑哄紓甯革級
+        try {
+            PatMedInhosp discharge = new PatMedInhosp();
+            discharge.setSerialnum("202601290002");
+            discharge.setOrgid("HOS001");
+            discharge.setPatno("P002");
+            discharge.setInhospstate("3"); // 褰撳墠鏄鍏ラ櫌
+            
+            stateMachineService.processDischarge(discharge); // 灏濊瘯鐩存帴鍑洪櫌
+            
+        } catch (StateTransitionException e) {
+            log.error("鐘舵�佽浆鎹㈠け璐ワ細{}", e.getMessage());
+            // 杈撳嚭: 闈炴硶鐨勭姸鎬佽浆鎹�: 浠� [3] 鍒� [1]
+        }
+        
+        // 闈炴硶杞崲绀轰緥2锛氶噸澶嶅叆闄紙浼氳handler鎷掔粷锛�
+        PatMedInhosp inHospital1 = new PatMedInhosp();
+        inHospital1.setSerialnum("202601290003");
+        inHospital1.setOrgid("HOS001");
+        inHospital1.setPatno("P003");
+        
+        stateMachineService.processInHospital(inHospital1); // 绗竴娆″叆闄細鎴愬姛
+        
+        boolean result = stateMachineService.processInHospital(inHospital1); // 绗簩娆″叆闄細澶辫触
+        // result = false锛屾棩蹇楄緭鍑鸿鍛�
+        */
+    }
+
+    /**
+     * 鐘舵�佹満鏋舵瀯璇存槑
+     * 
+     * 1. 鐘舵�佹灇涓� (InhospStateEnum)
+     *    - 瀹氫箟鎵�鏈夌姸鎬佸強鍏佽鐨勮浆鎹㈣鍒�
+     *    - PRE_ADMISSION(3) -> IN_HOSPITAL(0) -> DISCHARGED(1)
+     * 
+     * 2. 鐘舵�佸鐞嗗櫒 (InhospStateHandler)
+     *    - PreAdmissionHandler: 澶勭悊棰勫叆闄㈤�昏緫
+     *    - InHospitalHandler: 澶勭悊鍏ラ櫌閫昏緫
+     *    - DischargeHandler: 澶勭悊鍑洪櫌閫昏緫
+     * 
+     * 3. 鐘舵�佹満绠$悊鍣� (InhospStateMachine)
+     *    - 鍗忚皟鐘舵�佽浆鎹�
+     *    - 绠$悊鍒嗗竷寮忛攣
+     *    - 楠岃瘉鐘舵�佸悎娉曟��
+     * 
+     * 4. 闂ㄩ潰鏈嶅姟 (InhospStateMachineService)
+     *    - 鎻愪緵渚挎嵎API
+     *    - 灏佽澶嶆潅閫昏緫
+     * 
+     * 5. 寮傚父澶勭悊 (StateTransitionException)
+     *    - 澶勭悊闈炴硶鐘舵�佽浆鎹�
+     */
+
+    /**
+     * 鏁版嵁搴撻厤鍚堝缓璁�
+     * 
+     * 1. 娣诲姞鍞竴绱㈠紩锛堝缓璁級
+     * CREATE UNIQUE INDEX uk_serialnum_orgid_state 
+     * ON pat_med_inhosp(serialnum, orgid, inhospstate);
+     * 
+     * 2. 鎴栬�呮洿涓ユ牸鐨勭害鏉燂紙纭繚涓�涓偅鑰呭彧鏈変竴鏉¤褰曪級
+     * CREATE UNIQUE INDEX uk_serialnum_orgid 
+     * ON pat_med_inhosp(serialnum, orgid);
+     * 
+     * 娉ㄦ剰锛氬鏋滀娇鐢ㄧ2绉嶇储寮曪紝闇�瑕佺‘淇濓細
+     * - 鐘舵�佸彉鏇村繀椤昏蛋鏇存柊锛堜笉鑳芥彃鍏ユ柊璁板綍锛�
+     * - 闇�瑕佹竻鐞嗗巻鍙插鐘舵�佽褰�
+     */
+
+    /**
+     * 娓愯繘寮忛泦鎴愭柟妗�
+     * 
+     * 闃舵1锛氬弻鍐欐ā寮忥紙鎺ㄨ崘锛�
+     * - 淇濈暀鍘熸湁浠g爜涓嶅彉
+     * - 鏂板鐘舵�佹満璋冪敤锛岃褰曟棩蹇楀姣�
+     * - 楠岃瘉鐘舵�佹満閫昏緫姝g‘鎬�
+     * 
+     * 闃舵2锛氱伆搴﹀垏鎹�
+     * - 閮ㄥ垎cry鍊艰蛋鐘舵�佹満
+     * - 瑙傚療鐢熶骇鐜琛ㄧ幇
+     * 
+     * 闃舵3锛氬畬鍏ㄨ縼绉�
+     * - 鍏ㄩ儴閫昏緫鍒囨崲鍒扮姸鎬佹満
+     * - 绉婚櫎鍘熸湁if-else浠g爜
+     */
+}
diff --git a/smartor/src/main/java/com/smartor/statemachine/InhospStateMachineService.java b/smartor/src/main/java/com/smartor/statemachine/InhospStateMachineService.java
new file mode 100644
index 0000000..3f3a5c1
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/statemachine/InhospStateMachineService.java
@@ -0,0 +1,91 @@
+package com.smartor.statemachine;
+
+import com.smartor.domain.PatMedInhosp;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 浣忛櫌鐘舵�佹満鏈嶅姟锛堥棬闈㈡ā寮忥級
+ * 鎻愪緵渚挎嵎鐨勭姸鎬佽浆鎹㈡柟娉�
+ * 
+ * @author smartor
+ */
+@Slf4j
+@Service
+public class InhospStateMachineService {
+
+    @Autowired
+    private InhospStateMachine stateMachine;
+
+    /**
+     * 澶勭悊棰勫叆闄�
+     * 
+     * @param patMedInhosp 浣忛櫌璁板綍瀵硅薄
+     * @return 鏄惁鎴愬姛
+     */
+    public boolean processPreAdmission(PatMedInhosp patMedInhosp) {
+        log.info("銆怚nhospStateMachineService銆戝鐞嗛鍏ラ櫌锛歴erialnum={}, orgid={}", 
+                patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+        return stateMachine.transitionState(patMedInhosp, "3");
+    }
+
+    /**
+     * 澶勭悊鍏ラ櫌
+     * 
+     * @param patMedInhosp 浣忛櫌璁板綍瀵硅薄
+     * @return 鏄惁鎴愬姛
+     */
+    public boolean processInHospital(PatMedInhosp patMedInhosp) {
+        log.info("銆怚nhospStateMachineService銆戝鐞嗗叆闄細serialnum={}, orgid={}", 
+                patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+        return stateMachine.transitionState(patMedInhosp, "0");
+    }
+
+    /**
+     * 澶勭悊鍑洪櫌
+     * 
+     * @param patMedInhosp 浣忛櫌璁板綍瀵硅薄
+     * @return 鏄惁鎴愬姛
+     */
+    public boolean processDischarge(PatMedInhosp patMedInhosp) {
+        log.info("銆怚nhospStateMachineService銆戝鐞嗗嚭闄細serialnum={}, orgid={}", 
+                patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+        return stateMachine.transitionState(patMedInhosp, "1");
+    }
+
+    /**
+     * 鏍规嵁cry鍙傛暟澶勭悊鐘舵�佽浆鎹�
+     * 
+     * @param patMedInhosp 浣忛櫌璁板綍瀵硅薄
+     * @param cry 鐘舵�佺爜锛�0:鍏ラ櫌, 1:鍑洪櫌, 3:棰勫叆闄級
+     * @return 鏄惁鎴愬姛
+     */
+    public boolean processStateChange(PatMedInhosp patMedInhosp, String cry) {
+        log.info("銆怚nhospStateMachineService銆戞牴鎹甤ry澶勭悊鐘舵�佸彉鏇达細serialnum={}, orgid={}, cry={}", 
+                patMedInhosp.getSerialnum(), patMedInhosp.getOrgid(), cry);
+
+        if ("0".equals(cry)) {
+            return processInHospital(patMedInhosp);
+        } else if ("1".equals(cry)) {
+            return processDischarge(patMedInhosp);
+        } else if ("3".equals(cry)) {
+            return processPreAdmission(patMedInhosp);
+        } else {
+            log.error("銆怚nhospStateMachineService銆戞湭鐭ョ殑cry鍊硷細{}", cry);
+            return false;
+        }
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐘舵��
+     * 
+     * @param serialnum 娴佹按鍙�
+     * @param orgid 鏈烘瀯ID
+     * @param patno 鎮h�呯紪鍙�
+     * @return 褰撳墠鐘舵�佺爜
+     */
+    public String getCurrentState(String serialnum, String orgid, String patno) {
+        return stateMachine.getCurrentState(serialnum, orgid, patno);
+    }
+}
diff --git a/smartor/src/main/java/com/smartor/statemachine/handler/InhospStateHandler.java b/smartor/src/main/java/com/smartor/statemachine/handler/InhospStateHandler.java
new file mode 100644
index 0000000..604c94d
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/statemachine/handler/InhospStateHandler.java
@@ -0,0 +1,26 @@
+package com.smartor.statemachine.handler;
+
+import com.smartor.domain.PatMedInhosp;
+
+/**
+ * 浣忛櫌鐘舵�佸鐞嗗櫒鎺ュ彛
+ * 
+ * @author smartor
+ */
+public interface InhospStateHandler {
+
+    /**
+     * 澶勭悊鐘舵�佸彉鏇�
+     * 
+     * @param patMedInhosp 寰呭鐞嗙殑浣忛櫌璁板綍瀵硅薄
+     * @return 澶勭悊缁撴灉(true:鎴愬姛, false:澶辫触)
+     */
+    boolean handle(PatMedInhosp patMedInhosp);
+
+    /**
+     * 鑾峰彇璇ュ鐞嗗櫒瀵瑰簲鐨勭姸鎬佺爜
+     * 
+     * @return 鐘舵�佺爜
+     */
+    String getStateCode();
+}
diff --git a/smartor/src/main/java/com/smartor/statemachine/handler/impl/DischargeHandler.java b/smartor/src/main/java/com/smartor/statemachine/handler/impl/DischargeHandler.java
new file mode 100644
index 0000000..4b31cd9
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/statemachine/handler/impl/DischargeHandler.java
@@ -0,0 +1,103 @@
+package com.smartor.statemachine.handler.impl;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.smartor.domain.PatMedInhosp;
+import com.smartor.service.IPatMedInhospService;
+import com.smartor.statemachine.handler.InhospStateHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 鍑洪櫌鐘舵�佸鐞嗗櫒
+ * 
+ * @author smartor
+ */
+@Slf4j
+@Component
+public class DischargeHandler implements InhospStateHandler {
+
+    @Autowired
+    private IPatMedInhospService patMedInhospService;
+
+    @Override
+    public boolean handle(PatMedInhosp patMedInhosp) {
+        log.info("銆怐ischargeHandler銆戝鐞嗗嚭闄㈤�昏緫锛宻erialnum={}, orgid={}", 
+                patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+
+        PatMedInhosp query = new PatMedInhosp();
+        query.setPatno(StringUtils.trim(patMedInhosp.getPatno()));
+        query.setSerialnum(StringUtils.trim(patMedInhosp.getSerialnum()));
+        query.setOrgid(StringUtils.trim(patMedInhosp.getOrgid()));
+
+        // 1. 鍏堟鏌ユ槸鍚﹀凡瀛樺湪鍑洪櫌璁板綍
+        query.setInhospstate("1");
+        List<PatMedInhosp> dischargedRecords = patMedInhospService.selectPatMedInhosp(query);
+        if (CollectionUtils.isNotEmpty(dischargedRecords)) {
+            log.warn("銆怐ischargeHandler銆戝嚭闄㈣褰曞凡瀛樺湪锛岃烦杩囷紝serialnum={}, orgid={}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+            return false;
+        }
+
+        // 2. 妫�鏌ユ槸鍚﹀瓨鍦ㄥ叆闄㈣褰曪紙姝e父娴佺▼锛氬繀椤诲厛鍏ラ櫌鎵嶈兘鍑洪櫌锛�
+        query.setInhospstate("0");
+        List<PatMedInhosp> inHospitalRecords = patMedInhospService.selectPatMedInhosp(query);
+        if (CollectionUtils.isNotEmpty(inHospitalRecords)) {
+            // 瀛樺湪鍏ラ櫌璁板綍锛屾墽琛岀姸鎬佹洿鏂颁负鍑洪櫌
+            try {
+                patMedInhosp.setInhospstate("1");
+                patMedInhosp.setInhospid(inHospitalRecords.get(0).getInhospid());
+                int updateCount = patMedInhospService.updatePatMedInhosp(patMedInhosp);
+                log.info("銆怐ischargeHandler銆戞洿鏂板叆闄㈣褰曚负鍑洪櫌鐘舵�侊紝serialnum={}, updateCount={}", 
+                        patMedInhosp.getSerialnum(), updateCount);
+                return updateCount > 0;
+            } catch (Exception e) {
+                log.error("銆怐ischargeHandler銆戞洿鏂板叆闄㈣褰曞け璐ワ細serialnum={}, orgid={}, 閿欒锛歿}", 
+                        patMedInhosp.getSerialnum(), patMedInhosp.getOrgid(), e.getMessage(), e);
+                return false;
+            }
+        }
+
+        // 3. 妫�鏌ユ槸鍚﹀瓨鍦ㄩ鍏ラ櫌璁板綍锛堝紓甯告祦绋嬶細浠庨鍏ラ櫌鐩存帴鍑洪櫌锛屽彲鑳芥槸鍙栨秷鍏ラ櫌锛�
+        query.setInhospstate("3");
+        List<PatMedInhosp> preAdmissionRecords = patMedInhospService.selectPatMedInhosp(query);
+        if (CollectionUtils.isNotEmpty(preAdmissionRecords)) {
+            log.warn("銆怐ischargeHandler銆戝瓨鍦ㄩ鍏ラ櫌璁板綍浣嗘湭鍏ラ櫌锛屼笉鍏佽鐩存帴鍑洪櫌锛宻erialnum={}, orgid={}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+            // 鏍规嵁涓氬姟闇�姹傚喅瀹氭槸鍚﹀厑璁镐粠棰勫叆闄㈢洿鎺ュ嚭闄紝杩欓噷鏆傛椂涓嶅厑璁�
+            return false;
+        }
+
+        // 4. 涓嶅瓨鍦ㄤ换浣曡褰曪紝寮傚父鎯呭喌锛氫笉搴旇娌℃湁鍏ラ櫌璁板綍灏卞嚭闄�
+        log.warn("銆怐ischargeHandler銆戞棤鍏ラ櫌璁板綍锛屼笉鍏佽鐩存帴鎻掑叆鍑洪櫌璁板綍锛宻erialnum={}, orgid={}", 
+                patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+        
+        // 濡傛灉涓氬姟鍏佽鐩存帴鎻掑叆鍑洪櫌璁板綍锛堝鏁版嵁淇鍦烘櫙锛夛紝鍙互鍙栨秷娉ㄩ噴浠ヤ笅浠g爜
+        /*
+        try {
+            patMedInhosp.setInhospstate("1");
+            patMedInhospService.insertPatMedInhosp(patMedInhosp);
+            log.info("銆怐ischargeHandler銆戞垚鍔熸彃鍏ュ嚭闄㈣褰曪紙鏃犲叆闄㈣褰曪級锛宻erialnum={}", patMedInhosp.getSerialnum());
+            return true;
+        } catch (org.springframework.dao.DuplicateKeyException e) {
+            log.warn("銆怐ischargeHandler銆戝嚭闄㈣褰曞凡瀛樺湪锛堝苟鍙戞彃鍏ワ級锛岃烦杩囷細serialnum={}, orgid={}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+            return false;
+        } catch (Exception e) {
+            log.error("銆怐ischargeHandler銆戞彃鍏ュ嚭闄㈣褰曞け璐ワ細serialnum={}, orgid={}, 閿欒锛歿}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid(), e.getMessage(), e);
+            return false;
+        }
+        */
+        
+        return false;
+    }
+
+    @Override
+    public String getStateCode() {
+        return "1";
+    }
+}
diff --git a/smartor/src/main/java/com/smartor/statemachine/handler/impl/InHospitalHandler.java b/smartor/src/main/java/com/smartor/statemachine/handler/impl/InHospitalHandler.java
new file mode 100644
index 0000000..a88b962
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/statemachine/handler/impl/InHospitalHandler.java
@@ -0,0 +1,94 @@
+package com.smartor.statemachine.handler.impl;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.smartor.domain.PatMedInhosp;
+import com.smartor.service.IPatMedInhospService;
+import com.smartor.statemachine.handler.InhospStateHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 鍏ラ櫌鐘舵�佸鐞嗗櫒
+ * 
+ * @author smartor
+ */
+@Slf4j
+@Component
+public class InHospitalHandler implements InhospStateHandler {
+
+    @Autowired
+    private IPatMedInhospService patMedInhospService;
+
+    @Override
+    public boolean handle(PatMedInhosp patMedInhosp) {
+        log.info("銆怚nHospitalHandler銆戝鐞嗗叆闄㈤�昏緫锛宻erialnum={}, orgid={}", 
+                patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+
+        PatMedInhosp query = new PatMedInhosp();
+        query.setPatno(StringUtils.trim(patMedInhosp.getPatno()));
+        query.setSerialnum(StringUtils.trim(patMedInhosp.getSerialnum()));
+        query.setOrgid(StringUtils.trim(patMedInhosp.getOrgid()));
+
+        // 1. 鍏堟鏌ユ槸鍚﹀凡瀛樺湪鍏ラ櫌璁板綍
+        query.setInhospstate("0");
+        List<PatMedInhosp> inHospitalRecords = patMedInhospService.selectPatMedInhosp(query);
+        if (CollectionUtils.isNotEmpty(inHospitalRecords)) {
+            log.warn("銆怚nHospitalHandler銆戝叆闄㈣褰曞凡瀛樺湪锛岃烦杩囷紝serialnum={}, orgid={}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+            return false;
+        }
+
+        // 2. 妫�鏌ユ槸鍚﹀瓨鍦ㄩ鍏ラ櫌璁板綍
+        query.setInhospstate("3");
+        List<PatMedInhosp> preAdmissionRecords = patMedInhospService.selectPatMedInhosp(query);
+        if (CollectionUtils.isNotEmpty(preAdmissionRecords)) {
+            // 瀛樺湪棰勫叆闄㈣褰曪紝鎵ц鐘舵�佹洿鏂�
+            try {
+                patMedInhosp.setInhospstate("0");
+                patMedInhosp.setInhospid(preAdmissionRecords.get(0).getInhospid());
+                int updateCount = patMedInhospService.updatePatMedInhosp(patMedInhosp);
+                log.info("銆怚nHospitalHandler銆戞洿鏂伴鍏ラ櫌璁板綍涓哄叆闄㈢姸鎬侊紝serialnum={}, updateCount={}", 
+                        patMedInhosp.getSerialnum(), updateCount);
+                return updateCount > 0;
+            } catch (Exception e) {
+                log.error("銆怚nHospitalHandler銆戞洿鏂伴鍏ラ櫌璁板綍澶辫触锛歴erialnum={}, orgid={}, 閿欒锛歿}", 
+                        patMedInhosp.getSerialnum(), patMedInhosp.getOrgid(), e.getMessage(), e);
+                return false;
+            }
+        }
+
+        // 3. 妫�鏌ユ槸鍚﹀凡鍑洪櫌锛堝鏋滃凡鍑洪櫌鍒欎笉鍏佽鐩存帴鍏ラ櫌锛�
+        query.setInhospstate("1");
+        List<PatMedInhosp> dischargedRecords = patMedInhospService.selectPatMedInhosp(query);
+        if (CollectionUtils.isNotEmpty(dischargedRecords)) {
+            log.warn("銆怚nHospitalHandler銆戞偅鑰呭凡鍑洪櫌锛屼笉鍏佽鍐嶆鍏ラ櫌锛宻erialnum={}, orgid={}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+            return false;
+        }
+
+        // 4. 涓嶅瓨鍦ㄤ换浣曡褰曪紝鐩存帴鎻掑叆鍏ラ櫌璁板綍
+        try {
+            patMedInhosp.setInhospstate("0");
+            patMedInhospService.insertPatMedInhosp(patMedInhosp);
+            log.info("銆怚nHospitalHandler銆戞垚鍔熸彃鍏ュ叆闄㈣褰曪紝serialnum={}", patMedInhosp.getSerialnum());
+            return true;
+        } catch (org.springframework.dao.DuplicateKeyException e) {
+            log.warn("銆怚nHospitalHandler銆戝叆闄㈣褰曞凡瀛樺湪锛堝苟鍙戞彃鍏ワ級锛岃烦杩囷細serialnum={}, orgid={}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+            return false;
+        } catch (Exception e) {
+            log.error("銆怚nHospitalHandler銆戞彃鍏ュ叆闄㈣褰曞け璐ワ細serialnum={}, orgid={}, 閿欒锛歿}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid(), e.getMessage(), e);
+            return false;
+        }
+    }
+
+    @Override
+    public String getStateCode() {
+        return "0";
+    }
+}
diff --git a/smartor/src/main/java/com/smartor/statemachine/handler/impl/PreAdmissionHandler.java b/smartor/src/main/java/com/smartor/statemachine/handler/impl/PreAdmissionHandler.java
new file mode 100644
index 0000000..d3f41e6
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/statemachine/handler/impl/PreAdmissionHandler.java
@@ -0,0 +1,67 @@
+package com.smartor.statemachine.handler.impl;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.smartor.domain.PatMedInhosp;
+import com.smartor.service.IPatMedInhospService;
+import com.smartor.statemachine.handler.InhospStateHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 棰勫叆闄㈢姸鎬佸鐞嗗櫒
+ * 
+ * @author smartor
+ */
+@Slf4j
+@Component
+public class PreAdmissionHandler implements InhospStateHandler {
+
+    @Autowired
+    private IPatMedInhospService patMedInhospService;
+
+    @Override
+    public boolean handle(PatMedInhosp patMedInhosp) {
+        log.info("銆怭reAdmissionHandler銆戝鐞嗛鍏ラ櫌閫昏緫锛宻erialnum={}, orgid={}", 
+                patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+
+        // 鏌ヨ鏄惁宸插瓨鍦ㄤ换浣曠姸鎬佺殑璁板綍
+        PatMedInhosp query = new PatMedInhosp();
+        query.setPatno(StringUtils.trim(patMedInhosp.getPatno()));
+        query.setSerialnum(StringUtils.trim(patMedInhosp.getSerialnum()));
+        query.setOrgid(StringUtils.trim(patMedInhosp.getOrgid()));
+        query.setInhospstate(null); // 鏌ヨ鎵�鏈夌姸鎬�
+
+        List<PatMedInhosp> existingRecords = patMedInhospService.selectPatMedInhosp(query);
+        
+        if (CollectionUtils.isNotEmpty(existingRecords)) {
+            log.warn("銆怭reAdmissionHandler銆戣褰曞凡瀛樺湪锛岃烦杩囬鍏ラ櫌鎻掑叆锛宻erialnum={}, orgid={}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+            return false;
+        }
+
+        // 涓嶅瓨鍦ㄤ换浣曡褰曪紝鎵ц鎻掑叆
+        try {
+            patMedInhosp.setInhospstate("3");
+            patMedInhospService.insertPatMedInhosp(patMedInhosp);
+            log.info("銆怭reAdmissionHandler銆戞垚鍔熸彃鍏ラ鍏ラ櫌璁板綍锛宻erialnum={}", patMedInhosp.getSerialnum());
+            return true;
+        } catch (org.springframework.dao.DuplicateKeyException e) {
+            log.warn("銆怭reAdmissionHandler銆戦鍏ラ櫌璁板綍宸插瓨鍦紙骞跺彂鎻掑叆锛夛紝璺宠繃锛歴erialnum={}, orgid={}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid());
+            return false;
+        } catch (Exception e) {
+            log.error("銆怭reAdmissionHandler銆戞彃鍏ラ鍏ラ櫌璁板綍澶辫触锛歴erialnum={}, orgid={}, 閿欒锛歿}", 
+                    patMedInhosp.getSerialnum(), patMedInhosp.getOrgid(), e.getMessage(), e);
+            return false;
+        }
+    }
+
+    @Override
+    public String getStateCode() {
+        return "3";
+    }
+}
diff --git a/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml b/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
index 1c33426..06dc0aa 100644
--- a/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
+++ b/smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
@@ -662,25 +662,29 @@
         ) a
     </select>
 
-    <select id="selectTimelyRateBatch" parameterType="com.smartor.domain.ServiceSubtask" resultType="map">
+    <select id="selectTimelyRateBatch" parameterType="com.smartor.domain.entity.ServiceSubtaskEntity" resultType="map">
         SELECT
         <if test="groupKey != null and groupKey != ''">
             ${groupKey} as groupKey,
         </if>
-        SUM(CASE WHEN DATE(visit_time) &lt; DATE(IFNULL(finishtime, NOW())) THEN 1 ELSE 0 END) / COUNT(*) as rate
+        SUM(CASE WHEN finishtime IS NOT NULL AND DATE(visit_time) &lt;= DATE(finishtime) THEN 1 ELSE 0 END) / COUNT(*) AS finishRate,
+        <if test="rateDay != null">
+            SUM(CASE WHEN finishtime IS NOT NULL AND DATEDIFF(finishtime, endtime) &lt;= #{rateDay} THEN 1 ELSE 0 END) / COUNT(*) AS rate
+        </if>
+        <if test="rateDay == null">
+            NULL AS rate
+        </if>
         FROM service_subtask
         WHERE del_flag = 0
         AND visit_time IS NOT NULL
-        AND finishtime IS NOT NULL
-        <if test="orgid != null">AND orgid = #{orgid}</if>
         <if test="starttime == null and endtime==null">
-            AND visit_time &lt; NOW()
+            AND DATE(visit_time) &lt; DATE(NOW())
         </if>
         <if test="starttime != null and endtime!=null">
             AND visit_time >= #{starttime}
             AND visit_time &lt; DATE_ADD(#{endtime}, INTERVAL 1 DAY)
         </if>
-        <if test="orgid != null  and orgid != ''">and orgid = #{orgid}</if>
+        <if test="orgid != null and orgid != ''">AND orgid = #{orgid}</if>
         <if test="deptcode != null  and deptcode != ''">and deptcode = #{deptcode}</if>
         <if test="deptname != null  and deptname != ''">and deptname = #{deptname}</if>
         <if test="isabnormal != null">and isabnormal = #{isabnormal}</if>
@@ -698,6 +702,13 @@
         <if test="visitCount != null and visitCount > 1">
             AND visit_count > 1
         </if>
+        <if test="serviceTypeList != null">
+            AND service_type IN
+            <foreach collection="serviceTypeList" item="serviceType" open="(" separator=","
+                     close=")">
+                #{serviceType}
+            </foreach>
+        </if>
         <if test="groupKey != null and groupKey != ''">
             AND ${groupKey} IN
             <foreach collection="groupKeyList" item="key" open="(" separator=","

--
Gitblit v1.9.3