Browse Source

+ при редатировании товара можно загружать изображения + если несколько
изображений найдено по артикулу - можно выбрать одно

Александр Мусихин 2 years ago
parent
commit
d73c0db4d6

+ 26 - 9
app/Http/Controllers/ProductController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use App\Http\Requests\SaveProductRequest;
 use App\Http\Requests\SaveProductRequest;
 use App\Models\Product;
 use App\Models\Product;
 use Illuminate\Http\Request;
 use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Redirect;
 use Illuminate\Support\Str;
 use Illuminate\Support\Str;
 
 
 
 
@@ -48,7 +49,7 @@ class ProductController extends Controller
     }
     }
 
 
     // todo вынести в job, чтобы работала в фоне
     // todo вынести в job, чтобы работала в фоне
-    public function upload(Request $request)
+    public function upload_xls(Request $request)
     {
     {
         $xls = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile($request->file('file'));
         $xls = \PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile($request->file('file'));
         $xls->setReadDataOnly(true);
         $xls->setReadDataOnly(true);
@@ -77,7 +78,7 @@ class ProductController extends Controller
                 $good[3] = preg_replace('!\s+!', ' ', $good[3]);
                 $good[3] = preg_replace('!\s+!', ' ', $good[3]);
                 $tmp = explode(' ', $good[3], 2);
                 $tmp = explode(' ', $good[3], 2);
             }
             }
-
+            $images = $this->find_images($tmp[0]);
             $data = [
             $data = [
 //                'article' => $tmp[0],
 //                'article' => $tmp[0],
                 'series' => $series,
                 'series' => $series,
@@ -88,7 +89,7 @@ class ProductController extends Controller
                 'characteristics' => $good[4],
                 'characteristics' => $good[4],
                 'tech_description' => $good[7],
                 'tech_description' => $good[7],
                 'tech_description_short' => $good[8],
                 'tech_description_short' => $good[8],
-                'image_path' => $this->find_image($tmp[0]),
+                'image_path' => (!empty($images)) ? $images[0] : $images,
             ];
             ];
 
 
             $a = Product::query()->updateOrCreate(['article' => $tmp[0]], $data);
             $a = Product::query()->updateOrCreate(['article' => $tmp[0]], $data);
@@ -104,32 +105,48 @@ class ProductController extends Controller
 
 
     private $allfiles; // remember files list
     private $allfiles; // remember files list
 
 
-    private function find_image($article)
+    private function find_images($article)
     {
     {
         $path_to_files = './' . env('IMAGES_PATH', '---') . '/';
         $path_to_files = './' . env('IMAGES_PATH', '---') . '/';
         if (!isset($this->allfiles) || empty($this->allfiles)) {
         if (!isset($this->allfiles) || empty($this->allfiles)) {
             $this->allfiles = scandir($path_to_files);
             $this->allfiles = scandir($path_to_files);
         }
         }
+        $images = [];
         foreach ($this->allfiles as $filename) {
         foreach ($this->allfiles as $filename) {
             if ((mb_strpos($filename, $article) === 0) || (
             if ((mb_strpos($filename, $article) === 0) || (
                     mb_strpos(Str::lower($filename), Str::slug($article)) === 0))
                     mb_strpos(Str::lower($filename), Str::slug($article)) === 0))
-                return $filename;
+                $images[] = $filename;
         }
         }
-
-        return '';
+        return (!empty($images)) ? $images : '';
     }
     }
 
 
     public function product(Request $request, $id)
     public function product(Request $request, $id)
     {
     {
         $data['product'] = Product::query()->findOrFail($id);
         $data['product'] = Product::query()->findOrFail($id);
+        $data['images'] = $this->find_images($data['product']->article);
         return view('products.product', $data);
         return view('products.product', $data);
     }
     }
 
 
     public function save_product(SaveProductRequest $request)
     public function save_product(SaveProductRequest $request)
     {
     {
-        $p = Product::query()->where('id', $request->validated('id'))->update($request->validated());
-
+        Product::query()->where('id', $request->validated('id'))->update($request->validated());
         return redirect()->route('index');
         return redirect()->route('index');
     }
     }
 
 
+    public function upload_image(Request $request){
+        $path = public_path() . '/' . env('IMAGES_PATH');
+//        dd($path);
+        $file = $request->file('filename');
+        $new_filename = $request->article . '.' . date('YmdHis') . '.' . $file->extension();
+        $file->move($path, $new_filename);
+        Product::query()->where('article', $request->article)->update(['image_path' => $new_filename]);
+        return redirect()->back();
+    }
+
+    public function update_image(Request $request, $id){
+        $validated = $request->validate(['image_path' => 'required|string']);
+        Product::query()->where('id', $id)->update($validated);
+        return redirect()->route('view_product', $id);
+    }
+
 }
 }

+ 15 - 0
app/Http/Requests/SaveProductRequest.php

@@ -35,4 +35,19 @@ class SaveProductRequest extends FormRequest
             'tech_description_short' => 'required|string',
             'tech_description_short' => 'required|string',
         ];
         ];
     }
     }
+
+    public function messages()
+    {
+        return [
+            'series.required' => 'Не может быть пустым',
+            'name.required' => 'Не может быть пустым',
+            'name_for_form.required' => 'Не может быть пустым',
+            'product_group.required' => 'Не может быть пустым',
+            'price.required' => 'Не может быть пустым',
+            'characteristics.required' => 'Не может быть пустым',
+            'tech_description.required' => 'Не может быть пустым',
+            'tech_description_short.required' => 'Не может быть пустым',
+
+        ];
+    }
 }
 }

+ 2 - 1
composer.json

@@ -11,7 +11,8 @@
         "laravel/sanctum": "^3.0",
         "laravel/sanctum": "^3.0",
         "laravel/tinker": "^2.7",
         "laravel/tinker": "^2.7",
         "laravel/ui": "^4.2",
         "laravel/ui": "^4.2",
-        "phpoffice/phpspreadsheet": "^1.27"
+        "phpoffice/phpspreadsheet": "^1.27",
+        "phpoffice/phpword": "^1.0"
     },
     },
     "require-dev": {
     "require-dev": {
         "barryvdh/laravel-debugbar": "^3.7",
         "barryvdh/laravel-debugbar": "^3.7",

+ 176 - 1
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
         "This file is @generated automatically"
     ],
     ],
-    "content-hash": "459dea0eaee6d40278d8025cc1a15cd1",
+    "content-hash": "e8eada783b3c832be35318343a116427",
     "packages": [
     "packages": [
         {
         {
             "name": "brick/math",
             "name": "brick/math",
@@ -958,6 +958,68 @@
             ],
             ],
             "time": "2022-10-26T14:07:24+00:00"
             "time": "2022-10-26T14:07:24+00:00"
         },
         },
+        {
+            "name": "laminas/laminas-escaper",
+            "version": "2.12.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/laminas/laminas-escaper.git",
+                "reference": "ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490",
+                "reference": "ee7a4c37bf3d0e8c03635d5bddb5bb3184ead490",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "ext-mbstring": "*",
+                "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0"
+            },
+            "conflict": {
+                "zendframework/zend-escaper": "*"
+            },
+            "require-dev": {
+                "infection/infection": "^0.26.6",
+                "laminas/laminas-coding-standard": "~2.4.0",
+                "maglnet/composer-require-checker": "^3.8.0",
+                "phpunit/phpunit": "^9.5.18",
+                "psalm/plugin-phpunit": "^0.17.0",
+                "vimeo/psalm": "^4.22.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Laminas\\Escaper\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs",
+            "homepage": "https://laminas.dev",
+            "keywords": [
+                "escaper",
+                "laminas"
+            ],
+            "support": {
+                "chat": "https://laminas.dev/chat",
+                "docs": "https://docs.laminas.dev/laminas-escaper/",
+                "forum": "https://discourse.laminas.dev",
+                "issues": "https://github.com/laminas/laminas-escaper/issues",
+                "rss": "https://github.com/laminas/laminas-escaper/releases.atom",
+                "source": "https://github.com/laminas/laminas-escaper"
+            },
+            "funding": [
+                {
+                    "url": "https://funding.communitybridge.org/projects/laminas-project",
+                    "type": "community_bridge"
+                }
+            ],
+            "time": "2022-10-10T10:11:09+00:00"
+        },
         {
         {
             "name": "laravel/framework",
             "name": "laravel/framework",
             "version": "v9.48.0",
             "version": "v9.48.0",
@@ -2583,6 +2645,119 @@
             },
             },
             "time": "2023-01-24T20:07:45+00:00"
             "time": "2023-01-24T20:07:45+00:00"
         },
         },
+        {
+            "name": "phpoffice/phpword",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHPOffice/PHPWord.git",
+                "reference": "8521612b39edeec9055d3688ad555342a40857dd"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHPOffice/PHPWord/zipball/8521612b39edeec9055d3688ad555342a40857dd",
+                "reference": "8521612b39edeec9055d3688ad555342a40857dd",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "ext-json": "*",
+                "ext-xml": "*",
+                "laminas/laminas-escaper": ">=2.6",
+                "php": "^7.1|^8.0"
+            },
+            "require-dev": {
+                "dompdf/dompdf": "^2.0",
+                "ext-gd": "*",
+                "ext-libxml": "*",
+                "ext-zip": "*",
+                "mpdf/mpdf": "^8.1",
+                "php-coveralls/php-coveralls": "^2.5",
+                "phpmd/phpmd": "^2.13",
+                "phpunit/phpunit": ">=7.0",
+                "symfony/process": "^4.4",
+                "tecnickcom/tcpdf": "^6.5"
+            },
+            "suggest": {
+                "dompdf/dompdf": "Allows writing PDF",
+                "ext-gd2": "Allows adding images",
+                "ext-xmlwriter": "Allows writing OOXML and ODF",
+                "ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template",
+                "ext-zip": "Allows writing OOXML and ODF"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-develop": "0.19-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PhpOffice\\PhpWord\\": "src/PhpWord"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-3.0"
+            ],
+            "authors": [
+                {
+                    "name": "Mark Baker"
+                },
+                {
+                    "name": "Gabriel Bull",
+                    "email": "me@gabrielbull.com",
+                    "homepage": "http://gabrielbull.com/"
+                },
+                {
+                    "name": "Franck Lefevre",
+                    "homepage": "https://rootslabs.net/blog/"
+                },
+                {
+                    "name": "Ivan Lanin",
+                    "homepage": "http://ivan.lanin.org"
+                },
+                {
+                    "name": "Roman Syroeshko",
+                    "homepage": "http://ru.linkedin.com/pub/roman-syroeshko/34/a53/994/"
+                },
+                {
+                    "name": "Antoine de Troostembergh"
+                }
+            ],
+            "description": "PHPWord - A pure PHP library for reading and writing word processing documents (OOXML, ODF, RTF, HTML, PDF)",
+            "homepage": "https://phpword.readthedocs.io/",
+            "keywords": [
+                "ISO IEC 29500",
+                "OOXML",
+                "Office Open XML",
+                "OpenDocument",
+                "OpenXML",
+                "PhpOffice",
+                "PhpWord",
+                "Rich Text Format",
+                "WordprocessingML",
+                "doc",
+                "docx",
+                "html",
+                "odf",
+                "odt",
+                "office",
+                "pdf",
+                "php",
+                "reader",
+                "rtf",
+                "template",
+                "template processor",
+                "word",
+                "writer"
+            ],
+            "support": {
+                "issues": "https://github.com/PHPOffice/PHPWord/issues",
+                "source": "https://github.com/PHPOffice/PHPWord/tree/1.0.0"
+            },
+            "time": "2022-11-15T20:24:50+00:00"
+        },
         {
         {
             "name": "phpoption/phpoption",
             "name": "phpoption/phpoption",
             "version": "1.9.0",
             "version": "1.9.0",

+ 4 - 0
resources/sass/_custom.scss

@@ -8,3 +8,7 @@
 .prod-tr:has(td:hover) {
 .prod-tr:has(td:hover) {
     background-color: rgba(220,224,255,0.85);
     background-color: rgba(220,224,255,0.85);
 }
 }
+
+.notice {
+    color: #bfbfbf;
+}

+ 1 - 1
resources/views/layouts/app.blade.php

@@ -79,7 +79,7 @@
         </main>
         </main>
     </div>
     </div>
 
 
-    <form action="{{ route('upload') }}" method="post" enctype="multipart/form-data" class="visually-hidden"
+    <form action="{{ route('upload_xls') }}" method="post" enctype="multipart/form-data" class="visually-hidden"
           onchange="this.submit()">
           onchange="this.submit()">
         @csrf
         @csrf
         <input class="form-control" type="file" id="import-form" name="file">
         <input class="form-control" type="file" id="import-form" name="file">

+ 20 - 2
resources/views/products/index.blade.php

@@ -62,7 +62,9 @@
                 <table class="table">
                 <table class="table">
                     <thead>
                     <thead>
                     <tr class="align-middle">
                     <tr class="align-middle">
-                        <th>Артикул, Серия</th>
+                        <th class="text-center">Артикул, Серия<br>
+                            <label><input type="checkbox" onchange="toggle(this)">&nbsp;Все</label>
+                        </th>
 
 
                         <th>Группа <br> Наименование <br> Наименование под образец формы</th>
                         <th>Группа <br> Наименование <br> Наименование под образец формы</th>
                         <th>Цена</th>
                         <th>Цена</th>
@@ -77,7 +79,7 @@
                         <tr class="align-middle prod-tr">
                         <tr class="align-middle prod-tr">
                             <td class="text-center">
                             <td class="text-center">
                                 <label>
                                 <label>
-                                    <input type="checkbox" class="form-check-inline me-0" name="prd_{{ $product->id }}"><br>
+                                    <input type="checkbox" class="form-check-inline me-0 prd-chk" name="ids" value="{{ $product->id }}"><br>
                                     {{ $product->article }}<br>
                                     {{ $product->article }}<br>
                                     {{ $product->series }}
                                     {{ $product->series }}
                                 </label>
                                 </label>
@@ -114,4 +116,20 @@
         </div>
         </div>
     </div>
     </div>
 
 
+
+    <script>
+        function toggle(source) {
+            let checkboxes = document.querySelectorAll('.prd-chk');
+            for(let i =0; i < checkboxes.length; i++){
+                checkboxes[i].checked = source.checked;
+            }
+        }
+
+
+
+
+
+
+    </script>
+
 @endsection
 @endsection

+ 115 - 20
resources/views/products/product.blade.php

@@ -16,47 +16,96 @@
                         </div>
                         </div>
                         <div class="col-6">
                         <div class="col-6">
                             <label for="series" class="form-label">Серия</label>
                             <label for="series" class="form-label">Серия</label>
-                            <input class="form-control" name="series" id="series" value="{{ $product->series }}">
+                            <input class="form-control @error('series') border-danger @enderror"
+                                   name="series" id="series" value="{{ old('series', $product->series) }}">
+                            @error('series')
+                            <div class="form-text text-danger" id="titleError">
+                                {{ $message }}
+                            </div>
+                            @enderror
                         </div>
                         </div>
                     </div>
                     </div>
 
 
                     <div class="row mt-3">
                     <div class="row mt-3">
                         <div class="col-6">
                         <div class="col-6">
                             <label for="name" class="form-label">Наименовение</label>
                             <label for="name" class="form-label">Наименовение</label>
-                            <input class="form-control" name="name" id="name" value="{{ $product->name }}">
+                            <input class="form-control @error('name') border-danger @enderror"
+                                   name="name" id="name" value="{{ old('name', $product->name) }}">
+                            @error('name')
+                            <div class="form-text text-danger" id="titleError">
+                                {{ $message }}
+                            </div>
+                            @enderror
                         </div>
                         </div>
                         <div class="col-6">
                         <div class="col-6">
                             <label for="name_for_form" class="form-label">Наименование под образец формы</label>
                             <label for="name_for_form" class="form-label">Наименование под образец формы</label>
-                            <input class="form-control" name="name_for_form" id="name_for_form"
-                                   value="{{ $product->name_for_form }}">
+                            <input class="form-control @error('name_for_form') border-danger @enderror"
+                                   name="name_for_form" id="name_for_form"
+                                   value="{{ old('name_for_form', $product->name_for_form) }}">
+                            @error('name_for_form')
+                            <div class="form-text text-danger" id="titleError">
+                                {{ $message }}
+                            </div>
+                            @enderror
                         </div>
                         </div>
                     </div>
                     </div>
 
 
                     <div class="row mt-3">
                     <div class="row mt-3">
                         <div class="col-6">
                         <div class="col-6">
                             <label for="product_group" class="form-label">Группа</label>
                             <label for="product_group" class="form-label">Группа</label>
-                            <input class="form-control" name="product_group" id="product_group"
-                                   value="{{ $product->product_group }}">
+                            <input class="form-control @error('product_group') border-danger @enderror"
+                                   name="product_group" id="product_group"
+                                   value="{{ old('product_group', $product->product_group) }}">
+                            @error('product_group')
+                            <div class="form-text text-danger" id="titleError">
+                                {{ $message }}
+                            </div>
+                            @enderror
                         </div>
                         </div>
                         <div class="col-6">
                         <div class="col-6">
                             <label for="price" class="form-label">Цена</label>
                             <label for="price" class="form-label">Цена</label>
-                            <input type="number" class="form-control" name="price" id="price"
-                                   value="{{ $product->price }}">
+                            <input type="number" class="form-control @error('price') border-danger @enderror"
+                                   name="price" id="price"
+                                   value="{{ old('price', $product->price) }}">
+                            @error('price')
+                            <div class="form-text text-danger" id="titleError">
+                                {{ $message }}
+                            </div>
+                            @enderror
                         </div>
                         </div>
                     </div>
                     </div>
 
 
-                    <label for="characteristics" class="form-label">Характеристики</label>
-                    <textarea class="form-control" name="characteristics" rows="4"
-                              id="characteristics">{{ $product->characteristics }}</textarea>
+                    <label for="characteristics" class="form-label mt-3">Характеристики</label>
+                    <textarea class="form-control @error('characteristics') border-danger @enderror"
+                              name="characteristics" rows="4"
+                              id="characteristics">{{ old('characteristics', $product->characteristics) }}</textarea>
+                    @error('characteristics')
+                    <div class="form-text text-danger" id="titleError">
+                        {{ $message }}
+                    </div>
+                    @enderror
 
 
-                    <label for="tech_description" class="form-label">Техническое описание</label>
-                    <textarea class="form-control" name="tech_description" rows="6"
-                              id="tech_description">{{ $product->tech_description }}</textarea>
+                    <label for="tech_description" class="form-label mt-3">Техническое описание</label>
+                    <textarea class="form-control @error('tech_description') border-danger @enderror"
+                              name="tech_description" rows="5"
+                              id="tech_description">{{ old('tech_description', $product->tech_description) }}</textarea>
+                    @error('tech_description')
+                    <div class="form-text text-danger" id="titleError">
+                        {{ $message }}
+                    </div>
+                    @enderror
 
 
-                    <label for="tech_description_short" class="form-label">Техническое описание сокращенное без
+                    <label for="tech_description_short" class="form-label mt-3">Техническое описание сокращенное без
                         артикула</label>
                         артикула</label>
-                    <textarea class="form-control" name="tech_description_short" rows="6"
-                              id="tech_description_short">{{ $product->tech_description_short }}</textarea>
+                    <textarea class="form-control  @error('tech_description_short') border-danger @enderror"
+                              name="tech_description_short" rows="5"
+                              id="tech_description_short">{{
+                                old('tech_description_short', $product->tech_description_short) }}</textarea>
+                    @error('tech_description_short')
+                    <div class="form-text text-danger" id="titleError">
+                        {{ $message }}
+                    </div>
+                    @enderror
 
 
                     <div class="col-12 text-center mt-3">
                     <div class="col-12 text-center mt-3">
                         <button type="submit" class="btn btn-primary">Сохранить</button>
                         <button type="submit" class="btn btn-primary">Сохранить</button>
@@ -65,11 +114,57 @@
             </div>
             </div>
 
 
             <div class="col-sm-12 col-md-6">
             <div class="col-sm-12 col-md-6">
-                <img src="{{ '/' . env('IMAGES_PATH', '/fill_images_path_in_env') . '/' . $product->image_path }}"
-                     alt="{{ $product->article }}" class="img-fluid">
-            </div>
+                <div class="col-12 text-end">
+                    <button class="btn btn-primary" onclick="document.getElementById('upload-image-form').click()">
+                        Загрузить
+                    </button>
+                    <br>
+                    <span class="notice">Изображение сохраниться в папку с изображениями товаров: stroyprofit.com/{{ env('IMAGES_PATH', 'fill-path') }}/<br>
+                    Имя файла будет сформировано уникальное, в начале имени до точки будет артикул товара.</span>
+
+
+                    <form action="{{ route('upload_image') }}" method="post" enctype="multipart/form-data"
+                          class="visually-hidden" onchange="this.submit()">
+                        @csrf
+                        <input type="hidden" name="article" value="{{ $product->article }}">
+                        <input type="file" name="filename" id="upload-image-form" accept=".jpg">
+                    </form>
+                </div>
+
+
+                @empty($product->image_path)
+                    <div class="text-center my-5 fs-3">Нет изображения</div>
+                @else
+                    <div class="col-12 text-center" >
+                        <img src="{{ '/' . env('IMAGES_PATH', '/fill_images_path_in_env') . '/' . $product->image_path }}"
+                             alt="{{ $product->article }}" class="img-fluid" style="max-height: 40vh;">
+                    </div>
+
+                @endempty
+                @if(count($images) > 1)
+                    <div class="col-12 mt-3">
+                        <div class="fs-5 mb-4">Найдены изображения с таким артикулом:</div>
+                        <div class="row justify-content-center align-items-end">
+                            @foreach($images as $image)
+                                <div class="h-100 col-md-3 col-sm-2 text-center">
+                                    <img class="img-thumbnail"
+                                         src="{{ '/' . env('IMAGES_PATH', 'zzz') . '/' . $image }}" alt="{{ $image }}">
+
+
+                                    <form action="{{ route('update_image', $product->id) }}" method="post">
+                                        @csrf
+                                        <input type="hidden" name="image_path" value="{{ $image }}">
+                                        <button type="submit" class="btn btn-primary my-3">Выбрать</button>
+                                    </form>
 
 
+                                </div>
+                            @endforeach
+                        </div>
+                    </div>
+                @endif
 
 
+
+            </div>
         </div>
         </div>
     </div>
     </div>
 
 

+ 3 - 4
routes/web.php

@@ -18,10 +18,9 @@ use Illuminate\Support\Facades\Route;
 
 
 Route::get('/', [ProductController::class, 'index'])->name('index');
 Route::get('/', [ProductController::class, 'index'])->name('index');
 Route::get('/product/{id}', [ProductController::class, 'product'])->name('view_product');
 Route::get('/product/{id}', [ProductController::class, 'product'])->name('view_product');
-Route::post('/upload_xls', [ProductController::class, 'upload'])->name('upload');
+Route::post('/upload_xls', [ProductController::class, 'upload_xls'])->name('upload_xls');
+Route::post('/upload_image', [ProductController::class, 'upload_image'])->name('upload_image');
 Route::post('/save_product', [ProductController::class, 'save_product'])->name('save_product');
 Route::post('/save_product', [ProductController::class, 'save_product'])->name('save_product');
+Route::post('/update_image/{id}', [ProductController::class, 'update_image'])->name('update_image');
 
 
 
 
-//Auth::routes();
-
-Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');

+ 17 - 5
todo.txt

@@ -2,16 +2,25 @@
 + постраницчный вывод таблицы товаров, количество товаров на странице
 + постраницчный вывод таблицы товаров, количество товаров на странице
 + фильры: общий поиск, серия, диапазон цен
 + фильры: общий поиск, серия, диапазон цен
 + редактирование товара (все поля, кроме изображения и артикула)
 + редактирование товара (все поля, кроме изображения и артикула)
++ при редатировании товара можно загружать изображения
++ если несколько изображений найдено по артикулу - можно выбрать одно
+
+
+
+
+
+todo выбор товаров с запоминаннием при переходах между страницами
+todo формирование документа ворд из выбранных товаров
+todo Авторизация в системе без разделения ролей на базе «манагера»
 
 
 
 
 
 
 
 
-todo Авторизация в системе без разделения ролей на базе «манагера».
 
 
 Примерное ТЗ.
 Примерное ТЗ.
 todo Авторизация в системе без разделения ролей на базе «манагера».
 todo Авторизация в системе без разделения ролей на базе «манагера».
-+Каталог товаров по данной таблице xlsx.
-+Возможность обновлять и загружать новые товары из этой (или ее части) таблицы xlsx.(по аналогии с «манагером»). Товары должны быть разделены по сериям.
++ Каталог товаров по данной таблице xlsx.
++ озможность обновлять и загружать новые товары из этой (или ее части) таблицы xlsx.(по аналогии с «манагером»). Товары должны быть разделены по сериям.
 
 
 * Все картинки загружаются на сайт в одну папку. Название файла картинки обязательно содержит артикул изделия, может состоять из любых символов и быть любой длины, но при этом в названии может присутствовать разделитель «точка», до которого происходит идентификация изделия.
 * Все картинки загружаются на сайт в одну папку. Название файла картинки обязательно содержит артикул изделия, может состоять из любых символов и быть любой длины, но при этом в названии может присутствовать разделитель «точка», до которого происходит идентификация изделия.
 *** upd картинки берутся с сайта стройпрофит, если она есть в наличии - подтягиватеся, если нет, то сообщение об этом при импорте
 *** upd картинки берутся с сайта стройпрофит, если она есть в наличии - подтягиватеся, если нет, то сообщение об этом при импорте
@@ -23,8 +32,11 @@ todo Должна присутствовать возможность сформ
 - как для одного изделия, так и для группы изделий (как из одной серии, так и из разных) ;
 - как для одного изделия, так и для группы изделий (как из одной серии, так и из разных) ;
 - в отдельный файл для каждого изделия из выборки и в общий файл из выборки.
 - в отдельный файл для каждого изделия из выборки и в общий файл из выборки.
 
 
-+Просмотр каталога постранично, поиск по каталогу, возможно фильтры (например по серии, цене и тп).
++ Просмотр каталога постранично, поиск по каталогу, возможно фильтры (например по серии, цене и тп).
 
 
 Редактирование товара, возможность подгрузить фото.  Фото загружаю на сайт я(админ), файл на сайт загружаю я, иначе велик риск уничтожения всей информации.
 Редактирование товара, возможность подгрузить фото.  Фото загружаю на сайт я(админ), файл на сайт загружаю я, иначе велик риск уничтожения всей информации.
 Выгрузка в xlsx.
 Выгрузка в xlsx.
-+Дизайн - стандартный шаблон.
++ Дизайн - стандартный шаблон.
+
+
+todo нужно каким-то образом запоминать ранее выбранные изображения у товаров, либо при загрузке предоставлять выбор