From bcce8e5364bbbff564ab546235bef1444dfa79d7 Mon Sep 17 00:00:00 2001
From: eight <641137800@qq.com>
Date: 星期二, 06 八月 2024 20:29:59 +0800
Subject: [PATCH] birthday to datetime type

---
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentRespVO.java    |   95 ++++
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentPageReqVO.java |   76 +++
 sql/mysql/jh.sql                                                                                                              |    2 
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/appointment/AppointmentDO.java             |  119 +++++
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java           |   74 +++
 jh-module-ecg/jh-module-ecg-biz/src/main/resources/mapper/appointment/AppointmentMapper.xml                                   |   12 
 jh-module-ecg/jh-module-ecg-api/pom.xml                                                                                       |   33 +
 jh-module-ecg/jh-module-ecg-api/src/main/java/cn/lihu/jh/module/ecg/enums/ErrorCodeConstants.java                             |  165 ++++++++
 jh-module-ecg/jh-module-ecg-biz/src/test/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImplTest.java       |  202 ++++++++++
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/AppointmentController.java   |   95 ++++
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentService.java               |   55 ++
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentSaveReqVO.java |   76 +++
 jh-module-ecg/pom.xml                                                                                                         |   23 +
 jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/appointment/AppointmentMapper.java              |   44 ++
 jh-module-ecg/jh-module-ecg-biz/pom.xml                                                                                       |  124 ++++++
 15 files changed, 1,194 insertions(+), 1 deletions(-)

