使用Vue.js和Laravel构建库存管理应用

使用Vue.js和Laravel创建库存管理应用程序,整合CosmicJS PHP库实现数据存储与管理,涵盖前端与后端开发流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文最初出现在 Cosmic JS Blog中

在本教程中,我们将使用Laravel和Vue.js作为前端创建一个简单的库存管理应用程序。 本教程假定您具有面向对象的php和javascript的基础知识,尽管我们将学习Laravel和Vue.js的基础知识,但建议您对它们的概念有基本的了解。 现在,我们已经清除了该问题,启动您的php服务器,让我们来构建一些东西。

TL; DR

入门:

由于这是一个laravel应用程序,因此您将需要创建一个新的laravel项目,确保您的服务器满足laravel服务器要求中所述的laravel要求,并确保服务器上已安装Composer。 一旦安装了作曲家,打开命令行,并进入服务器根目录,然后简单地运行

composer  create-project --prefer-dist laravel/ laravel  inventory

成功运行后,这将在目录清单中设置一个新的laravel项目。

设置新项目后,您将运行npm install或npm install-如果要在Windows上开发,请使用no-bin-links。 这将下载并设置我们所有的javascript依赖项。 为了能够查看我们的空laravel项目,只需从项目目录运行php artisan serve,这将从我们项目的根目录启动php服务器,然后您可以在浏览器网址中输入http://127.0.0.1:8000应该使用默认的laravel屏幕。

设置Cosmic JS php库

我们将使用Cosmic JS php库中的某些功能,将存储库下载到一个单独的文件夹中,我们将需要对其进行一些编辑才能与laravel一起正常使用。 在inventory/app/文件夹中,创建一个/Vendor/cosmicjs文件夹,然后将cosmicjs-php库的所有内容复制到其中,例如, cosmicjs.php的路径将cosmicjs.php app/Vendor/cosmicjs/cosmicjs.php 。 然后将app/Vendor/cosmicjs/curl类重命名为app/Vendor/cosmicjs/cosmiccurl并更改代码的此顶部:

class Curl  {
  ...
  }

namespace App \ Vendor \ cosmicjs ;
class CosmicCurl  {
  ....
}

我们所做的是在cosmiccurl文件中添加了一个命名空间,以便我们可以导入laravel并更改类名以匹配文件名。 完成此操作后,替换此部分的cosmicjs.php

