优化:

1.产品编辑页数量文本更新为库存,前台文本把Quantity:改为Stock
2.交易信息在下,数据(变更文本为:产品信息) 在上,产品类型下放到交易信息第一排
3.产品类型调用到产品详情页第一行固定栏:产品类型:直接下单产品/非直接下单产品   英文:Product Type: Can Place Orders Wholesale/ Customization
4.产品编辑页面贸易术语必填(图片放大),产品详情页 贸易术语也是问号弹出图片,产品详情页
5.产品详情页Sales method:和Min Order删除。仅仅在按批售卖时才显示Min Order; 把一批多少(单位)和最少买多少(单位)集合到最小起订量 弹出在价格下方。格式如下:
Min Order:X批(1 batch=AA单位 | CC 单位 in total)
6.直接下单产品交易信息所有内容都是必填
This commit is contained in:
wuhui_zzw 2023-10-07 13:45:49 +08:00
parent 84d6777d0f
commit eede9e4e25
8 changed files with 418 additions and 157 deletions

View File

@ -130,10 +130,118 @@ class Product extends Base
public static function getUnitList(){
return [
['title'=>'set/sets'],
['title'=>'bag/bags'],
['title'=>'piece/pieces']
//A
['title' => 'Acre/Acres'],
['title' => 'Ampere/Amperes'],
//B
['title' => 'Bag/Bags'],
['title' => 'Barrel/Barrels'],
['title' => 'Blade/Blades'],
['title' => 'Box/Boxes'],
['title' => 'Bushel/Bushels'],
// C
['title' => 'Carat/Carats'],
['title' => 'Carton/Cartons'],
['title' => 'Case/Cases'],
['title' => 'Centimeter/Centimeters'],
['title' => 'Chain/Chains'],
['title' => 'Combo/Combos'],
['title' => 'Cubic Centimeter/Cubic Centimeters'],
['title' => 'Cubic Foot/Cubic Feet'],
['title' => 'Cubic Inch/Cubic Inches'],
['title' => 'Cubic Meter/Cubic Meters'],
['title' => 'Cubic Yard/Cubic Yards'],
// D
['title' => 'Degrees Fahrenheit'],
['title' => 'Dozen/Dozens'],
['title' => 'Dram/Drams'],
// F
['title' => 'Fluid Ounce/Fluid Ounces'],
['title' => 'Foot/Feet'],
['title' => 'Forty-FootContainer'],
['title' => 'Furlong/Furlongs'],
// G
['title' => 'Gallon/Gallons'],
['title' => 'Gill/Gills'],
['title' => 'Grain/Grains'],
['title' => 'Gram/Grams'],
['title' => 'Gross'],
// H
['title' => 'Hectare/Hectares'],
['title' => 'Hertz'],
// I
['title' => 'Inch/Inches'],
// K
['title' => 'Kiloampere/Kiloamperes'],
['title' => 'Kilogram/Kilograms'],
['title' => 'Kilohertz'],
['title' => 'Kilometer/kilometers'],
['title' => 'Kiloohm/Kiloohms'],
['title' => 'Kilovolt/Kilovolts'],
['title' => 'Kilowatt/Kilowatts'],
// L
['title' => 'Liter/Liters'],
['title' => 'Long Ton/Long Tons'],
// M
['title' => 'Megahertz'],
['title' => 'Meter/Meters'],
['title' => 'Metric Ton/Metric Tons'],
['title' => 'Mile/Miles'],
['title' => 'Milliampere/Milliamperes'],
['title' => 'Milligram/Milligrams'],
['title' => 'Millihertz'],
['title' => 'Milliliter/Milliliters'],
['title' => 'Milliohm/Milliohms'],
['title' => 'Millivolt/Millivolts'],
['title' => 'Milliwatt/Milliwatts'],
// N
['title' => 'Nautical Mile/Nautical Miles'],
// O
['title' => 'Ohm/Ohms'],
['title' => 'Ounce/Ounces'],
// P
['title' => 'Pack/Packs'],
['title' => 'Pair/Pairs'],
['title' => 'Pallet/Pallets'],
['title' => 'Parcel/Parcels'],
['title' => 'Perch/Perches'],
['title' => 'Piece/Pieces'],
['title' => 'Pint/Pints'],
['title' => 'Plant/Plants'],
['title' => 'Pole/Poles'],
['title' => 'Pound/Pounds'],
// Q
['title' => 'Quart/Quarts'],
['title' => 'Quarter/Quarters'],
// R
['title' => 'Rod/Rods'],
['title' => 'Roll/Rolls'],
// S
['title' => 'Set/Sets'],
['title' => 'Sheet/Sheets'],
['title' => 'Short Ton/Short Tons'],
['title' => 'Square Centimeter/Square Centimeters'],
['title' => 'Square Foot/Square Feet'],
['title' => 'Square Inch/Square Inches'],
['title' => 'Square Meter/Square Meters'],
['title' => 'Square Mile/Square Miles'],
['title' => 'Square Yard/Square Yards'],
['title' => 'Stone/Stones'],
['title' => 'Strand/Strands'],
// T
['title' => 'Ton/Tons'],
['title' => 'Tonne/Tonnes'],
['title' => 'Tray/Trays'],
['title' => 'Twenty-Foot Container'],
// U
['title' => 'Unit/Units'],
// V
['title' => 'Volt/Volts'],
// W
['title' => 'Watt/Watts'],
['title' => 'Wp'],
// Y
['title' => 'Yard/Yards'],
];
}

