优化:商品编辑页面布局调整,计量单位由手动填写且支持中英文切换修改为下拉框选择且不支持中英文切换

This commit is contained in:
wuhui_zzw 2023-09-22 10:39:48 +08:00
parent 650184d860
commit 9ad042da88
8 changed files with 339 additions and 313 deletions

View File

@ -177,6 +177,7 @@ class ProductController extends Controller
'categories' => CategoryRepo::flatten(locale(), false),
],
'_redirect' => $this->getRedirect(),
'unit_list' => Product::getUnitList(),
];
$data = hook_filter('admin.product.form.data', $data);

View File

@ -27,7 +27,9 @@ class Product extends Base
'height',
'minimum_order',
'sales_method',
'piece_to_batch'
'piece_to_batch',
'trade_term',
'unit'
];
protected $casts = [
@ -125,4 +127,15 @@ class Product extends Base
return $images[0] ?? '';
}
public static function getUnitList(){
return [
['title'=>'set/sets'],
['title'=>'bag/bags'],
['title'=>'piece/pieces']
];
}
}

View File

@ -28,7 +28,7 @@ class CartDetail extends JsonResource
$description = $product->description;
$productName = $description->name;
$unit = $description->unit ?? '';
$unit = $this->unit;//$description->unit ?? '';
$subTotal = $price * $this->quantity;
$image = $sku->image ?: $product->image;

View File

