import { defineStore } from 'pinia' import { computed, ref } from 'vue' import { get, post, extractApiErrorDetail } from 'src/services/api' const DRAFT_KEY = 'bssapp:production-product-costing:default-quantities:draft:v1' function safeJsonParse (raw) { try { return JSON.parse(raw) } catch { return null } } export const useProductionProductCostingDefaultQtyStore = defineStore('production_product_costing_default_qty', () => { const rows = ref([]) const loading = ref(false) const saving = ref(false) const error = ref('') // draftByNo: { [nHammaddeTuruNo]: { lDefaultMiktar } } const draftByNo = ref({}) const persistTimer = ref(0) const dirtyNos = computed(() => Object.keys(draftByNo.value || {}).map(k => Number(k)).filter(n => n > 0)) const hasUnsavedChanges = computed(() => dirtyNos.value.length > 0) function schedulePersistDraft () { try { if (persistTimer.value) window.clearTimeout(persistTimer.value) persistTimer.value = window.setTimeout(() => { persistTimer.value = 0 persistDraftNow() }, 350) } catch { persistDraftNow() } } function persistDraftNow () { try { const payload = { version: 1, savedAt: new Date().toISOString(), draftByNo: draftByNo.value || {} } localStorage.setItem(DRAFT_KEY, JSON.stringify(payload)) } catch { // ignore } } function hydrateDraft () { try { const raw = localStorage.getItem(DRAFT_KEY) if (!raw) return const payload = safeJsonParse(raw) if (!payload || typeof payload !== 'object') return if (!payload.draftByNo || typeof payload.draftByNo !== 'object') return draftByNo.value = payload.draftByNo } catch { // ignore } } function clearDraft () { draftByNo.value = {} try { localStorage.removeItem(DRAFT_KEY) } catch { // ignore } } function setDraft (nHammaddeTuruNo, patch) { const no = Number(nHammaddeTuruNo || 0) if (!(no > 0)) return const prev = draftByNo.value?.[String(no)] || {} draftByNo.value = { ...(draftByNo.value || {}), [String(no)]: { ...prev, ...(patch || {}) } } schedulePersistDraft() } function getEffectiveRow (row) { const no = Number(row?.nHammaddeTuruNo || 0) if (!(no > 0)) return row const draft = draftByNo.value?.[String(no)] if (!draft) return row return { ...row, lDefaultMiktar: typeof draft.lDefaultMiktar === 'number' ? draft.lDefaultMiktar : row?.lDefaultMiktar, __dirty: true } } async function fetch ({ search = '', limit = 2000 } = {}) { loading.value = true error.value = '' try { const data = await get('/pricing/production-product-costing/default-quantities', { search: String(search || '').trim(), limit }) const base = Array.isArray(data) ? data : [] rows.value = base.map(getEffectiveRow) } catch (e) { error.value = extractApiErrorDetail(e) || String(e?.message || e || 'Hata') throw e } finally { loading.value = false } } async function calcAvgForRow ({ nHammaddeTuruNo, topN = 10 } = {}) { const no = Number(nHammaddeTuruNo || 0) if (!(no > 0)) return null const resp = await post('/pricing/production-product-costing/default-quantities/calc-avg', { nHammaddeTuruNo: no, topN: Number(topN || 10) }) return resp } async function saveAll () { if (!hasUnsavedChanges.value) return { updated: 0 } saving.value = true error.value = '' try { const items = dirtyNos.value.map(no => { const patch = draftByNo.value?.[String(no)] || {} return { nHammaddeTuruNo: Number(no), lDefaultMiktar: Number(patch.lDefaultMiktar || 0) } }).filter(it => it.nHammaddeTuruNo > 0 && it.lDefaultMiktar > 0) const resp = await post('/pricing/production-product-costing/default-quantities/update-bulk', { items }) clearDraft() return resp } catch (e) { error.value = extractApiErrorDetail(e) || String(e?.message || e || 'Hata') throw e } finally { saving.value = false } } hydrateDraft() return { rows, loading, saving, error, draftByNo, dirtyNos, hasUnsavedChanges, fetch, setDraft, calcAvgForRow, saveAll, clearDraft } })