View File

@ -2396,6 +2396,8 @@ $(function () {
hload: true
}).then(function (res) {
updateMiniCartData(res);
})["catch"](function (err) {
console.log("修改购物车信息header - 错误:", err);
});
});
function updateMiniCartData(res) {
@ -2444,20 +2446,28 @@ $(document).on('click', '.quantity-wrap .right i', function (event) {
event.stopPropagation();
event.preventDefault();
var input = $(this).parent().siblings('input');
var minimum_order = input.attr('minimum_order') || 0; // 最小起订量
var minimum_order = input.attr('minimum') || 0; // 最小起订量
var sales_method = input.attr('sales_method') || 'piece'; // 销售方式piece=按件卖batches=按批卖
var piece_to_batch = input.attr('piece_to_batch') || 1; // 按批卖,每批等于多少件
var step = sales_method === 'piece' ? parseInt(1) : parseInt(piece_to_batch); // 点击后加减数量
var res_num = $(this).hasClass('bi-chevron-up') ? input.val() * 1 + step : input.val() * 1 - step;
if (sales_method === 'batches' && res_num % step !== 0) {
input.val(0);
input.get(0).dispatchEvent(new Event('input'));
return;
}
if ($(this).hasClass('bi-chevron-up')) {
input.val(input.val() * 1 + step);
input.get(0).dispatchEvent(new Event('input'));
return;
}
if (input.val() * 1 <= input.attr('minimum') * 1) {
input.val(0);
input.get(0).dispatchEvent(new Event('input'));
return;
}
if (input.val() * 1 <= 1) {
if (input.val() * 1 <= 0) {
return;
}
input.val(input.val() * 1 - step);

View File

@ -35,9 +35,15 @@
align-items: center;
}
#unitAndTradeTerm select {
width: 330px!important;
}
#unitAndTradeTerm .row:nth-child(2) select{
width: 150px!important;
}
#unitAndTradeTerm .col-auto {
width: 330px!important;
}
#unitAndTradeTerm .row:nth-child(2) .col-auto{
width: 150px!important;
}
#unitAndTradeTerm .row:nth-child(2) .col-form-label{
@ -55,10 +61,12 @@
width: 84px!important;
}
.trade-term-img{
width: 400px!important;
width: 1200px!important;
max-width: 90vw!important;
max-height: 95vh!important;
}
.popover{
--bs-popover-max-width: 550px!important;
--bs-popover-max-width: 100vw!important;
}
</style>
<ul class="nav nav-tabs nav-bordered mb-3" role="tablist">
@ -89,14 +97,86 @@
<div class="tab-content">
<div class="tab-pane fade show active" id="tab-basic">
{{--产品信息--}}
<div>
<h6 class="border-bottom pb-3 mb-4">{{ __('common.product_info') }}</h6>
<x-admin-form-input-locale :width="600" name="descriptions.*.name" title="{{ __('common.name') }}" :value="$descriptions" :required="true" />
@hook('admin.product.name.after')
<x-admin::form.row title="{{ __('common.image') }}">
<draggable
element="div"
ghost-class="dragabble-ghost"
class="product-images d-flex flex-wrap"
:list="form.images"
:options="{animation: 200, handle: '.product-item'}"
>
<div v-for="image, index in form.images" :key="index" class="wh-80 rounded-2 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">
<button class="btn btn-danger btn-sm wh-20 p-0" @click="removeImages(index)" type="button"><i class="bi bi-trash"></i></button>
</div>
<img :src="thumbnail(image)" class="img-fluid rounded-2">
<input type="hidden" name="images[]" :value="image">
</div>
<div v-if="!form.images.length" class="d-none"><input type="hidden" name="images[]" value=""></div>
<div class="set-product-img wh-80 rounded-2" @click="addProductImages"><i class="bi bi-plus fs-1 text-muted"></i></div>
</draggable>
<div class="help-text mb-1 mt-1">{{ __('admin/product.image_help') }}</div>
</x-admin::form.row>
<x-admin::form.row title="{{ __('product.video') }}">
<div class="d-flex align-items-end">
<div class="set-product-img wh-80 rounded-2 me-2" @click="addProductVideo">
<i v-if="form.video.path" class="bi bi-play-circle fs-1"></i>
<i v-else class="bi bi-plus fs-1 text-muted"></i>
</div>
<input type="hidden" name="video" :value="form.video.path">
<a v-if="form.video.path" target="_blank" :href="form.video.url">{{ __('common.view') }}</a>
</div>
<div class="help-text mb-1 mt-1">{{ __('admin/product.video_help') }}</div>
</x-admin::form.row>
<x-admin-form-input name="position" :title="__('common.sort_order')" :value="old('position', $product->position ?? '0')" />
@hookwrapper('admin.product.edit.brand')
<x-admin::form.row :title="__('admin/brand.index')">
<input type="text" value="{{ $product->brand->name ?? '' }}" id="brand-autocomplete" class="form-control wp-400 " />
<input type="hidden" name="brand_id" value="{{ old('brand_id', $product->brand_id ?? '') }}" />
</x-admin::form.row>
@endhookwrapper
<x-admin-form-select :title="__('admin/tax_class.index')" name="tax_class_id" :value="old('tax_class_id', $product->tax_class_id ?? '')" :options="$tax_classes" key="id" label="title" />
<x-admin::form.row :title="__('admin/category.index')">
<div class="wp-400 form-control" style="max-height: 240px;overflow-y: auto">
@foreach ($source['categories'] as $_category)
<div class="form-check">
<input class="form-check-input" type="checkbox" name="categories[]" value="{{ $_category->id }}"
id="category-{{ $_category->id }}" {{ in_array($_category->id, old('categories', $category_ids)) ? 'checked' : '' }}>
<label class="form-check-label" for="category-{{ $_category->id }}">
{{ $_category->name }}
</label>
</div>
@endforeach
</div>
</x-admin::form.row>
@hook('admin.product.edit.extra')
</div>
{{--交易信息--}}
<div>
<h5 class="border-bottom pb-3 mb-4">{{ __('product.transaction_info') }}</h5>
{{--产品类型--}}
<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">
<label class="form-check-label" for="active-1">{{ __('common.enable_status') }}</label>
</div>
<div class="form-check form-check-inline">
<input v-model="form.active" class="form-check-input" id="active-0" type="radio" name="active" value="0">
<label class="form-check-label" for="active-0">{{ __('common.disable_status') }}</label>
</div>
</div>
</x-admin::form.row>
{{--计量单位 语言切换弃用 改为下拉框选择;贸易术语 --}}
<div id="unitAndTradeTerm" class="wp-800">
<div id="unitAndTradeTerm">
{{--计量单位--}}
<x-admin::form.row :title="__('product.unit_of_measurement')">
<x-admin::form.row :title="__('product.unit_of_measurement')" required>
<select class="form-select me-3" name="unit" v-model="form.unit">
@foreach ($unit_list as $option)
<option value="{{ $option['title'] }}" {{ $option['title'] == $product->unit ? 'selected': '' }}>{{ $option['title'] }}</option>
@ -105,25 +185,50 @@
</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.trade_term')" name="trade_term" :value="old('trade_term', $product->trade_term ?? '')" :options="$trade_term" key="title" label="title" required />
<x-admin::form.row :title="__('product.trade_term')" required>
<select class="form-select me-3" name="trade_term">
@foreach ($trade_term as $option)
<option value="{{ $option['title'] }}" {{ $option['title'] == old('trade_term', $product->trade_term ?? '') ? 'selected': '' }}>
{{ $option['title'] }}
</option>
@endforeach
</select>
</x-admin::form.row>
<div style="width: 45px;height: 35px;text-align: right;float: left;">
<i class="bi bi-question-circle" id="tradeTerm"></i>
</div>
</div>
{{--销售方式--}}
<div id="salesMethodContent" class="wp-800">
<x-admin::form.row title="{{ __('product.sales_method') }}">
<div class="mb-1 mt-2 wp-200">
<div class="form-check form-check-inline">
<input v-model="form.sales_method" class="form-check-input" id="sales_method-piece" type="radio" name="sales_method" value="piece">
<label class="form-check-label" for="sales_method-piece">{{ __('product.sales_method_piece') }}</label>
<template v-if="form.active == 1" >
<x-admin::form.row title="{{ __('product.sales_method') }}" required>
<div class="mb-1 mt-2 wp-200">
<div class="form-check form-check-inline">
<input v-model="form.sales_method" class="form-check-input" id="sales_method-piece" type="radio" name="sales_method" value="piece">
<label class="form-check-label" for="sales_method-piece">{{ __('product.sales_method_piece') }}</label>
</div>
<div class="form-check form-check-inline">
<input v-model="form.sales_method" class="form-check-input" id="sales_method-batches" type="radio" name="sales_method" value="batches">
<label class="form-check-label" for="sales_method-batches">{{ __('product.sales_method_batches') }}</label>
</div>
</div>
<div class="form-check form-check-inline">
<input v-model="form.sales_method" class="form-check-input" id="sales_method-batches" type="radio" name="sales_method" value="batches">
<label class="form-check-label" for="sales_method-batches">{{ __('product.sales_method_batches') }}</label>
</x-admin::form.row>
</template>
<template v-else>
<x-admin::form.row title="{{ __('product.sales_method') }}">
<div class="mb-1 mt-2 wp-200">
<div class="form-check form-check-inline">
<input v-model="form.sales_method" class="form-check-input" id="sales_method-piece" type="radio" name="sales_method" value="piece">
<label class="form-check-label" for="sales_method-piece">{{ __('product.sales_method_piece') }}</label>
</div>
<div class="form-check form-check-inline">
<input v-model="form.sales_method" class="form-check-input" id="sales_method-batches" type="radio" name="sales_method" value="batches">
<label class="form-check-label" for="sales_method-batches">{{ __('product.sales_method_batches') }}</label>
</div>
</div>
</div>
</x-admin::form.row>
</x-admin::form.row>
</template>
<template v-if="form.sales_method == 'batches'">
<x-admin::form.row :title="__('product.one_batch_is_equal_to')" required>
<div class="d-flex wp-400">
@ -161,12 +266,12 @@
<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 v-if="form.sales_method == 'piece'" style="width: 300px;line-height: 34px;text-align:left;padding-left:5px;">@{{ form.unit }}</div>
<div v-else style="width: 300px;line-height: 34px;text-align:left;padding-left:5px;">@{{ form.unit }}</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>
<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">
@ -305,7 +410,7 @@
<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') }}">
<input type="number" class="form-control me-2 bg-white" v-model="variablesBatch.quantity" placeholder="{{ __('product.quantity') }}">
<button type="button" class="btn btn-primary text-nowrap" @click="batchSettingVariant">{{ __('common.batch_setting') }}</button>
</div>
@ -320,7 +425,7 @@
<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>
<th class="w-min-100">{{ __('product.quantity') }}</th>
</thead>
<tbody>
<tr v-for="(sku, skuIndex) in form.skus" :key="skuIndex">
@ -380,32 +485,62 @@
</div>
</div>
{{--长宽高 重量--}}
<x-admin::form.row :title="__('admin/product.length_width_height')">
<div class="d-flex wp-500">
<input type="text" name="length" placeholder="{{ __('admin/product.length') }}" value="{{ old('weight', $product->length ?? '') }}" class="form-control" style="flex: 0 0 95px" />
<div style="width: 40px;line-height: 34px;text-align:center">CM X</div>
<input type="text" name="width" placeholder="{{ __('admin/product.width') }}" value="{{ old('weight', $product->width ?? '') }}" class="form-control" style="flex: 0 0 95px" />
<div style="width: 40px;line-height: 34px;text-align:center">CM X</div>
<input type="text" name="height" placeholder="{{ __('admin/product.height') }}" value="{{ old('weight', $product->height ?? '') }}" class="form-control" style="flex: 0 0 95px" />
<div style="width: 30px;line-height: 34px;text-align:center">CM</div>
<template v-if="form.active == 1" >
<x-admin::form.row :title="__('admin/product.length_width_height')" required>
<div class="d-flex wp-800">
<input type="text" name="length" placeholder="{{ __('admin/product.length') }}" value="{{ old('weight', $product->length ?? '') }}" class="form-control" style="flex: 0 0 95px" />
<div style="width: 40px;line-height: 34px;text-align:center">CM X</div>
<input type="text" name="width" placeholder="{{ __('admin/product.width') }}" value="{{ old('weight', $product->width ?? '') }}" class="form-control" style="flex: 0 0 95px" />
<div style="width: 40px;line-height: 34px;text-align:center">CM X</div>
<input type="text" name="height" placeholder="{{ __('admin/product.height') }}" value="{{ old('weight', $product->height ?? '') }}" class="form-control" style="flex: 0 0 95px" />
<div style="width: 30px;line-height: 34px;text-align:center">CM</div>
<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>
<x-admin::form.row :title="__('admin/product.weight_text')">
<div class="d-flex wp-500">
<input type="text" name="weight" placeholder="{{ __('admin/product.weight_text') }}" value="{{ old('weight', $product->weight ?? '') }}" class="form-control" style="flex: 0 0 260px" />
<select class="form-select ms-4 bg-white wp-100" name="weight_class">
@foreach ($weight_classes as $item)
<option value="{{ $item }}" {{ $product->weight_class == $item ? 'selected' : '' }}>{{ __('product.' . $item) }}</option>
@endforeach
</select>
<div v-if="form.sales_method == 'piece'" style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
<div v-else style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
</div>
</x-admin::form.row>
<x-admin::form.row :title="__('admin/product.weight_text')" required>
<div class="d-flex wp-800">
<input type="text" name="weight" placeholder="{{ __('admin/product.weight_text') }}" value="{{ old('weight', $product->weight ?? '') }}" class="form-control" style="flex: 0 0 260px" />
<select class="form-select ms-4 bg-white wp-100" name="weight_class">
@foreach ($weight_classes as $item)
<option value="{{ $item }}" {{ $product->weight_class == $item ? 'selected' : '' }}>{{ __('product.' . $item) }}</option>
@endforeach
</select>
<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>
<div v-if="form.sales_method == 'piece'" style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
<div v-else style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
</div>
</x-admin::form.row>
</template>
<template v-else>
<x-admin::form.row :title="__('admin/product.length_width_height')">
<div class="d-flex wp-800">
<input type="text" name="length" placeholder="{{ __('admin/product.length') }}" value="{{ old('weight', $product->length ?? '') }}" class="form-control" style="flex: 0 0 95px" />
<div style="width: 40px;line-height: 34px;text-align:center">CM X</div>
<input type="text" name="width" placeholder="{{ __('admin/product.width') }}" value="{{ old('weight', $product->width ?? '') }}" class="form-control" style="flex: 0 0 95px" />
<div style="width: 40px;line-height: 34px;text-align:center">CM X</div>
<input type="text" name="height" placeholder="{{ __('admin/product.height') }}" value="{{ old('weight', $product->height ?? '') }}" class="form-control" style="flex: 0 0 95px" />
<div style="width: 30px;line-height: 34px;text-align:center">CM</div>
<div v-if="form.sales_method == 'piece'" style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
<div v-else style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
</div>
</x-admin::form.row>
<x-admin::form.row :title="__('admin/product.weight_text')">
<div class="d-flex wp-800">
<input type="text" name="weight" placeholder="{{ __('admin/product.weight_text') }}" value="{{ old('weight', $product->weight ?? '') }}" class="form-control" style="flex: 0 0 260px" />
<select class="form-select ms-4 bg-white wp-100" name="weight_class">
@foreach ($weight_classes as $item)
<option value="{{ $item }}" {{ $product->weight_class == $item ? 'selected' : '' }}>{{ __('product.' . $item) }}</option>
@endforeach
</select>
<div v-if="form.sales_method == 'piece'" style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
<div v-else style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
</div>
</x-admin::form.row>
</template>
{{--最小起订量--}}
{{-- 未开启根据数量设置价格、直接下单产品 --}}
<template v-if="form.price_setting === 'sku' && form.active == 1">
@ -432,8 +567,8 @@
<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 wp-100" 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 v-if="form.sales_method == 'piece'" style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
<div v-else style="width: 300px;line-height: 34px;text-align:left;padding-left: 5px;">@{{ form.unit }}</div>
</div>
</x-admin::form.row>
</template>
@ -441,13 +576,27 @@
@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 ?? '')" />
<template v-if="form.active == 1" >
<x-admin-form-input required name="skus[0][model]" :title="__('admin/product.model')" :value="old('skus.0.model', $product->skus[0]->model ?? '')" />
<x-admin-form-input required name="skus[0][quantity]" type="number" :title="__('product.quantity')" :value="old('skus.0.quantity', $product->skus[0]->quantity ?? '')" />
</template>
<template v-else>
<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][quantity]" type="number" :title="__('product.quantity')" :value="old('skus.0.quantity', $product->skus[0]->quantity ?? '')" />
</template>
{{--<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="">
@ -457,88 +606,6 @@
</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') }}"
:value="$descriptions" :required="true" />
@hook('admin.product.name.after')
<x-admin::form.row title="{{ __('common.image') }}">
<draggable
element="div"
ghost-class="dragabble-ghost"
class="product-images d-flex flex-wrap"
:list="form.images"
:options="{animation: 200, handle: '.product-item'}"
>
<div v-for="image, index in form.images" :key="index" class="wh-80 rounded-2 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">
<button class="btn btn-danger btn-sm wh-20 p-0" @click="removeImages(index)" type="button"><i class="bi bi-trash"></i></button>
</div>
<img :src="thumbnail(image)" class="img-fluid rounded-2">
<input type="hidden" name="images[]" :value="image">
</div>
<div v-if="!form.images.length" class="d-none"><input type="hidden" name="images[]" value=""></div>
<div class="set-product-img wh-80 rounded-2" @click="addProductImages"><i class="bi bi-plus fs-1 text-muted"></i></div>
</draggable>
<div class="help-text mb-1 mt-1">{{ __('admin/product.image_help') }}</div>
</x-admin::form.row>
<x-admin::form.row title="{{ __('product.video') }}">
<div class="d-flex align-items-end">
<div class="set-product-img wh-80 rounded-2 me-2" @click="addProductVideo">
<i v-if="form.video.path" class="bi bi-play-circle fs-1"></i>
<i v-else class="bi bi-plus fs-1 text-muted"></i>
</div>
<input type="hidden" name="video" :value="form.video.path">
<a v-if="form.video.path" target="_blank" :href="form.video.url">{{ __('common.view') }}</a>
</div>
<div class="help-text mb-1 mt-1">{{ __('admin/product.video_help') }}</div>
</x-admin::form.row>
<x-admin-form-input name="position" :title="__('common.sort_order')" :value="old('position', $product->position ?? '0')" />
@hookwrapper('admin.product.edit.brand')
<x-admin::form.row :title="__('admin/brand.index')">
<input type="text" value="{{ $product->brand->name ?? '' }}" id="brand-autocomplete" class="form-control wp-400 " />
<input type="hidden" name="brand_id" value="{{ old('brand_id', $product->brand_id ?? '') }}" />
</x-admin::form.row>
@endhookwrapper
<x-admin-form-select :title="__('admin/tax_class.index')" name="tax_class_id" :value="old('tax_class_id', $product->tax_class_id ?? '')" :options="$tax_classes" key="id" label="title" />
<x-admin::form.row :title="__('admin/category.index')">
<div class="wp-400 form-control" style="max-height: 240px;overflow-y: auto">
@foreach ($source['categories'] as $_category)
<div class="form-check">
<input class="form-check-input" type="checkbox" name="categories[]" value="{{ $_category->id }}"
id="category-{{ $_category->id }}" {{ in_array($_category->id, old('categories', $category_ids)) ? 'checked' : '' }}>
<label class="form-check-label" for="category-{{ $_category->id }}">
{{ $_category->name }}
</label>
</div>
@endforeach
</div>
</x-admin::form.row>
{{--状态--}}
<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">
<label class="form-check-label" for="active-1">{{ __('common.enable_status') }}</label>
</div>
<div class="form-check form-check-inline">
<input v-model="form.active" class="form-check-input" id="active-0" type="radio" name="active" value="0">
<label class="form-check-label" for="active-0">{{ __('common.disable_status') }}</label>
</div>
</div>
</x-admin::form.row>
@hook('admin.product.edit.extra')
</div>
<div class="tab-pane fade" id="tab-descriptions">
@ -1313,7 +1380,7 @@
$('input[name="brand_id"]').val(item['value']);
}
});
$('#tradeTerm').popover({
$('#tradeTerm,.trade-term-img').popover({
trigger : 'hover',//鼠标以上时触发弹出提示框
html: true,//开启html 为true的话data-content里就能放html代码了
placement: 'bottom',

View File

@ -16,6 +16,15 @@ $(document).on('click', '.quantity-wrap .right i', function(event) {
let piece_to_batch = input.attr('piece_to_batch') || 1;// 按批卖,每批等于多少件
let step = sales_method === 'piece' ? parseInt(1) : parseInt(piece_to_batch);// 点击后加减数量
let res_num = $(this).hasClass('bi-chevron-up') ? input.val() * 1 + step : input.val() * 1 - step;
if(sales_method === 'batches' && res_num%step !== 0){
input.val(0)
input.get(0).dispatchEvent(new Event('input'));
return;
}
if ($(this).hasClass('bi-chevron-up')) {
input.val(input.val() * 1 + step)
input.get(0).dispatchEvent(new Event('input'));

View File

@ -28,9 +28,9 @@ return [
'all' => 'All',
'status' => 'Status',
'enable' => 'Enable',
'enable_status' => 'Ordering of products',
'enable_status' => 'Can Place Orders Wholesale',//Ordering of products
'disable' => 'Disable',
'disable_status' => 'Indirect ordering of products',
'disable_status' => 'Customization',//Indirect ordering of products
'enabled' => 'Enabled',
'disabled' => 'Disabled',
'home' => 'Home',
@ -100,7 +100,7 @@ return [
'contacts' => 'Contacts',
'content' => 'Content',
'sku' => 'Sku',
'product_info' => 'Products Information',
'order' => [
'unpaid' => 'Unpaid',
'paid' => 'Paid',

View File

@ -18,7 +18,7 @@ return [
'brand' => 'Brand',
'category' => 'Category',
'model' => 'Model',
'quantity' => 'Quantity',
'quantity' => 'Stock',
'kg' => 'Kilogram',
'g' => 'Gram',
'oz' => 'Ounce',
@ -36,7 +36,7 @@ return [
'sales_method_batches' => 'Sold in batches',
'one_batch_is_equal_to' => 'one batch is equal to',
'piece' => 'piece',
'batches' => 'batches',
'batches' => 'batch',
'pieces_per_batch' => ':num :unit per batch',
'sales_method_piece_unit' => 'Sell by piece',
'total_num' => ':num :unit in total',

View File

@ -101,7 +101,7 @@ return [
'sku' => 'Sku',
'logistics' => '物流',
'product_info' => '产品信息',
'order' => [
'unpaid' => '待支付',
'paid' => '已支付',

View File

@ -122,6 +122,34 @@
.other-amount-format{
/*margin-right: 100px;*/
}
.trade-term-img{
width: 1200px!important;
max-width: 90vw!important;
max-height: 95vh!important;
}
.popover{
--bs-popover-max-width: 100vw!important;
}
.sku-min-order {
position: absolute;
bottom: -20px;
left: 0;
}
.num-price-content{
border-top: 1px solid #aaaaaa;
border-bottom: 1px solid #aaaaaa;
padding: 10px;
position: relative;
@if($product['sales_method'] == 'batches')
padding-bottom: 30px!important;
@endif
}
.num-min-order{
position: absolute;
bottom: 5px;
left: 90px;
}
</style>
<div class="container {{ request('iframe') ? 'pt-4' : '' }}" id="product-app" v-cloak>
<div class="row mb-5 mt-3 mt-md-0" id="product-top">
@ -167,47 +195,71 @@
<h1 class="mb-4 product-name">{{ $product['name'] }}</h1>
@endhookwrapper
@hookwrapper('product.detail.price')
<div class="price-wrap d-flex align-items-end" v-if="price_setting === 'sku'">
<div class="price-wrap d-flex align-items-end" v-if="price_setting === 'sku'" style="position: relative;">
<div class="new-price fs-1 lh-1 fw-bold me-2">{{$product['trade_term'] ?? 'DAP'}}</div>
<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">-</div>
<div class="old-price fs-1 lh-1 fw-bold me-2" v-if="product.price != product.origin_price && product.origin_price !== 0">@{{ product.origin_price_format }}</div>
@if($product['unit'])
{{--@if($product['unit'])
<div style="font-size: 15px;color: #999999;">/ {{explode('/',$product['unit'])[0]}}&nbsp;|</div>
@endif
<div v-if="minimum_order > 0" style="font-size: 15px;color: #101010;">
@endif--}}
{{--<div v-if="minimum_order > 0" style="font-size: 15px;color: #101010;">
@if($product['sales_method'] == 'piece')
&nbsp;{{ $product['minimum_order'] }} {{$product['unit']}}<span style="color: #999999;">({{__('product.minimum_order')}})</span>
@else
&nbsp;{{ ($product['piece_to_batch'] * $product['minimum_order']) }} {{$product['unit']}}<span style="color: #999999;">({{__('product.minimum_order')}})</span>
@endif
</div>--}}
@if($product['sales_method'] == 'batches')
<div class="sku-min-order">
{{__('product.minimum_order')}}@{{ minimum_order }}
{{ __('product.batches') }}
1 {{ __('product.batches') }} = {{ $product['piece_to_batch'] }} {{ strpos($product['unit'], '/') !== false ? explode('/',$product['unit'])[0] : $product['unit']}} in total
</div>
@endif
</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" style="color: #1a9bff;font-size: 18px;height: 54px;line-height: 54px;">{{$product['trade_term'] ?? 'DAP'}}</div>
<div class="num-price-content price-wrap d-flex align-items-end" v-if="price_setting === 'num'">
<div class="item" style="color: #1a9bff;font-size: 18px;height: 54px;line-height: 54px;display: inline-flex;">
{{$product['trade_term'] ?? 'DAP'}}
<div style="width: 25px;height: 54px;text-align: center;float: left;font-size: 15px;">
<i class="bi bi-question-circle" id="tradeTerm"></i>
</div>
</div>
<div class="item" v-for="(item,index) in numPrices" style="flex: 1">
<div class="num" v-if="index < numPrices.length - 1" style="
white-space: nowrap;
color: #777777;
font-size: 18px;
margin-bottom: 5px;
">@{{ item.num }} - @{{ numPrices[index + 1].num - 1 }} sets
">@{{ item.num }} - @{{ numPrices[index + 1].num - 1 }} {{ strpos($product['unit'], '/') !== false ? explode('/',$product['unit'])[1] : $product['unit']}}
</div>
<div class="num" v-else-if="item.num" style="
white-space: nowrap;
color: #777777;
font-size: 18px;
margin-bottom: 5px;
">>= @{{ item.num }} sets
">>= @{{ item.num }} {{ strpos($product['unit'], '/') !== false ? explode('/',$product['unit'])[1] : $product['unit']}}
</div>
<div class="price">
<div class="new-price fs-3 lh-1 fw-bold me-2">@{{ item.price_format }}</div>
</div>
</div>
@if($product['sales_method'] == 'batches')
<div class="num-min-order">
{{__('product.minimum_order')}}@{{ minimum_order }}
{{ __('product.batches') }}
1 {{ __('product.batches') }} = {{ $product['piece_to_batch'] }} {{ strpos($product['unit'], '/') !== false ? explode('/',$product['unit'])[0] : $product['unit']}} in total
</div>
@endif
</div>
@endhookwrapper
<div class="stock-and-sku mb-4">
<div class="d-flex" >
<span class="title text-muted" style="width: auto!important;">{{__('product.product_type')}}</span>
{{ $product['active'] == 1 ? __('common.enable_status') : __('common.disable_status') }}
</div>
@hookwrapper('product.detail.quantity')
<div class="d-flex">
<span class="title text-muted">{{ __('product.quantity') }}</span>
@ -237,23 +289,23 @@
<div class="d-flex" v-if="product.model"><span class="title text-muted">{{ __('shop/products.model') }}</span> @{{ product.model }}</div>
@endhookwrapper
<div v-if="minimum_order > 0" class="d-flex" >
{{--<div v-if="minimum_order > 0" class="d-flex" >
<span class="title text-muted" style="width: auto!important;">{{ __('product.sales_method') }}</span>
@if($product['sales_method'] == 'piece')
{{ __('product.sales_method_piece_unit',['unit'=>$product['unit']]) }}
@else
{{ __('product.sales_method_batches') }}{{ __('product.pieces_per_batch',['num'=>$product['piece_to_batch'],'unit'=>$product['unit']]) }}
@endif
</div>
</div>--}}
<div class="d-flex" >
{{--<div class="d-flex" >
<span class="title text-muted" style="width: auto!important;">{{__('product.minimum_order')}}</span>@{{ minimum_order }}
@if($product['sales_method'] == 'piece')
{{ $product['unit'] }}
@else
{{ __('product.batches') }}{{__('product.total_num',['num'=>($product['piece_to_batch'] * $product['minimum_order']),'unit'=>$product['unit']])}}
@endif
</div>
</div>--}}
{{--@if(!empty($product['unit']))
<div class="d-flex">
@ -993,12 +1045,19 @@
},
// 单规格 - 购买数量改变
singleQuantityChange(event){
let multiple_error = '{{ __('product.multiple_error') }}';
let _this = this;
let stock = _this.product.quantity || 0;// 库存
let quantity = event.target.value || 0;// 购买数量
// 判断是否超过库存
quantity = quantity > stock ? stock : quantity;// 不能超过库存
_this.quantity = typeof quantity != 'number' ? quantity.replace(/\D/g,'') : quantity;
// 判断:如果是批量购买 只能为N的倍数
let multiple_num = _this.sales_method === 'batches' ? parseInt(_this.piece_to_batch) : 1;
if(parseInt(quantity % multiple_num) != 0){
layer.msg(multiple_error.replace(':num',multiple_num));
return;
}
_this.$forceUpdate();
},
@ -1118,6 +1177,14 @@
$(document).ready(function () {
$('#zoom').trigger('zoom.destroy');
$('#zoom').zoom({url: $('#swiper a').attr('data-zoom-image')});
$('#tradeTerm').popover({
trigger : 'hover',//鼠标以上时触发弹出提示框
html: true,//开启html 为true的话data-content里就能放html代码了
placement: 'bottom',
delay: { "show": 0, "hide": 100 },
content:"<img class='trade-term-img' src='image/trade_term.png'>"
});
});
const selectedVariantsIndex = app.selectedVariantsIndex;