Files
boursecu_admin/src/pages/menuPages/customers/base/components/table.vue
T
2026-07-22 00:10:29 +03:30

395 lines
14 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="h-full min-h-0 min-w-0 max-w-full overflow-hidden">
<BasicShowContext title="لیست مشتریان">
<template #extra>
<BaseButton
v-if="isMobile"
type="primary"
size="small"
icon="vuesax-linear:user-add"
@click="emits('add')"
>
افزودن
</BaseButton>
</template>
<div class="flex h-full min-h-0 flex-col">
<BaseTable v-if="!isMobile" class="h-full min-h-0 min-w-0" v-bind="tblProps" @register="submit" ref="tbl">
<template #extraHeader>
<BaseButton type="primary" size="small" icon="vuesax-linear:user-add" @click="emits('add')">
افزودن مشتری
</BaseButton>
</template>
<template #accountingCode="{ record }">
<button
type="button"
class="inline-flex items-center gap-1.5 border-none bg-transparent p-0 text-sm cursor-pointer"
style="color: var(--admin-text)"
@click="openAccountingCodeEdit(record)"
>
<span dir="ltr">{{ accountingCodeOf(record) }}</span>
<Icon icon="vuesax-linear:edit-2" size="16" color="#4572E9" />
</button>
</template>
<template #action="{ record }">
<div class="gap-2 hidden md:flex justify-center">
<a-tooltip :key="record.is_archive" placement="bottom" class="cursor-pointer">
<template #title>
<span>{{ record.is_archive ? 'بیرون بردن از بایگانی' : 'بایگانی کردن' }}</span>
</template>
<a-popconfirm
title="آیا مشتری را بایگانی می کنید؟"
ok-text="تایید"
cancel-text="رد"
placement="topLeft"
@confirm="archiveFunction(record.id)"
>
<Icon class="cursor-pointer" icon="vuesax-linear:archive-tick" color="#e3bf00" />
</a-popconfirm>
</a-tooltip>
<a-tooltip
:key="record.active"
placement="bottom"
class="cursor-pointer"
@click="changeCustomerActivationFunction(record.id)"
>
<template #title>
<span>{{ record.active ? 'غیرفعال کردن حساب کاربری' : 'فعال کردن حساب کاربری' }}</span>
</template>
<Icon
:icon="record.active ? 'vuesax-linear:user-tick' : 'vuesax-linear:user-remove'"
:color="record.active ? '#54AD06' : '#ad0627'"
/>
</a-tooltip>
<a-tooltip placement="bottom" class="cursor-pointer" @click="emits('chargeWallet', record)">
<template #title><span>شارژ کیف پول</span></template>
<Icon icon="vuesax-linear:wallet-add" color="#9333ea" />
</a-tooltip>
<a-tooltip
v-if="tahesabEnabled && !isValidAccountingCode(record.moshtari_code)"
placement="bottom"
class="cursor-pointer"
@click="openTahesabRegister(record)"
>
<template #title><span>در ته‌حساب ثبت نشده — کلیک برای ثبت</span></template>
<Icon icon="vuesax-linear:profile-add" color="#CA8A04" />
</a-tooltip>
<a-tooltip
v-if="pargarEnabled && !isValidAccountingCode(record.pargar_account_id)"
placement="bottom"
class="cursor-pointer"
@click="openPargarRegister(record)"
>
<template #title><span>در پرگار ثبت نشده — کلیک برای ثبت</span></template>
<Icon icon="vuesax-linear:profile-add" color="#7C3AED" />
</a-tooltip>
<a-tooltip
v-if="accountingEnabled"
placement="bottom"
class="cursor-pointer"
@click="openAccountingCodeEdit(record)"
>
<template #title><span>ویرایش کد حسابداری</span></template>
<Icon icon="vuesax-linear:card-edit" color="#0d9488" />
</a-tooltip>
<a-tooltip placement="bottom" class="cursor-pointer" @click="emits('info', record)">
<template #title><span>مشخصات</span></template>
<Icon icon="vuesax-linear:stickynote" color="#10913A" />
</a-tooltip>
<a-tooltip placement="bottom" class="cursor-pointer" @click="emits('edit', record)">
<template #title><span>ویرایش</span></template>
<Icon icon="vuesax-linear:edit" color="#4572E9" />
</a-tooltip>
<a-tooltip
:key="record.trade_active"
placement="bottom"
class="cursor-pointer"
@click="changeCustomerOrderActivationFunction(record.id)"
>
<template #title>
<span>{{ record.trade_active ? 'غیر مجاز کردن سفارش دهی' : 'مجاز کردن سفارش دهی' }}</span>
</template>
<Icon
:icon="record.trade_active === 1 ? 'vuesax-linear:box-tick' : 'vuesax-linear:box-remove'"
:color="record.trade_active === 1 ? '#54AD06' : '#ad0627'"
/>
</a-tooltip>
<a-tooltip
v-if="customerDirectSmsEnabled"
placement="bottom"
class="cursor-pointer"
@click="openDirectSms(record)"
>
<template #title><span>ارسال پیامک</span></template>
<Icon icon="vuesax-linear:sms" color="#0ea5e9" />
</a-tooltip>
<a-tooltip
v-if="!record.is_legal"
placement="bottom"
class="cursor-pointer"
@click="openConfirmUser(record)"
>
<template #title><span>تایید کاربر</span></template>
<Icon icon="vuesax-linear:user-search" color="#0d9488" />
</a-tooltip>
</div>
</template>
</BaseTable>
<CustomerMobileCardList
v-else
ref="mobileListRef"
class="min-h-0 flex-1"
@info="emits('info', $event)"
@edit="emits('edit', $event)"
@archive="handleArchive"
@toggleActive="(item) => changeCustomerActivationFunction(item.id)"
@chargeWallet="emits('chargeWallet', $event)"
@toggleTrade="(item) => changeCustomerOrderActivationFunction(item.id)"
@confirmUser="openConfirmUser"
@sendSms="openDirectSms"
@editAccounting="openAccountingCodeEdit"
/>
</div>
<CustomerDirectSmsModal v-model:visible="directSmsVisible" :customer="directSmsCustomer" />
<CustomerAccountingCodeModal
v-model:visible="accountingCodeVisible"
:customer="accountingCodeCustomer"
:provider="accountingProviderSetting"
@success="fetch"
/>
<BasicModal
v-model:visible="confirmVisible"
:width="isMobile ? '92vw' : '50vw'"
title="تایید مشتری"
@ok="confirmUserFunction"
ok-text="تایید"
:loading="loading"
@close="confirmVisible = false"
>
<div class="mt-[-10px] mb-10 font-bold">آیا از اطلاعات وارد شده اطمینان دارید؟</div>
<div class="grid grid-cols-4 gap-2">
<BasicInfoItem title="نام و نام خانوادگی" :value="confirmInfo?.name" />
<BasicInfoItem title="شماره همراه" :value="confirmInfo?.mobile" />
<BasicInfoItem
title="تاریخ تولد"
:value="confirmInfo?.birth_date ? toJalaliNoTime(confirmInfo?.birth_date) : '_'"
/>
<BasicInfoItem title="شماره تلفن" :value="confirmInfo?.phone_number ?? '_'" />
<BasicInfoItem title="نام استان" :value="confirmInfo?.province" />
<BasicInfoItem title="نام شهر" :value="confirmInfo?.city" />
<BasicInfoItem title="شماره ملی" :value="confirmInfo?.n_code" />
</div>
</BasicModal>
<TahesabRetryModal
v-if="tahesabEnabled"
v-model="tahesabRegisterVisible"
mode="register-customer"
:customer-id="tahesabCustomer?.id"
:customer-name="tahesabCustomer?.name"
@success="fetch"
/>
<PargarRetryModal
v-if="pargarEnabled"
v-model="pargarRegisterVisible"
mode="register-customer"
:customer-id="pargarCustomer?.id"
:customer-name="pargarCustomer?.name"
@success="fetch"
/>
</BasicShowContext>
</div>
</template>
<script setup lang="ts">
import { message, Modal } from 'ant-design-vue'
import { onMounted, ref, computed } from 'vue'
import {
changeCustomerActivation,
changeCustomerArchive,
changeCustomerOrderActivation,
confirmUser,
getCustomerTable
} from '@/api/customer'
import { buildCustomerColumns } from '@/pages/menuPages/customers/base/hooks/customerColumns'
import CustomerMobileCardList from '@/pages/menuPages/customers/base/components/CustomerMobileCardList.vue'
import CustomerDirectSmsModal from '@/pages/menuPages/customers/base/components/CustomerDirectSmsModal.vue'
import CustomerAccountingCodeModal from '@/pages/menuPages/customers/base/components/CustomerAccountingCodeModal.vue'
import Icon from '@core/components/BaseIcon/src/Icon.vue'
import useBaseTable from '@core/components/BaseTable/hooks/useBaseTable'
import type { TableInput } from '@core/type/baseTable'
import { toJalaliNoTime } from '@core/utils/useDataTime'
import type { Customer } from '@/model/customer'
import { MODAL_ABOVE_ACTION_SHEET_Z_INDEX } from '@/constants/overlayZIndex'
import { isMobile } from '@core/utils/is'
import TahesabRetryModal from '@/components/TahesabRetryModal.vue'
import PargarRetryModal from '@/components/PargarRetryModal.vue'
import {
tahesabEnabledSetting,
pargarEnabledSetting,
accountingProviderSetting,
customerDirectSmsEnabledSetting,
initAccountingSettingsFromApi,
initWalletSettingsFromApi
} from '@/utils/config'
import { displayAccountingCode, isValidAccountingCode } from '@/utils/accountingCode'
const [submit, reload] = useBaseTable()
const emits = defineEmits(['delete', 'edit', 'add', 'info', 'chargeWallet'])
const loading = ref(false)
const confirmVisible = ref(false)
const confirmInfo = ref<Customer>()
const tahesabRegisterVisible = ref(false)
const tahesabCustomer = ref<Customer>()
const tahesabEnabled = tahesabEnabledSetting
const pargarRegisterVisible = ref(false)
const pargarCustomer = ref<Customer>()
const pargarEnabled = pargarEnabledSetting
const customerDirectSmsEnabled = customerDirectSmsEnabledSetting
const accountingCodeVisible = ref(false)
const accountingCodeCustomer = ref<Customer | null>(null)
const accountingEnabled = computed(() => {
const provider = accountingProviderSetting.value
return provider === 'pargar' || provider === 'tahesab'
})
function accountingCodeOf(record: Customer) {
const provider = accountingProviderSetting.value
if (provider === 'pargar') return displayAccountingCode(record.pargar_account_id)
if (provider === 'tahesab') return displayAccountingCode(record.moshtari_code)
return '-'
}
function openAccountingCodeEdit(user: Customer) {
accountingCodeCustomer.value = user
accountingCodeVisible.value = true
}
const directSmsVisible = ref(false)
const directSmsCustomer = ref<Customer | null>(null)
const mobileListRef = ref<null | { fetch: () => Promise<void> }>(null)
const catalogMetals = ref<Parameters<typeof buildCustomerColumns>[0]>([])
function rebuildColumns(metals = catalogMetals.value) {
catalogMetals.value = metals
tblProps.value.columns = buildCustomerColumns(metals, {
accountingProvider: accountingProviderSetting.value
})
}
const tblProps = ref<any>({
columns: buildCustomerColumns([], { accountingProvider: accountingProviderSetting.value }),
api: async (params: TableInput) => {
await initAccountingSettingsFromApi()
const data = await getCustomerTable(params)
const metals = data?.catalogMetals ?? []
rebuildColumns(metals)
return data
}
})
const fetch = async () => {
await Promise.allSettled([reload(), mobileListRef.value?.fetch?.() as Promise<void>])
}
defineExpose({ fetch })
onMounted(() => {
void initAccountingSettingsFromApi()
void initWalletSettingsFromApi()
})
function openDirectSms(user: Customer) {
directSmsCustomer.value = user
directSmsVisible.value = true
}
async function changeCustomerActivationFunction(id: number) {
try {
loading.value = true
await changeCustomerActivation(id)
await fetch()
message.success('تغییر وضعیت با موفقیت انجام شد')
} catch (e) {
console.error(e)
} finally {
loading.value = false
}
}
function openConfirmUser(user: Customer) {
confirmInfo.value = user
confirmVisible.value = true
}
function openTahesabRegister(user: Customer) {
tahesabCustomer.value = user
tahesabRegisterVisible.value = true
}
function openPargarRegister(user: Customer) {
pargarCustomer.value = user
pargarRegisterVisible.value = true
}
function handleArchive(customer: Customer) {
Modal.confirm({
title: 'آیا مشتری را بایگانی می کنید؟',
okText: 'تایید',
cancelText: 'رد',
centered: true,
zIndex: MODAL_ABOVE_ACTION_SHEET_Z_INDEX,
onOk: () => archiveFunction(customer.id)
})
}
async function archiveFunction(id: number) {
try {
loading.value = true
await changeCustomerArchive(id)
await fetch()
message.success('مشتری با موفقیت بایگانی شد.')
} catch (e) {
console.error(e)
} finally {
loading.value = false
}
}
async function confirmUserFunction() {
try {
loading.value = true
await confirmUser(confirmInfo.value?.id)
await fetch()
confirmVisible.value = false
} catch (e) {
console.log(e)
} finally {
loading.value = false
}
}
async function changeCustomerOrderActivationFunction(id: number) {
try {
loading.value = true
await changeCustomerOrderActivation(id)
await fetch()
message.success('تغییر وضعیت سفارش دهی با موفقیت انجام شد')
} catch (e) {
console.error(e)
} finally {
loading.value = false
}
}
</script>
<style lang="less">
.ant-popover,
.ant-tooltip {
z-index: 1001 !important;
}
</style>