work on moving customers from tahesab

This commit is contained in:
2026-06-28 23:41:46 +03:30
parent 218d3e9f5e
commit ec535d4576
5 changed files with 898 additions and 5 deletions
+162
View File
@@ -0,0 +1,162 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { importFromTahesab, type TahesabOnlyCustomer } from '@/api/tahesab'
export interface ImportError {
code: number
name: string
error: string
}
export type ImportStatus = 'idle' | 'running' | 'done' | 'canceled'
/** نتیجهٔ نهایی برای نمایش آیکن/متن مناسب */
export type ImportOutcome = 'running' | 'success' | 'error' | 'partial' | 'canceled'
/**
* فروشگاه سراسری برای فرایند «وارد کردن همه» مشتریان ته‌حساب.
* چون به‌صورت singleton است، با جابه‌جایی بین صفحات از بین نمی‌رود و
* عملیات در پس‌زمینه ادامه پیدا می‌کند.
*/
export const useCustomerImportStore = defineStore('customerImport', () => {
const status = ref<ImportStatus>('idle')
const queue = ref<TahesabOnlyCustomer[]>([])
const total = ref(0)
const processed = ref(0)
const success = ref(0)
const failed = ref(0)
const errors = ref<ImportError[]>([])
const doneCodes = ref<number[]>([])
// وضعیت نمایش: آیا UI فعال است و آیا کوچک شده (minimize)
const visible = ref(false)
const minimized = ref(false)
let cancelRequested = false
const active = computed(() => status.value === 'running')
const finished = computed(() => status.value === 'done' || status.value === 'canceled')
const percent = computed(() =>
total.value > 0 ? Math.min(100, Math.round((processed.value / total.value) * 100)) : 0,
)
const currentName = computed(() => queue.value[processed.value]?.name ?? '')
const outcome = computed<ImportOutcome>(() => {
if (status.value === 'running' || status.value === 'idle') return 'running'
if (status.value === 'canceled') return 'canceled'
if (failed.value === 0) return 'success'
if (success.value === 0) return 'error'
return 'partial'
})
function reset() {
status.value = 'idle'
queue.value = []
total.value = 0
processed.value = 0
success.value = 0
failed.value = 0
errors.value = []
doneCodes.value = []
visible.value = false
minimized.value = false
cancelRequested = false
}
function expand() {
minimized.value = false
}
function minimize() {
minimized.value = true
}
function cancel() {
if (status.value === 'running') cancelRequested = true
}
/** بستن دستی کارت پس از پایان عملیات */
function dismiss() {
if (status.value === 'running') return
reset()
}
async function start(customers: TahesabOnlyCustomer[]) {
if (status.value === 'running') return
if (!customers.length) return
queue.value = customers.slice()
total.value = customers.length
processed.value = 0
success.value = 0
failed.value = 0
errors.value = []
doneCodes.value = []
cancelRequested = false
status.value = 'running'
visible.value = true
minimized.value = false
await runLoop()
}
async function runLoop() {
while (processed.value < queue.value.length) {
if (cancelRequested) {
status.value = 'canceled'
return
}
const customer = queue.value[processed.value]
try {
const res = await importFromTahesab([customer])
if (res.success) {
success.value++
doneCodes.value.push(customer.code)
} else {
failed.value++
errors.value.push({
code: customer.code,
name: customer.name,
error: res.errors?.[0]?.error || 'ثبت ناموفق بود',
})
}
} catch (e) {
failed.value++
errors.value.push({
code: customer.code,
name: customer.name,
error: 'خطا در ارتباط با سرور',
})
}
processed.value++
}
status.value = 'done'
// پس از تکمیل محو نمی‌شود؛ تا زمانی که کاربر گزارش را ببندد باقی می‌ماند
}
return {
status,
queue,
total,
processed,
success,
failed,
errors,
doneCodes,
visible,
minimized,
active,
finished,
percent,
currentName,
outcome,
start,
cancel,
dismiss,
expand,
minimize,
reset,
}
})