Share stored document retry flow across tender detail and vault
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { readableDocument, readStoredDocument, retryDocumentExtraction } from '../services/storedDocument';
|
||||
import { documentProcessingLabel } from '../services/documentProcessing';
|
||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { useApp } from '../context/AppContext';
|
||||
@@ -88,44 +89,13 @@ export const TenderDocuments = ({ tender }) => {
|
||||
try { await deleteDocument(id); belgeleriYukle(); } catch (err) { setError(err.message); }
|
||||
};
|
||||
|
||||
// PDF/metin tarayıcıda (pdfjs) okunur; docx/xlsx/zip için tarayıcıda çözücü
|
||||
// yok, sunucudaki çıkarıcıya sorulur. .doc ve .rar'ın karşılığı yok.
|
||||
const tarayicidaOkunur = (ad) => /\.(pdf|txt|md)$/i.test(String(ad || ''));
|
||||
const sunucudaOkunur = (ad) => /\.(docx|xlsx|zip)$/i.test(String(ad || ''));
|
||||
const okunabilirMi = (ad) => tarayicidaOkunur(ad) || sunucudaOkunur(ad);
|
||||
|
||||
const belgeMetni = async (b) => {
|
||||
if (sunucudaOkunur(b.ad)) {
|
||||
const r = await fetch(`/api/me/documents/text?id=${encodeURIComponent(b.id)}`, {
|
||||
headers: { Authorization: `Bearer ${getToken()}` },
|
||||
});
|
||||
const d = await r.json().catch(() => ({}));
|
||||
if (!d.success) throw new Error(d.error || 'metin çıkarılamadı');
|
||||
return d.metin;
|
||||
}
|
||||
const r = await fetch(`/api/me/documents/download?id=${encodeURIComponent(b.id)}`, {
|
||||
headers: { Authorization: `Bearer ${getToken()}` },
|
||||
});
|
||||
if (!r.ok) throw new Error('belge indirilemedi');
|
||||
const blob = await r.blob();
|
||||
// extractText { text, pageCount, usedPages } döndürür — nesneyi metin sanıp
|
||||
// göndermek analizi sessizce bozuyordu.
|
||||
const { text } = await extractText(new File([blob], b.ad, { type: b.mime || 'application/pdf' }));
|
||||
return text;
|
||||
};
|
||||
const okunabilirMi = readableDocument;
|
||||
const belgeMetni = readStoredDocument;
|
||||
|
||||
const kalemleriYenidenCikar = async (b) => {
|
||||
setBusy('kalem'); setError(null); setBilgi(null);
|
||||
try {
|
||||
let metin;
|
||||
try { metin = await belgeMetni(b); }
|
||||
catch (readError) {
|
||||
try { await reportDocumentReadError(b.id,b.isleme); }
|
||||
catch { throw new Error(`${readError.message} (hata durumu kaydedilemedi; listeyi yenileyin)`); }
|
||||
throw readError;
|
||||
}
|
||||
const { kalemCikar } = await import('../services/kalem');
|
||||
const result = await kalemCikar({ ikn, metin, dosya:b.ad, documentId:b.id });
|
||||
const result = await retryDocumentExtraction(b);
|
||||
setBilgi({ isleme: `${b.ad}: ${result.sayi || 0} kalem çıkarıldı.` });
|
||||
} catch (e) { setError(`Kalem çıkarımı tamamlanamadı: ${e.message}. Dosya kaydı korunmuştur.`); }
|
||||
finally { await belgeleriYukle(); setBusy(null); }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { readableDocument, retryDocumentExtraction } from '../../services/storedDocument';
|
||||
import { documentProcessingLabel } from '../../services/documentProcessing';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useApp } from '../../context/AppContext';
|
||||
@@ -16,6 +17,7 @@ export const DocumentVault = () => {
|
||||
const [durum, setDurum] = useState(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [hata, setHata] = useState(null);
|
||||
const [islemeBilgi, setIslemeBilgi] = useState(null);
|
||||
const [kategori, setKategori] = useState(KATEGORILER[0]);
|
||||
const dosyaRef = useRef(null);
|
||||
|
||||
@@ -26,6 +28,19 @@ export const DocumentVault = () => {
|
||||
};
|
||||
useEffect(yukle, [authUser]);
|
||||
|
||||
const yenidenIsle = async (document) => {
|
||||
setBusy(true); setHata(null); setIslemeBilgi(null);
|
||||
try {
|
||||
const result = await retryDocumentExtraction(document);
|
||||
setIslemeBilgi(`${document.ad}: ${result.sayi || 0} kalem çıkarıldı.`);
|
||||
} catch (error) { setHata(error.message); }
|
||||
finally {
|
||||
try { setDurum(await listDocuments()); }
|
||||
catch { setHata(previous => [previous, 'Belge listesi yenilenemedi.'].filter(Boolean).join(' ')); }
|
||||
setBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
const dosyaSecildi = async (e) => {
|
||||
const f = e.target.files?.[0];
|
||||
if (!f) return;
|
||||
@@ -250,6 +265,7 @@ export const DocumentVault = () => {
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{islemeBilgi && <p role="status" className="text-xs text-slate-700">{islemeBilgi}</p>}
|
||||
{durum.belgeler.map((d) => (
|
||||
<div key={d.id} className="bg-white rounded-xl border border-slate-200 p-4 shadow-xs flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
@@ -273,7 +289,14 @@ export const DocumentVault = () => {
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 shrink-0">
|
||||
<div className="flex flex-wrap items-center gap-1">
|
||||
{d.tur === 'ihale' && d.ikn && readableDocument(d.ad) && (
|
||||
<button onClick={() => yenidenIsle(d)} disabled={busy || !d.erisilebilir}
|
||||
aria-label={`${d.ad} için kalem çıkarımını yeniden dene`}
|
||||
className="text-[10px] text-blue-700 font-bold disabled:opacity-40">
|
||||
Kalemleri yeniden çıkar
|
||||
</button>
|
||||
)}
|
||||
<button onClick={() => downloadDocument(d.id, d.ad).catch((e) => setHata(e.message))}
|
||||
className="text-slate-400 hover:text-teal-600 p-1" title="İndir">
|
||||
<Download className="w-4 h-4" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Sunucu tarafı hesap servisleri: plan/kota, kullanıcı verisi, API anahtarları, belgeler.
|
||||
* (Önceden bunların hepsi localStorage'daydı veya sahteydi.)
|
||||
*/
|
||||
import { getToken } from './auth';
|
||||
import { getToken } from './auth.js';
|
||||
|
||||
const auth = () => ({ Authorization: `Bearer ${getToken()}`, 'Content-Type': 'application/json' });
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* korunuyor). Bir kullanıcı dokümanı yükleyince kalemler havuza yazılıyor ve
|
||||
* o ihale herkesin kartında kalemleriyle görünüyor.
|
||||
*/
|
||||
import { getToken } from './auth';
|
||||
import { getToken } from './auth.js';
|
||||
|
||||
/** Bir ihalenin tüm kalemleri. */
|
||||
export async function kalemleriGetir(ikn) {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { getToken } from './auth.js';
|
||||
import { reportDocumentReadError } from './account.js';
|
||||
|
||||
export const readableDocument = (name) => /\.(pdf|txt|md|docx|xlsx|zip)$/i.test(String(name || ''));
|
||||
|
||||
export async function readStoredDocument(document) {
|
||||
if (!readableDocument(document.ad)) throw new Error('Bu dosya biçiminden metin çıkarımı desteklenmiyor.');
|
||||
const office = /\.(docx|xlsx|zip)$/i.test(document.ad);
|
||||
const response = await fetch(`/api/me/documents/${office ? 'text' : 'download'}?id=${encodeURIComponent(document.id)}`, {
|
||||
headers: {Authorization:`Bearer ${getToken()}`},
|
||||
});
|
||||
if (office) {
|
||||
const result = await response.json().catch(() => ({}));
|
||||
if (!response.ok || !result.success) throw new Error(result.error || 'Belge metni alınamadı.');
|
||||
return result.metin;
|
||||
}
|
||||
if (!response.ok) throw new Error('Belge indirilemedi.');
|
||||
const blob = await response.blob();
|
||||
const { extractText } = await import('./pdfText');
|
||||
return (await extractText(new File([blob],document.ad,{type:document.mime || 'application/octet-stream'}))).text;
|
||||
}
|
||||
|
||||
export async function retryDocumentExtraction(document) {
|
||||
if (document.tur !== 'ihale' || !document.ikn) throw new Error('İhaleye bağlı ihale dokümanı gerekli.');
|
||||
const token = getToken();
|
||||
const checkSession = () => { if (!token || token !== getToken()) throw new Error('Oturum değişti; belgeyi yeniden açın.'); };
|
||||
checkSession();
|
||||
let text;
|
||||
try { text = await readStoredDocument(document); }
|
||||
catch (error) {
|
||||
checkSession();
|
||||
try { await reportDocumentReadError(document.id,document.isleme); }
|
||||
catch { throw new Error(`${error.message} (hata durumu kaydedilemedi; listeyi yenileyin)`); }
|
||||
throw error;
|
||||
}
|
||||
checkSession();
|
||||
const { kalemCikar } = await import('./kalem.js');
|
||||
checkSession();
|
||||
return kalemCikar({ikn:document.ikn,metin:text,dosya:document.ad,documentId:document.id});
|
||||
}
|
||||
Reference in New Issue
Block a user