1월21일 작업
This commit is contained in:
@@ -12,6 +12,7 @@ import org.springframework.web.servlet.ModelAndView;
|
|||||||
|
|
||||||
import com.madeu.constants.Constants;
|
import com.madeu.constants.Constants;
|
||||||
import com.madeu.crm.kiosk.dto.ConsentFormDTO;
|
import com.madeu.crm.kiosk.dto.ConsentFormDTO;
|
||||||
|
import com.madeu.crm.kiosk.dto.UserDTO;
|
||||||
import com.madeu.crm.kiosk.service.KioskService;
|
import com.madeu.crm.kiosk.service.KioskService;
|
||||||
import com.madeu.init.ManagerDraftAction;
|
import com.madeu.init.ManagerDraftAction;
|
||||||
import com.madeu.service.web.webloghistory.WebLogHistoryService;
|
import com.madeu.service.web.webloghistory.WebLogHistoryService;
|
||||||
@@ -205,61 +206,32 @@ public class KioskController extends ManagerDraftAction {
|
|||||||
* 고객 등록
|
* 고객 등록
|
||||||
*/
|
*/
|
||||||
@PostMapping("/kiosk/putUser.do")
|
@PostMapping("/kiosk/putUser.do")
|
||||||
public HashMap<String, Object> putUser(HttpServletRequest request, HttpServletResponse response) {
|
public HashMap<String, Object> putUser(@RequestBody UserDTO dto, HttpServletRequest request) {
|
||||||
log.debug("KioskController putUser START");
|
log.debug("KioskController putUser START");
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
HashMap<String, Object> resultMap = new HashMap<>();
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
paramMap.put("loginMemberId", "customer");
|
// DTO에 직접 필요한 공통 정보 세팅
|
||||||
paramMap.put("regId", "customer");
|
dto.setRegId("customer");
|
||||||
paramMap.put("modId", "customer");
|
dto.setModId("customer");
|
||||||
map = kioskService.putUser(paramMap);
|
dto.setMuUserId("U");
|
||||||
|
|
||||||
|
// DTO를 직접 서비스로 전달 (Service 인터페이스도 UserDTO를 받도록 수정 필요)
|
||||||
|
resultMap = kioskService.putUser(dto);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.error("Error inserting user", e);
|
||||||
map.put("msgCode", Constants.FAIL);
|
resultMap.put("msgCode", Constants.FAIL);
|
||||||
map.put("msgDesc", "서버 오류가 발생했습니다.");
|
resultMap.put("msgDesc", "서버 오류가 발생했습니다.");
|
||||||
errorMsg.append(e.getMessage());
|
errorMsg.append(e.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
if (Constants.OK != map.get("msgCode")) {
|
// 결과 처리 및 로그 기록 (기존과 동일)
|
||||||
map.put("msgCode", Constants.FAIL);
|
processFinalResult(resultMap, dto, errorMsg, request);
|
||||||
map.put("success", false);
|
|
||||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
|
||||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 로그 기록
|
return resultMap;
|
||||||
try {
|
|
||||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
|
||||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
insertMap.put("url", "/kiosk/putUser.do");
|
|
||||||
insertMap.put("func", "putUser");
|
|
||||||
insertMap.put("funcName", "고객 등록");
|
|
||||||
insertMap.put("service", "kioskService");
|
|
||||||
insertMap.put("serviceName", "고객 등록");
|
|
||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
|
||||||
insertMap.put("tId", map.get("tId"));
|
|
||||||
if (("").equals(String.valueOf(errorMsg)) || null == (String.valueOf(errorMsg))
|
|
||||||
|| 0 == String.valueOf(errorMsg).length()) {
|
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
|
||||||
} else {
|
|
||||||
insertMap.put("resultCode", "ERROR");
|
|
||||||
}
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
|
||||||
insertMap.put("muMemberId", "customer");
|
|
||||||
|
|
||||||
webLogHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.debug("KioskController putUser END");
|
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -437,4 +409,55 @@ public class KioskController extends ManagerDraftAction {
|
|||||||
log.debug("KioskController getReserveUserOptionList END");
|
log.debug("KioskController getReserveUserOptionList END");
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 결과 처리 및 공통 응답 포맷 정리, 로그 기록 준비 메서드
|
||||||
|
*/
|
||||||
|
private void processFinalResult(HashMap<String, Object> resultMap, UserDTO dto, StringBuffer errorMsg, HttpServletRequest request) {
|
||||||
|
|
||||||
|
// 1. 결과 코드에 따른 성공 여부 및 기본 메시지 설정
|
||||||
|
if (!Constants.OK.equals(resultMap.get("msgCode"))) {
|
||||||
|
resultMap.put("msgCode", Constants.FAIL);
|
||||||
|
resultMap.put("success", false);
|
||||||
|
if (null == resultMap.get("msgDesc") || "".equals(resultMap.get("msgDesc"))) {
|
||||||
|
resultMap.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resultMap.put("success", true);
|
||||||
|
if (null == resultMap.get("msgDesc") || "".equals(resultMap.get("msgDesc"))) {
|
||||||
|
resultMap.put("msgDesc", "성공적으로 등록되었습니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 웹 로그 기록 (비동기 또는 서비스 호출)
|
||||||
|
try {
|
||||||
|
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
||||||
|
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
insertMap.put("url", "/kiosk/putUser.do");
|
||||||
|
insertMap.put("func", "putUser");
|
||||||
|
insertMap.put("funcName", "고객 등록");
|
||||||
|
insertMap.put("service", "kioskService");
|
||||||
|
insertMap.put("serviceName", "고객 등록");
|
||||||
|
|
||||||
|
// DTO의 toString()을 사용하여 요청 파라미터 기록
|
||||||
|
insertMap.put("requestValue", dto != null ? dto.toString() : "NULL");
|
||||||
|
insertMap.put("responseValue", String.valueOf(resultMap));
|
||||||
|
insertMap.put("tId", resultMap.get("tId"));
|
||||||
|
|
||||||
|
if (errorMsg.length() == 0) {
|
||||||
|
insertMap.put("resultCode", "SUCCESS");
|
||||||
|
} else {
|
||||||
|
insertMap.put("resultCode", "ERROR");
|
||||||
|
}
|
||||||
|
insertMap.put("resultMsg", errorMsg.toString());
|
||||||
|
insertMap.put("muMemberId", "customer");
|
||||||
|
|
||||||
|
// 로그 서비스 호출
|
||||||
|
webLogHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Log History Insertion Error: ", e);
|
||||||
|
// 로그 기록 실패가 비즈니스 로직에 영향을 주지 않도록 내부에서 예외 처리
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
48
src/main/java/com/madeu/crm/kiosk/dto/UserDTO.java
Normal file
48
src/main/java/com/madeu/crm/kiosk/dto/UserDTO.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package com.madeu.crm.kiosk.dto;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class UserDTO {
|
||||||
|
// MyBatis mapping 필드
|
||||||
|
private String muUserId; // 유저 ID 생성용 접두어
|
||||||
|
private String userName; // 고객명
|
||||||
|
private String nationality; // 국적 아이템 코드
|
||||||
|
private String nationalityCode; // 국적 카테고리 코드 (C202404110001)
|
||||||
|
private String birthday; // 생년월일 (YYYYMMDD)
|
||||||
|
private String gender; // 성별 (M/F)
|
||||||
|
private String userRrn1; // 주민번호 앞자리
|
||||||
|
private String userRrn2; // 주민번호 뒷자리
|
||||||
|
private String userPno; // 여권번호
|
||||||
|
private String userArc1; // 외국인등록번호 앞자리 (필요시)
|
||||||
|
private String userArc2; // 외국인등록번호 뒷자리 (필요시)
|
||||||
|
private String userType; // 고객타입 아이템 코드
|
||||||
|
private String userTypeCode; // 고객타입 카테고리 코드
|
||||||
|
private String phoneNumber; // 연락처
|
||||||
|
private String phoneNumber2; // 보조 연락처
|
||||||
|
private String muGroupId; // 그룹 ID
|
||||||
|
private String channel; // 방문경로 아이템 코드
|
||||||
|
private String channelCode; // 방문경로 카테고리 코드 (C202404110003)
|
||||||
|
private String introUserId; // 추천인 고객 ID (텍스트 입력값)
|
||||||
|
private String introMemberId; // 추천직원 ID
|
||||||
|
private String etc; // 특이사항
|
||||||
|
private String memo; // 메모
|
||||||
|
private String smsYn; // SMS 수신여부 (Y/N)
|
||||||
|
private String refusePhotoYn; // 사진촬영동의여부 (Y/N)
|
||||||
|
private String remark; // 비고
|
||||||
|
private String regId; // 등록자 ID
|
||||||
|
private String modId; // 수정자 ID
|
||||||
|
private String address;
|
||||||
|
private String addressDtl;
|
||||||
|
private String email;
|
||||||
|
private String introName;
|
||||||
|
private Map<String, Object> userNumber;
|
||||||
|
|
||||||
|
// 서명 데이터 (Base64)
|
||||||
|
private String signatureData;
|
||||||
|
}
|
||||||
@@ -2,8 +2,11 @@ package com.madeu.crm.kiosk.map;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
import com.madeu.crm.kiosk.dto.ConsentFormDTO;
|
import com.madeu.crm.kiosk.dto.ConsentFormDTO;
|
||||||
|
import com.madeu.crm.kiosk.dto.UserDTO;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface KioskMAP {
|
public interface KioskMAP {
|
||||||
@@ -42,4 +45,6 @@ public interface KioskMAP {
|
|||||||
|
|
||||||
// 예약 고객 옵션 리스트
|
// 예약 고객 옵션 리스트
|
||||||
List<Map<String, Object>> getReserveUserOptionList(Map<String, Object> paramMap);
|
List<Map<String, Object>> getReserveUserOptionList(Map<String, Object> paramMap);
|
||||||
|
|
||||||
|
int insertUser(UserDTO dto);
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.madeu.crm.kiosk.service;
|
package com.madeu.crm.kiosk.service;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -12,7 +12,9 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import com.madeu.constants.Constants;
|
import com.madeu.constants.Constants;
|
||||||
import com.madeu.crm.kiosk.dto.ConsentFormDTO;
|
import com.madeu.crm.kiosk.dto.ConsentFormDTO;
|
||||||
|
import com.madeu.crm.kiosk.dto.UserDTO;
|
||||||
import com.madeu.crm.kiosk.map.KioskMAP;
|
import com.madeu.crm.kiosk.map.KioskMAP;
|
||||||
|
import com.madeu.dao.web.webuser.WebUserSqlMapDAO;
|
||||||
import com.madeu.util.ValidationCheckUtil;
|
import com.madeu.util.ValidationCheckUtil;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -24,6 +26,8 @@ public class KioskService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private KioskMAP kioskMAP; // 인터페이스 기반 Mapper 주입
|
private KioskMAP kioskMAP; // 인터페이스 기반 Mapper 주입
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebUserSqlMapDAO webUserSqlMapDAO;
|
||||||
/**
|
/**
|
||||||
* 진료 리스트 조회 (option)
|
* 진료 리스트 조회 (option)
|
||||||
*/
|
*/
|
||||||
@@ -95,32 +99,67 @@ public class KioskService {
|
|||||||
/**
|
/**
|
||||||
* 고객 등록
|
* 고객 등록
|
||||||
*/
|
*/
|
||||||
public HashMap<String, Object> putUser(HashMap<String, Object> paramMap) throws Exception {
|
public HashMap<String, Object> putUser(UserDTO dto) throws Exception {
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boolean check = true;
|
boolean check = true;
|
||||||
String tId = String.valueOf(System.currentTimeMillis());
|
String tId = String.valueOf(System.currentTimeMillis());
|
||||||
|
|
||||||
// 유효성 검사 로직
|
// 1. DTO 필드를 이용한 유효성 검사 로직
|
||||||
if(!ValidationCheckUtil.emptyCheck(String.valueOf(paramMap.get("nationality")))) {
|
if(!ValidationCheckUtil.emptyCheck(dto.getNationality())) {
|
||||||
check = false; map.put("msgCode", Constants.FAIL); map.put("msgDesc","국적 정보가 없습니다.");
|
check = false; map.put("msgCode", Constants.FAIL); map.put("msgDesc","국적 정보가 없습니다.");
|
||||||
} else if(!ValidationCheckUtil.emptyCheck(String.valueOf(paramMap.get("userName")))) {
|
} else if(!ValidationCheckUtil.emptyCheck(dto.getUserName())) {
|
||||||
check = false; map.put("msgCode", Constants.FAIL); map.put("msgDesc","고객 성함 정보가 없습니다.");
|
check = false; map.put("msgCode", Constants.FAIL); map.put("msgDesc","고객 성함 정보가 없습니다.");
|
||||||
} else if(!ValidationCheckUtil.nickNameCheck(String.valueOf(paramMap.get("userName")))) {
|
} else if(!ValidationCheckUtil.nickNameCheck(dto.getUserName())) {
|
||||||
check = false; map.put("msgCode", Constants.FAIL); map.put("msgDesc","유효하지 않은 이름 형식입니다.");
|
check = false; map.put("msgCode", Constants.FAIL); map.put("msgDesc","유효하지 않은 이름 형식입니다.");
|
||||||
} else if(!ValidationCheckUtil.phoneNumberCheck(String.valueOf(paramMap.get("phoneNumber")))) {
|
} else if(!ValidationCheckUtil.phoneNumberCheck(dto.getPhoneNumber())) {
|
||||||
check = false; map.put("msgCode", Constants.FAIL); map.put("msgDesc","유효하지 않은 전화번호 형식입니다.");
|
check = false; map.put("msgCode", Constants.FAIL); map.put("msgDesc","유효하지 않은 전화번호 형식입니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(check) {
|
if(check) {
|
||||||
String muUserId = ("U").concat(String.valueOf(System.currentTimeMillis()));
|
String muUserId = ("U").concat(String.valueOf(System.currentTimeMillis()));
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
// 2. DTO에 필요한 추가 정보 세팅 (Setter 활용)
|
||||||
paramMap.put("muUserId", muUserId);
|
// muUserId는 매퍼의 selectKey에서 생성되지만, 접두어 등이 필요하다면 세팅
|
||||||
paramMap.put("tId", tId);
|
dto.setMuUserId(muUserId);
|
||||||
paramMap.put("tDate", sdf.format(Calendar.getInstance().getTime()));
|
|
||||||
|
// tId 등 로그용 데이터가 DTO에 필드로 정의되어 있다면 세팅,
|
||||||
|
// 없다면 결과 map에만 담아서 리턴
|
||||||
|
map.put("tId", tId);
|
||||||
|
|
||||||
|
// 3. MyBatis 매퍼 호출 (DTO 객체 자체를 전달)
|
||||||
|
kioskMAP.insertUser(dto);
|
||||||
|
//A: 개인정보수집및이용안내
|
||||||
|
//B: 메이드유시술동의서
|
||||||
|
//C: 이용약관동의서
|
||||||
|
//G: 사진촬영거부동의서
|
||||||
|
String[] types = {"A","B","C","G"};
|
||||||
|
HashMap<String, Object> consentFormMap = new HashMap<>();
|
||||||
|
for (String type : types) {
|
||||||
|
String muUserAgreementId = ("UA").concat(String.valueOf(System.currentTimeMillis()));
|
||||||
|
|
||||||
|
consentFormMap.put("muUserAgreementId", muUserAgreementId);
|
||||||
|
|
||||||
|
|
||||||
|
consentFormMap.put("muUserId", dto.getUserNumber().get("id"));
|
||||||
|
consentFormMap.put("userName", dto.getUserName());
|
||||||
|
consentFormMap.put("type", type);
|
||||||
|
consentFormMap.put("renewalCycle", 12);
|
||||||
|
|
||||||
|
LocalDateTime oneYearLater = LocalDateTime.now().plusYears(1);
|
||||||
|
|
||||||
|
// MariaDB DATETIME 표준 형식 (YYYY-MM-DD HH:mm:ss)
|
||||||
|
String expirationDate = oneYearLater.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
consentFormMap.put("expirationDate", expirationDate);
|
||||||
|
consentFormMap.put("cdnUrl", "-");
|
||||||
|
consentFormMap.put("filePath", "-");
|
||||||
|
consentFormMap.put("fileName", "-");
|
||||||
|
consentFormMap.put("originalFileName", "-");
|
||||||
|
consentFormMap.put("loginMemberId", "kiosk");
|
||||||
|
|
||||||
|
webUserSqlMapDAO.insertUserAgreement(consentFormMap);
|
||||||
|
}
|
||||||
|
|
||||||
kioskMAP.putUser(paramMap);
|
|
||||||
|
|
||||||
map.put("msgCode", Constants.OK);
|
map.put("msgCode", Constants.OK);
|
||||||
map.put("msgDesc", "등록되었습니다.");
|
map.put("msgDesc", "등록되었습니다.");
|
||||||
|
|||||||
@@ -148,7 +148,67 @@
|
|||||||
</if>
|
</if>
|
||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
<insert id="insertUser" parameterType="com.madeu.crm.kiosk.dto.UserDTO">
|
||||||
|
/** KioskMAP.insertUser **/
|
||||||
|
<selectKey resultType="HashMap" keyProperty="userNumber" order="BEFORE">
|
||||||
|
SELECT USER.id AS id
|
||||||
|
,USER.NUMBER AS number
|
||||||
|
,MCIN.MU_CATEGORY_ITEM_ID AS nationality
|
||||||
|
,MCIT.MU_CATEGORY_ITEM_ID AS userType
|
||||||
|
,MCIC.MU_CATEGORY_ITEM_ID AS channel
|
||||||
|
FROM (SELECT CONCAT('U', DATE_FORMAT(NOW(), '%Y%m%d'), '-', LPAD(IFNULL(MAX(SUBSTRING(USER_NUMBER, 11)) + 1, 1), 3, '0')) AS NUMBER
|
||||||
|
,CONCAT(#{muUserId}, LPAD((SELECT NEXTVAL(MU_USER_SEQ)), 11, 0)) AS id
|
||||||
|
FROM MU_USER AS MU
|
||||||
|
WHERE USER_NUMBER LIKE CONCAT('U', DATE_FORMAT(NOW(), '%Y%m%d'), '%')
|
||||||
|
) AS USER
|
||||||
|
LEFT JOIN MU_CATEGORY_ITEM AS MCIN
|
||||||
|
ON MCIN.CATEGORY_CODE = #{nationalityCode}
|
||||||
|
AND MCIN.CATEGORY_ITEM_CODE = #{nationality}
|
||||||
|
LEFT JOIN MU_CATEGORY_ITEM AS MCIT
|
||||||
|
ON MCIT.CATEGORY_CODE = #{userTypeCode}
|
||||||
|
AND MCIT.CATEGORY_ITEM_CODE = #{userType}
|
||||||
|
LEFT JOIN MU_CATEGORY_ITEM AS MCIC
|
||||||
|
ON MCIC.CATEGORY_CODE = #{channelCode}
|
||||||
|
AND MCIC.CATEGORY_ITEM_CODE = #{channel}
|
||||||
|
</selectKey>
|
||||||
|
|
||||||
|
INSERT INTO MU_USER (
|
||||||
|
MU_USER_ID, USER_NUMBER, USER_NAME, NATIONALITY, BIRTHDAY, GENDER,
|
||||||
|
USER_RRN1, USER_RRN2, USER_PNO, USER_TYPE, PHONE_NUMBER,
|
||||||
|
CHANNEL, INTRO_USER_ID, ETC, SMS_YN, REFUSE_PHOTO_YN,
|
||||||
|
WRITE_DATE, WRITE_TIME, CUD_FLAG, USE_YN, REG_ID, REG_DATE, MOD_ID, MOD_DATE,
|
||||||
|
ADDRESS, ADDRESS_DETAILS, EMAIL, INTRO_NAME
|
||||||
|
) VALUES (
|
||||||
|
#{userNumber.id}
|
||||||
|
,#{userNumber.number}
|
||||||
|
,#{userName}
|
||||||
|
,#{userNumber.nationality}
|
||||||
|
,#{birthday}
|
||||||
|
,#{gender}
|
||||||
|
,#{userRrn1}
|
||||||
|
,#{userRrn2}
|
||||||
|
,#{userPno}
|
||||||
|
,#{userNumber.userType}
|
||||||
|
,#{phoneNumber}
|
||||||
|
,#{userNumber.channel}
|
||||||
|
,#{introUserId}
|
||||||
|
,#{etc}
|
||||||
|
,#{smsYn}
|
||||||
|
,#{refusePhotoYn}
|
||||||
|
,NOW()
|
||||||
|
,NOW()
|
||||||
|
,'C'
|
||||||
|
,'Y'
|
||||||
|
,#{regId}
|
||||||
|
,NOW()
|
||||||
|
,#{modId}
|
||||||
|
,NOW()
|
||||||
|
,#{address}
|
||||||
|
,#{addressDtl}
|
||||||
|
,#{email}
|
||||||
|
,#{introName}
|
||||||
|
)
|
||||||
|
</insert>
|
||||||
<insert id="putUser" parameterType="hashmap">
|
<insert id="putUser" parameterType="hashmap">
|
||||||
/** KioskSql.insertUser **/
|
/** KioskSql.insertUser **/
|
||||||
<selectKey resultType="HashMap" keyProperty="userNumber" order="BEFORE">
|
<selectKey resultType="HashMap" keyProperty="userNumber" order="BEFORE">
|
||||||
|
|||||||
@@ -754,3 +754,23 @@ button {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content:间-between; /* 제목은 왼쪽, 메시지는 오른쪽 혹은 적절한 간격 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.validation-msg {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #ff4d4f; /* 경고 빨간색 */
|
||||||
|
font-weight: normal;
|
||||||
|
margin-left: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
animation: fadeIn 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateX(-5px); }
|
||||||
|
to { opacity: 1; transform: translateX(0); }
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
this.choicesInstances = new Map();
|
this.choicesInstances = new Map();
|
||||||
this.data = {
|
this.data = {
|
||||||
nationality: '',
|
nationality: '',
|
||||||
nationalityCode: '', // 선택된 국적 코드 저장용
|
nationalityCode: '',
|
||||||
visitPath: ''
|
visitPath: ''
|
||||||
};
|
};
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
this.isInitialized = true;
|
this.isInitialized = true;
|
||||||
|
|
||||||
|
$('input').attr('autocomplete', 'off');
|
||||||
}
|
}
|
||||||
|
|
||||||
validateDependencies() { return !!($ && window.Choices); }
|
validateDependencies() { return !!($ && window.Choices); }
|
||||||
@@ -47,16 +48,15 @@
|
|||||||
if (nationalityInstance) {
|
if (nationalityInstance) {
|
||||||
const element = nationalityInstance.passedElement.element;
|
const element = nationalityInstance.passedElement.element;
|
||||||
element.addEventListener('change', (event) => {
|
element.addEventListener('change', (event) => {
|
||||||
this.data.nationalityCode = event.detail.value; // 국적 코드 업데이트
|
this.data.nationalityCode = event.detail.value;
|
||||||
this.updateUIByNationality(event.detail.value);
|
this.updateUIByNationality(event.detail.value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#modalAddress, #btnSearchAddress').on('click', () => {
|
$('#address, #btnSearchAddress').on('click', () => {
|
||||||
this.openAddrSearch();
|
this.openAddrSearch();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 체크박스 직접 클릭 방지 및 안내 문구 출력
|
|
||||||
const consentIds = ['#agreePrivacy', '#agreeProcedure', '#agreeTerms', '#refusePhoto'];
|
const consentIds = ['#agreePrivacy', '#agreeProcedure', '#agreeTerms', '#refusePhoto'];
|
||||||
$(consentIds.join(', ')).on('click', (e) => {
|
$(consentIds.join(', ')).on('click', (e) => {
|
||||||
if (!this.allowSystemCheck) {
|
if (!this.allowSystemCheck) {
|
||||||
@@ -64,8 +64,33 @@
|
|||||||
alert('동의서 보기 버튼을 클릭하여 내용을 확인하신 후 [동의함] 버튼을 눌러주세요.');
|
alert('동의서 보기 버튼을 클릭하여 내용을 확인하신 후 [동의함] 버튼을 눌러주세요.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$('#btnFillTestData').on('click', () => {
|
||||||
|
// 1. 기본 텍스트 정보
|
||||||
|
$('input[name="modalUserName"]').val('홍길동');
|
||||||
|
$('input[name="modalUserRrn1"]').val('950101');
|
||||||
|
$('input[name="modalUserRrn2"]').val('1234567').trigger('input'); // input 트리거로 생년월일/성별 로직 실행
|
||||||
|
$('input[name="modalPhoneNumber"]').val('01012345678');
|
||||||
|
$('input[name="address"]').val('서울특별시 강남구 테헤란로 123');
|
||||||
|
$('input[name="addressDtl"]').val('메이드유 빌딩 5층');
|
||||||
|
$('#email').val('test@madeu.com');
|
||||||
|
$('input[name="introName"]').val('관리자');
|
||||||
|
$('textarea[name="modalEtc"]').val('특이사항 없음 (테스트 데이터)');
|
||||||
|
|
||||||
|
// 2. 방문경로 (Choices.js 인스턴스 제어)
|
||||||
|
const channelInstance = this.choicesInstances.get('channel');
|
||||||
|
if (channelInstance) {
|
||||||
|
const firstVal = channelInstance.config.choices[1]?.value; // 첫 번째 옵션 선택
|
||||||
|
if (firstVal) channelInstance.setChoiceByValue(firstVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 동의서 항목 강제 체크
|
||||||
|
// 시스템 체크 허용 플래그를 일시적으로 켜서 click 방지 로직을 우회합니다.
|
||||||
|
this.allowSystemCheck = true;
|
||||||
|
$('#agreePrivacy, #agreeProcedure, #agreeTerms, #refusePhoto').prop('checked', true);
|
||||||
|
this.allowSystemCheck = false;
|
||||||
|
|
||||||
|
//alert('테스트 데이터가 입력되었습니다.');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUIByNationality(selectedCode) {
|
updateUIByNationality(selectedCode) {
|
||||||
@@ -122,7 +147,7 @@
|
|||||||
instance.setChoices(choices, 'value', 'label', true);
|
instance.setChoices(choices, 'value', 'label', true);
|
||||||
if (choicesKey === 'nationality') {
|
if (choicesKey === 'nationality') {
|
||||||
instance.setChoiceByValue(this.KOREA_CODE);
|
instance.setChoiceByValue(this.KOREA_CODE);
|
||||||
this.data.nationalityCode = this.KOREA_CODE; // 초기 국적 설정
|
this.data.nationalityCode = this.KOREA_CODE;
|
||||||
this.updateUIByNationality(this.KOREA_CODE);
|
this.updateUIByNationality(this.KOREA_CODE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,13 +156,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
openAddrSearch() {
|
openAddrSearch() {
|
||||||
// 1. 다이얼로그를 담을 컨테이너 생성 (없으면 생성)
|
|
||||||
let $addrDialog = $('#addrSearchDialog');
|
let $addrDialog = $('#addrSearchDialog');
|
||||||
if ($addrDialog.length === 0) {
|
if ($addrDialog.length === 0) {
|
||||||
$addrDialog = $('<div id="addrSearchDialog" style="display:none; overflow:hidden;"></div>').appendTo('body');
|
$addrDialog = $('<div id="addrSearchDialog" style="display:none; overflow:hidden;"></div>').appendTo('body');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. jQuery UI Dialog 초기화
|
|
||||||
$addrDialog.dialog({
|
$addrDialog.dialog({
|
||||||
modal: true,
|
modal: true,
|
||||||
title: '주소 검색',
|
title: '주소 검색',
|
||||||
@@ -147,14 +170,11 @@
|
|||||||
draggable: true,
|
draggable: true,
|
||||||
open: function() {
|
open: function() {
|
||||||
const guideElement = document.getElementById('addrSearchDialog');
|
const guideElement = document.getElementById('addrSearchDialog');
|
||||||
// 3. daum.Postcode를 해당 div 내(embed)에 실행
|
|
||||||
new daum.Postcode({
|
new daum.Postcode({
|
||||||
oncomplete: (data) => {
|
oncomplete: (data) => {
|
||||||
let addr = data.userSelectedType === 'R' ? data.roadAddress : data.jibunAddress;
|
let addr = data.userSelectedType === 'R' ? data.roadAddress : data.jibunAddress;
|
||||||
document.getElementById("modalAddress").value = addr;
|
document.getElementById("address").value = addr;
|
||||||
document.getElementById("modalAddressDetail").focus();
|
document.getElementById("addressDtl").focus();
|
||||||
|
|
||||||
// 선택 완료 후 다이얼로그 닫기
|
|
||||||
$addrDialog.dialog('close');
|
$addrDialog.dialog('close');
|
||||||
},
|
},
|
||||||
width: '100%',
|
width: '100%',
|
||||||
@@ -166,152 +186,59 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// NewPatientPage 클래스 내부에 추가
|
||||||
/**
|
savePatientData(signatureData) {
|
||||||
* [Modal] 고객 검색 팝업 클래스
|
// 서버 UserDTO 구조와 매핑될 데이터 수집
|
||||||
* 작성일 : 2024. 04. 02.
|
const param = {
|
||||||
* 작성자 : NTsoft (Refactored to Class)
|
userName: $('input[name="modalUserName"]').val(),
|
||||||
*/
|
nationality: this.data.nationalityCode, // Choices로 선택된 코드값
|
||||||
/**
|
nationalityCode: 'C202404110001', // 국적 카테고리 고정값
|
||||||
* [Modal] 고객 검색 팝업 클래스 (jQuery UI Dialog 버전)
|
birthday: $('#modalBirthday').val(),
|
||||||
*/
|
gender: $('input[name="modalGender"]:checked').val(),
|
||||||
class UserIntroSelectModal {
|
userRrn1: $('input[name="modalUserRrn1"]').val(),
|
||||||
constructor() {
|
userRrn2: $('input[name="modalUserRrn2"]').val(),
|
||||||
this.callback = null;
|
userPno: $('input[name="modalUserPno"]').val(),
|
||||||
this.dataList = null;
|
phoneNumber: $('input[name="modalPhoneNumber"]').val(),
|
||||||
this.modalId = 'userIntroSelectModal';
|
channel: $('#selectChannel').val(),
|
||||||
}
|
channelCode: 'C202404110003', // 방문경로 카테고리 고정값
|
||||||
|
introUserId: $('input[name="modalRecommendId"]').val(), // 추천인 텍스트
|
||||||
init() {
|
etc: $('textarea[name="modalEtc"]').val(),
|
||||||
$(`#${this.modalId}`).remove();
|
smsYn: $('input[name="modalSmsYn"]:checked').val(),
|
||||||
$('body').append(this.getHtmlTemplate());
|
refusePhotoYn: $('#refusePhoto').is(':checked') ? 'Y' : 'N',
|
||||||
|
signatureData: signatureData, // 서명 Base64 데이터
|
||||||
$(`#${this.modalId}`).dialog({
|
address: $('#address').val(),
|
||||||
autoOpen: false,
|
addressDtl: $('#addressDtl').val(),
|
||||||
modal: true,
|
email: $('#email').val(),
|
||||||
width: 450, // 3개 항목이므로 너비를 좀 더 슬림하게 조정
|
introName: $('#introName').val()
|
||||||
resizable: false,
|
|
||||||
draggable: true,
|
|
||||||
dialogClass: 'user-select-dialog', // CSS 커스텀 클래스 연결
|
|
||||||
open: function() {
|
|
||||||
$(".ui-dialog-titlebar").hide(); // 타이틀바 숨김
|
|
||||||
$('.ui-widget-overlay').css({ 'opacity': 0.5, 'background': '#000' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.setEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
setEvent() {
|
|
||||||
const $modal = $(`#${this.modalId}`);
|
|
||||||
$modal.find('.btnCancle').on("click", () => $modal.dialog("close"));
|
|
||||||
|
|
||||||
$modal.find('#searchIntroUserBtn').on('click', () => this.searchIntroUserList());
|
|
||||||
$modal.find('#introUserSearchKeyword').on('keypress', (e) => {
|
|
||||||
if (e.which === 13) this.searchIntroUserList();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
searchIntroUserList() {
|
|
||||||
const searchKeyword = document.querySelector("#introUserSearchKeyword").value;
|
|
||||||
if (searchKeyword.length < 2) {
|
|
||||||
alert("검색어를 2자 이상 입력해주세요.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append("menuClass", window.menuClass || "");
|
|
||||||
formData.append("userSearchKeywordParam", searchKeyword);
|
|
||||||
// 정렬 파라미터 추가
|
|
||||||
formData.append("userSort", "BIRTHDAY DESC");
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: encodeURI('/webuser/selectListUserOption.do'),
|
|
||||||
data: formData,
|
|
||||||
dataType: "json",
|
|
||||||
processData: false,
|
|
||||||
contentType: false,
|
|
||||||
type: 'POST',
|
|
||||||
success: (data) => {
|
|
||||||
if (data.msgCode === '0') this.renderTable(data.rows);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTable(rows) {
|
|
||||||
const tbody = document.querySelector(`#${this.modalId} tbody`);
|
|
||||||
tbody.innerHTML = "";
|
|
||||||
this.dataList = rows;
|
|
||||||
|
|
||||||
if (!rows || rows.length === 0) {
|
|
||||||
tbody.innerHTML = '<tr><td colspan="3" style="text-align: center; padding: 40px 0; color: #adb5bd;">조회 결과가 없습니다.</td></tr>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rows.forEach((user, index) => {
|
|
||||||
const genderClass = (user.gender === '남' || user.gender === 'M') ? 'gender-M' : 'gender-F';
|
|
||||||
const tr = document.createElement('tr');
|
|
||||||
tr.innerHTML = `
|
|
||||||
<td class="user-name">${user.userName}</td>
|
|
||||||
<td>${this.convertDateFormat(user.birthday)}</td>
|
|
||||||
<td><span class="gender-tag ${genderClass}">${user.gender}</span></td>
|
|
||||||
`;
|
|
||||||
tr.onclick = () => {
|
|
||||||
if (this.callback) this.callback(user);
|
|
||||||
$(`#${this.modalId}`).dialog("close");
|
|
||||||
};
|
};
|
||||||
tbody.appendChild(tr);
|
|
||||||
|
// 로딩바가 있다면 여기서 표시 (예: $.blockUI();)
|
||||||
|
console.log(param);
|
||||||
|
$.ajax({
|
||||||
|
url: '/kiosk/putUser.do',
|
||||||
|
type: 'POST',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify(param),
|
||||||
|
success: (res) => {
|
||||||
|
// Controller의 resultMap.put("success", true)와 대응
|
||||||
|
if (res.success) {
|
||||||
|
alert(res.msgDesc || '고객 등록이 완료되었습니다.');
|
||||||
|
location.href = '/kiosk'; // 완료 후 메인으로 이동
|
||||||
|
} else {
|
||||||
|
alert(res.msgDesc || '저장에 실패했습니다.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (xhr) => {
|
||||||
|
alert('서버와 통신 중 오류가 발생했습니다.');
|
||||||
|
console.error(xhr);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
popup(callback) {
|
|
||||||
this.init();
|
|
||||||
this.callback = callback;
|
|
||||||
$(`#${this.modalId}`).dialog("open");
|
|
||||||
}
|
|
||||||
|
|
||||||
convertDateFormat(input) {
|
|
||||||
if (!input) return '-';
|
|
||||||
const dateMatch = input.match(/\d{4}-\d{2}-\d{2}/);
|
|
||||||
return dateMatch ? dateMatch[0].replace(/-/g, '.') : input;
|
|
||||||
}
|
|
||||||
|
|
||||||
getHtmlTemplate() {
|
|
||||||
return `
|
|
||||||
<div id="${this.modalId}" style="display:none;">
|
|
||||||
<div class="search-header">
|
|
||||||
<div class="search-input-wrapper">
|
|
||||||
<input id="introUserSearchKeyword" type="text" placeholder="고객명 또는 생년월일" />
|
|
||||||
<button id="searchIntroUserBtn" class="btn-search">검색</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="table-wrapper">
|
|
||||||
<table class="user-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>성함</th>
|
|
||||||
<th>생년월일</th>
|
|
||||||
<th>성별</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td colspan="3" style="text-align: center; padding: 40px 0; color: #adb5bd;">검색어를 입력하세요.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer-ui">
|
|
||||||
<button type="button" class="btn-close-ui btnCancle">닫기</button>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Utility] 서명 다이얼로그 관리 클래스 (jQuery UI 버전)
|
* [Utility] 서명 다이얼로그 관리 클래스
|
||||||
*/
|
*/
|
||||||
class SignatureDialogManager {
|
class SignatureDialogManager {
|
||||||
constructor(modalId = 'agreementInsertModal') {
|
constructor(modalId = 'agreementInsertModal') {
|
||||||
@@ -320,16 +247,11 @@
|
|||||||
this.signaturePad = null;
|
this.signaturePad = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 다이얼로그 초기화 및 DOM 생성
|
|
||||||
*/
|
|
||||||
init() {
|
init() {
|
||||||
$(`#${this.modalId}`).remove();
|
$(`#${this.modalId}`).remove();
|
||||||
$('body').append(this.getHtmlTemplate());
|
$('body').append(this.getHtmlTemplate());
|
||||||
|
|
||||||
const $modal = $(`#${this.modalId}`);
|
const $modal = $(`#${this.modalId}`);
|
||||||
|
|
||||||
// jQuery UI Dialog 설정
|
|
||||||
$modal.dialog({
|
$modal.dialog({
|
||||||
autoOpen: false,
|
autoOpen: false,
|
||||||
modal: true,
|
modal: true,
|
||||||
@@ -339,7 +261,6 @@
|
|||||||
dialogClass: 'signature-ui-dialog',
|
dialogClass: 'signature-ui-dialog',
|
||||||
open: () => {
|
open: () => {
|
||||||
this.initSignaturePad();
|
this.initSignaturePad();
|
||||||
// 기본 타이틀바 숨기기 (커스텀 헤더 사용 시)
|
|
||||||
$(".ui-dialog-titlebar").hide();
|
$(".ui-dialog-titlebar").hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -347,9 +268,6 @@
|
|||||||
this.setEvent();
|
this.setEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 서명 패드 라이브러리 초기화
|
|
||||||
*/
|
|
||||||
initSignaturePad() {
|
initSignaturePad() {
|
||||||
const canvas = document.querySelector(`#${this.modalId} canvas`);
|
const canvas = document.querySelector(`#${this.modalId} canvas`);
|
||||||
if (!canvas) return;
|
if (!canvas) return;
|
||||||
@@ -361,13 +279,10 @@
|
|||||||
});
|
});
|
||||||
this.resizeCanvas(canvas);
|
this.resizeCanvas(canvas);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("SignaturePad 로드 실패. 라이브러리를 확인하세요.");
|
console.error("SignaturePad 로드 실패.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 캔버스 크기 최적화
|
|
||||||
*/
|
|
||||||
resizeCanvas(canvas) {
|
resizeCanvas(canvas) {
|
||||||
const ratio = Math.max(window.devicePixelRatio || 1, 1);
|
const ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||||
canvas.width = canvas.offsetWidth * ratio;
|
canvas.width = canvas.offsetWidth * ratio;
|
||||||
@@ -376,46 +291,29 @@
|
|||||||
if (this.signaturePad) this.signaturePad.clear();
|
if (this.signaturePad) this.signaturePad.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 이벤트 바인딩
|
|
||||||
*/
|
|
||||||
setEvent() {
|
setEvent() {
|
||||||
const $modal = $(`#${this.modalId}`);
|
const $modal = $(`#${this.modalId}`);
|
||||||
|
|
||||||
// 취소/닫기
|
|
||||||
$modal.find('.btnCancle').on('click', () => $modal.dialog('close'));
|
$modal.find('.btnCancle').on('click', () => $modal.dialog('close'));
|
||||||
|
|
||||||
// 지우기 (초기화)
|
|
||||||
$modal.find('.btnReset').on('click', () => {
|
$modal.find('.btnReset').on('click', () => {
|
||||||
if (this.signaturePad) this.signaturePad.clear();
|
if (this.signaturePad) this.signaturePad.clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 등록 완료 (저장)
|
|
||||||
$modal.find('.btnSave').on('click', () => {
|
$modal.find('.btnSave').on('click', () => {
|
||||||
if (this.signaturePad && this.signaturePad.isEmpty()) {
|
if (this.signaturePad && this.signaturePad.isEmpty()) {
|
||||||
alert("서명을 진행해 주세요.");
|
alert("서명을 진행해 주세요.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataUrl = this.signaturePad.toDataURL();
|
const dataUrl = this.signaturePad.toDataURL();
|
||||||
if (this.callback) this.callback(dataUrl);
|
if (this.callback) this.callback(dataUrl);
|
||||||
$modal.dialog('close');
|
$modal.dialog('close');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 다이얼로그 오픈
|
|
||||||
* @param {Function} callback 서명 완료 후 실행될 함수
|
|
||||||
*/
|
|
||||||
open(callback) {
|
open(callback) {
|
||||||
this.init();
|
this.init();
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
$(`#${this.modalId}`).dialog('open');
|
$(`#${this.modalId}`).dialog('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* HTML 템플릿
|
|
||||||
*/
|
|
||||||
getHtmlTemplate() {
|
getHtmlTemplate() {
|
||||||
return `
|
return `
|
||||||
<div id="${this.modalId}" title="서명 확인" style="display:none; padding:0;">
|
<div id="${this.modalId}" title="서명 확인" style="display:none; padding:0;">
|
||||||
@@ -423,8 +321,18 @@
|
|||||||
.signature-ui-dialog { border-radius: 12px; overflow: hidden; border: none; box-shadow: 0 5px 20px rgba(0,0,0,0.2); }
|
.signature-ui-dialog { border-radius: 12px; overflow: hidden; border: none; box-shadow: 0 5px 20px rgba(0,0,0,0.2); }
|
||||||
.sig-header { padding: 15px; background: #339af0; color: #fff; font-weight: bold; }
|
.sig-header { padding: 15px; background: #339af0; color: #fff; font-weight: bold; }
|
||||||
.sig-body { padding: 20px; text-align: center; }
|
.sig-body { padding: 20px; text-align: center; }
|
||||||
|
|
||||||
|
/* 문구와 버튼을 나란히 배치하기 위한 스타일 */
|
||||||
|
.sig-info-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.sig-info-text { color: #495057; margin: 0; font-size: 14px; }
|
||||||
|
|
||||||
.canvas-area { border: 1px solid #dee2e6; background: #f8f9fa; border-radius: 4px; margin-bottom: 10px; }
|
.canvas-area { border: 1px solid #dee2e6; background: #f8f9fa; border-radius: 4px; margin-bottom: 10px; }
|
||||||
.canvas-area canvas { width: 100%; height: 200px; cursor: crosshair; }
|
.canvas-area canvas { width: 100%; height: 200px; cursor: crosshair; display: block; }
|
||||||
.sig-footer { padding: 15px; background: #f8f9fa; text-align: right; border-top: 1px solid #eee; }
|
.sig-footer { padding: 15px; background: #f8f9fa; text-align: right; border-top: 1px solid #eee; }
|
||||||
.sig-btn { padding: 8px 16px; border-radius: 6px; border: none; cursor: pointer; font-weight: 600; margin-left: 5px; }
|
.sig-btn { padding: 8px 16px; border-radius: 6px; border: none; cursor: pointer; font-weight: 600; margin-left: 5px; }
|
||||||
.sig-btn-primary { background: #339af0; color: #fff; }
|
.sig-btn-primary { background: #339af0; color: #fff; }
|
||||||
@@ -432,11 +340,14 @@
|
|||||||
</style>
|
</style>
|
||||||
<div class="sig-header">본인 서명 확인</div>
|
<div class="sig-header">본인 서명 확인</div>
|
||||||
<div class="sig-body">
|
<div class="sig-body">
|
||||||
<p style="margin-bottom: 10px; color: #495057;">아래 영역에 서명해 주세요.</p>
|
<div class="sig-info-row">
|
||||||
|
<p class="sig-info-text">아래 영역에 서명해 주세요.</p>
|
||||||
|
<button type="button" class="sig-btn sig-btn-secondary btnReset" style="font-size: 12px; padding: 4px 10px; margin: 0;">지우기</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="canvas-area">
|
<div class="canvas-area">
|
||||||
<canvas></canvas>
|
<canvas></canvas>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="sig-btn sig-btn-secondary btnReset" style="font-size: 12px; padding: 4px 10px;">지우기</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="sig-footer">
|
<div class="sig-footer">
|
||||||
<button type="button" class="sig-btn sig-btn-secondary btnCancle">취소</button>
|
<button type="button" class="sig-btn sig-btn-secondary btnCancle">취소</button>
|
||||||
@@ -446,53 +357,35 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
|
|
||||||
// 클래스 인스턴스 생성 (기존 소스와 호환성을 위해 변수명 유지 가능)
|
|
||||||
const userIntroSelectModal = new UserIntroSelectModal();
|
|
||||||
|
|
||||||
const signatureDialog = new SignatureDialogManager();
|
const signatureDialog = new SignatureDialogManager();
|
||||||
$('.registration_bth').on('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
|
|
||||||
// 2. 서명 모달 오픈 (jQuery UI 기반으로 커스텀한 경우)
|
|
||||||
if (typeof signatureDialog !== 'undefined') {
|
|
||||||
signatureDialog.open((signatureData) => {
|
|
||||||
// 서명 완료 시 실행될 콜백: 여기서 실제 서버 전송(Ajax) 함수 호출
|
|
||||||
this.savePatientData(signatureData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const pageApp = new NewPatientPage();
|
const pageApp = new NewPatientPage();
|
||||||
window.newPatientPage = pageApp;
|
window.newPatientPage = pageApp;
|
||||||
pageApp.init();
|
pageApp.init();
|
||||||
|
|
||||||
|
$('.btnSave').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (validateForm()) {
|
||||||
|
//alert("검증 완료! 서명 단계로 이동합니다.");
|
||||||
|
if (typeof signatureDialog !== 'undefined') {
|
||||||
|
signatureDialog.open((signatureData) => {
|
||||||
|
// 실제 저장 로직 호출 예시: pageApp.savePatientData(signatureData);
|
||||||
|
console.log("서명 완료", signatureData);
|
||||||
|
pageApp.savePatientData(signatureData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('.consent-link').on('click', function(e) {
|
$('.consent-link').on('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
openConsentDialog($(this).data('type'));
|
openConsentDialog($(this).data('type'));
|
||||||
});
|
});
|
||||||
$('.searchIntroUser').on('click', function() {
|
|
||||||
// 모달 팝업 호출
|
|
||||||
userIntroSelectModal.popup(function(data) {
|
|
||||||
// [Callback] 고객을 선택했을 때 실행될 로직
|
|
||||||
console.log("선택된 추천인 정보:", data);
|
|
||||||
|
|
||||||
// 1. input 필드에 선택된 사용자의 이름 표시
|
|
||||||
$('input[name="modalRecommendId"]').val(data.userName);
|
|
||||||
|
|
||||||
// 2. (옵션) 실제 DB 저장을 위한 ID값 등을 hidden 필드에 저장할 경우
|
|
||||||
// if ($('#recommendUserNo').length > 0) {
|
|
||||||
// $('#recommendUserNo').val(data.muUserId);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}, { type: "recommend" }); // 필요 시 요청 파라미터 전달
|
|
||||||
});
|
|
||||||
function openConsentDialog(type) {
|
function openConsentDialog(type) {
|
||||||
if ($('#dynamicConsentDialog').length) $('#dynamicConsentDialog').dialog('destroy').remove();
|
if ($('#dynamicConsentDialog').length) $('#dynamicConsentDialog').dialog('destroy').remove();
|
||||||
|
|
||||||
const $dialog = $('<div id=\"dynamicConsentDialog\" style=\"overflow-y: auto; padding: 20px; line-height: 1.6;\"></div>');
|
const $dialog = $('<div id="dynamicConsentDialog" style="overflow-y: auto; padding: 20px; line-height: 1.6;"></div>');
|
||||||
let isAgreed = false;
|
let isAgreed = false;
|
||||||
|
|
||||||
$dialog.dialog({
|
$dialog.dialog({
|
||||||
@@ -522,25 +415,25 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$dialog.html('<div style=\"text-align:center; padding:50px;\">내용을 불러오는 중입니다...</div>');
|
$dialog.html('<div style="text-align:center; padding:50px;">내용을 불러오는 중입니다...</div>');
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/kiosk/getConsentForm.do',
|
url: '/kiosk/getConsentForm.do',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
consentFormTypeCd: getConsentFormTypeCd(type), // 코드로 변환하여 전송
|
consentFormTypeCd: getConsentFormTypeCd(type),
|
||||||
nationalCd: pageApp.data.nationalityCode // 현재 국적 코드 전송
|
nationalCd: pageApp.data.nationalityCode
|
||||||
}),
|
}),
|
||||||
success: function(res) {
|
success: function(res) {
|
||||||
if(res && res.consentFormContent) {
|
if(res && res.consentFormContent) {
|
||||||
$dialog.html(res.consentFormContent);
|
$dialog.html(res.consentFormContent);
|
||||||
} else {
|
} else {
|
||||||
$dialog.html('<div style=\"text-align:center; color:red;\">등록된 동의서 내용이 없습니다.</div>');
|
$dialog.html('<div style="text-align:center; color:red;">등록된 동의서 내용이 없습니다.</div>');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
$dialog.html('<div style=\"text-align:center; color:red;\">서버 통신 중 오류가 발생했습니다.</div>');
|
$dialog.html('<div style="text-align:center; color:red;">서버 통신 중 오류가 발생했습니다.</div>');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -555,9 +448,6 @@
|
|||||||
return titles[type] || '동의서';
|
return titles[type] || '동의서';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* type 명칭을 DB consentFormTypeCd 코드로 변환
|
|
||||||
*/
|
|
||||||
function getConsentFormTypeCd(type) {
|
function getConsentFormTypeCd(type) {
|
||||||
const typeMapping = {
|
const typeMapping = {
|
||||||
'agreePrivacy': 'C202601180001',
|
'agreePrivacy': 'C202601180001',
|
||||||
@@ -567,5 +457,63 @@
|
|||||||
};
|
};
|
||||||
return typeMapping[type] || '';
|
return typeMapping[type] || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateForm() {
|
||||||
|
let isValid = true;
|
||||||
|
$('.validation-msg').text('');
|
||||||
|
|
||||||
|
// --- 1. 기본 정보 검증 ---
|
||||||
|
let basicError = "";
|
||||||
|
if (!$('input[name="modalUserName"]').val().trim()) {
|
||||||
|
basicError = "이름 필수";
|
||||||
|
} else if (!$('#selectNationality').val()) {
|
||||||
|
basicError = "국적 선택";
|
||||||
|
} else if ($('input[name="modalUserRrn1"]').val().length < 6) {
|
||||||
|
basicError = "주민번호 확인";
|
||||||
|
} else if (!$('input[name="modalPhoneNumber"]').val().trim()) {
|
||||||
|
basicError = "연락처 필수";
|
||||||
|
} else if (!$('#address').val().trim()) {
|
||||||
|
basicError = "주소 검색 필요";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basicError) {
|
||||||
|
$('#msg-basic').text(" (⚠️ " + basicError + ")");
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 2. 개인정보 동의 검증 ---
|
||||||
|
let consentError = "";
|
||||||
|
if (!$('#agreePrivacy').is(':checked')) {
|
||||||
|
consentError = "이용안내 미동의";
|
||||||
|
} else if (!$('#agreeProcedure').is(':checked')) {
|
||||||
|
consentError = "시술동의 미확인";
|
||||||
|
} else if (!$('#agreeTerms').is(':checked')) {
|
||||||
|
consentError = "약관 미동의";
|
||||||
|
} else if (!$('#refusePhoto').is(':checked')) {
|
||||||
|
consentError = "사진촬영 미동의";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (consentError) {
|
||||||
|
$('#msg-consent').text(" (⚠️ " + consentError + ")");
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
const firstErrorField = $('.validation-msg:contains("⚠️")').first();
|
||||||
|
if (firstErrorField.length) {
|
||||||
|
$('html, body').animate({
|
||||||
|
scrollTop: firstErrorField.offset().top - 100
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('input, select, textarea').on('input change', function() {
|
||||||
|
$(this).closest('section').find('.validation-msg').text('');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
@@ -38,6 +38,9 @@
|
|||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="page-header">
|
<header class="page-header">
|
||||||
<h1 class="title">신규 고객 등록</h1>
|
<h1 class="title">신규 고객 등록</h1>
|
||||||
|
<button type="button" id="btnFillTestData" style="padding: 5px 15px; background: #ff4757; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; font-weight: bold;">
|
||||||
|
테스트 데이터 채우기
|
||||||
|
</button>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- Body -->
|
<!-- Body -->
|
||||||
@@ -46,7 +49,7 @@
|
|||||||
|
|
||||||
<!-- Column 1: Basic Info -->
|
<!-- Column 1: Basic Info -->
|
||||||
<section class="form-section-card col-card">
|
<section class="form-section-card col-card">
|
||||||
<div class="section-title">기본 정보</div>
|
<div class="section-title">기본 정보<span id="msg-basic" class="validation-msg"></span></div>
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label class="required">고객명</label>
|
<label class="required">고객명</label>
|
||||||
@@ -111,23 +114,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label class="required">주소</label>
|
<label for="address" class="required">주소</label>
|
||||||
<div class="address-input-group" style="display: flex; gap: 8px;">
|
<div class="address-input-group" style="display: flex; gap: 8px;">
|
||||||
<input id="modalAddress" name="modalAddress" type="text" placeholder="주소를 검색하세요" readonly style="flex: 1; cursor: pointer;" />
|
<input id="address" name="address" type="text" placeholder="주소를 검색하세요" readonly style="flex: 1; cursor: pointer;" />
|
||||||
<button type="button" id="btnSearchAddress" class="btn-small" style="padding: 0 15px; background: #333; color: #fff; border-radius: 4px;">검색</button>
|
<button type="button" id="btnSearchAddress" class="btn-small" style="padding: 0 15px; background: #333; color: #fff; border-radius: 4px;">검색</button>
|
||||||
</div>
|
</div>
|
||||||
<input id="modalAddressDetail" name="modalAddressDetail" type="text" placeholder="상세 주소를 입력하세요" style="margin-top: 8px;" />
|
<input id="addressDtl" name="addressDtl" type="text" placeholder="상세 주소를 입력하세요" style="margin-top: 8px;" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label class="required">이메일</label>
|
<label for="email">이메일</label>
|
||||||
<input name="email" type="text" placeholder="imadeu@naver.com" />
|
<input id="email" name="email" type="text" placeholder="imadeu@naver.com" />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Column 2: Contact Info -->
|
<!-- Column 2: Contact Info -->
|
||||||
<section class="form-section-card col-card">
|
<section class="form-section-card col-card">
|
||||||
<div class="section-title">개인정보 수집 및 이용동의</div>
|
<div class="section-title">개인정보 수집 및 이용동의<span id="msg-consent" class="validation-msg"></div>
|
||||||
|
|
||||||
<div class="form-row checkbox-row">
|
<div class="form-row checkbox-row">
|
||||||
<label for="agreePrivacy">개인정보 수집 및 이용안내</label>
|
<label for="agreePrivacy">개인정보 수집 및 이용안내</label>
|
||||||
@@ -179,7 +182,7 @@
|
|||||||
|
|
||||||
<!-- Column 3: Additional Info -->
|
<!-- Column 3: Additional Info -->
|
||||||
<section class="form-section-card col-card">
|
<section class="form-section-card col-card">
|
||||||
<div class="section-title">기타 정보</div>
|
<div class="section-title">기타 정보<span id="msg-etc" class="validation-msg"></div>
|
||||||
|
|
||||||
<!-- Channel -->
|
<!-- Channel -->
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
@@ -191,12 +194,9 @@
|
|||||||
|
|
||||||
<!-- Recommender -->
|
<!-- Recommender -->
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label>추천인</label>
|
<label for="introName">추천인</label>
|
||||||
<div class="searchIntroUser" style="position:relative; cursor:pointer;">
|
<div class="searchIntroUser" style="position:relative; cursor:pointer;">
|
||||||
<input type="text" name="modalRecommendId" placeholder="검색하여 선택하세요" readonly
|
<input type="text" id="introName" name="introName" placeholder="추천인 성함을 입력해주세요" style="cursor:pointer; padding-right:40px;" />
|
||||||
style="cursor:pointer; padding-right:40px;" />
|
|
||||||
<img src="/image/web/search_B.svg" alt="search"
|
|
||||||
style="position:absolute; right:12px; top:50%; transform:translateY(-50%); width:18px;">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
<footer class="page-footer">
|
<footer class="page-footer">
|
||||||
<!-- Use project standard classes -->
|
<!-- Use project standard classes -->
|
||||||
<button type="button" class="cancel_btn btnCancle">취소</button>
|
<button type="button" class="cancel_btn btnCancle">취소</button>
|
||||||
<button type="button" class="registration_bth btnSave">등록 완료</button>
|
<button type="button" class="registration_bth btnSave">서명</button>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user