include( "curl.php" );
$curl = new Curl;
class CosmicJS  {
  function __construct ( ) {
    global $curl;
    global $config;
    $ this ->curl = $curl;
    $ this ->config = $config;
    $ this ->config->bucket_slug = $config->bucket_slug;
    $ this ->config->object_slug = $config->object_slug;
    $ this ->config->read_key = $config->read_key;
    $ this ->config->write_key = $config->write_key;
    $ this ->config->url = "https://api.cosmicjs.com/v1/" . $ this ->config->bucket_slug;
    $ this ->config->objects_url = $ this ->config->url . "/objects?read_key=" . $ this ->config->read_key;
    $ this ->config->object_url = $ this ->config->url . "/object/" . $ this ->config->object_slug . "?read_key=" . $ this ->config->read_key;
    $ this ->config->media_url = $ this ->config->url . "/media?read_key=" . $ this ->config->read_key;
    $ this ->config->add_object_url = $ this ->config->url . "/add-object?write_key=" . $ this ->config->write_key;
    $ this ->config->edit_object_url = $ this ->config->url . "/edit-object?write_key=" . $ this ->config->write_key;
    $ this ->config->delete_object_url = $ this ->config->url . "/delete-object?write_key=" . $ this ->config->write_key;
  }

namespace App \ Vendor \ cosmicjs ;
use App \ Vendor \ cosmicjs \ CosmicCurl ;
class CosmicJS  {
    private $config;
    private $curl;
    function __construct ($bucket_slug, $type_slug,$object_slug = "" , $read_key = "" , $write_key = "" )  {
        $this ->curl = new CosmicCurl();
        $this ->config = new \stdClass();
        //$this->config = $config;
        $this ->config->bucket_slug = $bucket_slug;
        $this ->config->object_slug = $object_slug;
        $this ->config->type_slug = $type_slug;
        $this ->config->read_key = $read_key;
        $this ->config->write_key = $write_key;
        $this ->config->url = "https://api.cosmicjs.com/v1/" . $this ->config->bucket_slug;
        $this ->config->objects_url = $this ->config->url . "/objects?read_key=" . $this ->config->read_key;
        $this ->config->object_type_url = $this ->config->url . "/object-type/" . $this ->config->type_slug . "?read_key=" . $this ->config->read_key;
        $this ->config->object_url = $this ->config->url . "/object/" . $this ->config->object_slug . "?read_key=" . $this ->config->read_key;
        $this ->config->media_url = $this ->config->url . "/media?read_key=" . $this ->config->read_key;
        $this ->config->add_object_url = $this ->config->url . "/add-object?write_key=" . $this ->config->write_key;
        $this ->config->edit_object_url = $this ->config->url . "/edit-object?write_key=" . $this ->config->write_key;
        $this ->config->delete_object_url = $this ->config->url . "/delete-object?write_key=" . $this ->config->write_key;
    }

所做的更改是它使用其名称空间导入了cosmiccurl,它使我们能够在laravel中快速创建cosmicjs对象的多个实例,只需通过构造函数参数进行初始化即可,而不必设置一些会变得混乱的配置变量当用于大型应用程序时。 最后,将以下函数添加到cosmicjs.php文件中。

public function getByObjectSlug ($key,$slug)
     {   
        $this ->config->object_by_meta_object = $this ->config->url . "/object-type/" . $this ->config->type_slug . "/search?metafield_key=" . $key . "&metafield_object_slug=" .$slug;
        $data = json_decode( $this ->curl->get( $this ->config->object_by_meta_object));
        return $data;
    }

构建我们的应用

现在我们已经在app / Vendor文件夹中设置了cosmicjs库,是时候实际构建一些东西了。 由于所有请求都将由app/Http/Controller/IndexController.php文件处理,因此将其打开并复制并粘贴此代码。

<?php
namespace App \ Http \ Controllers ;
use Illuminate \ Http \ Request ;
use App \ Vendor \ cosmicjs \ CosmicJS ;
use GuzzleHttp \ Client ;
class IndexController extends Controller  {
    private $locations_cosmic;
    private $items_cosmic;
    private $bucket_slug = '' ;
    private $read_key = '' ;
    private $write_key = '' ;
    public function __construct ()  {
        //initialize cosmicjs php instance for fetching all locations
        $this ->bucket_slug = config( 'cosmic.slug' );
        $this ->read_key = config( 'cosmic.read' );
        $this ->write_key = config( 'cosmic.write' );
        $this ->locations_cosmic = new CosmicJS( $this ->bucket_slug, 'locations' );
        $this ->items_cosmic = new CosmicJS( $this ->bucket_slug, 'items' , $this ->read_key, $this ->write_key);
    }
    public function index ($location = null)  {
        //get objects with cosmic-js php
        $locations = $this ->locations_cosmic->getObjectsType();
        //set locations and bucket_slug variable to be passed to view
        if (property_exists($locations, 'objects' )) {
            $data[ 'locations' ] = $locations->objects;
        }
        else
        {
            $data[ 'locations' ] = [];
        }
        $data[ 'bucket_slug' ] = $this ->bucket_slug;
        //if location slug was passed in url, pass it to view as well
        if ($location) {
            $data[ 'location_slug' ] = $location;
        } else {
            $data[ 'location_slug' ] = '' ;
        }
        //load view
        return view( 'index' , $data);
    }
    //fetch items for location based on slug
    public function itemsByLocation ($slug)  {
        //fetch items using the cosmicjs library's custom function
        $items = $this ->items_cosmic->getByObjectSlug( 'location' , $slug);
        //if the returned value has "object" property, pass it 
        if (property_exists($items, 'objects' )) {
            //returning arrays in laravel automatically converts it to json string
            return $items->objects;
        } else {
            return 0 ;
        }
    }
    public function newLocation (Request $request)  {
        //get passed input
        $title = $request->input( 'title' );
        $address = $request->input( 'address' );
        $picture = $request->input( 'image' );
        //set data array
        $data[ 'title' ] = $title;
        $data[ 'type_slug' ] = "locations" ;
        $data[ 'bucket_slug' ] = $this ->bucket_slug;
        $metafields = array ();
        $address_data[ 'key' ] = "address" ;
        $address_data[ 'type' ] = 'textarea' ;
        $address_data[ 'value' ] = $address;
        if ($picture != '' ) {
            $picture_data[ 'key' ] = "picture" ;
            $picture_data[ 'type' ] = 'file' ;
            $picture_data[ 'value' ] = $picture;
            array_push($metafields, $picture_data);
        }
        array_push($metafields, $address_data);
        $data[ 'metafields' ] = $metafields;
        //create a new guzzle client
        $client = new Client();
        //create guzzle request with data array passed as json value
        $result = $client->post( 'https://api.cosmicjs.com/v1/' . $this ->bucket_slug . '/add-object' , [
            'json' => $data,
            'headers' => [
                'Content-type' => 'application/json' ,
            ]
        ]);
        //flash message
        $request->session()->flash( 'status' , 'The location"' . $title . '" was successfully locations' );
        //return result body
        return $result->getBody();
    }
    //create a new item
    public function newItem (Request $request)  {
        //get data
        $name = $request->input( 'name' );
        $count = $request->input( 'count' );
        $location_id = $request->input( 'location' );
        $picture = $request->input( 'image' );
        //create data array to be passed
        $data[ 'title' ] = $name;
        $data[ 'type_slug' ] = "items" ;
        $data[ 'bucket_slug' ] = $this ->bucket_slug;
        $count_metafield[ 'key' ] = "count" ;
        $count_metafield[ 'value' ] = $count;
        $count_metafield[ 'type' ] = "text" ;
        $location_meta[ 'key' ] = "location" ;
        $location_meta[ 'object_type' ] = "locations" ;
        $location_meta[ 'type' ] = "object" ;
        $location_meta[ 'value' ] = $location_id;
        $metafields = array ();
        //set picture if passed into request
        if ($picture != '' ) {
            $picture_data[ 'key' ] = "picture" ;
            $picture_data[ 'type' ] = 'file' ;
            $picture_data[ 'value' ] = $picture;
            array_push($metafields, $picture_data);
        }
        array_push($metafields, $count_metafield);
        array_push($metafields, $location_meta);
        $data[ 'metafields' ] = $metafields;
        $client = new Client();
        $result = $client->post( 'https://api.cosmicjs.com/v1/' . $this ->bucket_slug . '/add-object' , [
            'json' => $data,
            'headers' => [
                'Content-type' => 'application/json' ,
            ]
        ]);
        //flash message
        $request->session()->flash( 'status' , 'The Item "' . $name . '" was successfully created' );
        //return result body
        return $result->getBody();
    }
    public function editItem (Request $request)  {
        $name = $request->input( 'name' );
        $count = $request->input( 'count' );
        $slug = $request->input( 'slug' );
        $location_id = $request->input( 'location_id' );
        $data[ 'title' ] = $name;
        $data[ 'slug' ] = $slug;
        $count_meta[ 'key' ] = "count" ;
        $count_meta[ 'value' ] = $count;
        $count_meta[ 'type' ] = "text" ;
        $location_meta[ 'key' ] = "location" ;
        $location_meta[ 'object_type' ] = "locations" ;
        $location_meta[ 'type' ] = "object" ;
        $location_meta[ 'value' ] = $location_id;
        $metafields = array ();
        //set picture if passed into request
        if ($request->input( 'image' )) {
            $picture_data[ 'key' ] = "picture" ;
            $picture_data[ 'type' ] = 'file' ;
            $picture_data[ 'value' ] = $request->input( 'image' );
            array_push($metafields, $picture_data);
        }
        array_push($metafields, $count_meta);
        array_push($metafields, $location_meta);
        $data[ 'metafields' ] = $metafields;
        $client = new Client();
        $result = $client->put( 'https://api.cosmicjs.com/v1/' . $this ->bucket_slug . '/edit-object' , [
            'json' => $data,
            'headers' => [
                'Content-type' => 'application/json' ,
            ]
        ]);
        //flash message
        $request->session()->flash( 'status' , 'The Item was successfully edited!' );
        //return result body
        return $result->getBody();
    }
    public function deleteItem (Request $request, $slug)  {
        //create new client and delete item
        $client = new Client();
        $result = $client->delete( 'https://api.cosmicjs.com/v1/' . $this ->bucket_slug . '/' . $slug, [
            'headers' => [
                'Content-type' => 'application/json' ,
            ]
        ]);
        //flash message
        $request->session()->flash( 'status' , 'The Item was successfully deleted!' );
        return $result;
    }
}

上面的代码很自言自语,带有注释

注意事项:

