 
 
      本日、このトレーニングプロジェクトの作業は完了します。 つまり、この記事では、新しい顧客の記録と財務書類をシステムに追加するページの開発と、このデータを編集するメカニズムの作成について説明します。 ここでは、APIの改善点をいくつか見て、Budget Managerを稼働状態にします。
APIの改訂
まず、
models
      
      フォルダーに移動し、
budget.js
      
      ファイルを開きます。 モデルの
description
      
      フィールドを追加します。
 description: {   type: String,   required: true },
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      app/api
      
      フォルダーに移動し、その中にある
budget.js
      
      ファイルを開きます。 ここでは、新しいドキュメントが正しく処理されるようにデータストレージ関数
store
      
      を編集し、ドキュメントを編集できる
edit
      
      機能を追加し、ドキュメントを削除するために必要な
remove
      
      関数を追加し、ドキュメントをフィルター処理できる
getByState
      
      関数を追加します。 完全なファイルコードを次に示します。 表示するには、対応するブロックを展開します。 将来、同じ方法で大きなコードフラグメントが発行されます。
  ソースコード 
       const mongoose = require('mongoose'); const api = {}; api.store = (User, Budget, Client, Token) => (req, res) => { if (Token) {   Client.findOne({ _id: req.body.client }, (error, client) => {     if (error) res.status(400).json(error);     if (client) {       const budget = new Budget({         client_id: req.body.client,         user_id: req.query.user_id,         client: client.name,         state: req.body.state,         description: req.body.description,         title: req.body.title,         total_price: req.body.total_price,         items: req.body.items       });       budget.save(error => {         if (error) return res.status(400).json(error)         res.status(200).json({ success: true, message: "Budget registered successfully" })       })     } else {       res.status(400).json({ success: false, message: "Invalid client" })     }   }) } else return res.status(401).send({ success: false, message: 'Unauthorized' }); } api.getAll = (User, Budget, Token) => (req, res) => { if (Token) {   Budget.find({ user_id: req.query.user_id }, (error, budget) => {     if (error) return res.status(400).json(error);     res.status(200).json(budget);     return true;   }) } else return res.status(403).send({ success: false, message: 'Unauthorized' }); } api.getAllFromClient = (User, Budget, Token) => (req, res) => { if (Token) {   Budget.find({ client_id: req.query.client_id }, (error, budget) => {     if (error) return res.status(400).json(error);     res.status(200).json(budget);     return true;   }) } else return res.status(401).send({ success: false, message: 'Unauthorized' }); } api.index = (User, Budget, Client, Token) => (req, res) => { if (Token) {   User.findOne({ _id: req.query.user_id }, (error, user) => {     if (error) res.status(400).json(error);     if (user) {       Budget.findOne({ _id: req.query._id }, (error, budget) => {         if (error) res.status(400).json(error);         res.status(200).json(budget);       })     } else {       res.status(400).json({ success: false, message: "Invalid budget" })     }   }) } else return res.status(401).send({ success: false, message: 'Unauthorized' }); } api.edit = (User, Budget, Client, Token) => (req, res) => { if (Token) {   User.findOne({ _id: req.query.user_id }, (error, user) => {     if (error) res.status(400).json(error);     if (user) {       Budget.findOneAndUpdate({ _id: req.body._id }, req.body, (error, budget) => {         if (error) res.status(400).json(error);         res.status(200).json(budget);       })     } else {       res.status(400).json({ success: false, message: "Invalid budget" })     }   }) } else return res.status(401).send({ success: false, message: 'Unauthorized' }); } api.getByState = (User, Budget, Client, Token) => (req, res) => { if (Token) {   User.findOne({ _id: req.query.user_id }, (error, user) => {     if (error) res.status(400).json(error);     if (user) {       Budget.find({ state: req.query.state }, (error, budget) => {         console.log(budget)         if (error) res.status(400).json(error);         res.status(200).json(budget);       })     } else {       res.status(400).json({ success: false, message: "Invalid budget" })     }   }) } else return res.status(401).send({ success: false, message: 'Unauthorized' }); } api.remove = (User, Budget, Client, Token) => (req, res) => { if (Token) {   Budget.remove({ _id: req.query._id }, (error, removed) => {     if (error) res.status(400).json(error);     res.status(200).json({ success: true, message: 'Removed successfully' });   }) } else return res.status(401).send({ success: false, message: 'Unauthorized' }); } module.exports = api;
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      api
      
      フォルダーからclient.jsファイルに同様の変更を加えます。
  ソースコード 
       const mongoose = require('mongoose'); const api = {}; api.store = (User, Client, Token) => (req, res) => { if (Token) {   User.findOne({ _id: req.query.user_id }, (error, user) => {     if (error) res.status(400).json(error);     if (user) {       const client = new Client({         user_id: req.query.user_id,         name: req.body.name,         email: req.body.email,         phone: req.body.phone,       });       client.save(error => {         if (error) return res.status(400).json(error);         res.status(200).json({ success: true, message: "Client registration successful" });       })     } else {       res.status(400).json({ success: false, message: "Invalid client" })     }   }) } else return res.status(403).send({ success: false, message: 'Unauthorized' }); } api.getAll = (User, Client, Token) => (req, res) => { if (Token) {   Client.find({ user_id: req.query.user_id }, (error, client) => {     if (error) return res.status(400).json(error);     res.status(200).json(client);     return true;   }) } else return res.status(403).send({ success: false, message: 'Unauthorized' }); } api.index = (User, Client, Token) => (req, res) => { if (Token) {   User.findOne({ _id: req.query.user_id }, (error, user) => {     if (error) res.status(400).json(error);     if (user) {       Client.findOne({ _id: req.query._id }, (error, client) => {         if (error) res.status(400).json(error);         res.status(200).json(client);       })     } else {       res.status(400).json({ success: false, message: "Invalid client" })     }   }) } else return res.status(401).send({ success: false, message: 'Unauthorized' }); } api.edit = (User, Client, Token) => (req, res) => { if (Token) {   User.findOne({ _id: req.query.user_id }, (error, user) => {     if (error) res.status(400).json(error);     if (user) {       Client.findOneAndUpdate({ _id: req.body._id }, req.body, (error, client) => {         if (error) res.status(400).json(error);         res.status(200).json(client);       })     } else {       res.status(400).json({ success: false, message: "Invalid client" })     }   }) } else return res.status(401).send({ success: false, message: 'Unauthorized' }); } api.remove = (User, Client, Token) => (req, res) => { if (Token) {   User.findOne({ _id: req.query.user_id }, (error, user) => {     if (error) res.status(400).json(error);     if (user) {       Client.remove({ _id: req.query._id }, (error, removed) => {         if (error) res.status(400).json(error);         res.status(200).json({ success: true, message: 'Removed successfully' });       })     } else {       res.status(400).json({ success: false, message: "Invalid client" })     }   }) } else return res.status(401).send({ success: false, message: 'Unauthorized' }); } module.exports = api;
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      最後に、システムに新しいルートを追加します。 これを行うには、
routes
      
      フォルダーに移動して
