PageSourceSearch

https://m.thankqcamping.com/js/search_list.js?version=20261001-1

js thankqcamping.com collected 2026-10-01 15:27:37 UTC 22,404 bytes, 524 lines download raw bytes

1const DataListManager = {
2    _viewType: "PIC",
3    _isPending: false,
4    _currentAjax: null,
5    _adCurrentAjax: null,
6    init: function() {
7        this.adFetchData();
8        this.fetchData();
9    },
10    fetchData: function(isReset) {
11        this._isPending = true;
12        if (DataListManager._currentAjax) DataListManager._currentAjax.abort();
13
14        if (isReset) {
15            $("#DivResvList").html("");
16            $(window).scrollTop(0);
17            filterManager._selectedFilters.page = 0
18
19            this.adFetchData();
20        }
21
22        this.showSkeleton();
23
24        const subRegionValue = searchFilterManager._filter.sub_region.length > 0  ? searchFilterManager._filter.sub_region.join(",") : "";
25        const siteTpValue = filterManager._selectedFilters.ser_site_tp.length > 0  ? filterManager._selectedFilters.ser_site_tp.join(",") : "";
26        const campPositionValue = filterManager._selectedFilters.ser_camp_position.length > 0  ? filterManager._selectedFilters.ser_camp_position.join(",") : "";
27        const campSpecValue = filterManager._selectedFilters.ser_camp_spec.length > 0  ? filterManager._selectedFilters.ser_camp_spec.join(",") : "";
28        const serPgTp= filterManager._selectedFilters.ser_pg_tp.length > 0  ? filterManager._selectedFilters.ser_pg_tp.join(",") : "";
29        const festaValue= filterManager._selectedFilters.ser_festa_gbn;
30        const isFesta = festaValue == "" ? "" : "Y";
31        const keySubCd2Value = filterManager._selectedFilters.ser_key_sub_cd2.length > 0  ? filterManager._selectedFilters.ser_key_sub_cd2.join(",") : "";
32
33        const isNoneEmptyButton = searchFilterManager._filter.ser_res_date == "" && searchFilterManager._filter.ser_res_end_date == "" ? 'Y' : 'N';
34
35        const param = {
36            region: searchFilterManager._filter.region,
37            sub_region: subRegionValue,
38            site_tp: siteTpValue,
39            ser_disc_yn: filterManager._selectedFilters.ser_disc_yn,
40            ser_empty_yn: filterManager._selectedFilters.ser_empty_yn,
41            ser_pg_tp: serPgTp,
42            ser_long_yn: filterManager._selectedFilters.ser_long_yn,
43            ser_res_days: filterManager._selectedFilters.res_day,
44            ser_keyword: searchFilterManager._inputFieldEl.value,
45            ser_sort: filterManager._selectedFilters.ser_sort || "R",
46            ser_camp_spec: campSpecValue,
47            ser_camp_position: campPositionValue,
48            ser_key_sub_cd2: keySubCd2Value,
49            ser_q_point: filterManager._selectedFilters.ser_q_point,
50            ser_deposit_yn: filterManager._selectedFilters.ser_deposit_yn,
51            ser_new_yn: filterManager._selectedFilters.ser_new_yn,
52            ser_kid: filterManager._selectedFilters.ser_kid,
53            ser_key_cd: filterManager._selectedFilters.ser_key_cd,
54            ser_key_sub_cd: filterManager._selectedFilters.ser_key_sub_cd,
55            ser_festa_gbn: filterManager._selectedFilters.ser_festa_gbn,
56            ser_2peopleOnly: filterManager._selectedFilters.ser_2peopleOnly,
57            ser_res_dt: searchFilterManager._filter.res_date,
58            ser_res_edt: searchFilterManager._filter.res_end_date,
59            ser_only_able: filterManager._selectedFilters.ser_only_able,
60            ser_get_coupon_yn: filterManager._selectedFilters.ser_get_coupon_yn,
61            ser_st: "N",
62            ser_adult_count: searchFilterManager._filter.adultCount,
63            ser_child_count: searchFilterManager._filter.childCount,
64            ser_festa_gbn: festaValue,
65            festa_yn: isFesta,
66            view_type: this._viewType,
67            is_empty_button: isNoneEmptyButton,
68            page_num: filterManager._selectedFilters.page + 1
69        }
70      
71        DataListManager._currentAjax = $.ajax({
72            type: "POST",
73            url: "/resv/ax_list_search.hbb",
74            data: param,
75            success: function(dataObj) {
76                DataListManager.onSuccess(dataObj, isReset, isNoneEmptyButton);
77            },
78            error: DataListManager.onError
79        });
80    },
81    adFetchData: function (){
82        const siteTpValue = filterManager._selectedFilters.ser_site_tp.length > 0  ? filterManager._selectedFilters.ser_site_tp.join(",") : "";
83        
84        const param = {
85            "pr_cate": "LIST",
86            "view_type": this._viewType,
87
88            "ser_new_yn": filterManager._selectedFilters.ser_new_yn,
89            "ser_long_yn": filterManager._selectedFilters.ser_long_yn,
90            "ser_festa_gbn": filterManager._selectedFilters.ser_festa_gbn,
91            "site_tp": siteTpValue,
92            "region": searchFilterManager._filter.region,
93            "ser_sort": filterManager._selectedFilters.ser_sort,
94            "ser_keyword": searchFilterManager._inputFieldEl.value
95        }
96
97        DataListManager._adCurrentAjax = $.ajax({
98            type: "POST",
99            url: "/resv/ax_camp_pr.hbb",
100            data: param,
101            success: function(dataObj) {
102                DataListManager.onAdSuccess(dataObj);
103            },
104            error: function(xhr, status, error) {
105                DataListManager.onError(xhr, status, error);
106            }
107        });
108    },
109    onSuccess: function (dataObj, isReset, isNoneEmptyButton) {
110        DataListManager._currentAjax = null;
111        const emptyButtonEl = document.getElementById("empty_y");
112
113        if (!(searchFilterManager._filter.ser_res_date == "" && searchFilterManager._filter.ser_res_end_date == "")) {
114            emptyButtonEl.style.display = "flex";
115        } else {
116            emptyButtonEl.style.display = "none";
117        }
118
119        if (dataObj == "") {
120            this._isPending = true;
121            this.hideSkeleton();
122            return;
123        }
124        
125        const parsed = JSON.parse(dataObj);
126        const contents = parsed?.data?.campList ?? [];
127        //console.log(contents);
128
129        if (contents.length === 0) {
130            this._isPending = true;
131            this.hideSkeleton();
132            return;
133        }
134
135        if (isReset) $("#DivResvList").empty();
136
137        const html = contents
138            .map(camp => this.renderCampCard(camp, isNoneEmptyButton))
139            .join("");
140
141        this.hideSkeleton();
142        //$("#DivResvList").append(html);
143        const container = document.getElementById("DivResvList");
144        const fragment = document.createDocumentFragment();
145        const temp = document.createElement("div");
146        temp.innerHTML = html;
147        while (temp.firstChild) {
148            fragment.appendChild(temp.firstChild);
149        }
150        container.appendChild(fragment);
151        DataListManager.campSwiper();
152        setTimeout(() => {
153            DataListManager.campEventSwiper();
154        }, 0);
155        this._isPending = false;
156    },
157    onError: function(e){
158        //console.log(e);
159        DataListManager.hideSkeleton();
160
161        this._isPending = false;
162    },
163    onAdSuccess: function(dataObj) {
164        DataListManager._adCurrentAjax = null;
165        
166        $("#DivResvPrList").html("");
167        const container = document.getElementById("DivResvPrList");
168        const temp = document.createElement("div");
169        temp.innerHTML = dataObj;
170
171        const fragment = document.createDocumentFragment();
172        while (temp.firstChild) {
173            fragment.appendChild(temp.firstChild);
174        }
175
176        container.appendChild(fragment);
177        setTimeout(() => {
178            DataListManager.lineBannerSwiper();
179        }, 0);
180    },
181    goResSerNext: function(){
182        filterManager._selectedFilters.page = filterManager._selectedFilters.page + 1
183        this.fetchData()
184    },
185    renderCampCard: function (camp, isNoneEmptyButton) {
186        const campSeq = camp.campSeq;
187        const name = escapeHtml(camp.campName);
188        const addr = escapeHtml(camp.addr.split(" ").slice(0, 2).join(" "));
189
190        const brdCnt = Number(camp.brdCnt ?? camp.BRD_CNT ?? 0);
191        const monthlyBrdCnt = Number(camp.monthlyBrdCnt ?? camp.MONTHLY_BRD_CNT ?? 0);
192
193        const isGoCamping = !!(camp.goCampingId ?? camp.GOCAMPING_ID);
194        const isSafety = !!(camp.safetyCertPic ?? camp.SAFETY_CERT_PIC);
195
196        // 이미지 슬라이드
197        const swiperClass = `camp_swiper_${campSeq}`;
198        const slides = (camp.campPicList ?? [])
199            .map((p, i) => `
200					    <li class="swiper-slide">
201					        <img 
202					            ${i === 0 ? `src="${p.imgUrl}"` : `data-src="${p.imgUrl}"`}
203					            alt="${p.title}"
204					            loading="lazy"
205					            decoding="async"
206					        >
207					    </li>
208					`).join("");
209        // 페스타 뱃지
210        const festaBadges = camp.festaList;
211        const festaHtml = festaBadges.length ? `${festaBadges.map(fasta => `<p class="bat_c">${fasta.festaCdNm}</p>`).join("")}` : "";
212
213        // 업체쿠폰 뱃지
214        const campCouponBadges = Array.isArray(camp.campCouponList)
215            ? camp.campCouponList
216            : [];
217
218        const visibleCouponList = campCouponBadges.slice(0, 3);
219        const hiddenCouponCount = campCouponBadges.length - visibleCouponList.length;
220
221        const campCouponHtml = [
222            ...visibleCouponList.map(campCoupon => `<p class="bat_c">${campCoupon.title}</p>`),
223            hiddenCouponCount > 0 ? `<p class="bat_c">쿠폰(+${hiddenCouponCount})</p>` : ""
224        ].join("");
225
226        // 시즌 뱃지
227        const seasonBadges = camp.seasonCampSpecList;
228        const seasonHtml = Array.isArray(seasonBadges) && seasonBadges.length ? `${seasonBadges.map(season => `<p class="bat_cp">${season}</p>`).join("")}` : "";
229
230        // 신규 여부
231        const isNew = camp.newYn === "Y" || camp.newYn === true;
232        // 찜 여부
233        const isFavor = camp.favorYn === "Y" || camp.isFavor === true;
234
235        // 반려동물 동반 여부
236        const isPet = Array.isArray(camp.campSpecs) && camp.campSpecs.includes("BP000");
237
238        // 예약여부
239        const reserveStateHtml = camp.availableSiteCnt === null || isNoneEmptyButton === 'Y' ? "" : camp.ableCnt === 0 ? `<p class="q_res clo">예약마감</p>` : (camp.ableCnt / camp.siteCnt * 100) >= 20 ? `<p class="q_res ok">예약가능</p>` : `<p class="q_res imm">마감임박</p>`;
240
241        // Q-Point 적립여부
242        const qpointDepositPer = ["A", "C"].includes(camp.thankqYn) === true && camp.qmoneyAgree === "Y" ? (mem_grade <= 1 ? 0 : mem_grade) : 0;
243
244        // 가격    
245        const campFee = Number(camp.minBasicPrice ?? camp.minBasicPrice ?? 0);
246        const campSaleFee = Number(camp.minSalePrice ?? camp.minSalePrice ?? 0);
247        const discountPer = campFee > 0 ? Math.floor(((campFee - campSaleFee) / campFee) * 100) : 0;
248
249        const priceHtml =
250            discountPer === 0 ? `
251            <div class="price_g">
252                <p class="price">
252${campFee.toLocaleString()}~</p>
253            </div>
254            `
255                : 
256              campSaleFee > campFee ?
257               	`
258                <div class="price_g">
259                    <p class="price">${campSaleFee.toLocaleString()}~</p>
260                </div>
261            `
262            :
263            `
264                <p class="per">${discountPer}%</p>
265                <div class="price_g">
266                    <p class="ex_price">${campFee.toLocaleString()}원</p>
267                    <p class="price">${campSaleFee.toLocaleString()}~</p>
268                </div>
269            `;
270
271        //이벤트
272        let event_html = ""
273        if (camp.eventList && camp.eventList.length > 0) {
274            const event_slides = (camp.eventList ?? [])
275                .map((p) => `<p class="swiper-slide place_event_text">${p.eventTitle}</p>`)
276                .join("");
277
278            event_html = `
279					  	<div class="swiper-container">
280			            <div class="swiper-wrapper text_slider">
281			                ${event_slides}
282			            </div>
283			        </div>
284			      `;
285        }
286
287        return `
288        <div class="camp_div ${this._viewType === "PIC" ? "" : "type_info"}">
289            <a href="javascript:clkNewView(${campSeq},'');">
290                <div class="box_g">
291
292                    <div class="pic">
293                    		<div class="festa_bat pic-type">
294													<ul class="flex" style="gap: 6px;">
295													    ${isNew ? `<li><img src="/images/search/new.png" /></li>` : ""}
296													    ${camp.festaList.some(f => f.festaCd === "DL000") ? `<li><img src="/images/search/festa_01.png" /></li>` : ""}
297			                                            ${camp.festaList.some(f => f.festaCd === "DL001") ? `<li><img src="/images/search/festa_02.png" /></li>` : ""}
298			                                            ${camp.festaList.some(f => f.festaCd === "DL002") ? `<li><img src="/images/search/festa_03.png" /></li>` : ""}
299			                                            ${camp.festaList.some(f => f.festaCd === "DL012") ? `<li><img src="/images/search/festa_05.png" /></li>` : ""}
300                                                        ${camp.festaList.some(f => f.festaCd === "DL007") && enter_path === "BE011" ? `<li><img src="/images/search/festa_04.png" /></li>` : ""}
301                                                        ${camp.festaList.some(f => f.festaCd === "DL008") ? `<li><img src="/images/search/festa_06.png" /></li>` : ""}
302                                                        ${camp.festaList.some(f => f.festaCd === "DL013") ? `<li><img src="/images/search/festa_07.png" /></li>` : ""}
303                                                        ${camp.festaList.some(f => f.festaCd === "DL011") ? `<li><img src="/images/search/festa_08.png" /></li>` : ""}
304													</ul>
305												</div>
306                        
307                        <div class="bat_zzim">
308                            <button type="button" data-value="${campSeq}" class="btn_zzim ${isFavor ? "on" : ""}"></button>
309                        </div>
310                        
311                        <div class="swiper-container camp_swiper list_img ${swiperClass}">
312                            <ul class="swiper-wrapper">
313                                ${slides}
314                            </ul>
315                            <div class="pagination_com swiper-pagination"></div>
316                        </div>
317                    </div>
318
319                    <div class="text_box">
320                        <div>
321                            <div>
322                                <div class="top_text">
323                                    <div class="top_text_bat">
324                                    ${isGoCamping ? `<p class="bat_gocamping list-type">고캠핑인증</p>` : ""}
325                                    ${isSafety ? `<p class="bat_safe list-type">안전캠핑교육인증</p>` : ""}
326                                    </div>
327                        
328                                    <p class="name">${name}</p>
329                        
330                                    <div class="right_text_bat">
331                                    ${isGoCamping ? `<p class="bat_gocamping pic-type">고캠핑인증</p>` : ""}
332                                    ${isSafety ? `<p class="bat_safe pic-type">안전캠핑교육인증</p>` : ""}
333                                    </div>
334                                </div>
335                        
336                                <div class="center_text">
337                                    <p class="addr">${addr}</p>
338                                    <p class="review">
338 후기 ${brdCnt.toLocaleString()} ${monthlyBrdCnt > 0 ? `(최근${monthlyBrdCnt.toLocaleString()})` : ""}</p>
339                                </div>
340                            </div>
341                        
342                            <div>
343                                <div class="top_bat">
344                                    <div class="benefit_bat">
345                                        ${camp.qpointDepositPer > 0 && camp.jhId=="" ? `<p class="bat_p">Q-Point 적립</p>` : ""}
346                                        ${camp.qmoneyAgree == 'Y' ? `<p class="bat_p">Q-Point사용</p>` : ""}
347                                        ${escapeHtml(camp.sigungu).includes("가평") ? `<p class="bat_c">웰컴 가평</p>` : ""}
348                                        ${camp.discYn == 'Y'? `<p class="bat_s">할인특가</p>` : ""}
349                                        ${camp.specDiscYn == 'Y' ? `<p class="bat_s">우대할인특가</p>` : ""}
350                                        ${camp.eventYn == 'Y' ? `<p class="bat_e">업체이벤트</p>` : ""}
351                                        ${festaHtml}
352                                        ${campCouponHtml}
353                                    </div>
354                                </div>
355
356                                <div class="mid_bat">
357                                    <div class="benefit_bat">
358                                        ${seasonHtml}
359                                        ${isPet? `<p class="bat_noti">반려동물동반</p>` : ""}
360                                        ${camp.emptyAlarmYn == 'Y' ? `<p class="bat_noti">빈자리알림</p>` : ""}
361                                        ${camp.pgTps.includes("C") || camp.pgTps.includes("V") ? `<p class="bat_card">온라인결제</p>` : ""}
362                                    </div>
363                                </div>
364                            </div>
365                        </div>
366                        
367                        <div class="btm_text">
368                            <div>${reserveStateHtml}</div>
369                            <div class="price_div">${priceHtml}</div>
370                        </div>
371                    </div>
372
373                </div>
374								<!-- box_g -->
375								<div class="etc_txt">
376										${event_html}
377								</div>																
378            </a>
379        </div>
380				`;
381    },
382    showSkeleton: function() {
383        const skeletonListHTML = `
384				<div class="camp_div skeleton">
385					<a href="#">
386						<div class="box_g">
387							<div class="pic"></div>
388							<div class="text_box">
389								<div>
390									<div>
391										<div class="top_text"></div>
392										<div class="center_text"></div>
393									</div>
394									<div>
395										<div class="top_bat">
396											<div class="benefit_bat">
397												<p class="item"></p>
398												<p class="item"></p>
399												<p class="item"></p>
400											</div>
401										</div>
402									</div>
403								</div>
404								<div class="btm_text">
405									<p></p>
406									<div class="price_div"></div>
407								</div>
408							</div>
409						</div>
410					</a>
411				</div>
412			`;
413
414        for (let i = 0; i < 5; i++) {  // 스켈레톤 5개 추가
415            $("#DivResvList").append(skeletonListHTML);
416        }
417    },
418    hideSkeleton: function() {
419        $("#DivResvList .skeleton").remove();
420    },
421    campSwiper: function(){
422        document.querySelectorAll('.camp_swiper').forEach(function(el){
423
424            // 이미 생성된 swiper 방지
425            if (el.swiper) return;
426
427            const swiper = new Swiper(el, {
428                pagination: {
429                    el: el.querySelector(".pagination_com"),
430                    clickable: true
431                },
432                slidesPerView: 1,
433                spaceBetween: 5,
434                loop: false,
435                observer: true,
436                observeParents: true
437            });
438
439            // 슬라이드 변경 시 이미지 로딩
440            swiper.on('slideChange', function () {
441                for (let i = 0; i < swiper.slides.length; i++) {
442                    const slide = swiper.slides[i];
443                    const img = slide.querySelector("img[data-src]");
444                    if (img && !img.src) {
445                        img.src = img.dataset.src;
446                    }
447                }
448            });
449        });
450    },
451    campEventSwiper: function() {
452    	console.log('campEventSwiper')
453        const targets = document.querySelectorAll('.etc_txt .swiper-container');
454
455        const observer = new IntersectionObserver((entries) => {
456
457				    entries.forEach(entry => {
458				
459				        if (!entry.isIntersecting) return;
460				
461				        const el = entry.target;
462				
463				        if (el.swiper) return;
464				
465				        new Swiper(el, {
466				            direction: 'vertical',
467				            loop: true,
468				            slidesPerView: 1,
469				            autoplay: {
470				                delay: 2000,
471				                disableOnInteraction: false,
472				            },
473				            speed: 600,
474				        });
475				
476				    });
477				
478				}, {
479				    threshold: 0
480				});
481
482        targets.forEach(el => observer.observe(el))    
483    },
484    lineBannerSwiper: function() {
485		    line_banner_swiper = new Swiper('.line_banner_swiper', {
486		        pagination: {
487		            el: ".line_banner_pagination",
488		            type: "fraction",
489		        },
490		        slidesPerView: 1,
491		        loop: true,
492		        effect: "fade",
493		        fadeEffect: {
494		            crossFade: true
495		        },
496		        autoplay: {
497		            delay: 4000,
498		        },
499		        spaceBetween: 13,
500		        observer: true,
501		        observeParents: true,
502		        on: {
503		            init:function () {
504		                var activeSlide = this.slides[this.activeIndex];
505		                var activeId = $(activeSlide).find('img').attr('id');
506		                if(activeId) axMainBnLog('V',activeId)
507		            },
508		            slideChange: function () {
509		                var activeSlide = this.slides[this.activeIndex];
510		                var activeId = $(activeSlide).find('img').attr('id');
511		                if(activeId) axMainBnLog('V',activeId)
512		            }
513		        }
514		    });
515		}
516}
517
518function escapeHtml(str) {
519    return String(str ?? "")
520        .replaceAll("&", "&amp;")
521        .replaceAll("<", "&lt;")
522        .replaceAll(">", "&gt;")
523        .replaceAll('"', "&quot;");
524}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.