카페24 기능10

김종민·2025년 7월 23일
0

카페24

목록 보기
9/10
post-thumbnail

마이페이지 내 등급별 프로그레스 바가 올라가는 코드

<!--@css(/layout/membership.css)-->
<div class="member_head section" module="myshop_asyncbankbook" style="border:0;">
    <div class="left" module="myshop_asyncbenefit">
        <div style="display:none;">
            <div class="next_grade">{$sNextGrade}</div>
            <div class="next_grade_price">{$sGradeIncreasePrice}</div>
        </div>
        <img src="https://seoyoonwells.cafe24.com/web/upload/od_img/family.png" class="grade_img">
        <div>
            <h2>안녕하세요 {$member_name} 님!<br>
             {$member_name}님의 회원 등급은 <span class="grade">{$group_name}</span></h2>
            <p class="total_buy_price">구매 누적금액: {$sPeriodOrderPrice}</p>
            <p class="total_buy_period">등급은 최근 12개월간 구매금액 기준입니다.</p>
        </div>
        <a href="/article/공지사항/1/125/">등급별 혜택 보기</a>
    </div>
    <div class="right">
        <div class="cou">
            <div><h2>쿠폰</h2><a href="/myshop/coupon/coupon.html">자세히보기</a></div>
            <div>{$coupon_cnt}개</div>
        </div>
         <div class="cou">
            <div><h2>적립금</h2><a href="/myshop/mileage/historyList.html">자세히보기</a></div>
            <div>{$total_mileage}</div>
        </div>
    </div>
</div>

<style>
.progress-wrapper {
  position: absolute;
 opacity:0.5;
  top: 145px;
  left: 0;
    transition: all 0.3s ease;
  width: 100%;
  height: 10px;
  display: flex;
  z-index: 1;
}
.progress-segment {
  width: 12.5%;
  height: 100%;
  background: #d9d9d9;
  position: relative;
}
.progress-segment.active {
  background: #f5a200;
}
.progress-segment.active::after {
  content: '';
  position: absolute;
  top: 50%;
  z-index:100;
  right: -8px;
  transform: translateY(-50%);
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  border-left: 10px solid #f5a200;
}
    
    @media screen and (max-width: 1024px) {
.progress-wrapper{   top: calc(60px + 22%);}
}
    
</style>

<div class="grade-track">
  <div class="progress-wrapper">
    <div class="progress-segment" data-step="0"></div>
    <div class="progress-segment" data-step="1"></div>
    <div class="progress-segment" data-step="2"></div>
    <div class="progress-segment" data-step="3"></div>
    <div class="progress-segment" data-step="4"></div>
    <div class="progress-segment" data-step="5"></div>
    <div class="progress-segment" data-step="6"></div>
    <div class="progress-segment" data-step="7"></div>
  </div>

  <ul class="grade-steps">
    <li class="step" data-grade="FRIEND">
      <div class="grade-icon">
        <img src="https://seoyoonwells.cafe24.com/web/upload/od_img/friend.png" alt="FRIEND">
      </div>
      <p class="title">FRIEND</p>
      <p class="desc">회원가입 즉시</p>
    </li>
    <li class="step" data-grade="FAMILY">
      <div class="grade-icon">
        <img src="https://seoyoonwells.cafe24.com/web/upload/od_img/family.png" alt="FAMILY">
      </div>
      <p class="title">FAMILY</p>
      <p class="desc"><span class="mo_block">구매금액</span> <span class="mo_block">10만원 이상</span> 50만원 미만</p>
    </li>
    <li class="step" data-grade="VIP">
      <div class="grade-icon">
        <img src="https://seoyoonwells.cafe24.com/web/upload/od_img/vip.png" alt="VIP">
      </div>
      <p class="title">VIP</p>
      <p class="desc"><span class="mo_block">구매금액</span> <span class="mo_block">50만원 이상</span> 150만원 미만</p>
    </li>
    <li class="step" data-grade="RENOPTIETER">
      <div class="grade-icon crown">
        <img src="https://seoyoonwells.cafe24.com/web/upload/od_img/renopti.png" class="renopti_img" alt="RENOPTIETER">
      </div>
      <p class="title">RENOPTIETER</p>
      <p class="desc"><span class="mo_block">구매금액</span>150만원 이상</p>
    </li>
  </ul>

  <div class="remain-box"></div>
