Исправления фронта
Множество оптимизаций по фронту
This commit is contained in:
@@ -2,27 +2,28 @@
|
||||
<Transition name="dialog">
|
||||
<div v-if="show" class="dialog-overlay" @click.self="handleCancel">
|
||||
<div class="dialog">
|
||||
<h3>{{ title }}</h3>
|
||||
<p v-html="message"></p>
|
||||
<h3>{{ dialogTitle }}</h3>
|
||||
<p v-html="dialogMessage"></p>
|
||||
<div class="dialog-buttons">
|
||||
<button class="btn-cancel" @click="handleCancel">
|
||||
{{ cancelText }}
|
||||
<button class="btn-cancel" @click="handleCancel" :disabled="loading">
|
||||
{{ dialogCancelText }}
|
||||
</button>
|
||||
<button
|
||||
v-if="showDiscard"
|
||||
v-if="dialogShowDiscard"
|
||||
class="btn-discard"
|
||||
@click="handleDiscard"
|
||||
:disabled="loading"
|
||||
>
|
||||
{{ discardText }}
|
||||
{{ dialogDiscardText }}
|
||||
</button>
|
||||
<button
|
||||
class="btn-confirm"
|
||||
:class="variant"
|
||||
:class="dialogVariant"
|
||||
@click="handleConfirm"
|
||||
:disabled="isLoading"
|
||||
:disabled="loading"
|
||||
>
|
||||
<span v-if="isLoading" class="btn-loader"></span>
|
||||
<span v-else>{{ confirmText }}</span>
|
||||
<span v-if="loading" class="btn-loader"></span>
|
||||
<span v-else>{{ dialogConfirmText }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,58 +32,87 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { DIALOGS } from '../stores/dialogs'
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
// Тип диалога из конфига (archive, restore, deleteTask, etc.)
|
||||
type: {
|
||||
type: String,
|
||||
default: 'Подтверждение'
|
||||
default: null
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
default: 'Вы уверены?'
|
||||
},
|
||||
confirmText: {
|
||||
type: String,
|
||||
default: 'Подтвердить'
|
||||
},
|
||||
cancelText: {
|
||||
type: String,
|
||||
default: 'Отмена'
|
||||
},
|
||||
discardText: {
|
||||
type: String,
|
||||
default: 'Не сохранять'
|
||||
},
|
||||
showDiscard: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// Варианты: 'default', 'danger', 'warning'
|
||||
variant: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
// Состояние загрузки (блокирует кнопку подтверждения)
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
// Прямые props (переопределяют type если заданы)
|
||||
title: String,
|
||||
message: String,
|
||||
confirmText: String,
|
||||
cancelText: String,
|
||||
discardText: String,
|
||||
showDiscard: Boolean,
|
||||
variant: String,
|
||||
// Async callback для подтверждения — сам управляет loading
|
||||
action: {
|
||||
type: Function,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
// Получаем конфиг по типу
|
||||
const config = computed(() => props.type ? DIALOGS[props.type] : {})
|
||||
|
||||
// Computed свойства с fallback: props → config → default
|
||||
const dialogTitle = computed(() => props.title ?? config.value.title ?? 'Подтверждение')
|
||||
const dialogMessage = computed(() => props.message ?? config.value.message ?? 'Вы уверены?')
|
||||
const dialogConfirmText = computed(() => props.confirmText ?? config.value.confirmText ?? 'Подтвердить')
|
||||
const dialogCancelText = computed(() => props.cancelText ?? 'Отмена')
|
||||
const dialogDiscardText = computed(() => props.discardText ?? 'Не сохранять')
|
||||
const dialogShowDiscard = computed(() => props.showDiscard ?? config.value.showDiscard ?? false)
|
||||
const dialogVariant = computed(() => props.variant ?? config.value.variant ?? 'default')
|
||||
|
||||
const emit = defineEmits(['confirm', 'cancel', 'discard'])
|
||||
|
||||
const handleConfirm = () => {
|
||||
emit('confirm')
|
||||
// Внутреннее состояние загрузки
|
||||
const loading = ref(false)
|
||||
|
||||
// Сброс состояния при закрытии диалога
|
||||
watch(() => props.show, (newVal) => {
|
||||
if (!newVal) {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
|
||||
const handleConfirm = async () => {
|
||||
if (loading.value) return
|
||||
|
||||
// Если есть async action — вызываем его и управляем loading
|
||||
if (props.action) {
|
||||
loading.value = true
|
||||
try {
|
||||
await props.action()
|
||||
// Успех — эмитим confirm для закрытия
|
||||
emit('confirm')
|
||||
} catch (e) {
|
||||
console.error('ConfirmDialog action failed:', e)
|
||||
// При ошибке — не закрываем диалог
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
} else {
|
||||
// Простой режим — просто эмитим
|
||||
emit('confirm')
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
if (loading.value) return
|
||||
emit('cancel')
|
||||
}
|
||||
|
||||
const handleDiscard = () => {
|
||||
if (loading.value) return
|
||||
emit('discard')
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user