  • 我们创建一个新的Cosmic JS实例来检索位置
  • 我们正在设置vuejs前端将与之交互的所有功能
  • $ client = new CLient()创建一个新的食人鱼实例,我们用它来调用宇宙api

接下来,我们将在routes/web.php文件中创建路由。 打开文件,然后复制此代码并将其粘贴到其中。

<?php
Route::get( '/{location?}' , 'IndexController@index' );
Route::get( 'items/{slug}' , 'IndexController@itemsByLocation' );
Route::post( 'locations/new' , 'IndexController@newLocation' );
Route::post( 'items/new' , 'IndexController@newItem' );
Route::post( 'items/edit' , 'IndexController@editItem' );

我们在做什么

我们正在将所有IndexCOntroller的功能注册到路由,以便前端可以访问它们。

建立前端

还记得我们的IndexController返回视图('index',$ data);中的这段代码吗? 很好的时间来创建将要加载的视图。 打开/resources/views文件夹并打开master.blade.php然后将其复制并粘贴到其中。

< html lang = "{{ config('app.locale') }}" >
    < head >
        < meta charset = "utf-8" >
        < meta http-equiv = "X-UA-Compatible" content = "IE=edge" >
        < meta name = "viewport" content = "width=device-width, initial-scale=1" >
        <!-- Set Csrf token on all pages -->
        < meta name = "csrf-token" content = "{{ csrf_token() }}" >
        <!-- Load Bootstrap-->
        < link rel = "stylesheet" href = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity = "sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin = "anonymous" >
        < link href = "https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/6.6.2/sweetalert2.css" rel = "stylesheet" type = "text/css" >
        < title > Inventory Manger </ title >
        <!-- Fonts -->
        < link rel = "stylesheet" href = "{{ asset('css/font-awesome/css/font-awesome.min.css')}}" />
        < link href = "https://fonts.googleapis.com/css?family=Raleway:100,600" rel = "stylesheet" type = "text/css" >
        < script src = "https://use.fontawesome.com/682442a8be.js" > </ script >
        <!-- Set Csrf token to be used by javascript and axios-->
        < script > 
window .Laravel = <?php
echo json_encode([
     'csrfToken'  => csrf_token(),
]);
?>
         </ script >
        <!-- Styles -->
        < style > 
            .location-tab {
                height : 104px ;
                padding-left : 150px ;
            }
            
            .location-tab > img {
                position : absolute;
                left : 0 ;
                top : 0 ;
                height : 100% ;
                width : auto;
                max-width : 130px ;
            }
            
            .text-primary {
                color : #29ABE2 !important ;
            }
            
            .panel-heading {
                background-color : #29ABE2 !important ;
                color : white !important ;
            }
            
            .panel {
                border-color : #29ABE2 !important ;
            }
            
            .btn-primary {
                background-color : #29ABE2 !important ;
                color : white !important ;
                border-color : #29ABE2 !important ;
                border-radius : 3px ;
                margin : 10px 0 ;
            }
         </ style >
    </ head >
    < body >
        < div class = "container" >
            < div id = "wrapper" >
                @yield('content')
            </ div >
        </ div >
        <!-- Load Jquery and bootstrap js-->
        < script src = "https://code.jquery.com/jquery-3.2.1.min.js" integrity = "sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin = "anonymous" > </ script >
        < script src = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity = "sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin = "anonymous" > </ script >
        < script src = "https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/6.6.2/sweetalert2.min.js" > </ script >
        < script src = "{{ asset('/js/app.js')}}" > </ script >
        @yield('scripts')
    </ body >
</ html >

master.blade.php将用作可扩展布局,然后我们可以将其用作所有其他视图的父级布局。 现在,在同一文件夹中创建一个index.blade.php文件,并将其粘贴到其中。

@extends( 'master' )
@section( 'content' )
<div class =" row ">
    < div class =" col - md -12">
        < div style =" float : left ">
            < h1 > Inventory Management </ h1 >
        </ div >
        < div style =" float : right ; padding - top : 20 px ">
            < a class =" btn btn - default ">< i class =" fa fa - github "></ i > View on Github </ a >
        </ div >
    </ div >
</ div >
< div class =" row ">
    < div class =" col - md -12">
        < div style =" float : right ; margin - bottom : 15 px ;">< a href =" https :// cosmicjs . com " target =" _blank " style =" text - decoration : none ;">< img class =" pull - left " src =" https :// cosmicjs . com / images / logo . svg " width ="28" height ="28" style =" margin - right : 10 px ;">< span style =" color : rgb (102, 102, 102); position : relative ; top : 3 px ;"> Proudly powered by Cosmic JS </ span ></ a ></ div >
    </ div >
</ div >
< div class =" row " style =" font - size : 16 px ">
    <!-- Display vue component and set props from given data  -->
    < inventory message =" {{Session::get( 'status' )}} " :initial-locations=" {{ json_encode($locations) }} " slug=" {{ $bucket_slug }} " location-slug=" {{ $location_slug }} "></inventory>
</div>
@endsection
@section('scripts')
<script>
</script>
@endsection

注意事项

