sposchedule

Форк
1
/
SubjectsView.vue 
230 строк · 7.0 Кб
1
<script setup lang="ts">
2
  import { ref } from 'vue';
3
  import DataTable from 'primevue/datatable';
4
  import Column from 'primevue/column';
5
  import InputText from 'primevue/inputtext';
6
  import Button from 'primevue/button';
7
  import { useDateFormat } from '@vueuse/core';
8
  import { useToast } from 'primevue/usetoast';
9
  import {
10
    useSubjectsQuery,
11
    useDestroySubject,
12
    useStoreSubject,
13
    useUpdateSubject,
14
  } from '../../queries/subjects';
15
  import Textarea from 'primevue/textarea';
16
  import { FilterMatchMode } from '@primevue/core/api';
17

18
  const { data: subjects } = useSubjectsQuery();
19

20
  const toast = useToast();
21

22
  const newSubjectName = ref('');
23
  const newSubjectError = ref(false);
24

25
  const editingRows = ref([]);
26
  const selectedSubjects = ref([]);
27

28
  const { mutateAsync, isPending: isUpdated } = useUpdateSubject();
29
  const onRowEditSave = async event => {
30
    let { newData } = event;
31
    try {
32
      await mutateAsync({ id: newData.id, body: newData });
33
    } catch (e) {
34
      toast.add({
35
        severity: 'error',
36
        summary: 'Ошибка',
37
        detail: e?.response.data.message,
38
        life: 3000,
39
        closable: true,
40
      });
41
      return;
42
    }
43
  };
44

45
  const { mutateAsync: destroySubject, isPending: isDestroyed } =
46
    useDestroySubject();
47
  const deleteSubjects = async () => {
48
    if (!selectedSubjects.value.length) return;
49

50
    for (let i = 0; i < selectedSubjects.value.length; i++) {
51
      try {
52
        await destroySubject(selectedSubjects.value[i].id);
53
      } catch (e) {
54
        toast.add({
55
          severity: 'error',
56
          summary: 'Ошибка',
57
          detail: e?.response.data.message,
58
          life: 3000,
59
          closable: true,
60
        });
61
        return;
62
      }
63
    }
64
    selectedSubjects.value = [];
65
  };
66

67
  const { mutateAsync: storeSubject, isPending: isStored } = useStoreSubject();
68
  const addSubject = async () => {
69
    try {
70
      await storeSubject(newSubjectName.value);
71
    } catch (e) {
72
      newSubjectError.value = true;
73
      toast.add({
74
        severity: 'error',
75
        summary: 'Ошибка',
76
        detail: e?.response.data.message,
77
        life: 3000,
78
        closable: true,
79
      });
80
      newSubjectName.value = '';
81
      return;
82
    }
83
    newSubjectError.value = false;
84
    newSubjectName.value = '';
85
  };
86

87
  const importSubjectsState = ref();
88
  const importingSubjects = ref();
89

90
  async function parseAndSendSubjects() {
91
    // Разделяем введенные предметы на массив строк, убирая пустые строки и пробелы
92
    const subjects = importingSubjects.value
93
      .split('\n')
94
      .map(subject => subject.trim())
95
      .filter(subject => subject);
96

97
    // Проходим по каждому предмету и отправляем его на сервер
98
    for (const subject of subjects) {
99
      try {
100
        // Отправляем данные на сервер
101
        await storeSubject(subject);
102

103
        // Успешное добавление предмета
104
        toast.add({
105
          severity: 'success',
106
          summary: 'Успех',
107
          detail: `Предмет "${subject}" успешно добавлен`,
108
          life: 3000,
109
          closable: true,
110
        });
111
      } catch (e) {
112
        // Обработка ошибки при отправке
113
        newSubjectError.value = true;
114
        toast.add({
115
          severity: 'error',
116
          summary: 'Ошибка',
117
          detail:
118
            e?.response?.data?.message ||
119
            `Ошибка при добавлении предмета "${subject}"`,
120
          life: 3000,
121
          closable: true,
122
        });
123
        continue; // Продолжаем с следующего предмета
124
      }
125
    }
126

127
    // Очистка поля после завершения отправки
128
    newSubjectError.value = false;
129
    importingSubjects.value = '';
130
  }
131

132
  const filters = ref({
133
    global: { value: null, matchMode: FilterMatchMode.CONTAINS },
134
    name: { value: null, matchMode: FilterMatchMode.STARTS_WITH },
135
  });
136
</script>
137

138
<template>
139
  <div class="flex flex-col gap-4">
140
    <div class="flex flex-wrap justify-between items-baseline">
141
      <h1 class="text-2xl">Предметы</h1>
142
    </div>
143
    <div class="">
144
      <form
145
        class="flex flex-wrap items-center gap-4 p-4 rounded-lg bg-surface-100 dark:bg-surface-800"
146
      >
147
        <InputText
148
          v-model="newSubjectName"
149
          :invalid="newSubjectError"
150
          placeholder="Пример: Математика"
151
          class="w-full md:w-60"
152
        />
153
        <Button
154
          type="submit"
155
          :disabled="!newSubjectName"
156
          label="Добавить предмет"
157
          @click.prevent="addSubject"
158
        />
159
        <Button
160
          label="Импорт"
161
          icon="pi pi-file-import"
162
          outlined
163
          type="submit"
164
          @click.prevent="importSubjectsState = !importSubjectsState"
165
        />
166
        <div v-if="importSubjectsState" class="flex flex-col gap-2">
167
          <Textarea
168
            v-model="importingSubjects"
169
            placeholder="Введите в столбик название предметов"
170
            rows="5"
171
            cols="30"
172
          />
173
          <Button type="submit" @click.prevent="parseAndSendSubjects">
174
            Импортировать
175
          </Button>
176
        </div>
177
      </form>
178
    </div>
179
    <div class="">
180
      <DataTable
181
        v-model:filters="filters"
182
        v-model:selection="selectedSubjects"
183
        v-model:editing-rows="editingRows"
184
        paginator
185
        :rows="10"
186
        :global-filter-fields="['name']"
187
        :loading="isUpdated || isDestroyed || isStored"
188
        :value="subjects"
189
        edit-mode="row"
190
        data-key="id"
191
        :pt="{
192
          table: { style: 'min-width: 50rem' },
193
        }"
194
        @row-edit-save="onRowEditSave"
195
      >
196
        <template #header>
197
          <div class="flex flex-wrap items-center gap-2 justify-between">
198
            <Button
199
              severity="danger"
200
              :disabled="!selectedSubjects.length || !subjects.length"
201
              type="button"
202
              icon="pi pi-trash"
203
              label="Удалить"
204
              outlined
205
              @click="deleteSubjects"
206
            />
207
            <InputText v-model="filters['global'].value" placeholder="Поиск" />
208
          </div>
209
        </template>
210
        <Column selection-mode="multiple" header-style="width: 3rem" />
211
        <Column field="name" header="Название предмета">
212
          <template #editor="{ data, field }">
213
            <InputText v-model="data[field]" />
214
          </template>
215
        </Column>
216

217
        <Column field="updated_at" header="Дата изменения">
218
          <template #body="slotProps">
219
            {{ useDateFormat(slotProps.data.updated_at, 'DD.MM.YY HH:mm:ss') }}
220
          </template>
221
        </Column>
222
        <Column
223
          :row-editor="true"
224
          style="width: 10%; min-width: 8rem"
225
          body-style="text-align:center"
226
        />
227
      </DataTable>
228
    </div>
229
  </div>
230
</template>
231

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

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

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

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