budget.js
      
      ファイルを開きます。
  ソースコード 
       const passport = require('passport'),     config = require('@config'),     models = require('@BudgetManager/app/setup'); module.exports = (app) => { const api = app.BudgetManagerAPI.app.api.budget; app.route('/api/v1/budget')    .post(passport.authenticate('jwt', config.session), api.store(models.User, models.Budget, models.Client, app.get('budgetsecret')))    .get(passport.authenticate('jwt', config.session), api.getAll(models.User, models.Budget, app.get('budgetsecret')))    .get(passport.authenticate('jwt', config.session), api.getAllFromClient(models.User, models.Budget, app.get('budgetsecret')))    .delete(passport.authenticate('jwt', config.session), api.remove(models.User, models.Budget, models.Client, app.get('budgetsecret'))) app.route('/api/v1/budget/single')    .get(passport.authenticate('jwt', config.session), api.index(models.User, models.Budget, models.Client, app.get('budgetsecret')))    .put(passport.authenticate('jwt', config.session), api.edit(models.User, models.Budget, models.Client, app.get('budgetsecret'))) app.route('/api/v1/budget/state')    .get(passport.authenticate('jwt', config.session), api.getByState(models.User, models.Budget, models.Client, app.get('budgetsecret'))) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      同じフォルダーにある
client.js
      
      ファイルに同様の変更を加えます。
  ソースコード 
       const passport = require('passport'),     config = require('@config'),     models = require('@BudgetManager/app/setup'); module.exports = (app) => { const api = app.BudgetManagerAPI.app.api.client; app.route('/api/v1/client')    .post(passport.authenticate('jwt', config.session), api.store(models.User, models.Client, app.get('budgetsecret')))    .get(passport.authenticate('jwt', config.session), api.getAll(models.User, models.Client, app.get('budgetsecret')))    .delete(passport.authenticate('jwt', config.session), api.remove(models.User, models.Client, app.get('budgetsecret'))) app.route('/api/v1/client/single')   .get(passport.authenticate('jwt', config.session), api.index(models.User, models.Client, app.get('budgetsecret')))   .put(passport.authenticate('jwt', config.session), api.edit(models.User, models.Client, app.get('budgetsecret'))) }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      APIに対して行う必要があるすべての変更です。
ルーターの改良
次に、ルートに新しいコンポーネントを追加します。 これを行うには、
router
      
      フォルダー内にある
index.js
      
      ファイルを開きます。
  ソースコード 
       ... // Global components import Header from '@/components/Header' import List from '@/components/List/List' import Create from '@/components/pages/Create' // Register components Vue.component('app-header', Header) Vue.component('list', List) Vue.component('create', Create) Vue.use(Router) const router = new Router({ routes: [   {     path: '/',     name: 'Home',     components: {       default: Home,       header: Header,       list: List,       create: Create     }   },   {     path: '/login',     name: 'Authentication',     component: Authentication   } ] }) …
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ここで、
Create
      
      コンポーネントをインポートして定義し、
Home
      
      ルートコンポーネントに割り当てました(以下でコンポーネントを作成します)。
新しいコンポーネントの作成
componentコンポーネントの作成
Create
      
      コンポーネントから始めましょう。
components/pages
      
      フォルダーに移動し、
Create.vue
      
      新しい
Create.vue
      
      ファイルを作成します。
  ソースコード 
       <template> <div class="l-create-page">   <budget-creation v-if="budgetCreation && !editPage" slot="budget-creation" :clients="clients" :saveBudget="saveBudget"></budget-creation>   <client-creation v-if="!budgetCreation && !editPage" slot="client-creation" :saveClient="saveClient"></client-creation>   <budget-edit v-else-if="budgetEdit && editPage"     slot="budget-creation"     :clients="clients"     :selectedBudget="budget"     :fixClientNameAndUpdate="fixClientNameAndUpdate">   </budget-edit>   <client-edit v-else-if="!budgetEdit && editPage"     slot="client-creation"     :selectedClient="client"     :updateClient="updateClient">   </client-edit> </div> </template> <script> import BudgetCreation from './../Creation/BudgetCreation' import ClientCreation from './../Creation/ClientCreation' import BudgetEdit from './../Creation/BudgetEdit' import ClientEdit from './../Creation/ClientEdit' export default {   props: [     'budgetCreation', 'clients', 'saveBudget',     'saveClient', 'budget', 'client', 'updateClient',     'fixClientNameAndUpdate', 'editPage', 'budgetEdit'   ],   components: {     'budget-creation': BudgetCreation,     'client-creation': ClientCreation,     'budget-edit': BudgetEdit,     'client-edit': ClientEdit   } } </script>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      最初の名前付きスロットは
budget-creation
      
      です。 これは、新しい財務ドキュメントを作成するために使用するコンポーネントを表します。
budgetCreation
      
      プロパティ
budgetCreation
      
      true
      
      設定され、
editPage
      
      が
false
      
      に設定されている場合にのみ表示され
false
      
      。すべてのクライアントと
saveBudget
      
      メソッドを
saveBudget
      
      ます。
2番目の名前付きスロットは
client-creation
      
      です。 これは、新しい顧客を作成するために使用されるコンポーネントです。
budgetCreation
      
      プロパティ
budgetCreation
      
      false
      
      に設定され、
editPage
      
      も
false
      
      場合にのみ表示され
false
      
      。 ここで、saveClientメソッドを渡します。
3番目の名前付きスロットは
budget-edit
      
      です。 これは、選択したドキュメントの編集に使用されるコンポーネントです。
editPage
      
      と
editPage
      
      true
      
      設定されて
editPage
      
      場合にのみ
budgetEdit
      
      され
true
      
      。 ここでは、すべてのクライアント、選択した財務ドキュメント、および
fixClientNameAndUpdate
      
      メソッドを転送します。
そして最後に、顧客情報の編集に使用される最後の名前付きスロットがあります。
budgetEdit
      
      プロパティ
budgetEdit
      
      false
      
      に設定され、
editPage
      
      が
true
      
      設定されている
true
      
      され
true
      
      。 選択したクライアントと
updateClient
      
      メソッドを渡します。
予算BudgetCreationコンポーネント
新しい財務ドキュメントの作成に使用されるコンポーネントを開発します。
components
      
      フォルダーに移動して、その中に新しいフォルダーを作成し、それに
Creation
      
      という名前を付けます。 このフォルダーで、
BudgetCreation.vue
      
      コンポーネント
BudgetCreation.vue
      
      作成し
BudgetCreation.vue
      
      。
コンポーネントは非常に大きいため、テンプレートから始めて段階的に分析します。
BudgetCreationコンポーネントテンプレート
  コンポーネントテンプレートコードは次のとおりです 
       <template> <div class="l-budget-creation">   <v-layout row wrap>     <span class="md-budget-state-hint uppercased white--text">status</span>     <v-flex xs12 md2>       <v-select         label="Status"         :items="states"         v-model="budget.state"       >       </v-select>     </v-flex>     <v-flex xs12 md9 offset-md1>       <v-select         label="Client"         :items="clients"         v-model="budget.client"         item-text="name"         item-value="_id"       >       </v-select>     </v-flex>     <v-flex xs12 md12>       <v-text-field label="Title"                     v-model="budget.title"                     required                     color="light-blue lighten-1">       </v-text-field>       <v-text-field label="Description"                     v-model="budget.description"                     textarea                     required                     color="light-blue lighten-1">       </v-text-field>     </v-flex>     <v-layout row wrap v-for="item in budget.items" class="l-budget-item" :key="item.id">       <v-flex xs12 md1>         <v-btn block dark color="red lighten-1" @click.native="removeItem(item)">Remove</v-btn>       </v-flex>       <v-flex xs12 md3 offset-md1>         <v-text-field label="Title"                       box dark                       v-model="item.title"                       required                       color="light-blue lighten-1">         </v-text-field>       </v-flex>       <v-flex xs12 md1 offset-md1>         <v-text-field label="Price"                       box dark                       prefix="$"                       v-model="item.price"                       required                       color="light-blue lighten-1">         </v-text-field>       </v-flex>       <v-flex xs12 md2 offset-md1>         <v-text-field label="Quantity"                       box dark                       min="0"                       v-model="item.quantity"                       type="number"                       required                       color="light-blue lighten-1">         </v-text-field>       </v-flex>       <v-flex xs12 md2>         <span class="md-budget-item-subtotal white--text">ITEM PRICE $ {{ item.subtotal }}</span>       </v-flex>     </v-layout>     <v-flex xs12 md2 offset-md10>       <v-btn block color="md-add-item-btn light-blue lighten-1" @click.native="addItem()">Add item</v-btn>     </v-flex>     <v-flex xs12 md2 offset-md10>       <span class="md-budget-item-total white--text">TOTAL $ {{ budget.total_price }}</span>     </v-flex>     <v-flex xs12 md2 offset-md10>       <v-btn block color="md-add-item-btn green lighten-1" @click.native="saveBudget(budget)">Save</v-btn>     </v-flex>   </v-layout> </div> </template>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ここでは、最初に
v-select
      
      要素をテンプレートに追加してドキュメントの状態を設定し、次に
v-select
      
      を使用して必要なクライアントを選択します。 次に、ドキュメントのタイトルを入力する
v-text-field
      
      と説明を表示する
v-text-field
      
      があります。
次に、
budget.items
      
      要素を
budget.items
      
      します。これにより、ドキュメントに要素を追加して削除する機会が与えられます。 また、
removeItem
      
      関数を呼び出して、削除する要素を渡すことができる赤いボタンもあります。
さらに、製品名、単価、数量をそれぞれ対象とする3つの
v-text-fields
      
      があります。
シリーズの最後には単純な
span
      
      要素があり、商品の数量と価格の積である
subtotal
      
      という行に
subtotal
      
      を表示します。
製品リストの下にはさらに3つのアイテムがあります。 これは、
addItem
      
      関数、ドキュメント内のすべての商品の合計コストを表示する
span
      
      要素(すべての要素の
subtotal
      
      合計)を呼び出して新しい要素を追加するために使用される青いボタン、およびドキュメントをデータベースに保存するために使用される緑のボタン
saveBudget
      
      関数を呼び出して、保存するドキュメントをパラメーターとして渡します。
BudgetCreationコンポーネントスクリプト
  BudgetCreationコンポーネントを強化するコードは次のとおりです。 
       <script> export default {   props: ['clients', 'saveBudget'],   data () {     return {       budget: {         title: null,         description: null,         state: 'writing',         client: null,         get total_price () {           let value = 0           this.items.forEach(({ subtotal }) => {             value += parseInt(subtotal)           })           return value         },         items: [           {             title: null,             quantity: 0,             price: 0,             get subtotal () {               return this.quantity * this.price             }           }         ]       },       states: [         'writing', 'editing', 'pending', 'approved', 'denied', 'waiting'       ]     }   },   methods: {     addItem () {       const items = this.budget.items       const item = {         title: '',         quantity: 0,         price: 0,         get subtotal () {           return this.quantity * this.price         }       }       items.push(item)     },     removeItem (selected) {       const items = this.budget.items       items.forEach((item, index) => {         if (item === selected) {           items.splice(index, 1)         }       })     }   } } </script>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      このコードでは、
clients
      
      と
saveBudget
      
      2つのプロパティを最初に取得し
clients
      
      。 これらのプロパティのソースは、
Home
      
      コンポーネントです。
次に、データの役割を果たすオブジェクトと配列を定義します。 オブジェクトの名前は
budget
      
      です。 ドキュメントの作成に使用され、値を追加してデータベースに保存できます。 このオブジェクトには、プロパティ
title
      
      (title)、
description
      
      (description)、
state
      
      (デフォルトのstateを
writing
      
      設定)、
client
      
      (client)、
total_price
      
      (ドキュメントの総コスト)、items
items
      
      配列があり
items
      
      。 商品には、
title
      
      (名前)、
quantity
      
      (数量)、
price
      
      (価格)、および
subtotal
      
      (小計)のプロパティがあります。
ここでは、ドキュメントの
states
      
      の配列
states
      
      が定義されています。 その値は、ドキュメントの状態を設定するために使用されます。 これらの状態は、
writing
      
      、
editing
      
      pending
      
      、
pending
      
      、
approved
      
      、
denied
      
      、
waiting
      
      です。
以下に、データ構造の説明の後に、
addItem
      
      (製品を追加するための)と
removeItem
      
      (それらを削除するための)の2つのメソッドがあり
addItem
      
      。
青いボタンをクリックするたびに、
addItem
      
      メソッドが
addItem
      
      メソッドは、要素を
budget
      
      オブジェクト内の
items
      
      配列に追加します。
removeItem
      
      メソッドは反対のアクションを実行します。 つまり、赤いボタンをクリックすると、指定されたアイテムが
items
      
      配列から削除され
items
      
      。
BudgetCreationコンポーネントスタイル
  問題のコンポーネントのスタイルは次のとおりです。 
       <style lang="scss"> @import "./../../assets/styles"; .uppercased {   text-transform: uppercase; } .l-budget-creation {   label, input, .icon, .input-group__selections__comma, textarea {     color: #29b6f6!important;   }   .input-group__details {     &:before {       background-color: $border-color-input !important;     }   }   .input-group__input {     border-color: $border-color-input !important;     .input-group--text-field__prefix {       margin-bottom: 3px !important;     }   }   .input-group--focused {     .input-group__input {       border-color: #29b6f6!important;     }   } } .md-budget-state-hint {   margin: 10px 0;   display: block;   width: 100%; } .md-budget-state {   background-color: rgba(41, 182, 246, .6);   display: flex;   height: 35px;   width: 100%;   font-size: 14px;   align-items: center;   justify-content: center;   border-radius: 2px;   margin: 10px 0 15px; } .l-budget-item {   align-items: center; } .md-budget-item-subtotal {   font-size: 16px;   text-align: center;   display: block; } .md-budget-item-total {   font-size: 22px;   text-align: center;   display: block;   width: 100%;   margin: 30px 0 10px; } .md-add-item-btn {   margin-top: 30px !important;   display: block; } .list__tile__title, .input-group__selections {   text-transform: uppercase !important; } </style>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      次に、次のコンポーネントを検討します。
▍ClientCreationコンポーネント
実際、このコンポーネントは、レビューしたばかりの
BudgetCreation
      
      コンポーネントの簡易バージョンです。 上記で行ったように、我々はそれを部分的に検討します。
BudgetCreation
      
      コンポーネントを理解すれば、
BudgetCreation
      
      を簡単に理解できます。
  ClientCreationコンポーネントテンプレート 
       <template> <div class="l-client-creation">   <v-layout row wrap>     <v-flex xs12 md4>       <v-text-field label="Name"                     v-model="client.name"                     required                     color="green lighten-1">       </v-text-field>     </v-flex>     <v-flex xs12 md3 offset-md1>       <v-text-field label="Email"                     v-model="client.email"                     required                     color="green lighten-1">       </v-text-field>     </v-flex>     <v-flex xs12 md3 offset-md1>       <v-text-field label="Phone"                     v-model="client.phone"                     required                     mask="phone"                     color="green lighten-1">       </v-text-field>     </v-flex>     <v-flex xs12 md2 offset-md10>       <v-btn block color="md-add-item-btn green lighten-1" @click.native="saveClient(client)">Save</v-btn>     </v-flex>   </v-layout> </div> </template>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        ClientCreationコンポーネントスクリプト 
       <script> export default {   props: ['saveClient'],   data () {     return {       client: {         name: null,         email: null,         phone: null       }     }   } } </script>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        ClientCreationコンポーネントスタイル 
       <style lang="scss"> @import "./../../assets/styles"; .uppercased {   text-transform: uppercase; } .l-client-creation {   label, input, .icon, .input-group__selections__comma, textarea {     color: #66bb6a!important;   }   .input-group__details {     &:before {       background-color: $border-color-input !important;     }   }   .input-group__input {     border-color: $border-color-input !important;     .input-group--text-field__prefix {       margin-bottom: 3px !important;     }   }   .input-group--focused {     .input-group__input {       border-color: #66bb6a!important;     }   } } </style>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      次に、
BudgetEdit
      
      コンポーネントの
BudgetEdit
      
      です。
▍BudgetEditコンポーネント
実際、このコンポーネントは、すでに考慮されている
BudgetCreation
      
      コンポーネントの修正バージョンです。 そのコンポーネントを検討してください。
  BudgetEditコンポーネントテンプレート 
       <template> <div class="l-budget-creation">   <v-layout row wrap>     <span class="md-budget-state-hint uppercased white--text">status</span>     <v-flex xs12 md2>       <v-select         label="Status"         :items="states"         v-model="budget.state"       >       </v-select>     </v-flex>     <v-flex xs12 md9 offset-md1>       <v-select         label="Client"         :items="clients"         v-model="budget.client_id"         item-text="name"         item-value="_id"       >       </v-select>     </v-flex>     <v-flex xs12 md12>       <v-text-field label="Title"                     v-model="budget.title"                     required                     color="light-blue lighten-1">       </v-text-field>       <v-text-field label="Description"                     v-model="budget.description"                     textarea                     required                     color="light-blue lighten-1">       </v-text-field>     </v-flex>     <v-layout row wrap v-for="item in budget.items" class="l-budget-item" :key="item.id">       <v-flex xs12 md1>         <v-btn block dark color="red lighten-1" @click.native="removeItem(item)">Remove</v-btn>       </v-flex>       <v-flex xs12 md3 offset-md1>         <v-text-field label="Title"                       box dark                       v-model="item.title"                       required                       color="light-blue lighten-1">         </v-text-field>       </v-flex>       <v-flex xs12 md1 offset-md1>         <v-text-field label="Price"                       box dark                       prefix="$"                       v-model="item.price"                       required                       color="light-blue lighten-1">         </v-text-field>       </v-flex>       <v-flex xs12 md2 offset-md1>         <v-text-field label="Quantity"                       box dark                       min="0"                       v-model="item.quantity"                       type="number"                       required                       color="light-blue lighten-1">         </v-text-field>       </v-flex>       <v-flex xs12 md2>         <span class="md-budget-item-subtotal white--text">ITEM PRICE $ {{ item.subtotal }}</span>       </v-flex>     </v-layout>     <v-flex xs12 md2 offset-md10>       <v-btn block color="md-add-item-btn light-blue lighten-1" @click.native="addItem()">Add item</v-btn>     </v-flex>     <v-flex xs12 md2 offset-md10>       <span class="md-budget-item-total white--text">TOTAL $ {{ budget.total_price }}</span>     </v-flex>     <v-flex xs12 md2 offset-md10>       <v-btn block color="md-add-item-btn green lighten-1" @click.native="fixClientNameAndUpdate(budget)">Update</v-btn>     </v-flex>   </v-layout> </div> </template>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      BudgetEdit
      
      と
BudgetCreation
      
      コンポーネントテンプレートの唯一の違いは、保存ボタンとその関連ロジックです。 つまり、
BudgetCreation
      
      では
Save
      
      と表示され、
saveBudget
      
      メソッドが呼び出され
Save
      
      。
BudgetEdit
      
      このボタンに碑文の
Update
      
      が表示され、
fixClientNameAndUpdate
      
      メソッドが
fixClientNameAndUpdate
      
      ます。
  BudgetCreationコンポーネントスクリプト 
       <script> export default {   props: ['clients', 'fixClientNameAndUpdate', 'selectedBudget'],   data () {     return {       budget: {         title: null,         description: null,         state: 'pending',         client: null,         get total_price () {           let value = 0           this.items.forEach(({ subtotal }) => {             value += parseInt(subtotal)           })           return value         },         items: [           {             title: null,             quantity: 0,             price: null,             get subtotal () {               return this.quantity * this.price             }           }         ]       },       states: [         'writing', 'editing', 'pending', 'approved', 'denied', 'waiting'       ]     }   },   mounted () {     this.parseBudget()   },   methods: {     addItem () {       const items = this.budget.items       const item = {         title: '',         quantity: 0,         price: 0,         get subtotal () {           return this.quantity * this.price         }       }       items.push(item)     },     removeItem (selected) {       const items = this.budget.items       items.forEach((item, index) => {         if (item === selected) {           items.splice(index, 1)         }       })     },     parseBudget () {       for (let key in this.selectedBudget) {         if (key !== 'total' && key !== 'items') {           this.budget[key] = this.selectedBudget[key]         }         if (key === 'items') {           const items = this.selectedBudget.items           const buildItems = item => ({             title: item.title,             quantity: item.quantity,             price: item.price,             get subtotal () {               return this.quantity * this.price             }           })           const parseItems = items => items.map(buildItems)           this.budget.items = parseItems(items)         }       }     }   } } </script>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      すべて3つのプロパティで始まります。 これらは、
clients
      
      、
fixClientNameAndUpdate
      
      、および
selectedBudget
      
      です。 このデータは、
BudgetCreation
      
      コンポーネントのデータと同じです。 つまり、
Budget
      
      オブジェクトと
states
      
      配列があり
states
      
      。
さらに、ここでは、
mounted
      
      コンポーネントライフサイクルイベントハンドラーを確認できます。このハンドラーでは、
parseBudget
      
      メソッドを呼び出します。 最後に、
BudgetCreation
      
      コンポーネントでおなじみの
addItem
      
      と
removeItem
      
      メソッド、および新しい
parseBudget
      
      メソッドを含む
methods
      
      オブジェクトがあり
addItem
      
      。 このメソッドは、
budget
      
      オブジェクトの値を
selectedBudget
      
      プロパティで渡される値に設定するために使用
selectedBudget
      
      ますが、ドキュメントの商品の小計とドキュメントの合計金額の計算にも使用されます。
  BudgetCreationコンポーネントスタイル 
       <style lang="scss"> @import "./../../assets/styles"; .uppercased {   text-transform: uppercase; } .l-budget-creation {   label, input, .icon, .input-group__selections__comma, textarea {     color: #29b6f6!important;   }   .input-group__details {     &:before {       background-color: $border-color-input !important;     }   }   .input-group__input {     border-color: $border-color-input !important;     .input-group--text-field__prefix {       margin-bottom: 3px !important;     }   }   .input-group--focused {     .input-group__input {       border-color: #29b6f6!important;     }   } } .md-budget-state-hint {   margin: 10px 0;   display: block;   width: 100%; } .md-budget-state {   background-color: rgba(41, 182, 246, .6);   display: flex;   height: 35px;   width: 100%;   font-size: 14px;   align-items: center;   justify-content: center;   border-radius: 2px;   margin: 10px 0 15px; } .l-budget-item {   align-items: center; } .md-budget-item-subtotal {   font-size: 16px;   text-align: center;   display: block; } .md-budget-item-total {   font-size: 22px;   text-align: center;   display: block;   width: 100%;   margin: 30px 0 10px; } .md-add-item-btn {   margin-top: 30px !important;   display: block; } .list__tile__title, .input-group__selections {   text-transform: uppercase !important; } </style>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ▍ClientEditコンポーネント
検討したばかりのこのコンポーネントは、クライアントの作成に使用する対応するコンポーネント
ClientCreation
      
      似ています。 主な違いは、
saveClient
      
      メソッドの代わりに
updateClient
      
      メソッドが
updateClient
      
      です。 デバイスコンポーネント
ClientEdit
      
      検討してください。
  ClientEditコンポーネントテンプレート 
       <template> <div class="l-client-creation">   <v-layout row wrap>     <v-flex xs12 md4>       <v-text-field label="Name"                     v-model="client.name"                     required                     color="green lighten-1">       </v-text-field>     </v-flex>     <v-flex xs12 md3 offset-md1>       <v-text-field label="Email"                     v-model="client.email"                     required                     color="green lighten-1">       </v-text-field>     </v-flex>     <v-flex xs12 md3 offset-md1>       <v-text-field label="Phone"                     v-model="client.phone"                     required                     mask="phone"                     color="green lighten-1">       </v-text-field>     </v-flex>     <v-flex xs12 md2 offset-md10>       <v-btn block color="md-add-item-btn green lighten-1" @click.native="updateClient(client)">Update</v-btn>     </v-flex>   </v-layout> </div> </template>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        ClientEditコンポーネントスクリプト 
       <script> export default {   props: ['updateClient', 'selectedClient'],   data () {     return {       client: {         name: null,         email: null,         phone: null       }     }   },   mounted () {     this.client = this.selectedClient   } } </script>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        ClientEditコンポーネントスタイル 
       <style lang="scss"> @import "./../../assets/styles"; .uppercased {   text-transform: uppercase; } .l-client-creation {   label, input, .icon, .input-group__selections__comma, textarea {     color: #66bb6a!important;   }   .input-group__details {     &:before {       background-color: $border-color-input !important;     }   }   .input-group__input {     border-color: $border-color-input !important;     .input-group--text-field__prefix {       margin-bottom: 3px !important;     }   }   .input-group--focused {     .input-group__input {       border-color: #66bb6a!important;     }   } } </style>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      これにより、新しいコンポーネントの作成が完了し、システムに既に存在していたコンポーネントの処理に進みます。
既存のコンポーネントの改良
これで、既存のコンポーネントにいくつかの変更を加えるだけで、アプリケーションを使用する準備が整います。
ListBody
      
      コンポーネントから始めましょう。
▍ListBodyコンポーネント
ListBodyコンポーネントテンプレート
このコンポーネントのコードは
ListBody.vue
      
      ファイルに保存されていることを思い出してください
  ソースコード 
       <template> <section class="l-list-body">   <div class="md-list-item"        v-if="data != null && parsedBudgets === null"        v-for="item in data">     <div :class="budgetsVisible ? 'md-budget-info white--text' : 'md-client-info white--text'"           v-for="info in item"           v-if="info != item._id && info != item.client_id">       {{ info }}     </div>     <div :class="budgetsVisible ? 'l-budget-actions white--text' : 'l-client-actions white--text'">       <v-btn small flat color="yellow accent-1" @click.native="getItemAndEdit(item)">         <v-icon>mode_edit</v-icon>       </v-btn>       <v-btn small flat color="red lighten-1" @click.native="deleteItem(item, data, budgetsVisible)">         <v-icon>delete_forever</v-icon>       </v-btn>     </div>   </div>   <div class="md-list-item"        v-if="parsedBudgets !== null"        v-for="item in parsedBudgets">     <div :class="budgetsVisible ? 'md-budget-info white--text' : 'md-client-info white--text'"           v-for="info in item"           v-if="info != item._id && info != item.client_id">       {{ info }}     </div>     <div :class="budgetsVisible ? 'l-budget-actions white--text' : 'l-client-actions white--text'">       <v-btn small flat color="yellow accent-1" @click.native="getItemAndEdit(item)">         <v-icon>mode_edit</v-icon>       </v-btn>       <v-btn small flat color="red lighten-1" @click.native="deleteItem(item, data, budgetsVisible)">         <v-icon>delete_forever</v-icon>       </v-btn>     </div>   </div> </section> </template>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      このコンポーネントでは、いくつかの変更と追加を実行するだけで済みます。 そのため、最初に
md-list-item
      
      ブロックの
v-if
      
      コンストラクトに新しい条件を追加します。
 parsedBudgets === null
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      さらに、編集ボタンをクリックしてドキュメントを表示できるため、ドキュメントを表示するために使用した最初のボタンを削除します。
ここでは、
getItemAndEdit
      
      メソッドを新しい最初のボタンに、
deleteItem
      
      メソッドを最後のボタンに追加して、この要素、データ、および
budgetsVisible
      
      変数をパラメーターとして
budgetsVisible
      
      ます。
この下には
md-item-list
      
      ブロックがあり、検索後にフィルター処理されたドキュメントのリストを表示するために使用します。
  ListBodyコンポーネントスクリプト 
       <script> export default {   props: ['data', 'budgetsVisible', 'deleteItem', 'getBudget', 'getClient', 'parsedBudgets'],   methods: {     getItemAndEdit (item) {       !item.phone ? this.getBudget(item) : this.getClient(item)     }   } } </script>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      このコンポーネントでは、多くのプロパティを取得します。 それらについて説明します。
-   data
 
 
 
 :これはドキュメントのリストまたはクライアントのリストのいずれかですが、両方ではありません。
 
 
-   budgetsVisible
 
 
 
 :ドキュメントまたはクライアントのリストを表示しているかどうかを確認するために使用されますtrue
 
 
 
 またはfalse
 
 
 
 場合がありfalse
 
 
 
 。
 
 
-   deleteItem
 
 
 
 :パラメーターとして要素を取る要素を削除する関数。
 
 
-   getBudget
 
 
 
 :編集する予定の単一のドキュメントをロードするために使用する関数。
 
 
-   getClient
 
 
 
 :さらに編集するために個々のクライアントのカードをロードするために使用される関数。
 
 
-   parsedBudgets
 
 
 
 :検索の実行後にフィルター処理されたドキュメント。
 
 
コンポーネントには
getItemAndEdit
      
      1つだけあります。 彼は、パラメータとして要素を受け取り、電話番号を含む要素のプロパティの分析に基づいて、要素が顧客のカードであるか財務書類であるかを決定します。
  ListBodyコンポーネントスタイル 
       <style lang="scss"> @import "./../../assets/styles"; .l-list-body {   display: flex;   flex-direction: column;   .md-list-item {     width: 100%;     display: flex;     flex-direction: column;     margin: 15px 0;     @media (min-width: 960px) {       flex-direction: row;       margin: 0;     }     .md-budget-info {       flex-basis: 25%;       width: 100%;       background-color: rgba(0, 175, 255, 0.45);       border: 1px solid $border-color-input;       padding: 0 15px;       display: flex;       height: 35px;       align-items: center;       justify-content: center;       &:first-of-type, &:nth-of-type(2) {         text-transform: capitalize;       }       &:nth-of-type(3) {         text-transform: uppercase;       }       @media (min-width: 601px) {         justify-content: flex-start;       }     }     .md-client-info {       @extend .md-budget-info;       background-color: rgba(102, 187, 106, 0.45)!important;       &:nth-of-type(2) {         text-transform: none;       }     }     .l-budget-actions {       flex-basis: 25%;       display: flex;       background-color: rgba(0, 175, 255, 0.45);       border: 1px solid $border-color-input;       align-items: center;       justify-content: center;       .btn {         min-width: 45px !important;         margin: 0 5px !important;       }     }     .l-client-actions {       @extend .l-budget-actions;       background-color: rgba(102, 187, 106, 0.45)!important;     }   } } </style>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ListBody
      
      ,
Header
      
      .
▍ Header
   Header 
       <template> <header class="l-header-container">   <v-layout row wrap :class="budgetsVisible ? 'l-budgets-header' : 'l-clients-header'">     <v-flex xs12 md5>       <v-text-field v-model="searchValue"                     label="Search"                     append-icon="search"                     :color="budgetsVisible ? 'light-blue lighten-1' : 'green lighten-1'">       </v-text-field>     </v-flex>     <v-flex xs12 offset-md1 md1>       <v-btn block              :color="budgetsVisible ? 'light-blue lighten-1' : 'green lighten-1'"              @click.native="$emit('toggleVisibleData')">              {{ budgetsVisible ? "Clients" : "Budgets" }}       </v-btn>     </v-flex>     <v-flex xs12 offset-md1 md2>       <v-select label="Status"                 :color="budgetsVisible ? 'light-blue lighten-1' : 'green lighten-1'"                 v-model="status"                 :items="statusItems"                 single-line                 @change="selectState">       </v-select>     </v-flex>     <v-flex xs12 offset-md1 md1>       <v-btn block color="red lighten-1 white--text" @click.native="submitSignout()">Sign out</v-btn>     </v-flex>   </v-layout> </header> </template>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      , ,
v-model
      
      searchValue
      
      .
,
v-select
      
      ,
change
      
      selectState
      
      .
   Header 
       <script> import Authentication from '@/components/pages/Authentication' export default {   props: ['budgetsVisible', 'selectState', 'search'],   data () {     return {       searchValue: '',       status: '',       statusItems: [         'all', 'approved', 'denied', 'waiting', 'writing', 'editing'       ]     }   },   watch: {     'searchValue': function () {       this.$emit('input', this.searchValue)     }   },   created () {     this.searchValue = this.search   },   methods: {     submitSignout () {       Authentication.signout(this, '/login')     }   } } </script>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      —
selectState
      
      , ,
search
      
      , .
search
      
      searchValue
      
      statusItems
      
      .
   Header 
       <script> import Authentication from '@/components/pages/Authentication' export default {   props: ['budgetsVisible', 'selectState', 'search'],   data () {     return {       searchValue: '',       status: '',       statusItems: [         'all', 'approved', 'denied', 'waiting', 'writing', 'editing'       ]     }   },   watch: {     'searchValue': function () {       this.$emit('input', this.searchValue)     }   },   created () {     this.searchValue = this.search   },   methods: {     submitSignout () {       Authentication.signout(this, '/login')     }   } } </script>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Header
      
      ,
Home
      
      .
▍ Home
   Home 
       <template> <main class="l-home-page">   <app-header :budgetsVisible="budgetsVisible"     @toggleVisibleData="budgetsVisible = !budgetsVisible; budgetCreation = !budgetCreation"     :selectState="selectState"     :search="search"     v-model="search">   </app-header>   <div class="l-home">     <h4 class="white--text text-xs-center my-0">       Focus Budget Manager     </h4>     <list v-if="listPage">       <list-header slot="list-header" :headers="budgetsVisible ? budgetHeaders : clientHeaders"></list-header>       <list-body slot="list-body"                  :budgetsVisible="budgetsVisible"                  :data="budgetsVisible ? budgets : clients"                  :search="search"                  :deleteItem="deleteItem"                  :getBudget="getBudget"                  :getClient="getClient"                  :parsedBudgets="parsedBudgets">       </list-body>     </list>     <create v-else-if="createPage"       :budgetCreation="budgetCreation"       :budgetEdit="budgetEdit"       :editPage="editPage"       :clients="clients"       :budget="budget"       :client="client"       :saveBudget="saveBudget"       :saveClient="saveClient"       :fixClientNameAndUpdate="fixClientNameAndUpdate"       :updateClient="updateClient">     </create>   </div>   <v-snackbar :timeout="timeout"               bottom="bottom"               :color="snackColor"               v-model="snackbar">     {{ message }}   </v-snackbar>   <v-fab-transition>     <v-speed-dial v-model="fab"                   bottom                   right                   fixed                   direction="top"                   transition="scale-transition">         <v-btn slot="activator"                color="red lighten-1"                dark                fab                v-model="fab">               <v-icon>add</v-icon>               <v-icon>close</v-icon>         </v-btn>         <v-tooltip left>           <v-btn color="light-blue lighten-1"                  dark                  small                  fab                  slot="activator"                  @click.native="budgetCreation = true; listPage = false; editPage = false; createPage = true">                 <v-icon>assignment</v-icon>           </v-btn>           <span>Add new Budget</span>         </v-tooltip>         <v-tooltip left>           <v-btn color="green lighten-1"                  dark                  small                  fab                  slot="activator"                  @click.native="budgetCreation = false; listPage = false; editPage = false; createPage = true">                 <v-icon>account_circle</v-icon>           </v-btn>           <span>Add new Client</span>         </v-tooltip>         <v-tooltip left>           <v-btn color="purple lighten-2"                  dark                  small                  fab                  slot="activator"                  @click.native="budgetCreation = false; listPage = true; budgetsVisible = true">                 <v-icon>assessment</v-icon>           </v-btn>           <span>List Budgets</span>         </v-tooltip>         <v-tooltip left>           <v-btn color="deep-orange lighten-2"                  dark                  small                  fab                  slot="activator"                  @click.native="budgetCreation = false; listPage = true; budgetsVisible = false;">                 <v-icon>supervisor_account</v-icon>           </v-btn>           <span>List Clients</span>         </v-tooltip>     </v-speed-dial>   </v-fab-transition> </main> </template>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      , .
budgetsVisible
      
      ,
selectState
      
      ,
search
      
      toggleVisibleData
      
      , ,
toggleVisibleData
      
      ,
v-model
      
      search
      
      .
list
      
      v-if
      
      , , . ,
list-body
      
      .
create
      
      ,
list
      
      , , . , .
v-fab-transition
      
      , , .
   Home 
       <script> import Axios from 'axios' import Authentication from '@/components/pages/Authentication' import ListHeader from './../List/ListHeader' import ListBody from './../List/ListBody' const BudgetManagerAPI = `http://${window.location.hostname}:3001` export default {   components: {     'list-header': ListHeader,     'list-body': ListBody   },   data () {     return {       parsedBudgets: null,       budget: null,       client: null,       state: null,       search: null,       budgets: [],       clients: [],       budgetHeaders: ['Client', 'Title', 'Status', 'Actions'],       clientHeaders: ['Client', 'Email', 'Phone', 'Actions'],       budgetsVisible: true,       snackbar: false,       timeout: 6000,       message: '',       fab: false,       listPage: true,       createPage: true,       editPage: false,       budgetCreation: true,       budgetEdit: true,       snackColor: 'red lighten-1'     }   },   mounted () {     this.getAllBudgets()     this.getAllClients()     this.hidden = false   },   watch: {     'search': function () {       if (this.search !== null || this.search !== '') {         const searchTerm = this.search         const regex = new RegExp(`^(${searchTerm})`, 'g')         const results = this.budgets.filter(budget => budget.client.match(regex))         this.parsedBudgets = results       } else {         this.parsedBudgets = null       }     }   },   methods: {     getAllBudgets () {       Axios.get(`${BudgetManagerAPI}/api/v1/budget`, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: { user_id: this.$cookie.get('user_id') }       }).then(({data}) => {         this.budgets = this.dataParser(data, '_id', 'client', 'title', 'state', 'client_id')       }).catch(error => {         this.errorHandler(error)       })     },     getAllClients () {       Axios.get(`${BudgetManagerAPI}/api/v1/client`, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: { user_id: this.$cookie.get('user_id') }       }).then(({data}) => {         this.clients = this.dataParser(data, 'name', 'email', '_id', 'phone')       }).catch(error => {         this.errorHandler(error)       })     },     getBudget (budget) {       Axios.get(`${BudgetManagerAPI}/api/v1/budget/single`, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: {           user_id: this.$cookie.get('user_id'),           _id: budget._id         }       }).then(({data}) => {         this.budget = data         this.enableEdit('budget')       }).catch(error => {         this.errorHandler(error)       })     },     getClient (client) {       Axios.get(`${BudgetManagerAPI}/api/v1/client/single`, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: {           user_id: this.$cookie.get('user_id'),           _id: client._id         }       }).then(({data}) => {         this.client = data         this.enableEdit('client')       }).catch(error => {         this.errorHandler(error)       })     },     enableEdit (type) {       if (type === 'budget') {         this.listPage = false         this.budgetEdit = true         this.budgetCreation = false         this.editPage = true       } else if (type === 'client') {         this.listPage = false         this.budgetEdit = false         this.budgetCreation = false         this.editPage = true       }     },     saveBudget (budget) {       Axios.post(`${BudgetManagerAPI}/api/v1/budget`, budget, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: { user_id: this.$cookie.get('user_id') }       })       .then(res => {         this.resetFields(budget)         this.snackbar = true         this.message = res.data.message         this.snackColor = 'green lighten-1'         this.getAllBudgets()       })       .catch(error => {         this.errorHandler(error)       })     },     fixClientNameAndUpdate (budget) {       this.clients.find(client => {         if (client._id === budget.client_id) {           budget.client = client.name         }       })       this.updateBudget(budget)     },     updateBudget (budget) {       Axios.put(`${BudgetManagerAPI}/api/v1/budget/single`, budget, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: { user_id: this.$cookie.get('user_id') }       })       .then(() => {         this.snackbar = true         this.message = 'Budget updated'         this.snackColor = 'green lighten-1'         this.listPage = true         this.budgetCreation = false         this.budgetsVisible = true         this.getAllBudgets()       })       .catch(error => {         this.errorHandler(error)       })     },     updateClient (client) {       Axios.put(`${BudgetManagerAPI}/api/v1/client/single`, client, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: { user_id: this.$cookie.get('user_id') }       })       .then(() => {         this.snackbar = true         this.message = 'Client updated'         this.snackColor = 'green lighten-1'         this.listPage = true         this.budgetCreation = false         this.budgetsVisible = false         this.getAllClients()       })       .catch(error => {         this.errorHandler(error)       })     },     saveClient (client) {       Axios.post(`${BudgetManagerAPI}/api/v1/client`, client, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: { user_id: this.$cookie.get('user_id') }       })       .then(res => {         this.resetFields(client)         this.snackbar = true         this.message = res.data.message         this.snackColor = 'green lighten-1'         this.getAllClients()       })       .catch(error => {         this.errorHandler(error)       })     },     deleteItem (selected, items, api) {       let targetApi = ''       api ? targetApi = 'budget' : targetApi = 'client'       Axios.delete(`${BudgetManagerAPI}/api/v1/${targetApi}`, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: {           user_id: this.$cookie.get('user_id'),           _id: selected._id         }       })       .then(() => {         this.removeItem(selected, items)       })       .then(() => {         api ? this.getAllBudgets() : this.getAllClients()       })       .catch(error => {         this.errorHandler(error)       })     },     errorHandler (error) {       const status = error.response.status       this.snackbar = true       this.snackColor = 'red lighten-1'       if (status === 404) {         this.message = 'Invalid request'       } else if (status === 401 || status === 403) {         this.message = 'Unauthorized'       } else if (status === 400) {         this.message = 'Invalid or missing information'       } else {         this.message = error.message       }     },     removeItem (selected, items) {       items.forEach((item, index) => {         if (item === selected) {           items.splice(index, 1)         }       })     },     dataParser (targetedArray, ...options) {       let parsedData = []       targetedArray.forEach(item => {         let parsedItem = {}         options.forEach(option => (parsedItem[option] = item[option]))         parsedData.push(parsedItem)       })       return parsedData     },     resetFields (item) {       for (let key in item) {         item[key] = null         if (key === 'quantity' || key === 'price') {           item[key] = 0         }         item['items'] = []       }     },     selectState (state) {       this.state = state       state === 'all' ? this.getAllBudgets() : this.getBudgetsByState(state)     },     getBudgetsByState (state) {       Axios.get(`${BudgetManagerAPI}/api/v1/budget/state`, {         headers: { 'Authorization': Authentication.getAuthenticationHeader(this) },         params: { user_id: this.$cookie.get('user_id'), state }       }).then(({data}) => {         this.budgets = this.dataParser(data, '_id', 'client', 'title', 'state', 'client_id')       }).catch(error => {         this.errorHandler(error)       })     }   } } </script>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      . .
