Построение данных в календаре

79
19 марта 2021, 10:00

Вопрос: при выборе года и месяца календарь заполняется данными о выходе сотрудника на работу по плану и факту за определенный месяц... не получается отстроить график так, чтобы отображалась данные за следующий и предыдущий месяцы...

Код:

<template>
  <div class="outputGraph">
    <div class="window">
        <div class="window-charts">
            <div class="window-charts-text">
                <p>График выходов</p>
            </div>
            <div class="window-charts-block">
                <div class="window-charts-block-btn" @click.stop="showModalYears()" ref="clickBlock">
                    <p ref="yearsMonth">{{ objCurrentYearsMonth.date }}</p>
                    <span></span>
                </div>
                <div class="window-charts-block-modal opacity" ref="modalCalendar">
                    <!-- модалка календаря -->
                    <div class="window-charts-block-modal-years noheader" ref="years" >
                        <span class="noheader previous" @click="switchYears($event)"></span>
                        <p class="noheader" ref="yearsActive">{{ objCurrentYearsMonth.currentYears }}</p>
                        <span class="noheader next" @click="switchYears($event)"></span>
                    </div>
                    <div class="window-charts-block-modal-month" v-on:click="addModalYears($event)" v-for="i in listMonth"  ref="blockMonth"><span
                        ref="clickMonth">{{ i }}</span>
                    </div>
                </div>
            </div>
        </div>
        <div class="output-graph">
            <div class="output-graph__days">
                <div v-for="key in listDays"><span>{{ key }}</span></div>
            </div>
            <div class="output-graph__graphic">
                <div class="output-graph__graphic__block" ref="graphicBlock"
                     v-for="key in objCurrentYearsMonth.startDay">
                    <div class="output-graph__graphic__block-transform">
                        <div class="block">
                            <span></span>                   <!-- строим по порядку, пока дней хватает в месяце-->
                            <span></span>                   <!-- после, начинаем новый отсчет-->
                        </div>
                        <div>
                            <span></span>
                        </div>
                    </div>
                    <div class="daysPlan">
                        <span class="disagree"
                        ></span>
                        <span></span>
                    </div>
                </div>
                <div class="output-graph__graphic__block" v-for="key in objCurrentYearsMonth.maxDaysThisMonth">
                    <div class="output-graph__graphic__block-transform">
                        <div class="block">
                            <span v-if="key <= objCurrentYearsMonth.maxDaysThisMonth">{{ key }}</span>
                            <!-- строим по порядку, пока дней хватает в месяце-->
                            <span v-if="key > objCurrentYearsMonth.maxDaysThisMonth">{{ key - objCurrentYearsMonth.maxDaysThisMonth }}</span>
                            <!-- после, начинаем новый отсчет-->
                        </div>
                        <div>
                            <span  title="план">{{ employeeExitSchedule.daysPlan[key - 1] }}</span>
                        </div>
                    </div>
                    <div class="daysPlan">
                        <span class="disagree"
                              v-if="employeeExitSchedule.daysFact[key - 1] !== employeeExitSchedule.daysPlan[key - 1]">{{ employeeExitSchedule.daysFact[key - 1] }}</span>
                        <span v-if="employeeExitSchedule.daysFact[key - 1] === employeeExitSchedule.daysPlan[key - 1]" title="факт">{{ employeeExitSchedule.daysFact[key - 1] }}</span>
                    </div>
                </div>
                <div class="output-graph__graphic__block" ref="graphicBlock"
                     v-for="key in objCurrentYearsMonth.endDay">
                    <div class="output-graph__graphic__block-transform">
                        <div class="block">
                            <span></span>                   <!-- строим по порядку, пока дней хватает в месяце-->
                            <span></span>                   <!-- после, начинаем новый отсчет-->
                        </div>
                        <div>
                            <span></span>
                        </div>
                    </div>
                    <div class="daysPlan">
                        <span class="disagree"
                        ></span>
                        <span></span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</template>
 <script>
 export default {
    name: "employeeCardExitSchedule",
    props: {
        workerId: Number
    },
    data: function () {
        return {
            objCurrentYearsMonth: {                                                                                 // Объект содеражащий общую информацию
                currentYears: '',                                                                                   // выбранный год
                currentMonth: '',                                                                                   // выбранный месяц
                NumberMonth: '',                                                                                    // номер выбранного месяца
                date: '',                                                                                           // данные выводимые в текущий год и месяц
                maxDaysThisMonth: '',                                                                               // количество дней в текущем месяце
                startDay: '',                                                                                       // номер дня с которого начался месяц
                endDay: '',                                                                                         // номер дня с которого начался месяц
                normalDayPlan: 0,                                                                                   // норма дней plan
                normalHourPlan: 0,                                                                                  // норма часов plan
                normalDayFact: 0,                                                                                   // норма дней fact
                normalHourFact: 0,                                                                                  // норма часов fact
                processingDay: 0,                                                                                   // переработка по дням
                processingHour: 0,                                                                                  // переработка по часам
            },
            listDays: ['ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ', 'ВС'],                                                   // дни недели для отображения  в построении блока
            listMonth: ["Январь", "Феврваль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"], // список месяцев
            employeeExitSchedule: {},                                                                               //пришедшие данные с сервера по графику выхода сотрудника
            numberWeek: ''                                                                                          // количество недель, которые захватывает месяц
        }
    },
    methods: {
        /**
         * Функция отображения календаря по клику и сохранения данных выбранные пользователем
         */
        showModalYears() {
            let modalCalendar = this.$refs.modalCalendar;                                                           // если у dom элемента по refs ссылке есть селектор 'opacity', то удаляется и теи самым список отображаеться
            modalCalendar.classList.toggle('opacity');                                                              // если класса 'opacity' нет, добавляет его, если есть – удаляет.
        },
        /**
         * Функция обрабатывает события клика во время выбора месяца из списка,
         * определяет номер выбранного месяца и год
         * Входные параметры: event - элемент по которому произведен клик
         * На выходе записываем выбранный год и месяц, идентификатор месяца
         */
        addModalYears(event) {
            let year = this.$refs.yearsActive.textContent,                                                          // определяем выбранный год
                numberMonth = 0;                                                                                    // номер выбранного месяца
            this.showModalYears();                                                                                  // вызов метода showModalYears()
            //console.log(this.objCurrentYearsMonth.date);
            for (let i = 0; i < this.listMonth.length; i++) {                                                       // цикл по перебору массива месяцев и нахождение месяца по счету который выбрали
                if (this.listMonth[i] === event.target.textContent) {                                               // если этот месяц равен событию на которое кликаем
                    numberMonth = i;                                                                                // то выбирается
                    break
                }
            }
            this.clickDate(new Date(year, numberMonth))                                                             // вызов метода для получения данных за месяц
        },
        /**
         * Метод при первоначальной загрузке страницы определяет текущую дату и вызывает метод
         * (если агрумент не был передан по умолчанию устанавливается текущая дата)
         * на ajax-запрос по получению данных за месяц.
         */
        clickDate(selectedDate = new Date()) {
            this.ajaxDataMonth(selectedDate);                                                                       // При выборе другого месяца или/и года, в функцию передается дата с выбранным годом и месяцем
            let year = selectedDate.getFullYear(),                                                                  // вычисляем текущий год
                month = selectedDate.getMonth(),                                                                    // вычисляем текущий месяц
                cuntDay = new Date(year, month + 1, 0).getDate(),                                                   // количество дней в текущем месяце
                startDay = new Date(year, month).getDay(),                                                          // день недели начала месяца
                endDay =  new Date(year, month + 1, 0).getDay();                                                    // день недели окончания месяца
            if (startDay === 0) {                                                                                   // устанавливаем значение для достройки в начале пустых ячеек календаря(если равно 0)
                this.objCurrentYearsMonth.startDay = 6;                                                             // то значение дня с которого начинался месяц равно 6часам
            } else {                                                                                                // иначе
                this.objCurrentYearsMonth.startDay = startDay - 1;                                                  // отнимаем 1 смену
            }
            if (endDay === 0) {                                                                                     // устанавливаем значение для достройки в конце пустых ячеек календаря(если равно 0)
                this.objCurrentYearsMonth.endDay = endDay;                                                          // то это последний день
            } else {                                                                                                // иначе
                this.objCurrentYearsMonth.endDay = 7 - endDay;                                                      // отнимаем
            }
            this.objCurrentYearsMonth.currentYears = year;                                                          // записал год нынешний
            this.objCurrentYearsMonth.maxDaysThisMonth = cuntDay;                                                   // записал количество дней в текущем месяце
            this.objCurrentYearsMonth.NumberMonth = month;
            this.objCurrentYearsMonth.date = this.listMonth[month] + " " + year;                                    //записал строку месяц и год
            let dateWeek = new Date(year, month + 1, 0);
            this.numberWeek =  Math.ceil( (dateWeek.getDate() - (dateWeek.getDay() ? dateWeek.getDay() : 7) ) / 7 ) +1;

            for (let i = 0; i < this.$refs.blockMonth.length; i++) {
                if (this.$refs.blockMonth[i].classList.contains('month-active')) {
                    this.$refs.blockMonth[i].classList.remove('month-active');
                    break
                }
            }
            this.$refs.blockMonth[this.objCurrentYearsMonth.NumberMonth].classList.add('month-active');
            console.log('Год - ', this.objCurrentYearsMonth.currentYears, 'Номер месяца - ', this.objCurrentYearsMonth.NumberMonth);
        },
        /**
         * Метод ajax-запроса на получение данных по графику работ за выбранные месяц
         */
        ajaxDataMonth(selectedDate) {                                                                               // selectedDate-выбранная дата
            this.employeeExitSchedule = {                                                                           // Тестовый набор входных данных и результатов их обработки
                    daysFact: ['1', '1', '1', 'в', '2', 'в', '1', '1', '1', 'в', 'в', '2', '1', 'в', '1', '1', '1', 'в', '1', '2', '1', '1', 'в', 'в', 'в', '1', '1', '1', 'в', '1', '1'], // фактический график выходов
                    daysPlan: ['в', '2', '1', '1', 'в', 'в', '1', '1', '1', 'в', 'в', '1', '1', 'в', '1', '1', '2', 'в', '1', '1', '1', '1', '1', 'в', 'в', '1', '1', '1', 'в', '1', '2']   // плановый график выходов
                };
            this.calculationDay(this.employeeExitSchedule, this.objCurrentYearsMonth)
        },
        /**
         * функция по выбору года
         * входные параметры
         * event - элемент по которому кликнули
         * */
        switchYears(event) {
            if (event.target.classList.contains('next')) {                                                          // если dom элемент "кнопка вперед"
                this.objCurrentYearsMonth.currentYears = +this.objCurrentYearsMonth.currentYears + 1;               // тогда добавляем год на 1
            } else if (event.target.classList.contains('previous')) {                                               // если dom элемент кнопка "назад"
                this.objCurrentYearsMonth.currentYears = +this.objCurrentYearsMonth.currentYears - 1;               // тогда отнимаем год на 1
            }
        },
        /*
           Запрос на получение данных о графике выходов
       */
          async getGraphicWorkerCard(workerObjId) {
            const postData = {
                controller: 'ordersystem\\WorkSchedule',                                                            // путь контроллеру
                method: 'GetGraphicWorkerCard',                                                                           // имя метода для полученния данных работника
                subscribe: '',                                                                                      // подписка на список работникаов
                data: JSON.stringify({
                    worker_id: workerObjId,
                    month: '',
                    year: ''
                })
            };
            let workerGraphic = await sendAjax(postData);
            this.employeeExitSchedule = workerGraphic.Items;
        },
    },
    computed: {
        monthlyWorkerGraphic() {
            return this.workerGraphic;
        }
    },
    mounted() {
        this.clickDate();
    }
}
</script>
Answer 1

Пример реализации календаря, точнее шаблон. Разбито на компоненты: месяц, неделя, день. Данные уже прокините сами

const Day = Vue.component('Day', { 
  props: ['date'], 
  template: `<div class='day'>{{date.getDate()}}</div>`, 
}); 
 
const Week = Vue.component('Week', { 
  props: ['weekIndex', 'dayOfWeek'], 
  components: { Day }, 
  template: `<div class='week'> 
          <Day  
            v-for="index in 7"  
            :date="getDate(index)"  
            :key="getDate(index).getTime()"> 
          </Day> 
        </div>`, 
  computed: { 
startDay() { 
  // определяем день года, с которого необходимо начать отрисовку недели 
  const dayIndex = this.dayOfWeek.getDay() || 7; 
  const different = time.day * (dayIndex - 1); 
  const start = this.dayOfWeek - different; 
  return new Date(start); 
}, 
  }, 
  methods: { 
getDate(index) { 
  return new Date(this.startDay.getTime() + time.day * (index - 1)); 
}, 
  }, 
}); 
const time = { 
  day: 1000 * 60 * 60 * 24, 
  week: 1000 * 60 * 60 * 24 * 7, 
}; 
 
const Month = Vue.component('Month', { 
  props: ['date'], 
  components: { Week }, 
  template: `<div> 
          <div>{{monthName}}</div> 
          <div class='month'> 
            <Week  
              v-for="index in 6"  
              :key="index"  
              :weekIndex="index"  
              :dayOfWeek='getDayOfWeek(index)'> 
            </Week> 
          </div> 
        </div>`, 
  computed: { 
monthName() { 
  return this.date.toLocaleDateString('en-US', { month: 'short' }); 
}, 
startDay() { 
  if (!this.date) return; 
  // 1-й день месяца 
  return new Date(this.date.getFullYear(), this.date.getMonth()); 
}, 
  }, 
  methods: { 
getDayOfWeek(index) { 
  // по сути, просто какой-нибудь день той недели, в которою мы передаем данные 
  return new Date(this.startDay.getTime() + time.week * (index - 1)); 
}, 
  }, 
}); 
 
