1
0

Исправление ошибок фронта

Правим фронт от ошибок
This commit is contained in:
2026-01-15 15:27:39 +07:00
parent 6f35b84725
commit 7e1482f515
11 changed files with 513 additions and 60 deletions

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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 {