-  parsedBudgets
 
 
 
 : , .
 
 
-  budget
 
 
 
 : , .
 
 
-  client
 
 
 
 : , .
 
 
-  state
 
 
 
 : , , .
 
 
-  search
 
 
 
 : , .
 
 
-  budgets
 
 
 
 : , API.
 
 
-  clients
 
 
 
 : , API.
 
 
-  budgetHeaders
 
 
 
 : , .
 
 
-  clientHeaders
 
 
 
 : , , .
 
 
-  budgetsVisible
 
 
 
 : , .
 
 
-  snackbar
 
 
 
 : .
 
 
-  timeout
 
 
 
 : - .
 
 
-  message
 
 
 
 : , .
 
 
-  fab
 
 
 
 : ,false
 
 
 
 .
 
 
-  listPage
 
 
 
 : , ,true
 
 
 
 .
 
 
-  createPage
 
 
 
 : , ,false
 
 
 
 .
 
 
-  editPage
 
 
 
 : , ,false
 
 
 
 .
 
 
-  budgetCreation
 
 
 
 : , ,true
 
 
 
 .
 
 
-  budgetEdit
 
 
 
 : , ,true
 
 
 
 .
 
 
-  snackColor
 
 
 
 : .
 
 
, , ,
mounted
      
      , .
