diff --git a/beike/Admin/Http/Controllers/LogisticsController.php b/beike/Admin/Http/Controllers/LogisticsController.php new file mode 100644 index 00000000..f4677e58 --- /dev/null +++ b/beike/Admin/Http/Controllers/LogisticsController.php @@ -0,0 +1,221 @@ +all(); + if (! isset($requestData['sort'])) { + $requestData['sort'] = 'logistics.updated_at'; + } + $productList = LogisticsRepo::list($requestData); + $products = LogisticsResource::collection($productList); + $productsFormat = $products->jsonSerialize(); + + $data = [ + 'categories' => CategoryRepo::flatten(locale()), + 'products_format' => $productsFormat, + 'products' => $products, + 'type' => 'products', + ]; + + $data = hook_filter('admin.product.index.data', $data); + + if ($request->expectsJson()) { + return $productsFormat; + } + + return view('admin::pages.products.index', $data); + } + + public function trashed(Request $request) + { + $requestData = $request->all(); + $requestData['trashed'] = true; + $productList = LogisticsRepo::list($requestData); + $products = LogisticsResource::collection($productList); + $productsFormat = $products->jsonSerialize(); + + $data = [ + 'categories' => CategoryRepo::flatten(locale()), + 'products_format' => $productsFormat, + 'products' => $products, + 'type' => 'trashed', + ]; + + $data = hook_filter('admin.product.trashed.data', $data); + + if ($request->expectsJson()) { + return $products; + } + + return view('admin::pages.products.index', $data); + } + + public function create(Request $request) + { + return $this->form($request, new Logistics()); + } + + public function store(LogisticsRequest $request) + { + try { + $requestData = $request->all(); + $product = (new LogisticsService)->create($requestData); + + $data = [ + 'request_data' => $requestData, + 'product' => $product, + ]; + + hook_action('admin.product.store.after', $data); + + return redirect()->to(admin_route('products.index')) + ->with('success', trans('common.created_success')); + } catch (\Exception $e) { + return redirect(admin_route('products.create')) + ->withInput() + ->withErrors(['error' => $e->getMessage()]); + } + } + + public function edit(Request $request, Logistics $product) + { + return $this->form($request, $product); + } + + public function update(LogisticsRequest $request, Logistics $product) + { + try { + $requestData = $request->all(); + $product = (new LogisticsService)->update($product, $requestData); + + $data = [ + 'request_data' => $requestData, + 'product' => $product, + ]; + hook_action('admin.product.update.after', $data); + + return redirect()->to($this->getRedirect())->with('success', trans('common.updated_success')); + } catch (\Exception $e) { + return redirect(admin_route('products.edit', $product))->withErrors(['error' => $e->getMessage()]); + } + } + + public function copy(LogisticsRequest $request, Logistics $product) + { + try { + $product = (new LogisticsService)->copy($product); + + $data = [ + 'product' => $product, + ]; + hook_action('admin.product.copy.after', $data); + + return json_success(trans('common.copy_success'), []); + } catch (\Exception $e) { + return json_encode($e->getMessage()); + } + } + + public function destroy(Request $request, Logistics $product) + { + $product->delete(); + hook_action('admin.product.destroy.after', $product); + + return json_success(trans('common.deleted_success')); + } + + public function restore(Request $request) + { + $productId = $request->id ?? 0; + Logistics::withTrashed()->find($productId)->restore(); + + hook_action('admin.product.restore.after', $productId); + + return ['success' => true]; + } + + protected function form(Request $request, Logistics $logistics) + { + + $logistics = hook_filter('admin.logistics.form.product', $logistics); + + $data = [ + 'logistics' => $logistics, + 'languages' => LanguageRepo::all(), + 'weight_classes' => Weight::getWeightUnits(), + '_redirect' => $this->getRedirect(), + ]; + + $data = hook_filter('admin.logistics.form.data', $data); + + return view('admin::pages.logistics.form.form', $data); + } + + public function name(int $id) + { + $name = LogisticsRepo::getName($id); + + return json_success(trans('common.get_success'), $name); + } + + /** + * 根据商品ID批量获取商品名称 + * + * @param Request $request + * @return array + */ + public function getNames(Request $request): array + { + $productIds = explode(',', $request->get('product_ids')); + $name = LogisticsRepo::getNames($productIds); + + return json_success(trans('common.get_success'), $name); + } + + public function autocomplete(Request $request) + { + $products = LogisticsRepo::autocomplete($request->get('name') ?? ''); + + return json_success(trans('common.get_success'), $products); + } + + public function updateStatus(Request $request) + { + LogisticsRepo::updateStatusByIds($request->get('ids'), $request->get('status')); + + return json_success(trans('common.updated_success'), []); + } + + public function destroyByIds(Request $request) + { + $productIds = $request->get('ids'); + LogisticsRepo::DeleteByIds($productIds); + + hook_action('admin.product.destroy_by_ids.after', $productIds); + + return json_success(trans('common.deleted_success'), []); + } + + public function trashedClear() + { + LogisticsRepo::forceDeleteTrashed(); + } +} diff --git a/beike/Admin/Routes/admin.php b/beike/Admin/Routes/admin.php index a3df2130..9abe22f0 100644 --- a/beike/Admin/Routes/admin.php +++ b/beike/Admin/Routes/admin.php @@ -219,6 +219,10 @@ Route::prefix($adminName) Route::middleware('can:products_update')->put('products/{product}', [Controllers\ProductController::class, 'update'])->name('products.update'); Route::middleware('can:products_delete')->delete('products/{product}', [Controllers\ProductController::class, 'destroy'])->name('products.destroy'); + // 物流 + Route::middleware('can:logistics_index')->get('logistics', [Controllers\LogisticsController::class, 'index'])->name('logistics.index'); + Route::middleware('can:logistics_create')->get('logistics/create', [Controllers\LogisticsController::class, 'create'])->name('logistics.create'); + // 区域组 Route::middleware('can:regions_index')->get('regions', [Controllers\RegionController::class, 'index'])->name('regions.index'); Route::middleware('can:regions_create')->post('regions', [Controllers\RegionController::class, 'store'])->name('regions.store'); diff --git a/beike/Admin/View/Components/Sidebar.php b/beike/Admin/View/Components/Sidebar.php index 3459d07b..5334f8f0 100644 --- a/beike/Admin/View/Components/Sidebar.php +++ b/beike/Admin/View/Components/Sidebar.php @@ -124,6 +124,13 @@ class Sidebar extends Component 'prefixes' => $this->getInquirySubPrefix(), 'children' => $this->getInquirySubRoutes(), ], + [ + 'route' => 'logistics.index', + 'title' => trans('admin/common.logistics'), + 'icon' => 'bi bi-gear', + 'prefixes' => $this->getInquirySubPrefix(), + 'children' => $this->getInquirySubRoutes(), + ], ]; return hook_filter('admin.components.sidebar.menus', $menus); diff --git a/beike/Models/Logistics.php b/beike/Models/Logistics.php new file mode 100644 index 00000000..edc019ed --- /dev/null +++ b/beike/Models/Logistics.php @@ -0,0 +1,19 @@ +belongsTo(country::class, 'country_id', 'id'); + } +} diff --git a/beike/Repositories/LogisticsRepo.php b/beike/Repositories/LogisticsRepo.php new file mode 100644 index 00000000..99629e66 --- /dev/null +++ b/beike/Repositories/LogisticsRepo.php @@ -0,0 +1,420 @@ + + * @created 2022-06-23 11:19:23 + * @modified 2022-06-23 11:19:23 + */ + +namespace Beike\Repositories; + +use Beike\Models\Attribute; +use Beike\Models\AttributeValue; +use Beike\Models\Logistics; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Collection; +use Illuminate\Database\Eloquent\HigherOrderBuilderProxy; +use Illuminate\Http\Resources\Json\AnonymousResourceCollection; +use Illuminate\Support\Facades\DB; + +class LogisticsRepo +{ + private static $allLogisticssWithName; + + /** + * 获取商品详情 + */ + public static function getLogisticsDetail($product) + { + if (is_int($product)) { + $product = Logistics::query()->findOrFail($product); + } + $product->load('description', 'skus', 'masterSku', 'brand', 'relations', 'numPrices');//, 'price_setting', 'numPrices'); + + hook_filter('repo.product.get_detail', $product); + + return $product; + } + + /** + * 通过单个或多个商品分类获取商品列表 + * + * @param $categoryId + * @param $filterData + * @return LengthAwarePaginator + */ + public static function getLogisticssByCategory($categoryId, $filterData) + { + $builder = static::getBuilder(array_merge(['category_id' => $categoryId, 'active' => 1], $filterData)); + + return $builder->with('inCurrentWishlist') + ->paginate($filterData['per_page'] ?? perPage()) + ->withQueryString(); + } + + /** + * 通过商品ID获取商品列表 + * @param $productIds + * @return AnonymousResourceCollection + */ + public static function getLogisticssByIds($productIds): AnonymousResourceCollection + { + if (! $productIds) { + return LogisticsSimple::collection(new Collection()); + } + $builder = static::getBuilder(['product_ids' => $productIds])->whereHas('masterSku'); + $products = $builder->with('inCurrentWishlist')->get(); + + return LogisticsSimple::collection($products); + } + + /** + * 获取商品筛选对象 + * + * @param array $filters + * @return Builder + * @throws \Exception + */ + public static function getBuilder(array $filters = []): Builder + { + $builder = Logistics::query()->with('description', 'skus', 'masterSku', 'attributes'); + + $builder->leftJoin('product_descriptions as pd', function ($build) { + $build->whereColumn('pd.product_id', 'products.id') + ->where('locale', locale()); + }); + $builder->leftJoin('product_skus', function ($build) { + $build->whereColumn('product_skus.product_id', 'products.id') + ->where('is_default', 1) + ->where('product_skus.deleted_at', null); + }); + $builder->select(['products.*', 'pd.name', 'pd.content', 'pd.meta_title', 'pd.meta_description', 'pd.meta_keywords', 'pd.name', 'product_skus.price']); + + if (isset($filters['category_id'])) { + $builder->whereHas('categories', function ($query) use ($filters) { + if (is_array($filters['category_id'])) { + $query->whereIn('category_id', $filters['category_id']); + } else { + $query->where('category_id', $filters['category_id']); + } + }); + } + + $productIds = $filters['product_ids'] ?? []; + if ($productIds) { + $builder->whereIn('products.id', $productIds); + $productIds = implode(',', $productIds); + $builder->orderByRaw("FIELD(products.id, {$productIds})"); + } + + // attr 格式:attr=10:10,13|11:34,23|3:4 + if (isset($filters['attr']) && $filters['attr']) { + $attributes = self::parseFilterParamsAttr($filters['attr']); + foreach ($attributes as $attribute) { + $builder->whereHas('attributes', function ($query) use ($attribute) { + $query->where('attribute_id', $attribute['attr']) + ->whereIn('attribute_value_id', $attribute['value']); + }); + } + } + + if (isset($filters['sku']) || isset($filters['model'])) { + $builder->whereHas('skus', function ($query) use ($filters) { + if (isset($filters['sku'])) { + $query->where('sku', 'like', "%{$filters['sku']}%"); + } + if (isset($filters['model'])) { + $query->where('model', 'like', "%{$filters['model']}%"); + } + }); + } + + if (isset($filters['price']) && $filters['price']) { + $builder->whereHas('skus', function ($query) use ($filters) { + // price 格式:price=30-100 + $prices = explode('-', $filters['price']); + if (! $prices[1]) { + $query->where('price', '>', $prices[0] ?: 0)->where('is_default', 1); + } else { + $query->whereBetween('price', [$prices[0] ?? 0, $prices[1]])->where('is_default', 1); + } + }); + } + + if (isset($filters['name'])) { + $builder->where('pd.name', 'like', "%{$filters['name']}%"); + } + + $keyword = trim($filters['keyword'] ?? ''); + if ($keyword) { + $keywords = explode(' ', $keyword); + $keywords = array_unique($keywords); + $keywords = array_diff($keywords, ['']); + $builder->where(function (Builder $query) use ($keywords) { + $query->whereHas('skus', function (Builder $query) use ($keywords) { + $keywordFirst = array_shift($keywords); + $query->where('sku', 'like', "%{$keywordFirst}%") + ->orWhere('model', 'like', "%{$keywordFirst}%"); + + foreach ($keywords as $keyword) { + $query->orWhere('sku', 'like', "%{$keyword}%") + ->orWhere('model', 'like', "%{$keyword}%"); + } + }); + foreach ($keywords as $keyword) { + $query->orWhere('pd.name', 'like', "%{$keyword}%"); + } + }); + } + + if (isset($filters['created_start'])) { + $builder->where('products.created_at', '>', $filters['created_start']); + } + + if (isset($filters['created_end'])) { + $builder->where('products.created_at', '>', $filters['created_end']); + } + + if (isset($filters['active'])) { + $builder->where('active', (int) $filters['active']); + } + + // 回收站 + if (isset($filters['trashed']) && $filters['trashed']) { + $builder->onlyTrashed(); + } + + $sort = $filters['sort'] ?? 'products.position'; + $order = $filters['order'] ?? 'desc'; + $builder->orderBy($sort, $order); + + return hook_filter('repo.product.builder', $builder); + } + + public static function parseFilterParamsAttr($attr) + { + $attributes = explode('|', $attr); + $attributes = array_map(function ($item) { + $itemArr = explode(':', $item); + if (count($itemArr) != 2) { + throw new \Exception('Params attr has an error format!'); + } + + return [ + 'attr' => $itemArr[0], + 'value' => explode(',', $itemArr[1]), + ]; + }, $attributes); + + return $attributes; + } + + public static function getFilterAttribute($data): array + { + $builder = static::getBuilder(array_diff_key($data, ['attr' => '', 'price' => ''])) + ->select(['pa.attribute_id', 'pa.attribute_value_id']) + ->with(['attributes.attribute.description', 'attributes.attribute_value.description']) + ->leftJoin('product_attributes as pa', 'pa.product_id', 'products.id') + ->whereNotNull('pa.attribute_id') + ->distinct() + ->reorder('pa.attribute_id'); + + if ($attributesIds = system_setting('base.multi_filter', [])['attribute'] ?? []) { + $builder->whereIn('pa.attribute_id', $attributesIds); + } + + $productAttributes = $builder->get()->toArray(); + + $attributeMap = array_column(Attribute::query()->with('description')->orderBy('sort_order')->get()->toArray(), null, 'id'); + $attributeValueMap = array_column(AttributeValue::query()->with('description')->get()->toArray(), null, 'id'); + + $attributes = isset($data['attr']) ? self::parseFilterParamsAttr($data['attr']) : []; + $attributeMaps = array_column($attributes, 'value', 'attr'); + $results = []; + foreach ($productAttributes as $item) { + if (! isset($attributeMap[$item['attribute_id']]) || ! isset($attributeValueMap[$item['attribute_value_id']])) { + continue; + } + $attribute = $attributeMap[$item['attribute_id']]; + $attributeValue = $attributeValueMap[$item['attribute_value_id']]; + if (! isset($results[$item['attribute_id']])) { + $results[$item['attribute_id']] = [ + 'id' => $attribute['id'], + 'name' => $attribute['description']['name'], + ]; + } + if (! isset($results[$item['attribute_id']]['values'][$item['attribute_value_id']])) { + $results[$item['attribute_id']]['values'][$item['attribute_value_id']] = [ + 'id' => $attributeValue['id'], + 'name' => $attributeValue['description']['name'], + 'selected' => in_array($attributeValue['id'], $attributeMaps[$attribute['id']] ?? []), + ]; + } + } + + $results = array_map(function ($item) { + $item['values'] = array_values($item['values']); + + return $item; + }, $results); + + return array_values($results); + } + + public static function getFilterPrice($data) + { + $selectPrice = $data['price'] ?? '-'; + // unset($data['price']); + $builder = static::getBuilder(['category_id' => $data['category_id']])->leftJoin('product_skus as ps', 'products.id', 'ps.product_id') + ->where('ps.is_default', 1); + $min = $builder->min('ps.price'); + $max = $builder->max('ps.price'); + + $priceArr = explode('-', $selectPrice); + $selectMin = $priceArr[0]; + $selectMax = $priceArr[1]; + + return [ + 'min' => $min, + 'max' => $max, + 'select_min' => ($selectMin && $selectMin > $min) ? $selectMin : $min, + 'select_max' => ($selectMax && $selectMax < $max) ? $selectMax : $max, + ]; + } + + public static function list($data = []) + { + return static::getBuilder($data)->paginate($data['per_page'] ?? 20); + } + + public static function autocomplete($name) + { + $products = Logistics::query()->with('description') + ->whereHas('description', function ($query) use ($name) { + $query->where('name', 'like', "%{$name}%"); + })->limit(10)->get(); + $results = []; + foreach ($products as $product) { + $results[] = [ + 'id' => $product->id, + 'name' => $product->description->name, + 'status' => $product->active, + 'image' => $product->image, + ]; + } + + return $results; + } + + /** + * 获取商品ID获取单个商品名称 + * + * @param $id + * @return HigherOrderBuilderProxy|mixed|string + */ + public static function getNameById($id) + { + $product = Logistics::query()->find($id); + if ($product) { + return $product->description->name; + } + + return ''; + } + + /** + * 通过商品ID获取商品名称 + * @param $id + * @return mixed|string + */ + public static function getName($id) + { + return self::getNameById($id); + } + + /** + * 获取所有商品ID和名称列表 + * + * @return array|null + */ + public static function getAllLogisticssWithName(): ?array + { + if (self::$allLogisticssWithName !== null) { + return self::$allLogisticssWithName; + } + + $items = []; + $products = static::getBuilder()->select('id')->get(); + foreach ($products as $product) { + $items[$product->id] = [ + 'id' => $product->id, + 'name' => $product->description->name ?? '', + ]; + } + + return self::$allLogisticssWithName = $items; + } + + /** + * @param $productIds + * @return array + */ + public static function getNames($productIds): array + { + $products = self::getListByLogisticsIds($productIds); + + return $products->map(function ($product) { + return [ + 'id' => $product->id, + 'name' => $product->description->name ?? '', + ]; + })->toArray(); + } + + /** + * 通过商品ID获取商品列表 + * @return array|Builder[]|Collection + */ + public static function getListByLogisticsIds($productIds) + { + if (empty($productIds)) { + return []; + } + $products = Logistics::query() + ->with(['description']) + ->whereIn('id', $productIds) + ->orderByRaw(DB::raw('FIELD(id, ' . implode(',', $productIds) . ')')) + ->get(); + + return $products; + } + + public static function DeleteByIds($ids) + { + Logistics::query()->whereIn('id', $ids)->delete(); + } + + public static function updateStatusByIds($ids, $status) + { + Logistics::query()->whereIn('id', $ids)->update(['active' => $status]); + } + + public static function forceDeleteTrashed() + { + $products = Logistics::onlyTrashed(); + + $productsIds = $products->pluck('id')->toArray(); + + LogisticsRelation::query()->whereIn('product_id', $productsIds)->orWhere('relation_id', $productsIds)->delete(); + LogisticsAttribute::query()->whereIn('product_id', $productsIds)->delete(); + LogisticsCategory::query()->whereIn('product_id', $productsIds)->delete(); + LogisticsSku::query()->whereIn('product_id', $productsIds)->delete(); + LogisticsDescription::query()->whereIn('product_id', $productsIds)->delete(); + + $products->forceDelete(); + } +} diff --git a/database/factories/LogisticsFactory.php b/database/factories/LogisticsFactory.php new file mode 100644 index 00000000..c36239aa --- /dev/null +++ b/database/factories/LogisticsFactory.php @@ -0,0 +1,24 @@ + 0, + 'image' => 'path/to/image.jpg', + 'video' => '', + 'sort_order' => 0, + 'status' => true, + 'variable' => '', + ]; + } +} diff --git a/resources/beike/admin/views/pages/logistics/form/form.blade.php b/resources/beike/admin/views/pages/logistics/form/form.blade.php new file mode 100644 index 00000000..9c9ece0d --- /dev/null +++ b/resources/beike/admin/views/pages/logistics/form/form.blade.php @@ -0,0 +1,1248 @@ +@extends('admin::layouts.master') + +@section('title', __('admin/product.logistics_show')) + +@section('body-class', 'page-product-form') + +@push('header') + + + +@endpush + +@section('page-title-right') + +@endsection + +@section('content') + @if ($errors->has('error')) + + @endif + @if ($errors->any()) +
+ @foreach ($errors->all() as $error) +
{{ $error }}
+ @endforeach +
+ @endif + + + +
+
+
+ @csrf + @method($product->id ? 'PUT' : 'POST') + + +
+
+
{{ __('common.data') }}
+ + @hook('admin.product.name.after') + + +
+
+ +
+ + +
+
+
+
+
{{ __('admin/product.image_help') }}
+
+ + +
+
+ + +
+ + {{ __('common.view') }} +
+
{{ __('admin/product.video_help') }}
+
+ + + + +
+ +
CM X
+ +
CM X
+ +
CM
+
+
+ + +
+ + +
+
+ + @hookwrapper('admin.product.edit.brand') + + + + + @endhookwrapper + + + + +
+ @foreach ($source['categories'] as $_category) +
+ id, old('categories', $category_ids)) ? 'checked' : '' }}> + +
+ @endforeach +
+
+ + + + @hook('admin.product.edit.extra') + +
+
{{ __('admin/product.stocks') }}
+ + +
+
+ price_setting == 'sku' ? 'checked' : '' }}> + +
+
+ price_setting == 'num' ? 'checked' : '' }}> + +
+
+
+ + +{{-- 阶梯价格设置表格 (最小起订量,产品价格),预览,可以增加删除价格区间--}} +
+
+
+
最小起订量
+
产品价格
+
删除
+
+
+
+
+
+
+ +
+
_@{{ item.num }}件
+
+
+ +
@{{ item.num }}件等于价格:@{{ item.num * item.price }}
+
+ +
+
+ +
+
+
+ 预览 +
+
+
+
@{{ item.num }} ~ @{{ form.numPrices[index + 1].num - 1 }}
+
≧@{{ item.num }}
+
价格@{{ item.price }}
+
+
+
+
+ + +
新增价格区间
+ +
+ + + + + + + @hookwrapper('admin.product.edit.switch') + + + + @endhookwrapper + + + +
+ +
+
+
+ +
+
+
+ @{{ variant.name[current_language_code] }} + {{ __('common.edit') }} + {{ __('common.delete') }} +
+
+ {{ __('admin/product.add_variable_image') }} + {{ __('admin/product.add_variable_value') }} +
+
+ +
+
{{ __('admin/product.add_variable_value') }}
+
+ +
+
+ + {{ __('admin/product.add_variable') }} +
+ +
+
+
+ +
+
+ + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ @{{ variant.name[current_language_code] || 'No name' }} + {{ __('common.image') }}{{ __('admin/product.model') }}sku{{ __('admin/product.price') }}{{ __('admin/product.origin_price') }}{{ __('admin/product.cost_price') }}{{ __('admin/product.quantity') }}
+
+
+
+ +
+ + +
+
+
+ + +
+ + {{ __('common.error_required', ['name' => 'sku']) }} + {{ __('admin/product.default_main_product') }} + + + {{ __('common.error_required', ['name' => __('admin/product.price')]) }} + + + {{ __('common.error_required', ['name' => __('admin/product.origin_price')]) }} + +
+
+
+ +
{{ __('admin/product.add_variable') }}
+
+
+ + @hookwrapper('admin.product.edit.variable') +
+ + + + + + + + + + + + + + +
+ @endhookwrapper +
+
+
+
{{ __('admin/product.product_details') }}
+ + + + +
+ @foreach ($languages as $language) +
+ +
+ @endforeach + @hook('admin.product.content.after') +
+
+
+
+
{{ __('admin/attribute.index') }}
+ +
+ + + + + + + + + + + + + +
{{ __('admin/attribute.index') }}{{ __('admin/attribute.attribute_value') }}
+ + +
{{ __('common.error_required', ['name' => __('admin/attribute.index')]) }}
+
+ + +
{{ __('common.error_required', ['name' => __('admin/attribute.attribute_value')]) }}
+
+ +
+
+
+
+ +
+
SEO
+ + @hook('admin.product.seo.before') + + + +
+ @foreach ($languages as $language) +
+ {{ $language['name'] }} + +
+ @endforeach +
+
+ +
+ @foreach ($languages as $language) +
+ {{ $language['name'] }} + +
+ @endforeach +
+
+ + @hook('admin.product.seo.after') +
+ +
+
{{ __('admin/product.product_relations') }}
+ + +
+
+ + +
+ + +
+
+
+
+
+
+ + + + + + + + + + + + @hook('admin.product.sku.edit.item.after') + + + + {{ __('common.save') }} + {{ __('common.cancel') }} + + + + + + + + + + + + + + +
+ {{ __('common.save') }} + {{ __('common.cancel') }} +
+
+
+
+
+
+
+ + @hook('admin.product.form.footer') +@endsection + +@push('footer') + + +@endpush diff --git a/resources/beike/admin/views/pages/logistics/index.blade.php b/resources/beike/admin/views/pages/logistics/index.blade.php new file mode 100644 index 00000000..7a7d382e --- /dev/null +++ b/resources/beike/admin/views/pages/logistics/index.blade.php @@ -0,0 +1,311 @@ +@extends('admin::layouts.master') + +@section('title', __('admin/common.product')) + +@section('content') + @if ($errors->has('error')) + + @endif + + @if (session()->has('success')) + + @endif + +
+
+
+
+
+
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + @hook('admin.product.list.filter') +
+ +
+ +
+ + +
+
+
+ +
+ @if ($type != 'trashed') + + + + @else + @if ($products->total()) + + @endif + @endif + + @if ($type != 'trashed' && $products->total()) +
+ + + +
+ @endif +
+ + @if ($products->total()) +
+ + + + + + + + + + + + @if ($type != 'trashed') + + @endif + @hook('admin.product.list.column') + + + + + @foreach ($products_format as $product) + + + + + + + + + @if ($type != 'trashed') + + @endif + @hook('admin.product.list.column_value') + + + @endforeach + +
{{ __('common.id') }}{{ __('product.image') }}{{ __('product.name') }}{{ __('product.price') }} +
+ {{ __('common.created_at') }} +
+ + +
+
+
+
+ {{ __('common.sort_order') }} +
+ + +
+
+
{{ __('common.status') }}{{ __('common.action') }}
{{ $product['id'] }} +
+
+ {{ $product['name'] }} + {{ $product['price_formatted'] }}{{ $product['created_at'] }}{{ $product['position'] }} +{{--
--}} +{{-- --}} +{{--
--}} + + {{ $product['active'] ? __('common.enable_status') : __('common.disable_status') }} + +
+ @if ($product['deleted_at'] == '') + {{ __('common.edit') }} + {{ __('common.copy') }} + {{ __('common.delete') }} + @hook('admin.product.list.action') + @else + {{ __('common.restore') }} + @hook('admin.products.trashed.action') + @endif +
+
+ + {{ $products->withQueryString()->links('admin::vendor/pagination/bootstrap-4') }} + @else + + @endif +
+
+
+ + @hook('admin.product.list.content.footer') +@endsection + +@push('footer') + +@endpush diff --git a/resources/beike/admin/views/pages/products/form/form.blade.php b/resources/beike/admin/views/pages/products/form/form.blade.php index 05981fdc..7b9d40b2 100644 --- a/resources/beike/admin/views/pages/products/form/form.blade.php +++ b/resources/beike/admin/views/pages/products/form/form.blade.php @@ -96,9 +96,9 @@
-
CM X
-
CM X
-
CM
+
CM X
+
CM X
+
CM
diff --git a/resources/lang/en/admin/common.php b/resources/lang/en/admin/common.php index 2895febf..aa29a0ce 100644 --- a/resources/lang/en/admin/common.php +++ b/resources/lang/en/admin/common.php @@ -101,4 +101,5 @@ return [ 'update_date' => 'Update date', 'update_btn' => 'Download', 'expired_at' => 'Expired', + 'logistics' => 'Logistics', ]; diff --git a/resources/lang/en/admin/logistics.php b/resources/lang/en/admin/logistics.php new file mode 100644 index 00000000..6633c33e --- /dev/null +++ b/resources/lang/en/admin/logistics.php @@ -0,0 +1,58 @@ + + * @created 2022-08-02 14:22:41 + * @modified 2022-08-02 14:22:41 + */ + +return [ + 'logistics_index' => 'Index', + 'logistics_name' => 'Logistics Name', + 'logistics_img' => 'Logistics Image', + 'logistics_create' => 'Create', + 'logistics_show' => 'Detail', + 'logistics_update' => 'Edit', + 'logistics_delete' => 'Delete', + 'logistics_trashed' => 'Trashed', + 'logistics_restore' => 'Restore', + 'clear_restore' => 'Empty Recycle Bin', + 'logistics_filter_index' => 'View Filters', + 'logistics_filter_update' => 'Modify Filters', + + 'batch_delete' => 'Batch Delete', + 'batch_active' => 'Batch Active', + 'batch_inactive' => 'Batch Inactive', + + 'basic_information' => 'Basic Information', + 'product_details' => 'Product details', + 'product_relations' => 'Related Logistics', + 'stocks' => 'Product inventory', + 'model' => 'Model', + 'price' => 'Price', + 'origin_price' => 'Original Price', + 'cost_price' => 'Cost Price', + 'quantity' => 'Quantity', + 'enable_multi_spec' => 'Enable multi-spec', + 'image_help' => 'The first picture will be used as the main picture of the product, and multiple pictures can be uploaded at the same time, and the position of multiple pictures can be adjusted at will', + 'video_help' => 'If the prompt exceeds the system size limit, please modify the php.ini parameter post_max_size', + 'add_variable' => 'Add Specs', + 'add_variable_value' => 'Add Specification Value', + 'add_variable_image' => 'Add Spec Image', + 'default_main_product' => 'Default main product', + 'modify_order' => 'Double-click to modify, drag to adjust the order', + 'weight_text' => 'weight', + 'length_width_height' => 'Length, width and height', + 'length' => 'Length', + 'width' => 'Width', + 'height' => 'Height', + 'weight_class' => 'weight unit', + + 'confirm_batch_product' => 'Are you sure you want to delete the selected logistics in batches? ', + 'confirm_batch_status' => 'Confirm to modify the status of the selected logistics in batches? ', + 'confirm_batch_restore' => 'Confirm to restore the selected product? ', + 'confirm_delete_restore' => 'Are you sure you want to empty the recycle bin? ', +]; diff --git a/resources/lang/en/admin/product.php b/resources/lang/en/admin/product.php index a41d82a7..750da990 100644 --- a/resources/lang/en/admin/product.php +++ b/resources/lang/en/admin/product.php @@ -46,6 +46,9 @@ return [ 'modify_order' => 'Double-click to modify, drag to adjust the order', 'weight_text' => 'weight', 'length_width_height' => 'Length, width and height', + 'length' => 'Length', + 'width' => 'Width', + 'height' => 'Height', 'weight_class' => 'weight unit', 'confirm_batch_product' => 'Are you sure you want to delete the selected products in batches? ', diff --git a/resources/lang/zh_cn/admin/common.php b/resources/lang/zh_cn/admin/common.php index dc14bf7e..a741c7e5 100644 --- a/resources/lang/zh_cn/admin/common.php +++ b/resources/lang/zh_cn/admin/common.php @@ -99,4 +99,5 @@ return [ 'update_date' => '更新日期', 'update_btn' => '前往下载', 'expired_at' => '到期时间', + 'logistics' => '物流管理', ]; diff --git a/resources/lang/zh_cn/admin/logistics.php b/resources/lang/zh_cn/admin/logistics.php new file mode 100644 index 00000000..2cd55ee6 --- /dev/null +++ b/resources/lang/zh_cn/admin/logistics.php @@ -0,0 +1,63 @@ + + * @created 2022-08-02 14:22:41 + * @modified 2022-08-02 14:22:41 + */ + +return [ + 'logistics_index' => '物流列表', + 'logistics_name' => '物流名称', + 'logistics_img' => '物流图片', + 'logistics_create' => '创建物流', + 'logistics_show' => '物流详情', + 'logistics_update' => '更新物流', + 'logistics_delete' => '删除物流', + 'logistics_trashed' => '回收站', + 'logistics_restore' => '恢复回收站', + 'clear_restore' => '清空回收站', + 'logistics_filter_index' => '查看高级筛选', + 'logistics_filter_update' => '修改高级筛选', + + 'batch_delete' => '批量删除', + 'batch_active' => '批量上架', + 'batch_inactive' => '批量下架', + + 'basic_information' => '基础信息', + 'product_details' => '物流详情', + 'product_relations' => '相关物流', + 'stocks' => '物流库存', + 'model' => '型号', + 'price' => '价格', + 'origin_price' => '原价', + 'cost_price' => '成本价', + 'quantity' => '数量', + 'enable_multi_spec' => '启用多规格', + 'image_help' => '第一张图片将作为物流主图,支持同时上传多张图片,多张图片之间可随意调整位置', + 'video_help' => '如果提示超出系统大小限制,请修改 php.ini 参数 post_max_size', + 'add_variable' => '添加规格', + 'add_variable_value' => '添加规格值', + 'add_variable_image' => '添加规格图片', + 'default_main_product' => '默认主物流', + 'modify_order' => '双击修改、拖动调整顺序', + 'weight_text' => '重量', + 'length_width_height' => '长宽高', + 'length' => '长', + 'width' => '宽', + 'height' => '高', + 'weight_class' => '重量单位', + + 'confirm_batch_product' => '确认要批量删除选中的物流吗?', + 'confirm_batch_status' => '确认要批量修改选中的物流的状态吗?', + 'confirm_batch_restore' => '确认要恢复选中的物流吗?', + 'confirm_delete_restore' => '确认要清空回收站吗?', + 'price_setting' => '价格设置', + 'price_setting_by' =>[ + 'sku' => '根据规格设置价格', + 'num' => '根据数量设置价格', + ] +]; diff --git a/resources/lang/zh_cn/admin/product.php b/resources/lang/zh_cn/admin/product.php index e223eb44..857e39c5 100644 --- a/resources/lang/zh_cn/admin/product.php +++ b/resources/lang/zh_cn/admin/product.php @@ -46,6 +46,9 @@ return [ 'modify_order' => '双击修改、拖动调整顺序', 'weight_text' => '重量', 'length_width_height' => '长宽高', + 'length' => '长', + 'width' => '宽', + 'height' => '高', 'weight_class' => '重量单位', 'confirm_batch_product' => '确认要批量删除选中的商品吗?', diff --git a/resources/lang/zh_cn/common.php b/resources/lang/zh_cn/common.php index 09a4ffbc..7acc6ae7 100644 --- a/resources/lang/zh_cn/common.php +++ b/resources/lang/zh_cn/common.php @@ -99,6 +99,7 @@ return [ 'contacts' => '联系人', 'content' => '内容', 'sku' => 'Sku', + 'logistics' => '物流', 'order' => [