app/template/default/Product/detail.twig line 1

Open in your IDE?
  1. {#
  2. This file is part of EC-CUBE
  3. Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  4. http://www.ec-cube.co.jp/
  5. For the full copyright and license information, please view the LICENSE
  6. file that was distributed with this source code.
  7. #}
  8. {% extends 'default_frame.twig' %}
  9. {% set body_class = 'product_page' %}
  10. {% block stylesheet %}
  11.     <link rel="stylesheet" type="text/css" href="/html/user_data/assets/css/calendar.css">
  12. {% endblock %}
  13. {% block javascript %}
  14.     <script>
  15.         eccube.classCategories = {{ class_categories_as_json(Product)|raw }};
  16.         // 規格2に選択肢を割り当てる。
  17.         function fnSetClassCategories(form, classcat_id2_selected) {
  18.             var $form = $(form);
  19.             var product_id = $form.find('input[name=product_id]').val();
  20.             var $sele1 = $form.find('select[name=classcategory_id1]');
  21.             var $sele2 = $form.find('select[name=classcategory_id2]');
  22.             eccube.setClassCategories($form, product_id, $sele1, $sele2, classcat_id2_selected);
  23.         }
  24.         {% if form.classcategory_id2 is defined %}
  25.         fnSetClassCategories(
  26.             $('#form1'), {{ form.classcategory_id2.vars.value|json_encode|raw }}
  27.         );
  28.         {% elseif form.classcategory_id1 is defined %}
  29.         eccube.checkStock($('#form1'), {{ Product.id }}, {{ form.classcategory_id1.vars.value|json_encode|raw }}, null);
  30.         {% endif %}
  31.     </script>
  32.     <script>
  33.         $(function() {
  34.             // bfcache無効化
  35.             $(window).bind('pageshow', function(event) {
  36.                 if (event.originalEvent.persisted) {
  37.                     location.reload(true);
  38.                 }
  39.             });
  40.             // Core Web Vital の Cumulative Layout Shift(CLS)対策のため
  41.             // img タグに width, height が付与されている.
  42.             // 630px 未満の画面サイズでは縦横比が壊れるための対策
  43.             // see https://github.com/EC-CUBE/ec-cube/pull/5023
  44.             $('.ec-grid2__cell').hide();
  45.             var removeSize = function () {
  46.                 $('.slide-item').height('');
  47.                 $('.slide-item img')
  48.                     .removeAttr('width')
  49.                     .removeAttr('height')
  50.                     .removeAttr('style');
  51.             };
  52.             var slickInitial = function(slick) {
  53.                 $('.ec-grid2__cell').fadeIn(1500);
  54.                 var baseHeight = $(slick.target).height();
  55.                 var baseWidth = $(slick.target).width();
  56.                 var rate = baseWidth / baseHeight;
  57.                 $('.slide-item').height(baseHeight * rate); // 余白を削除する
  58.                 // transform を使用することでCLSの影響を受けないようにする
  59.                 $('.slide-item img')
  60.                     .css(
  61.                         {
  62.                             'transform-origin': 'top left',
  63.                             'transform': 'scaleY(' + rate + ')',
  64.                             'transition': 'transform .1s'
  65.                         }
  66.                     );
  67.                 // 正しいサイズに近くなったら属性を解除する
  68.                 setTimeout(removeSize, 500);
  69.             };
  70.             $('.item_visual').on('init', slickInitial);
  71.             // リサイズ時は CLS の影響を受けないため属性を解除する
  72.             $(window).resize(removeSize);
  73.             $('.item_visual').slick({
  74.                 dots: true,
  75.                 arrows: false,
  76.                 responsive: [{
  77.                     breakpoint: 768,
  78.                     settings: {
  79.                         dots: true
  80.                     }
  81.                 }]
  82.             });
  83.             $('.slideThumb').on('click', function() {
  84.                 var index = $(this).attr('data-index');
  85.                 $('.item_visual').slick('slickGoTo', index, false);
  86.             })
  87.         });
  88.     </script>
  89.     <script>
  90.         $(function() {
  91.             $('.add-cart').on('click', function(event) {
  92.                 {% if form.classcategory_id1 is defined %}
  93.                 // 規格1フォームの必須チェック
  94.                 if ($('#classcategory_id1').val() == '__unselected' || $('#classcategory_id1').val() == '') {
  95.                     $('#classcategory_id1')[0].setCustomValidity('{{ '項目が選択されていません'|trans }}');
  96.                     return true;
  97.                 } else {
  98.                     $('#classcategory_id1')[0].setCustomValidity('');
  99.                 }
  100.                 {% endif %}
  101.                 {% if form.classcategory_id2 is defined %}
  102.                 // 規格2フォームの必須チェック
  103.                 if ($('#classcategory_id2').val() == '__unselected' || $('#classcategory_id2').val() == '') {
  104.                     $('#classcategory_id2')[0].setCustomValidity('{{ '項目が選択されていません'|trans }}');
  105.                     return true;
  106.                 } else {
  107.                     $('#classcategory_id2')[0].setCustomValidity('');
  108.                 }
  109.                 {% endif %}
  110.                 // 個数フォームのチェック
  111.                 if ($('#quantity').val() < 1) {
  112.                     $('#quantity')[0].setCustomValidity('{{ '1以上で入力してください。'|trans }}');
  113.                     return true;
  114.                 } else {
  115.                     $('#quantity')[0].setCustomValidity('');
  116.                 }
  117.                 event.preventDefault();
  118.                 $form = $('#form1');
  119.                 $.ajax({
  120.                     url: $form.attr('action'),
  121.                     type: $form.attr('method'),
  122.                     data: $form.serialize(),
  123.                     dataType: 'json',
  124.                     beforeSend: function(xhr, settings) {
  125.                         // Buttonを無効にする
  126.                         $('.add-cart').prop('disabled', true);
  127.                     }
  128.                 }).done(function(data) {
  129.                     // レスポンス内のメッセージをalertで表示
  130.                     $.each(data.messages, function() {
  131.                         $('#ec-modal-header').text(this);
  132.                     });
  133.                     $('.ec-modal').show()
  134.                     // カートブロックを更新する
  135.                     $.ajax({
  136.                         url: "{{ url('block_cart') }}",
  137.                         type: 'GET',
  138.                         dataType: 'html'
  139.                     }).done(function(html) {
  140.                         $('.ec-headerRole__cart').html(html);
  141.                     });
  142.                 }).fail(function(data) {
  143.                     alert('{{ 'カートへの追加に失敗しました。'|trans }}');
  144.                 }).always(function(data) {
  145.                     // Buttonを有効にする
  146.                     $('.add-cart').prop('disabled', false);
  147.                 });
  148.             });
  149.         });
  150.         $('.ec-modal-wrap').on('click', function(e) {
  151.             // モーダル内の処理は外側にバブリングさせない
  152.             e.stopPropagation();
  153.         });
  154.         $('.ec-modal-overlay, .ec-modal, .ec-modal-close, .ec-inlineBtn--cancel').on('click', function() {
  155.             $('.ec-modal').hide()
  156.         });
  157.     </script>
  158.     <script type="application/ld+json">
  159.     {
  160.         "@context": "https://schema.org/",
  161.         "@type": "Product",
  162.         "name": "{{ Product.name }}",
  163.         "image": [
  164.             {% for img in Product.ProductImage %}
  165.                 "{{ app.request.schemeAndHttpHost }}{{ asset(img, 'save_image') }}"{% if not loop.last %},{% endif %}
  166.             {% else %}
  167.                 "{{ app.request.schemeAndHttpHost }}{{ asset(''|no_image_product, 'save_image') }}"
  168.             {% endfor %}
  169.         ],
  170.         "description": "{{ Product.description_list | default(Product.description_detail) | replace({'\n': '', '\r': ''}) | slice(0,300) }}",
  171.         {% if Product.code_min %}
  172.         "sku": "{{ Product.code_min }}",
  173.         {% endif %}
  174.         "offers": {
  175.             "@type": "Offer",
  176.             "url": "{{ url('product_detail', {'id': Product.id}) }}",
  177.             "priceCurrency": "{{ eccube_config.currency }}",
  178.             "price": {{ Product.getPrice02IncTaxMin ? Product.getPrice02IncTaxMin : 0}},
  179.             "availability": "{{ Product.stock_find ? "InStock" : "OutOfStock" }}"
  180.         }
  181.     }
  182.     </script>
  183.     <script>
  184.         const rental_setting = '{{ rental_setting }}';
  185.     </script>
  186.     <script src="/html/user_data/assets/js/calendar.js"></script>
  187.     <script>
  188.         $(function() {
  189.             let name = $('#product_id').text();
  190.             if (name.length == 1) {
  191.                 name = '0000' + name;
  192.             }
  193.             else if (name.length == 2) {
  194.                 name = '000' + name;
  195.             }
  196.             else if (name.length == 3) {
  197.                 name = '00' + name;
  198.             }
  199.             else if (name.length == 4) {
  200.                 name = '0' + name;
  201.             }
  202.             $('#product_id').text(name);
  203.             
  204.             if ($('#classcategory_id1').length == 0) {
  205.   {# レンタル商品でない場合はカレンダー非表示 #}
  206.                 $('.ec-periodInput').hide();
  207.             }
  208.             else {
  209.                 $('.ec-numberInput').hide();
  210.                 let class_id = one_class_id;
  211.   {% if is_admin == 0 %}
  212.   {# 管理者でなければ商品規格から当日を除外 #}
  213.                 let del = 0;
  214.                 $('#classcategory_id1 option').each(function(index) {
  215.                     if ($(this).text().indexOf('当日') > -1) {
  216.                         del = index;
  217.                     }
  218.                 });
  219.                 $('#classcategory_id1 option').eq(del).remove();
  220.   {% else %}
  221.   {# 管理者 #}
  222.                 class_id = admin_class_id;
  223.   {% endif %}
  224.                 $('#classcategory_id1 option').eq(0).remove();
  225.                 let realsettings = [];
  226.                 $('#classcategory_id1 option').each(function () {
  227.                   const id = $(this).val();
  228.                   for (i = 0; i < settings.length; i++) {
  229.                     const setting = settings[i];
  230.                     if (id == setting['id']) {
  231.                       realsettings.push(setting);
  232.                     }
  233.                   }
  234.                 });
  235.                 settings = realsettings;
  236.                 let period = '{{ period }}';
  237.                 $('.ec-periodInput input').val(period);
  238.                 if (period) {
  239.                     if (period.indexOf('~') > -1) {
  240.                       period = period.split('|')[0];
  241.                       period = period.split('~');
  242.                       let start = period[0].split('/');
  243.                       let end = period[1].split('/');
  244.                       start = new Date(start[0], start[1], start[2]);
  245.                       end = new Date(end[0], end[1], end[2]);
  246.                       let termDay = (end - start) / 86400000;
  247.                       for (i = 0; i < settings.length; i++) {
  248.                         const setting = settings[i];
  249.                         if (termDay == setting['period'] - 1) {
  250.                           class_id = setting['id'];
  251.                         }
  252.                       }
  253.                     }
  254.                 }
  255.                 else {
  256.                   class_id = settings[0]['id'];
  257.                 }
  258.                 $('#classcategory_id1').val(class_id).change();
  259.                 let label = $('#classcategory_id1').prev();
  260.                 let number = $('.ec-periodInput .number');
  261.                 let cart_btn = $('.add-cart');
  262.                 let period_input = $('#period');
  263.                 number.hide();
  264.                 setInterval(function() {
  265.                     if ($('#classcategory_id1').val() == '__unselected') {
  266.                         label.text('未選択');
  267.                         number.text(0);
  268.                     }
  269.                     else {
  270.                         let price = $('.price02-default').text();
  271.                         if (label.text() != price) {
  272.                             label.text(price);
  273.                         }
  274.                         number.text($('#classcategory_id1').val());
  275.                     }
  276.                     if (period_input.val()) {
  277.                       cart_btn.show();
  278.                     }
  279.                     else {
  280.                       cart_btn.hide();
  281.                     }
  282.                 }, 100);
  283.             }
  284.             $('body').addClass('script_loaded');
  285.         });
  286.     </script>
  287. {% endblock %}
  288. {% block main %}
  289. <div class="c_inner">
  290.     <div class="item_detail">
  291.         {% set is_gold = false %}
  292.         {% if Product.ProductCategories is not empty %}
  293.         <div class="head">
  294.             {% for ProductCategory in Product.ProductCategories %}
  295.                 {% set flag = false %}
  296.                 {% for Category in ProductCategory.Category.path %}
  297.                 {% if loop.first == true and Category.id == 131 %} {% set flag = true %} {% endif %}
  298.                 {% if loop.first == true and Category.id == 193 %} {% set is_gold = true %} {% endif %}
  299.             {% endfor %}
  300.             {% if flag == true %}{# 表示するカテゴリ指定の場合の分岐処理 #}
  301.                 <p>HOME > 
  302.                   {% for Category in ProductCategory.Category.path %}
  303.                     <a href="{{ url('product_list') }}?category_id={{ Category.id }}">{{ Category.name }}</a> > 
  304.                   {% endfor %}
  305.                   {{ Product.name }}
  306.                 </p>
  307.             {% endif %}
  308.             {% endfor %}
  309.         </div>
  310.         {% endif %}
  311.         <div class="row2">
  312.             <div class="mv">
  313.                 <div class="item_visual">
  314.                     {% for ProductImage in Product.ProductImage %}
  315.                         <div class="slide-item"><img src="{{ asset(ProductImage, 'save_image') }}" alt="{{ loop.first ? Product.name : '' }}" width="550" height="550"{% if loop.index > 1 %} loading="lazy"{% endif %}></div>
  316.                     {% else %}
  317.                         <div class="slide-item"><img src="{{ asset(''|no_image_product, 'save_image') }}" alt="{{ loop.first ? Product.name : '' }}" width="550" height="550"></div>
  318.                     {% endfor %}
  319.                 </div>
  320.                 <ul class="item_nav">
  321.                     {% for ProductImage in Product.ProductImage %}
  322.                         <li class="slideThumb" data-index="{{ loop.index0 }}"><img src="{{ asset(ProductImage, 'save_image') }}" alt="" width="133" height="133" loading="lazy"></li>
  323.                     {% endfor %}
  324.                 </ul>
  325.             </div>
  326.             <div class="desc">
  327.                 <!--{% if sale_type == '3' %}
  328.                 <div id="pick_up_only" style="margin-bottom: 1em"><span>ヤマト便配送不可</span></div>
  329.                 {% endif %}-->
  330.                 {% if Product.freearea %}
  331.                 <div id="pick_up_only" style="margin-bottom: 1em"><span>{{Product.freearea}}</span></div>
  332.                 {% endif %}
  333.                 {# 商品名 #}
  334.                 <div class="ec-productRole__title">
  335.                     {% if Product.brand %}
  336.                     <p>{{ Product.brand }}</p>
  337.                     {% endif %}
  338.                     <h2 class="ec-headingTitle">{{ Product.name }}</h2>
  339.                 </div>
  340.                 {# 商品コード #}
  341.                 {% if Product.code_min is not empty %}
  342.                     <div class="ec-productRole__code">
  343.                         {{ '商品コード'|trans }}: <span class="product-code-default">{{ Product.code_min }}{% if Product.code_min != Product.code_max %} ~ {{ Product.code_max }}{% endif %}</span>
  344.                     </div>
  345.                 {% endif %}
  346.                 
  347.                 <p class="data">
  348.                   <i>品番: {{ Product.number }}</i>
  349.                   <i>ID: <span id="product_id">{{ Product.id }}</span></i>
  350.                 </p>
  351.                 <form action="{{ url('product_add_cart', {id:Product.id}) }}" method="post" id="form1" name="form1">
  352.                     {% if Product.stock_find %}
  353.                         <div class="ec-productRole__actions">
  354.                             {% if form.classcategory_id1 is defined %}
  355.                                 <div class="ec-select">
  356.                                     {{ form_row(form.classcategory_id1) }}
  357.                                     {{ form_errors(form.classcategory_id1) }}
  358.                                 </div>
  359.                                 {% if form.classcategory_id2 is defined %}
  360.                                     <div class="ec-select">
  361.                                         {{ form_row(form.classcategory_id2) }}
  362.                                         {{ form_errors(form.classcategory_id2) }}
  363.                                     </div>
  364.                                 {% endif %}
  365.                             {% endif %}
  366.                 {# 販売価格 #}
  367.                 <div class="ec-productRole__price" style="display: none;">
  368.                     {% if Product.hasProductClass -%}
  369.                         {% if Product.getPrice02IncTaxMin == Product.getPrice02IncTaxMax %}
  370.                             <div class="ec-price">
  371.                                 <span class="ec-price__price price02-default">{{ Product.getPrice02IncTaxMin|price }}</span>
  372.                                 <span class="ec-price__tax">{{ '税込'|trans }}</span>
  373.                             </div>
  374.                         {% else %}
  375.                             <div class="ec-price">
  376.                                 <span class="ec-price__price price02-default">{{ Product.getPrice02IncTaxMin|price }} ~ {{ Product.getPrice02IncTaxMax|price }}</span>
  377.                                 <span class="ec-price__tax">{{ '税込'|trans }}</span>
  378.                             </div>
  379.                         {% endif %}
  380.                     {% else %}
  381.                         <div class="ec-price">
  382.                             <span class="ec-price__price">{{ Product.getPrice02IncTaxMin|price }}</span>
  383.                             <span class="ec-price__tax">{{ '税込'|trans }}</span>
  384.                         </div>
  385.                     {% endif %}
  386.                 </div>
  387.                             <div class="ec-numberInput"><span>{{ '数量'|trans }}</span>
  388.                                 {{ form_widget(form.quantity) }}
  389.                                 {{ form_errors(form.quantity) }}
  390.                             </div>
  391.                         </div>
  392.                         {% if is_gold == false or user_status == 3 -%}
  393.                         <div class="ec-periodInput">
  394.                             <div class="cal_root" data-period="{{ reserved }}">
  395.                                 {{ form_widget(form.period) }}
  396.                                 {{ form_errors(form.period) }}
  397.                                 <em>レンタル期間を選択する</em>
  398.                                 <div class="cal_wrap"></div>
  399.                                 <div class="number"></div>
  400.                             </div>
  401.                         </div>
  402.                         <div class="ec-productRole__btn">
  403.                             <button type="submit" class="ec-blockBtn--action add-cart">
  404.                                 {{ 'RESERVE'|trans }}
  405.                             </button>
  406.                         </div>
  407.                         {% else %}
  408.                         <div style="display:none">{{ form_widget(form.period) }}{{ form_errors(form.period) }}</div>
  409.                         {% endif %}
  410.                     {% else %}
  411.                         <div style="display:none">{{ form_widget(form.period) }}{{ form_errors(form.period) }}</div>
  412.                         <div class="ec-productRole__btn">
  413.                             <button type="button" class="ec-blockBtn--action" disabled="disabled">
  414.                                 {{ 'ただいま品切れ中です。'|trans }}
  415.                             </button>
  416.                         </div>
  417.                     {% endif %}
  418.                     {{ form_rest(form) }}
  419.                 </form>
  420.                 <div class="ec-modal">
  421.                     <div class="ec-modal-overlay">
  422.                         <div class="ec-modal-wrap">
  423.                             <span class="ec-modal-close"><span class="ec-icon"><img src="{{ asset('assets/icon/cross-dark.svg') }}" alt=""/></span></span>
  424.                             <div id="ec-modal-header" class="text-center">{{ 'カートに追加しました。'|trans }}</div>
  425.                             <div class="ec-modal-box">
  426.                                 <div class="ec-role">
  427.                                     <span class="ec-inlineBtn--cancel">{{ 'お買い物を続ける'|trans }}</span>
  428.                                     <a href="{{ url('cart') }}" class="ec-inlineBtn--action">{{ 'カートへ進む'|trans }}</a>
  429.                                 </div>
  430.                             </div>
  431.                         </div>
  432.                     </div>
  433.                 </div>
  434.                 <div class="contact">
  435.                     <a href="{{ url('contact') }}?product={{ Product.id }}">この商品についてお問い合わせ</a>
  436.                 </div>
  437.                 {% if BaseInfo.option_favorite_product %}
  438.                     <form action="{{ url('product_add_favorite', {id:Product.id}) }}" method="post">
  439.                         <div class="ec-productRole__btn">
  440.                             {% if is_favorite == false %}
  441.                                 <button type="submit" id="favorite" class="favorite" title="{{ 'お気に入りに追加'|trans }}"></button>
  442.                             {% else %}
  443.                                 <button type="submit" id="favorite" class="favorite done" disabled="disabled" title="{{ 'お気に入りに追加済です。'|trans }}"></button>
  444.                             {% endif %}
  445.                         </div>
  446.                     </form>
  447.                 {% endif %}
  448.                 <div class="description">
  449.                     {# 在庫数 #}
  450.                     {% if Product.stock_min %}
  451.                     <p><b>在庫数</b>{{ Product.stock_min }}{% if Product.stock_min != Product.stock_max %} ~ {{ Product.stock_max }}{% endif %}</p>
  452.                     {% endif %}
  453.                     {% if Product.size %}
  454.                     <p><b>SIZE</b>{{ Product.size }}</p>
  455.                     {% endif %}
  456.                     {% if Product.material %}
  457.                     <p><b>MATERIAL</b>{{ Product.material }}</p>
  458.                     {% endif %}
  459.                     <p><b>DETAILS</b>
  460.                     {{ Product.description_detail|raw|nl2br }}</p>
  461.                 </div>
  462.                 
  463.                 {# タグ #}
  464.                 <dl class="tag">
  465.                   <dt class="ft_e">TAG</dt>
  466.                   <dd>
  467.                   {% for Tag in Product.Tags %}
  468.                       <i class="tag_{{ Tag.id }}"><a href="/products/list?category_id=&name=&tag1={{ Tag.id }}">{{ Tag }}</a></i>
  469.                   {% endfor %}
  470.                   </dd>
  471.                 </dl>
  472.             </div>
  473.         </div>
  474.   <!--{% if Product.freearea %}
  475.         <div class="ec-productRole__description">
  476.             {{ include(template_from_string(Product.freearea)) }}
  477.         </div>
  478.   {% endif %}-->
  479.     </div>
  480. </div>
  481. {% endblock %}