diff --git a/jh-module-ecg/jh-module-ecg-api/pom.xml b/jh-module-ecg/jh-module-ecg-api/pom.xml
new file mode 100644
index 0000000..91fee6d
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-api/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>cn.lihu</groupId>
+        <artifactId>jh-module-ecg</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>jh-module-ecg-api</artifactId>
+    <packaging>jar</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>
+        ecg 妯″潡 API锛屾毚闇茬粰鍏跺畠妯″潡璋冪敤
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-common</artifactId>
+        </dependency>
+
+        <!-- 鍙傛暟鏍¢獙 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/jh-module-ecg/jh-module-ecg-api/src/main/java/cn/lihu/jh/module/ecg/enums/ErrorCodeConstants.java b/jh-module-ecg/jh-module-ecg-api/src/main/java/cn/lihu/jh/module/ecg/enums/ErrorCodeConstants.java
new file mode 100644
index 0000000..28b7bfb
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-api/src/main/java/cn/lihu/jh/module/ecg/enums/ErrorCodeConstants.java
@@ -0,0 +1,165 @@
+package cn.lihu.jh.module.system.enums;
+
+import cn.lihu.jh.framework.common.exception.ErrorCode;
+
+/**
+ * System 閿欒鐮佹灇涓剧被
+ *
+ * system 绯荤粺锛屼娇鐢� 1-002-000-000 娈�
+ */
+public interface ErrorCodeConstants {
+
+    // ========== AUTH 妯″潡 1-002-000-000 ==========
+    ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1_002_000_000, "鐧诲綍澶辫触锛岃处鍙峰瘑鐮佷笉姝g‘");
+    ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1_002_000_001, "鐧诲綍澶辫触锛岃处鍙疯绂佺敤");
+    ErrorCode AUTH_LOGIN_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_004, "楠岃瘉鐮佷笉姝g‘锛屽師鍥狅細{}");
+    ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_002_000_005, "鏈粦瀹氳处鍙凤紝闇�瑕佽繘琛岀粦瀹�");
+    ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_007, "鎵嬫満鍙蜂笉瀛樺湪");
+
+    // ========== 鑿滃崟妯″潡 1-002-001-000 ==========
+    ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1_002_001_000, "宸茬粡瀛樺湪璇ュ悕瀛楃殑鑿滃崟");
+    ErrorCode MENU_PARENT_NOT_EXISTS = new ErrorCode(1_002_001_001, "鐖惰彍鍗曚笉瀛樺湪");
+    ErrorCode MENU_PARENT_ERROR = new ErrorCode(1_002_001_002, "涓嶈兘璁剧疆鑷繁涓虹埗鑿滃崟");
+    ErrorCode MENU_NOT_EXISTS = new ErrorCode(1_002_001_003, "鑿滃崟涓嶅瓨鍦�");
+    ErrorCode MENU_EXISTS_CHILDREN = new ErrorCode(1_002_001_004, "瀛樺湪瀛愯彍鍗曪紝鏃犳硶鍒犻櫎");
+    ErrorCode MENU_PARENT_NOT_DIR_OR_MENU = new ErrorCode(1_002_001_005, "鐖惰彍鍗曠殑绫诲瀷蹇呴』鏄洰褰曟垨鑰呰彍鍗�");
+
+    // ========== 瑙掕壊妯″潡 1-002-002-000 ==========
+    ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1_002_002_000, "瑙掕壊涓嶅瓨鍦�");
+    ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1_002_002_001, "宸茬粡瀛樺湪鍚嶄负銆恵}銆戠殑瑙掕壊");
+    ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1_002_002_002, "宸茬粡瀛樺湪缂栫爜涓恒�恵}銆戠殑瑙掕壊");
+    ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1_002_002_003, "涓嶈兘鎿嶄綔绫诲瀷涓虹郴缁熷唴缃殑瑙掕壊");
+    ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "鍚嶅瓧涓恒�恵}銆戠殑瑙掕壊宸茶绂佺敤");
+    ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "缂栫爜銆恵}銆戜笉鑳戒娇鐢�");
+
+    // ========== 鐢ㄦ埛妯″潡 1-002-003-000 ==========
+    ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1_002_003_000, "鐢ㄦ埛璐﹀彿宸茬粡瀛樺湪");
+    ErrorCode USER_MOBILE_EXISTS = new ErrorCode(1_002_003_001, "鎵嬫満鍙峰凡缁忓瓨鍦�");
+    ErrorCode USER_EMAIL_EXISTS = new ErrorCode(1_002_003_002, "閭宸茬粡瀛樺湪");
+    ErrorCode USER_NOT_EXISTS = new ErrorCode(1_002_003_003, "鐢ㄦ埛涓嶅瓨鍦�");
+    ErrorCode USER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_002_003_004, "瀵煎叆鐢ㄦ埛鏁版嵁涓嶈兘涓虹┖锛�");
+    ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1_002_003_005, "鐢ㄦ埛瀵嗙爜鏍¢獙澶辫触");
+    ErrorCode USER_IS_DISABLE = new ErrorCode(1_002_003_006, "鍚嶅瓧涓恒�恵}銆戠殑鐢ㄦ埛宸茶绂佺敤");
+    ErrorCode USER_COUNT_MAX = new ErrorCode(1_002_003_008, "鍒涘缓鐢ㄦ埛澶辫触锛屽師鍥狅細瓒呰繃绉熸埛鏈�澶х鎴烽厤棰�({})锛�");
+    ErrorCode USER_IMPORT_INIT_PASSWORD = new ErrorCode(1_002_003_009, "鍒濆瀵嗙爜涓嶈兘涓虹┖");
+
+    // ========== 閮ㄩ棬妯″潡 1-002-004-000 ==========
+    ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "宸茬粡瀛樺湪璇ュ悕瀛楃殑閮ㄩ棬");
+    ErrorCode DEPT_PARENT_NOT_EXITS = new ErrorCode(1_002_004_001,"鐖剁骇閮ㄩ棬涓嶅瓨鍦�");
+    ErrorCode DEPT_NOT_FOUND = new ErrorCode(1_002_004_002, "褰撳墠閮ㄩ棬涓嶅瓨鍦�");
+    ErrorCode DEPT_EXITS_CHILDREN = new ErrorCode(1_002_004_003, "瀛樺湪瀛愰儴闂紝鏃犳硶鍒犻櫎");
+    ErrorCode DEPT_PARENT_ERROR = new ErrorCode(1_002_004_004, "涓嶈兘璁剧疆鑷繁涓虹埗閮ㄩ棬");
+    ErrorCode DEPT_NOT_ENABLE = new ErrorCode(1_002_004_006, "閮ㄩ棬({})涓嶅浜庡紑鍚姸鎬侊紝涓嶅厑璁搁�夋嫨");
+    ErrorCode DEPT_PARENT_IS_CHILD = new ErrorCode(1_002_004_007, "涓嶈兘璁剧疆鑷繁鐨勫瓙閮ㄩ棬涓虹埗閮ㄩ棬");
+
+    // ========== 宀椾綅妯″潡 1-002-005-000 ==========
+    ErrorCode POST_NOT_FOUND = new ErrorCode(1_002_005_000, "褰撳墠宀椾綅涓嶅瓨鍦�");
+    ErrorCode POST_NOT_ENABLE = new ErrorCode(1_002_005_001, "宀椾綅({}) 涓嶅浜庡紑鍚姸鎬侊紝涓嶅厑璁搁�夋嫨");
+    ErrorCode POST_NAME_DUPLICATE = new ErrorCode(1_002_005_002, "宸茬粡瀛樺湪璇ュ悕瀛楃殑宀椾綅");
+    ErrorCode POST_CODE_DUPLICATE = new ErrorCode(1_002_005_003, "宸茬粡瀛樺湪璇ユ爣璇嗙殑宀椾綅");
+
+    // ========== 瀛楀吀绫诲瀷 1-002-006-000 ==========
+    ErrorCode DICT_TYPE_NOT_EXISTS = new ErrorCode(1_002_006_001, "褰撳墠瀛楀吀绫诲瀷涓嶅瓨鍦�");
+    ErrorCode DICT_TYPE_NOT_ENABLE = new ErrorCode(1_002_006_002, "瀛楀吀绫诲瀷涓嶅浜庡紑鍚姸鎬侊紝涓嶅厑璁搁�夋嫨");
+    ErrorCode DICT_TYPE_NAME_DUPLICATE = new ErrorCode(1_002_006_003, "宸茬粡瀛樺湪璇ュ悕瀛楃殑瀛楀吀绫诲瀷");
+    ErrorCode DICT_TYPE_TYPE_DUPLICATE = new ErrorCode(1_002_006_004, "宸茬粡瀛樺湪璇ョ被鍨嬬殑瀛楀吀绫诲瀷");
+    ErrorCode DICT_TYPE_HAS_CHILDREN = new ErrorCode(1_002_006_005, "鏃犳硶鍒犻櫎锛岃瀛楀吀绫诲瀷杩樻湁瀛楀吀鏁版嵁");
+
+    // ========== 瀛楀吀鏁版嵁 1-002-007-000 ==========
+    ErrorCode DICT_DATA_NOT_EXISTS = new ErrorCode(1_002_007_001, "褰撳墠瀛楀吀鏁版嵁涓嶅瓨鍦�");
+    ErrorCode DICT_DATA_NOT_ENABLE = new ErrorCode(1_002_007_002, "瀛楀吀鏁版嵁({})涓嶅浜庡紑鍚姸鎬侊紝涓嶅厑璁搁�夋嫨");
+    ErrorCode DICT_DATA_VALUE_DUPLICATE = new ErrorCode(1_002_007_003, "宸茬粡瀛樺湪璇ュ�肩殑瀛楀吀鏁版嵁");
+
+    // ========== 閫氱煡鍏憡 1-002-008-000 ==========
+    ErrorCode NOTICE_NOT_FOUND = new ErrorCode(1_002_008_001, "褰撳墠閫氱煡鍏憡涓嶅瓨鍦�");
+
+    // ========== 鐭俊娓犻亾 1-002-011-000 ==========
+    ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1_002_011_000, "鐭俊娓犻亾涓嶅瓨鍦�");
+    ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1_002_011_001, "鐭俊娓犻亾涓嶅浜庡紑鍚姸鎬侊紝涓嶅厑璁搁�夋嫨");
+    ErrorCode SMS_CHANNEL_HAS_CHILDREN = new ErrorCode(1_002_011_002, "鏃犳硶鍒犻櫎锛岃鐭俊娓犻亾杩樻湁鐭俊妯℃澘");
+
+    // ========== 鐭俊妯℃澘 1-002-012-000 ==========
+    ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "鐭俊妯℃澘涓嶅瓨鍦�");
+    ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_012_001, "宸茬粡瀛樺湪缂栫爜涓恒�恵}銆戠殑鐭俊妯℃澘");
+    ErrorCode SMS_TEMPLATE_API_ERROR = new ErrorCode(1_002_012_002, "鐭俊 API 妯℃澘璋冪敤澶辫触锛屽師鍥犳槸锛歿}");
+    ErrorCode SMS_TEMPLATE_API_AUDIT_CHECKING = new ErrorCode(1_002_012_003, "鐭俊 API 妯$増鏃犳硶浣跨敤锛屽師鍥狅細瀹℃壒涓�");
+    ErrorCode SMS_TEMPLATE_API_AUDIT_FAIL = new ErrorCode(1_002_012_004, "鐭俊 API 妯$増鏃犳硶浣跨敤锛屽師鍥狅細瀹℃壒涓嶉�氳繃锛寋}");
+    ErrorCode SMS_TEMPLATE_API_NOT_FOUND = new ErrorCode(1_002_012_005, "鐭俊 API 妯$増鏃犳硶浣跨敤锛屽師鍥狅細妯$増涓嶅瓨鍦�");
+
+    // ========== 鐭俊鍙戦�� 1-002-013-000 ==========
+    ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1_002_013_000, "鎵嬫満鍙蜂笉瀛樺湪");
+    ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_013_001, "妯℃澘鍙傛暟({})缂哄け");
+    ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_013_002, "鐭俊妯℃澘涓嶅瓨鍦�");
+
+    // ========== 鐭俊楠岃瘉鐮� 1-002-014-000 ==========
+    ErrorCode SMS_CODE_NOT_FOUND = new ErrorCode(1_002_014_000, "楠岃瘉鐮佷笉瀛樺湪");
+    ErrorCode SMS_CODE_EXPIRED = new ErrorCode(1_002_014_001, "楠岃瘉鐮佸凡杩囨湡");
+    ErrorCode SMS_CODE_USED = new ErrorCode(1_002_014_002, "楠岃瘉鐮佸凡浣跨敤");
+    ErrorCode SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1_002_014_004, "瓒呰繃姣忔棩鐭俊鍙戦�佹暟閲�");
+    ErrorCode SMS_CODE_SEND_TOO_FAST = new ErrorCode(1_002_014_005, "鐭俊鍙戦�佽繃浜庨绻�");
+
+    // ========== 绉熸埛淇℃伅 1-002-015-000 ==========
+    ErrorCode TENANT_NOT_EXISTS = new ErrorCode(1_002_015_000, "绉熸埛涓嶅瓨鍦�");
+    ErrorCode TENANT_DISABLE = new ErrorCode(1_002_015_001, "鍚嶅瓧涓恒�恵}銆戠殑绉熸埛宸茶绂佺敤");
+    ErrorCode TENANT_EXPIRE = new ErrorCode(1_002_015_002, "鍚嶅瓧涓恒�恵}銆戠殑绉熸埛宸茶繃鏈�");
+    ErrorCode TENANT_CAN_NOT_UPDATE_SYSTEM = new ErrorCode(1_002_015_003, "绯荤粺绉熸埛涓嶈兘杩涜淇敼銆佸垹闄ょ瓑鎿嶄綔锛�");
+    ErrorCode TENANT_NAME_DUPLICATE = new ErrorCode(1_002_015_004, "鍚嶅瓧涓恒�恵}銆戠殑绉熸埛宸插瓨鍦�");
+    ErrorCode TENANT_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "鍩熷悕涓恒�恵}銆戠殑绉熸埛宸插瓨鍦�");
+
+    // ========== 绉熸埛濂楅 1-002-016-000 ==========
+    ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "绉熸埛濂楅涓嶅瓨鍦�");
+    ErrorCode TENANT_PACKAGE_USED = new ErrorCode(1_002_016_001, "绉熸埛姝e湪浣跨敤璇ュ椁愶紝璇风粰绉熸埛閲嶆柊璁剧疆濂楅鍚庡啀灏濊瘯鍒犻櫎");
+    ErrorCode TENANT_PACKAGE_DISABLE = new ErrorCode(1_002_016_002, "鍚嶅瓧涓恒�恵}銆戠殑绉熸埛濂楅宸茶绂佺敤");
+
+    // ========== 绀句氦鐢ㄦ埛 1-002-018-000 ==========
+    ErrorCode SOCIAL_USER_AUTH_FAILURE = new ErrorCode(1_002_018_000, "绀句氦鎺堟潈澶辫触锛屽師鍥犳槸锛歿}");
+    ErrorCode SOCIAL_USER_NOT_FOUND = new ErrorCode(1_002_018_001, "绀句氦鎺堟潈澶辫触锛屾壘涓嶅埌瀵瑰簲鐨勭敤鎴�");
+
+    ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "鑾峰緱鎵嬫満鍙峰け璐�");
+    ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR = new ErrorCode(1_002_018_201, "鑾峰緱灏忕▼搴忕爜澶辫触");
+    ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR = new ErrorCode(1_002_018_202, "鑾峰緱灏忕▼搴忚闃呮秷鎭ā鐗堝け璐�");
+    ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR = new ErrorCode(1_002_018_203, "鍙戦�佸皬绋嬪簭璁㈤槄娑堟伅澶辫触");
+    ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_210, "绀句氦瀹㈡埛绔笉瀛樺湪");
+    ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "绀句氦瀹㈡埛绔凡瀛樺湪閰嶇疆");
+
+
+    // ========== OAuth2 瀹㈡埛绔� 1-002-020-000 =========
+    ErrorCode OAUTH2_CLIENT_NOT_EXISTS = new ErrorCode(1_002_020_000, "OAuth2 瀹㈡埛绔笉瀛樺湪");
+    ErrorCode OAUTH2_CLIENT_EXISTS = new ErrorCode(1_002_020_001, "OAuth2 瀹㈡埛绔紪鍙峰凡瀛樺湪");
+    ErrorCode OAUTH2_CLIENT_DISABLE = new ErrorCode(1_002_020_002, "OAuth2 瀹㈡埛绔凡绂佺敤");
+    ErrorCode OAUTH2_CLIENT_AUTHORIZED_GRANT_TYPE_NOT_EXISTS = new ErrorCode(1_002_020_003, "涓嶆敮鎸佽鎺堟潈绫诲瀷");
+    ErrorCode OAUTH2_CLIENT_SCOPE_OVER = new ErrorCode(1_002_020_004, "鎺堟潈鑼冨洿杩囧ぇ");
+    ErrorCode OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH = new ErrorCode(1_002_020_005, "鏃犳晥 redirect_uri: {}");
+    ErrorCode OAUTH2_CLIENT_CLIENT_SECRET_ERROR = new ErrorCode(1_002_020_006, "鏃犳晥 client_secret: {}");
+
+    // ========== OAuth2 鎺堟潈 1-002-021-000 =========
+    ErrorCode OAUTH2_GRANT_CLIENT_ID_MISMATCH = new ErrorCode(1_002_021_000, "client_id 涓嶅尮閰�");
+    ErrorCode OAUTH2_GRANT_REDIRECT_URI_MISMATCH = new ErrorCode(1_002_021_001, "redirect_uri 涓嶅尮閰�");
+    ErrorCode OAUTH2_GRANT_STATE_MISMATCH = new ErrorCode(1_002_021_002, "state 涓嶅尮閰�");
+
+    // ========== OAuth2 鎺堟潈 1-002-022-000 =========
+    ErrorCode OAUTH2_CODE_NOT_EXISTS = new ErrorCode(1_002_022_000, "code 涓嶅瓨鍦�");
+    ErrorCode OAUTH2_CODE_EXPIRE = new ErrorCode(1_002_022_001, "code 宸茶繃鏈�");
+
+    // ========== 閭璐﹀彿 1-002-023-000 ==========
+    ErrorCode MAIL_ACCOUNT_NOT_EXISTS = new ErrorCode(1_002_023_000, "閭璐﹀彿涓嶅瓨鍦�");
+    ErrorCode MAIL_ACCOUNT_RELATE_TEMPLATE_EXISTS = new ErrorCode(1_002_023_001, "鏃犳硶鍒犻櫎锛岃閭璐﹀彿杩樻湁閭欢妯℃澘");
+
+    // ========== 閭欢妯$増 1-002-024-000 ==========
+    ErrorCode MAIL_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_024_000, "閭欢妯$増涓嶅瓨鍦�");
+    ErrorCode MAIL_TEMPLATE_CODE_EXISTS = new ErrorCode(1_002_024_001, "閭欢妯$増 code({}) 宸插瓨鍦�");
+
+    // ========== 閭欢鍙戦�� 1-002-025-000 ==========
+    ErrorCode MAIL_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_025_000, "妯℃澘鍙傛暟({})缂哄け");
+    ErrorCode MAIL_SEND_MAIL_NOT_EXISTS = new ErrorCode(1_002_025_001, "閭涓嶅瓨鍦�");
+
+    // ========== 绔欏唴淇℃ā鐗� 1-002-026-000 ==========
+    ErrorCode NOTIFY_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_026_000, "绔欏唴淇℃ā鐗堜笉瀛樺湪");
+    ErrorCode NOTIFY_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_026_001, "宸茬粡瀛樺湪缂栫爜涓恒�恵}銆戠殑绔欏唴淇℃ā鏉�");
+
+    // ========== 绔欏唴淇℃ā鐗� 1-002-027-000 ==========
+
+    // ========== 绔欏唴淇″彂閫� 1-002-028-000 ==========
+    ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_028_000, "妯℃澘鍙傛暟({})缂哄け");
+
+}
diff --git a/jh-module-ecg/jh-module-ecg-biz/pom.xml b/jh-module-ecg/jh-module-ecg-biz/pom.xml
new file mode 100644
index 0000000..582771c
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/pom.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>cn.lihu</groupId>
+        <artifactId>jh-module-ecg</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>jh-module-ecg-biz</artifactId>
+    <packaging>jar</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>
+        ecg 妯″潡涓�
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-module-ecg-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-module-infra-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+
+        <!-- 涓氬姟缁勪欢 -->
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-spring-boot-starter-biz-data-permission</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-spring-boot-starter-biz-tenant</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-spring-boot-starter-biz-ip</artifactId>
+        </dependency>
+
+        <!-- Web 鐩稿叧 -->
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!-- DB 鐩稿叧 -->
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-spring-boot-starter-mybatis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-spring-boot-starter-redis</artifactId>
+        </dependency>
+
+        <!-- Job 瀹氭椂浠诲姟鐩稿叧 -->
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-spring-boot-starter-job</artifactId>
+        </dependency>
+
+        <!-- 娑堟伅闃熷垪鐩稿叧 -->
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-spring-boot-starter-mq</artifactId>
+        </dependency>
+
+        <!-- 宸ュ叿绫荤浉鍏� -->
+        <dependency>
+            <groupId>cn.lihu</groupId>
+            <artifactId>jh-spring-boot-starter-excel</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+
+        <!-- 涓夋柟浜戞湇鍔$浉鍏� -->
+        <dependency>
+            <groupId>com.xingyuv</groupId>
+            <artifactId>spring-boot-starter-justauth</artifactId> <!-- 绀句氦鐧婚檰锛堜緥濡傝锛屼釜浜哄井淇°�佷紒涓氬井淇$瓑绛夛級 -->
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>wx-java-mp-spring-boot-starter</artifactId> <!-- 寰俊鐧诲綍锛堝叕浼楀彿锛� -->
+        </dependency>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>  <!-- 寰俊鐧诲綍锛堝皬绋嬪簭锛� -->
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId> <!-- 鐭俊锛堥樋閲屼簯锛� -->
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-dysmsapi</artifactId> <!-- 鐭俊锛堥樋閲屼簯锛� -->
+        </dependency>
+        <dependency>
+            <groupId>com.tencentcloudapi</groupId>
+            <artifactId>tencentcloud-sdk-java-sms</artifactId> <!-- 鐭俊锛堣吘璁簯锛� -->
+        </dependency>
+
+        <dependency>
+            <groupId>com.xingyuv</groupId>
+            <artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 楠岃瘉鐮侊紝涓�鑸敤浜庣櫥褰曚娇鐢� -->
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/AppointmentController.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/AppointmentController.java
new file mode 100644
index 0000000..3f92d62
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/AppointmentController.java
@@ -0,0 +1,95 @@
+package cn.lihu.jh.module.ecg.controller.admin.appointment;
+
+import org.springframework.web.bind.annotation.*;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import jakarta.validation.constraints.*;
+import jakarta.validation.*;
+import jakarta.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.lihu.jh.framework.common.pojo.PageParam;
+import cn.lihu.jh.framework.common.pojo.PageResult;
+import cn.lihu.jh.framework.common.pojo.CommonResult;
+import cn.lihu.jh.framework.common.util.object.BeanUtils;
+import static cn.lihu.jh.framework.common.pojo.CommonResult.success;
+
+import cn.lihu.jh.framework.excel.core.util.ExcelUtils;
+
+import cn.lihu.jh.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.lihu.jh.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.*;
+import cn.lihu.jh.module.ecg.dal.dataobject.appointment.AppointmentDO;
+import cn.lihu.jh.module.ecg.service.appointment.AppointmentService;
+
+@Tag(name = "绠$悊鍚庡彴 - 棰勭害")
+@RestController
+@RequestMapping("/ecg/appointment")
+@Validated
+public class AppointmentController {
+
+    @Resource
+    private AppointmentService appointmentService;
+
+    @PostMapping("/create")
+    @Operation(summary = "鍒涘缓棰勭害")
+    @PreAuthorize("@ss.hasPermission('ecg:appointment:create')")
+    public CommonResult<Integer> createAppointment(@Valid @RequestBody AppointmentSaveReqVO createReqVO) {
+        return success(appointmentService.createAppointment(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "鏇存柊棰勭害")
+    @PreAuthorize("@ss.hasPermission('ecg:appointment:update')")
+    public CommonResult<Boolean> updateAppointment(@Valid @RequestBody AppointmentSaveReqVO updateReqVO) {
+        appointmentService.updateAppointment(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "鍒犻櫎棰勭害")
+    @Parameter(name = "id", description = "缂栧彿", required = true)
+    @PreAuthorize("@ss.hasPermission('ecg:appointment:delete')")
+    public CommonResult<Boolean> deleteAppointment(@RequestParam("id") Integer id) {
+        appointmentService.deleteAppointment(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "鑾峰緱棰勭害")
+    @Parameter(name = "id", description = "缂栧彿", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('ecg:appointment:query')")
+    public CommonResult<AppointmentRespVO> getAppointment(@RequestParam("id") Integer id) {
+        AppointmentDO appointment = appointmentService.getAppointment(id);
+        return success(BeanUtils.toBean(appointment, AppointmentRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "鑾峰緱棰勭害鍒嗛〉")
+    @PreAuthorize("@ss.hasPermission('ecg:appointment:query')")
+    public CommonResult<PageResult<AppointmentRespVO>> getAppointmentPage(@Valid AppointmentPageReqVO pageReqVO) {
+        PageResult<AppointmentDO> pageResult = appointmentService.getAppointmentPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, AppointmentRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "瀵煎嚭棰勭害 Excel")
+    @PreAuthorize("@ss.hasPermission('ecg:appointment:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportAppointmentExcel(@Valid AppointmentPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<AppointmentDO> list = appointmentService.getAppointmentPage(pageReqVO).getList();
+        // 瀵煎嚭 Excel
+        ExcelUtils.write(response, "棰勭害.xls", "鏁版嵁", AppointmentRespVO.class,
+                        BeanUtils.toBean(list, AppointmentRespVO.class));
+    }
+
+}
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentPageReqVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentPageReqVO.java
new file mode 100644
index 0000000..78f3cf2
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentPageReqVO.java
@@ -0,0 +1,76 @@
+package cn.lihu.jh.module.ecg.controller.admin.appointment.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.lihu.jh.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.lihu.jh.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "绠$悊鍚庡彴 - 棰勭害鍒嗛〉 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class AppointmentPageReqVO extends PageParam {
+
+    @Schema(description = "鎮h�呯紪鍙�", example = "29034")
+    private String patId;
+
+    @Schema(description = "鎮h�呭鍚�", example = "璧靛叚")
+    private String patName;
+
+    @Schema(description = "鎮h�呮�у埆")
+    private Boolean patGender;
+
+    @Schema(description = "鎮h�呯敓鏃�")
+    private LocalDate patBirthday;
+
+    @Schema(description = "鎮h�呮墜鏈�")
+    private String patMobile;
+
+    @Schema(description = "鎮h�呯數璇�")
+    private String patPhone;
+
+    @Schema(description = "韬唤璇佸彿", example = "798")
+    private String patIdentityId;
+
+    @Schema(description = "鎮h�呭湴鍧�")
+    private String patAddr;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ瀹や唬鐮�")
+    private String patDeptCode;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ瀹ゅ悕绉�")
+    private String patDeptDesc;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ梾鍖轰唬鐮�")
+    private String patWardCode;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ梾鍖哄悕绉�")
+    private String patWardDesc;
+
+    @Schema(description = "搴婂彿")
+    private String patBedNo;
+
+    @Schema(description = "棰勭害缂栧彿", example = "27849")
+    private String bookId;
+
+    @Schema(description = "棰勭害妫�鏌ユ椂闂存")
+    private LocalDateTime bookPeriodStart;
+
+    @Schema(description = "棰勭害妫�鏌ユ椂闂存")
+    private LocalDateTime bookPeriodEnd;
+
+    @Schema(description = "棰勭害鍙戠敓鏃堕棿")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] bookTime;
+
+    @Schema(description = "棰勭害妫�鏌ョ被鍨�", example = "2")
+    private Boolean bookCheckType;
+
+    @Schema(description = "棰勭害鏉ユ簮锛歑绯荤粺銆佹姢澹墜鍔ㄩ绾�")
+    private String bookSrc;
+
+}
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentRespVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentRespVO.java
new file mode 100644
index 0000000..8b2696e
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentRespVO.java
@@ -0,0 +1,95 @@
+package cn.lihu.jh.module.ecg.controller.admin.appointment.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+import cn.lihu.jh.framework.excel.core.annotations.DictFormat;
+import cn.lihu.jh.framework.excel.core.convert.DictConvert;
+
+@Schema(description = "绠$悊鍚庡彴 - 棰勭害 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class AppointmentRespVO {
+
+    @Schema(description = "鎮h�呯紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "29034")
+    @ExcelProperty("鎮h�呯紪鍙�")
+    private String patId;
+
+    @Schema(description = "鎮h�呭鍚�", requiredMode = Schema.RequiredMode.REQUIRED, example = "璧靛叚")
+    @ExcelProperty("鎮h�呭鍚�")
+    private String patName;
+
+    @Schema(description = "鎮h�呮�у埆", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty(value = "鎮h�呮�у埆", converter = DictConvert.class)
+    @DictFormat("system_user_sex") // TODO 浠g爜浼樺寲锛氬缓璁缃埌瀵瑰簲鐨� DictTypeConstants 鏋氫妇绫讳腑
+    private Boolean patGender;
+
+    @Schema(description = "鎮h�呯敓鏃�")
+    @ExcelProperty("鎮h�呯敓鏃�")
+    private LocalDate patBirthday;
+
+    @Schema(description = "鎮h�呮墜鏈�")
+    @ExcelProperty("鎮h�呮墜鏈�")
+    private String patMobile;
+
+    @Schema(description = "鎮h�呯數璇�")
+    @ExcelProperty("鎮h�呯數璇�")
+    private String patPhone;
+
+    @Schema(description = "韬唤璇佸彿", example = "798")
+    @ExcelProperty("韬唤璇佸彿")
+    private String patIdentityId;
+
+    @Schema(description = "鎮h�呭湴鍧�")
+    @ExcelProperty("鎮h�呭湴鍧�")
+    private String patAddr;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ瀹や唬鐮�")
+    @ExcelProperty("鎮h�呮墍鍦ㄧ瀹や唬鐮�")
+    private String patDeptCode;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ瀹ゅ悕绉�")
+    @ExcelProperty("鎮h�呮墍鍦ㄧ瀹ゅ悕绉�")
+    private String patDeptDesc;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ梾鍖轰唬鐮�")
+    @ExcelProperty("鎮h�呮墍鍦ㄧ梾鍖轰唬鐮�")
+    private String patWardCode;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ梾鍖哄悕绉�")
+    @ExcelProperty("鎮h�呮墍鍦ㄧ梾鍖哄悕绉�")
+    private String patWardDesc;
+
+    @Schema(description = "搴婂彿")
+    @ExcelProperty("搴婂彿")
+    private String patBedNo;
+
+    @Schema(description = "棰勭害缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "27849")
+    @ExcelProperty("棰勭害缂栧彿")
+    private String bookId;
+
+    @Schema(description = "棰勭害妫�鏌ユ椂闂存", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("棰勭害妫�鏌ユ椂闂存")
+    private LocalDateTime bookPeriodStart;
+
+    @Schema(description = "棰勭害妫�鏌ユ椂闂存", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("棰勭害妫�鏌ユ椂闂存")
+    private LocalDateTime bookPeriodEnd;
+
+    @Schema(description = "棰勭害鍙戠敓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("棰勭害鍙戠敓鏃堕棿")
+    private LocalDateTime bookTime;
+
+    @Schema(description = "棰勭害妫�鏌ョ被鍨�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @ExcelProperty(value = "棰勭害妫�鏌ョ被鍨�", converter = DictConvert.class)
+    @DictFormat("ecg_check_type") // TODO 浠g爜浼樺寲锛氬缓璁缃埌瀵瑰簲鐨� DictTypeConstants 鏋氫妇绫讳腑
+    private Boolean bookCheckType;
+
+    @Schema(description = "棰勭害鏉ユ簮锛歑绯荤粺銆佹姢澹墜鍔ㄩ绾�", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("棰勭害鏉ユ簮锛歑绯荤粺銆佹姢澹墜鍔ㄩ绾�")
+    private String bookSrc;
+
+}
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentSaveReqVO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentSaveReqVO.java
new file mode 100644
index 0000000..ceaa1f8
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/appointment/vo/AppointmentSaveReqVO.java
@@ -0,0 +1,76 @@
+package cn.lihu.jh.module.ecg.controller.admin.appointment.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "绠$悊鍚庡彴 - 棰勭害鏂板/淇敼 Request VO")
+@Data
+public class AppointmentSaveReqVO {
+
+    @Schema(description = "鎮h�呯紪鍙�", requiredMode = Schema.RequiredMode.REQUIRED, example = "29034")
+    @NotEmpty(message = "鎮h�呯紪鍙蜂笉鑳戒负绌�")
+    private String patId;
+
+    @Schema(description = "鎮h�呭鍚�", requiredMode = Schema.RequiredMode.REQUIRED, example = "璧靛叚")
+    @NotEmpty(message = "鎮h�呭鍚嶄笉鑳戒负绌�")
+    private String patName;
+
+    @Schema(description = "鎮h�呮�у埆", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "鎮h�呮�у埆涓嶈兘涓虹┖")
+    private Boolean patGender;
+
+    @Schema(description = "鎮h�呯敓鏃�")
+    private LocalDate patBirthday;
+
+    @Schema(description = "鎮h�呮墜鏈�")
+    private String patMobile;
+
+    @Schema(description = "鎮h�呯數璇�")
+    private String patPhone;
+
+    @Schema(description = "韬唤璇佸彿", example = "798")
+    private String patIdentityId;
+
+    @Schema(description = "鎮h�呭湴鍧�")
+    private String patAddr;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ瀹や唬鐮�")
+    private String patDeptCode;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ瀹ゅ悕绉�")
+    private String patDeptDesc;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ梾鍖轰唬鐮�")
+    private String patWardCode;
+
+    @Schema(description = "鎮h�呮墍鍦ㄧ梾鍖哄悕绉�")
+    private String patWardDesc;
+
+    @Schema(description = "搴婂彿")
+    private String patBedNo;
+
+    @Schema(description = "棰勭害缂栧彿", requiredMode = Schema.RequiredMode.REQUIRED, example = "27849")
+    @NotEmpty(message = "棰勭害缂栧彿涓嶈兘涓虹┖")
+    private String bookId;
+
+    @Schema(description = "棰勭害妫�鏌ユ椂闂存", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "棰勭害妫�鏌ユ椂闂存涓嶈兘涓虹┖")
+    private LocalDateTime bookPeriodStart;
+
+    @Schema(description = "棰勭害妫�鏌ユ椂闂存", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "棰勭害妫�鏌ユ椂闂存涓嶈兘涓虹┖")
+    private LocalDateTime bookPeriodEnd;
+
+    @Schema(description = "棰勭害鍙戠敓鏃堕棿", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "棰勭害鍙戠敓鏃堕棿涓嶈兘涓虹┖")
+    private LocalDateTime bookTime;
+
+    @Schema(description = "棰勭害妫�鏌ョ被鍨�", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotNull(message = "棰勭害妫�鏌ョ被鍨嬩笉鑳戒负绌�")
+    private Boolean bookCheckType;
+
+}
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/appointment/AppointmentDO.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/appointment/AppointmentDO.java
new file mode 100644
index 0000000..12846e0
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/dataobject/appointment/AppointmentDO.java
@@ -0,0 +1,119 @@
+package cn.lihu.jh.module.ecg.dal.dataobject.appointment;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.lihu.jh.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 棰勭害 DO
+ *
+ * @author 椹墤娉�
+ */
+@TableName("appointment")
+@KeySequence("appointment_seq") // 鐢ㄤ簬 Oracle銆丳ostgreSQL銆並ingbase銆丏B2銆丠2 鏁版嵁搴撶殑涓婚敭鑷銆傚鏋滄槸 MySQL 绛夋暟鎹簱锛屽彲涓嶅啓銆�
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AppointmentDO extends BaseDO {
+
+    /**
+     * id
+     */
+    @TableId
+    private Integer id;
+    /**
+     * 鎮h�呯紪鍙�
+     */
+    private String patId;
+    /**
+     * 鎮h�呭鍚�
+     */
+    private String patName;
+    /**
+     * 鎮h�呮�у埆
+     *
+     * 鏋氫妇 {@link TODO system_user_sex 瀵瑰簲鐨勭被}
+     */
+    private Boolean patGender;
+    /**
+     * 鎮h�呯敓鏃�
+     */
+    private LocalDate patBirthday;
+    /**
+     * 鎮h�呮墜鏈�
+     */
+    private String patMobile;
+    /**
+     * 鎮h�呯數璇�
+     */
+    private String patPhone;
+    /**
+     * 韬唤璇佸彿
+     */
+    private String patIdentityId;
+    /**
+     * 鎮h�呭湴鍧�
+     */
+    private String patAddr;
+    /**
+     * 鎮h�呮墍鍦ㄧ瀹や唬鐮�
+     */
+    private String patDeptCode;
+    /**
+     * 鎮h�呮墍鍦ㄧ瀹ゅ悕绉�
+     */
+    private String patDeptDesc;
+    /**
+     * 鎮h�呮墍鍦ㄧ梾鍖轰唬鐮�
+     */
+    private String patWardCode;
+    /**
+     * 鎮h�呮墍鍦ㄧ梾鍖哄悕绉�
+     */
+    private String patWardDesc;
+    /**
+     * 搴婂彿
+     */
+    private String patBedNo;
+    /**
+     * 棰勭害缂栧彿
+     */
+    private String bookId;
+    /**
+     * 棰勭害妫�鏌ユ椂闂存
+     */
+    private LocalDateTime bookPeriodStart;
+    /**
+     * 棰勭害妫�鏌ユ椂闂存
+     */
+    private LocalDateTime bookPeriodEnd;
+    /**
+     * 棰勭害鍙戠敓鏃堕棿
+     */
+    private LocalDateTime bookTime;
+    /**
+     * 棰勭害妫�鏌ョ被鍨�
+     *
+     * 鏋氫妇 {@link TODO ecg_check_type 瀵瑰簲鐨勭被}
+     */
+    private Boolean bookCheckType;
+    /**
+     * 棰勭害鏉ユ簮锛歑绯荤粺銆佹姢澹墜鍔ㄩ绾�
+     */
+    private String bookSrc;
+    /**
+     * 浠庢暟鎹钩鍙板悓姝ユ椂闂�
+     */
+    private LocalDateTime syncTime;
+
+}
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/appointment/AppointmentMapper.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/appointment/AppointmentMapper.java
new file mode 100644
index 0000000..666cea2
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/dal/mysql/appointment/AppointmentMapper.java
@@ -0,0 +1,44 @@
+package cn.lihu.jh.module.ecg.dal.mysql.appointment;
+
+import java.util.*;
+
+import cn.lihu.jh.framework.common.pojo.PageResult;
+import cn.lihu.jh.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.lihu.jh.framework.mybatis.core.mapper.BaseMapperX;
+import cn.lihu.jh.module.ecg.dal.dataobject.appointment.AppointmentDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.*;
+
+/**
+ * 棰勭害 Mapper
+ *
+ * @author 椹墤娉�
+ */
+@Mapper
+public interface AppointmentMapper extends BaseMapperX<AppointmentDO> {
+
+    default PageResult<AppointmentDO> selectPage(AppointmentPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<AppointmentDO>()
+                .eqIfPresent(AppointmentDO::getPatId, reqVO.getPatId())
+                .likeIfPresent(AppointmentDO::getPatName, reqVO.getPatName())
+                .eqIfPresent(AppointmentDO::getPatGender, reqVO.getPatGender())
+                .eqIfPresent(AppointmentDO::getPatBirthday, reqVO.getPatBirthday())
+                .eqIfPresent(AppointmentDO::getPatMobile, reqVO.getPatMobile())
+                .eqIfPresent(AppointmentDO::getPatPhone, reqVO.getPatPhone())
+                .eqIfPresent(AppointmentDO::getPatIdentityId, reqVO.getPatIdentityId())
+                .eqIfPresent(AppointmentDO::getPatAddr, reqVO.getPatAddr())
+                .eqIfPresent(AppointmentDO::getPatDeptCode, reqVO.getPatDeptCode())
+                .eqIfPresent(AppointmentDO::getPatDeptDesc, reqVO.getPatDeptDesc())
+                .eqIfPresent(AppointmentDO::getPatWardCode, reqVO.getPatWardCode())
+                .eqIfPresent(AppointmentDO::getPatWardDesc, reqVO.getPatWardDesc())
+                .eqIfPresent(AppointmentDO::getPatBedNo, reqVO.getPatBedNo())
+                .eqIfPresent(AppointmentDO::getBookId, reqVO.getBookId())
+                .eqIfPresent(AppointmentDO::getBookPeriodStart, reqVO.getBookPeriodStart())
+                .eqIfPresent(AppointmentDO::getBookPeriodEnd, reqVO.getBookPeriodEnd())
+                .betweenIfPresent(AppointmentDO::getBookTime, reqVO.getBookTime())
+                .eqIfPresent(AppointmentDO::getBookCheckType, reqVO.getBookCheckType())
+                .eqIfPresent(AppointmentDO::getBookSrc, reqVO.getBookSrc())
+                .orderByDesc(AppointmentDO::getId));
+    }
+
+}
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentService.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentService.java
new file mode 100644
index 0000000..b2b19a1
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentService.java
@@ -0,0 +1,55 @@
+package cn.lihu.jh.module.ecg.service.appointment;
+
+import java.util.*;
+import jakarta.validation.*;
+import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.*;
+import cn.lihu.jh.module.ecg.dal.dataobject.appointment.AppointmentDO;
+import cn.lihu.jh.framework.common.pojo.PageResult;
+import cn.lihu.jh.framework.common.pojo.PageParam;
+
+/**
+ * 棰勭害 Service 鎺ュ彛
+ *
+ * @author 椹墤娉�
+ */
+public interface AppointmentService {
+
+    /**
+     * 鍒涘缓棰勭害
+     *
+     * @param createReqVO 鍒涘缓淇℃伅
+     * @return 缂栧彿
+     */
+    Integer createAppointment(@Valid AppointmentSaveReqVO createReqVO);
+
+    /**
+     * 鏇存柊棰勭害
+     *
+     * @param updateReqVO 鏇存柊淇℃伅
+     */
+    void updateAppointment(@Valid AppointmentSaveReqVO updateReqVO);
+
+    /**
+     * 鍒犻櫎棰勭害
+     *
+     * @param id 缂栧彿
+     */
+    void deleteAppointment(Integer id);
+
+    /**
+     * 鑾峰緱棰勭害
+     *
+     * @param id 缂栧彿
+     * @return 棰勭害
+     */
+    AppointmentDO getAppointment(Integer id);
+
+    /**
+     * 鑾峰緱棰勭害鍒嗛〉
+     *
+     * @param pageReqVO 鍒嗛〉鏌ヨ
+     * @return 棰勭害鍒嗛〉
+     */
+    PageResult<AppointmentDO> getAppointmentPage(AppointmentPageReqVO pageReqVO);
+
+}
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java
new file mode 100644
index 0000000..cf0654b
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImpl.java
@@ -0,0 +1,74 @@
+package cn.lihu.jh.module.ecg.service.appointment;
+
+import org.springframework.stereotype.Service;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.*;
+import cn.lihu.jh.module.ecg.dal.dataobject.appointment.AppointmentDO;
+import cn.lihu.jh.framework.common.pojo.PageResult;
+import cn.lihu.jh.framework.common.pojo.PageParam;
+import cn.lihu.jh.framework.common.util.object.BeanUtils;
+
+import cn.lihu.jh.module.ecg.dal.mysql.appointment.AppointmentMapper;
+
+import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.*;
+
+/**
+ * 棰勭害 Service 瀹炵幇绫�
+ *
+ * @author 椹墤娉�
+ */
+@Service
+@Validated
+public class AppointmentServiceImpl implements AppointmentService {
+
+    @Resource
+    private AppointmentMapper appointmentMapper;
+
+    @Override
+    public Integer createAppointment(AppointmentSaveReqVO createReqVO) {
+        // 鎻掑叆
+        AppointmentDO appointment = BeanUtils.toBean(createReqVO, AppointmentDO.class);
+        appointmentMapper.insert(appointment);
+        // 杩斿洖
+        return appointment.getId();
+    }
+
+    @Override
+    public void updateAppointment(AppointmentSaveReqVO updateReqVO) {
+        // 鏍¢獙瀛樺湪
+        validateAppointmentExists(updateReqVO.getId());
+        // 鏇存柊
+        AppointmentDO updateObj = BeanUtils.toBean(updateReqVO, AppointmentDO.class);
+        appointmentMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteAppointment(Integer id) {
+        // 鏍¢獙瀛樺湪
+        validateAppointmentExists(id);
+        // 鍒犻櫎
+        appointmentMapper.deleteById(id);
+    }
+
+    private void validateAppointmentExists(Integer id) {
+        if (appointmentMapper.selectById(id) == null) {
+            throw exception(APPOINTMENT_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public AppointmentDO getAppointment(Integer id) {
+        return appointmentMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<AppointmentDO> getAppointmentPage(AppointmentPageReqVO pageReqVO) {
+        return appointmentMapper.selectPage(pageReqVO);
+    }
+
+}
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/resources/mapper/appointment/AppointmentMapper.xml b/jh-module-ecg/jh-module-ecg-biz/src/main/resources/mapper/appointment/AppointmentMapper.xml
new file mode 100644
index 0000000..29a842c
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/resources/mapper/appointment/AppointmentMapper.xml
@@ -0,0 +1,12 @@
+<?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="cn.lihu.jh.module.ecg.dal.mysql.appointment.AppointmentMapper">
+
+    <!--
+        涓�鑸儏鍐典笅锛屽敖鍙兘浣跨敤 Mapper 杩涜 CRUD 澧炲垹鏀规煡鍗冲彲銆�
+        鏃犳硶婊¤冻鐨勫満鏅紝渚嬪璇村琛ㄥ叧鑱旀煡璇紝鎵嶄娇鐢� XML 缂栧啓 SQL銆�
+        浠g爜鐢熸垚鍣ㄦ殏鏃跺彧鐢熸垚 Mapper XML 鏂囦欢鏈韩锛屾洿澶氭帹鑽� MybatisX 蹇�熷紑鍙戞彃浠舵潵鐢熸垚鏌ヨ銆�
+        鏂囨。鍙锛歨ttps://www.iocoder.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>
\ No newline at end of file
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/test/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImplTest.java b/jh-module-ecg/jh-module-ecg-biz/src/test/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImplTest.java
new file mode 100644
index 0000000..1aa3885
--- /dev/null
+++ b/jh-module-ecg/jh-module-ecg-biz/src/test/java/cn/lihu/jh/module/ecg/service/appointment/AppointmentServiceImplTest.java
@@ -0,0 +1,202 @@
+package cn.lihu.jh.module.ecg.service.appointment;
+
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import jakarta.annotation.Resource;
+
+import cn.lihu.jh.framework.test.core.ut.BaseDbUnitTest;
+
+import cn.lihu.jh.module.ecg.controller.admin.appointment.vo.*;
+import cn.lihu.jh.module.ecg.dal.dataobject.appointment.AppointmentDO;
+import cn.lihu.jh.module.ecg.dal.mysql.appointment.AppointmentMapper;
+import cn.lihu.jh.framework.common.pojo.PageResult;
+
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Import;
+import java.util.*;
+import java.time.LocalDateTime;
+
+import static cn.hutool.core.util.RandomUtil.*;
+import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.*;
+import static cn.lihu.jh.framework.test.core.util.AssertUtils.*;
+import static cn.lihu.jh.framework.test.core.util.RandomUtils.*;
+import static cn.lihu.jh.framework.common.util.date.LocalDateTimeUtils.*;
+import static cn.lihu.jh.framework.common.util.object.ObjectUtils.*;
+import static cn.lihu.jh.framework.common.util.date.DateUtils.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * {@link AppointmentServiceImpl} 鐨勫崟鍏冩祴璇曠被
+ *
+ * @author 椹墤娉�
+ */
+@Import(AppointmentServiceImpl.class)
+public class AppointmentServiceImplTest extends BaseDbUnitTest {
+
+    @Resource
+    private AppointmentServiceImpl appointmentService;
+
+    @Resource
+    private AppointmentMapper appointmentMapper;
+
+    @Test
+    public void testCreateAppointment_success() {
+        // 鍑嗗鍙傛暟
+        AppointmentSaveReqVO createReqVO = randomPojo(AppointmentSaveReqVO.class).setId(null);
+
+        // 璋冪敤
+        Integer appointmentId = appointmentService.createAppointment(createReqVO);
+        // 鏂█
+        assertNotNull(appointmentId);
+        // 鏍¢獙璁板綍鐨勫睘鎬ф槸鍚︽纭�
+        AppointmentDO appointment = appointmentMapper.selectById(appointmentId);
+        assertPojoEquals(createReqVO, appointment, "id");
+    }
+
+    @Test
+    public void testUpdateAppointment_success() {
+        // mock 鏁版嵁
+        AppointmentDO dbAppointment = randomPojo(AppointmentDO.class);
+        appointmentMapper.insert(dbAppointment);// @Sql: 鍏堟彃鍏ュ嚭涓�鏉″瓨鍦ㄧ殑鏁版嵁
+        // 鍑嗗鍙傛暟
+        AppointmentSaveReqVO updateReqVO = randomPojo(AppointmentSaveReqVO.class, o -> {
+            o.setId(dbAppointment.getId()); // 璁剧疆鏇存柊鐨� ID
+        });
+
+        // 璋冪敤
+        appointmentService.updateAppointment(updateReqVO);
+        // 鏍¢獙鏄惁鏇存柊姝g‘
+        AppointmentDO appointment = appointmentMapper.selectById(updateReqVO.getId()); // 鑾峰彇鏈�鏂扮殑
+        assertPojoEquals(updateReqVO, appointment);
+    }
+
+    @Test
+    public void testUpdateAppointment_notExists() {
+        // 鍑嗗鍙傛暟
+        AppointmentSaveReqVO updateReqVO = randomPojo(AppointmentSaveReqVO.class);
+
+        // 璋冪敤, 骞舵柇瑷�寮傚父
+        assertServiceException(() -> appointmentService.updateAppointment(updateReqVO), APPOINTMENT_NOT_EXISTS);
+    }
+
+    @Test
+    public void testDeleteAppointment_success() {
+        // mock 鏁版嵁
+        AppointmentDO dbAppointment = randomPojo(AppointmentDO.class);
+        appointmentMapper.insert(dbAppointment);// @Sql: 鍏堟彃鍏ュ嚭涓�鏉″瓨鍦ㄧ殑鏁版嵁
+        // 鍑嗗鍙傛暟
+        Integer id = dbAppointment.getId();
+
+        // 璋冪敤
+        appointmentService.deleteAppointment(id);
+       // 鏍¢獙鏁版嵁涓嶅瓨鍦ㄤ簡
+       assertNull(appointmentMapper.selectById(id));
+    }
+
+    @Test
+    public void testDeleteAppointment_notExists() {
+        // 鍑嗗鍙傛暟
+        Integer id = randomIntegerId();
+
+        // 璋冪敤, 骞舵柇瑷�寮傚父
+        assertServiceException(() -> appointmentService.deleteAppointment(id), APPOINTMENT_NOT_EXISTS);
+    }
+
+    @Test
+    @Disabled  // TODO 璇蜂慨鏀� null 涓洪渶瑕佺殑鍊硷紝鐒跺悗鍒犻櫎 @Disabled 娉ㄨВ
+    public void testGetAppointmentPage() {
+       // mock 鏁版嵁
+       AppointmentDO dbAppointment = randomPojo(AppointmentDO.class, o -> { // 绛変細鏌ヨ鍒�
+           o.setPatId(null);
+           o.setPatName(null);
+           o.setPatGender(null);
+           o.setPatBirthday(null);
+           o.setPatMobile(null);
+           o.setPatPhone(null);
+           o.setPatIdentityId(null);
+           o.setPatAddr(null);
+           o.setPatDeptCode(null);
+           o.setPatDeptDesc(null);
+           o.setPatWardCode(null);
+           o.setPatWardDesc(null);
+           o.setPatBedNo(null);
+           o.setBookId(null);
+           o.setBookPeriodStart(null);
+           o.setBookPeriodEnd(null);
+           o.setBookTime(null);
+           o.setBookCheckType(null);
+           o.setBookSrc(null);
+       });
+       appointmentMapper.insert(dbAppointment);
+       // 娴嬭瘯 patId 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatId(null)));
+       // 娴嬭瘯 patName 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatName(null)));
+       // 娴嬭瘯 patGender 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatGender(null)));
+       // 娴嬭瘯 patBirthday 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatBirthday(null)));
+       // 娴嬭瘯 patMobile 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatMobile(null)));
+       // 娴嬭瘯 patPhone 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatPhone(null)));
+       // 娴嬭瘯 patIdentityId 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatIdentityId(null)));
+       // 娴嬭瘯 patAddr 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatAddr(null)));
+       // 娴嬭瘯 patDeptCode 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatDeptCode(null)));
+       // 娴嬭瘯 patDeptDesc 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatDeptDesc(null)));
+       // 娴嬭瘯 patWardCode 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatWardCode(null)));
+       // 娴嬭瘯 patWardDesc 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatWardDesc(null)));
+       // 娴嬭瘯 patBedNo 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setPatBedNo(null)));
+       // 娴嬭瘯 bookId 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setBookId(null)));
+       // 娴嬭瘯 bookPeriodStart 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setBookPeriodStart(null)));
+       // 娴嬭瘯 bookPeriodEnd 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setBookPeriodEnd(null)));
+       // 娴嬭瘯 bookTime 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setBookTime(null)));
+       // 娴嬭瘯 bookCheckType 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setBookCheckType(null)));
+       // 娴嬭瘯 bookSrc 涓嶅尮閰�
+       appointmentMapper.insert(cloneIgnoreId(dbAppointment, o -> o.setBookSrc(null)));
+       // 鍑嗗鍙傛暟
+       AppointmentPageReqVO reqVO = new AppointmentPageReqVO();
+       reqVO.setPatId(null);
+       reqVO.setPatName(null);
+       reqVO.setPatGender(null);
+       reqVO.setPatBirthday(null);
+       reqVO.setPatMobile(null);
+       reqVO.setPatPhone(null);
+       reqVO.setPatIdentityId(null);
+       reqVO.setPatAddr(null);
+       reqVO.setPatDeptCode(null);
+       reqVO.setPatDeptDesc(null);
+       reqVO.setPatWardCode(null);
+       reqVO.setPatWardDesc(null);
+       reqVO.setPatBedNo(null);
+       reqVO.setBookId(null);
+       reqVO.setBookPeriodStart(null);
+       reqVO.setBookPeriodEnd(null);
+       reqVO.setBookTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
+       reqVO.setBookCheckType(null);
+       reqVO.setBookSrc(null);
+
+       // 璋冪敤
+       PageResult<AppointmentDO> pageResult = appointmentService.getAppointmentPage(reqVO);
+       // 鏂█
+       assertEquals(1, pageResult.getTotal());
+       assertEquals(1, pageResult.getList().size());
+       assertPojoEquals(dbAppointment, pageResult.getList().get(0));
+    }
+
+}
\ No newline at end of file
diff --git a/jh-module-ecg/pom.xml b/jh-module-ecg/pom.xml
new file mode 100644
index 0000000..997f5c0
--- /dev/null
+++ b/jh-module-ecg/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>cn.lihu</groupId>
+        <artifactId>jh</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <modules>
+        <module>jh-module-ecg-api</module>
+        <module>jh-module-ecg-biz</module>
+    </modules>
+    <artifactId>jh-module-ecg</artifactId>
+    <packaging>pom</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>
+        XX鍖婚櫌蹇冪數绉戞ā鍧�
+    </description>
+
+</project>
diff --git a/sql/mysql/jh.sql b/sql/mysql/jh.sql
index c11eef2..e6ca7aa 100644
--- a/sql/mysql/jh.sql
+++ b/sql/mysql/jh.sql
@@ -11,7 +11,7 @@
   `pat_id` varchar(30) NOT NULL COMMENT '鎮h�呯紪鍙�',
   `pat_name` varchar(10) NOT NULL COMMENT '鎮h�呭鍚�',
   `pat_gender` bit(1) NOT NULL COMMENT '鎮h�呮�у埆',
-  `pat_birthday` date DEFAULT NULL COMMENT '鎮h�呯敓鏃�',
+  `pat_birthday` datetime DEFAULT NULL COMMENT '鎮h�呯敓鏃�',
   `pat_mobile` char(11) DEFAULT NULL COMMENT '鎮h�呮墜鏈�',
   `pat_phone` varchar(20) DEFAULT NULL COMMENT '鎮h�呯數璇�',
   `pat_identity_id` varchar(20) DEFAULT NULL COMMENT '韬唤璇佸彿',

--
Gitblit v1.9.3