Исправление ошибок фронта
Правим фронт от ошибок
This commit is contained in:
@@ -428,12 +428,13 @@ defineExpose({
|
||||
}
|
||||
|
||||
.btn-loader {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.2);
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.3);
|
||||
border-top-color: #000;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
animation: spin 0.7s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
|
||||
@@ -349,6 +349,8 @@ const stopRefresh = () => {
|
||||
|
||||
// Отправка комментария
|
||||
const sendComment = async () => {
|
||||
if (isSendingComment.value) return // Защита от повторного вызова
|
||||
|
||||
const hasText = newCommentText.value.trim()
|
||||
const files = commentFormRef.value?.getFiles() || []
|
||||
const hasFiles = files.length > 0
|
||||
@@ -524,6 +526,7 @@ const removeNewFile = (index) => {
|
||||
}
|
||||
|
||||
const saveEditPanel = async () => {
|
||||
if (isSavingEdit.value) return // Защита от повторного вызова
|
||||
if (!editingCommentText.value.trim() || !editingCommentId.value) return
|
||||
|
||||
isSavingEdit.value = true
|
||||
@@ -1041,11 +1044,12 @@ defineExpose({
|
||||
}
|
||||
|
||||
.btn-loader {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.2);
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.3);
|
||||
border-top-color: #000;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
animation: spin 0.7s linear infinite;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -153,6 +153,9 @@ import { useMobile } from '../../composables/useMobile'
|
||||
|
||||
const { isMobile } = useMobile()
|
||||
|
||||
// Состояние загрузки для кнопки сохранения
|
||||
const isSaving = ref(false)
|
||||
|
||||
const props = defineProps({
|
||||
show: Boolean,
|
||||
card: Object,
|
||||
@@ -181,6 +184,11 @@ const props = defineProps({
|
||||
isProjectAdmin: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// Callback для сохранения (возвращает Promise)
|
||||
onSave: {
|
||||
type: Function,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
@@ -188,7 +196,6 @@ const emit = defineEmits(['close', 'save', 'delete', 'archive', 'restore'])
|
||||
|
||||
// State
|
||||
const isNew = ref(true)
|
||||
const isSaving = ref(false)
|
||||
const activeTab = ref('edit')
|
||||
const commentsCount = ref(0)
|
||||
|
||||
@@ -263,49 +270,56 @@ const cancelClose = () => {
|
||||
|
||||
// Save
|
||||
const handleSave = async () => {
|
||||
if (!canSave.value) return
|
||||
if (!canSave.value || isSaving.value) return
|
||||
|
||||
isSaving.value = true
|
||||
editTabRef.value.fileError = ''
|
||||
|
||||
if (props.card?.id) {
|
||||
// Upload new files
|
||||
const newFiles = editTabRef.value.getNewFiles()
|
||||
for (const file of newFiles) {
|
||||
const result = await taskImageApi.upload(props.card.id, file.preview, file.name)
|
||||
if (result.success) {
|
||||
file.isNew = false
|
||||
file.name = result.file.name
|
||||
file.preview = result.file.url
|
||||
} else {
|
||||
editTabRef.value.fileError = result.errors?.file || 'Ошибка загрузки файла'
|
||||
isSaving.value = false
|
||||
return
|
||||
try {
|
||||
if (props.card?.id) {
|
||||
// Upload new files
|
||||
const newFiles = editTabRef.value.getNewFiles()
|
||||
for (const file of newFiles) {
|
||||
const result = await taskImageApi.upload(props.card.id, file.preview, file.name)
|
||||
if (result.success) {
|
||||
file.isNew = false
|
||||
file.name = result.file.name
|
||||
file.preview = result.file.url
|
||||
} else {
|
||||
editTabRef.value.fileError = result.errors?.file || 'Ошибка загрузки файла'
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Delete marked files
|
||||
const filesToDelete = editTabRef.value.getFilesToDelete()
|
||||
if (filesToDelete.length > 0) {
|
||||
const fileNames = filesToDelete.map(f => f.name)
|
||||
const result = await taskImageApi.delete(props.card.id, fileNames)
|
||||
if (!result.success) {
|
||||
editTabRef.value.fileError = result.errors?.file || 'Ошибка удаления файла'
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
editTabRef.value.removeDeletedFiles()
|
||||
}
|
||||
|
||||
// Delete marked files
|
||||
const filesToDelete = editTabRef.value.getFilesToDelete()
|
||||
if (filesToDelete.length > 0) {
|
||||
const fileNames = filesToDelete.map(f => f.name)
|
||||
const result = await taskImageApi.delete(props.card.id, fileNames)
|
||||
if (!result.success) {
|
||||
editTabRef.value.fileError = result.errors?.file || 'Ошибка удаления файла'
|
||||
isSaving.value = false
|
||||
return
|
||||
}
|
||||
const formData = editTabRef.value.getFormData()
|
||||
const taskData = {
|
||||
...formData,
|
||||
id: props.card?.id
|
||||
}
|
||||
|
||||
editTabRef.value.removeDeletedFiles()
|
||||
// Вызываем callback и ждём завершения
|
||||
if (props.onSave) {
|
||||
await props.onSave(taskData)
|
||||
} else {
|
||||
emit('save', taskData)
|
||||
}
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
|
||||
const formData = editTabRef.value.getFormData()
|
||||
emit('save', {
|
||||
...formData,
|
||||
id: props.card?.id
|
||||
})
|
||||
|
||||
isSaving.value = false
|
||||
}
|
||||
|
||||
// Delete
|
||||
@@ -397,6 +411,7 @@ watch(() => props.show, async (newVal) => {
|
||||
activeTab.value = 'edit'
|
||||
commentsCount.value = props.card?.comments_count || 0
|
||||
previewImage.value = null
|
||||
isSaving.value = false // Сброс состояния кнопки сохранения
|
||||
|
||||
// Reset comments tab
|
||||
commentsTabRef.value?.reset()
|
||||
@@ -466,6 +481,10 @@ onUpdated(refreshIcons)
|
||||
}
|
||||
|
||||
.btn-save {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 120px;
|
||||
padding: 12px 28px;
|
||||
background: var(--accent);
|
||||
border: none;
|
||||
@@ -488,12 +507,13 @@ onUpdated(refreshIcons)
|
||||
}
|
||||
|
||||
.btn-loader {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.2);
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid rgba(0, 0, 0, 0.3);
|
||||
border-top-color: #000;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
animation: spin 0.7s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
|
||||
Reference in New Issue
Block a user