category qosishsh to'g'irlandi
This commit is contained in:
@@ -14,7 +14,9 @@ use App\Jobs\Dashboard\Category\Update as UpdateJob;
|
||||
use App\Models\Characteristic;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Throwable;
|
||||
|
||||
class Controller extends ExController
|
||||
{
|
||||
@@ -25,17 +27,46 @@ class Controller extends ExController
|
||||
public function index()
|
||||
{
|
||||
$this->authorize('view', 'categories');
|
||||
$categories = Category::select('id', 'name->ru as category', 'position', 'parent_id', 'image')
|
||||
->where('parent_id', null)
|
||||
->with(['children' => function ($parent) {
|
||||
return $parent->select('id', 'name->ru as category', 'parent_id', 'position', 'image')->orderBy('position', 'asc')->with(['children' => function ($parent) {
|
||||
return $parent->select('id', 'name->ru as category', 'parent_id', 'position', 'image')->orderBy('position', 'asc');
|
||||
}]);
|
||||
}])->orderBy('position', 'asc')->get();
|
||||
$categories = $this->categoryTree();
|
||||
|
||||
return view('dashboard.category.index', compact('categories'));
|
||||
}
|
||||
|
||||
private function categoryTree($parentId = null, array $visited = [])
|
||||
{
|
||||
return Category::select('id', 'name', 'position', 'parent_id', 'image')
|
||||
->when($parentId === null, function ($query) {
|
||||
$query->whereNull('parent_id');
|
||||
}, function ($query) use ($parentId) {
|
||||
$query->where('parent_id', $parentId);
|
||||
})
|
||||
->orderBy('position', 'asc')
|
||||
->get()
|
||||
->map(function (Category $category) use ($visited) {
|
||||
if (in_array($category->id, $visited, true)) {
|
||||
return [
|
||||
'id' => $category->id,
|
||||
'category' => $category->name['ru'] ?? $category->name['uz'] ?? '',
|
||||
'position' => $category->position,
|
||||
'parent_id' => $category->parent_id,
|
||||
'image' => $category->image,
|
||||
'image_url' => $category->image_url,
|
||||
'children' => [],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $category->id,
|
||||
'category' => $category->name['ru'] ?? $category->name['uz'] ?? '',
|
||||
'position' => $category->position,
|
||||
'parent_id' => $category->parent_id,
|
||||
'image' => $category->image,
|
||||
'image_url' => $category->image_url,
|
||||
'children' => $this->categoryTree($category->id, [...$visited, $category->id]),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StoreRequest $request
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\JsonResponse|\Illuminate\View\View
|
||||
@@ -55,20 +86,39 @@ class Controller extends ExController
|
||||
return view('dashboard.category.store', compact('brands', 'parent_categories'));
|
||||
}
|
||||
|
||||
$category = $this->dispatchSync(new StoreJob($request));
|
||||
try {
|
||||
$category = DB::transaction(function () use ($request) {
|
||||
$category = $this->dispatchSync(new StoreJob($request));
|
||||
|
||||
if (!empty($request->char)) {
|
||||
foreach ($request->char as $char) {
|
||||
Characteristic::create([
|
||||
'name' => $char['name'],
|
||||
'type' => $char['type'],
|
||||
'category_id' => $category->id,
|
||||
'filter' => $char['filter'] == 'true' ? 1 : 0
|
||||
]);
|
||||
}
|
||||
if (!empty($request->char)) {
|
||||
foreach ($request->char as $char) {
|
||||
Characteristic::create([
|
||||
'name' => $char['name'] ?? ['ru' => '', 'uz' => ''],
|
||||
'type' => $char['type'] ?? 'text',
|
||||
'category_id' => $category->id,
|
||||
'filter' => filter_var($char['filter'] ?? false, FILTER_VALIDATE_BOOLEAN)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $category;
|
||||
});
|
||||
} catch (Throwable $exception) {
|
||||
Log::error('Category store failed', [
|
||||
'message' => $exception->getMessage(),
|
||||
'trace' => $exception->getTraceAsString(),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Category could not be saved.',
|
||||
'error' => config('app.debug') ? $exception->getMessage() : null,
|
||||
], 500);
|
||||
}
|
||||
|
||||
$this->success(trans('admin.messages.created'));
|
||||
if ($category) {
|
||||
$this->success(trans('admin.messages.created'));
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => true
|
||||
@@ -103,39 +153,52 @@ class Controller extends ExController
|
||||
return view('dashboard.category.update', compact('parent_categories', 'category', 'brands'));
|
||||
}
|
||||
|
||||
$image = $request->getImage($category);
|
||||
try {
|
||||
$image = $request->getImage($category);
|
||||
|
||||
$this->dispatchSync(new UpdateJob($category, $request, $image));
|
||||
DB::transaction(function () use ($category, $request, $image) {
|
||||
$this->dispatchSync(new UpdateJob($category, $request, $image));
|
||||
|
||||
if (!empty($request->char)) {
|
||||
foreach ($request->char as $char) {
|
||||
if ($char['id'] == null || $char['id'] == 'null') {
|
||||
Characteristic::create([
|
||||
'name' => $char['name'],
|
||||
'type' => $char['type'],
|
||||
'category_id' => $category->id,
|
||||
'filter' => $char['filter'] == 'true' ? 1 : 0
|
||||
]);
|
||||
} else {
|
||||
Characteristic::where('id', $char['id'])->update([
|
||||
'name' => $char['name'],
|
||||
'type' => $char['type'],
|
||||
'filter' => $char['filter'] == 'true' ? 1 : 0
|
||||
]);
|
||||
if (!empty($request->char)) {
|
||||
foreach ($request->char as $char) {
|
||||
if ($char['id'] == null || $char['id'] == 'null') {
|
||||
Characteristic::create([
|
||||
'name' => $char['name'] ?? ['ru' => '', 'uz' => ''],
|
||||
'type' => $char['type'] ?? 'text',
|
||||
'category_id' => $category->id,
|
||||
'filter' => filter_var($char['filter'] ?? false, FILTER_VALIDATE_BOOLEAN)
|
||||
]);
|
||||
} else {
|
||||
Characteristic::where('id', $char['id'])->update([
|
||||
'name' => $char['name'] ?? ['ru' => '', 'uz' => ''],
|
||||
'type' => $char['type'] ?? 'text',
|
||||
'filter' => filter_var($char['filter'] ?? false, FILTER_VALIDATE_BOOLEAN)
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($request->deletes['char'])) {
|
||||
$chars = Characteristic::whereIn('id', $request->deletes['char'])->get();
|
||||
if (!empty($request->deletes['char'])) {
|
||||
$chars = Characteristic::whereIn('id', $request->deletes['char'])->get();
|
||||
|
||||
foreach ($chars as $char) {
|
||||
$char->values()->detach();
|
||||
// foreach ($char->values as $value) {
|
||||
// $value->delete();
|
||||
// }
|
||||
$char->delete();
|
||||
}
|
||||
foreach ($chars as $char) {
|
||||
$char->values()->detach();
|
||||
$char->delete();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Throwable $exception) {
|
||||
Log::error('Category update failed', [
|
||||
'category_id' => $category->id,
|
||||
'message' => $exception->getMessage(),
|
||||
'trace' => $exception->getTraceAsString(),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'status' => false,
|
||||
'message' => 'Category could not be saved.',
|
||||
'error' => config('app.debug') ? $exception->getMessage() : null,
|
||||
], 500);
|
||||
}
|
||||
|
||||
$this->success(trans('admin.messages.updated'));
|
||||
@@ -145,7 +208,6 @@ class Controller extends ExController
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
|
||||
@@ -82,17 +82,7 @@ class Controller extends ExController
|
||||
{
|
||||
if ($request->isMethod('get')) {
|
||||
$this->authorize('create', 'products');
|
||||
$categories = $this->categories->select('id', 'name->ru as category')
|
||||
->where('parent_id', null)
|
||||
->with([
|
||||
'parents' => function ($parent) {
|
||||
return $parent->select('id', 'name->ru as category', 'parent_id')->with([
|
||||
'parents' => function ($parent) {
|
||||
return $parent->select('id', 'name->ru as category', 'parent_id');
|
||||
}
|
||||
]);
|
||||
}
|
||||
])->get();
|
||||
$categories = $this->categoryTree();
|
||||
$brands = $this->brands->get();
|
||||
$colors = $this->colors->get();
|
||||
$measurement = Measurement::query()->get();
|
||||
@@ -146,6 +136,31 @@ class Controller extends ExController
|
||||
}
|
||||
}
|
||||
|
||||
private function categoryTree($parentId = null, array $visited = [])
|
||||
{
|
||||
return Category::select('id', 'name', 'parent_id')
|
||||
->when($parentId === null, function ($query) {
|
||||
$query->whereNull('parent_id');
|
||||
}, function ($query) use ($parentId) {
|
||||
$query->where('parent_id', $parentId);
|
||||
})
|
||||
->orderBy('position', 'asc')
|
||||
->get()
|
||||
->map(function (Category $category) use ($visited) {
|
||||
$children = in_array($category->id, $visited, true)
|
||||
? collect()
|
||||
: $this->categoryTree($category->id, [...$visited, $category->id]);
|
||||
|
||||
return [
|
||||
'id' => $category->id,
|
||||
'category' => $category->name['ru'] ?? $category->name['uz'] ?? '',
|
||||
'parent_id' => $category->parent_id,
|
||||
'parents' => $children,
|
||||
'$isDisabled' => $children->isNotEmpty(),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return array
|
||||
@@ -309,17 +324,7 @@ class Controller extends ExController
|
||||
}
|
||||
|
||||
|
||||
$categories = $this->categories->select('id', 'name->ru as category')
|
||||
->where('parent_id', null)
|
||||
->with([
|
||||
'parents' => function ($parent) {
|
||||
return $parent->select('id', 'name->ru as category', 'parent_id')->with([
|
||||
'parents' => function ($parent) {
|
||||
return $parent->select('id', 'name->ru as category', 'parent_id');
|
||||
}
|
||||
]);
|
||||
}
|
||||
])->get();
|
||||
$categories = $this->categoryTree();
|
||||
|
||||
$brands = $this->brands->get();
|
||||
$measurement = Measurement::query()->get();
|
||||
|
||||
@@ -793,7 +793,16 @@ export default {
|
||||
.catch((error) => {
|
||||
if (error.response) {
|
||||
this.error = true;
|
||||
this.errors = error.response.data.errors;
|
||||
this.errors =
|
||||
error.response.data.errors ||
|
||||
error.response.data.details ||
|
||||
[
|
||||
[
|
||||
error.response.data.error ||
|
||||
error.response.data.message ||
|
||||
"Server error",
|
||||
],
|
||||
];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -804,7 +804,16 @@ export default {
|
||||
.catch((error) => {
|
||||
if (error.response) {
|
||||
this.error = true;
|
||||
this.errors = error.response.data.errors;
|
||||
this.errors =
|
||||
error.response.data.errors ||
|
||||
error.response.data.details ||
|
||||
[
|
||||
[
|
||||
error.response.data.error ||
|
||||
error.response.data.message ||
|
||||
"Server error",
|
||||
],
|
||||
];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -63,51 +63,28 @@
|
||||
|
||||
<multiselect
|
||||
:options="categories"
|
||||
v-model="category.first"
|
||||
v-model="category.path[0]"
|
||||
label="category"
|
||||
@change="
|
||||
DetectCategory($event)
|
||||
"
|
||||
track-by="category"
|
||||
@input="selectCategoryLevel(0)"
|
||||
track-by="id"
|
||||
></multiselect>
|
||||
<!-- //@change="getCharacteristics($event)"-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="col-4"
|
||||
v-if="category.two_view"
|
||||
v-for="level in categoryLevels"
|
||||
:key="'category-level-' + level"
|
||||
>
|
||||
<div class="form-group">
|
||||
<label>Суб категория *</label>
|
||||
|
||||
<multiselect
|
||||
:options="
|
||||
category.first.parents
|
||||
"
|
||||
v-model="category.two"
|
||||
:options="categoryOptions(level)"
|
||||
v-model="category.path[level]"
|
||||
label="category"
|
||||
@change="DetectCategoryTwo"
|
||||
track-by="category"
|
||||
></multiselect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="col-4"
|
||||
v-if="category.three_view"
|
||||
>
|
||||
<div class="form-group">
|
||||
<label>Под категория *</label>
|
||||
|
||||
<multiselect
|
||||
:options="
|
||||
category.two.parents
|
||||
"
|
||||
v-model="category.three"
|
||||
label="category"
|
||||
@change="DetectCategory"
|
||||
track-by="category"
|
||||
@input="selectCategoryLevel(level)"
|
||||
track-by="id"
|
||||
></multiselect>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1074,6 +1051,22 @@ export default {
|
||||
|
||||
this.watch_count.three = 2;
|
||||
},
|
||||
|
||||
"category.path": {
|
||||
deep: true,
|
||||
handler() {
|
||||
const selected = this.lastSelectedCategory();
|
||||
|
||||
if (!selected) {
|
||||
this.products.category_id = null;
|
||||
this.characteristics = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.products.category_id = selected.id;
|
||||
this.getCharacteristics(selected.id);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
data: function () {
|
||||
@@ -1106,6 +1099,7 @@ export default {
|
||||
three: {},
|
||||
two_view: false,
|
||||
three_view: false,
|
||||
path: [],
|
||||
},
|
||||
|
||||
watch_count: {
|
||||
@@ -1136,6 +1130,22 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
categoryLevels() {
|
||||
const levels = [];
|
||||
let current = this.category.path[0];
|
||||
let level = 1;
|
||||
|
||||
while (current && current.parents && current.parents.length > 0) {
|
||||
levels.push(level);
|
||||
current = this.category.path[level];
|
||||
level++;
|
||||
}
|
||||
|
||||
return levels;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getPosterPreview() {
|
||||
if (this.products.poster instanceof File) {
|
||||
@@ -1145,35 +1155,58 @@ export default {
|
||||
},
|
||||
setCategory() {
|
||||
if (this.products.categories[0]) {
|
||||
if (this.products.categories[0].parent) {
|
||||
if (this.products.categories[0].parent.parent) {
|
||||
this.category.two_view = true;
|
||||
this.category.three_view = true;
|
||||
this.products.category_id =
|
||||
this.products.categories[0].id;
|
||||
|
||||
this.category.first =
|
||||
this.products.categories[0].parent.parent;
|
||||
this.category.two = this.products.categories[0].parent;
|
||||
this.category.three = this.products.categories[0];
|
||||
} else {
|
||||
this.products.category_id =
|
||||
this.products.categories[0].id;
|
||||
|
||||
this.category.first =
|
||||
this.products.categories[0].parent;
|
||||
this.category.two = this.products.categories[0];
|
||||
this.category.two_view = true;
|
||||
}
|
||||
} else {
|
||||
this.products.category_id = this.products.categories[0].id;
|
||||
this.category.first = this.products.categories[0];
|
||||
}
|
||||
this.products.category_id = this.products.categories[0].id;
|
||||
this.category.path = this.findCategoryPath(
|
||||
this.categories,
|
||||
this.products.categories[0].id
|
||||
);
|
||||
|
||||
this.getCharacteristics(this.product.categories[0].id);
|
||||
}
|
||||
},
|
||||
|
||||
findCategoryPath(categories, id, path = []) {
|
||||
for (const category of categories || []) {
|
||||
const currentPath = [...path, category];
|
||||
|
||||
if (category.id === id) {
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
const childPath = this.findCategoryPath(
|
||||
category.parents || [],
|
||||
id,
|
||||
currentPath
|
||||
);
|
||||
|
||||
if (childPath.length > 0) {
|
||||
return childPath;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
|
||||
categoryOptions(level) {
|
||||
const parent = this.category.path[level - 1];
|
||||
|
||||
return parent && parent.parents ? parent.parents : [];
|
||||
},
|
||||
|
||||
selectCategoryLevel(level) {
|
||||
this.category.path.splice(level + 1);
|
||||
},
|
||||
|
||||
lastSelectedCategory() {
|
||||
for (let i = this.category.path.length - 1; i >= 0; i--) {
|
||||
if (this.category.path[i] && this.category.path[i].id) {
|
||||
return this.category.path[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
DetectCategory() {
|
||||
this.category.two = {
|
||||
parents: [],
|
||||
|
||||
@@ -59,51 +59,28 @@
|
||||
|
||||
<multiselect
|
||||
:options="categories"
|
||||
v-model="category.first"
|
||||
v-model="category.path[0]"
|
||||
label="category"
|
||||
@change="
|
||||
DetectCategory($event)
|
||||
"
|
||||
track-by="category"
|
||||
@input="selectCategoryLevel(0)"
|
||||
track-by="id"
|
||||
></multiselect>
|
||||
<!-- //@change="getCharacteristics($event)"-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="col-4"
|
||||
v-if="category.two_view"
|
||||
v-for="level in categoryLevels"
|
||||
:key="'category-level-' + level"
|
||||
>
|
||||
<div class="form-group">
|
||||
<label>Суб категория *</label>
|
||||
|
||||
<multiselect
|
||||
:options="
|
||||
category.first.parents
|
||||
"
|
||||
v-model="category.two"
|
||||
:options="categoryOptions(level)"
|
||||
v-model="category.path[level]"
|
||||
label="category"
|
||||
@change="DetectCategoryTwo"
|
||||
track-by="category"
|
||||
></multiselect>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="col-4"
|
||||
v-if="category.three_view"
|
||||
>
|
||||
<div class="form-group">
|
||||
<label>Под категория *</label>
|
||||
|
||||
<multiselect
|
||||
:options="
|
||||
category.two.parents
|
||||
"
|
||||
v-model="category.three"
|
||||
label="category"
|
||||
@change="DetectCategory"
|
||||
track-by="category"
|
||||
@input="selectCategoryLevel(level)"
|
||||
track-by="id"
|
||||
></multiselect>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1136,6 +1113,7 @@ export default {
|
||||
three: {},
|
||||
two_view: false,
|
||||
three_view: false,
|
||||
path: [],
|
||||
},
|
||||
|
||||
characteristic: false,
|
||||
@@ -1149,6 +1127,20 @@ export default {
|
||||
uploadDisabled() {
|
||||
return this.files.length === 0;
|
||||
},
|
||||
|
||||
categoryLevels() {
|
||||
const levels = [];
|
||||
let current = this.category.path[0];
|
||||
let level = 1;
|
||||
|
||||
while (current && current.parents && current.parents.length > 0) {
|
||||
levels.push(level);
|
||||
current = this.category.path[level];
|
||||
level++;
|
||||
}
|
||||
|
||||
return levels;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
@@ -1181,6 +1173,22 @@ export default {
|
||||
|
||||
this.DetectCategoryThree();
|
||||
},
|
||||
|
||||
"category.path": {
|
||||
deep: true,
|
||||
handler() {
|
||||
const selected = this.lastSelectedCategory();
|
||||
|
||||
if (!selected) {
|
||||
this.product.category_id = null;
|
||||
this.characteristics = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.product.category_id = selected.id;
|
||||
this.getCharacteristics(selected.id);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -1312,11 +1320,37 @@ export default {
|
||||
.catch((error) => {
|
||||
if (error.response) {
|
||||
this.error = true;
|
||||
this.errors = error.response.data.errors;
|
||||
this.errors = error.response.data.errors || {
|
||||
product: [
|
||||
error.response.data.messages ||
|
||||
error.response.data.message ||
|
||||
"Ошибка при сохранении",
|
||||
],
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
categoryOptions(level) {
|
||||
const parent = this.category.path[level - 1];
|
||||
|
||||
return parent && parent.parents ? parent.parents : [];
|
||||
},
|
||||
|
||||
selectCategoryLevel(level) {
|
||||
this.category.path.splice(level + 1);
|
||||
},
|
||||
|
||||
lastSelectedCategory() {
|
||||
for (let i = this.category.path.length - 1; i >= 0; i--) {
|
||||
if (this.category.path[i] && this.category.path[i].id) {
|
||||
return this.category.path[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
remaincharRUCount: function () {
|
||||
if (this.product.short_body.ru.length > 300) {
|
||||
this.short_limit.ru = "Превышен лимит в 300 символов.";
|
||||
|
||||
Reference in New Issue
Block a user