sposchedule

Форк
1
/
ChangesSchedulesView.vue 
315 строк · 8.5 Кб
1
<script setup lang="ts">
2
  import DatePicker from 'primevue/datepicker';
3
  import ChangesScheduleItem from '@/components/schedule/AdminChangesScheduleItem.vue';
4
  import { computed, onMounted, ref, watch } from 'vue';
5
  import {
6
    useChangesSchedulesQuery,
7
    useCoursesQuery,
8
  } from '@/queries/schedules';
9
  import { useDateFormat } from '@vueuse/core';
10
  import { useScheduleStore } from '@/stores/schedule';
11
  import { storeToRefs } from 'pinia';
12
  import router from '@/router';
13
  import { useRoute } from 'vue-router';
14
  import Select from 'primevue/select';
15
  import Button from 'primevue/button';
16
  import { useBuildingsQuery } from '@/queries/buildings';
17
  import { useGroupsPublicQuery } from '@/queries/groups';
18
  import { reducedWeekDays, dateRegex } from '@/composables/constants';
19
  import BlockUI from 'primevue/blockui';
20

21
  const route = useRoute();
22
  const scheduleStore = useScheduleStore();
23
  const { course, date, schedulesChanges } = storeToRefs(scheduleStore);
24
  const { setSchedulesChanges } = scheduleStore;
25

26
  const isoDate = computed(() => {
27
    return date.value ? useDateFormat(date.value, 'DD.MM.YYYY').value : null;
28
  });
29

30
  const selectedGroup = ref();
31
  const building = ref(null);
32

33
  const { data: courses } = useCoursesQuery(building);
34

35
  const coursesWithLabel = computed(() => {
36
    return (
37
      courses.value?.map(course => ({
38
        label: `${course.course} курс`,
39
        value: course.course,
40
      })) || []
41
    );
42
  });
43

44
  const selectedCourse = computed(() => {
45
    return course.value;
46
  });
47

48
  const updateQueryParams = () => {
49
    router.replace({
50
      query: {
51
        ...route.query,
52
        date: isoDate.value || undefined,
53
        building: building.value || undefined,
54
        course: selectedCourse.value || undefined,
55
        group: selectedGroup.value || undefined,
56
      },
57
    });
58
  };
59

60
  const {
61
    data: changesSchedules,
62
    isError,
63
    isFetching,
64
    isSuccess,
65
  } = useChangesSchedulesQuery(
66
    isoDate,
67
    building,
68
    selectedCourse,
69
    selectedGroup
70
  );
71

72
  watch(
73
    changesSchedules,
74
    newData => {
75
      if (newData) {
76
        setSchedulesChanges(newData);
77
      }
78
    },
79
    { deep: true }
80
  );
81

82
  watch(
83
    [isoDate, building, selectedCourse, selectedGroup],
84
    () => {
85
      updateQueryParams();
86
    },
87
    { deep: true }
88
  );
89

90
  watch(
91
    building,
92
    () => {
93
      course.value = null;
94
      selectedGroup.value = null;
95
    },
96
    { flush: 'sync' }
97
  );
98

99
  watch(
100
    course,
101
    () => {
102
      selectedGroup.value = null;
103
    },
104
    { flush: 'sync' }
105
  );
106

107
  onMounted(() => {
108
    if (route.query.date && dateRegex.test(route.query.date as string)) {
109
      // Если дата есть в query параметрах, используем ее
110
      const [day, month, year] = (route.query.date as string)
111
        .split('.')
112
        .map(Number);
113
      date.value = new Date(year, month - 1, day);
114
    } else {
115
      // Если нет даты ни в query, ни в localStorage, используем текущую дату
116
      date.value = new Date();
117
    }
118
    if (route.query.building) {
119
      building.value = route.query.building as string;
120
    }
121
    if (route.query.course) {
122
      // Если курс есть в query параметрах, используем его
123
      course.value = Number(route.query.course as string);
124
    }
125

126
    if (route.query.group) {
127
      selectedGroup.value = route.query.group as string;
128
    }
129

130
    updateQueryParams();
131
  });
132

133
  const { data: groups } = useGroupsPublicQuery(
134
    selectedGroup,
135
    building,
136
    course
137
  );
138

139
  const { data: buildingsFethed } = useBuildingsQuery();
140
  const buildings = computed(() => {
141
    return (
142
      buildingsFethed.value?.map(building => ({
143
        value: building.name,
144
        label: `${building.name} корпус`,
145
      })) || []
146
    );
147
  });
148

149
  function handleDatePickerBtns(day) {
150
    switch (day) {
151
      case 'today':
152
        date.value = new Date();
153
        break;
154

155
      case 'tomorrow':
156
        const tomorrow = new Date();
157
        tomorrow.setDate(tomorrow.getDate() + 1);
158
        date.value = tomorrow;
159
        break;
160
    }
161
  }
162
</script>
163

164
<template>
165
  <div class="flex flex-col gap-4">
166
    <div class="flex flex-wrap justify-between items-baseline">
167
      <h1 class="text-2xl">Расписание (изменения)</h1>
168
    </div>
169
    <div
170
      class="flex items-center justify-between gap-4 p-4 rounded-lg bg-surface-100 dark:bg-surface-800"
171
    >
172
      <div class="flex gap-2 items-center flex-wrap w-full">
173
        <DatePicker
174
          v-model="date"
175
          append-to="self"
176
          class="shrink-0"
177
          show-icon
178
          icon-display="input"
179
          :invalid="isError"
180
          date-format="dd.mm.yy"
181
        >
182
          <template #inputicon="slotProps">
183
            <div
184
              class="flex gap-2 justify-between items-center"
185
              @click="slotProps.clickCallback"
186
            >
187
              <small>{{
188
                reducedWeekDays[
189
                  useDateFormat(date, 'dddd', {
190
                    locales: 'ru-RU',
191
                  }).value
192
                ]
193
              }}</small>
194
              <small>{{ schedulesChanges?.week_type }}</small>
195
            </div>
196
          </template>
197
          <template #footer="slotProps">
198
            <div class="flex justify-between pt-1">
199
              <Button
200
                severity="secondary"
201
                size="small"
202
                label="Сегодня"
203
                @click="handleDatePickerBtns('today')"
204
              />
205
              <Button
206
                severity="secondary"
207
                size="small"
208
                label="Завтра"
209
                @click="handleDatePickerBtns('tomorrow')"
210
              />
211
            </div>
212
          </template>
213
        </DatePicker>
214
        <Select
215
          v-model="building"
216
          title="Корпус"
217
          show-clear
218
          :options="buildings"
219
          option-label="label"
220
          option-value="value"
221
          placeholder="Корпус"
222
        />
223
        <Select
224
          v-model="course"
225
          show-clear
226
          :options="coursesWithLabel"
227
          option-label="label"
228
          option-value="value"
229
          placeholder="Курс"
230
        />
231
        <Select
232
          v-model="selectedGroup"
233
          empty-filter-message="Группы не найдены"
234
          filter
235
          show-clear
236
          option-value="name"
237
          :options="groups"
238
          option-label="name"
239
          placeholder="Группа"
240
        />
241
        <Button
242
          target="_blank"
243
          icon="pi pi-print"
244
          as="router-link"
245
          :to="{
246
            path: '/print/changes',
247
            query: {
248
              date: isoDate,
249
            },
250
          }"
251
        />
252
        <div class="ml-auto self-center">
253
          <div
254
            v-if="schedulesChanges?.last_updated"
255
            class="flex gap-1 flex-row items-center lg:flex-col lg:gap-0 lg:items-end flex-wrap"
256
          >
257
            <span class="text-xs text-surface-400 leading-none"
258
              >Последние обновление:</span
259
            >
260
            <time
261
              title="Последние обновление"
262
              class="text-sm text-right text-surface-400"
263
              :datetime="schedulesChanges?.last_updated"
264
              >{{
265
                useDateFormat(
266
                  schedulesChanges?.last_updated,
267
                  'DD.MM.YYYY HH:mm:ss'
268
                )
269
              }}</time
270
            >
271
          </div>
272
        </div>
273
      </div>
274
    </div>
275

276
    <span v-if="isError"
277
      >Семестра на данную дату не найдено, чтобы добавить перейдите на экран
278
      добавления
279
      <RouterLink class="underline" to="/admin/semesters">семестра</RouterLink>
280
    </span>
281
    <div v-if="isSuccess">
282
      <BlockUI class="schedules" :blocked="isFetching">
283
        <ChangesScheduleItem
284
          v-for="(item, index) in schedulesChanges?.schedules"
285
          :key="index"
286
          class="schedule"
287
          :date="isoDate"
288
          :schedule="item?.schedule"
289
          :semester="item?.semester"
290
          :type="item?.schedule?.type"
291
          :group="item?.group"
292
          :lessons="item?.schedule?.lessons"
293
          :week-type="item?.week_type"
294
          :published="item?.schedule?.published"
295
        />
296
      </BlockUI>
297
    </div>
298
  </div>
299
</template>
300

301
<style scoped>
302
  .schedules {
303
    display: flex;
304
    /* flex-direction: column; */
305
    flex-wrap: wrap;
306
    row-gap: 2rem;
307
    column-gap: 10px;
308
    justify-content: space-between;
309
  }
310

311
  .schedule {
312
    min-width: 440px;
313
    flex: 0 1 calc(25% - 10px);
314
  }
315
</style>
316

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.