added table

This commit is contained in:
2026-08-16 20:01:54 +03:30
parent 27f3a6212a
commit 609f6b2fa3
17 changed files with 1227 additions and 39 deletions
+187
View File
@@ -0,0 +1,187 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { chunk } from 'lodash'
import { createSMS } from '@/api/sms'
export interface GroupSmsSendError {
batch: number
numbers: string[]
error: string
}
export type GroupSmsSendStatus = 'idle' | 'running' | 'done' | 'canceled'
export type GroupSmsSendOutcome = 'running' | 'success' | 'error' | 'partial' | 'canceled'
/** هر درخواست حداکثر ۱۰ شماره — پنل پیامک زیر فشار نرود */
const BATCH_SIZE = 10
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
/**
* ارسال گروهی پیامک — مثل ایمپورت مشتری حسابداری:
* در پس‌زمینه ادامه می‌یابد، مینیمایز می‌شود، ۱۰تایی پیش می‌رود.
*/
export const useGroupSmsSendStore = defineStore('groupSmsSend', () => {
const status = ref<GroupSmsSendStatus>('idle')
const messageText = ref('')
const queue = ref<string[]>([])
const total = ref(0)
const processed = ref(0)
const success = ref(0)
const failed = ref(0)
const errors = ref<GroupSmsSendError[]>([])
const currentBatch = ref(0)
const totalBatches = ref(0)
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 currentLabel = computed(() => {
if (!active.value) return ''
if (totalBatches.value <= 0) return '...'
return `دسته ${Math.min(currentBatch.value + 1, totalBatches.value)} از ${totalBatches.value}`
})
const outcome = computed<GroupSmsSendOutcome>(() => {
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'
messageText.value = ''
queue.value = []
total.value = 0
processed.value = 0
success.value = 0
failed.value = 0
errors.value = []
currentBatch.value = 0
totalBatches.value = 0
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(numbers: string[], message: string) {
if (status.value === 'running') return
const unique = Array.from(new Set(numbers.map((n) => String(n).trim()).filter(Boolean)))
if (!unique.length || !message.trim()) return
messageText.value = message
queue.value = unique
total.value = unique.length
processed.value = 0
success.value = 0
failed.value = 0
errors.value = []
currentBatch.value = 0
totalBatches.value = Math.ceil(unique.length / BATCH_SIZE)
cancelRequested = false
status.value = 'running'
visible.value = true
minimized.value = false
await runLoop()
}
async function sendBatchWithRetry(batchNumbers: string[], attempt = 0): Promise<void> {
try {
await createSMS({
message: messageText.value,
numbers: batchNumbers
})
} catch (e) {
if (attempt < 2 && !cancelRequested) {
await sleep(1500 * (attempt + 1))
return sendBatchWithRetry(batchNumbers, attempt + 1)
}
throw e
}
}
async function runLoop() {
const batches = chunk(queue.value, BATCH_SIZE)
for (let i = 0; i < batches.length; i++) {
if (cancelRequested) {
status.value = 'canceled'
return
}
currentBatch.value = i
const batchNumbers = batches[i]
try {
await sendBatchWithRetry(batchNumbers)
success.value += batchNumbers.length
} catch {
failed.value += batchNumbers.length
errors.value.push({
batch: i + 1,
numbers: batchNumbers,
error: 'خطا در ارتباط با پنل پیامک'
})
}
processed.value += batchNumbers.length
if (i < batches.length - 1) await sleep(250)
}
status.value = 'done'
}
return {
status,
messageText,
queue,
total,
processed,
success,
failed,
errors,
currentBatch,
totalBatches,
visible,
minimized,
active,
finished,
percent,
currentLabel,
outcome,
start,
cancel,
dismiss,
expand,
minimize,
reset
}
})