后台商品详情多规格批量设置等
This commit is contained in:
parent
ed31084759
commit
8451c0b819
|
|
@ -151,7 +151,11 @@ function type_route($type, $value): string
|
||||||
} elseif ($type == 'static') {
|
} elseif ($type == 'static') {
|
||||||
return shop_route($value);
|
return shop_route($value);
|
||||||
} elseif ($type == 'custom') {
|
} elseif ($type == 'custom') {
|
||||||
return $value;
|
if (Str::startsWith($value, ['http://', 'https://'])) {
|
||||||
|
return $value;
|
||||||
|
} else {
|
||||||
|
return "//{$value}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
|
|
|
||||||
|
|
@ -244,8 +244,8 @@ class ProductRepo
|
||||||
public static function getFilterPrice($data)
|
public static function getFilterPrice($data)
|
||||||
{
|
{
|
||||||
$selectPrice = $data['price'] ?? '-';
|
$selectPrice = $data['price'] ?? '-';
|
||||||
unset($data['price']);
|
// unset($data['price']);
|
||||||
$builder = self::getBuilder($data)->leftJoin('product_skus as ps', 'products.id', 'ps.product_id')
|
$builder = self::getBuilder(['category_id' => $data['category_id']])->leftJoin('product_skus as ps', 'products.id', 'ps.product_id')
|
||||||
->where('ps.is_default', 1);
|
->where('ps.is_default', 1);
|
||||||
$min = $builder->min('ps.price');
|
$min = $builder->min('ps.price');
|
||||||
$max = $builder->max('ps.price');
|
$max = $builder->max('ps.price');
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.max-h-100 {
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.col-form-label.required {
|
.col-form-label.required {
|
||||||
&::before {
|
&::before {
|
||||||
content: "*";
|
content: "*";
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@ body.page-product-form {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.batch-setting {
|
||||||
|
.form-control {
|
||||||
|
max-width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.variant-value-img {
|
.variant-value-img {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@
|
||||||
:list="form.images"
|
:list="form.images"
|
||||||
:options="{animation: 200, handle: '.product-item'}"
|
:options="{animation: 200, handle: '.product-item'}"
|
||||||
>
|
>
|
||||||
<div v-for="image, index in form.images" :key="index" class="wh-80 product-item position-relative me-2 mb-2">
|
<div v-for="image, index in form.images" :key="index" class="wh-80 product-item position-relative me-2 mb-2 border d-flex justify-content-center align-items-center max-h-100 overflow-hidden">
|
||||||
<div class="position-absolute top-0 end-0">
|
<div class="position-absolute top-0 end-0">
|
||||||
<button class="btn btn-danger btn-sm wh-20 p-0" @click="removeImages(index)" type="button"><i class="bi bi-trash"></i></button>
|
<button class="btn btn-danger btn-sm wh-20 p-0" @click="removeImages(index)" type="button"><i class="bi bi-trash"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -168,7 +168,29 @@
|
||||||
<el-button type="primary" plain size="small" @click="modalVariantOpenButtonClicked(-1, null)" class="btn btn-xs mr-1 mb-1">{{ __('admin/product.add_variable') }}</el-button>
|
<el-button type="primary" plain size="small" @click="modalVariantOpenButtonClicked(-1, null)" class="btn btn-xs mr-1 mb-1">{{ __('admin/product.add_variable') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="form.skus.length && form.variables.length" class="mt-3 table-push">
|
<div v-if="form.skus.length && form.variables.length" class="mt-3 table-push table-responsive">
|
||||||
|
<div class="batch-setting d-flex align-items-center mb-3 p-2 bg-body">
|
||||||
|
<div v-for="(variant, index) in form.variables" :key="index" class="me-2">
|
||||||
|
<select class="form-select me-2 bg-white" aria-label="Default select example" v-model="variablesBatch.variables[index]">
|
||||||
|
<option selected value="">@{{ variant.name[current_language_code] || 'No name' }}</option>
|
||||||
|
<option :value="value_index" v-for="value, value_index in variant.values" :key="index+'-'+value_index" >
|
||||||
|
@{{ value.name[current_language_code]}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div role="button" class="border d-flex justify-content-center align-items-center border-dashed bg-light wh-40 me-2 bg-white" @click="batchSettingVariantImage">
|
||||||
|
<img :src="thumbnail(variablesBatch.image)" class="img-fluid" v-if="variablesBatch.image">
|
||||||
|
<i class="bi bi-plus fs-3 text-muted" v-else></i>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-control me-2 bg-white" v-model="variablesBatch.model" placeholder="{{ __('admin/product.model') }}">
|
||||||
|
<input type="text" class="form-control me-2 bg-white" v-model="variablesBatch.sku" placeholder="sku">
|
||||||
|
<input type="number" class="form-control me-2 bg-white" v-model="variablesBatch.price" placeholder="{{ __('admin/product.price') }}">
|
||||||
|
<input type="number" class="form-control me-2 bg-white" v-model="variablesBatch.origin_price" placeholder="{{ __('admin/product.origin_price') }}">
|
||||||
|
<input type="number" class="form-control me-2 bg-white" v-model="variablesBatch.cost_price" placeholder="{{ __('admin/product.cost_price') }}">
|
||||||
|
<input type="number" class="form-control me-2 bg-white" v-model="variablesBatch.quantity" placeholder="{{ __('admin/product.quantity') }}">
|
||||||
|
<button type="button" class="btn btn-primary text-nowrap" @click="batchSettingVariant">{{ __('common.batch_setting') }}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<table class="table table-bordered table-hover">
|
<table class="table table-bordered table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<th v-for="(variant, index) in form.variables" :key="'pv-header-' + index">
|
<th v-for="(variant, index) in form.variables" :key="'pv-header-' + index">
|
||||||
|
|
@ -200,7 +222,7 @@
|
||||||
<input type="hidden" class="form-control" v-model="sku.images[index]" :name="'skus[' + skuIndex + '][images][]'"
|
<input type="hidden" class="form-control" v-model="sku.images[index]" :name="'skus[' + skuIndex + '][images][]'"
|
||||||
placeholder="image">
|
placeholder="image">
|
||||||
</div>
|
</div>
|
||||||
<div class="border d-flex justify-content-center align-items-center border-dashed bg-light wh-40" @click="addProductImages(skuIndex)"><i class="bi bi-plus fs-3 text-muted"></i></div>
|
<div class="border d-flex justify-content-center align-items-center border-dashed bg-light wh-40" role="button" @click="addProductImages(skuIndex)"><i class="bi bi-plus fs-3 text-muted"></i></div>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" class="form-control" :name="'skus[' + skuIndex + '][is_default]'" :value="skuIndex == 0 ? 1 : 0">
|
<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"
|
<input v-for="(variantValueIndex, j) in sku.variants" type="hidden"
|
||||||
|
|
@ -383,7 +405,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<x-admin::form.row title="">
|
<x-admin::form.row title="">
|
||||||
<button type="submit" class="btn btn-primary mt-3 btn-lg">{{ __('common.save') }}</button>
|
<button type="button" @click="productsSubmit" class="btn btn-primary btn-submit mt-3 btn-lg">{{ __('common.save') }}</button>
|
||||||
</x-admin::form.row>
|
</x-admin::form.row>
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
|
|
@ -457,6 +479,18 @@
|
||||||
skus: @json($product->skus ?? []),
|
skus: @json($product->skus ?? []),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
variablesBatch: {
|
||||||
|
variables: [],
|
||||||
|
model: '',
|
||||||
|
sku: '',
|
||||||
|
price: '',
|
||||||
|
origin_price: '',
|
||||||
|
cost_price: '',
|
||||||
|
quantity: '',
|
||||||
|
image: '',
|
||||||
|
status: false,
|
||||||
|
},
|
||||||
|
|
||||||
relations: {
|
relations: {
|
||||||
keyword: '',
|
keyword: '',
|
||||||
products: @json($relations ?? []),
|
products: @json($relations ?? []),
|
||||||
|
|
@ -491,6 +525,7 @@
|
||||||
|
|
||||||
rules: {}
|
rules: {}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
// variant value 重复次数
|
// variant value 重复次数
|
||||||
variantValueRepetitions() {
|
variantValueRepetitions() {
|
||||||
|
|
@ -509,6 +544,13 @@
|
||||||
return (this.form.skus.length && this.form.skus[0].variants.length) || ''
|
return (this.form.skus.length && this.form.skus[0].variants.length) || ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
beforeMount() {
|
||||||
|
if (this.form.variables.length) {
|
||||||
|
this.variablesBatch.variables = this.form.variables.map((v, i) => '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
'source.variables': {
|
'source.variables': {
|
||||||
deep: true,
|
deep: true,
|
||||||
|
|
@ -525,13 +567,27 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.form.variables = variants;
|
this.form.variables = variants;
|
||||||
|
// 在 variablesBatch.variables 生成对应的 variants 的index
|
||||||
|
this.variablesBatch.variables = variants.map((v, i) => '');
|
||||||
|
|
||||||
if (this.isMove) return;
|
if (this.isMove) return;
|
||||||
this.remakeSkus();
|
this.remakeSkus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
// 表单提交,检测是否开启多规格 做处理
|
||||||
|
productsSubmit() {
|
||||||
|
if (!this.editing.isVariable) {
|
||||||
|
this.source.variables = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
$('form#app').submit();
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
|
||||||
relationsQuerySearch(keyword, cb) {
|
relationsQuerySearch(keyword, cb) {
|
||||||
$http.get('products/autocomplete?name=' + encodeURIComponent(keyword), null, {hload:true}).then((res) => {
|
$http.get('products/autocomplete?name=' + encodeURIComponent(keyword), null, {hload:true}).then((res) => {
|
||||||
cb(res.data);
|
cb(res.data);
|
||||||
|
|
@ -550,9 +606,9 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
isVariableChange(e) {
|
isVariableChange(e) {
|
||||||
if (!e) {
|
// if (!e) {
|
||||||
this.source.variables = [];
|
// this.source.variables = [];
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
|
|
||||||
variantIsImage(e, index) {
|
variantIsImage(e, index) {
|
||||||
|
|
@ -563,6 +619,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
batchSettingVariantImage() {
|
||||||
|
bk.fileManagerIframe(images => {
|
||||||
|
this.variablesBatch.image = images[0].path;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
addProductImages(skuIndex) {
|
addProductImages(skuIndex) {
|
||||||
bk.fileManagerIframe(images => {
|
bk.fileManagerIframe(images => {
|
||||||
if (!isNaN(skuIndex)) {
|
if (!isNaN(skuIndex)) {
|
||||||
|
|
@ -585,6 +647,61 @@
|
||||||
this.form.skus[variantIndex].images.splice(index, 1)
|
this.form.skus[variantIndex].images.splice(index, 1)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
batchSettingVariant() {
|
||||||
|
// 要修改的 skuIndex 下标
|
||||||
|
let setSkuIndex = [];
|
||||||
|
|
||||||
|
this.form.skus.forEach((sku, skuIndex) => {
|
||||||
|
this.variablesBatch.variables.forEach((variantIndex, index) => {
|
||||||
|
if (variantIndex !== '') {
|
||||||
|
// 根据 variantIndex, index,修改 sku.variants[index] 的值
|
||||||
|
if (sku.variants[index] == variantIndex) {
|
||||||
|
setSkuIndex.push(skuIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 variantIndex 全部为空,就把所有的 skuIndex 都加入到 setSkuIndex 中
|
||||||
|
if (this.variablesBatch.variables.every(v => v === '')) {
|
||||||
|
setSkuIndex.push(skuIndex);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 修改 skuIndex 下标对应的 sku
|
||||||
|
setSkuIndex.forEach((index) => {
|
||||||
|
if (this.variablesBatch.model) {
|
||||||
|
this.form.skus[index].model = this.variablesBatch.model + '-' + (index + 1);
|
||||||
|
}
|
||||||
|
if (this.variablesBatch.sku) {
|
||||||
|
this.form.skus[index].sku = this.variablesBatch.sku + '-' + (index + 1);
|
||||||
|
}
|
||||||
|
if (this.variablesBatch.image) {
|
||||||
|
this.form.skus[index].images = [this.variablesBatch.image];
|
||||||
|
}
|
||||||
|
if (this.variablesBatch.price) {
|
||||||
|
this.form.skus[index].price = this.variablesBatch.price;
|
||||||
|
}
|
||||||
|
if (this.variablesBatch.origin_price) {
|
||||||
|
this.form.skus[index].origin_price = this.variablesBatch.origin_price;
|
||||||
|
}
|
||||||
|
if (this.variablesBatch.cost_price) {
|
||||||
|
this.form.skus[index].cost_price = this.variablesBatch.cost_price;
|
||||||
|
}
|
||||||
|
if (this.variablesBatch.quantity) {
|
||||||
|
this.form.skus[index].quantity = this.variablesBatch.quantity;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// this.variablesBatch 对象内除了 variables 之外的值都清空
|
||||||
|
for (let key in this.variablesBatch) {
|
||||||
|
if (key !== 'variables') {
|
||||||
|
this.variablesBatch[key] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
dialogVariablesFormSubmit(form) {
|
dialogVariablesFormSubmit(form) {
|
||||||
const name = JSON.parse(JSON.stringify(this.dialogVariables.form.name));
|
const name = JSON.parse(JSON.stringify(this.dialogVariables.form.name));
|
||||||
const variantIndex = this.dialogVariables.variantIndex;
|
const variantIndex = this.dialogVariables.variantIndex;
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,6 @@ header {
|
||||||
|
|
||||||
#offcanvas-right-cart {
|
#offcanvas-right-cart {
|
||||||
.select-wrap {
|
.select-wrap {
|
||||||
flex: 1;
|
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,8 @@ body.page-categories {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
margin-top: 0;
|
line-height: 1;
|
||||||
|
margin: 16px 0;
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ return [
|
||||||
'text_list' => 'List',
|
'text_list' => 'List',
|
||||||
'text_form' => 'From',
|
'text_form' => 'From',
|
||||||
'text_to' => 'To',
|
'text_to' => 'To',
|
||||||
|
'batch_setting' => 'Batch setting',
|
||||||
|
|
||||||
'id' => 'ID',
|
'id' => 'ID',
|
||||||
'created_at' => 'Created At',
|
'created_at' => 'Created At',
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ return [
|
||||||
'text_list' => '列表',
|
'text_list' => '列表',
|
||||||
'text_form' => '从',
|
'text_form' => '从',
|
||||||
'text_to' => '到',
|
'text_to' => '到',
|
||||||
|
'batch_setting' => '批量设置',
|
||||||
|
|
||||||
'id' => 'ID',
|
'id' => 'ID',
|
||||||
'created_at' => '创建时间',
|
'created_at' => '创建时间',
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ return [
|
||||||
'text_list' => '列表',
|
'text_list' => '列表',
|
||||||
'text_form' => '從',
|
'text_form' => '從',
|
||||||
'text_to' => '到',
|
'text_to' => '到',
|
||||||
|
'batch_setting' => '批量設置',
|
||||||
|
|
||||||
'id' => 'ID',
|
'id' => 'ID',
|
||||||
'created_at' => '創建時間',
|
'created_at' => '創建時間',
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,9 @@
|
||||||
<h1 class="mb-4 product-name">{{ $product['name'] }}</h1>
|
<h1 class="mb-4 product-name">{{ $product['name'] }}</h1>
|
||||||
<div class="price-wrap d-flex align-items-end">
|
<div class="price-wrap d-flex align-items-end">
|
||||||
<div class="new-price fs-1 lh-1 fw-bold me-2">@{{ product.price_format }}</div>
|
<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">@{{ product.origin_price_format }}</div>
|
<div class="old-price text-muted text-decoration-line-through" v-if="product.price != product.origin_price">
|
||||||
|
@{{ product.origin_price_format }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stock-and-sku mb-4">
|
<div class="stock-and-sku mb-4">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue