wip
This commit is contained in:
parent
faf3d09084
commit
db2ebdb8da
|
|
@ -6,6 +6,7 @@ use Beike\Admin\Http\Resources\ProductResource;
|
|||
use Beike\Admin\Repositories\CategoryRepo;
|
||||
use Beike\Models\Product;
|
||||
use Beike\Admin\Services\ProductService;
|
||||
use Beike\Repositories\LanguageRepo;
|
||||
use Beike\Repositories\ProductRepo;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
|
|
@ -73,6 +74,7 @@ class ProductController extends Controller
|
|||
'product' => $product,
|
||||
'descriptions' => $descriptions ?? [],
|
||||
'category_ids' => $categoryIds ?? [],
|
||||
'languages' => LanguageRepo::all(),
|
||||
'source' => [
|
||||
'categories' => CategoryRepo::flatten(locale()),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class ProductController extends Controller
|
|||
$data = [
|
||||
'product' => (new ProductDetail($product))->jsonSerialize(),
|
||||
];
|
||||
dd($data);
|
||||
|
||||
return view('product', $data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,17 @@ body {
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
.file-manager-box .layui-layer-title {
|
||||
background-color: #293042;
|
||||
color: #fff;
|
||||
border-color: #404e72;
|
||||
}
|
||||
.file-manager-box .layui-layer-ico {
|
||||
background: url("/image/close.png") no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
transition: margin-left 0.25s ease-in-out, left 0.25s ease-in-out, margin-right 0.25s ease-in-out, right 0.25s ease-in-out;
|
||||
|
|
@ -537,3 +548,129 @@ body.page-login .btn:not(.btn-link):hover {
|
|||
transform: scale(1.02);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body.page-product-form .variants-producr-img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #eee;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
body.page-product-form .variant-value-img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
body.page-product-form .selectable-variants div[id^=selectable-variant-] {
|
||||
border: 1px solid #eee;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
body.page-product-form .selectable-variants .title {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
background: #f5f5f5;
|
||||
justify-content: space-between;
|
||||
}
|
||||
body.page-product-form .selectable-variants .title:hover .btn-link {
|
||||
display: block;
|
||||
}
|
||||
body.page-product-form .selectable-variants .title > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
body.page-product-form .selectable-variants .title b {
|
||||
border-right: 1px solid #f4f4f4;
|
||||
padding-right: 10px;
|
||||
}
|
||||
body.page-product-form .selectable-variants .title .btn-link {
|
||||
padding: 3px 12px;
|
||||
display: none;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap {
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div {
|
||||
border: 1px solid #eee;
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
padding: 4px 6px;
|
||||
cursor: pointer;
|
||||
border-radius: 2px;
|
||||
align-items: center;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div:active {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .value-img {
|
||||
line-height: 1;
|
||||
margin-right: 3px;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .value-img a {
|
||||
width: 26px;
|
||||
display: flex;
|
||||
height: 26px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div:hover {
|
||||
border-color: #fd560f;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div:hover .btn-remove {
|
||||
display: block;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .btn-remove {
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
right: -7px;
|
||||
cursor: pointer;
|
||||
font-size: 17px;
|
||||
display: none;
|
||||
background: #fff;
|
||||
line-height: 1;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .btn-remove:hover {
|
||||
color: #d80000;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .tools {
|
||||
background: #fd560f;
|
||||
top: -24px;
|
||||
right: -31px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .tools .btn-link {
|
||||
min-width: 27px;
|
||||
text-align: center;
|
||||
float: left;
|
||||
padding: 0;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
height: 30px;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .tools .btn-link:hover {
|
||||
background: #be3a02;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .tools .btn-link.rank {
|
||||
cursor: move;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .name {
|
||||
text-align: center;
|
||||
min-width: 40px;
|
||||
}
|
||||
body.page-product-form .selectable-variants .variants-wrap > div .name + .btn-link {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12301,7 +12301,7 @@ textarea.form-control-lg {
|
|||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 1rem;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
border-bottom: 1px solid #f3f3f3;
|
||||
border-top-left-radius: calc(0.3rem - 1px);
|
||||
border-top-right-radius: calc(0.3rem - 1px);
|
||||
}
|
||||
|
|
@ -12328,7 +12328,7 @@ textarea.form-control-lg {
|
|||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: 0.75rem;
|
||||
border-top: 1px solid #dee2e6;
|
||||
border-top: 1px solid #f3f3f3;
|
||||
border-bottom-right-radius: calc(0.3rem - 1px);
|
||||
border-bottom-left-radius: calc(0.3rem - 1px);
|
||||
}
|
||||
|
|
@ -13586,7 +13586,7 @@ textarea.form-control-lg {
|
|||
}
|
||||
|
||||
.border {
|
||||
border: 1px solid #dee2e6 !important;
|
||||
border: 1px solid #f3f3f3 !important;
|
||||
}
|
||||
|
||||
.border-0 {
|
||||
|
|
@ -13594,7 +13594,7 @@ textarea.form-control-lg {
|
|||
}
|
||||
|
||||
.border-top {
|
||||
border-top: 1px solid #dee2e6 !important;
|
||||
border-top: 1px solid #f3f3f3 !important;
|
||||
}
|
||||
|
||||
.border-top-0 {
|
||||
|
|
@ -13602,7 +13602,7 @@ textarea.form-control-lg {
|
|||
}
|
||||
|
||||
.border-end {
|
||||
border-right: 1px solid #dee2e6 !important;
|
||||
border-right: 1px solid #f3f3f3 !important;
|
||||
}
|
||||
|
||||
.border-end-0 {
|
||||
|
|
@ -13610,7 +13610,7 @@ textarea.form-control-lg {
|
|||
}
|
||||
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid #dee2e6 !important;
|
||||
border-bottom: 1px solid #f3f3f3 !important;
|
||||
}
|
||||
|
||||
.border-bottom-0 {
|
||||
|
|
@ -13618,7 +13618,7 @@ textarea.form-control-lg {
|
|||
}
|
||||
|
||||
.border-start {
|
||||
border-left: 1px solid #dee2e6 !important;
|
||||
border-left: 1px solid #f3f3f3 !important;
|
||||
}
|
||||
|
||||
.border-start-0 {
|
||||
|
|
|
|||
|
|
@ -2065,6 +2065,29 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/* harmony import */ var _js_http__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../js/http */ "./resources/js/http.js");
|
||||
|
||||
window.$http = _js_http__WEBPACK_IMPORTED_MODULE_0__["default"];
|
||||
var base = document.querySelector('base').href;
|
||||
$(document).on('click', '.open-file-manager', function (event) {
|
||||
var $this = $(this);
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '图片管理器',
|
||||
shadeClose: false,
|
||||
skin: 'file-manager-box',
|
||||
scrollbar: false,
|
||||
shade: 0.4,
|
||||
area: ['1060px', '680px'],
|
||||
content: "".concat(base, "/file_manager"),
|
||||
success: function success(layerInstance, index) {
|
||||
var iframeWindow = window[layerInstance.find("iframe")[0]["name"]];
|
||||
|
||||
iframeWindow.callback = function (images) {
|
||||
$this.find('img').prop('src', images[0].url);
|
||||
$this.next('input').val(images[0].path);
|
||||
$this.next('input')[0].dispatchEvent(new Event('input'));
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
$(document).ready(function ($) {
|
||||
$.ajaxSetup({
|
||||
headers: {
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 7.7 KiB |
|
|
@ -27,6 +27,20 @@ body {
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
.file-manager-box {
|
||||
.layui-layer-title {
|
||||
background-color: #293042;
|
||||
color: #fff;
|
||||
border-color: #404e72;
|
||||
}
|
||||
|
||||
.layui-layer-ico {
|
||||
background: url('/image/close.png') no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
}
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
// flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,167 @@
|
|||
@charset "UTF-8";
|
||||
|
||||
body.page-product-form {
|
||||
.variants-producr-img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #eee;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center; // flex-start | center
|
||||
justify-content: center; // flex-end | center | space-between
|
||||
}
|
||||
|
||||
.variant-value-img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center; // flex-start | center
|
||||
justify-content: center; // flex-end | center | space-between
|
||||
}
|
||||
|
||||
.selectable-variants {
|
||||
div[id^="selectable-variant-"] {
|
||||
border: 1px solid #eee;
|
||||
// padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
background: #f5f5f5;
|
||||
justify-content: space-between;
|
||||
&:hover {
|
||||
.btn-link {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
b {
|
||||
border-right: 1px solid #f4f4f4;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
padding: 3px 12px;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.variants-wrap {
|
||||
// overflow: hidden;
|
||||
padding: 0 10px;
|
||||
// display: flex;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
> div {
|
||||
border: 1px solid #eee;
|
||||
// padding: 3px 8px;
|
||||
margin-right: 10px;
|
||||
// float: left;
|
||||
display: flex;
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
padding: 4px 6px;
|
||||
cursor: pointer;
|
||||
border-radius: 2px;
|
||||
align-items: center;
|
||||
&:active {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.value-img {
|
||||
line-height: 1;
|
||||
// padding: 2px;
|
||||
margin-right: 3px;
|
||||
|
||||
a {
|
||||
width: 26px;
|
||||
display: flex;
|
||||
height: 26px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: $primary;
|
||||
|
||||
.tools {
|
||||
// display: block;
|
||||
}
|
||||
.btn-remove {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-remove {
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
right: -7px;
|
||||
cursor: pointer;
|
||||
font-size: 17px;
|
||||
display: none;
|
||||
background: #fff;
|
||||
line-height: 1;
|
||||
&:hover {
|
||||
color: #d80000;
|
||||
}
|
||||
}
|
||||
|
||||
.tools {
|
||||
// position: absolute;
|
||||
background: $primary;
|
||||
top: -24px;
|
||||
right: -31px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
// z-index: -1;
|
||||
// opacity: 0;
|
||||
|
||||
.btn-link {
|
||||
min-width: 27px;
|
||||
text-align: center;
|
||||
float: left;
|
||||
padding: 0;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
// display: none;
|
||||
color: #fff;
|
||||
height: 30px;
|
||||
&:hover {
|
||||
background: darken($primary, 15%);
|
||||
}
|
||||
|
||||
&.rank {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
// border-right: 1px solid #eee;
|
||||
text-align: center;
|
||||
// padding: 0 5px 0 0;
|
||||
min-width: 40px;
|
||||
|
||||
& +.btn-link {
|
||||
padding-left: 5px;
|
||||
// margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,3 +21,4 @@ $primary: #fd560f;
|
|||
@import 'form';
|
||||
@import 'element-ui';
|
||||
@import 'login';
|
||||
@import 'page-product';
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ $form-floating-padding-y: .8rem;
|
|||
$form-floating-height: 50px;
|
||||
$btn-focus-width: 0;
|
||||
$table-border-color: #e9ecef;
|
||||
$border-color: #f3f3f3;
|
||||
|
||||
@import './bootstrap-icons';
|
||||
@import 'node_modules/bootstrap-5.1.3/scss/bootstrap';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,30 @@
|
|||
import http from "../../../js/http";
|
||||
window.$http = http;
|
||||
const base = document.querySelector('base').href;
|
||||
|
||||
$(document).on('click', '.open-file-manager', function(event) {
|
||||
const $this = $(this);
|
||||
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '图片管理器',
|
||||
shadeClose: false,
|
||||
skin: 'file-manager-box',
|
||||
scrollbar: false,
|
||||
shade: 0.4,
|
||||
area: ['1060px', '680px'],
|
||||
content: `${base}/file_manager`,
|
||||
success: function(layerInstance, index) {
|
||||
var iframeWindow = window[layerInstance.find("iframe")[0]["name"]];
|
||||
iframeWindow.callback = function(images) {
|
||||
$this.find('img').prop('src', images[0].url);
|
||||
$this.next('input').val(images[0].path)
|
||||
$this.next('input')[0].dispatchEvent(new Event('input'));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$(document).ready(function ($) {
|
||||
$.ajaxSetup({
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<script src="{{ asset('vendor/axios/0.21.1/axios.min.js') }}"></script>
|
||||
<script src="{{ mix('build/js/app.js') }}"></script> --}}
|
||||
{{-- <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.8/index.min.js"></script> --}}
|
||||
|
||||
<script src="{{ asset('vendor/bootstrap/5.1.3/js/bootstrap.bundle.min.js') }}"></script>
|
||||
<link href="{{ mix('/build/beike/admin/css/bootstrap.css') }}" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/2.6.2/css.css') }}">
|
||||
<link href="{{ mix('build/beike/admin/css/app.css') }}" rel="stylesheet">
|
||||
|
|
|
|||
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
@section('title', '分类管理')
|
||||
|
||||
@push('header')
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.min.js"></script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div id="app">
|
||||
<el-card class="box-card">
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
@extends('admin::layouts.master')
|
||||
|
||||
@section('body-class', 'page-product-form')
|
||||
|
||||
@push('header')
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js"></script>
|
||||
<script src="{{ asset('vendor/vue/Sortable.min.js') }}"></script>
|
||||
<script src="{{ asset('vendor/vue/vuedraggable.js') }}"></script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
{{-- <div class="card-header"><h6 class="card-title">基础信息</h6></div> --}}
|
||||
<div class="card-body">
|
||||
<h2>product</h2>
|
||||
<h5 class="border-bottom pb-3 mb-4">基础信息</h5>
|
||||
<form action="{{ $product->id ? admin_route('products.update', $product) : admin_route('products.store') }}"
|
||||
method="POST" id="app">
|
||||
@csrf
|
||||
|
|
@ -37,118 +41,218 @@
|
|||
</x-admin::form.row>
|
||||
|
||||
<div>
|
||||
<h2>skus</h2>
|
||||
<input type="radio" v-model="editing.isVariable" :value="false"> 单规格
|
||||
<input type="radio" v-model="editing.isVariable" :value="true"> 多规格
|
||||
<div v-if="editing.isVariable">
|
||||
<div>
|
||||
<div v-for="(variant, variantIndex) in source.variables">
|
||||
<div>
|
||||
<input type="text" v-model="variant.name" placeholder="variant name">
|
||||
<h5 class="border-bottom pb-3 mb-4">商品库存</h5>
|
||||
|
||||
<div v-for="(value, valueIndex) in variant.values">
|
||||
<input v-model="variant.values[valueIndex].name" type="text" placeholder="variant value name">
|
||||
</div>
|
||||
<button type="button" @click="addVariantValue(variantIndex)">Add value</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row align-items-center">
|
||||
<label for="" class="col-sm-2 col-form-label">启用多规格</label>
|
||||
<div class="col-sm-10">
|
||||
<el-switch v-model="editing.isVariable"></el-switch>
|
||||
</div>
|
||||
|
||||
<button type="button" @click="addVariant">Add variant</button>
|
||||
</div>
|
||||
|
||||
<div v-if="form.skus.length">
|
||||
<input v-if="form.skus.length" type="hidden" name="variables" :value="JSON.stringify(form.variables)">
|
||||
<table>
|
||||
<thead>
|
||||
<th v-for="(variant, index) in form.variables" :key="'pv-header-' + index">
|
||||
@{{ variant.name || 'No name' }}
|
||||
</th>
|
||||
<th>image</th>
|
||||
<th>model</th>
|
||||
<th>sku</th>
|
||||
<th>price</th>
|
||||
<th>orgin price</th>
|
||||
<th>cost price</th>
|
||||
<th>quantity</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(sku, skuIndex) in form.skus">
|
||||
<template v-for="(variantValueIndex, j) in sku.variants">
|
||||
<td v-if="skuIndex % variantValueRepetitions[j] == 0" :key="'pvv' + skuIndex + '-' + j"
|
||||
:rowspan="variantValueRepetitions[j]">
|
||||
<span>@{{ form.variables[j].values[variantValueIndex].name || 'No name' }}</span>
|
||||
</td>
|
||||
</template>
|
||||
<td>
|
||||
<input type="text" v-model="sku.image" :name="'skus[' + skuIndex + '][image]'"
|
||||
placeholder="image">
|
||||
<input type="hidden" :name="'skus[' + skuIndex + '][is_default]'" :value="skuIndex == 0 ? 1 : 0">
|
||||
<input v-for="(variantValueIndex, j) in sku.variants" type="hidden"
|
||||
:name="'skus[' + skuIndex + '][variants][' + j + ']'" :value="variantValueIndex">
|
||||
</td>
|
||||
<td><input type="text" v-model="sku.model" :name="'skus[' + skuIndex + '][model]'"
|
||||
placeholder="model"></td>
|
||||
<td><input type="text" v-model="sku.sku" :name="'skus[' + skuIndex + '][sku]'" placeholder="sku">
|
||||
</td>
|
||||
<td><input type="text" v-model="sku.price" :name="'skus[' + skuIndex + '][price]'"
|
||||
placeholder="price"></td>
|
||||
<td><input type="text" v-model="sku.origin_price" :name="'skus[' + skuIndex + '][origin_price]'"
|
||||
placeholder="origin_price"></td>
|
||||
<td><input type="text" v-model="sku.cost_price" :name="'skus[' + skuIndex + '][cost_price]'"
|
||||
placeholder="cost_price">
|
||||
</td>
|
||||
<td><input type="text" v-model="sku.quantity" :name="'skus[' + skuIndex + '][quantity]'"
|
||||
placeholder="quantity"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!editing.isVariable">
|
||||
<div>
|
||||
<input type="text" name="skus[0][image]" placeholder="image"
|
||||
value="{{ old('skus.0.image', $product->skus[0]->image ?? '') }}">
|
||||
<input type="text" name="skus[0][model]" placeholder="model"
|
||||
value="{{ old('skus.0.model', $product->skus[0]->model ?? '') }}">
|
||||
<input type="text" name="skus[0][sku]" placeholder="sku"
|
||||
value="{{ old('skus.0.sku', $product->skus[0]->sku ?? '') }}">
|
||||
<input type="text" name="skus[0][price]" placeholder="price"
|
||||
value="{{ old('skus.0.price', $product->skus[0]->price ?? '') }}">
|
||||
<input type="text" name="skus[0][origin_price]" placeholder="origin_price"
|
||||
value="{{ old('skus.0.origin_price', $product->skus[0]->origin_price ?? '') }}">
|
||||
<input type="text" name="skus[0][cost_price]" placeholder="cost_price"
|
||||
value="{{ old('skus.0.cost_price', $product->skus[0]->cost_price ?? '') }}">
|
||||
<input type="text" name="skus[0][quantity]" placeholder="quantity"
|
||||
value="{{ old('skus.0.quantity', $product->skus[0]->quantity ?? '') }}">
|
||||
<input type="hidden" name="skus[0][variants]" placeholder="variants" value="">
|
||||
<input type="hidden" name="skus[0][position]" placeholder="position" value="0">
|
||||
<input type="hidden" name="skus[0][is_default]" placeholder="is_default" value="1">
|
||||
<div class="form-group">
|
||||
<div class="row align-items-center">
|
||||
<label for="" class="col-sm-2 col-form-label"></label>
|
||||
<div class="col-sm-10">
|
||||
<div v-if="editing.isVariable" class="selectable-variants">
|
||||
<div>
|
||||
<div v-for="(variant, variantIndex) in source.variables" :id="'selectable-variant-' + variantIndex">
|
||||
<div class="title">
|
||||
<div>
|
||||
<b>@{{ variant.name[current_language_code] }}</b>
|
||||
<el-link type="primary" @click="modalVariantOpenButtonClicked(variantIndex, null)">编辑</el-link>
|
||||
<el-link type="danger" class="ms-2" @click="removeSourceVariant(variantIndex)">移除</el-link>
|
||||
</div>
|
||||
<div>
|
||||
<el-checkbox v-model="variant.isImage" border size="mini" class="me-2 bg-white">添加规格图片</el-checkbox>
|
||||
<el-button type="primary" plain size="mini" @click="modalVariantOpenButtonClicked(variantIndex, -1)">Add value</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<draggable
|
||||
element="div"
|
||||
v-if="variant.values.length"
|
||||
class="variants-wrap"
|
||||
@end="(e) => {swapSourceVariantValue(e, variantIndex)}"
|
||||
ghost-class="dragabble-ghost"
|
||||
:list="variant.values"
|
||||
:options="{animation: 100}"
|
||||
>
|
||||
<div v-for="(value, value_index) in variant.values" :key="value_index" class="variants-item" @dblclick="modalVariantOpenButtonClicked(variantIndex, value_index)">
|
||||
{{-- <div class="value-img" v-if="variant.isImage"> --}}
|
||||
{{-- <a href="" :id="'value-img-' + i + '-' + value_index" data-toggle="image" data-no-preview> --}}
|
||||
{{-- <img :src="thumbnail(value.image)" class="img-responsive" /> --}}
|
||||
{{-- </a> --}}
|
||||
{{-- </div> --}}
|
||||
|
||||
<div class="open-file-manager variant-value-img" v-if="variant.isImage">
|
||||
<div>
|
||||
<img :src="thumbnail(value.image)" class="img-fluid">
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" v-model="value.image">
|
||||
|
||||
<div class="btn-remove" @click="removeSourceVariantValue(variantIndex, value_index)"><i class="el-icon-error"></i></div>
|
||||
<div class="name">
|
||||
@{{ value.name[current_language_code] }}
|
||||
</div>
|
||||
</div>
|
||||
</draggable>
|
||||
<div v-else>
|
||||
<div class="p-2" @click="addVariantValue(variantIndex)">请添加 Value</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-button type="primary" size="small" @click="modalVariantOpenButtonClicked(-1, null)" class="btn btn-xs mr-1 mb-1">Add variant</el-button>
|
||||
</div>
|
||||
|
||||
<div v-if="form.skus.length" class="mt-3">
|
||||
<input v-if="form.skus.length" type="hidden" name="variables" :value="JSON.stringify(form.variables)">
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead>
|
||||
<th v-for="(variant, index) in form.variables" :key="'pv-header-' + index">
|
||||
@{{ variant.name[current_language_code] || 'No name' }}
|
||||
</th>
|
||||
<th>image</th>
|
||||
<th>model</th>
|
||||
<th>sku</th>
|
||||
<th>price</th>
|
||||
<th>orgin price</th>
|
||||
<th>cost price</th>
|
||||
<th>quantity</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(sku, skuIndex) in form.skus" :key="skuIndex">
|
||||
<template v-for="(variantValueIndex, j) in sku.variants">
|
||||
<td v-if="skuIndex % variantValueRepetitions[j] == 0" :key="'pvv' + skuIndex + '-' + j"
|
||||
:rowspan="variantValueRepetitions[j]">
|
||||
<span>@{{ form.variables[j].values[variantValueIndex].name[current_language_code] || 'No name' }}</span>
|
||||
</td>
|
||||
</template>
|
||||
<td>
|
||||
<div class="open-file-manager variants-producr-img">
|
||||
<div>
|
||||
<img :src="thumbnail(sku.image)" class="img-fluid">
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" class="form-control" v-model="sku.image" :name="'skus[' + skuIndex + '][image]'"
|
||||
placeholder="image">
|
||||
|
||||
<input type="hidden" class="form-control" :name="'skus[' + skuIndex + '][is_default]'" :value="skuIndex == 0 ? 1 : 0">
|
||||
<input v-for="(variantValueIndex, j) in sku.variants" type="hidden"
|
||||
:name="'skus[' + skuIndex + '][variants][' + j + ']'" :value="variantValueIndex">
|
||||
</td>
|
||||
<td><input type="text" class="form-control" v-model="sku.model" :name="'skus[' + skuIndex + '][model]'"
|
||||
placeholder="model"></td>
|
||||
<td><input type="text" class="form-control" v-model="sku.sku" :name="'skus[' + skuIndex + '][sku]'" placeholder="sku">
|
||||
</td>
|
||||
<td><input type="text" class="form-control" v-model="sku.price" :name="'skus[' + skuIndex + '][price]'"
|
||||
placeholder="price"></td>
|
||||
<td><input type="text" class="form-control" v-model="sku.origin_price" :name="'skus[' + skuIndex + '][origin_price]'"
|
||||
placeholder="origin_price"></td>
|
||||
<td><input type="text" class="form-control" v-model="sku.cost_price" :name="'skus[' + skuIndex + '][cost_price]'"
|
||||
placeholder="cost_price">
|
||||
</td>
|
||||
<td><input type="text" class="form-control" v-model="sku.quantity" :name="'skus[' + skuIndex + '][quantity]'"
|
||||
placeholder="quantity"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!editing.isVariable">
|
||||
<div>
|
||||
<input type="text" name="skus[0][image]" placeholder="image"
|
||||
value="{{ old('skus.0.image', $product->skus[0]->image ?? '') }}">
|
||||
<input type="text" name="skus[0][model]" placeholder="model"
|
||||
value="{{ old('skus.0.model', $product->skus[0]->model ?? '') }}">
|
||||
<input type="text" name="skus[0][sku]" placeholder="sku"
|
||||
value="{{ old('skus.0.sku', $product->skus[0]->sku ?? '') }}">
|
||||
<input type="text" name="skus[0][price]" placeholder="price"
|
||||
value="{{ old('skus.0.price', $product->skus[0]->price ?? '') }}">
|
||||
<input type="text" name="skus[0][origin_price]" placeholder="origin_price"
|
||||
value="{{ old('skus.0.origin_price', $product->skus[0]->origin_price ?? '') }}">
|
||||
<input type="text" name="skus[0][cost_price]" placeholder="cost_price"
|
||||
value="{{ old('skus.0.cost_price', $product->skus[0]->cost_price ?? '') }}">
|
||||
<input type="text" name="skus[0][quantity]" placeholder="quantity"
|
||||
value="{{ old('skus.0.quantity', $product->skus[0]->quantity ?? '') }}">
|
||||
<input type="hidden" name="skus[0][variants]" placeholder="variants" value="">
|
||||
<input type="hidden" name="skus[0][position]" placeholder="position" value="0">
|
||||
<input type="hidden" name="skus[0][is_default]" placeholder="is_default" value="1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
|
||||
<el-dialog
|
||||
title="编辑"
|
||||
:visible.sync="dialogVariables.show"
|
||||
width="400"
|
||||
@close="closedialogVariablesFormDialog('form')"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form ref="form" :rules="rules" :model="dialogVariables.form" label-width="100px">
|
||||
<el-form-item label="名称" required class="language-inputs">
|
||||
<el-form-item :prop="'name.' + lang.code" :inline-message="true" v-for="lang, lang_i in source.languages" :key="lang_i"
|
||||
:rules="[
|
||||
{ required: true, message: '输入框不能为空', trigger: 'blur' },
|
||||
]"
|
||||
>
|
||||
<el-input size="mini" v-model="dialogVariables.form.name[lang.code]" placeholder="请填写名称"><template slot="prepend">@{{lang.name}}</template></el-input>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="dialogVariablesFormSubmit('form')">保存</el-button>
|
||||
<el-button @click="closedialogVariablesFormDialog('form')">取消</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
|
||||
@push('footer')
|
||||
<script>
|
||||
Vue.prototype.thumbnail = function thumbnail(image, width, height) {
|
||||
return '{{ asset('catalog') }}' + image;
|
||||
};
|
||||
|
||||
var app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
current_language_code: '{{ current_language_code() }}',
|
||||
form: {
|
||||
variables: @json($product->variables ?? []),
|
||||
skus: @json($product->skus ?? []),
|
||||
},
|
||||
source: {
|
||||
variables: @json($product->variables ?? []),
|
||||
languages: @json($languages ?? []),
|
||||
},
|
||||
|
||||
editing: {
|
||||
isVariable: @json(($product->variables ?? null) != null),
|
||||
}
|
||||
},
|
||||
|
||||
dialogVariables: {
|
||||
show: false,
|
||||
variantIndex: null,
|
||||
variantValueIndex: null,
|
||||
form: {
|
||||
name: {}
|
||||
},
|
||||
},
|
||||
|
||||
rules: {}
|
||||
},
|
||||
computed: {
|
||||
// variant value 重复次数
|
||||
|
|
@ -184,18 +288,80 @@
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
addVariant() {
|
||||
this.source.variables.push({
|
||||
name: '',
|
||||
values: []
|
||||
// addVariant() {
|
||||
// this.source.variables.push({
|
||||
// name: '',
|
||||
// values: []
|
||||
// });
|
||||
// },
|
||||
|
||||
dialogVariablesFormSubmit(form) {
|
||||
const name = JSON.parse(JSON.stringify(this.dialogVariables.form.name));
|
||||
const variantIndex = this.dialogVariables.variantIndex;
|
||||
const variantValueIndex = this.dialogVariables.variantValueIndex;
|
||||
|
||||
this.$refs[form].validate((valid) => {
|
||||
if (!valid) {
|
||||
this.$message.error('请检查表单是否填写正确');
|
||||
return;
|
||||
}
|
||||
|
||||
if (variantValueIndex !== null) {
|
||||
if (variantValueIndex == -1) { // 创建
|
||||
this.source.variables[variantIndex].values.push({name, image: ''});
|
||||
} else {
|
||||
this.source.variables[variantIndex].values[variantValueIndex].name = name;
|
||||
}
|
||||
} else {
|
||||
if (variantIndex == -1) { // 创建
|
||||
this.source.variables.push({name, values: [], isImage: false});
|
||||
} else {
|
||||
this.source.variables[variantIndex].name = name;
|
||||
}
|
||||
}
|
||||
|
||||
this.dialogVariables.show = false;
|
||||
});
|
||||
},
|
||||
|
||||
closedialogVariablesFormDialog(form) {
|
||||
this.dialogVariables.show = false;
|
||||
this.dialogVariables.variantIndex = null;
|
||||
this.dialogVariables.variantValueIndex = null;
|
||||
this.dialogVariables.form.name = {};
|
||||
this.$refs[form].clearValidate();
|
||||
},
|
||||
|
||||
modalVariantOpenButtonClicked(variantIndex, variantValueIndex) {
|
||||
this.dialogVariables.variantIndex = variantIndex;
|
||||
this.dialogVariables.variantValueIndex = variantValueIndex;
|
||||
|
||||
let name = null;
|
||||
if (variantIndex === -1 || variantValueIndex === -1) {
|
||||
name = {};
|
||||
} else {
|
||||
if (variantValueIndex !== null) {
|
||||
// 编辑 variant value
|
||||
name = this.source.variables[variantIndex].values[variantValueIndex].name;
|
||||
} else {
|
||||
// 编辑 variant
|
||||
name = this.source.variables[variantIndex].name;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(name)
|
||||
this.dialogVariables.form.name = JSON.parse(JSON.stringify(name));
|
||||
this.dialogVariables.show = true;
|
||||
},
|
||||
|
||||
removeSourceVariant() {
|
||||
|
||||
},
|
||||
|
||||
addVariantValue(variantIndex) {
|
||||
this.source.variables[variantIndex].values.push({
|
||||
name: '',
|
||||
image: ''
|
||||
});
|
||||
this.dialogVariables.show = true;
|
||||
this.dialogVariables.type = 'variant-value';
|
||||
this.dialogVariables.variantIndex = variantIndex;
|
||||
},
|
||||
|
||||
remakeSkus() {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
@section('title', '商品管理')
|
||||
|
||||
@push('header')
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.min.js"></script>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/underscore.js/1.13.3/underscore.min.js"></script>
|
||||
@endpush
|
||||
|
||||
|
|
@ -11,8 +10,6 @@
|
|||
<div id="product-app">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
|
||||
<div class="bg-light p-4">
|
||||
<div class="row">
|
||||
<div class="col-xxl-20 col-xl-3 col-lg-4 col-md-4 d-flex align-items-center mb-3">
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@
|
|||
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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue