<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Записная книжка</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <div id="app">
            <div class="form">
                <div><p class="h4">Форма</p></div>
                <div class="form-row">
                    <div class="col-md-5 mb-3">
                        <label>Имя</label>
                        <input type="text" class="form-control" :class="{'is-valid': form_name !== ''}" v-model="form_name" required>

                    </div>
                    <div class="col-md-5 mb-3">
                        <label>Номер телефона:</label>
                        <input type="text" class="form-control" :class="check_valid_phone()" v-model="form_phone" required>
                        <div class="invalid-feedback" v-if="check_valid_phone() == 'is-invalid'"> Этот номер уже используется</div>
                    </div>
                    <div class="col-md-2 mb-3 d-flex flex-column">
                      
                        <button class="btn btn-success mt-auto" v-if="check_valid_phone() !== 'is-invalid' && form_name !== '' && form_phone !== '' " @click="save_item()">Сохранить</button>
                        <button class="btn btn-secondary mt-auto is-invalid" v-if="check_valid_phone() == 'is-invalid' ||  form_name == '' || form_phone == '' ">Нельзя сохранить</button>
                        <div class="invalid-feedback w-100" v-if="check_valid_phone() == 'is-invalid' "> Ошибка </div>
                    </div>
                </div>
            </div>
            <div class="search form-row"> 
                <div class="col-md-12 mb-3">
                    <label class="h4">Поиск по номеру телефона:</label>
                    <input type="text" class="form-control" v-model="search_phone" required>
                </div>
            </div>
            <table class="table table-hover table-sm">
                <thead>
                    <tr>
                        <th scope="col">#:</th>                                
                        <th scope="col">Имя:</th>
                        <th scope="col">Телефон:</th>
                        <th scope="col">Действия:</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="(item,index) in table" v-if="table.length > 0" :class="{'table-success': item.phone == search_phone}">
                        <td>{{index+1}}</td>
                        <td>{{item.name}}</td>
                        <td>{{item.phone}}</td>
                        <td>
                            <a href="#edit" @click="edit_item(index)" class="btn btn-sm btn-info">Редактировать</a>
                            <a href="#delete" @click="delete_item(index)" class="btn btn-sm btn-danger">Удалить</a>
                        </td>
                    </tr>
                    <tr v-if="!table.length">
                        <td colspan="4">Данные еще не добавлены</td>
                    </tr>
                </tbody>
            </table>
        </div>        
    </div>


    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                form_id: false,
                form_phone: '',
                form_name: '',
                search_phone: '',
                table: []
            },
            computed: {
                
            },
            methods: { 
                check_valid_phone: function(){        
                    if(this.form_phone == ''){ return ''; }
                    if(this.form_id !== false){
                      if(this.table.map(function(e) { return e.phone; }).indexOf(this.form_phone) > 0 ){
                         if(this.table.map(function(e) { return e.phone; }).indexOf(this.form_phone) == this.form_id){ return 'is-valid'; }else{ return 'is-invalid';}
                      }else{
                         return 'is-valid';
                      }                       
                    }else{
                        if(this.table.map(function(e) { return e.phone; }).indexOf(this.form_phone) < 0 ){ return 'is-valid'; } else { return 'is-invalid';}
                    }
                },                
                update_localStorage: function(){
                    this.form_id = false;
                    this.form_name = '';
                    this.form_phone = '';
                    localStorage.setItem("table", JSON.stringify(this.table));
                },
                save_item: function(){
                    let update_date = true;
                    
                    if(this.form_id !== false){
                        if(app.table.map(function(e) { return e.phone; }).indexOf(app.form_phone) < 0 || app.table.map(function(e) { return e.phone; }).indexOf(app.form_phone) == this.form_id){
                            this.table[this.form_id].name = this.form_name;
                            this.table[this.form_id].phone = this.form_phone;
                        }else{
                            update_date = false;              
                        }   
                    }else{
                        if(this.table.map(function(e) { return e.phone; }).indexOf(this.form_phone) < 0 ){
                            this.table.push({name: this.form_name, phone: this.form_phone});
                        }else{
                            update_date = false;                           
                        }  
                    }
                    if(update_date){
                        this.update_localStorage();
                    }else{
                        alert("Phone number use user "+this.table.find( x => x.phone == this.form_phone).name);
                    }                    
                },
                edit_item: function(index){      
                    console.log(this.table[index])          
                    this.form_id = index;
                    this.form_name = this.table[index].name;
                    this.form_phone = this.table[index].phone;

                },
                delete_item: function(index){
                    this.table.splice(index,1);
                    this.update_localStorage();
                },
            }, 
            updated: function() {            
                            
            },      
            mounted: function() {      
                if(JSON.parse(localStorage.getItem("table")).length){
                    this.table = JSON.parse(localStorage.getItem("table"));
                }
            }
        });
    </script>
</body>
</html>

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.