new Vue({ 
  el: '#app', 
  components: { Month }, 
  template: `<div><input v-model="value" type='date'> 
            <Month v-if="date" :date="date"></Month> 
        </div>`, 
  data() { 
return { 
  value: new Date(), 
}; 
  }, 
  computed: { 
date() { 
  const z = new Date(this.value); 
  return z.toString() === 'Invalid Date' ? false : z; 
}, 
  }, 
});
body{ 
  background-color: white; 
  overflow: hidden; 
 
} 
#app{ 
  height: 100vh; 
  border: 1px solid red; 
  overflow: scroll; 
} 
.month{ 
  width: 300px; 
  border: 1px solid red 
} 
.week{ 
  display: flex; 
} 
.day{ 
  width: 13%; 
  height: 30px; 
  flex-grow: 3; 
  border: 1px solid; 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.1/vue.js"></script> 
 
   <div id="app"> </div>

READ ALSO
Как остановить по клику на кнопку интервальное выполнение функции

Как остановить по клику на кнопку интервальное выполнение функции

Вроде не новичок в JS, но вопрос возник довольно легкий и глупыйКак остановить по клику на кнопку интервальное выполнение функции, а затем...

75
Lazyload для тега picture

Lazyload для тега picture

Подскажите, пожалуйста, как правильно лениво загружать (желательно по скроллу) картинки, которые собираются через тег <picture>?

98
Как работает стек вызова функций при рекурсии?

Как работает стек вызова функций при рекурсии?

Написал простую рекурсию (работает как задумано):

88
Изменить атрибут src img

Изменить атрибут src img

На сайте имеется блок < div id='recentpostsae' > с последними публикациямиВ нем нужно изменить src img, с 's72-c' на 's150-c', в данный момент src имеет вид https://site

165