  1. 我们创建了一个主布局,其中包含可用内容,脚本和样式的可用部分,我们的其他视图可以扩展这些部分。
  2. 我们添加了vue组件(将在下一部分中创建),其中props作为控制器提供给视图的数据

创建我们的控制器

本节假定您具有Vuejs的基本知识,否则,我建议您重新学习Vuejs,因为解释某些vue函数的工作原理超出了本教程的范围。 现在开始,打开命令提示符并cd到应用程序的文件夹,然后运行npm run watch来启动laravel mix,这将在我们对任何文件进行更改时编译我们的资产,或者您可以在任何时候键入npm run dev您需要自己编译资产。 打开/resources/assets/js/app.js文件并更改它

Vue.component( 'example' , require ( './components/Example.vue' ));

Vue.component( 'inventory' , require ( './components/Inventory.vue' ));

在这里,我们将默认示例组件替换为将要创建的名为清单的组件。在/resources/assets/js/components文件夹中,创建和Inventory.vue文件来容纳我们的组件。 在新创建的文件中复制此代码并将其粘贴到其中

< template >
    < div >
        <!---- ADD LOCATION FORM -->
        < div v-if = "add_location" >
            < button class = "btn btn-primary" v-on:click = "add_location=false" > < span class = "glyphicon glyphicon-chevron-left" aria-hidden = "true" > </ span > Go back </ button >
            < div class = "panel panel-default" >
                < div class = "panel-heading" > Add New Location </ div >
                < div class = "panel-body" >
                    < form id = "location_form" name = "location" >
                        < div class = "form-group" >
                            < label for = "name" > Name </ label >
                            < input type = "text" class = "form-control" name = "title" required = "" >
                            < label for = "address" > Address </ label >
                            < input type = "text" class = "form-control" name = "address" required = "" >
                            < label for = "image" > Image </ label >
                            < input type = "file" class = "form-control media" name = "media" />
                        </ div >
                        < button type = "submit" class = "btn btn-primary" :class = "{disabled: isDisabled}" v-on:click.prevent = "addLocation" > Submit </ button >
                    </ form >
                </ div >
            </ div >
        </ div >
        < div v-else >
            <!---- LOCATIONS LIST -->
            < div v-if = "unselected" >
                < button class = "btn btn-primary pull-right" v-on:click = "add_location = true" > < span class = "glyphicon glyphicon-plus" aria-hidden = "true" > </ span > Add New </ button >
                < ul class = "list-group" >
                    < button type = "button" class = "list-group-item location-tab text-primary" :class = "{disabled: list_disable}" v-for = "location in locations" v-on:click = "fetchItems(location)" > < img v-if = "location.metadata.hasOwnProperty('picture')" :src = "location.metadata.picture.url" > {{ location.title }}  -  {{ location.metadata.address}} </ button >
                </ ul >
            </ div >
            < div v-else >
                <!---- ADD ITEM FORM -->
                < div v-if = "add_item" >
                    < button class = "btn btn-primary" v-on:click = "add_item=false" > < span class = "glyphicon glyphicon-chevron-left" aria-hidden = "true" > </ span > Go back </ button >
                    < div class = "panel panel-default" >
                        < div class = "panel-heading" > Add New Item </ div >
                        < div class = "panel-body" >
                            < form id = "item_form" >
                                < div class = "form-group" >
                                    < label for = "name" > Name </ label >
                                    < input type = "text" class = "form-control" name = "name" >
                                </ div >
                                < div class = "form-group" >
                                    < label for = "count" > Count </ label >
                                    < input type = "number" class = "form-control" name = "count" >
                                </ div >
                                < div >
                                    < label for = "image" > Image </ label >
                                    < input type = "file" class = "form-control media" name = "media" />
                                </ div >
                                < button type = "submit" class = "btn btn-primary" :class = "{disabled: isDisabled}" v-on:click.prevent = "addItem" > Submit </ button >
                            </ form >
                        </ div >
                    </ div >
                </ div >
                <!---- EDIT ITEM FORM -->
                < div v-else-if = "edit_item" >
                    < button class = "btn btn-primary" v-on:click = "edit_item=false" > < span class = "glyphicon glyphicon-chevron-left" aria-hidden = "true" > </ span > Go back </ button >
                    < div class = "panel panel-default" >
                        < div class = "panel-heading" > Edit  {{ selected_item.title }} </ div >
                        < div class = "panel-body" >
                            < form id = "edit_item" >
                                < div class = "form-group" >
                                    < label for = "name" > Name </ label >
                                    < input type = "text" class = "form-control" name = "name" :value = "selected_item.title" >
                                </ div >
                                < div class = "form-group" >
                                    < label for = "count" > Count </ label >
                                    < input type = "number" class = "form-control" name = "count" :value = "selected_item.metadata.count" >
                                </ div >
                                < button type = "submit" class = "btn btn-primary" :class = "{disabled: isDisabled}" v-on:click.prevent = "editItem" > Submit </ button >
                            </ form >
                        </ div >
                    </ div >
                </ div >
                < div v-else >
                    <!---- ITEMS LIST -->
                    < button class = "btn btn-primary" v-on:click = "unselected=true" > < span class = "glyphicon glyphicon-chevron-left" aria-hidden = "true" > </ span > Go back </ button >
                    < button class = "btn btn-primary pull-right" v-on:click = "add_item = true" > < span class = "glyphicon glyphicon-plus" aria-hidden = "true" > </ span > Add New Item </ button >
                    < div class = "panel panel-default" >
                        < div class = "panel-heading" > {{ selected_location.title }} </ div >
                        < div class = "panel-body" >
                            < ul class = "list-group" >
                                < button type = "button" class = "list-group-item text-primary location-tab" :class = "{disabled: isDisabled}" v-for = "item in items" > < img v-if = "item.metadata.hasOwnProperty('picture')" :src = "item.metadata.picture.url" > {{ item.title }}  -  {{ item.metadata.count }}  < div class = "pull-right" > < span class = "glyphicon glyphicon-pencil" aria-hidden = "true" v-on:click.prevent = "openEdit(item)" > </ span > < span class = "glyphicon glyphicon-trash" aria-hidden = "true" v-on:click.prevent = "deleteItem(item)" style = "padding: 0 5px;" > </ span > </ div > </ button >
                            </ ul >
                        </ div >
                    </ div >
                </ div >
            </ div >
        </ div >
    </ div >
</ template >
< script > 
    export default {
        mounted() {
            var self = this ;
            //If location slug was passed show items for that location
            if ( this .message)
            {
                swal( this .message);
            }
            if ( this .locationSlug)
            {
                this .unselected = false ;
                //find location with slug
                var item = this .locations.filter( function ( obj )
                 {
                    return obj.slug === self.locationSlug;
                });
                this .selected_location = item[ 0 ];
                this .fetchItems( this .selected_location);
            }
        },
        props : [ 'initial-locations' , 'slug' , 'location-slug' , 'message' ],
        data : function ( )  {
            return {
                edit_item : false ,
                locations : this .initialLocations,
                isDisabled : false ,
                list_disable : false ,
                unselected : true ,
                items : [],
                add_location : false ,
                selected_location : [],
                selected_item : [],
                add_item : false
            };
        },
        methods : {
            fetchItems(location)
            {
                //disable the list and fetch items from laravel
                var self = this ;
                this .list_disable = true ;
                axios.get( 'items/' + location.slug).then( response => {
                    if (response.data.constructor === Array )
                    {
                        self.items = (response.data);
                        self.selected_location = location;
                        self.unselected = false ;
                    } else {
                        self.selected_location = location;
                        self.items = [];
                        self.unselected = false ;
                    }
                    self.list_disable = false ;
                });
            },
            addLocation()
            {
                //disable button
                this .isDisabled = true ;
                var image = '' ;
                var form = $( "#location_form" )[ 0 ];
                var data = new FormData(form);
                //Check if image is selected then upload image first
                if ($( "#location_form .media" ).val() !== '' )
                {
                    //delete X-csrf-token default header as it is not accepted by cosmic api
                    delete axios.defaults.headers.common[ "X-CSRF-TOKEN" ];
                    axios.post( 'https://api.cosmicjs.com/v1/' + this .slug + '/media' , data).then( function ( response )
                     {
                        //set x-csrf-token again
                        window .axios.defaults.headers.common[ 'X-CSRF-TOKEN' ] = window .Laravel.csrfToken;
                        //get image name, append to formdata and send form data to laravel to add location
                        image = response.data.media.name;
                        data.set( 'image' , image);
                        axios.post( 'locations/new' , data).then( response => {
                            location.reload( true );
                        });
                    });
                } else {
                    window .axios.defaults.headers.common[ 'X-CSRF-TOKEN' ] = window .Laravel.csrfToken;
                    //send form data to laravel without image
                    axios.post( 'locations/new' , data).then( response => {
                        location.reload( true );
                    });
                }
            },
            //set selected item and open edit item section
            openEdit(item)
            {
                this .selected_item = item;
                this .edit_item = true ;
            },
            addItem() {
                var self = this ;
                this .isDisabled = true ;
                var form = $( '#item_form' )[ 0 ];
                var data = new FormData(form);
                data.append( 'location' , this .selected_location._id);
                //Check if image is selected the upload image first
                if ($( "#item_form .media" ).val() !== '' )
                {
                    //delete X-csrf-token default header as it is not allowed by cosmic api and post
                    delete axios.defaults.headers.common[ "X-CSRF-TOKEN" ];
                    axios.post( 'https://api.cosmicjs.com/v1/' + this .slug + '/media' , data).then( function ( response )
                     {
                        //set x-csrf-token again
                        window .axios.defaults.headers.common[ 'X-CSRF-TOKEN' ] = window .Laravel.csrfToken;
                        //get image name, append to formdata and send form data to laravel to add location
                        var image = response.data.media.name;
                        data.set( 'image' , image);
                        axios.post( 'items/new' , data).then( response => {
                            //refresh page BUT pass location_slug, which then makes the app load into the passed location
                            window .location.href = "./" + self.selected_location.slug;
                        });
                    });
                } else {
                    //add header back after post
                    window .axios.defaults.headers.common[ 'X-CSRF-TOKEN' ] = window .Laravel.csrfToken;
                    //send form data to laravel without image
                    axios.post( 'items/new' , data).then( response => {
                        window .location.href = "./" + self.selected_location.slug;
                    });
                }
            },
            editItem()
            {
                //edit item, by sending data to IndexController's editItem() function
                var self = this ;
                var form = $( "#edit_item" )[ 0 ];
                var data = new FormData(form);
                this .isDisabled = true ;
                data.append( 'slug' , this .selected_item.slug);
                if ( this .selected_item.metadata.hasOwnProperty( 'picture' )){
                    data.append( 'image' , this .selected_item.metafields[ 0 ].value);
                }
                
                data.append( 'location_id' , this .selected_location._id);
                axios.post( 'items/edit' , data).then( response => {
                    //refresh page BUT pass location_slug, which then makes the app load into the passed location
                    window .location.href = "./" + self.selected_location.slug;
                });
            },
            deleteItem(item)
            {
                var self = this ;
                swal({
                    title : 'Are you sure?' ,
                    text : 'You will not be able to recover this item!' ,
                    type : 'warning' ,
                    showCancelButton : true ,
                    confirmButtonText : 'Yes, delete it!' ,
                    cancelButtonText : 'Nope, still need it'
                }).then( function ( ) {
                    axios.get( 'item/' + item.slug + '/delete' ).then( response => {
                    window .location.href = "./" + self.selected_location.slug;
                });
                })
                
            }
        }
    }
 </ script >

最大的问题是,这里发生了什么(很多)?

在我们的Vue组件中发生了很多事情,因为大多数前端都在这里,为了使教程简单起见,将阐明各节和变量的主要目标,并且代码中的注释还说明了该节的内容是为了完成

