fix bug of pargar 4
This commit is contained in:
@@ -85,6 +85,38 @@ export const syncAllWalletsFromPargarChunk = async (params?: {
|
||||
force: params?.force ?? false,
|
||||
})
|
||||
|
||||
export interface StuckOutboundRow {
|
||||
id: number
|
||||
export_id: string
|
||||
type: string
|
||||
amount: number | null
|
||||
desc: string
|
||||
order_id: number | null
|
||||
withdraw_id: number | null
|
||||
customer_id: number | null
|
||||
customer_name?: string | null
|
||||
customer_mobile?: string | null
|
||||
pargar_account_id?: string | number | null
|
||||
created_at?: string | null
|
||||
waited_minutes: number
|
||||
}
|
||||
|
||||
export interface StuckOutboundSummary {
|
||||
count: number
|
||||
customers: number
|
||||
waited_minutes: number
|
||||
oldest_at: string | null
|
||||
last_confirmed_at: string | null
|
||||
threshold_minutes: number
|
||||
rows: StuckOutboundRow[]
|
||||
}
|
||||
|
||||
/** اسناد پنل که پرگار هنوز تحویل نگرفته — ماندهٔ این مشتریها اعمال نمیشود */
|
||||
export const getStuckOutbound = async (minutes?: number) =>
|
||||
await useAxios.get<StuckOutboundSummary>('/admin/pargar/stuck-outbound', {
|
||||
params: minutes === undefined ? undefined : { minutes },
|
||||
})
|
||||
|
||||
export interface PanelOnlyCustomer {
|
||||
id: number
|
||||
name: string
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div class="dashboard-v2 box-border min-h-full w-full max-w-full overflow-x-hidden p-2 md:p-3">
|
||||
<a-spin :spinning="loading">
|
||||
<PargarStuckOutboundAlert v-if="pargarEnabled" compact class="mb-2" />
|
||||
|
||||
<!-- Hero -->
|
||||
<section
|
||||
class="dashboard-hero rounded-xl bg-gradient-to-l from-[#0f766e] via-[#1e3a5f] to-[#0f172a] px-3 py-2.5 text-white shadow-md"
|
||||
@@ -451,8 +453,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import DashboardLabelWithHelp from '@/pages/dashboard/components/DashboardLabelWithHelp.vue'
|
||||
import PargarStuckOutboundAlert from '@/pages/menuPages/accounting/components/PargarStuckOutboundAlert.vue'
|
||||
import DashboardQuickActionsBar from '@/pages/dashboard/components/DashboardQuickActionsBar.vue'
|
||||
import DashboardQuickWalletModal from '@/pages/dashboard/components/DashboardQuickWalletModal.vue'
|
||||
import DashboardSectionHeader from '@/pages/dashboard/components/DashboardSectionHeader.vue'
|
||||
@@ -478,6 +481,13 @@ import { metalBalanceTitle, metalLabel } from '@/utils/adminMetalLabels'
|
||||
import { formatOrderServiceFee } from '@/utils/orderServiceFee'
|
||||
import { getMainMetal } from '@/utils/metalLabels'
|
||||
import { TRADE_WEIGHT_UNIT_GRAM, TRADE_WEIGHT_UNIT_KILOGRAM } from '@/utils/weightUnit'
|
||||
import { initAccountingSettingsFromApi, pargarEnabledSetting } from '@/utils/config'
|
||||
|
||||
const pargarEnabled = pargarEnabledSetting
|
||||
|
||||
onMounted(() => {
|
||||
void initAccountingSettingsFromApi()
|
||||
})
|
||||
|
||||
const copy = {
|
||||
hero: dashboardHero,
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<a-alert v-if="summary && summary.count > 0" type="warning" show-icon>
|
||||
<template #message>
|
||||
<div class="flex flex-wrap items-center gap-x-2 gap-y-1">
|
||||
<span class="font-bold">{{ summary.count }} سند پنل هنوز در پرگار ثبت نشده</span>
|
||||
<span v-if="summary.customers" class="text-xs text-gray-600">
|
||||
ماندهٔ {{ summary.customers }} مشتری تا ثبت این اسناد روی کیف اعمال نمیشود
|
||||
</span>
|
||||
<a-button type="link" size="small" :loading="loading" @click="load">بروزرسانی</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="flex flex-col gap-2 text-xs">
|
||||
<div class="text-gray-600">
|
||||
قدیمیترین سند {{ waitLabel(summary.waited_minutes) }} در صف است.
|
||||
<template v-if="lastConfirmedLabel">
|
||||
آخرین سندی که پرگار تحویل گرفته: {{ lastConfirmedLabel }}
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template v-if="!compact">
|
||||
<div class="flex flex-col gap-1">
|
||||
<div v-for="row in visibleRows" :key="row.id" class="stuck-row">
|
||||
<span class="font-bold">{{ pargarTypeLabel(row.type) }} {{ row.export_id }}</span>
|
||||
<span>{{ row.customer_name || 'بدون مشتری' }}</span>
|
||||
<span dir="ltr">{{ amountLabel(row) }}</span>
|
||||
<span class="text-gray-500">{{ waitLabel(row.waited_minutes) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a-button
|
||||
v-if="summary.rows.length > PREVIEW_COUNT"
|
||||
type="link"
|
||||
size="small"
|
||||
class="self-start"
|
||||
@click="expanded = !expanded"
|
||||
>
|
||||
{{ expanded ? 'بستن لیست' : `${summary.rows.length - PREVIEW_COUNT} سند دیگر` }}
|
||||
</a-button>
|
||||
</template>
|
||||
|
||||
<div class="text-gray-500">
|
||||
پرگار این اسناد را با «دریافت اسناد» میگیرد؛ تا آن زمان ماندهٔ این مشتریها عمداً اعمال نمیشود.
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-alert>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { getStuckOutbound, type StuckOutboundRow, type StuckOutboundSummary } from '@/api/pargar'
|
||||
import { pargarTypeLabel } from '../utils/pargarDisplay'
|
||||
import { usePrice } from '@core/utils/usePrice'
|
||||
import { toJalali } from '@core/utils/useDataTime'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
/** فقط خلاصه بدون لیست اسناد — برای داشبورد */
|
||||
compact?: boolean
|
||||
pollMs?: number
|
||||
/** سندی که کمتر از این مدت در صف است هنوز «گیرکرده» نیست */
|
||||
thresholdMinutes?: number
|
||||
}>(),
|
||||
{ compact: false, pollMs: 60000, thresholdMinutes: 15 }
|
||||
)
|
||||
|
||||
const PREVIEW_COUNT = 5
|
||||
|
||||
const summary = ref<StuckOutboundSummary>()
|
||||
const loading = ref(false)
|
||||
const expanded = ref(false)
|
||||
let timer: ReturnType<typeof setInterval> | undefined
|
||||
|
||||
const visibleRows = computed(() => {
|
||||
const rows = summary.value?.rows ?? []
|
||||
return expanded.value ? rows : rows.slice(0, PREVIEW_COUNT)
|
||||
})
|
||||
|
||||
const lastConfirmedLabel = computed(() =>
|
||||
summary.value?.last_confirmed_at ? toJalali(summary.value.last_confirmed_at) : ''
|
||||
)
|
||||
|
||||
function waitLabel(minutes: number): string {
|
||||
if (minutes < 60) return `${minutes} دقیقه`
|
||||
const hours = Math.floor(minutes / 60)
|
||||
if (hours < 24) return `${hours} ساعت`
|
||||
return `${Math.floor(hours / 24)} روز`
|
||||
}
|
||||
|
||||
function amountLabel(row: StuckOutboundRow): string {
|
||||
if (row.amount == null) return '—'
|
||||
if (row.type === 'wallet_cash') return usePrice(Math.abs(row.amount))
|
||||
return `${Math.abs(row.amount).toFixed(4)} گرم`
|
||||
}
|
||||
|
||||
async function load() {
|
||||
try {
|
||||
loading.value = true
|
||||
summary.value = await getStuckOutbound(props.thresholdMinutes)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void load()
|
||||
if (props.pollMs > 0) {
|
||||
timer = setInterval(() => void load(), props.pollMs)
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer) clearInterval(timer)
|
||||
})
|
||||
|
||||
defineExpose({ load })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.stuck-row {
|
||||
@apply flex flex-wrap items-center gap-x-3 gap-y-1 rounded-lg bg-white/60 px-2 py-1;
|
||||
}
|
||||
</style>
|
||||
@@ -5,6 +5,7 @@
|
||||
class="flex h-full w-full min-w-0 max-w-full flex-col overflow-x-hidden"
|
||||
:class="activeTab === 'customer-sync' || activeTab === 'pargar-customer-sync' || activeTab === 'zarin-customer-sync' ? 'overflow-y-auto' : 'overflow-hidden'"
|
||||
>
|
||||
<PargarStuckOutboundAlert v-if="pargarEnabled" class="mb-3 shrink-0" />
|
||||
<ATabs v-model:activeKey="activeTab" class="mb-3 shrink-0">
|
||||
<ATabPane key="reports" tab="گزارشات" />
|
||||
<ATabPane v-if="tahesabEnabled" key="tahesab" tab="اسناد تهحساب" />
|
||||
@@ -155,6 +156,7 @@ import zarinTbl from './components/zarinTable.vue'
|
||||
import zarinCustomerSync from './components/ZarinCustomerSync.vue'
|
||||
import pargarTbl from './components/pargarTable.vue'
|
||||
import pargarCustomerSync from './components/PargarCustomerSync.vue'
|
||||
import PargarStuckOutboundAlert from './components/PargarStuckOutboundAlert.vue'
|
||||
import type { FormInstance } from 'ant-design-vue'
|
||||
import BasicInfoModal from '@/components/BasicInfoModal/index.vue'
|
||||
import { message } from 'ant-design-vue/es'
|
||||
|
||||
Reference in New Issue
Block a user