2026-01-25 작업

This commit is contained in:
pjs
2026-01-25 21:54:15 +09:00
parent a7d2fa31e7
commit 50d2f05404
12 changed files with 399 additions and 446 deletions

View File

@@ -30,6 +30,10 @@ public class DatabaseConfig {
factoryBean.setDataSource(dataSource);
factoryBean.setMapperLocations(applicationContext.getResources("classpath:/mappers/**/*.xml"));
org.apache.ibatis.session.Configuration mybatisConfig = new org.apache.ibatis.session.Configuration();
mybatisConfig.setMapUnderscoreToCamelCase(true); // 언더바를 카멜케이스로 매핑
factoryBean.setConfiguration(mybatisConfig);
return factoryBean.getObject();
}

View File

@@ -37,6 +37,8 @@ public interface Constants {
static final public String END_DATE_NONE = "408"; // 서비스 종료일 정보가 없습니다.
static final public String USER_SAME = "409"; // 이미 등록되어 있는 사용자입니다.
static final public String EBS_ID_UNEQUAL = "410"; // 사용자 정보가 없습니다.
static final public String SERVER_ERROR = "서버 오류가 발생했습니다."; //서버 오류가 발생했습니다.
}

View File

@@ -1,6 +1,7 @@
package com.madeu.crm.kiosk.ctrl;
import java.util.HashMap;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -12,6 +13,7 @@ import org.springframework.web.servlet.ModelAndView;
import com.madeu.constants.Constants;
import com.madeu.crm.kiosk.dto.ConsentFormDTO;
import com.madeu.crm.kiosk.dto.KioskDTO;
import com.madeu.crm.kiosk.dto.UserDTO;
import com.madeu.crm.kiosk.service.KioskService;
import com.madeu.init.ManagerDraftAction;
@@ -224,7 +226,7 @@ public class KioskController extends ManagerDraftAction {
} catch (Exception e) {
log.error("Error inserting user", e);
resultMap.put("msgCode", Constants.FAIL);
resultMap.put("msgDesc", "서버 오류가 발생했습니다.");
resultMap.put("msgDesc", Constants.SERVER_ERROR);
errorMsg.append(e.getMessage());
} finally {
// 결과 처리 및 로그 기록 (기존과 동일)
@@ -234,6 +236,26 @@ public class KioskController extends ManagerDraftAction {
return resultMap;
}
/**
* 고객 등록
*/
@PostMapping("/kiosk/putSubmit.do")
public KioskDTO putSubmit(@RequestBody KioskDTO dto) {
return null;
}
/**
* 고객 등록
* @throws Exception
*/
@PostMapping("/kiosk/getUserByPhoneNumber.do")
public HashMap<String, Object> getUserByPhoneNumber(@RequestBody KioskDTO dto) throws Exception {
return kioskService.getUserByPhoneNumber(dto);
}
/**
* 고객 정보 조회
*/

View File

@@ -0,0 +1,19 @@
package com.madeu.crm.kiosk.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class KioskDTO {
private String userNumber; // 고객명
private String userName; // 고객명
private String birthday; // 생년월일 (YYYYMMDD)
private String gender; // 성별 (M/F)
private String phoneNumber;
private String lastVisitDate;
private String msgCode;
private String msgDesc;
}

View File

@@ -6,6 +6,7 @@ import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
import com.madeu.crm.kiosk.dto.ConsentFormDTO;
import com.madeu.crm.kiosk.dto.KioskDTO;
import com.madeu.crm.kiosk.dto.UserDTO;
@Mapper
@@ -47,4 +48,6 @@ public interface KioskMAP {
List<Map<String, Object>> getReserveUserOptionList(Map<String, Object> paramMap);
int insertUser(UserDTO dto);
List<KioskDTO> selectUserByPhoneNumber(KioskDTO dto);
}

View File

@@ -12,6 +12,7 @@ import org.springframework.stereotype.Service;
import com.madeu.constants.Constants;
import com.madeu.crm.kiosk.dto.ConsentFormDTO;
import com.madeu.crm.kiosk.dto.KioskDTO;
import com.madeu.crm.kiosk.dto.UserDTO;
import com.madeu.crm.kiosk.map.KioskMAP;
import com.madeu.dao.web.webuser.WebUserSqlMapDAO;
@@ -312,4 +313,28 @@ public class KioskService {
public ConsentFormDTO getConsentForm(ConsentFormDTO dto) {
return kioskMAP.selectConsentForm(dto);
}
public HashMap<String, Object> getUserByPhoneNumber(KioskDTO dto) throws Exception {
HashMap<String, Object> map = new HashMap<>();
List<KioskDTO> list = null;
try {
list = kioskMAP.selectUserByPhoneNumber(dto);
map.put("list", list);
map.put("msgCode", Constants.OK);
//dto.setMsgDesc(Constants.SERVER_ERROR);
} catch (Exception e) {
map.put("msgCode", Constants.FAIL);
map.put("msgDesc", Constants.SERVER_ERROR);
e.printStackTrace();
}
return map;
}
}

View File

@@ -16,11 +16,6 @@ spring:
aop:
proxy-target-class: false
mybatis:
mapper-locations: mybatis/mappers/*.xml
configuration:
map-underscore-to-camel-case: true
server:
encoding:
charset: UTF-8

View File

@@ -438,6 +438,7 @@
END AS "appUseYn"
,DATE_FORMAT(MU.APP_INTRO_DATE, '%Y-%m-%d') AS "appIntroDate"
,DATE_FORMAT(MU.LEAVE_DATE, '%Y-%m-%d') AS "leaveDate"
,INTRO_NAME as "introName"
FROM MU_USER AS MU
LEFT JOIN MU_CATEGORY_ITEM AS MCIN
ON MCIN.MU_CATEGORY_ITEM_ID = MU.NATIONALITY

View File

@@ -364,6 +364,27 @@
AND MU.MU_USER_ID = #{muUserId}
</select>
<select id="selectUserByPhoneNumber" parameterType="com.madeu.crm.kiosk.dto.KioskDTO" resultType="com.madeu.crm.kiosk.dto.KioskDTO">
SELECT
MU_USER_ID,
USER_NUMBER,
USER_NAME,
BIRTHDAY,
GENDER,
PHONE_NUMBER,
USER_TYPE,
LAST_VISIT_DATE,
ETC,
MEMO
FROM MU_USER
WHERE USE_YN = 'Y'
AND PHONE_NUMBER = #{phoneNumber}
ORDER BY USER_NUMBER DESC
</select>
<select id="getHospital" parameterType="hashmap" resultType="hashmap">
/** KioskSql.getHospital **/
SELECT MH.MU_HOSPITAL_ID AS "muHospitalId"

View File

@@ -92,17 +92,17 @@ function fn_selectUser() {
$("#channel").parent().find('button').text(data.userDetail[0].channelName);
$("#channelCd").val(channel);
}
// $("#email").val(data.userDetail[0].email);
$("#email").val(data.userDetail[0].email);
$("#userNumber").text(data.userDetail[0].userNumber);
$("#birthday").val(data.userDetail[0].birthday);
$("#nationality").val(nationality);
$("#userName").val(data.userDetail[0].userName);
// $("#address").val(
// (data.userDetail && data.userDetail[0]
// ? (data.userDetail[0].zipCode ? '(' + data.userDetail[0].zipCode + ') ' : '') + (data.userDetail[0].address || '')
// : '')
// );
// $("#addressDetails").val(data.userDetail[0].addressDetails);
$("#address").val(
(data.userDetail && data.userDetail[0]
? (data.userDetail[0].zipCode ? '(' + data.userDetail[0].zipCode + ') ' : '') + (data.userDetail[0].address || '')
: '')
);
$("#addressDetails").val(data.userDetail[0].addressDetails);
$("#identity").text(data.userDetail[0].identity);
$("#phoneNumber").val(fn_setFormatPhone(data.userDetail[0].phoneNumber??''));
$("#phoneNumber2").val(fn_setFormatPhone(data.userDetail[0].phoneNumber2??''));
@@ -160,7 +160,9 @@ function fn_selectUser() {
document.getElementById("fatPercent").innerText = (userPhysical.fatPercent || '-') + '%';
document.getElementById("bmi").innerText = (userPhysical.bmi || '-') + ' kg/m2';
}
console.log(data);
$("#introName").val(data.userDetail[0].introName);
$("#introName").val(data.userDetail[0].introName);
} else {
modalEvent.danger("조회 오류", data.msgDesc);
}
@@ -236,8 +238,8 @@ function fn_updateUser() {
let etc = $("#etc").val();
let birthday = $("#birthday").val();
//우편번호
// let address = $("#address").val();
// let addressDetails = $("#addressDetails").val().trim();
let address = $("#address").val();
let addressDetails = $("#addressDetails").val().trim();
// let zipCode = '';
// let streetAddress= '';
// let regex = /\((\d+)\)(.+)/;
@@ -251,7 +253,7 @@ function fn_updateUser() {
// let regPassport = /^[A-PR-WYa-pr-wy][1-9]\d\s?\d{4}[1-9]$/; // 대략적인 여권번호 형식
let regForeigner = /^[0-9]{6}-[5-8][0-9]{6}$/; // 외국인 등록번호 형식
let regPhone = /^[0-9]{8,11}$/; // 전화번호 형식
// let regEmail = /^([0-9a-zA-Z_\.-]+)@([0-9a-zA-Z_-]+)(\.[0-9a-zA-Z_-]+){1,2}$/; // 이메일 형식
let regEmail = /^([0-9a-zA-Z_\.-]+)@([0-9a-zA-Z_-]+)(\.[0-9a-zA-Z_-]+){1,2}$/; // 이메일 형식
let identification = $("#identification .selected").attr("id");
let introUserId = document.getElementById('recommendUserId').dataset.userId??'';

View File

@@ -1,446 +1,301 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<html lang="ko">
<head>
<th:block th:replace="/web/include/head :: layout_head"></th:block>
<th:block layout:fragment="layout_css">
<link rel="stylesheet" href="/css/kiosk/existing-patient.css">
</th:block>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>기존 고객 조회 - 메이드유 CRM</title>
<link rel="stylesheet" href="/css/web/font.css">
<link rel="stylesheet" href="/css/kiosk/new-patient.css">
<script src="/js/web/jquery.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<script src="/js/web/jquery-ui.js"></script>
<style>
/* 페이지 기본 레이아웃 */
.page-body.search-mode {
display: flex;
justify-content: center;
align-items: center;
padding-top: 60px;
}
.search-card {
width: 100%;
max-width: 480px;
}
.phone-group {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
}
.phone-group input {
flex: 1;
text-align: center;
height: 44px;
border: 1px solid var(--border-color);
border-radius: 4px;
font-size: 16px;
}
/* [변경] 스크롤 기능을 위한 테이블 컨테이너 */
.user-list-container {
max-height: 450px; /* 약 10row 기준 높이 (1row 당 약 45px) */
overflow-y: auto;
border: 1px solid var(--border-color);
border-radius: 4px;
margin-top: 10px;
}
.user-list-table {
width: 100%;
border-collapse: collapse;
}
/* [변경] 헤더 고정 스타일 */
.user-list-table thead th {
position: sticky;
top: 0;
background-color: #f8f9fa;
padding: 12px 8px;
border-bottom: 2px solid var(--border-color);
font-size: 13px;
color: var(--text-sub);
text-align: center;
z-index: 10;
}
.user-list-table td {
padding: 12px 8px;
border-bottom: 1px solid #eee;
font-size: 14px;
text-align: center;
color: var(--text-main);
cursor: pointer;
}
.user-list-table tr:hover td {
background-color: #f1f8ff;
}
/* 라디오 버튼 스타일 */
.user-radio {
width: 18px;
height: 18px;
accent-color: var(--primary-color);
cursor: pointer;
}
/* jQuery UI 버튼 스타일 */
.btn-registration {
background-color: var(--primary-color) !important;
color: #ffffff !important;
border: 1px solid var(--primary-color) !important;
font-weight: 600 !important;
}
.btn-registration:hover {
background-color: var(--primary-hover) !important;
}
.ui-dialog {
border-radius: 12px !important;
padding: 0 !important;
overflow: hidden;
border: none !important;
box-shadow: 0 10px 30px rgba(0,0,0,0.1) !important;
}
.ui-dialog-titlebar {
background: #fff !important;
border: none !important;
border-bottom: 1px solid var(--border-color) !important;
padding: 15px 20px !important;
}
/* 커스텀 스크롤바 디자인 */
.user-list-container::-webkit-scrollbar {
width: 6px;
}
.user-list-container::-webkit-scrollbar-thumb {
background-color: #ccd3d9;
border-radius: 10px;
}
.user-list-container::-webkit-scrollbar-track {
background-color: #f1f3f5;
}
</style>
</head>
<th:block layout:fragment="layout_top_script">
<script src="/js/kiosk/common.js"></script>
<script src="/js/web/signature_pad.js"></script>
</th:block>
<th:block layout:fragment="layout_content">
<div id="reserveReadyInsertModal" class="kiosk-container"> <!-- ID kept for JS compatibility -->
<!-- Header -->
<body>
<div class="new-patient-container">
<header class="page-header">
<h1 class="title">기존 고객 바로접수</h1>
<h1 class="title">기존 고객 조회</h1>
</header>
<!-- Body -->
<main class="page-body">
<div id="list1" class="form-grid-layout"> <!-- ID kept for JS compatibility -->
<!-- Column 1: Customer Search & Info -->
<section class="form-section-card">
<div class="section-title">고객 조회</div>
<div class="form-row">
<label>고객 검색</label>
<div class="search_box" data-toggle="modal" data-target=".client_inquiry"
style="position:relative; cursor:pointer;">
<input type="hidden" name="modalUserId" />
<input type="text" name="modalUserName" placeholder="터치하여 고객 검색 (이름/연락처)" readonly
style="padding-right: 40px; cursor:pointer;" />
<img src="/image/web/search_B.svg" alt="search"
style="position:absolute; right:12px; top:50%; transform:translateY(-50%); width:18px;">
</div>
<main class="page-body search-mode">
<section class="form-section-card search-card">
<div class="section-title">
연락처 조회
<span id="phone-error" class="validation-msg" style="visibility: hidden;">번호를 정확히 입력해주세요.</span>
</div>
<div class="form-row">
<label>고객 정보</label>
<table class="info-table">
<tr>
<th>고객등급</th>
<td class="modalUserType">-</td>
</tr>
<tr>
<th>생년월일</th>
<td class="modalBirthday">-</td>
</tr>
<tr>
<th>성별</th>
<td class="modalGender">-</td>
</tr>
<tr>
<th>국적</th>
<td class="modalNationality">-</td>
</tr>
<tr>
<th>연락처</th>
<td class="modalPhoneNumber">-</td>
</tr>
<tr>
<th>특이사항</th>
<td class="modalMemo">-</td>
</tr>
</table>
<label class="required">연락처</label>
<div class="phone-group">
<input type="tel" id="phone1" maxlength="3" placeholder="010" inputmode="numeric" value="010">
<span>-</span>
<input type="tel" id="phone2" maxlength="4" placeholder="0000" inputmode="numeric" value="3873">
<span>-</span>
<input type="tel" id="phone3" maxlength="4" placeholder="0000" inputmode="numeric" value="8265">
</div>
</div>
<div style="margin-top: 20px;">
<button type="button" class="registration_bth" style="width: 100%;" onclick="validateAndSearch()">조회하기</button>
</div>
</section>
<!-- Column 2: Reservation Details -->
<section class="form-section-card reserveRowBox">
<div class="section-title">예약 정보</div>
<!-- Dynamic reservation row will be injected here or statically defined if logic permits.
The original JS appends ".modal_table_content". We will adapt.
For now, we define the structure directly for the FIRST row to avoid JS injection issues on load if possible.
However, legacy JS appends it. Let's keep the container relative.
-->
<!-- We'll let JS append the complicated row, but stylize the container -->
</section>
<!-- Column 3: Staff & Memo -->
<section class="form-section-card">
<div class="section-title">담당자 및 메모</div>
<div class="form-row">
<label>담당자 (직원)</label>
<input type="hidden" name="modalMemberId" />
<!-- Read Mode -->
<div class="read_box" style="display:flex; gap:10px;">
<input type="text" name="modalMemberName" placeholder="담당자 없음" disabled>
<button class="manager_btn" style="width:50px; padding:0; background:#f0f2f5;"><img
src="/image/web/menu_6_off.svg" alt="수정" style="width:20px;"></button>
</div>
<!-- Edit Mode -->
<div class="search_box member_box" style="display:none; position:relative; margin-top:5px;">
<input type="text" name="modalMemberName" readonly placeholder="담당자 검색"
style="padding-right: 80px;" />
<img src="/image/web/search_B.svg"
style="position:absolute; right:60px; top:50%; transform:translateY(-50%); width:18px;">
<button class="cancel_btn"
style="position:absolute; right:0; top:0; height:100%; border-radius:0 4px 4px 0;">취소</button>
</div>
</div>
<div class="form-row" style="margin-top:20px;">
<label>접수 메모</label>
<textarea placeholder="접수 시 참고할 메모를 입력하세요 (선택)" style="height:150px;"></textarea>
</div>
</section>
</div>
</main>
<!-- Footer -->
<footer class="page-footer">
<button type="button" class="cancel_btn btnCancle">취소</button>
<div id="list1"> <!-- Scope required for JS selector -->
<button type="button" class="registration_bth btnSave">접수 완료</button>
</div>
<button type="button" class="cancel_btn" onclick="moveKiosk()">뒤로가기</button>
</footer>
</div>
</div>
</th:block>
<div id="customerDialog" title="고객 선택" style="display:none;">
<p style="margin: 15px 0 10px; font-size: 14px; color: #666;">접수하실 고객님을 선택해 주세요.</p>
<th:block layout:fragment="layout_popup">
<!-- Member Search Modal (Hidden by default) -->
<div id="memberSearchModal" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true" style="display:none;">
<div class="modal-dialog" style="max-width:600px; margin: 100px auto;">
<div class="modal-content">
<div class="modal-header" style="background:#f8f9fa; border-bottom:1px solid #ddd; padding:15px;">
<h5 class="modal-title" style="margin:0; font-weight:700;">직원 검색</h5>
</div>
<div class="modal-body" style="padding:20px;">
<div style="display:flex; gap:10px; margin-bottom:15px;">
<input id="memberSearchKeyword" type="text" class="form-control" placeholder="이름 또는 연락처"
style="height:40px; flex:1;">
<button id="searchMemberBtn" class="btn btn-primary"
style="height:40px; width:80px; background:#1B66C9; color:#fff; border:none; border-radius:4px;">검색</button>
</div>
<div class="list1_modal_table" style="max-height:300px; overflow-y:auto;">
<table class="table table-hover" style="width:100%; font-size:14px;">
<thead style="background:#f1f3f5;">
<div class="user-list-container">
<table class="user-list-table">
<thead>
<tr>
<th style="padding:10px;">이름</th>
<th style="padding:10px;">연락처</th>
<th style="padding:10px;">부서</th>
<th>선택</th>
<th>성함</th>
<th>생년월일</th>
<th>성별</th>
<th>최근 방문일</th>
</tr>
</thead>
<tbody>
<!-- Dynamic Content -->
<tbody id="userListBody">
</tbody>
</table>
</div>
</div>
<div class="modal-footer" style="padding:15px; border-top:1px solid #ddd;">
<button type="button" class="btn btn-secondary btnCancle" data-dismiss="modal">닫기</button>
</div>
</div>
</div>
</div>
</th:block>
<th:block layout:fragment="layout_script">
<script type="text/javascript">
<script>
const inputs = [
document.getElementById('phone1'),
document.getElementById('phone2'),
document.getElementById('phone3')
];
$(document).ready(function() {
// Page Init
reserveReadyInsertModal.init();
});
let reserveReadyInsertModal = {
callback: null,
reqParam: null,
init: function () {
// Remove legacy modal template injection
// $('#reserveReadyInsertModal').remove();
// $('body').append( this.HtmlTemplate);
// Initialize Events
this.setEvent();
// Add default row
this.addRow();
// jQuery UI Dialog 설정
$("#customerDialog").dialog({
autoOpen: false,
modal: true,
width: 600, // 스크롤바 공간을 고려하여 너비 소폭 확장
resizable: false,
show: { effect: "fade", duration: 200 },
hide: { effect: "fade", duration: 200 },
buttons: [
{
text: "접수하기",
class: "btn-registration",
click: function() {
submitBtn();
}
},
setEvent: function () {
$('.btnCancle').on("click", function () {
history.back();
{
text: "닫기",
click: function() {
$(this).dialog("close");
}
}
]
});
$('#list1 .btnSave').on("click", function () {
reserveReadyInsertModal.save("I");
// 행 클릭 시 라디오 버튼 선택
$(document).on('click', '.user-list-table tbody tr', function() {
$(this).find('input[type="radio"]').prop('checked', true);
});
});
// User Search
$('#list1 input[name="modalUserName"]').on("click", function () {
userIntroSelectModal.popup(function (obj) {
// Populate User Info
$('#list1 input[name="modalUserId"]').val(obj.muuserid);
$('#list1 input[name="modalUserName"]').val(obj.username);
$('#list1 .modalPhoneNumber').text(fn_setFormatPhone(obj.phonenumber));
if ("T" == obj.userType2) {
$('.modalUserType').text('간편예약');
$('.modalBirthday').text(obj.birthday || '-');
} else {
$('.modalUserType').html(obj.usertype ? `<img src="\${obj.usertype.replace('C:', '')}" height="20"/>` : '일반');
$('.modalBirthday').text(obj.birthday);
$('.modalGender').text(obj.gender);
$('.modalNationality').text(obj.nationality || 'KR');
$('.modalMemo').text(obj.memo);
inputs.forEach((input, index) => {
input.addEventListener('input', (e) => {
e.target.value = e.target.value.replace(/[^0-9]/g, '');
if (e.target.value.length === e.target.maxLength && index < 2) {
inputs[index + 1].focus();
}
});
});
// Manager Edit Toggle
$('#list1 .manager_btn').on("click", function () {
$('#list1 .read_box').hide();
$('#list1 .member_box').show();
});
$('#list1 .cancel_btn').on("click", function () {
$('#list1 .read_box').show();
$('#list1 .member_box').hide();
});
function validateAndSearch() {
const values = inputs.map(input => input.value);
const phoneNumber = values.join('');
// Manager Search
$('input[name="modalMemberName"]').on("click", function () {
memberSearchModal.popup(function (obj) {
$('input[name="modalMemberName"]').val(obj.selectMemberName);
$('input[name="modalMemberId"]').val(obj.selectMemberId);
// Return to read mode
$('#list1 .read_box').show();
$('#list1 .member_box').hide();
});
});
},
/* Dynamic Row Addition (Re-styled) */
addRow: function () {
let h = `
<div class="form-row modal_table_content" style="border:1px solid #eee; padding:15px; border-radius:8px; margin-bottom:10px;">
<!-- Date -->
<div style="margin-bottom:10px;">
<label>예약일시</label>
<div style="display:flex; gap:10px;">
<div style="flex:1; position:relative;">
<input type="text" class="date_picker" name="modalReserveDate" placeholder="YYYY-MM-DD">
</div>
<div class="select_box dropdown" style="flex:1;">
<button class="label" data-toggle="dropdown">00:00</button>
<input type="hidden" name="modalReserveTime">
<ul class="select_option_list dropdown-menu time"></ul>
</div>
</div>
</div>
<!-- Category -->
<div style="margin-bottom:10px;">
<label>예약경로</label>
<div class="select_box dropdown">
<button class="label" data-toggle="dropdown">선택하세요</button>
<input type="hidden" name="modalReserveCategoryItemCode">
<ul class="select_option_list dropdown-menu category-list"></ul>
</div>
</div>
<!-- Procedure -->
<div style="margin-bottom:10px;">
<label>진료유형</label>
<div class="search_box">
<input type="hidden" name="modalTreatmentProcedureId" />
<input type="text" name="modalTreatmentProcedureName" readonly placeholder="진료/시술 검색" />
</div>
</div>
<!-- Doctor -->
<div>
<label>닥터/상담</label>
<div class="select_box dropdown">
<button class="label" data-toggle="dropdown">선택하세요</button>
<input type="hidden" name="modalReserveMemberId">
<ul class="select_option_list dropdown-menu doctor-list"></ul>
</div>
</div>
</div>
`;
$('.reserveRowBox').append(h);
this.setReserveCategoryCombo();
let lastRow = $('.reserveRowBox .modal_table_content').last();
// Init Datepicker
lastRow.find('.date_picker').datetimepicker({
format: 'YYYY-MM-DD',
defaultDate: moment()
}).on("dp.change", function (e) {
fn_searchSetTime(lastRow.find('.time'), e.date.format("YYYY-MM-DD"));
});
// Init Time
fn_searchSetTime(lastRow.find('.time'), moment().format("YYYY-MM-DD"));
// Procedure Search
lastRow.find('input[name="modalTreatmentProcedureName"]').on("click", function () {
treatmentProcedureSearchModal.popup(function (obj) {
lastRow.find('input[name="modalTreatmentProcedureId"]').val(obj.mutreatmentprocedureid);
lastRow.find('input[name="modalTreatmentProcedureName"]').val(obj.treatmentprocedurename);
// Set Doctor Combo
let comboData = fn_selectListReserveMemberOption(lastRow.find('.date_picker').val(), obj.mutreatmentprocedureid);
let html = '';
comboData.forEach(d => {
html += `<li class="option_list_item" id="doc_\${d.mumemberid}">\${d.typename} \${d.membername}</li>`;
});
lastRow.find('.doctor-list').html(html);
});
});
// Dropdown Click
lastRow.on('click', '.option_list_item', function () {
let txt = $(this).text();
let id = $(this).attr('id');
// Handle id prefix if any (e.g., doc_123)
if (id && id.indexOf('_') > -1) id = id.split('_')[1];
$(this).closest('.dropdown').find('.label').text(txt);
$(this).closest('.dropdown').find('input[type="hidden"]').val(id);
});
},
setReserveCategoryCombo: function () {
let category = fn_selectCategoryList();
let reservationCategory = category.find(cat => cat.categoryname === '예약경로');
if (reservationCategory) {
fn_selectModalOtherOption(reservationCategory.categorycode, '');
// The common function targets generic selectors. We might need to manually populate if it fails.
// Assuming fn_selectModalOtherOption works by finding selectors globally or passed context.
// For safety, let's manually populate the last row's category list if possible,
// or rely on common.js if it finds '.category-list'.
// Common.js usually finds by class. Let's assume it works or we use a custom fetch here if needed.
if (values[1].length < 3 || values[2].length < 4) {
$("#phone-error").css("visibility", "visible");
return;
}
},
save: function (state) {
// Validation & Save Logic (Copied from original but simplified selectors)
let muUserId = $('#list1 input[name="modalUserId"]').val();
let userName = $('#list1 input[name="modalUserName"]').val();
// Get reservation details from the generated row
let row = $('.reserveRowBox .modal_table_content').last();
let reserveDate = row.find('input[name="modalReserveDate"]').val();
let reserveTime = row.find('input[name="modalReserveTime"]').val();
let catCode = row.find('input[name="modalReserveCategoryItemCode"]').val();
let procId = row.find('input[name="modalTreatmentProcedureId"]').val();
let docId = row.find('input[name="modalReserveMemberId"]').val();
let memId = $('input[name="modalMemberId"]').val(); // Staff
if (!muUserId) { modalEvent.warning("접수", "고객을 선택해주세요."); return; }
if (!reserveDate || !reserveTime) { modalEvent.warning("접수", "예약 일시를 선택해주세요."); return; }
if (!procId) { modalEvent.warning("접수", "진료 유형을 선택해주세요."); return; }
modalEvent.info("접수", "접수를 진행하시겠습니까?", function () {
let formData = new FormData();
formData.append("muUserId", muUserId);
formData.append("userName", userName);
formData.append("reserveDate", reserveDate);
formData.append("reserveTime", reserveTime);
formData.append("reserveCategoryItemCode", catCode);
formData.append("muTreatmentProcedureId", procId);
formData.append("reserveMemberId", docId);
formData.append("muMemberId", memId);
$.ajax({
url: '/webreserve/insertReserveReady.do',
url: '/kiosk/getUserByPhoneNumber.do',
type: 'POST',
data: formData,
processData: false, contentType: false,
success: function (data) {
if (data.msgCode == '0') {
modalEvent.success("성공", "접수가 완료되었습니다.", function () {
history.back();
});
} else {
modalEvent.danger("실패", data.msgDesc);
}
}
});
});
}
};
contentType: 'application/json',
data: JSON.stringify({ phoneNumber: phoneNumber }),
success: function(res) {
let html = "";
if( res.msgCode == 0 ){
const userList = res.list;
let memberSearchModal = {
callback: null,
popup: function (cb) {
this.callback = cb;
$('#memberSearchModal').modal('show');
},
setSelect: function (id, name, phone) {
if (this.callback) this.callback({ selectMemberId: id, selectMemberName: name });
$('#memberSearchModal').modal('hide');
if (!userList || userList.length === 0) {
alert("조회된 정보가 없습니다.");
return;
}
};
// Search Button Event
$('#searchMemberBtn').on('click', function () {
let kw = $('#memberSearchKeyword').val();
let fd = new FormData();
fd.append("memberSearchKeywordParam", kw);
$.ajax({
url: '/kiosk/getMemberList.do',
type: 'POST',
data: fd, processData: false, contentType: false,
success: function (data) {
if (data.msgCode == '0') {
let tbody = $('#memberSearchModal tbody');
tbody.empty();
data.rows.forEach(m => {
let tr = $(`
<tr style="cursor:pointer;">
<td>\${m.membername}</td>
<td>\${fn_setFormatPhone(m.phonenumber)}</td>
<td>\${m.dutyname}</td>
userList.forEach((user, index) => {
html += `
<tr>
<td><input type="radio" name="selectedUser" class="user-radio" value="${user.userNumber}" ${index === 0 ? 'checked' : ''}></td>
<td class="user-name-cell">${user.userName}</td>
<td>${user.birthday || '-'}</td>
<td>${user.gender === 'M' ? '남' : (user.gender === 'F' ? '여' : '-')}</td>
<td>${user.lastVisitDate || '-'}</td>
</tr>
`);
tr.click(() => memberSearchModal.setSelect(m.mumemberid, m.membername, m.phonenumber));
tbody.append(tr);
`;
});
} else {
alert(res.msgDesc);
return;
}
}
});
});
$("#userListBody").html(html);
$("#customerDialog").dialog("open");
},
error: function() {
alert("통신 오류가 발생했습니다.");
}
});
}
function submitBtn() {
const selectedUser = $("input[name='selectedUser']:checked");
if (selectedUser.length === 0) {
alert("접수할 고객을 선택해 주세요.");
return;
}
const userName = selectedUser.val();
alert(userName + "님 접수가 완료되었습니다.");
$("#customerDialog").dialog("close");
}
function moveKiosk() {
window.location.href = "/kiosk";
}
</script>
</th:block>
</body>
</html>

View File

@@ -119,7 +119,7 @@
<label class="sub_label">보조 연락처</label>
<input id="phoneNumber2" name="phoneNumber" type="tel" placeholder="">
</div>
<!--<div class="input_box">
<div class="input_box">
<label>이메일</label>
<input id="email" type="text">
</div>
@@ -128,7 +128,7 @@
<input class="address" id="address" type="text" readonly="readonly">
<button class="address_btn" id="searchAddr" type="button">주소 찾기</button>
<input class="address_detail" id="addressDetails" type="text">
</div>-->
</div>
<div class="input_box">
<label>사진 거부</label>
<div class="gender">
@@ -177,6 +177,10 @@
<ul class="select_option_list dropdown-menu" id="treatment">
</ul>
</div>
<div class="last">
<label for="introName">고객 추천인</label>
<input type="text" id="introName" name="introName" readonly />
</div>
</div>
<div class="input_box two">
<div>