From bfb1ea283c4a4d3781b752d6270e85838cf169e6 Mon Sep 17 00:00:00 2001
From: liqianjin <949671634@qq.com>
Date: Fri, 11 Aug 2023 18:41:28 +0800
Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=A2=9E=E5=8A=A0=E3=80=91=E7=89=A9?=
=?UTF-8?q?=E6=B5=81=E7=AE=A1=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Http/Controllers/LogisticsController.php | 221 +++
beike/Admin/Routes/admin.php | 4 +
beike/Admin/View/Components/Sidebar.php | 7 +
beike/Models/Logistics.php | 19 +
beike/Repositories/LogisticsRepo.php | 420 ++++++
database/factories/LogisticsFactory.php | 24 +
.../views/pages/logistics/form/form.blade.php | 1248 +++++++++++++++++
.../views/pages/logistics/index.blade.php | 311 ++++
.../views/pages/products/form/form.blade.php | 6 +-
resources/lang/en/admin/common.php | 1 +
resources/lang/en/admin/logistics.php | 58 +
resources/lang/en/admin/product.php | 3 +
resources/lang/zh_cn/admin/common.php | 1 +
resources/lang/zh_cn/admin/logistics.php | 63 +
resources/lang/zh_cn/admin/product.php | 3 +
resources/lang/zh_cn/common.php | 1 +
16 files changed, 2387 insertions(+), 3 deletions(-)
create mode 100644 beike/Admin/Http/Controllers/LogisticsController.php
create mode 100644 beike/Models/Logistics.php
create mode 100644 beike/Repositories/LogisticsRepo.php
create mode 100644 database/factories/LogisticsFactory.php
create mode 100644 resources/beike/admin/views/pages/logistics/form/form.blade.php
create mode 100644 resources/beike/admin/views/pages/logistics/index.blade.php
create mode 100644 resources/lang/en/admin/logistics.php
create mode 100644 resources/lang/zh_cn/admin/logistics.php
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'))
+
| + | {{ __('common.id') }} | +{{ __('product.image') }} | +{{ __('product.name') }} | +{{ __('product.price') }} | +
+
+ {{ __('common.created_at') }}
+
+
+
+
+
+ |
+
+
+
+ {{ __('common.sort_order') }}
+
+
+
+
+
+ |
+ @if ($type != 'trashed')
+ {{ __('common.status') }} | + @endif + @hook('admin.product.list.column') +{{ __('common.action') }} | +
|---|---|---|---|---|---|---|---|---|
| + | {{ $product['id'] }} | +
+ ![]() |
+ + {{ $product['name'] }} + | +{{ $product['price_formatted'] }} | +{{ $product['created_at'] }} | +{{ $product['position'] }} | + @if ($type != 'trashed') +
+{{-- --}}
+{{-- --}}
+{{-- --}}
+
+ {{ $product['active'] ? __('common.enable_status') : __('common.disable_status') }}
+
+ |
+ @endif
+ @hook('admin.product.list.column_value')
+ + @if ($product['deleted_at'] == '') + {{ __('common.edit') }} + index }})">{{ __('common.copy') }} + index }})">{{ __('common.delete') }} + @hook('admin.product.list.action') + @else + index }})">{{ __('common.restore') }} + @hook('admin.products.trashed.action') + @endif + | +