</div>
<script> // &nbsp 없애기
	var options = document.getElementsByClassName('grade-steps') 
	for (index = 0; index < options.length; ++index) { 
		options[index].innerHTML = options[index].innerHTML.replace(/&nbsp;/g, ' '); 
		}
</script>
<script>
    
    
        
setTimeout(function() {
  var gradeText = $('.grade').text().trim().toUpperCase();
  console.log('[DEBUG] grade 텍스트:', gradeText);

  var gradeImgMap = {
    'FRIEND': 'https://seoyoonwells.cafe24.com/web/upload/od_img/friend.png',
    'FAMILY': 'https://seoyoonwells.cafe24.com/web/upload/od_img/family.png',
    'VIP': 'https://seoyoonwells.cafe24.com/web/upload/od_img/vip.png',
    'RENOPTIETER': 'https://seoyoonwells.cafe24.com/web/upload/od_img/renopti.png'
  };

  if (gradeImgMap[gradeText]) {
    console.log('[DEBUG] 이미지 src 설정:', gradeImgMap[gradeText]);
    $('.grade_img').attr('src', gradeImgMap[gradeText]);
  } else {
    console.warn('[WARN] 해당하는 등급 이미지가 없습니다:', gradeText);
  }
}, 500);
    
    
$(function () {
  function checkGradeLoaded(callback) {
    const gradeText = $('.grade').text().trim();
    const nextGradeText = $('.next_grade').text().trim();
    if (gradeText && nextGradeText) {
      callback();
    } else {
      setTimeout(() => checkGradeLoaded(callback), 100);
    }
  }

  checkGradeLoaded(function () {
    const grade = $('.grade').text().trim().toUpperCase();
    const nextGrade = $('.next_grade').text().trim().toUpperCase();
    const nextPriceText = $('.next_grade_price').text();
    const nextPrice = parseInt(nextPriceText.replace(/[^0-9]/g, ''), 10) || 0;
    const isMobile = window.innerWidth <= 1024;

    // ✅ 프로그레스 바 처리 (홀수 index만 사용)
    $('.progress-segment').removeClass('active');
    const stepMap = {
      'FRIEND': 1,
      'FAMILY': 3,
      'VIP': 5
    };
    const activeStep = stepMap[grade];
    if (activeStep !== undefined) {
      $('.progress-segment[data-step="' + activeStep + '"]').addClass('active');
    }

    // ✅ 등급 단계 표시 (data-grade 기준)
    $('.grade-steps .step').removeClass('done current next');
    let foundCurrent = false;
    $('.grade-steps .step').each(function () {
      const stepGrade = $(this).data('grade')?.toString().toUpperCase();
      if (stepGrade === grade) {
        $(this).addClass('current');
        foundCurrent = true;
      } else if (foundCurrent && stepGrade === nextGrade) {
        $(this).addClass('next');
      } else if (!foundCurrent) {
        $(this).addClass('done');
      }
    });

    // ✅ 말풍선 처리 유지
    if (nextGrade && nextPrice > 0 && grade !== 'RENOPTIETER') {
      const formattedPrice = nextPrice.toLocaleString();
      const message = `${nextGrade} 등급까지 남은 금액: <strong>${formattedPrice}원</strong>`;
      $('.remain-box').html(message).show();

      $('.remain-box').removeClass('tail-friend tail-family tail-vip tail-renop');
      if (isMobile) {
        if (nextGrade === 'FAMILY') $('.remain-box').addClass('tail-family');
        else if (nextGrade === 'VIP') $('.remain-box').addClass('tail-vip');
        else if (nextGrade === 'RENOPTIETER') $('.remain-box').addClass('tail-renop');
        else $('.remain-box').addClass('tail-friend');
      }

      const $currentStep = $('.grade-steps .step.current');
      const $nextStep = $('.grade-steps .step.next');
      const $track = $('.grade-track');

      if ($currentStep.length && $nextStep.length && $track.length) {
        const currentOffset = $currentStep.offset();
        const nextOffset = $nextStep.offset();
        const trackOffset = $track.offset();
        const currentWidth = $currentStep.outerWidth();
        const nextWidth = $nextStep.outerWidth();

        const currentCenter = currentOffset.left - trackOffset.left + currentWidth / 2;
        const nextCenter = nextOffset.left - trackOffset.left + nextWidth / 2;
        const middleLeft = (currentCenter + nextCenter) / 2;

        if (isMobile) {
          $('.grade-steps').after($('.remain-box'));
          $('.remain-box').css({
            left: '50%',
            transform: 'translateX(-50%)',
            width: 'calc(100% - 40px)',
            maxWidth: '500px',
            margin: '20px auto 0',
            opacity: '1'
          });
        } else {
          $nextStep.append($('.remain-box'));
          $('.remain-box').css({
            position: 'relative',
            left: '50%',
            transform: 'translateX(-50%)',
            opacity: '1',
            marginTop: '25px'
          });
        }
      }
    } else {
      $('.remain-box').hide();
    }
  });
});
    
    
$(window).on('load resize', function () {
  var $img = $('.step.current .grade-icon img');
  var $wrapper = $('.progress-wrapper');

  var imgHeight = $img.outerHeight();
  var wrapperHeight = $wrapper.outerHeight();

  if (imgHeight && wrapperHeight) {
    var newTop = (imgHeight / 2) - (wrapperHeight / 2);
    var fixedOffset = 110; // 추가로 고정값을 더하고 싶으면 여기 수정

    // top 계산 적용
    $wrapper.css('top', (fixedOffset + newTop) + 'px');
	$wrapper.css('opacity', '1');
    console.log('[DEBUG] imgHeight:', imgHeight, '| wrapperHeight:', wrapperHeight, '| top:', fixedOffset + newTop + 'px');
  } else {
    console.log('[DEBUG] 이미지나 래퍼 높이 측정 실패');
  }
});
</script>
<style>
.member_head {display:flex; padding:30px 0 60px;}
.grade_img  {  height: 88px;}
.member_head .left {display:flex; gap:35px;}
.member_head .left h2 {font-size:20px; font-weight:600; line-height:1.58;}
.member_head .left h2 > span.grade {color:#FFA500;}
.member_head .left .total_buy_price {font-size:15px; font-weight:500; margin-top:5px;}
.member_head .left .total_buy_period {font-size:12px; font-weight:500; margin-top:5px; color:#666;}
.member_head .left a {font-sizE:15px; padding:10px 23px; border:1px solid #000; border-radius:30px; text-align:center; height: fit-content; margin-left:50px;}

.member_head .right {background:#F0F0F0; display:flex; padding:20px 27px; gap:40px;}
.member_head .right > div {display:flex;     flex-direction: column; gap:40px;}
.member_head .right > div > div:first-child {display:flex; gap:160px;     align-items: center; }
.member_head .right > div > div:last-child {font-size:17px; font-weight:500;}
.member_head .right > div  h2 {font-size:12px;}
.member_head .right > div a {color:#7B808F; font-size:10px; text-decoration:underline;}

.grade-track {
    max-width: 1680px;
    position: relative;
    width: 92%;
    padding:50px 0;
    border:1px solid #000;
    margin: 0 auto;
    text-align: center;
    font-family: 'Pretendard', sans-serif;
    margin-bottom:50px;
    position: relative;
}

.grade-steps {
    display: flex;
    align-items: flex-start
        justify-content: space-between;
    padding: 60px 0 40px;
    margin: 0;
    list-style: none;
    position: relative;
    z-index: 2;
}

.progress-bar {
    position: absolute;
    top: 145px;
    left: 0;
    right: 0;
    height: 10px;
    background: #d9d9d9;
    z-index: 1;
}

.progress-fill {
    height: 100%;
    width: 0%; /* JS로 동적으로 제어 가능 */
    background: #f5a200;
    transition: width 0.3s;
    position: relative;
}

.progress-fill::after {
    opacity:0;
    content: "";
    position: absolute;
    top: 50%;
    right: -8px; /* 살짝 오른쪽 바깥쪽으로 */
    transform: translateY(-50%);
    width: 0;
    height: 0;
    border-top: 20px solid transparent;
    transition: opacity 0.4s ease;
    border-bottom: 20px solid transparent;
    border-left: 20px solid #f5a200; /* 노란 화살표색 */
}
.progress-fill.show-arrow::after {
    opacity: 1;
}
.step {
    width: 25%;
    position: relative;
    z-index: 2;
}

.grade-icon {
    width: 74px;
    height:74px;
    border-radius: 50%;
    margin: 0 auto 20px;
    display: flex;
    background: #fff;
    justify-content: center;
    align-items: center;
    box-sizing: border-box;
}

.grade-icon img {
    width: 100%;
    opacity:0.3;
    height: auto;
}



.step .title {
    font-weight: 700;
    color: #000;
    opacity:0.3;
    margin: 0 0 4px;
    font-size:15px;
}

.step .desc {
    font-size: 14px;
    line-height: 1.4;
    color: #000;
    opacity:0.3;
    margin: 0;
}

.step.current .title,
.step.current .desc,
.step.current .grade-icon img{
    opacity:1;

}
.step.next .title,
.step.next .desc,
.step.next .grade-icon img{ 
    opacity:1;

}

.step.current .grade-icon img {border: 3px solid #f5a200; border-radius:100%;}
.renopti_img {border:0 !important;}

.step.current .desc,
.step.next .desc {font-weight:700;}

.step.done .title,
.step.done .desc,
.step.dones .grade-icon img
{
    opacity:0.3;
}
.step.next .title,    
.step.current .title  {color:#FFA500;}



.renopti_img{   margin-top: -23px;}
.grade-icon.crown {
    position: relative;
}
.grade-icon.crown::before {
    content: "";
    position: absolute;
    top: -30px;
    left: 50%;
    width: 50px;
    height: 30px;
    background: url(crown.svg) center/contain no-repeat;
    transform: translateX(-50%);
}

.remain-box {
    position: absolute;
    opacity:0;
    z-index: 10;
    background: #FFA500;
    color: #fff;
    font-size: 13px;
    margin-top: -20px;
    font-weight: 500;
    padding: 14px 60px;
    border-radius: 32px;
    white-space: nowrap;
    width: fit-content;
    box-sizing: border-box;
}

.remain-box::before {
    content: "";
    position: absolute;
    top: -8px;
    left: 50%;
    transform: translateX(-50%);
    border-left: 8px solid transparent;
    border-right: 8px solid transparent;
    border-bottom: 8px solid #FFA500;
}

/* 말풍선 꼬리 (모바일) */
.remain-box::before {
    content: '';
    position: absolute;
    top: -8px;
    width: 0;
    height: 0;
    border-left: 8px solid transparent;
    border-right: 8px solid transparent;
    border-bottom: 8px solid #FFA500;
}

/* 꼬리 위치 (등급에 따라 조정) */
.tail-friend::before {
    transform: translateX(-50%);
    left: 9%;
}
.tail-family::before {
    left: 36%;
    transform: translateX(-50%);
}
.tail-vip::before {
    left: 64%;
    transform: translateX(-50%);
}
.tail-renop::before {
    left: 92%;
    transform: translateX(-50%);
}



.grade_msg {text-align:center; line-height:1.4; margin:30px 0 90px; }
.grade_msg b {font-weight:600; font-size:12px;}
.grade_msg .point {font-size:14px; color:#FFA500; font-weight:900;}
.grade_msg p {font-weight:600; font-size:12px; color:#828282;}


.only_mo {display:none;}

@media screen and (max-width: 1024px) {
    .member_head .left h2 > span.grade {font-weight:bold;}
    .only_mo {display: block;         width: 100%;
        position: absolute;
        bottom: 10px;
        text-align: center;}
    .grade-track {padding:50px 0 100px;}
    .member_head { flex-direction: column; width:100%; margin:0;}
    .member_head .left    { flex-direction: column; align-items: center; border:0; gap:20px;}
    .member_head .left h2 {text-align:center; font-weight:400;}
    .step .title {font-size:13px;}
    .total_buy_price,
    .total_buy_period{text-align:center;}
    .member_head .left a {margin-left:0;}
    .member_head .right > div {width:50%;}
    .member_head .right > div > div:first-child {gap:0;     justify-content: space-between;}
    .member_head .right {        margin: 40px 4% 0;}
    .grade-steps {    padding: 60px 0 0px;}
    .grade-icon {width:50%; height:auto;}
    .desc_period {display:none;}
    .renopti_img{   margin-top: -28%;}
    .grade-steps{  align-items: flex-start;}
    .progress-bar {top:39%;}
    .remain-box {padding:10px; font-size:11px; left: 50% !important;   margin-top: 20px;}
    .grade_msg .point {font-weight:700;}
    .grade_msg {line-height:1.8;}
    .mo_block {display:block;}
    .step .desc {font-size:10px;}
    .progress-fill::after {
        border-top: 10px solid transparent;
        border-bottom: 10px solid transparent;
        border-left: 10px solid #f5a200;
    }

}
</style>
profile
웹 퍼블리셔의 코딩 일기

0개의 댓글