文件补齐
This commit is contained in:
parent
02516b7825
commit
70c2160aca
2
.env
2
.env
|
|
@ -1,7 +1,7 @@
|
|||
APP_NAME='wyyl'
|
||||
APP_ENV=
|
||||
APP_KEY=base64:PItUypiY6FmV8oQTVIcIHyNQJAuuS36FmEs8exQbYAw=
|
||||
APP_DEBUG=false
|
||||
APP_DEBUG=true
|
||||
APP_LOG_LEVEL=
|
||||
APP_URL=http://43.153.17.83
|
||||
|
||||
|
|
|
|||
Binary file not shown.
119
LICENSE
119
LICENSE
|
|
@ -52,121 +52,4 @@ Licensor's trademarks, copyrights, patents, trade secrets or any other
|
|||
intellectual property. No patent license is granted to make, use, sell, offer
|
||||
for sale, have made, or import embodiments of any patent claims other than the
|
||||
licensed claims defined in Section 2. No license is granted to the trademarks
|
||||
of Licensor even if such marks are included in the Original Work. Nothing in
|
||||
this License shall be interpreted to prohibit Licensor from licensing under
|
||||
terms different from this License any Original Work that Licensor otherwise
|
||||
would have a right to license.
|
||||
|
||||
5) External Deployment. The term "External Deployment" means the use,
|
||||
distribution, or communication of the Original Work or Derivative Works in any
|
||||
way such that the Original Work or Derivative Works may be used by anyone
|
||||
other than You, whether those works are distributed or communicated to those
|
||||
persons or made available as an application intended for use over a network.
|
||||
As an express condition for the grants of license hereunder, You must treat
|
||||
any External Deployment by You of the Original Work or a Derivative Work as a
|
||||
distribution under section 1(c).
|
||||
|
||||
6) Attribution Rights. You must retain, in the Source Code of any Derivative
|
||||
Works that You create, all copyright, patent, or trademark notices from the
|
||||
Source Code of the Original Work, as well as any notices of licensing and any
|
||||
descriptive text identified therein as an "Attribution Notice." You must cause
|
||||
the Source Code for any Derivative Works that You create to carry a prominent
|
||||
Attribution Notice reasonably calculated to inform recipients that You have
|
||||
modified the Original Work.
|
||||
|
||||
7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that
|
||||
the copyright in and to the Original Work and the patent rights granted herein
|
||||
by Licensor are owned by the Licensor or are sublicensed to You under the
|
||||
terms of this License with the permission of the contributor(s) of those
|
||||
copyrights and patent rights. Except as expressly stated in the immediately
|
||||
preceding sentence, the Original Work is provided under this License on an "AS
|
||||
IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without
|
||||
limitation, the warranties of non-infringement, merchantability or fitness for
|
||||
a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK
|
||||
IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this
|
||||
License. No license to the Original Work is granted by this License except
|
||||
under this disclaimer.
|
||||
|
||||
8) Limitation of Liability. Under no circumstances and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise, shall the
|
||||
Licensor be liable to anyone for any indirect, special, incidental, or
|
||||
consequential damages of any character arising as a result of this License or
|
||||
the use of the Original Work including, without limitation, damages for loss
|
||||
of goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses. This limitation of liability shall not
|
||||
apply to the extent applicable law prohibits such limitation.
|
||||
|
||||
9) Acceptance and Termination. If, at any time, You expressly assented to this
|
||||
License, that assent indicates your clear and irrevocable acceptance of this
|
||||
License and all of its terms and conditions. If You distribute or communicate
|
||||
copies of the Original Work or a Derivative Work, You must make a reasonable
|
||||
effort under the circumstances to obtain the express assent of recipients to
|
||||
the terms of this License. This License conditions your rights to undertake
|
||||
the activities listed in Section 1, including your right to create Derivative
|
||||
Works based upon the Original Work, and doing so without honoring these terms
|
||||
and conditions is prohibited by copyright law and international treaty.
|
||||
Nothing in this License is intended to affect copyright exceptions and
|
||||
limitations (including "fair use" or "fair dealing"). This License shall
|
||||
terminate immediately and You may no longer exercise any of the rights granted
|
||||
to You by this License upon your failure to honor the conditions in Section
|
||||
1(c).
|
||||
|
||||
10) Termination for Patent Action. This License shall terminate automatically
|
||||
and You may no longer exercise any of the rights granted to You by this
|
||||
License as of the date You commence an action, including a cross-claim or
|
||||
counterclaim, against Licensor or any licensee alleging that the Original Work
|
||||
infringes a patent. This termination provision shall not apply for an action
|
||||
alleging patent infringement by combinations of the Original Work with other
|
||||
software or hardware.
|
||||
|
||||
11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this
|
||||
License may be brought only in the courts of a jurisdiction wherein the
|
||||
Licensor resides or in which Licensor conducts its primary business, and under
|
||||
the laws of that jurisdiction excluding its conflict-of-law provisions. The
|
||||
application of the United Nations Convention on Contracts for the
|
||||
International Sale of Goods is expressly excluded. Any use of the Original
|
||||
Work outside the scope of this License or after its termination shall be
|
||||
subject to the requirements and penalties of copyright or patent law in the
|
||||
appropriate jurisdiction. This section shall survive the termination of this
|
||||
License.
|
||||
|
||||
12) Attorneys' Fees. In any action to enforce the terms of this License or
|
||||
seeking damages relating thereto, the prevailing party shall be entitled to
|
||||
recover its costs and expenses, including, without limitation, reasonable
|
||||
attorneys' fees and costs incurred in connection with such action, including
|
||||
any appeal of such action. This section shall survive the termination of this
|
||||
License.
|
||||
|
||||
13) Miscellaneous. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent necessary
|
||||
to make it enforceable.
|
||||
|
||||
14) Definition of "You" in This License. "You" throughout this License,
|
||||
whether in upper or lower case, means an individual or a legal entity
|
||||
exercising rights under, and complying with all of the terms of, this License.
|
||||
For legal entities, "You" includes any entity that controls, is controlled by,
|
||||
or is under common control with you. For purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the direction or
|
||||
management of such entity, whether by contract or otherwise, or (ii) ownership
|
||||
of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial
|
||||
ownership of such entity.
|
||||
|
||||
15) Right to Use. You may use the Original Work in all ways not otherwise
|
||||
restricted or conditioned by this License or by law, and Licensor promises not
|
||||
to interfere with or be responsible for such uses by You.
|
||||
|
||||
16) Modification of This License. This License is Copyright © 2005 Lawrence
|
||||
Rosen. Permission is granted to copy, distribute, or communicate this License
|
||||
without modification. Nothing in this License permits You to modify this
|
||||
License as applied to the Original Work or to Derivative Works. However, You
|
||||
may modify the text of this License and copy, distribute or communicate your
|
||||
modified version (the "Modified License") and apply it to other original works
|
||||
of authorship subject to the following conditions: (i) You may not indicate in
|
||||
any way that your Modified License is the "Open Software License" or "OSL" and
|
||||
you may not use those names in the name of your Modified License; (ii) You
|
||||
must replace the notice specified in the first paragraph above with the notice
|
||||
"Licensed under <insert your license name here>" or with a notice of your own
|
||||
that is not confusingly similar to the notice in this License; and (iii) You
|
||||
may not claim that your original works are open source software unless your
|
||||
Modified License has been approved by Open Source Initiative (OSI) and You
|
||||
comply with its license review and certification process.
|
||||
of Licensor even if suc
|
||||
|
|
@ -14,6 +14,6 @@ class Logistics extends Base
|
|||
|
||||
public function country()
|
||||
{
|
||||
return $this->belongsTo(country::class, 'country_id', 'id');
|
||||
return $this->belongsTo(Country::class, 'country_id', 'id');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>恭喜,站点创建成功!</title>
|
||||
<style>
|
||||
.container {
|
||||
width: 60%;
|
||||
margin: 10% auto 0;
|
||||
background-color: #f0f0f0;
|
||||
padding: 2% 5%;
|
||||
border-radius: 10px
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
ul li {
|
||||
line-height: 2.3
|
||||
}
|
||||
|
||||
a {
|
||||
color: #20a53a
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>恭喜, 站点创建成功!</h1>
|
||||
<h3>这是默认index.html,本页面由系统自动生成</h3>
|
||||
<ul>
|
||||
<li>本页面在FTP根目录下的index.html</li>
|
||||
<li>您可以修改、删除或覆盖本页面</li>
|
||||
<li>FTP相关信息,请到“面板系统后台 > FTP” 查看</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1 @@
|
|||
open_basedir=/www/wwwroot/wyyl.dev.zoomtk.com/:/tmp/
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,73 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
/**
|
||||
* @copyright 2022 beikeshop.com - All Rights Reserved.
|
||||
* @link https://beikeshop.com
|
||||
* @Author pu shuo <pushuo@guangda.work>
|
||||
* @Date 2022-08-09 14:12:25
|
||||
* @LastEditTime 2022-09-16 19:05:44
|
||||
*/
|
||||
|
||||
body.page-pages-form {
|
||||
.autocomplete-group-wrapper {
|
||||
.inline-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.item-group-wrapper {
|
||||
padding: 10px;
|
||||
min-height: 280px;
|
||||
overflow: auto;
|
||||
background-color: #f5f5f5;
|
||||
// border: 1px solid #e3e3e3;
|
||||
|
||||
.item {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
padding: 5px 8px;
|
||||
margin-bottom: 4px;
|
||||
background: #fff;
|
||||
border: 1px solid #eee;
|
||||
cursor: move;
|
||||
display: flex;
|
||||
align-items: center; // flex-start | center
|
||||
justify-content: space-between; // flex-end | center | space-between
|
||||
&:hover {
|
||||
border-color: #aaa;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
line-height: 1;
|
||||
width: calc(100% - 16px);
|
||||
align-items: center; // flex-start | center
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
padding: 2px 0;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
i {
|
||||
// position: absolute;
|
||||
color: #999;
|
||||
font-weight: 400;
|
||||
&.right {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #222;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
@extends('admin::admin.layouts.master')
|
||||
|
||||
@section('title', '分类管理')
|
||||
|
||||
@section('content')
|
||||
<div id="app">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>编辑分类</span>
|
||||
</div>
|
||||
|
||||
<el-form label-width="200px" size="small1">
|
||||
|
||||
<el-form-item label="分类名称">
|
||||
<div style="max-width: 400px">
|
||||
@foreach (locales() as $locale)
|
||||
<el-input class="mb-1">
|
||||
<template slot="append">{{ $locale['name'] }}</template>
|
||||
</el-input>
|
||||
@endforeach
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="分类描述">
|
||||
<div style="max-width: 400px">
|
||||
@foreach (locales() as $locale)
|
||||
<el-input v-model="form.descriptions['{{ $locale['code'] }}'].content" class="mb-1">
|
||||
<template slot="append">{{ $locale['name'] }}</template>
|
||||
</el-input>
|
||||
@endforeach
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="上级分类">
|
||||
<el-select v-model="form.parent_id" placeholder="请选择上级分类">
|
||||
@foreach ($categories as $_category)
|
||||
<el-option label="{{ $_category->name }}" value="{{ $_category->id }}"></el-option>
|
||||
@endforeach
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.active">
|
||||
<el-radio :label="1">启用</el-radio>
|
||||
<el-radio :label="0">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="save">立即创建</el-button>
|
||||
<el-button>取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('footer')
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
parent_id: 0,
|
||||
active: 1,
|
||||
descriptions: {
|
||||
zh_cn: {
|
||||
name: '',
|
||||
content: '',
|
||||
},
|
||||
en: {
|
||||
name: '',
|
||||
content: '',
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
save() {
|
||||
axios.post(@json(admin_route('categories.store')), this.form).then(response => {
|
||||
this.loading = false;
|
||||
}).catch(error => {
|
||||
// this.$message.error(error.response.data.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -28,4 +28,4 @@ $(document).on('click', '.quantity-wrap .right i', function(event) {
|
|||
|
||||
input.val(input.val() * 1 - 1)
|
||||
input.get(0).dispatchEvent(new Event('input'));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
@extends('layout.master')
|
||||
|
||||
@section('body-class', 'page-order-success')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
|
||||
{{-- <x-shop-breadcrumb type="static" value="account.order.index" /> --}}
|
||||
|
||||
<div class="row mt-5 justify-content-center mb-5">
|
||||
<div class="col-12 col-md-9">@include('shared.steps', ['steps' => 3])</div>
|
||||
</div>
|
||||
|
||||
<div class="card order-wrap border">
|
||||
<div class="card-body main-body">
|
||||
<div class="order-top border-bottom">
|
||||
<div class="left">
|
||||
<i class="bi bi-check2-circle"></i>
|
||||
</div>
|
||||
<div class="right">
|
||||
<h3 class="order-title">{{ __('shop/account.order.order_success.order_success') }}</h3>
|
||||
<div class="order-info">
|
||||
<table class="table table-borderless">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ __('shop/account.order.order_success.order_number') }}:<span class="fw-bold">{{ $order['number'] }}</span></td>
|
||||
<td>{{ __('shop/account.order.order_success.amounts_payable') }}:<span class="fw-bold">{{ currency_format($order['total']) }}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ __('shop/account.order.order_success.payment_method') }}:<span class="fw-bold">{{ $order['payment_method_name'] }}</span></td>
|
||||
@if (current_customer())
|
||||
<td><a href="{{ shop_route('account.order.show', ['number' => $order->number]) }}">{{ __('shop/account.order.order_success.view_order') }}</a></td>
|
||||
@endif
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="{{ shop_route('orders.pay', [$order['number']]) }}" class="btn btn-primary">{{ __('shop/account.order.order_success.pay_now') }}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="text-muted mt-4">{{ __('shop/account.order.order_success.kind_tips') }}</div>
|
||||
<div class="mt-3">{{ __('shop/account.order.order_success.also') }}:<a href="/">{{ __('shop/account.order.order_success.continue_purchase') }}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-bottom">
|
||||
<div class="text-muted">{{ __('shop/account.order.order_success.contact_customer_service') }}:</div>
|
||||
<div>{{ __('shop/account.order.order_success.emaill') }}: {{ system_setting('base.email', '') }}</div>
|
||||
<div>{{ __('shop/account.order.order_success.service_hotline') }}: {{ system_setting('base.telephone', '') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@push('add-scripts')
|
||||
<script></script>
|
||||
@endpush
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
@extends('layout.master')
|
||||
@section('body-class', 'page-pages')
|
||||
@section('title', $page->description->meta_title ?: $page->description->title)
|
||||
@section('keywords', $page->description->meta_keywords)
|
||||
@section('description', $page->description->meta_description)
|
||||
|
||||
@push('header')
|
||||
<script src="{{ asset('vendor/swiper/swiper-bundle.min.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/swiper/swiper-bundle.min.css') }}">
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<x-shop-breadcrumb type="page" :value="$page['id']" />
|
||||
<div class="row">
|
||||
<div class="{{ $page->category ? "col-lg-9 col-12" : 'col-12' }}">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body h-min-600 p-lg-4">
|
||||
<h2 class="mb-3">{{ $page->description->title }}</h2>
|
||||
<div class="text-secondary opacity-75 mb-4">
|
||||
<span class="me-3"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg> {{ __('page_category.author') }}: {{ $page->author }}</span>
|
||||
<span class="me-3"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-clock"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg> {{ __('page_category.created_at') }}: {{ $page->created_at }}</span>
|
||||
<span><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg> {{ __('page_category.views') }}: {{ $page->views }}</span>
|
||||
</div>
|
||||
{!! $page_format['content'] !!}
|
||||
|
||||
|
||||
@if ($products)
|
||||
<div class="relations-wrap mt-5">
|
||||
<div class="container position-relative">
|
||||
<div class="title text-center fs-4 mb-4">{{ __('admin/product.product_relations') }}</div>
|
||||
<div class="product swiper-style-plus">
|
||||
<div class="swiper relations-swiper">
|
||||
<div class="swiper-wrapper">
|
||||
@foreach ($products as $item)
|
||||
<div class="swiper-slide">
|
||||
@include('shared.product', ['product' => $item])
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-pagination relations-pagination"></div>
|
||||
<div class="swiper-button-prev relations-swiper-prev"></div>
|
||||
<div class="swiper-button-next relations-swiper-next"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($page->category)
|
||||
<div class="col-lg-3 col-12">
|
||||
<div class="card mb-3 shadow-sm">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title">{{ __('product.category') }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
@foreach ($active_page_categories as $category)
|
||||
<li class="list-group-item p-0">
|
||||
<a href="{{ shop_route('page_categories.show', [$category->id]) }}"
|
||||
class="p-2 list-group-item-action nav-link">{{ $category->description->title }}</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('add-scripts')
|
||||
<script>
|
||||
var relationsSwiper = new Swiper ('.relations-swiper', {
|
||||
watchSlidesProgress: true,
|
||||
breakpoints:{
|
||||
320: {
|
||||
slidesPerView: 2,
|
||||
spaceBetween: 10,
|
||||
},
|
||||
768: {
|
||||
slidesPerView: 4,
|
||||
spaceBetween: 30,
|
||||
},
|
||||
},
|
||||
spaceBetween: 30,
|
||||
// 如果需要前进后退按钮
|
||||
navigation: {
|
||||
nextEl: '.relations-swiper-next',
|
||||
prevEl: '.relations-swiper-prev',
|
||||
},
|
||||
|
||||
// 如果需要分页器
|
||||
pagination: {
|
||||
el: '.relations-pagination',
|
||||
clickable: true,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -0,0 +1,566 @@
|
|||
@extends('layout.master')
|
||||
@section('body-class', 'page-product')
|
||||
@section('title', $product['meta_title'] ?: $product['name'])
|
||||
@section('keywords', $product['meta_keywords'] ?: system_setting('base.meta_keyword'))
|
||||
@section('description', $product['meta_description'] ?: system_setting('base.meta_description'))
|
||||
|
||||
@push('header')
|
||||
<script src="{{ asset('vendor/vue/2.7/vue' . (!config('app.debug') ? '.min' : '') . '.js') }}"></script>
|
||||
<script src="{{ asset('vendor/swiper/swiper-bundle.min.js') }}"></script>
|
||||
<script src="{{ asset('vendor/zoom/jquery.zoom.min.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/swiper/swiper-bundle.min.css') }}">
|
||||
|
||||
<script src="{{ asset('vendor/element-ui/2.15.6/js.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/2.15.6/css.css') }}">
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="container" id="product-app" v-cloak>
|
||||
<x-shop-breadcrumb type="product" :value="$product['id']" />
|
||||
|
||||
<div class="row mb-5 mt-3 mt-md-0" id="product-top">
|
||||
<div class="col-12 col-lg-6 mb-3">
|
||||
<div class="product-image d-flex align-items-start">
|
||||
@if(!is_mobile())
|
||||
<div class="left" v-if="images.length">
|
||||
<div class="swiper" id="swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide" :class="!index ? 'active' : ''" v-for="image, index in images">
|
||||
<a href="javascript:;" :data-image="image.preview" :data-zoom-image="image.popup">
|
||||
<img :src="image.thumb" class="img-fluid">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-pager">
|
||||
<div class="swiper-button-next new-feature-slideshow-next"></div>
|
||||
<div class="swiper-button-prev new-feature-slideshow-prev"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right" id="zoom">
|
||||
<img :src="images.length ? images[0].preview : '{{ asset('image/placeholder.png') }}'" class="img-fluid">
|
||||
</div>
|
||||
@else
|
||||
<div class="swiper" id="swiper-mobile">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide" v-for="image, index in images">
|
||||
<img :src="image.preview" class="img-fluid">
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-pagination mobile-pagination"></div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-lg-6">
|
||||
<div class="peoduct-info">
|
||||
@hookwrapper('product.detail.name')
|
||||
<h1 class="mb-4 product-name">{{ $product['name'] }}</h1>
|
||||
@endhookwrapper
|
||||
<div class="price-wrap d-flex align-items-end" v-if="price_setting === 'sku'">
|
||||
<div class="new-price fs-1 lh-1 fw-bold me-2">@{{ product.price_format }}</div>
|
||||
<div class="old-price text-muted text-decoration-line-through" v-if="product.price != product.origin_price && product.origin_price !== 0">
|
||||
@{{ product.origin_price_format }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="price-wrap d-flex align-items-end" v-if="price_setting === 'num'" style="
|
||||
border-top: 1px solid #aaaaaa;
|
||||
border-bottom: 1px solid #aaaaaa;
|
||||
padding: 10px;">
|
||||
<div class="item" v-for="(item,index) in numPrices" style="flex: 1">
|
||||
<div class="num" v-if="index < numPrices.length - 1" style="
|
||||
color: #777777;
|
||||
font-size: 18px;
|
||||
margin-bottom: 5px;
|
||||
">@{{ item.num }} - @{{ numPrices[index + 1].num - 1 }} sets</div>
|
||||
|
||||
<div class="num" v-else-if="item.num" style="
|
||||
color: #777777;
|
||||
font-size: 18px;
|
||||
margin-bottom: 5px;
|
||||
">>= @{{ item.num }} sets</div>
|
||||
<div class="price">
|
||||
<div class="new-price fs-3 lh-1 fw-bold me-2">@{{ item.price_format }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stock-and-sku mb-4">
|
||||
@hookwrapper('product.detail.quantity')
|
||||
<div class="d-flex">
|
||||
<span class="title text-muted">{{ __('product.quantity') }}:</span>
|
||||
<div :class="product.quantity > 0 ? 'text-success' : 'text-secondary'">
|
||||
<template v-if="product.quantity > 0">{{ __('shop/products.in_stock') }}</template>
|
||||
<template v-else>{{ __('shop/products.out_stock') }}</template>
|
||||
</div>
|
||||
</div>
|
||||
@endhookwrapper
|
||||
|
||||
@if ($product['brand_id'])
|
||||
@hookwrapper('product.detail.brand')
|
||||
<div class="d-flex">
|
||||
<span class="title text-muted">{{ __('product.brand') }}:</span>
|
||||
<a href="{{ shop_route('brands.show', $product['brand_id']) }}">{{ $product['brand_name'] }}</a>
|
||||
</div>
|
||||
@endhookwrapper
|
||||
@endif
|
||||
|
||||
@hookwrapper('product.detail.sku')
|
||||
<div class="d-flex"><span class="title text-muted">SKU:</span>@{{ product.sku }}</div>
|
||||
@endhookwrapper
|
||||
|
||||
@hookwrapper('product.detail.model')
|
||||
<div class="d-flex" v-if="product.model"><span class="title text-muted">{{ __('shop/products.model') }}:</span> @{{ product.model }}</div>
|
||||
@endhookwrapper
|
||||
</div>
|
||||
@if (0)
|
||||
<div class="rating-wrap d-flex">
|
||||
<div class="rating">
|
||||
@for ($i = 0; $i < 5; $i++)
|
||||
<i class="iconfont"></i>
|
||||
@endfor
|
||||
</div>
|
||||
<span class="text-muted">132 reviews</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="variables-wrap mb-4" v-if="source.variables.length">
|
||||
<div class="variable-group mb-2" v-for="variable, variable_index in source.variables" :key="variable_index">
|
||||
<p class="mb-2">@{{ variable.name }}</p>
|
||||
<div class="variable-info">
|
||||
<div
|
||||
v-for="value, value_index in variable.values"
|
||||
@click="checkedVariableValue(variable_index, value_index, value)"
|
||||
:key="value_index"
|
||||
:class="[value.selected ? 'selected' : '', value.disabled ? 'disabled' : '']">
|
||||
<span class="image" v-if="value.image"><img :src="value.image" class="img-fluid"></span>
|
||||
@{{ value.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($product['active'])
|
||||
<div class="quantity-btns">
|
||||
@hook('product.detail.buy.before')
|
||||
<div class="quantity-wrap">
|
||||
<input type="text" class="form-control" :disabled="!product.quantity" onkeyup="this.value=this.value.replace(/\D/g,'')" v-model="quantity" name="quantity">
|
||||
<div class="right">
|
||||
<i class="bi bi-chevron-up"></i>
|
||||
<i class="bi bi-chevron-down"></i>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-outline-dark ms-md-3 add-cart fw-bold"
|
||||
:disabled="!product.quantity"
|
||||
@click="addCart(false, this)"
|
||||
><i class="bi bi-cart-fill me-1"></i>{{ __('shop/products.add_to_cart') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark ms-3 fw-bold"
|
||||
:disabled="!product.quantity"
|
||||
@click="addCart(true, this)"
|
||||
><i class="bi bi-bag-fill me-1"></i>{{ __('shop/products.buy_now') }}
|
||||
</button>
|
||||
@hook('product.detail.buy.after')
|
||||
</div>
|
||||
<div class="add-wishlist">
|
||||
<button class="btn btn-link ps-0 text-secondary" data-in-wishlist="{{ $product['in_wishlist'] }}" onclick="bk.addWishlist('{{ $product['id'] }}', this)">
|
||||
<i class="bi bi-heart{{ $product['in_wishlist'] ? '-fill' : '' }} me-1"></i> {{ __('shop/products.add_to_favorites') }}
|
||||
</button>
|
||||
</div>
|
||||
@else
|
||||
{{-- <div class="text-danger"><i class="bi bi-exclamation-circle-fill"></i> {{ __('product.has_been_inactive') }}</div>--}}
|
||||
@endif
|
||||
<button
|
||||
style="width: 16em;"
|
||||
class="btn btn-outline-dark my-lg-2 add-cart fw-bold"
|
||||
:disabled="!product.quantity"
|
||||
@click="centerDialogVisable = true"
|
||||
><i class="bi bi-globe me-1"></i>{{ __('shop/products.inquiry') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 弹出层 -->
|
||||
<el-dialog title="Inquiry" :visible.sync="centerDialogVisable" width="700px" center>
|
||||
<div class="root" style="
|
||||
display: flex;">
|
||||
<div class="left" style="
|
||||
flex: 4;">
|
||||
<el-form :model="registerForm" ref="registerForm" label-width="90px" :rules="rules">
|
||||
<!-- 弹出层歌手名列 -->
|
||||
<el-form-item prop="contacts" label="Contacts" size="mini">
|
||||
<el-input v-model="registerForm.contacts" placeholder="Contacts"></el-input>
|
||||
</el-form-item>
|
||||
<!-- 弹出层歌手性别列 -->
|
||||
{{-- <el-form-item prop="sex" label="歌手性别" size="mini">--}}
|
||||
{{-- <el-radio-group v-model="registerForm.sex">--}}
|
||||
{{-- <el-radio :label="0">女</el-radio>--}}
|
||||
{{-- <el-radio :label="1">男</el-radio>--}}
|
||||
{{-- <el-radio :label="2">组合</el-radio>--}}
|
||||
{{-- <el-radio :label="3">不明</el-radio>--}}
|
||||
{{-- </el-radio-group>--}}
|
||||
{{-- </el-form-item>--}}
|
||||
<!-- <el-form-item prop="pic" label="歌手头像" size="mini">
|
||||
<el-input v-model="registerForm.pic" placeholder="歌手头像"></el-input>
|
||||
</el-form-item> -->
|
||||
<!-- 弹出层歌手生日列 -->
|
||||
{{-- <el-form-item prop="birth" label="生日" size="mini">--}}
|
||||
{{-- <el-date-picker type="date" placeholder="选择日期" v-model="registerForm.birth" style="width: 100%;"></el-date-picker>--}}
|
||||
{{-- </el-form-item>--}}
|
||||
<el-form-item prop="email" label="E-mail" size="mini">
|
||||
<el-input v-model="registerForm.email" placeholder="E-mail"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="content" label="Content" size="mini">
|
||||
<el-input v-model="registerForm.content" placeholder="Content" type="textarea" :rows="10" ></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="right" style="
|
||||
flex: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}">
|
||||
<div class="product" style="
|
||||
margin: -35px 10px 0 10px;">
|
||||
<div class="product-image">
|
||||
<img :src="images.length ? images[0].preview : '{{ asset('image/placeholder.png') }}'" class="img-fluid">
|
||||
</div>
|
||||
<div class="product-info" style="
|
||||
margin: 5px 5px 0 5px;">
|
||||
<div class="product-name">{{ $product['name'] }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 取消,确定按钮点击事件 -->
|
||||
<span slot="footer">
|
||||
{{-- <el-button size="mini" @click="centerDialogVisable = false">Cancel</el-button>--}}
|
||||
<el-button size="mini" @click="addSinger('registerForm')">Submit</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<div class="product-description">
|
||||
<div class="nav nav-tabs nav-overflow justify-content-start justify-content-md-center border-bottom mb-3">
|
||||
<a class="nav-link fw-bold active fs-5" data-bs-toggle="tab" href="#product-description">
|
||||
{{ __('shop/products.product_details') }}
|
||||
</a>
|
||||
@if ($product['attributes'])
|
||||
<a class="nav-link fw-bold fs-5" data-bs-toggle="tab" href="#product-attributes">
|
||||
{{ __('admin/attribute.index') }}
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade show active" id="product-description" role="tabpanel">
|
||||
{!! $product['description'] !!}
|
||||
</div>
|
||||
<div class="tab-pane fade" id="product-attributes" role="tabpanel">
|
||||
<table class="table table-bordered attribute-table">
|
||||
@foreach ($product['attributes'] as $group)
|
||||
<thead class="table-light">
|
||||
<tr><td colspan="2"><strong>{{ $group['attribute_group_name'] }}</strong></td></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($group['attributes'] as $item)
|
||||
<tr>
|
||||
<td>{{ $item['attribute'] }}</td>
|
||||
<td>{{ $item['attribute_value'] }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
@endforeach
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($relations)
|
||||
<div class="relations-wrap mt-5">
|
||||
<div class="container position-relative">
|
||||
<div class="title text-center fs-1 mb-4">{{ __('admin/product.product_relations') }}</div>
|
||||
<div class="product swiper-style-plus">
|
||||
<div class="swiper relations-swiper">
|
||||
<div class="swiper-wrapper">
|
||||
@foreach ($relations as $item)
|
||||
<div class="swiper-slide">
|
||||
@include('shared.product', ['product' => $item])
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-pagination relations-pagination"></div>
|
||||
<div class="swiper-button-prev relations-swiper-prev"></div>
|
||||
<div class="swiper-button-next relations-swiper-next"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endsection
|
||||
|
||||
@push('add-scripts')
|
||||
<script>
|
||||
let swiperMobile = null;
|
||||
|
||||
let app = new Vue({
|
||||
el: '#product-app',
|
||||
|
||||
data: {
|
||||
selectedVariantsIndex: [], // 选中的变量索引
|
||||
images: [],
|
||||
product: {
|
||||
id: 0,
|
||||
images: "",
|
||||
model: "",
|
||||
origin_price: 0,
|
||||
origin_price_format: "",
|
||||
position: 0,
|
||||
price: 0,
|
||||
price_format: "",
|
||||
quantity: 0,
|
||||
sku: "",
|
||||
},
|
||||
quantity: 1,
|
||||
source: {
|
||||
skus: @json($product['skus']),
|
||||
variables: @json($product['variables'] ?? []),
|
||||
},
|
||||
price_setting: @json($product['price_setting'] ?? 'sku'),
|
||||
numPrices: @json($product['numPrices'] ?? []),
|
||||
centerDialogVisable:false, // 设置显示框的状态
|
||||
registerForm:{ // 添加的信息
|
||||
contacts:'',
|
||||
email:'',
|
||||
content:'',
|
||||
product_sku_id:'',
|
||||
},
|
||||
rules: {
|
||||
contacts: [{
|
||||
required: true,
|
||||
message: '{{ __('shop/products.enter_contacts') }}',
|
||||
trigger: 'blur'
|
||||
}, ],
|
||||
email: [{
|
||||
required: true,
|
||||
type: 'email',
|
||||
message: '{{ __('shop/products.enter_email') }}',
|
||||
trigger: 'blur'
|
||||
}, ],
|
||||
content: [{
|
||||
required: true,
|
||||
message: '{{ __('shop/products.enter_content') }}',
|
||||
trigger: 'blur'
|
||||
}, ],
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
if(this.price_setting === 'num'){
|
||||
this.quantity = this.numPrices[0].num;
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
},
|
||||
|
||||
beforeMount () {
|
||||
const skus = JSON.parse(JSON.stringify(this.source.skus));
|
||||
const skuDefault = skus.find(e => e.is_default)
|
||||
this.selectedVariantsIndex = skuDefault.variants
|
||||
|
||||
// 为 variables 里面每一个 values 的值添加 selected、disabled 字段
|
||||
if (this.source.variables.length) {
|
||||
this.source.variables.forEach(variable => {
|
||||
variable.values.forEach(value => {
|
||||
this.$set(value, 'selected', false)
|
||||
this.$set(value, 'disabled', false)
|
||||
})
|
||||
})
|
||||
|
||||
this.checkedVariants()
|
||||
this.getSelectedSku();
|
||||
this.updateSelectedVariantsStatus()
|
||||
} else {
|
||||
// 如果没有默认的sku,则取第一个sku的第一个变量的第一个值
|
||||
this.product = skus[0];
|
||||
this.images = @json($product['images'] ?? []);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
addSinger(form){ // 点击确定按钮添加方法
|
||||
|
||||
this.$refs[form].validate((valid) => {
|
||||
if (!valid) {
|
||||
this.$message.error('{{ __('shop/checkout.check_form') }}');
|
||||
return;
|
||||
}
|
||||
this.registerForm.product_sku_id = this.product.id
|
||||
$http.post(`/inquiry`, this.registerForm).then((res) => {
|
||||
layer.msg('Success')
|
||||
this.registerForm = {
|
||||
contacts:'',
|
||||
email:'',
|
||||
content:'',
|
||||
product_sku_id:'',
|
||||
}
|
||||
})
|
||||
|
||||
this.centerDialogVisable=false
|
||||
});
|
||||
},
|
||||
checkedVariableValue(variable_idnex, value_index, value) {
|
||||
$('.product-image .swiper .swiper-slide').eq(0).addClass('active').siblings().removeClass('active');
|
||||
this.source.variables[variable_idnex].values.forEach((v, i) => {
|
||||
v.selected = i == value_index
|
||||
})
|
||||
|
||||
this.updateSelectedVariantsIndex();
|
||||
this.getSelectedSku();
|
||||
this.updateSelectedVariantsStatus()
|
||||
},
|
||||
|
||||
// 把对应 selectedVariantsIndex 下标选中 variables -> values 的 selected 字段为 true
|
||||
checkedVariants() {
|
||||
this.source.variables.forEach((variable, index) => {
|
||||
variable.values[this.selectedVariantsIndex[index]].selected = true
|
||||
})
|
||||
},
|
||||
|
||||
getSelectedSku() {
|
||||
// 通过 selectedVariantsIndex 的值比对 skus 的 variables
|
||||
const sku = this.source.skus.find(sku => sku.variants.toString() == this.selectedVariantsIndex.toString())
|
||||
const spuImages = @json($product['images'] ?? []);
|
||||
this.images = [...sku.images, ...spuImages]
|
||||
this.product = sku;
|
||||
if (swiperMobile) {
|
||||
swiperMobile.slideTo(0, 0, false)
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
$('#zoom img').attr('src', $('#swiper a').attr('data-image'));
|
||||
$('#zoom').trigger('zoom.destroy');
|
||||
$('#zoom').zoom({url: $('#swiper a').attr('data-zoom-image')});
|
||||
})
|
||||
},
|
||||
|
||||
addCart(isBuyNow = false) {
|
||||
if(this.price_setting === 'num' && this.quantity < this.numPrices[0].num){
|
||||
layer.msg( '{{ __('shop/products.quantity_error') }}' );
|
||||
return;
|
||||
}
|
||||
|
||||
bk.addCart({sku_id: this.product.id, quantity: this.quantity, isBuyNow});
|
||||
},
|
||||
|
||||
updateSelectedVariantsIndex() {
|
||||
// 获取选中的 variables 内 value的 下标 index 填充到 selectedVariantsIndex 中
|
||||
this.source.variables.forEach((variable, index) => {
|
||||
variable.values.forEach((value, value_index) => {
|
||||
if (value.selected) {
|
||||
this.selectedVariantsIndex[index] = value_index
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
updateSelectedVariantsStatus() {
|
||||
// skus 里面 quantity 不为 0 的 sku.variants
|
||||
const skus = this.source.skus.filter(sku => sku.quantity > 0).map(sku => sku.variants);
|
||||
this.source.variables.forEach((variable, index) => {
|
||||
variable.values.forEach((value, value_index) => {
|
||||
const selectedVariantsIndex = this.selectedVariantsIndex.slice(0);
|
||||
|
||||
selectedVariantsIndex[index] = value_index;
|
||||
const selectedSku = skus.find(sku => sku.toString() == selectedVariantsIndex.toString());
|
||||
if (selectedSku) {
|
||||
value.disabled = false;
|
||||
} else {
|
||||
value.disabled = true;
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("mouseover", ".product-image #swiper .swiper-slide a", function() {
|
||||
$(this).parent().addClass('active').siblings().removeClass('active');
|
||||
$('#zoom').trigger('zoom.destroy');
|
||||
$('#zoom img').attr('src', $(this).attr('data-image'));
|
||||
$('#zoom').zoom({url: $(this).attr('data-zoom-image')});
|
||||
});
|
||||
|
||||
var swiper = new Swiper("#swiper", {
|
||||
direction: "vertical",
|
||||
slidesPerView: 1,
|
||||
spaceBetween:3,
|
||||
breakpoints:{
|
||||
375:{
|
||||
slidesPerView: 3,
|
||||
spaceBetween:3,
|
||||
},
|
||||
480:{
|
||||
slidesPerView: 4,
|
||||
spaceBetween:27,
|
||||
},
|
||||
768:{
|
||||
slidesPerView: 6,
|
||||
spaceBetween:3,
|
||||
},
|
||||
},
|
||||
navigation: {
|
||||
nextEl: '.new-feature-slideshow-next',
|
||||
prevEl: '.new-feature-slideshow-prev',
|
||||
},
|
||||
observer: true,
|
||||
observeParents: true
|
||||
});
|
||||
|
||||
var relationsSwiper = new Swiper ('.relations-swiper', {
|
||||
watchSlidesProgress: true,
|
||||
breakpoints:{
|
||||
320: {
|
||||
slidesPerView: 2,
|
||||
spaceBetween: 10,
|
||||
},
|
||||
768: {
|
||||
slidesPerView: 4,
|
||||
spaceBetween: 30,
|
||||
},
|
||||
},
|
||||
spaceBetween: 30,
|
||||
// 如果需要前进后退按钮
|
||||
navigation: {
|
||||
nextEl: '.relations-swiper-next',
|
||||
prevEl: '.relations-swiper-prev',
|
||||
},
|
||||
|
||||
// 如果需要分页器
|
||||
pagination: {
|
||||
el: '.relations-pagination',
|
||||
clickable: true,
|
||||
},
|
||||
})
|
||||
|
||||
@if (is_mobile())
|
||||
swiperMobile = new Swiper("#swiper-mobile", {
|
||||
slidesPerView: 1,
|
||||
pagination: {
|
||||
el: ".mobile-pagination",
|
||||
},
|
||||
observer: true,
|
||||
observeParents: true
|
||||
});
|
||||
@endif
|
||||
|
||||
$(document).ready(function () {
|
||||
$('#zoom').trigger('zoom.destroy');
|
||||
$('#zoom').zoom({url: $('#swiper a').attr('data-zoom-image')});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
@section('content')
|
||||
@if (!request('iframe'))
|
||||
<x-shop-breadcrumb type="product" :value="$product['id']" />
|
||||
<x-shop-breadcrumb type="product" :value="$product['id']"/>
|
||||
@endif
|
||||
|
||||
<div class="container {{ request('iframe') ? 'pt-4' : '' }}" id="product-app" v-cloak>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
<div class="col-12 col-lg-6 mb-3">
|
||||
<div class="product-image d-flex align-items-start">
|
||||
@if(!is_mobile())
|
||||
<div class="left {{ $iframeClass }}" v-if="images.length">
|
||||
<div class="left {{ $iframeClass }}" v-if="images.length">
|
||||
<div class="swiper" id="swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide" :class="!index ? 'active' : ''" v-for="image, index in images">
|
||||
|
|
@ -42,8 +42,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="swiper-pager">
|
||||
<div class="swiper-button-next new-feature-slideshow-next"></div>
|
||||
<div class="swiper-button-prev new-feature-slideshow-prev"></div>
|
||||
<div class="swiper-button-next new-feature-slideshow-next"></div>
|
||||
<div class="swiper-button-prev new-feature-slideshow-prev"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -87,14 +87,16 @@
|
|||
color: #777777;
|
||||
font-size: 18px;
|
||||
margin-bottom: 5px;
|
||||
">@{{ item.num }} - @{{ numPrices[index + 1].num - 1 }} sets</div>
|
||||
">@{{ item.num }} - @{{ numPrices[index + 1].num - 1 }} sets
|
||||
</div>
|
||||
|
||||
<div class="num" v-else-if="item.num" style="
|
||||
white-space: nowrap;
|
||||
color: #777777;
|
||||
font-size: 18px;
|
||||
margin-bottom: 5px;
|
||||
">>= @{{ item.num }} sets</div>
|
||||
">>= @{{ item.num }} sets
|
||||
</div>
|
||||
<div class="price">
|
||||
<div class="new-price fs-3 lh-1 fw-bold me-2">@{{ item.price_format }}</div>
|
||||
</div>
|
||||
|
|
@ -113,12 +115,12 @@
|
|||
@endhookwrapper
|
||||
|
||||
@if ($product['brand_id'])
|
||||
@hookwrapper('product.detail.brand')
|
||||
<div class="d-flex">
|
||||
<span class="title text-muted">{{ __('product.brand') }}:</span>
|
||||
<a href="{{ shop_route('brands.show', $product['brand_id']) }}">{{ $product['brand_name'] }}</a>
|
||||
</div>
|
||||
@endhookwrapper
|
||||
@hookwrapper('product.detail.brand')
|
||||
<div class="d-flex">
|
||||
<span class="title text-muted">{{ __('product.brand') }}:</span>
|
||||
<a href="{{ shop_route('brands.show', $product['brand_id']) }}">{{ $product['brand_name'] }}</a>
|
||||
</div>
|
||||
@endhookwrapper
|
||||
@endif
|
||||
|
||||
@hookwrapper('product.detail.sku')
|
||||
|
|
@ -130,14 +132,14 @@
|
|||
@endhookwrapper
|
||||
</div>
|
||||
@if (0)
|
||||
<div class="rating-wrap d-flex">
|
||||
<div class="rating">
|
||||
@for ($i = 0; $i < 5; $i++)
|
||||
<i class="iconfont"></i>
|
||||
@endfor
|
||||
<div class="rating-wrap d-flex">
|
||||
<div class="rating">
|
||||
@for ($i = 0; $i < 5; $i++)
|
||||
<i class="iconfont"></i>
|
||||
@endfor
|
||||
</div>
|
||||
<span class="text-muted">132 reviews</span>
|
||||
</div>
|
||||
<span class="text-muted">132 reviews</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
|
|
@ -160,15 +162,21 @@
|
|||
justify-content: space-between;
|
||||
width: 500px;">
|
||||
<div class="variable-info-select-num-show">
|
||||
<div
|
||||
@click="checkedVariableValue(variable_index, value_index, value)"
|
||||
:key="value_index">
|
||||
<span class="image" v-if="value.image"><img :src="value.image" class="img-fluid"></span>
|
||||
@{{ value.name }}
|
||||
</div>
|
||||
<div
|
||||
@click="checkedVariableValue(variable_index, value_index, value)"
|
||||
:key="value_index">
|
||||
<span class="image" v-if="value.image"><img :src="value.image" class="img-fluid"></span>
|
||||
@{{ value.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="quantity-wrap">
|
||||
<input type="text" @change="quantityChange" class="form-control" :disabled="!product.quantity" onkeyup="this.value=this.value.replace(/\D/g,'')" v-model="value.quantity" value="0" :name="'variables['+ variable_index +'].value['+value_index+'].quantity'">
|
||||
<input type="text" @change="quantityChange"
|
||||
class="form-control"
|
||||
:disabled="!product.quantity"
|
||||
onkeyup="this.value=this.value.replace(/\D/g,'')"
|
||||
v-model="value.quantity"
|
||||
value="0"
|
||||
:name="'variables['+ variable_index +'].value['+value_index+'].quantity'">
|
||||
<div class="right">
|
||||
<i class="bi bi-chevron-up" @click="quantityChange"></i>
|
||||
<i class="bi bi-chevron-down" @click="quantityChange"></i>
|
||||
|
|
@ -198,7 +206,7 @@
|
|||
:product-price="product.price"
|
||||
:disabled="!product.quantity"
|
||||
@click="addCart(false, this)"
|
||||
><i class="bi bi-cart-fill me-1"></i>{{ __('shop/products.add_to_cart') }}
|
||||
><i class="bi bi-cart-fill me-1"></i>{{ __('shop/products.add_to_cart') }}
|
||||
</button>
|
||||
@endhookwrapper
|
||||
@hookwrapper('product.detail.buy_now')
|
||||
|
|
@ -208,7 +216,7 @@
|
|||
:product-id="product.id"
|
||||
:product-price="product.price"
|
||||
@click="addCart(true, this)"
|
||||
><i class="bi bi-bag-fill me-1"></i>{{ __('shop/products.buy_now') }}
|
||||
><i class="bi bi-bag-fill me-1"></i>{{ __('shop/products.buy_now') }}
|
||||
</button>
|
||||
@endhookwrapper
|
||||
@hook('product.detail.buy.after')
|
||||
|
|
@ -224,7 +232,7 @@
|
|||
@endhookwrapper
|
||||
@endif
|
||||
@else
|
||||
{{-- <div class="text-danger"><i class="bi bi-exclamation-circle-fill"></i> {{ __('product.has_been_inactive') }}</div>--}}
|
||||
{{-- <div class="text-danger"><i class="bi bi-exclamation-circle-fill"></i> {{ __('product.has_been_inactive') }}</div>--}}
|
||||
<div class="quantity-btns">
|
||||
@hook('product.detail.buy.before')
|
||||
@hookwrapper('product.detail.quantity.input')
|
||||
|
|
@ -249,9 +257,9 @@
|
|||
</div>
|
||||
@endif
|
||||
<ul class="totals">
|
||||
<li><span>Product Total</span><span>@{{ product_total }}</span></li>
|
||||
<li><span>Shipping Fee</span><span>@{{ shipping_fee }}</span></li>
|
||||
<li><span>Order Total</span><span>@{{ order_tota }}</span></li>
|
||||
<li><span>Product Total</span><span>@{{ product_total }}</span></li>
|
||||
<li><span>Shipping Fee</span><span>@{{ shipping_fee }}</span></li>
|
||||
<li><span>Order Total</span><span>@{{ order_tota }}</span></li>
|
||||
</ul>
|
||||
<button
|
||||
style="width: 16em;"
|
||||
|
|
@ -269,34 +277,34 @@
|
|||
display: flex;">
|
||||
<div class="left" style="
|
||||
flex: 4;">
|
||||
<el-form :model="registerForm" ref="registerForm" label-width="90px" :rules="rules">
|
||||
<!-- 弹出层歌手名列 -->
|
||||
<el-form-item prop="contacts" label="Contacts" size="mini">
|
||||
<el-input v-model="registerForm.contacts" placeholder="Contacts"></el-input>
|
||||
</el-form-item>
|
||||
<!-- 弹出层歌手性别列 -->
|
||||
{{-- <el-form-item prop="sex" label="歌手性别" size="mini">--}}
|
||||
{{-- <el-radio-group v-model="registerForm.sex">--}}
|
||||
{{-- <el-radio :label="0">女</el-radio>--}}
|
||||
{{-- <el-radio :label="1">男</el-radio>--}}
|
||||
{{-- <el-radio :label="2">组合</el-radio>--}}
|
||||
{{-- <el-radio :label="3">不明</el-radio>--}}
|
||||
{{-- </el-radio-group>--}}
|
||||
{{-- </el-form-item>--}}
|
||||
<!-- <el-form-item prop="pic" label="歌手头像" size="mini">
|
||||
<el-form :model="registerForm" ref="registerForm" label-width="90px" :rules="rules">
|
||||
<!-- 弹出层歌手名列 -->
|
||||
<el-form-item prop="contacts" label="Contacts" size="mini">
|
||||
<el-input v-model="registerForm.contacts" placeholder="Contacts"></el-input>
|
||||
</el-form-item>
|
||||
<!-- 弹出层歌手性别列 -->
|
||||
{{-- <el-form-item prop="sex" label="歌手性别" size="mini">--}}
|
||||
{{-- <el-radio-group v-model="registerForm.sex">--}}
|
||||
{{-- <el-radio :label="0">女</el-radio>--}}
|
||||
{{-- <el-radio :label="1">男</el-radio>--}}
|
||||
{{-- <el-radio :label="2">组合</el-radio>--}}
|
||||
{{-- <el-radio :label="3">不明</el-radio>--}}
|
||||
{{-- </el-radio-group>--}}
|
||||
{{-- </el-form-item>--}}
|
||||
<!-- <el-form-item prop="pic" label="歌手头像" size="mini">
|
||||
<el-input v-model="registerForm.pic" placeholder="歌手头像"></el-input>
|
||||
</el-form-item> -->
|
||||
<!-- 弹出层歌手生日列 -->
|
||||
{{-- <el-form-item prop="birth" label="生日" size="mini">--}}
|
||||
{{-- <el-date-picker type="date" placeholder="选择日期" v-model="registerForm.birth" style="width: 100%;"></el-date-picker>--}}
|
||||
{{-- </el-form-item>--}}
|
||||
<el-form-item prop="email" label="E-mail" size="mini">
|
||||
<el-input v-model="registerForm.email" placeholder="E-mail"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="content" label="Content" size="mini">
|
||||
<el-input v-model="registerForm.content" placeholder="Content" type="textarea" :rows="10" ></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 弹出层歌手生日列 -->
|
||||
{{-- <el-form-item prop="birth" label="生日" size="mini">--}}
|
||||
{{-- <el-date-picker type="date" placeholder="选择日期" v-model="registerForm.birth" style="width: 100%;"></el-date-picker>--}}
|
||||
{{-- </el-form-item>--}}
|
||||
<el-form-item prop="email" label="E-mail" size="mini">
|
||||
<el-input v-model="registerForm.email" placeholder="E-mail"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="content" label="Content" size="mini">
|
||||
<el-input v-model="registerForm.content" placeholder="Content" type="textarea" :rows="10"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
||||
@hook('product.detail.after')
|
||||
|
|
@ -331,9 +339,9 @@
|
|||
{{ __('shop/products.product_details') }}
|
||||
</a>
|
||||
@if ($product['attributes'])
|
||||
<a class="nav-link fw-bold fs-5" data-bs-toggle="tab" href="#product-attributes">
|
||||
{{ __('admin/attribute.index') }}
|
||||
</a>
|
||||
<a class="nav-link fw-bold fs-5" data-bs-toggle="tab" href="#product-attributes">
|
||||
{{ __('admin/attribute.index') }}
|
||||
</a>
|
||||
@endif
|
||||
@hook('product.tab.after.link')
|
||||
</div>
|
||||
|
|
@ -345,15 +353,17 @@
|
|||
<table class="table table-bordered attribute-table">
|
||||
@foreach ($product['attributes'] as $group)
|
||||
<thead class="table-light">
|
||||
<tr><td colspan="2"><strong>{{ $group['attribute_group_name'] }}</strong></td></tr>
|
||||
<tr>
|
||||
<td colspan="2"><strong>{{ $group['attribute_group_name'] }}</strong></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($group['attributes'] as $item)
|
||||
@foreach ($group['attributes'] as $item)
|
||||
<tr>
|
||||
<td>{{ $item['attribute'] }}</td>
|
||||
<td>{{ $item['attribute_value'] }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endforeach
|
||||
</tbody>
|
||||
@endforeach
|
||||
</table>
|
||||
|
|
@ -371,9 +381,9 @@
|
|||
<div class="swiper relations-swiper">
|
||||
<div class="swiper-wrapper">
|
||||
@foreach ($relations as $item)
|
||||
<div class="swiper-slide">
|
||||
@include('shared.product', ['product' => $item])
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
@include('shared.product', ['product' => $item])
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -397,10 +407,10 @@
|
|||
el: '#product-app',
|
||||
|
||||
data: {
|
||||
product_total:0,
|
||||
shipping_fee:0,
|
||||
order_tota:0,
|
||||
isNumSelect:false,
|
||||
product_total: 0,
|
||||
shipping_fee: 0,
|
||||
order_tota: 0,
|
||||
isNumSelect: false,
|
||||
selectedVariantsIndex: [], // 选中的变量索引
|
||||
images: [],
|
||||
product: {
|
||||
|
|
@ -422,58 +432,62 @@
|
|||
},
|
||||
price_setting: @json($product['price_setting'] ?? 'sku'),
|
||||
numPrices: @json($product['numPrices'] ?? []),
|
||||
centerDialogVisable:false, // 设置显示框的状态
|
||||
registerForm:{ // 添加的信息
|
||||
contacts:'',
|
||||
email:'',
|
||||
content:'',
|
||||
product_sku_id:'',
|
||||
centerDialogVisable: false, // 设置显示框的状态
|
||||
registerForm: { // 添加的信息
|
||||
contacts: '',
|
||||
email: '',
|
||||
content: '',
|
||||
product_sku_id: '',
|
||||
},
|
||||
rules: {
|
||||
contacts: [{
|
||||
required: true,
|
||||
message: '{{ __('shop/products.enter_contacts') }}',
|
||||
trigger: 'blur'
|
||||
}, ],
|
||||
},],
|
||||
email: [{
|
||||
required: true,
|
||||
type: 'email',
|
||||
message: '{{ __('shop/products.enter_email') }}',
|
||||
trigger: 'blur'
|
||||
}, ],
|
||||
},],
|
||||
content: [{
|
||||
required: true,
|
||||
message: '{{ __('shop/products.enter_content') }}',
|
||||
trigger: 'blur'
|
||||
}, ],
|
||||
},],
|
||||
},
|
||||
},
|
||||
|
||||
watch:{
|
||||
quantity: function(newval,oldval){
|
||||
watch: {
|
||||
quantity: function (newval, oldval) {
|
||||
|
||||
console.log("数量改变");
|
||||
|
||||
let price = 0;
|
||||
if(this.numPrices.light == 0){
|
||||
if (this.numPrices.light == 0) {
|
||||
price = this.product.price
|
||||
}else {
|
||||
} else {
|
||||
price = this.numPrices[0].price
|
||||
this.numPrices.forEach(v => {
|
||||
if(this.quantity > v.num){}
|
||||
if (this.quantity > v.num) {
|
||||
}
|
||||
price = v.price
|
||||
})
|
||||
}
|
||||
|
||||
this.product_total = (price * this.quantity).toFixed(2)
|
||||
this.shipping_fee = (this.product_total * 0.1 ).toFixed(2)
|
||||
this.order_tota = (this.product_total *1 + this.shipping_fee*1).toFixed(2)
|
||||
this.shipping_fee = (this.product_total * 0.1).toFixed(2)
|
||||
this.order_tota = (this.product_total * 1 + this.shipping_fee * 1).toFixed(2)
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if(this.price_setting === 'num'){
|
||||
if (this.price_setting === 'num') {
|
||||
// this.quantity = this.numPrices[0].num;
|
||||
}
|
||||
this.source.variables.forEach(variable => {
|
||||
if(variable.isNumSelect == true){
|
||||
if (variable.isNumSelect == true) {
|
||||
this.isNumSelect = true;
|
||||
}
|
||||
variable.values.forEach(value => {
|
||||
|
|
@ -482,7 +496,7 @@
|
|||
})
|
||||
},
|
||||
|
||||
beforeMount () {
|
||||
beforeMount() {
|
||||
const skus = JSON.parse(JSON.stringify(this.source.skus));
|
||||
const skuDefault = skus.find(e => e.is_default)
|
||||
this.selectedVariantsIndex = skuDefault.variants
|
||||
|
|
@ -507,8 +521,8 @@
|
|||
},
|
||||
|
||||
methods: {
|
||||
quantityChange(){
|
||||
setTimeout(()=>{
|
||||
quantityChange() {
|
||||
setTimeout(() => {
|
||||
|
||||
let num = 0;
|
||||
this.source.variables.forEach(variable => {
|
||||
|
|
@ -517,10 +531,10 @@
|
|||
})
|
||||
})
|
||||
this.quantity = num;
|
||||
console.log(this.quantity,num)
|
||||
},200);
|
||||
console.log(this.quantity, num)
|
||||
}, 200);
|
||||
},
|
||||
addSinger(form){ // 点击确定按钮添加方法
|
||||
addSinger(form) { // 点击确定按钮添加方法
|
||||
|
||||
this.$refs[form].validate((valid) => {
|
||||
if (!valid) {
|
||||
|
|
@ -531,14 +545,14 @@
|
|||
$http.post(`/inquiry`, this.registerForm).then((res) => {
|
||||
layer.msg('Success')
|
||||
this.registerForm = {
|
||||
contacts:'',
|
||||
email:'',
|
||||
content:'',
|
||||
product_sku_id:'',
|
||||
contacts: '',
|
||||
email: '',
|
||||
content: '',
|
||||
product_sku_id: '',
|
||||
}
|
||||
})
|
||||
|
||||
this.centerDialogVisable=false
|
||||
this.centerDialogVisable = false
|
||||
});
|
||||
},
|
||||
checkedVariableValue(variable_index, value_index, value) {
|
||||
|
|
@ -562,7 +576,8 @@
|
|||
getSelectedSku(reload = true) {
|
||||
// 通过 selectedVariantsIndex 的值比对 skus 的 variables
|
||||
const sku = this.source.skus.find(sku => sku.variants.toString() == this.selectedVariantsIndex.toString())
|
||||
this.images = @json($product['images'] ?? [])
|
||||
this.images =
|
||||
@json($product['images'] ?? [])
|
||||
|
||||
if (reload) {
|
||||
this.images.unshift(...sku.images)
|
||||
|
|
@ -584,8 +599,8 @@
|
|||
},
|
||||
|
||||
addCart(isBuyNow = false) {
|
||||
if(this.price_setting === 'num' && this.quantity < this.numPrices[0].num){
|
||||
layer.msg( '{{ __('shop/products.quantity_error') }}' );
|
||||
if (this.price_setting === 'num' && this.quantity < this.numPrices[0].num) {
|
||||
layer.msg('{{ __('shop/products.quantity_error') }}');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -642,7 +657,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
$(document).on("mouseover", ".product-image #swiper .swiper-slide a", function() {
|
||||
$(document).on("mouseover", ".product-image #swiper .swiper-slide a", function () {
|
||||
$(this).parent().addClass('active').siblings().removeClass('active');
|
||||
$('#zoom').trigger('zoom.destroy');
|
||||
$('#zoom img').attr('src', $(this).attr('data-image'));
|
||||
|
|
@ -653,19 +668,19 @@
|
|||
var swiper = new Swiper("#swiper", {
|
||||
direction: "vertical",
|
||||
slidesPerView: 1,
|
||||
spaceBetween:3,
|
||||
breakpoints:{
|
||||
375:{
|
||||
spaceBetween: 3,
|
||||
breakpoints: {
|
||||
375: {
|
||||
slidesPerView: 3,
|
||||
spaceBetween:3,
|
||||
spaceBetween: 3,
|
||||
},
|
||||
480:{
|
||||
480: {
|
||||
slidesPerView: 4,
|
||||
spaceBetween:27,
|
||||
spaceBetween: 27,
|
||||
},
|
||||
768:{
|
||||
768: {
|
||||
slidesPerView: 6,
|
||||
spaceBetween:3,
|
||||
spaceBetween: 3,
|
||||
},
|
||||
},
|
||||
navigation: {
|
||||
|
|
@ -676,9 +691,9 @@
|
|||
observeParents: true
|
||||
});
|
||||
|
||||
var relationsSwiper = new Swiper ('.relations-swiper', {
|
||||
var relationsSwiper = new Swiper('.relations-swiper', {
|
||||
watchSlidesProgress: true,
|
||||
breakpoints:{
|
||||
breakpoints: {
|
||||
320: {
|
||||
slidesPerView: 2,
|
||||
spaceBetween: 10,
|
||||
|
|
@ -704,13 +719,13 @@
|
|||
|
||||
@if (is_mobile())
|
||||
swiperMobile = new Swiper("#swiper-mobile", {
|
||||
slidesPerView: 1,
|
||||
pagination: {
|
||||
el: ".mobile-pagination",
|
||||
},
|
||||
observer: true,
|
||||
observeParents: true
|
||||
});
|
||||
slidesPerView: 1,
|
||||
pagination: {
|
||||
el: ".mobile-pagination",
|
||||
},
|
||||
observer: true,
|
||||
observeParents: true
|
||||
});
|
||||
@endif
|
||||
|
||||
$(document).ready(function () {
|
||||
|
|
|
|||
|
|
@ -39,4 +39,4 @@ mix.js(`plugins/${themeFileName}/Resources/beike/shop/${themeCode}/js/app.js`, `
|
|||
if (mix.inProduction()) {
|
||||
mix.version();
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue