Compare commits
1 Commits
4dfecf7fcf
...
8ba21f915f
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ba21f915f |
@@ -49,11 +49,21 @@
|
|||||||
<input id="sourceUrl" v-model="form.sourceUrl" type="url" :required="form.importMethod === 'url'" />
|
<input id="sourceUrl" v-model="form.sourceUrl" type="url" :required="form.importMethod === 'url'" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="error" class="error-message">{{ error }}</div>
|
<div v-if="importJob.jobId" class="job-status">
|
||||||
<div v-if="successMessage" class="success-message">{{ successMessage }}</div>
|
<h3>Статус импорта</h3>
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress" :style="{ width: importJob.progress + '%' }"></div>
|
||||||
|
</div>
|
||||||
|
<p>{{ importJob.message }} ({{ importJob.progress }}%)</p>
|
||||||
|
<div v-if="importJob.status === 'failed'" class="error-message">Ошибка: {{ importJob.message }}</div>
|
||||||
|
<div v-if="importJob.status === 'completed'" class="success-message">Импорт успешно завершен!</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button type="submit" :disabled="isLoading">
|
<div v-if="error && !importJob.jobId" class="error-message">{{ error }}</div>
|
||||||
{{ isLoading ? "Импорт..." : "Импортировать" }}
|
<!-- <div v-if="successMessage" class="success-message">{{ successMessage }}</div> -->
|
||||||
|
|
||||||
|
<button type="submit" :disabled="isLoading || (importJob.jobId !== null && importJob.status !== 'completed' && importJob.status !== 'failed')">
|
||||||
|
{{ isLoading ? "Запуск..." : "Импортировать" }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -61,8 +71,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, watch } from "vue";
|
import { ref, reactive, watch, onUnmounted } from "vue";
|
||||||
import apiClient from "@/api/axios";
|
import apiClient from "@/api/axios";
|
||||||
|
import { useAuthStore } from "@/stores/auth";
|
||||||
|
|
||||||
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
name: "",
|
name: "",
|
||||||
@@ -78,6 +91,16 @@ const isLoading = ref(false);
|
|||||||
const error = ref<string | null>(null);
|
const error = ref<string | null>(null);
|
||||||
const successMessage = ref<string | null>(null);
|
const successMessage = ref<string | null>(null);
|
||||||
|
|
||||||
|
// Состояние задачи импорта
|
||||||
|
const importJob = reactive({
|
||||||
|
jobId: null as number | null,
|
||||||
|
status: "" as string,
|
||||||
|
progress: 0,
|
||||||
|
message: "" as string,
|
||||||
|
});
|
||||||
|
|
||||||
|
let ws: WebSocket | null = null;
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => form.importerType,
|
() => form.importerType,
|
||||||
(newType) => {
|
(newType) => {
|
||||||
@@ -94,6 +117,57 @@ const onFileSelected = (event: Event) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const connectWebSocket = () => {
|
||||||
|
if (ws) {
|
||||||
|
ws.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||||
|
const host = window.location.host;
|
||||||
|
const url = `${protocol}//${host}/api/admin/ws/jobs?token=${authStore.token}`;
|
||||||
|
|
||||||
|
ws = new WebSocket(url);
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
if (data.job_id === importJob.jobId) {
|
||||||
|
importJob.status = data.status;
|
||||||
|
importJob.progress = data.progress;
|
||||||
|
importJob.message = data.error_message || getStatusMessage(data.status);
|
||||||
|
|
||||||
|
if (data.status === 'completed') {
|
||||||
|
successMessage.value = "Импорт завершен!";
|
||||||
|
isLoading.value = false;
|
||||||
|
} else if (data.status === 'failed') {
|
||||||
|
error.value = data.error_message;
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("WS parse error", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = () => {
|
||||||
|
console.log("WS closed");
|
||||||
|
if (importJob.status !== 'completed' && importJob.status !== 'failed' && importJob.jobId) {
|
||||||
|
// Reconnect logic could be here
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusMessage = (status: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'pending': return 'Ожидание очереди...';
|
||||||
|
case 'downloading': return 'Скачивание файлов...';
|
||||||
|
case 'processing': return 'Обработка...';
|
||||||
|
case 'completed': return 'Готово';
|
||||||
|
case 'failed': return 'Ошибка';
|
||||||
|
default: return status;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleImport = async () => {
|
const handleImport = async () => {
|
||||||
if (form.importMethod === "file" && !form.file) {
|
if (form.importMethod === "file" && !form.file) {
|
||||||
error.value = "Пожалуйста, выберите файл для импорта.";
|
error.value = "Пожалуйста, выберите файл для импорта.";
|
||||||
@@ -108,6 +182,12 @@ const handleImport = async () => {
|
|||||||
error.value = null;
|
error.value = null;
|
||||||
successMessage.value = null;
|
successMessage.value = null;
|
||||||
|
|
||||||
|
// Сброс состояния задачи
|
||||||
|
importJob.jobId = null;
|
||||||
|
importJob.status = "";
|
||||||
|
importJob.progress = 0;
|
||||||
|
importJob.message = "";
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("name", form.name);
|
formData.append("name", form.name);
|
||||||
formData.append("displayName", form.displayName);
|
formData.append("displayName", form.displayName);
|
||||||
@@ -127,13 +207,28 @@ const handleImport = async () => {
|
|||||||
"Content-Type": "multipart/form-data",
|
"Content-Type": "multipart/form-data",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
successMessage.value = response.data;
|
|
||||||
|
// Обработка асинхронного ответа
|
||||||
|
if (response.status === 202 && response.data.job_id) {
|
||||||
|
importJob.jobId = response.data.job_id;
|
||||||
|
importJob.status = 'pending';
|
||||||
|
importJob.message = 'Задача создана...';
|
||||||
|
connectWebSocket();
|
||||||
|
} else {
|
||||||
|
// Fallback for sync behavior (old) or other codes
|
||||||
|
successMessage.value = response.data;
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
error.value = e.response?.data || "Произошла ошибка при импорте.";
|
error.value = e.response?.data || "Произошла ошибка при импорте.";
|
||||||
} finally {
|
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (ws) ws.close();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user