, ,
watch
      
      . @mrmonkeytech , ( ).
.
-    getAllBudgets
 
 
 
 dataParser
 
 
 
 ,errorHandler
 
 
 
 catch
 
 
 
 .getAllClients
 
 
 
 .
 
 
-      getBudget
 
 
 
 getClient
 
 
 
 , API.
 
 
-   enableEdit
 
 
 
 , , , .
 
 
-   saveBudget
 
 
 
 saveClient
 
 
 
 , , .
 
 
-   fixClientNameAndUpdate
 
 
 
 ,ID
 
 
 
 ,updateBudget
 
 
 
 .
 
 
-   updateBudget
 
 
 
 .
 
 
-   updateClient
 
 
 
 .
 
 
-   deleteItem
 
 
 
 . ,selected
 
 
 
 ,items
 
 
 
 ( ),api
 
 
 
 .
 
 
-   errorHandler
 
 
 
 .
 
 
-   removeItem
 
 
 
 deleteItem
 
 
 
 , .
 
 
-   dataParser
 
 
 
 , , .
 
 
-   resetFields
 
 
 
 . , , .
 
 
-   selectState
 
 
 
 v-select
 
 
 
 Header
 
 
 
 .
 
 
-   getBudgetsByState
 
 
 
 selectState
 
 
 
 , .
 
 
   Home 
       <style lang="scss"> @import "./../../assets/styles"; .l-home {   background-color: $background-color;   margin: 25px auto;   padding: 15px;   min-width: 272px; } .snack__content {   justify-content: center !important; } </style>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      まとめ
- Budget Manager . .

, , — .
, , , , .
親愛なる読者! , ?