  1. 我们首先设置一些布尔值(edit_item,add_item,add_location,unselected),这些帮助在变量已更改的情况下切换应用的视图,例如,当edit_item为true时,视图将切换为编辑项形式
  2. isDisable和list_disable用于通过将某些ui元素的值绑定到“禁用”的引导按钮类来禁用某些ui元素,例如s按钮
  3. 挂载函数中的代码,只需检查是否传递了位置信息,如果是,则将视图切换到该位置的项目
  4. 创建的方法会在执行操作后执行调用,其主要逻辑在注释中说明
  5. 我们使用axios对laravel后端进行了所有调用
  6. 对于图片上传,我们首先检查是否选择了文件,然后首先上传所选文件,然后再创建一个新图片并将其图片元数据设置为返回的图片名称。

注意

  1. 确保更改完成后资产已成功编译,如果要手动编译资产,只需运行npm run production即可将其编译为productin模式。
  2. 我们创建一个自变量,并将其设置为大多数函数的开头,因为如果在某些嵌套函数调用中使用它,则会开始松散this变量的上下文。 可以在此堆栈溢出后找到更多信息

设置铲斗弹头

现在我们要设置铲斗弹头。 我们希望能够通过运行artisan php artisan make:command SetSlug进行设置,因此运行php artisan make:command SetSlug 。 现在导航到app/console/Commands/SetSlug并将其复制并粘贴到其中:

<?php
namespace App \ Console \ Commands ;
use Illuminate \ Console \ Command ;
class SetSlug extends Command  {
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'bucket {slug} {read?} {write?}' ;
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Set the bucket slug' ;
    /**
     * Create a new command instance.
     *
     * @return void
     */
    protected $files;
    protected $read;
    protected $write;
    public function __construct (\Illuminate\Filesystem\Filesystem $files)  {
        parent ::__construct();
        $this ->files = $files;
        
    }
    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle ()  {
        $this ->read = $this ->argument( 'slug' );
        $this ->write = $this ->argument( 'slug' );
        $config_path = base_path() . "/config/cosmic.php" ;
        $content = "<?php\n\treturn [\n\t\t'slug' => '" . $this ->argument( 'slug' ) . "',\n\t\t"
                . "'read' => '" . $this ->argument( 'read' ). "',\n\t\t"
                . "'write' => '" . $this ->argument( 'write' ). "',\n\t];" ;
        $this ->files->put($config_path, $content);
        echo "Bucket variables set" ;
    }
}

我们正在做的是在config / cosmic.php中打开/创建一个配置文件,并从命令中保存我们的变量,现在可以使用php artisan bucket bucket_slug read_key write_key来设置bucket Slug。 现在,在命令部分的app / console / kernel.php中将其注册为

protected $commands = [
        Commands\SetSlug::class
    ];

结论

我们能够使用vue,宇宙的Js php库,大量的消耗和大量的axios创建和更新项目。 您可以随意修改代码并进行自己的修改,这是删除项目,移动到新位置的一种方式,您可以自己命名,记住我们只是将Cosmic JS与Laravel惊人地结合使用而已。 因此,继续创造惊人的东西。

From: https://hackernoon.com/building-an-inventory-management-app-using-vue-js-and-laravel-1abc492d95d7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值