@ -46,7 +46,7 @@ class ProductDetail extends JsonResource
return [
'id' => $this->id,
'name' => $this->description->name ?? '',
'unit' => $this->description->unit ?? '',
'unit' => $this->unit,//$this->description->unit ?? '',
'description' => $this->description->content ?? '',
'meta_title' => $this->description->meta_title ?? '',
'meta_keywords' => $this->description->meta_keywords ?? '',

View File

@ -31,7 +31,7 @@ class ProductSimple extends JsonResource
}
$name = $this->description->name ?? '';
$unit = $this->description->unit ?? '';
$unit = $this->unit;//$this->description->unit ?? '';
$images = $this->images != NULL ? $this->images : [];
$data = [

View File

@ -54,6 +54,313 @@
<div class="tab-content">
<div class="tab-pane fade show active" id="tab-basic">
{{--交易信息--}}
<div>
<h5 class="border-bottom pb-3 mb-4">{{ __('product.transaction_info') }}</h5>
<x-admin::form.row title="{{ __('admin/product.price_setting_by.num') }}">
<div class="mb-1 mt-2">
<div class="form-check form-check-inline">
<input v-model="form.price_setting" class="form-check-input" id="price_setting-sku" type="radio" name="price_setting" id="price_setting-sku" value="sku" {{ $product->price_setting == 'sku' ? 'checked' : '' }}>
<label class="form-check-label" for="price_setting-sku">{{ __('common.disable') }}</label>
</div>
<div class="form-check form-check-inline">
<input v-model="form.price_setting" class="form-check-input" id="price_setting-num" type="radio" name="price_setting" id="price_setting-num" value="num" {{ $product->price_setting == 'num' ? 'checked' : '' }}>
<label class="form-check-label" for="price_setting-num">{{ __('common.enable') }}</label>
</div>
</div>
</x-admin::form.row>
<span v-if="form.price_setting === 'num'">
{{-- 阶梯价格设置表格 (最小起订量,产品价格),预览,可以增加删除价格区间--}}
<div class="price_setting_by_num">
<div class="left">
<div class="head">
<div class="num" >{{__('admin/product.minimum_order')}}</div>
<div class="price">产品价格</div>
<div class="delete">删除</div>
</div>
<div class="body">
<div class="item" v-for="(item,index) in form.numPrices">
<div class="num">
<div class="top">
<div class="title"></div>
<input type="number" :name="'numPrices[' + index + '][num]'" v-model="item.num" value="" placeholder="数量" required="required" class="form-control wp-100">
<div v-if="form.sales_method == 'piece'" style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.piece') }}</div>
<div v-else style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.batches') }}</div>
</div>
<div class="tip" >
<span style="visibility: hidden;">_</span>
<span v-if="item.num">@{{ form.sales_method == 'piece' ? item.num : item.num * form.piece_to_batch }}{{ __('product.piece') }}</span>
</div>
</div>
<div class="price">
<input type="number" :name="'numPrices[' + index + '][price]'" v-model="item.price" value="" placeholder="价格" required="required" step="any" class="form-control wp-100">
<div class="tip" v-if="item.price">
<tmplate v-if="form.sales_method == 'piece'">
@{{ item.num }}件等于价格:@{{ (item.num * item.price).toFixed(2) }}
</tmplate>
<template v-else>
@{{ item.num }}批含@{{ item.num * form.piece_to_batch }}件商品($@{{ item.price }}/件),@{{ item.num }}批总价$@{{ ((item.num * form.piece_to_batch) * item.price).toFixed(2) }}
</template>
</div>
</div>
<div class="delete" @click="removeNumPrices(index)"><a style="cursor: pointer;color: #0072ff;">删除</a></div>
</div>
</div>
<div class="bottom">
<a style="cursor: pointer;color: #0072ff;" @click="addNumPrices"> {{ __('admin/product.add_variable') }}</a>
</div>
</div>
<div class="right">
<div class="head">
预览
</div>
<div class="body">
<div class="item" v-for="(item,index) in form.numPrices">
<div class="num" v-if="index < form.numPrices.length - 1">
@{{ form.sales_method == 'piece' ? item.num : item.num * form.piece_to_batch }} ~ @{{ form.sales_method == 'piece' ? (form.numPrices[index + 1].num - 1) : form.numPrices[index + 1].num * form.piece_to_batch - 1 }}
</div>
<div class="num" v-else-if="item.num">@{{ form.sales_method == 'piece' ? item.num : item.num * form.piece_to_batch }}</div>
<div class="price" v-if="item.price">价格@{{ item.price }}</div>
</div>
</div>
</div>
</div>
<input class="form-control d-none" :value="numPricesIsEmpty" required>
<div class="invalid-feedback" style="font-size: 16px;margin-left: 200px;"><i class="bi bi-exclamation-circle-fill"></i> 新增价格区间</div>
<template>
{{-- <input type="hidden" value="{{ old('skus.0.image', $product->skus[0]->image ?? '') }}" name="skus[0][image]">--}}
{{-- <x-admin-form-input name="skus[0][model]" :title="__('admin/product.model')" :value="old('skus.0.model', $product->skus[0]->model ?? '')" />--}}
{{-- <x-admin-form-input name="skus[0][sku]" title="sku" :value="old('skus.0.sku', $product->skus[0]->sku ?? '')" required />--}}
{{-- <x-admin-form-input name="skus[0][price]" type="number" :title="__('admin/product.price')" :value="old('skus.0.price', $product->skus[0]->price ?? '')" step="any" required />--}}
{{-- --}}{{-- <x-admin-form-input name="skus[0][origin_price]" type="number" :title="__('admin/product.origin_price')" :value="old('skus.0.origin_price', $product->skus[0]->origin_price ?? '')" step="any" required />--}}
{{-- <x-admin-form-input name="skus[0][cost_price]" type="number" :title="__('admin/product.cost_price')" :value="old('skus.0.cost_price', $product->skus[0]->cost_price ?? '')" />--}}
{{-- <x-admin-form-input name="skus[0][quantity]" type="number" :title="__('admin/product.quantity')" :value="old('skus.0.quantity', $product->skus[0]->quantity ?? '')" />--}}
{{-- <input type="hidden" name="skus[0][price]" placeholder="variants" :value="form.numPrices.length !== 0 ? form.numPrices[0].price : ''">--}}
{{-- <input type="hidden" name="skus[0][origin_price]" placeholder="position" :value="form.numPrices.length !== 0 ? form.numPrices[form.numPrices.length - 1].price : ''">--}}
{{-- <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">--}}
</template>
</span>
<input type="hidden" name="variables" :value="JSON.stringify(form.variables)">
<input type="hidden" name="numPrices" value="" v-if="form.price_setting === 'sku'">
@hookwrapper('admin.product.edit.switch')
<x-admin::form.row :title="__('admin/product.enable_multi_spec')">
<el-switch v-model="editing.isVariable" @change="isVariableChange" class="mt-2"></el-switch>
</x-admin::form.row>
@endhookwrapper
<input type="hidden" name="variables" :value="JSON.stringify(form.variables)">
<div class="row g-3 mb-3" v-if="editing.isVariable">
<label for="" class="wp-200 col-form-label text-end"></label>
<div class="col-auto wp-200-">
<div class="selectable-variants">
<div>
<draggable :list="source.variables" :options="{animation: 100}">
<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)">{{ __('common.edit') }}</el-link>
<el-link type="danger" class="ms-2" @click="removeSourceVariant(variantIndex)">{{ __('common.delete') }}</el-link>
</div>
<div>
<el-checkbox v-model="variant.isNumSelect" @change="(e) => {variantIsNumSelect(e, variantIndex)}" border size="mini" class="me-2 bg-white">{{ __('admin/product.num_select') }}</el-checkbox>
<el-checkbox v-model="variant.isImage" @change="(e) => {variantIsImage(e, variantIndex)}" border size="mini" class="me-2 bg-white">{{ __('admin/product.add_variable_image') }}</el-checkbox>
<el-button type="primary" plain size="mini" @click="modalVariantOpenButtonClicked(variantIndex, -1)">{{ __('admin/product.add_variable_value') }}</el-button>
</div>
</div>
<template v-if="variant.values.length">
<draggable
element="div"
@start="isMove = true"
class="variants-wrap"
@update="(e) => {swapSourceVariantValue(e, variantIndex)}"
@end="isMove = false"
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="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 class="ps-2 mt-2 mb-3 opacity-50"><i class="bi bi-exclamation-circle"></i> {{ __('admin/product.modify_order') }}</div>
</template>
<div v-else class="d-flex justify-content-center align-items-center">
<div class="p-4 fs-5 btn" @click="modalVariantOpenButtonClicked(variantIndex, -1)"><i class="bi bi-plus-square-dotted"></i> {{ __('admin/product.add_variable_value') }}</div>
</div>
</div>
</draggable>
<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 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" style="max-height: 40px;">
<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" v-if="form.price_setting === 'sku'" class="form-control me-2 bg-white" v-model="variablesBatch.price" placeholder="{{ __('admin/product.price') }}">
<input type="number" v-if="form.price_setting === 'sku'" 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">
<thead>
<th v-for="(variant, index) in form.variables" :key="'pv-header-' + index">
@{{ variant.name[current_language_code] || 'No name' }}
</th>
<th width="106px">{{ __('common.image') }}</th>
<th class="w-min-100">{{ __('admin/product.model') }}</th>
{{--<th class="w-min-100">sku</th>--}}
<th v-if="form.price_setting === 'sku'" class="w-min-100">{{ __('admin/product.price') }}</th>
<th v-if="form.price_setting === 'sku'" class="w-min-100">{{ __('admin/product.origin_price') }}</th>
{{--<th class="w-min-100">{{ __('admin/product.cost_price') }}</th>--}}
<th class="w-min-100">{{ __('admin/product.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="product-images d-flex flex-wrap" style="margin-right: -8px">
<div v-for="image, index in sku.images" :key="index" class="product-item wh-40 border d-flex justify-content-center align-items-center me-2 mb-2 position-relative">
<div class="position-absolute top-0 end-0">
<button class="btn btn-danger btn-sm wh-20 p-0" @click="removeSkuImages(skuIndex, index)" type="button"><i class="bi bi-trash"></i></button>
</div>
<img :src="thumbnail(image)" class="img-fluid" style="max-height: 40px;">
<input type="hidden" class="form-control" v-model="sku.images[index]" :name="'skus[' + skuIndex + '][images][]'"
placeholder="image">
</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>
<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="{{ __('admin/product.model') }}"></td>
{{-- <td>
<input type="text" class="form-control" v-model="sku.sku" :name="'skus[' + skuIndex + '][sku]'" placeholder="sku" :style="sku.is_default ? 'margin-top: 19px;' : ''" required>
<span role="alert" class="invalid-feedback">{{ __('common.error_required', ['name' => 'sku']) }}</span>
<span v-if="sku.is_default" class="text-success">{{ __('admin/product.default_main_product') }}</span>
</td>--}}
<td v-if="form.price_setting === 'sku'">
<input type="number" class="form-control" v-model="sku.price" :name="'skus[' + skuIndex + '][price]'" step="any"
placeholder="{{ __('admin/product.price') }}" required>
<span role="alert" class="invalid-feedback">{{ __('common.error_required', ['name' => __('admin/product.price')]) }}</span>
</td>
<td v-if="form.price_setting === 'sku'">
<input type="number" class="form-control" v-model="sku.origin_price" :name="'skus[' + skuIndex + '][origin_price]'" step="any"
placeholder="{{ __('admin/product.origin_price') }}" required>
<span role="alert" class="invalid-feedback">{{ __('common.error_required', ['name' => __('admin/product.origin_price')]) }}</span>
</td>
<input type="hidden" :name="'skus[' + skuIndex + '][price]'" v-if="form.price_setting === 'num'" placeholder="variants" :value="form.numPrices.length !== 0 ? form.numPrices[0].price : ''">
<input type="hidden" :name="'skus[' + skuIndex + '][origin_price]'" v-if="form.price_setting === 'num'" placeholder="position" :value="form.numPrices.length !== 0 ? form.numPrices[form.numPrices.length - 1].price : ''">
{{--<td>
<input type="number" class="form-control" v-model="sku.cost_price" :name="'skus[' + skuIndex + '][cost_price]'" placeholder="{{ __('admin/product.cost_price') }}">
</td>--}}
<td><input type="number" class="form-control" v-model="sku.quantity" :name="'skus[' + skuIndex + '][quantity]'"
placeholder="{{ __('admin/product.quantity') }}"></td>
</tr>
</tbody>
</table>
</div>
</div>
<input class="form-control d-none" :value="skuIsEmpty" required>
<div class="invalid-feedback" style="font-size: 16px"><i class="bi bi-exclamation-circle-fill"></i> {{ __('admin/product.add_variable') }}</div>
</div>
</div>
{{--最小起订量--}}
{{-- 未开启根据数量设置价格、直接下单产品 --}}
<template v-if="form.price_setting === 'sku' && form.active == 1">
<x-admin::form.row :title="__('admin/product.minimum_order')" required>
<div class="d-flex wp-500">
<input type="number" name="minimum_order" v-model="form.minimum_order" class="form-control"/>
<div v-if="form.sales_method == 'piece'" style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.piece') }}</div>
<div v-else style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.batches') }}</div>
</div>
</x-admin::form.row>
</template>
{{-- 未开启根据数量设置价格、非直接下单商品 --}}
<template v-else-if="form.price_setting === 'sku' && form.active != 1">
<x-admin::form.row :title="__('admin/product.minimum_order')">
<div class="d-flex wp-500">
<input type="number" name="minimum_order" v-model="form.minimum_order" class="form-control"/>
<div v-if="form.sales_method == 'piece'" style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.piece') }}</div>
<div v-else style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.batches') }}</div>
</div>
</x-admin::form.row>
</template>
{{--开启根据数量设置价格 - 数量固定为最小起订量--}}
<template v-else>
<x-admin::form.row :title="__('admin/product.minimum_order')" required>
<div class="d-flex wp-500">
<input type="number" name="minimum_order" :value="form.numPrices.length !== 0 ? form.numPrices[0].num : 0" class="form-control" readonly/>
<div v-if="form.sales_method == 'piece'" style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.piece') }}</div>
<div v-else style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.batches') }}</div>
</div>
</x-admin::form.row>
</template>
@hookwrapper('admin.product.edit.variable')
<div v-if="!editing.isVariable">
<input type="hidden" value="{{ old('skus.0.image', $product->skus[0]->image ?? '') }}" name="skus[0][image]">
<x-admin-form-input name="skus[0][model]" :title="__('admin/product.model')" :value="old('skus.0.model', $product->skus[0]->model ?? '')" />
{{--<x-admin-form-input name="skus[0][sku]" title="sku" :value="old('skus.0.sku', $product->skus[0]->sku ?? '')" required />--}}
<span v-if="form.price_setting === 'sku'">
<x-admin-form-input name="skus[0][price]" type="number" :title="__('admin/product.price')" :value="old('skus.0.price', $product->skus[0]->price ?? '')" step="any" required />
<x-admin-form-input name="skus[0][origin_price]" type="number" :title="__('admin/product.origin_price')" :value="old('skus.0.origin_price', $product->skus[0]->origin_price ?? '')" step="any" required />
</span>
<x-admin-form-input name="skus[0][quantity]" type="number" :title="__('admin/product.quantity')" :value="old('skus.0.quantity', $product->skus[0]->quantity ?? '')" />
<input type="hidden" name="skus[0][price]" v-if="form.price_setting === 'num'" placeholder="variants" :value="form.numPrices.length !== 0 ? form.numPrices[0].price : ''">
<input type="hidden" name="skus[0][origin_price]" v-if="form.price_setting === 'num'" placeholder="position" :value="form.numPrices.length !== 0 ? form.numPrices[form.numPrices.length - 1].price : ''">
<input type="hidden" name="skus[0][variants]" placeholder="variants" value="">
<input type="hidden" name="skus[0][position]" placeholder="position" value="0">
{{--<x-admin-form-input name="skus[0][cost_price]" type="number" :title="__('admin/product.cost_price')" :value="old('skus.0.cost_price', $product->skus[0]->cost_price ?? '')" required />--}}
<input type="hidden" name="skus[0][is_default]" placeholder="is_default" value="1">
</div>
@endhookwrapper
</div>
{{--其他数据--}}
<h6 class="border-bottom pb-3 mb-4">{{ __('common.data') }}</h6>
<x-admin-form-input-locale
:width="600" name="descriptions.*.name" title="{{ __('common.name') }}"
@ -146,8 +453,11 @@
</div>
</x-admin::form.row>
{{--计量单位--}}
<x-admin-form-input-locale :width="600" name="descriptions.*.unit" title="{{ __('product.unit_of_measurement') }}" :value="$descriptions" :required="true" />
{{--计量单位 语言切换弃用 改为下拉框选择--}}
<x-admin-form-select :title="__('product.unit_of_measurement')" name="unit" :value="old('unit', $product->unit ?? '')" :options="$unit_list" key="title" label="title" />
{{--<x-admin-form-input-locale :width="600" name="descriptions.*.unit" title="{{ __('product.unit_of_measurement') }}" :value="$descriptions" :required="true" />--}}
{{--贸易术语--}}
<x-admin-form-input name="trade_term" :title="__('product.trade_term')" :value="old('trade_term', $product->trade_term ?? '')" />
{{--销售方式--}}
<x-admin::form.row title="{{ __('product.sales_method') }}">
<div class="mb-1 mt-2">
@ -171,7 +481,7 @@
</template>
{{--状态--}}
<x-admin::form.row title="{{ __('common.status') }}">
<x-admin::form.row title="{{ __('product.product_type') }}">
<div class="mb-1 mt-2">
<div class="form-check form-check-inline">
<input v-model="form.active" class="form-check-input" id="active-1" type="radio" name="active" value="1">
@ -185,311 +495,7 @@
</x-admin::form.row>
@hook('admin.product.edit.extra')
<div>
<h5 class="border-bottom pb-3 mb-4">{{ __('admin/product.stocks') }}</h5>
<x-admin::form.row title="{{ __('admin/product.price_setting_by.num') }}">
<div class="mb-1 mt-2">
<div class="form-check form-check-inline">
<input v-model="form.price_setting" class="form-check-input" id="price_setting-sku" type="radio" name="price_setting" id="price_setting-sku" value="sku" {{ $product->price_setting == 'sku' ? 'checked' : '' }}>
<label class="form-check-label" for="price_setting-sku">{{ __('common.disable') }}</label>
</div>
<div class="form-check form-check-inline">
<input v-model="form.price_setting" class="form-check-input" id="price_setting-num" type="radio" name="price_setting" id="price_setting-num" value="num" {{ $product->price_setting == 'num' ? 'checked' : '' }}>
<label class="form-check-label" for="price_setting-num">{{ __('common.enable') }}</label>
</div>
</div>
</x-admin::form.row>
<span v-if="form.price_setting === 'num'">
{{-- 阶梯价格设置表格 (最小起订量,产品价格),预览,可以增加删除价格区间--}}
<div class="price_setting_by_num">
<div class="left">
<div class="head">
<div class="num" >{{__('admin/product.minimum_order')}}</div>
<div class="price">产品价格</div>
<div class="delete">删除</div>
</div>
<div class="body">
<div class="item" v-for="(item,index) in form.numPrices">
<div class="num">
<div class="top">
<div class="title"></div>
<input type="number" :name="'numPrices[' + index + '][num]'" v-model="item.num" value="" placeholder="数量" required="required" class="form-control wp-100">
<div v-if="form.sales_method == 'piece'" style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.piece') }}</div>
<div v-else style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.batches') }}</div>
</div>
<div class="tip" >
<span style="visibility: hidden;">_</span>
<span v-if="item.num">@{{ form.sales_method == 'piece' ? item.num : item.num * form.piece_to_batch }}{{ __('product.piece') }}</span>
</div>
</div>
<div class="price">
<input type="number" :name="'numPrices[' + index + '][price]'" v-model="item.price" value="" placeholder="价格" required="required" step="any" class="form-control wp-100">
<div class="tip" v-if="item.price">
<tmplate v-if="form.sales_method == 'piece'">
@{{ item.num }}件等于价格:@{{ (item.num * item.price).toFixed(2) }}
</tmplate>
<template v-else>
@{{ item.num }}批含@{{ item.num * form.piece_to_batch }}件商品($@{{ item.price }}/件),@{{ item.num }}批总价$@{{ ((item.num * form.piece_to_batch) * item.price).toFixed(2) }}
</template>
</div>
</div>
<div class="delete" @click="removeNumPrices(index)"><a style="cursor: pointer;color: #0072ff;">删除</a></div>
</div>
</div>
<div class="bottom">
<a style="cursor: pointer;color: #0072ff;" @click="addNumPrices"> {{ __('admin/product.add_variable') }}</a>
</div>
</div>
<div class="right">
<div class="head">
预览
</div>
<div class="body">
<div class="item" v-for="(item,index) in form.numPrices">
<div class="num" v-if="index < form.numPrices.length - 1">
@{{ form.sales_method == 'piece' ? item.num : item.num * form.piece_to_batch }} ~ @{{ form.sales_method == 'piece' ? (form.numPrices[index + 1].num - 1) : form.numPrices[index + 1].num * form.piece_to_batch - 1 }}
</div>
<div class="num" v-else-if="item.num">@{{ form.sales_method == 'piece' ? item.num : item.num * form.piece_to_batch }}</div>
<div class="price" v-if="item.price">价格@{{ item.price }}</div>
</div>
</div>
</div>
</div>
<input class="form-control d-none" :value="numPricesIsEmpty" required>
<div class="invalid-feedback" style="font-size: 16px;margin-left: 200px;"><i class="bi bi-exclamation-circle-fill"></i> 新增价格区间</div>
<template>
{{-- <input type="hidden" value="{{ old('skus.0.image', $product->skus[0]->image ?? '') }}" name="skus[0][image]">--}}
{{-- <x-admin-form-input name="skus[0][model]" :title="__('admin/product.model')" :value="old('skus.0.model', $product->skus[0]->model ?? '')" />--}}
{{-- <x-admin-form-input name="skus[0][sku]" title="sku" :value="old('skus.0.sku', $product->skus[0]->sku ?? '')" required />--}}
{{-- <x-admin-form-input name="skus[0][price]" type="number" :title="__('admin/product.price')" :value="old('skus.0.price', $product->skus[0]->price ?? '')" step="any" required />--}}
{{-- --}}{{-- <x-admin-form-input name="skus[0][origin_price]" type="number" :title="__('admin/product.origin_price')" :value="old('skus.0.origin_price', $product->skus[0]->origin_price ?? '')" step="any" required />--}}
{{-- <x-admin-form-input name="skus[0][cost_price]" type="number" :title="__('admin/product.cost_price')" :value="old('skus.0.cost_price', $product->skus[0]->cost_price ?? '')" />--}}
{{-- <x-admin-form-input name="skus[0][quantity]" type="number" :title="__('admin/product.quantity')" :value="old('skus.0.quantity', $product->skus[0]->quantity ?? '')" />--}}
{{-- <input type="hidden" name="skus[0][price]" placeholder="variants" :value="form.numPrices.length !== 0 ? form.numPrices[0].price : ''">--}}
{{-- <input type="hidden" name="skus[0][origin_price]" placeholder="position" :value="form.numPrices.length !== 0 ? form.numPrices[form.numPrices.length - 1].price : ''">--}}
{{-- <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">--}}
</template>
</span>
<input type="hidden" name="variables" :value="JSON.stringify(form.variables)">
<input type="hidden" name="numPrices" value="" v-if="form.price_setting === 'sku'">
@hookwrapper('admin.product.edit.switch')
<x-admin::form.row :title="__('admin/product.enable_multi_spec')">
<el-switch v-model="editing.isVariable" @change="isVariableChange" class="mt-2"></el-switch>
</x-admin::form.row>
@endhookwrapper
<input type="hidden" name="variables" :value="JSON.stringify(form.variables)">
<div class="row g-3 mb-3" v-if="editing.isVariable">
<label for="" class="wp-200 col-form-label text-end"></label>
<div class="col-auto wp-200-">
<div class="selectable-variants">
<div>
<draggable :list="source.variables" :options="{animation: 100}">
<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)">{{ __('common.edit') }}</el-link>
<el-link type="danger" class="ms-2" @click="removeSourceVariant(variantIndex)">{{ __('common.delete') }}</el-link>
</div>
<div>
<el-checkbox v-model="variant.isNumSelect" @change="(e) => {variantIsNumSelect(e, variantIndex)}" border size="mini" class="me-2 bg-white">{{ __('admin/product.num_select') }}</el-checkbox>
<el-checkbox v-model="variant.isImage" @change="(e) => {variantIsImage(e, variantIndex)}" border size="mini" class="me-2 bg-white">{{ __('admin/product.add_variable_image') }}</el-checkbox>
<el-button type="primary" plain size="mini" @click="modalVariantOpenButtonClicked(variantIndex, -1)">{{ __('admin/product.add_variable_value') }}</el-button>
</div>
</div>
<template v-if="variant.values.length">
<draggable
element="div"
@start="isMove = true"
class="variants-wrap"
@update="(e) => {swapSourceVariantValue(e, variantIndex)}"
@end="isMove = false"
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="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 class="ps-2 mt-2 mb-3 opacity-50"><i class="bi bi-exclamation-circle"></i> {{ __('admin/product.modify_order') }}</div>
</template>
<div v-else class="d-flex justify-content-center align-items-center">
<div class="p-4 fs-5 btn" @click="modalVariantOpenButtonClicked(variantIndex, -1)"><i class="bi bi-plus-square-dotted"></i> {{ __('admin/product.add_variable_value') }}</div>
</div>
</div>
</draggable>
<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 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" style="max-height: 40px;">
<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" v-if="form.price_setting === 'sku'" class="form-control me-2 bg-white" v-model="variablesBatch.price" placeholder="{{ __('admin/product.price') }}">
<input type="number" v-if="form.price_setting === 'sku'" 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">
<thead>
<th v-for="(variant, index) in form.variables" :key="'pv-header-' + index">
@{{ variant.name[current_language_code] || 'No name' }}
</th>
<th width="106px">{{ __('common.image') }}</th>
<th class="w-min-100">{{ __('admin/product.model') }}</th>
{{--<th class="w-min-100">sku</th>--}}
<th v-if="form.price_setting === 'sku'" class="w-min-100">{{ __('admin/product.price') }}</th>
<th v-if="form.price_setting === 'sku'" class="w-min-100">{{ __('admin/product.origin_price') }}</th>
{{--<th class="w-min-100">{{ __('admin/product.cost_price') }}</th>--}}
<th class="w-min-100">{{ __('admin/product.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="product-images d-flex flex-wrap" style="margin-right: -8px">
<div v-for="image, index in sku.images" :key="index" class="product-item wh-40 border d-flex justify-content-center align-items-center me-2 mb-2 position-relative">
<div class="position-absolute top-0 end-0">
<button class="btn btn-danger btn-sm wh-20 p-0" @click="removeSkuImages(skuIndex, index)" type="button"><i class="bi bi-trash"></i></button>
</div>
<img :src="thumbnail(image)" class="img-fluid" style="max-height: 40px;">
<input type="hidden" class="form-control" v-model="sku.images[index]" :name="'skus[' + skuIndex + '][images][]'"
placeholder="image">
</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>
<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="{{ __('admin/product.model') }}"></td>
{{-- <td>
<input type="text" class="form-control" v-model="sku.sku" :name="'skus[' + skuIndex + '][sku]'" placeholder="sku" :style="sku.is_default ? 'margin-top: 19px;' : ''" required>
<span role="alert" class="invalid-feedback">{{ __('common.error_required', ['name' => 'sku']) }}</span>
<span v-if="sku.is_default" class="text-success">{{ __('admin/product.default_main_product') }}</span>
</td>--}}
<td v-if="form.price_setting === 'sku'">
<input type="number" class="form-control" v-model="sku.price" :name="'skus[' + skuIndex + '][price]'" step="any"
placeholder="{{ __('admin/product.price') }}" required>
<span role="alert" class="invalid-feedback">{{ __('common.error_required', ['name' => __('admin/product.price')]) }}</span>
</td>
<td v-if="form.price_setting === 'sku'">
<input type="number" class="form-control" v-model="sku.origin_price" :name="'skus[' + skuIndex + '][origin_price]'" step="any"
placeholder="{{ __('admin/product.origin_price') }}" required>
<span role="alert" class="invalid-feedback">{{ __('common.error_required', ['name' => __('admin/product.origin_price')]) }}</span>
</td>
<input type="hidden" :name="'skus[' + skuIndex + '][price]'" v-if="form.price_setting === 'num'" placeholder="variants" :value="form.numPrices.length !== 0 ? form.numPrices[0].price : ''">
<input type="hidden" :name="'skus[' + skuIndex + '][origin_price]'" v-if="form.price_setting === 'num'" placeholder="position" :value="form.numPrices.length !== 0 ? form.numPrices[form.numPrices.length - 1].price : ''">
{{--<td>
<input type="number" class="form-control" v-model="sku.cost_price" :name="'skus[' + skuIndex + '][cost_price]'" placeholder="{{ __('admin/product.cost_price') }}">
</td>--}}
<td><input type="number" class="form-control" v-model="sku.quantity" :name="'skus[' + skuIndex + '][quantity]'"
placeholder="{{ __('admin/product.quantity') }}"></td>
</tr>
</tbody>
</table>
</div>
</div>
<input class="form-control d-none" :value="skuIsEmpty" required>
<div class="invalid-feedback" style="font-size: 16px"><i class="bi bi-exclamation-circle-fill"></i> {{ __('admin/product.add_variable') }}</div>
</div>
</div>
{{--最小起订量--}}
{{-- 未开启根据数量设置价格、直接下单产品 --}}
<template v-if="form.price_setting === 'sku' && form.active == 1">
<x-admin::form.row :title="__('admin/product.minimum_order')" required>
<div class="d-flex wp-500">
<input type="number" name="minimum_order" v-model="form.minimum_order" class="form-control"/>
<div v-if="form.sales_method == 'piece'" style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.piece') }}</div>
<div v-else style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.batches') }}</div>
</div>
</x-admin::form.row>
</template>
{{-- 未开启根据数量设置价格、非直接下单商品 --}}
<template v-else-if="form.price_setting === 'sku' && form.active != 1">
<x-admin::form.row :title="__('admin/product.minimum_order')">
<div class="d-flex wp-500">
<input type="number" name="minimum_order" v-model="form.minimum_order" class="form-control"/>
<div v-if="form.sales_method == 'piece'" style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.piece') }}</div>
<div v-else style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.batches') }}</div>
</div>
</x-admin::form.row>
</template>
{{--开启根据数量设置价格 - 数量固定为最小起订量--}}
<template v-else>
<x-admin::form.row :title="__('admin/product.minimum_order')" required>
<div class="d-flex wp-500">
<input type="number" name="minimum_order" :value="form.numPrices.length !== 0 ? form.numPrices[0].num : 0" class="form-control" readonly/>
<div v-if="form.sales_method == 'piece'" style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.piece') }}</div>
<div v-else style="width: 30px;line-height: 34px;text-align:center">/{{ __('product.batches') }}</div>
</div>
</x-admin::form.row>
</template>
@hookwrapper('admin.product.edit.variable')
<div v-if="!editing.isVariable">
<input type="hidden" value="{{ old('skus.0.image', $product->skus[0]->image ?? '') }}" name="skus[0][image]">
<x-admin-form-input name="skus[0][model]" :title="__('admin/product.model')" :value="old('skus.0.model', $product->skus[0]->model ?? '')" />
{{--<x-admin-form-input name="skus[0][sku]" title="sku" :value="old('skus.0.sku', $product->skus[0]->sku ?? '')" required />--}}
<span v-if="form.price_setting === 'sku'">
<x-admin-form-input name="skus[0][price]" type="number" :title="__('admin/product.price')" :value="old('skus.0.price', $product->skus[0]->price ?? '')" step="any" required />
<x-admin-form-input name="skus[0][origin_price]" type="number" :title="__('admin/product.origin_price')" :value="old('skus.0.origin_price', $product->skus[0]->origin_price ?? '')" step="any" required />
</span>
<x-admin-form-input name="skus[0][quantity]" type="number" :title="__('admin/product.quantity')" :value="old('skus.0.quantity', $product->skus[0]->quantity ?? '')" />
<input type="hidden" name="skus[0][price]" v-if="form.price_setting === 'num'" placeholder="variants" :value="form.numPrices.length !== 0 ? form.numPrices[0].price : ''">
<input type="hidden" name="skus[0][origin_price]" v-if="form.price_setting === 'num'" placeholder="position" :value="form.numPrices.length !== 0 ? form.numPrices[form.numPrices.length - 1].price : ''">
<input type="hidden" name="skus[0][variants]" placeholder="variants" value="">
<input type="hidden" name="skus[0][position]" placeholder="position" value="0">
{{--<x-admin-form-input name="skus[0][cost_price]" type="number" :title="__('admin/product.cost_price')" :value="old('skus.0.cost_price', $product->skus[0]->cost_price ?? '')" required />--}}
<input type="hidden" name="skus[0][is_default]" placeholder="is_default" value="1">
</div>
@endhookwrapper
</div>
</div>
<div class="tab-pane fade" id="tab-descriptions">
<h6 class="border-bottom pb-3 mb-4">{{ __('admin/product.product_details') }}</h6>

View File

@ -44,4 +44,9 @@ return [
'quantity_error_mini' => 'Purchase quantity error, the total purchase quantity of [:goods_name] must be greater than or equal to [:num]',
'quantity_error_multiple' => 'Purchase quantity error, the total purchase quantity of [:goods_name] must be a multiple of [:num]',
'product_type' => 'Product type',
'transaction_info' => 'Transaction information',
'trade_term' => 'Trade Term',
];

View File

@ -32,7 +32,7 @@ return [
'minimum_order' => '起订量',
'minimum_order_error' => '采购数量必须大于等于:num',
'unit_of_measurement' => '计量单位',
'sales_method' => '销售方式',
'sales_method' => '基础销售方式',
'sales_method_piece' => '按件卖',
'sales_method_batches' => '按批卖',
'one_batch_is_equal_to' => '1批等于',
@ -45,7 +45,8 @@ return [
'quantity_error_mini' => '采购数量错误,【:goods_name】的采购总数量必须大于等于【:num】',
'quantity_error_multiple' => '采购数量错误,【:goods_name】的采购总数量必须是【:num】的倍数',
'product_type' => '产品类型',
'transaction_info' => '交易信息',
'trade_term' => '贸易术语',
];