그리드 내부 드롭다운 메뉴 위치를 마우스 클릭 위치 기반으로 변경

dev
박성영 4 months ago
parent 106095430f
commit a10689d792

@ -44,6 +44,11 @@ public class Ma30Controller {
return "ma30/list"+ TilesConstants.BASE;
}
@GetMapping("/four_list.do")
public String fourListPage(Model model) {
return "ma30/four_list"+ TilesConstants.BASE;
}
@PostMapping("/list.ajax")
public ResponseEntity<?> listAjax(@ModelAttribute Ma30FindRlistSearchVO paramVO) {

@ -0,0 +1,592 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="dateUtil" uri="http://egovframework.go.kr/functions/date-util" %>
<!-- Main body -->
<div class="main_body">
<section id="section8" class="main_bars">
<div class="bgs-main">
<section id="section5">
<div class="sub_title"></div>
</section>
</div>
</section>
<div class="contants_body">
<div class="gs_b_top" style="border-bottom: 0;">
<ul class="lef">
<li class="th">
<label>
<input id="schDateChk" name="schDateChk" type="checkbox" style="width: 18px; height: 18px; padding-bottom: 15px;" value="1">
일자검색 :
</label>
</li>
<li>
<select id="schDayGubun" name="schDayGubun" title="일자구분" class="input" disabled="disabled">
<option value="JOSA_ENDDT">적발일자</option>
<option value="FST_WARNNING_ENDDT">사전통지</option>
<option value="SND_WARNNING_ENDDT">시정명령</option>
<option value="GOBAL_ENDDT">시정촉구</option>
<option value="PRE_BUGWA_ENDDT">부과예고</option>
<option value="BUGWA_ENDDT">부과</option>
<option value="NAPBU_CHOKGU_ENDDT">납부촉구</option>
<option value="A.RECOVER_DT">시정완료</option>
<option value="YUYEENDDATE">유예기간</option>
<option value="A.MNG_YY">연도</option>
</select>
<input type="text" id="schBeginDt" name="schBeginDt" class="input calender datepicker" value="${dateUtil:getCurrentDateAddDays('yyyy-MM-dd',-30)}" disabled="disabled"/> ~
<input type="text" id="schEndDt" name="schEndDt" class="input calender datepicker" value="${dateUtil:getCurrentDateTime('yyyy-MM-dd')}" disabled="disabled" />
</li>
<li class="th">법정동 :</li>
<li><input type="text" id="schBdongName" name="schBdongName" maxlength="10" class="input"/></li>
<li class="th">지번 :</li>
<li>
<input type="text" id="schBuldMnnm" name="schBuldMnnm" maxlength="10" class="input"/>
-
<input type="text" id="schBuldSlno" name="schBuldSlno" class="input">
</li>
<li class="th">소유주 :</li>
<li><input type="text" id="schOResName" name="schOResName" maxlength="10" class="input"/></li>
<li class="th">행위자 :</li>
<li><input type="text" id="schHResName" name="schHResName" class="input"/></li>
<li class="th">관리번호 :</li>
<li><input type="text" id="schRegstrMngNo" name="schRegstrMngNo" class="input"/></li>
</ul>
<ul class="rig2">
<li><button type="button" id="search_btn" class="newbtnss bg1">검색</button></li>
</ul>
</div>
<div class="gs_b_top">
<ul class="lef">
<li class="th">
<label>
<input id="schOnlyMyDataChk" name="schOnlyMyDataChk" type="checkbox" style="width: 18px; height: 18px; padding-bottom: 15px;" value="1">
내가 등록한 자료만 조회
</label>
</li>
<li class="th">
<label style="padding-left: 15px;"><input type="radio" id="schAllDataChk" name="schDataChk" value="A"/> 전체</label>
<label style="padding-left: 15px;"><input type="radio" id="schNewDataChk" name="schDataChk" value="B"/> 신규</label>
<label style="padding-left: 15px;"><input type="radio" id="schJaeBugwaDataChk" name="schDataChk" value="C"/> 재부과</label>
</li>
</ul>
</div>
<!-- 4개 그리드 분할 레이아웃 -->
<div class="gs_booking">
<!-- 상단 2개 그리드 -->
<div class="row" style="margin-bottom: 10px;">
<div class="col-sm-6">
<div class="box_column">
<ul class="box_title" style="display: flex; justify-content: space-between; align-items: center;">
<li class="tit">단속자료 목록 1</li>
<li style="text-align: right;">
<select id="perPageSelect" class="input" style="width: 110px;">
<option value="15">페이지당 15</option>
<option value="50">페이지당 50</option>
<option value="100">페이지당 100</option>
</select>
<span class="page_number"><span id="currentPage1"></span><span class="bar">/</span><span id="totalPages1"></span> Pages</span>
</li>
</ul>
<div class="containers">
<div id="grid1"></div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="box_column">
<ul class="box_title" style="display: flex; justify-content: space-between; align-items: center;">
<li class="tit">단속자료 목록 2</li>
<li style="text-align: right;">
<span class="page_number"><span id="currentPage2"></span><span class="bar">/</span><span id="totalPages2"></span> Pages</span>
</li>
</ul>
<div class="containers">
<div id="grid2"></div>
</div>
</div>
</div>
</div>
<!-- 하단 2개 그리드 -->
<div class="row">
<div class="col-sm-6">
<div class="box_column">
<ul class="box_title" style="display: flex; justify-content: space-between; align-items: center;">
<li class="tit">단속자료 목록 3</li>
<li style="text-align: right;">
<span class="page_number"><span id="currentPage3"></span><span class="bar">/</span><span id="totalPages3"></span> Pages</span>
</li>
</ul>
<div class="containers">
<div id="grid3"></div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="box_column">
<ul class="box_title" style="display: flex; justify-content: space-between; align-items: center;">
<li class="tit">단속자료 목록 4</li>
<li style="text-align: right;">
<span class="page_number"><span id="currentPage4"></span><span class="bar">/</span><span id="totalPages4"></span> Pages</span>
</li>
</ul>
<div class="containers">
<div id="grid4"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /Main body -->
<script type="text/javascript">
/**
* 4개 분할 그리드 테스트 모듈
* 동일한 데이터를 4개의 그리드에 분할하여 표시하는 테스트 기능을 제공합니다.
*/
(function(window, $) {
'use strict';
var SEARCH_COND = {};
// 검색정보 셋팅
var setSearchCond = function() {
var schDateChk = !!$("#schDateChk").is(':checked');
var schDayGubun = $.trim(nvl($("#schDayGubun").val(), ""));
var schBeginDt = $.trim(nvl($("#schBeginDt").val(), ""));
var schEndDt = $.trim(nvl($("#schEndDt").val(), ""));
var schBdongName = $.trim(nvl($("#schBdongName").val(), ""));
var schBuldMnnm = $.trim(nvl($("#schBuldMnnm").val(), ""));
var schBuldSlno = $.trim(nvl($("#schBuldSlno").val(), ""));
var schOResName = $.trim(nvl($("#schOResName").val(), ""));
var schHResName = $.trim(nvl($("#schHResName").val(), ""));
var schRegstrMngNo = $.trim(nvl($("#schRegstrMngNo").val(), ""));
var schOnlyMyDataChk = !!$("#schOnlyMyDataChk").is(':checked');
var schDataChk = $.trim(nvl($("input[name=schDataChk]:checked").val(), ""));
SEARCH_COND.schDateChk = schDateChk;
SEARCH_COND.schDayGubun = schDayGubun;
SEARCH_COND.schBeginDt = schBeginDt;
SEARCH_COND.schEndDt = schEndDt;
SEARCH_COND.schBdongName = schBdongName;
SEARCH_COND.schBuldMnnm = schBuldMnnm;
SEARCH_COND.schBuldSlno = schBuldSlno;
SEARCH_COND.schOResName = schOResName;
SEARCH_COND.schHResName = schHResName;
SEARCH_COND.schRegstrMngNo = schRegstrMngNo;
SEARCH_COND.schOnlyMyDataChk = schOnlyMyDataChk;
SEARCH_COND.schDataChk = schDataChk;
SEARCH_COND.isMywork = false; //이거 왜쓰는거임?
SEARCH_COND.schMyworkGubun = "N"; //이거 왜쓰는거임?
};
/**
* 로그인 로그 목록 관리 네임스페이스
*/
var Ma30List = {
/**
* 그리드 관련 객체 - 4개 그리드 관리
*/
grid: {
/**
* 그리드 인스턴스들 (4개)
*/
instances: {
grid1: null,
grid2: null,
grid3: null,
grid4: null
},
/**
* 그리드 설정 초기화
* @param {String} gridId - 그리드 ID (grid1, grid2, grid3, grid4)
* @returns {Object} 그리드 설정 객체
*/
initConfig: function(gridId) {
// 데이터 소스 설정
var dataSource = this.createDataSource();
// 현재 선택된 perPage 값 가져오기
var perPage = parseInt($('#perPageSelect').val() || 15, 10);
// 그리드 설정 객체 생성
var gridConfig = new XitTuiGridConfig();
// 기본 설정
gridConfig.setOptDataSource(dataSource); // 데이터소스 연결
gridConfig.setOptGridId(gridId); // 그리드를 출력할 Element ID
gridConfig.setOptGridHeight(130); // 그리드 높이(단위: px) - 4분할에 맞게 줄임
gridConfig.setOptRowHeight(30); // 그리드 행 높이(단위: px)
gridConfig.setOptRowHeaderType('rowNum'); // 행 첫번째 셀 타입(rowNum: 순번, checkbox: 체크박스, '': 출력 안함)
gridConfig.setOptUseClientSort(false); // 서버사이드 정렬 false
// 페이징 옵션 설정
gridConfig.setOptPageOptions({
useClient: false, // 클라이언트 페이징 여부(false: 서버 페이징)
perPage: perPage // 페이지당 표시 건수
});
gridConfig.setOptHeader(this.getGridOptHeader());
gridConfig.setOptColumns(this.getGridColumns());
return gridConfig;
},
getGridOptHeader: function() {
return {
height: 60,
complexColumns: [
{
header: '단속현황',
name: 'dansokhyeonhwang',
childNames: ['mngYy', 'regstrMngNo', 'mngNo', 'bdongName', 'posAddr', 'addrEtc', 'actions']
},
]
}
},
/**
* 그리드 컬럼 정의
* @returns {Array} 그리드 컬럼 배열
*/
getGridColumns: function() {
return [
{
header: '연도',
name: 'mngYy',
width: 60,
align: 'center'
},
{
header: '관리번호',
name: 'regstrMngNo',
width: 100,
align: 'center'
},
{
header: '연번',
name: 'mngNo',
width: 60,
align: 'center'
},
{
header: '동',
name: 'bdongName',
width: 80,
align: 'center'
},
{
header: '지번',
name: 'posAddr',
width: 80,
align: 'center'
},
{
header: '상세주소',
name: 'addrEtc',
width: 150,
align: 'left'
},
{
header: '작업',
name: 'actions',
width: 80,
align: 'center',
sortable: false,
resizable: false,
formatter: function(props) {
// 개발자가 직접 커스텀 메뉴 아이템 설정 (새로운 방식 사용)
return XitTuiGridDropdownMenu.createMenuHtml(props, {
menuItems: [
{ text: '보기', action: 'view', class: 'js-row-view' },
{ text: '상세정보', action: 'detail', class: 'js-row-detail' },
{ text: '수정', action: 'edit', class: 'js-row-edit' },
{ text: '삭제', action: 'delete', class: 'js-row-delete', style: 'color: #dc3545;' }
]
});
}
},
];
},
/**
* 데이터 소스 생성
* @returns {Object} 데이터 소스 객체
*/
createDataSource: function() {
return {
api: {
readData: {
url: '<c:url value="/ma30/list.ajax"/>',
method: 'POST',
contentType: 'application/x-www-form-urlencoded',
processData: true
}
},
initialRequest: true, // 초기 데이터 요청 여부
serializer: function(params) {
// 기본 파라미터 (페이지 정보 등)
var defaultParams = $.param(params);
// 검색 폼 데이터
setSearchCond();
var searchParams = $.param(SEARCH_COND);
// 모든 파라미터 조합
console.log(defaultParams + '&' + searchParams);
return defaultParams + '&' + searchParams;
}
};
},
/**
* 4개 그리드 인스턴스 생성
*/
create: function() {
var Grid = tui.Grid;
var self = this;
// 그리드 ID 배열
var gridIds = ['grid1', 'grid2', 'grid3', 'grid4'];
// 각 그리드 생성
gridIds.forEach(function(gridId) {
var gridConfig = self.initConfig(gridId);
self.instances[gridId] = gridConfig.instance(Grid);
// 드롭다운 메뉴가 잘리지 않도록 overflow 설정 조정
$('#' + gridId).css('overflow', 'visible');
});
// 그리드 테마 설정
Grid.applyTheme('striped');
// 공통 오버플로우 설정
$('.containers').css('overflow', 'visible');
$('.gs_booking').css('overflow', 'visible');
// 그리드 이벤트 설정
this.gridBindEvents();
},
/**
* 4개 그리드 이벤트 바인딩
*/
gridBindEvents: function() {
var self = this;
var gridIds = ['grid1', 'grid2', 'grid3', 'grid4'];
// 각 그리드별로 이벤트 바인딩
gridIds.forEach(function(gridId, index) {
var instance = self.instances[gridId];
var gridNumber = index + 1;
// 요청 성공 시 총 건수 표시
instance.on('successResponse', function(ev) {
var responseObj = JSON.parse(ev.xhr.response);
$("#currentPage" + gridNumber).text(responseObj.data.pagination.page);
$("#totalPages" + gridNumber).text(responseObj.data.pagination.totalPages);
});
// XIT 공통 컴포넌트를 사용하여 드롭다운 메뉴 이벤트 바인딩
var menuCallbacks = {
view: function(row, rowKey) {
Ma30List.openViewModal(row);
},
detail: function(row, rowKey) {
// 새로 추가된 상세정보 메뉴 액션
Ma30List.openDetailModal(row);
},
edit: function(row, rowKey) {
console.log(row);
Ma30List.openEditPage(row);
},
delete: function(row, rowKey) {
if (!confirm('정말 삭제하시겠습니까?')) return;
// 삭제 요청 처리 (실제 구현시 적절한 URL로 변경 필요)
$.ajax({
url: '<c:url value="/ma30/delete.ajax"/>',
type: 'POST',
data: { regstrMngNo: row.regstrMngNo },
success: function(res) {
alert('삭제되었습니다.');
// 성공 시 현재 페이지 유지하여 모든 그리드 새로고침
gridIds.forEach(function(gId) {
var page = self.instances[gId].getPagination().getCurrentPage();
self.instances[gId].readData(page);
});
},
error: function() {
alert('삭제 중 오류가 발생했습니다.');
}
});
}
};
// 공통 컴포넌트로 이벤트 바인딩
XitTuiGridDropdownMenu.bindEvents('#' + gridId, menuCallbacks, instance);
});
}
},
/**
* 이벤트 핸들러 설정
*/
eventBindEvents: function() {
var self = this;
$("#schDateChk").on("change", function() {
if( $(this).is(":checked") ){
$("#schDayGubun").removeAttr("disabled");
$("#schBeginDt").removeAttr("disabled");
$("#schEndDt").removeAttr("disabled");
}else{
$("#schDayGubun").attr("disabled", "disabled");
$("#schBeginDt").attr("disabled", "disabled");
$("#schEndDt").attr("disabled", "disabled");}
})
// 검색 버튼 클릭 이벤트 - 모든 그리드 업데이트
$('#search_btn').on('click', function() {
// 페이지를 1로 리셋
$("#page").val(1);
// 모든 그리드 데이터 리로드
Object.keys(self.grid.instances).forEach(function(gridId) {
self.grid.instances[gridId].readData(1);
});
});
// 검색어 입력 필드에서 엔터키 이벤트 처리
$('#schForm input').on('keypress', function(e) {
if (e.which === 13) { // 엔터키 코드는 13
e.preventDefault(); // 기본 이벤트 방지
$('#search_btn').trigger('click'); // 검색 버튼 클릭 이벤트 트리거
}
});
// perPage 변경 이벤트 - 모든 그리드에 적용
$('#perPageSelect').on('change', function() {
var perPage = parseInt($(this).val(), 10);
// 모든 그리드의 perPage 설정 변경 및 데이터 리로드
Object.keys(self.grid.instances).forEach(function(gridId) {
self.grid.instances[gridId].setPerPage(perPage);
});
});
},
/**
* 모듈 초기화
*/
init: function() {
// 그리드 생성
this.grid.create();
// 이벤트 핸들러 설정
this.eventBindEvents();
},
/**
* 상세보기 모달 열기
* @param {Object} row - 선택된 행 데이터
*/
openViewModal: function(row) {
// 상세 정보를 표시할 모달 구현
// 프로젝트 공통 모달 규칙에 맞춰 구현
console.log('상세보기:', row);
alert('상세보기 기능입니다.\n관리번호: ' + row.regstrMngNo + '\n연도: ' + row.mngYy);
// 실제 구현 시 아래와 같이 모달을 열어주세요
// 예시: Xit 공통 모달 활용
/*
var modalConfig = {
title: '단속자료 상세보기',
url: '<c:url value="/ma30/view.do"/>',
params: { regstrMngNo: row.regstrMngNo },
size: 'lg' // 모달 크기
};
XitModal.open(modalConfig);
*/
},
/**
* 상세정보 모달 열기 (새로 추가된 커스텀 메뉴 예제)
* @param {Object} row - 선택된 행 데이터
*/
openDetailModal: function(row) {
// 상세 정보를 더 자세히 표시하는 모달 (기본 보기와 다른 형태)
console.log('상세정보:', row);
var detailInfo =
'=== 상세 단속자료 정보 ===\n' +
'관리번호: ' + (row.regstrMngNo || '없음') + '\n' +
'연도: ' + (row.mngYy || '없음') + '\n' +
'연번: ' + (row.mngNo || '없음') + '\n' +
'동: ' + (row.bdongName || '없음') + '\n' +
'지번: ' + (row.posAddr || '없음') + '\n' +
'상세주소: ' + (row.addrEtc || '없음');
alert(detailInfo);
// 실제 구현 시 더 상세한 모달을 만들 수 있음
/*
var modalConfig = {
title: '단속자료 상세정보',
url: '<c:url value="/ma30/detailView.do"/>',
params: { regstrMngNo: row.regstrMngNo },
size: 'xl' // 큰 모달로 더 많은 정보 표시
};
XitModal.open(modalConfig);
*/
},
/**
* 수정 페이지 이동
* @param {Object} row - 선택된 행 데이터
*/
openEditPage: function(row) {
// 수정 페이지로 이동 또는 수정 모달 열기
console.log('수정:', row);
// 페이지 이동 방식
if (confirm('수정 페이지로 이동하시겠습니까?')) {
location.href = '<c:url value="/ma30/edit.do"/>' + '?regstrMngNo=' + encodeURIComponent(row.regstrMngNo);
}
// 모달 방식으로 구현하려면 아래와 같이 사용
/*
var modalConfig = {
title: '단속자료 수정',
url: '<c:url value="/ma30/editForm.do"/>',
params: { regstrMngNo: row.regstrMngNo },
size: 'xl' // 모달 크기
};
XitModal.open(modalConfig);
*/
}
};
// 페이지 로드 시 초기화
$(function() {
Ma30List.init();
});
// 전역 네임스페이스에 모듈 노출
window.Ma30List = Ma30List;
})(window, jQuery);
</script>

@ -345,6 +345,7 @@
Ma30List.openDetailModal(row);
},
edit: function(row, rowKey) {
console.log(row);
Ma30List.openEditPage(row);
},
delete: function(row, rowKey) {

@ -641,7 +641,7 @@ var XitTuiGridDropdownMenu = {
}
});
// 메뉴 버튼 클릭 이벤트 - 메뉴 토글
// 메뉴 버튼 클릭 이벤트 - 클릭 위치 기반 메뉴 토글 (스크롤 안전)
$gridEl.off('click', '.' + config.btnClass).on('click', '.' + config.btnClass, function(e) {
e.preventDefault();
e.stopPropagation();
@ -657,10 +657,7 @@ var XitTuiGridDropdownMenu = {
// 메뉴가 보이면 숨김
$menu.hide();
} else {
// 메뉴가 숨겨져 있으면 표시
var btnOffset = $btn.offset();
var btnHeight = $btn.outerHeight();
var btnWidth = $btn.outerWidth();
// 메뉴가 숨겨져 있으면 표시 - 클릭 위치 기준 간단한 방식
// 메뉴를 임시로 표시하여 크기 측정
$menu.css({
@ -677,51 +674,49 @@ var XitTuiGridDropdownMenu = {
'display': 'none'
});
// 화면 크기 정보
var windowHeight = $(window).height();
var windowScrollTop = $(window).scrollTop();
var viewportBottom = windowScrollTop + windowHeight;
// 클릭 위치 기반 계산 (스크롤에 안전)
// clientX, clientY는 뷰포트 기준 좌표이므로 스크롤에 영향을 받지 않음
var clickX = e.clientX || 0;
var clickY = e.clientY || 0;
// 본 위치 계산 (버튼 아래쪽) - 35px 위쪽으로 조정하여 정확한 위치에 표시
var defaultTop = btnOffset.top + btnHeight + 2 - 35;
var menuBottom = defaultTop + menuHeight;
// 뷰포트 크
var windowHeight = $(window).height();
var windowWidth = $(window).width();
var finalTop, finalLeft;
// 세로 위치 결정: 메뉴가 화면 하단을 벗어나는지 확인
if (menuBottom > viewportBottom - 10) { // 10px 여유 공간
// 메뉴를 버튼 위쪽에 표시 - 35px 위쪽으로 조정하여 일관성 유지
finalTop = btnOffset.top - menuHeight - 2 - 35;
// 버튼 위쪽에 표시해도 화면 상단을 벗어나는 경우
if (finalTop < windowScrollTop + 10) {
// 화면 내에서 최적 위치로 조정
finalTop = windowScrollTop + 10;
}
// 간단한 위치 결정 로직
// 세로 위치: 클릭 지점 아래에 충분한 공간이 있으면 아래로, 없으면 위로
if (clickY + menuHeight + 10 <= windowHeight) {
// 아래쪽에 표시할 공간이 있음
finalTop = clickY + 5; // 클릭 지점 바로 아래
} else {
// 기본 위치 (버튼 아래쪽) 사용
finalTop = defaultTop;
// 위쪽에 표시
finalTop = Math.max(10, clickY - menuHeight - 5); // 클릭 지점 위쪽
}
// 가로 위치 계산 (버튼 우측 정렬)
finalLeft = btnOffset.left - menuWidth + btnWidth;
// 메뉴가 화면 왼쪽을 벗어나는지 확인
if (finalLeft < 10) {
// 버튼 왼쪽 정렬로 변경
finalLeft = btnOffset.left;
// 가로 위치: 클릭 지점 기준으로 우측 정렬, 공간이 없으면 좌측 정렬
if (clickX - menuWidth + 20 >= 0) {
// 우측 정렬 (메뉴가 버튼 오른쪽 끝에 맞춰짐)
finalLeft = clickX - menuWidth + 20;
} else if (clickX + menuWidth + 10 <= windowWidth) {
// 좌측 정렬 (클릭 지점에서 시작)
finalLeft = clickX;
} else {
// 화면 중앙 정렬
finalLeft = Math.max(10, Math.min(windowWidth - menuWidth - 10, clickX - menuWidth / 2));
}
// 메뉴가 화면 오른쪽을 벗어나는지 확인
var windowWidth = $(window).width();
if (finalLeft + menuWidth > windowWidth - 10) {
finalLeft = windowWidth - menuWidth - 10;
}
// 최종 경계 검사 (뷰포트 내 강제 조정)
finalTop = Math.max(10, Math.min(windowHeight - menuHeight - 10, finalTop));
finalLeft = Math.max(10, Math.min(windowWidth - menuWidth - 10, finalLeft));
// 최종 위치 적용 및 표시
// 클릭 위치 기반 메뉴 표시 (스크롤 상황에서도 정확)
$menu.css({
'top': finalTop,
'left': finalLeft
'left': finalLeft,
'position': 'fixed', // fixed 포지션으로 뷰포트 기준 위치 고정
'z-index': 9999 // 다른 요소들 위에 표시 보장
}).show();
}
});

Loading…
Cancel
Save