hesabixCore/webUI/src/views/acc/inquiry/panel.vue

1159 lines
42 KiB
Vue
Raw Normal View History

2025-07-16 18:41:53 +03:30
<template>
2025-07-17 12:37:31 +03:30
<v-toolbar color="toolbar" :title="$t('drawer.inquiry')">
<template v-slot:prepend>
<v-tooltip :text="$t('dialog.back')" location="bottom">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" @click="$router.back()" class="d-none d-sm-flex" variant="text"
icon="mdi-arrow-right" />
</template>
</v-tooltip>
</template>
</v-toolbar>
<v-container class="pa-0">
<v-card :loading="loading" :disabled="loading">
<v-card-text class="pa-8">
<!-- نمایش اعتبار کاربر -->
<v-card variant="elevated" class="mb-8 credit-card" :class="`credit-card-${getCreditCardColor()}`"
elevation="4">
<div class="credit-card-background">
<div class="credit-card-pattern"></div>
</div>
<v-card-text class="pa-8 position-relative">
<div class="d-flex flex-column flex-md-row align-start align-md-center justify-space-between mb-6">
<div class="d-flex align-center mb-4 mb-md-0">
<div class="credit-icon-wrapper me-3">
<v-icon size="40" color="white">mdi-wallet</v-icon>
</div>
<div>
<h4 class="text-h5 font-weight-bold text-white mb-1">اعتبار فعلی</h4>
<p class="text-body-2 text-white-lighten-1 mb-0 d-none d-sm-block">موجودی حساب شما برای استفاده از
سرویسهای استعلام</p>
<p class="text-caption text-white-lighten-1 mb-0 d-block d-sm-none">موجودی حساب</p>
</div>
</div>
<div class="text-center text-md-right">
<v-btn color="white" variant="outlined" prepend-icon="mdi-plus" @click="$router.push('/acc/sms/panel')"
class="add-credit-btn" size="large">
<span class="d-none d-sm-inline">افزایش اعتبار</span>
<span class="d-inline d-sm-none">افزایش</span>
</v-btn>
</div>
</div>
<div class="credit-amount-section">
<div class="credit-amount-display">
<div class="amount-label d-none d-sm-block">موجودی</div>
<div class="amount-label d-block d-sm-none">موجودی حساب</div>
<div class="amount-value">
<span class="amount-number">{{ formatCurrency(businessInfo.smsCharge || 0) }}</span>
<span class="currency-symbol">ریال</span>
</div>
</div>
<div class="credit-status-indicator">
<v-chip :color="getCreditStatusColor()" size="small" variant="flat" class="status-chip">
<v-icon start size="16">{{ getCreditStatusIcon() }}</v-icon>
<span class="d-none d-sm-inline">{{ getCreditStatusText() }}</span>
<span class="d-inline d-sm-none">{{ getCreditStatusTextShort() }}</span>
</v-chip>
</div>
</div>
<!-- هشدار اعتبار کم -->
<v-alert v-if="hasLowCredit" type="warning" variant="tonal" class="mt-6 credit-alert" border="start">
<template v-slot:prepend>
<v-icon>mdi-alert-circle</v-icon>
</template>
<div>
<strong>اعتبار کم:</strong> اعتبار شما برای استفاده از سرویسهای استعلام کافی نیست.
لطفاً اعتبار خود را افزایش دهید.
</div>
</v-alert>
</v-card-text>
</v-card>
<!-- نمایش سرویسهای فعال -->
<v-row>
<!-- تبدیل کد پستی به آدرس -->
<v-col cols="12" sm="12" md="6" lg="4" v-if="inquirySettings.enablePostalCodeToAddress">
<v-card variant="outlined" class="service-card h-100" elevation="0" @click="openPostalCodeDialog">
<div class="service-card-header bg-success-lighten-5 pa-4">
<div class="d-flex align-center justify-space-between mb-3">
<div class="d-flex align-center">
<v-icon size="32" color="success" class="mr-3">mdi-map-marker</v-icon>
<div>
<h5 class="text-subtitle-1 font-weight-medium text-success mb-1">تبدیل کد پستی به آدرس</h5>
<p class="text-caption text-medium-emphasis mb-0">تبدیل خودکار کد پستی به آدرس کامل</p>
</div>
</div>
<v-chip color="success" size="small" variant="flat">
فعال
</v-chip>
</div>
</div>
<v-card-text class="pa-4">
<div class="d-flex align-center justify-space-between">
<div>
<p class="text-body-2 text-medium-emphasis mb-1">کارمزد هر استعلام:</p>
<p class="text-h6 font-weight-medium text-success">{{ inquirySettings.postalCodeToAddressFee }} ریال
</p>
</div>
<v-btn color="success" variant="outlined" prepend-icon="mdi-magnify"
@click.stop="openPostalCodeDialog">
استعلام
</v-btn>
</div>
</v-card-text>
</v-card>
</v-col>
<!-- تبدیل شماره کارت به شبا -->
<v-col cols="12" sm="12" md="6" lg="4" v-if="inquirySettings.enableCardToSheba">
<v-card variant="outlined" class="service-card h-100" elevation="0" @click="openCardToShebaDialog">
<div class="service-card-header bg-info-lighten-5 pa-4">
<div class="d-flex align-center justify-space-between mb-3">
<div class="d-flex align-center">
<v-icon size="32" color="info" class="mr-3">mdi-credit-card</v-icon>
<div>
<h5 class="text-subtitle-1 font-weight-medium text-info mb-1">تبدیل شماره کارت به شبا</h5>
<p class="text-caption text-medium-emphasis mb-0">تبدیل شماره کارت بانکی به شماره شبا</p>
</div>
</div>
<v-chip color="info" size="small" variant="flat">
فعال
</v-chip>
</div>
</div>
<v-card-text class="pa-4">
<div class="d-flex align-center justify-space-between">
<div>
<p class="text-body-2 text-medium-emphasis mb-1">کارمزد هر استعلام:</p>
<p class="text-h6 font-weight-medium text-info">{{ inquirySettings.cardToShebaFee }} ریال</p>
</div>
<v-btn color="info" variant="outlined" prepend-icon="mdi-magnify" @click.stop="openCardToShebaDialog">
استعلام
</v-btn>
</div>
</v-card-text>
</v-card>
</v-col>
<!-- تبدیل حساب به شبا -->
<v-col cols="12" sm="12" md="6" lg="4" v-if="inquirySettings.enableAccountToSheba">
<v-card variant="outlined" class="service-card h-100" elevation="0" @click="openAccountToShebaDialog">
<div class="service-card-header bg-warning-lighten-5 pa-4">
<div class="d-flex align-center justify-space-between mb-3">
<div class="d-flex align-center">
<v-icon size="32" color="warning" class="mr-3">mdi-bank</v-icon>
<div>
<h5 class="text-subtitle-1 font-weight-medium text-warning mb-1">تبدیل حساب به شبا</h5>
<p class="text-caption text-medium-emphasis mb-0">تبدیل شماره حساب بانکی به شماره شبا</p>
</div>
</div>
<v-chip color="warning" size="small" variant="flat">
فعال
</v-chip>
</div>
</div>
<v-card-text class="pa-4">
<div class="d-flex align-center justify-space-between">
<div>
<p class="text-body-2 text-medium-emphasis mb-1">کارمزد هر استعلام:</p>
<p class="text-h6 font-weight-medium text-warning">{{ inquirySettings.accountToShebaFee }} ریال</p>
</div>
<v-btn color="warning" variant="outlined" prepend-icon="mdi-magnify"
@click.stop="openAccountToShebaDialog">
استعلام
</v-btn>
</div>
</v-card-text>
</v-card>
</v-col>
</v-row>
<!-- پیام عدم وجود سرویس فعال -->
<v-row v-if="!hasActiveServices">
<v-col cols="12">
<v-card variant="outlined" class="pa-8 text-center">
<v-icon size="64" color="grey-lighten-1" class="mb-4">mdi-information-outline</v-icon>
<h3 class="text-h5 font-weight-medium text-grey-darken-1 mb-2">هیچ سرویس استعلامی فعال نیست</h3>
<p class="text-body-1 text-medium-emphasis">در حال حاضر هیچ سرویس استعلامی در سیستم فعال نشده است. لطفاً
با
مدیر سیستم تماس بگیرید.</p>
</v-card>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-container>
<!-- دیالوگ تبدیل کد پستی به آدرس -->
<v-dialog v-model="postalCodeDialog" max-width="500px" persistent>
<v-card>
<v-card-title class="text-h6 font-weight-medium d-flex align-center">
<v-icon start color="success" class="mr-2">mdi-map-marker</v-icon>
تبدیل کد پستی به آدرس
</v-card-title>
<v-card-text class="pt-4">
<div class="mb-4">
<p class="text-body-2 text-medium-emphasis">
با استفاده از این سرویس میتوانید کد پستی را به آدرس کامل تبدیل کنید.
</p>
</div>
<v-form ref="postalCodeForm" v-model="postalCodeFormValid">
<v-text-field v-model="postalCodeData.postalCode" label="کد پستی" placeholder="مثال: 1234567890"
prepend-inner-icon="mdi-map-marker" variant="outlined" density="comfortable" :rules="[
v => !!v || 'کد پستی الزامی است',
v => v.length === 10 || 'کد پستی باید 10 رقم باشد',
v => /^\d+$/.test(v) || 'کد پستی باید فقط شامل اعداد باشد'
]" maxlength="10" counter></v-text-field>
<v-alert type="info" variant="tonal" class="mt-4">
<template v-slot:prepend>
<v-icon>mdi-information</v-icon>
</template>
<div>
<strong>کارمزد سرویس:</strong> {{ inquirySettings.postalCodeToAddressFee.toLocaleString() }} ریال
<br>
<small class="text-caption">
💡 اگر این کد پستی قبلاً استعلام شده باشد، کارمزدی کسر نمیشود
</small>
</div>
</v-alert>
<!-- نمایش خطا -->
<v-alert v-if="postalCodeError" type="error" variant="tonal" class="mt-4" border="start">
{{ postalCodeError }}
</v-alert>
<!-- نمایش نتیجه -->
<v-alert v-if="inquiryResults.postalCode" type="success" variant="tonal" class="mt-4" border="start">
<template v-slot:prepend>
<v-icon>mdi-check-circle</v-icon>
</template>
<div>
<p class="font-weight-medium mb-1">آدرس یافت شده:</p>
<p class="text-body-2">{{ formatAddress(inquiryResults.postalCode.address) }}</p>
<p class="text-caption text-medium-emphasis mt-1">
{{ inquiryResults.postalCode.fromCache ? 'از حافظه موقت' : 'از سرور اصلی' }}
</p>
</div>
</v-alert>
</v-form>
</v-card-text>
<v-card-actions class="pa-6 pt-0">
<v-spacer></v-spacer>
<v-btn variant="outlined" @click="postalCodeDialog = false" :disabled="postalCodeLoading">
انصراف
</v-btn>
<v-btn color="success" @click="submitPostalCodeInquiry" :loading="postalCodeLoading"
:disabled="!postalCodeFormValid">
استعلام
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- دیالوگ تبدیل شماره کارت به شبا -->
<v-dialog v-model="cardToShebaDialog" max-width="500px" persistent>
<v-card>
<v-card-title class="text-h6 font-weight-medium d-flex align-center">
<v-icon start color="info" class="mr-2">mdi-credit-card</v-icon>
تبدیل شماره کارت به شبا
</v-card-title>
<v-card-text class="pt-4">
<v-form ref="cardToShebaForm" v-model="cardToShebaFormValid">
<v-text-field v-model="cardToShebaData.cardNumber" label="شماره کارت" placeholder="مثال: 6037991234567890"
prepend-inner-icon="mdi-credit-card" variant="outlined" density="comfortable" :rules="[
v => !!v || 'شماره کارت الزامی است',
v => v.length === 16 || 'شماره کارت باید 16 رقم باشد',
v => /^\d+$/.test(v) || 'شماره کارت باید فقط شامل اعداد باشد'
]" maxlength="16" counter></v-text-field>
<v-alert type="info" variant="tonal" class="mt-4">
<template v-slot:prepend>
<v-icon>mdi-information</v-icon>
</template>
<div>
<strong>کارمزد سرویس:</strong> {{ inquirySettings.cardToShebaFee.toLocaleString() }} ریال
<br>
<small class="text-caption">
💡 اگر این شماره کارت قبلاً استعلام شده باشد، کارمزدی کسر نمیشود
</small>
</div>
</v-alert>
<!-- نمایش خطا -->
<v-alert v-if="cardToShebaError" type="error" variant="tonal" class="mt-4" border="start">
{{ cardToShebaError }}
</v-alert>
<!-- نمایش نتیجه -->
<v-alert v-if="inquiryResults.cardToSheba" type="success" variant="tonal" class="mt-4" border="start">
<template v-slot:prepend>
<v-icon>mdi-check-circle</v-icon>
</template>
<div>
<p class="font-weight-medium mb-2">اطلاعات کارت:</p>
<div class="mb-2">
<strong>شماره شبا:</strong>
<span class="font-family-monospace">{{ inquiryResults.cardToSheba.IBAN }}</span>
</div>
<div class="mb-2">
<strong>نام صاحب کارت:</strong>
<span>{{ inquiryResults.cardToSheba.name }}</span>
</div>
<div class="mb-2">
<strong>نام بانک:</strong>
<span>{{ inquiryResults.cardToSheba.bank_name }}</span>
</div>
<p class="text-caption text-medium-emphasis mt-2">
{{ inquiryResults.cardToSheba.fromCache ? 'از حافظه موقت' : 'از سرور اصلی' }}
</p>
</div>
</v-alert>
</v-form>
</v-card-text>
<v-card-actions class="pa-6 pt-0">
<v-spacer></v-spacer>
<v-btn variant="outlined" @click="cardToShebaDialog = false" :disabled="cardToShebaLoading">
انصراف
</v-btn>
<v-btn color="info" @click="submitCardToShebaInquiry" :loading="cardToShebaLoading"
:disabled="!cardToShebaFormValid">
استعلام
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- دیالوگ تبدیل حساب به شبا -->
<v-dialog v-model="accountToShebaDialog" max-width="500px" persistent>
<v-card>
<v-card-title class="text-h6 font-weight-medium d-flex align-center">
<v-icon start color="warning" class="mr-2">mdi-bank</v-icon>
تبدیل حساب به شبا
</v-card-title>
<v-card-text class="pt-4">
<v-form ref="accountToShebaForm" v-model="accountToShebaFormValid">
<v-select v-model="accountToShebaData.bankCode" label="کد بانک" placeholder="انتخاب کنید"
prepend-inner-icon="mdi-bank" variant="outlined" density="comfortable" :items="bankCodes" item-title="name"
item-value="code" :rules="[
v => !!v || 'کد بانک الزامی است'
]"></v-select>
<v-text-field v-model="accountToShebaData.accountNumber" label="شماره حساب"
placeholder="مثال: 4600000123456789" prepend-inner-icon="mdi-account" variant="outlined"
density="comfortable" class="mt-4" :rules="[
v => !!v || 'شماره حساب الزامی است',
v => v.length >= 10 || 'شماره حساب باید حداقل 10 رقم باشد',
v => /^\d+$/.test(v) || 'شماره حساب باید فقط شامل اعداد باشد'
]" maxlength="20" counter></v-text-field>
<v-alert type="info" variant="tonal" class="mt-4">
<template v-slot:prepend>
<v-icon>mdi-information</v-icon>
</template>
<div>
<strong>کارمزد سرویس:</strong> {{ inquirySettings.accountToShebaFee.toLocaleString() }} ریال
<br>
<small class="text-caption">
💡 اگر این حساب قبلاً استعلام شده باشد، کارمزدی کسر نمیشود
</small>
</div>
</v-alert>
<!-- نمایش خطا -->
<v-alert v-if="accountToShebaError" type="error" variant="tonal" class="mt-4" border="start">
{{ accountToShebaError }}
</v-alert>
<!-- نمایش نتیجه -->
<v-alert v-if="inquiryResults.accountToSheba" type="success" variant="tonal" class="mt-4" border="start">
<template v-slot:prepend>
<v-icon>mdi-check-circle</v-icon>
</template>
<div>
<p class="font-weight-medium mb-2">اطلاعات حساب:</p>
<div class="mb-2">
<strong>شماره شبا:</strong>
<span class="font-family-monospace">{{ inquiryResults.accountToSheba.IBAN }}</span>
</div>
<p class="text-caption text-medium-emphasis mt-2">
{{ inquiryResults.accountToSheba.fromCache ? 'از حافظه موقت' : 'از سرور اصلی' }}
</p>
</div>
</v-alert>
</v-form>
</v-card-text>
<v-card-actions class="pa-6 pt-0">
<v-spacer></v-spacer>
<v-btn variant="outlined" @click="accountToShebaDialog = false" :disabled="accountToShebaLoading">
انصراف
</v-btn>
<v-btn color="warning" @click="submitAccountToShebaInquiry" :loading="accountToShebaLoading"
:disabled="!accountToShebaFormValid">
استعلام
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- Snackbar برای نمایش پیامها -->
2025-07-17 12:43:17 +03:30
<v-snackbar v-model="snackbar.show" :color="snackbar.color" :timeout="snackbar.timeout" location="bottom">
2025-07-17 12:37:31 +03:30
{{ snackbar.text }}
<template v-slot:actions>
<v-btn color="white" variant="text" @click="snackbar.show = false">
بستن
</v-btn>
</template>
</v-snackbar>
2025-07-16 18:41:53 +03:30
</template>
<script>
2025-07-17 12:37:31 +03:30
import axios from "axios";
2025-07-16 18:41:53 +03:30
export default {
name: 'panel',
data() {
return {
2025-07-17 12:37:31 +03:30
loading: true,
businessInfo: {
smsCharge: 0
},
inquirySettings: {
enablePostalCodeToAddress: false,
postalCodeToAddressFee: 0,
enableCardToSheba: false,
cardToShebaFee: 0,
enableAccountToSheba: false,
accountToShebaFee: 0,
},
// دیالوگ‌ها
postalCodeDialog: false,
cardToShebaDialog: false,
accountToShebaDialog: false,
// فرم‌ها
postalCodeFormValid: false,
cardToShebaFormValid: false,
accountToShebaFormValid: false,
// داده‌های فرم
postalCodeData: {
postalCode: ''
},
cardToShebaData: {
cardNumber: ''
},
accountToShebaData: {
bankCode: '',
accountNumber: ''
},
// وضعیت لودینگ
postalCodeLoading: false,
cardToShebaLoading: false,
accountToShebaLoading: false,
// خطاها
postalCodeError: null,
cardToShebaError: null,
accountToShebaError: null,
// Snackbar
snackbar: {
show: false,
text: '',
color: 'success',
timeout: 3000
},
// نتایج استعلام
inquiryResults: {
postalCode: null,
cardToSheba: null,
accountToSheba: null
}
}
},
computed: {
hasActiveServices() {
return this.inquirySettings.enablePostalCodeToAddress ||
this.inquirySettings.enableCardToSheba ||
this.inquirySettings.enableAccountToSheba;
},
hasLowCredit() {
const minCredit = Math.min(
this.inquirySettings.postalCodeToAddressFee,
this.inquirySettings.cardToShebaFee,
this.inquirySettings.accountToShebaFee
);
return (this.businessInfo.smsCharge || 0) < minCredit;
},
bankCodes() {
return [
{ code: '066', name: 'دی' },
{ code: '015', name: 'سپه' },
{ code: '061', name: 'شهر' },
{ code: '012', name: 'ملت' },
{ code: '017', name: 'ملی' },
{ code: '013', name: 'رفاه' },
{ code: '059', name: 'سینا' },
{ code: '014', name: 'مسکن' },
{ code: '062', name: 'آینده' },
{ code: '063', name: 'انصار' },
{ code: '018', name: 'تجارت' },
{ code: '070', name: 'رسالت' },
{ code: '056', name: 'سامان' },
{ code: '010', name: 'مرکزی' },
{ code: '058', name: 'سرمایه' },
{ code: '019', name: 'صادرات' },
{ code: '052', name: 'قوامین' },
{ code: '054', name: 'پارسیان' },
{ code: '016', name: 'کشاورزی' },
{ code: '064', name: 'گردشگری' },
{ code: '021', name: 'پست بانک' },
{ code: '057', name: 'پاسارگاد' },
{ code: '053', name: 'کارآفرین' },
{ code: '078', name: 'خاورمیانه' },
{ code: '069', name: 'ایران زمین' },
{ code: '079', name: 'مهر اقتصاد' },
{ code: '011', name: 'صنعت و معدن' },
{ code: '055', name: 'اقتصاد نوین' },
{ code: '022', name: 'توسعه تعاون' },
{ code: '020', name: 'توسعه صادرات' },
{ code: '095', name: 'ایران-ونزوئلا' },
{ code: '065', name: 'حکمت ایرانیان' },
{ code: '060', name: 'قرض الحسنه مهر' },
{ code: '075', name: 'موسسه اعتباری ملل' },
{ code: '080', name: 'موسسه اعتباری نور' },
{ code: '073', name: 'موسسه اعتباری کوثر' },
{ code: '051', name: 'موسسه اعتباری توسعه' }
];
2025-07-16 18:41:53 +03:30
}
},
methods: {
2025-07-17 12:37:31 +03:30
// نمایش Snackbar
showSnackbar(text, color = 'success', timeout = 3000) {
this.snackbar = {
show: true,
text,
color,
timeout
};
},
// فرمت کردن آبجکت آدرس به رشته خوانا
formatAddress(addressObj) {
if (!addressObj || typeof addressObj !== 'object') return '';
const parts = [];
if (addressObj.province) parts.push(addressObj.province);
if (addressObj.town) parts.push(addressObj.town);
if (addressObj.street2) parts.push(addressObj.street2);
if (addressObj.street) parts.push(addressObj.street);
if (addressObj.district) parts.push('محله ' + addressObj.district);
if (addressObj.building_name) parts.push('ساختمان ' + addressObj.building_name);
if (addressObj.number) parts.push('پلاک ' + addressObj.number);
if (addressObj.floor) parts.push('طبقه ' + addressObj.floor);
if (addressObj.side_floor) parts.push('واحد ' + addressObj.side_floor);
if (addressObj.description) parts.push(addressObj.description);
return parts.join('، ');
},
// فرمت کردن عدد به ریال
formatCurrency(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
// تعیین رنگ کارت اعتبار بر اساس میزان اعتبار
getCreditCardColor() {
if (this.hasLowCredit) {
return 'error';
} else if ((this.businessInfo.smsCharge || 0) > 100000) {
return 'success';
} else {
return 'primary';
}
},
// تعیین رنگ وضعیت اعتبار
getCreditStatusColor() {
if (this.hasLowCredit) {
return 'error';
} else if ((this.businessInfo.smsCharge || 0) > 100000) {
return 'success';
} else {
return 'warning';
}
},
// تعیین آیکون وضعیت اعتبار
getCreditStatusIcon() {
if (this.hasLowCredit) {
return 'mdi-alert';
} else if ((this.businessInfo.smsCharge || 0) > 100000) {
return 'mdi-check-circle';
} else {
return 'mdi-information';
}
},
// تعیین متن وضعیت اعتبار
getCreditStatusText() {
if (this.hasLowCredit) {
return 'اعتبار کم';
} else if ((this.businessInfo.smsCharge || 0) > 100000) {
return 'اعتبار کافی';
} else {
return 'اعتبار متوسط';
}
},
// تعیین متن کوتاه وضعیت اعتبار برای موبایل
getCreditStatusTextShort() {
if (this.hasLowCredit) {
return 'کم';
} else if ((this.businessInfo.smsCharge || 0) > 100000) {
return 'کافی';
} else {
return 'متوسط';
}
},
// بارگذاری تنظیمات استعلامات
async loadInquirySettings() {
try {
this.loading = true;
const response = await axios.get('/api/plugins/inquiry/settings/get');
this.inquirySettings = {
enablePostalCodeToAddress: response.data.enablePostalCodeToAddress === '1' || response.data.enablePostalCodeToAddress === true,
postalCodeToAddressFee: parseInt(response.data.postalCodeToAddressFee) || 0,
enableCardToSheba: response.data.enableCardToSheba === '1' || response.data.enableCardToSheba === true,
cardToShebaFee: parseInt(response.data.cardToShebaFee) || 0,
enableAccountToSheba: response.data.enableAccountToSheba === '1' || response.data.enableAccountToSheba === true,
accountToShebaFee: parseInt(response.data.accountToShebaFee) || 0,
};
} catch (error) {
console.error('خطا در بارگذاری تنظیمات استعلامات:', error);
this.showSnackbar('خطا در بارگذاری تنظیمات استعلامات', 'error');
} finally {
this.loading = false;
}
},
// بارگذاری اطلاعات کسب و کار
async loadBusinessInfo() {
try {
const activeBid = localStorage.getItem('activeBid');
if (!activeBid) {
console.error('شناسه کسب و کار فعال یافت نشد');
return;
}
const response = await axios.get(`/api/business/get/info/${activeBid}`);
this.businessInfo = response.data;
} catch (error) {
console.error('خطا در بارگذاری اطلاعات کسب و کار:', error);
this.showSnackbar('خطا در بارگذاری اطلاعات کسب و کار', 'error');
}
},
// باز کردن دیالوگ کد پستی
openPostalCodeDialog() {
this.postalCodeData.postalCode = '';
this.postalCodeError = null;
this.inquiryResults.postalCode = null; // Clear previous result
this.postalCodeDialog = true;
},
// باز کردن دیالوگ کارت به شبا
openCardToShebaDialog() {
this.cardToShebaData.cardNumber = '';
this.cardToShebaError = null;
this.inquiryResults.cardToSheba = null; // Clear previous result
this.cardToShebaDialog = true;
},
// باز کردن دیالوگ حساب به شبا
openAccountToShebaDialog() {
this.accountToShebaData.bankCode = '';
this.accountToShebaData.accountNumber = '';
this.accountToShebaError = null;
this.inquiryResults.accountToSheba = null; // Clear previous result
this.accountToShebaDialog = true;
},
// ارسال استعلام کد پستی
async submitPostalCodeInquiry() {
if (!this.$refs.postalCodeForm.validate()) return;
// بررسی اعتبار کافی
if ((this.businessInfo.smsCharge || 0) < this.inquirySettings.postalCodeToAddressFee) {
this.showSnackbar('اعتبار شما برای این استعلام کافی نیست. لطفاً اعتبار خود را افزایش دهید.', 'error');
return;
}
try {
this.postalCodeLoading = true;
this.postalCodeError = null;
const response = await axios.post('/api/plugins/inquiry/postalcode-to-address', {
postal_code: this.postalCodeData.postalCode
});
if (response.data.success) {
// نمایش پیام مناسب بر اساس منبع داده
const message = response.data.from_cache
? 'اطلاعات آدرس از حافظه موقت دریافت شد (بدون کسر کارمزد)'
: 'اطلاعات آدرس با موفقیت دریافت شد';
// ذخیره نتیجه
this.inquiryResults.postalCode = {
postalCode: this.postalCodeData.postalCode,
address: response.data.data,
fromCache: response.data.from_cache,
message: response.data.message
};
this.showSnackbar(message, 'success');
// به‌روزرسانی اعتبار کاربر
if (!response.data.from_cache) {
this.businessInfo.smsCharge = Math.max(0, (this.businessInfo.smsCharge || 0) - this.inquirySettings.postalCodeToAddressFee);
}
// this.postalCodeDialog = false; // حذف بستن دیالوگ
} else {
// مدیریت خطاهای خاص
let errorMessage = response.data.message || 'خطا در استعلام';
if (response.data.error_code === 'HTTP_ERROR_504') {
errorMessage = 'سرویس استعلام کد پستی در دسترس نیست. لطفاً بعداً تلاش کنید.';
}
this.postalCodeError = errorMessage;
this.showSnackbar(errorMessage, 'error');
}
} catch (error) {
console.error('خطا در استعلام کد پستی:', error);
this.postalCodeError = 'خطا در برقراری ارتباط با سرور';
this.showSnackbar('خطا در برقراری ارتباط با سرور', 'error');
} finally {
this.postalCodeLoading = false;
}
},
// ارسال استعلام کارت به شبا
async submitCardToShebaInquiry() {
if (!this.$refs.cardToShebaForm.validate()) return;
// بررسی اعتبار کافی
if ((this.businessInfo.smsCharge || 0) < this.inquirySettings.cardToShebaFee) {
this.showSnackbar('اعتبار شما برای این استعلام کافی نیست. لطفاً اعتبار خود را افزایش دهید.', 'error');
return;
}
try {
this.cardToShebaLoading = true;
this.cardToShebaError = null;
const response = await axios.post('/api/plugins/inquiry/card-to-sheba', {
card_number: this.cardToShebaData.cardNumber
});
if (response.data.success) {
// نمایش پیام مناسب بر اساس منبع داده
const message = response.data.from_cache
? 'اطلاعات کارت از حافظه موقت دریافت شد (بدون کسر کارمزد)'
: 'اطلاعات کارت با موفقیت دریافت شد';
// ذخیره نتیجه
this.inquiryResults.cardToSheba = {
cardNumber: this.cardToShebaData.cardNumber,
IBAN: response.data.data.IBAN,
name: response.data.data.name,
bank_name: response.data.data.bank_name,
fromCache: response.data.from_cache,
message: response.data.message
};
this.showSnackbar(message, 'success');
// به‌روزرسانی اعتبار کاربر
if (!response.data.from_cache) {
this.businessInfo.smsCharge = Math.max(0, (this.businessInfo.smsCharge || 0) - this.inquirySettings.cardToShebaFee);
}
// this.cardToShebaDialog = false; // حذف بستن دیالوگ
} else {
// مدیریت خطاهای خاص
let errorMessage = response.data.message || 'خطا در استعلام';
// تبدیل کدهای خطا به پیام‌های فارسی
if (response.data.error_code) {
switch (response.data.error_code) {
case 'CARD_LOST':
errorMessage = 'کارت گم شده است';
break;
case 'CARD_EXPIRED':
errorMessage = 'کارت منقضی شده است';
break;
case 'CARD_NOT_FOUND':
errorMessage = 'کارت وارد شده در سیستم بانکی وجود ندارد';
break;
case 'CARD_NOT_ACTIVE':
errorMessage = 'کارت غیر فعال است';
break;
case 'ACCOUNT_NOT_ACTIVE':
errorMessage = 'حساب متصل به کارت فعال نیست';
break;
case 'CARD_NUMBER_NOT_VALID':
errorMessage = 'شماره کارت نامعتبر است';
break;
}
}
this.cardToShebaError = errorMessage;
this.showSnackbar(errorMessage, 'error');
}
} catch (error) {
console.error('خطا در استعلام کارت به شبا:', error);
this.cardToShebaError = 'خطا در برقراری ارتباط با سرور';
this.showSnackbar('خطا در برقراری ارتباط با سرور', 'error');
} finally {
this.cardToShebaLoading = false;
}
},
// ارسال استعلام حساب به شبا
async submitAccountToShebaInquiry() {
if (!this.$refs.accountToShebaForm.validate()) return;
// بررسی اعتبار کافی
if ((this.businessInfo.smsCharge || 0) < this.inquirySettings.accountToShebaFee) {
this.showSnackbar('اعتبار شما برای این استعلام کافی نیست. لطفاً اعتبار خود را افزایش دهید.', 'error');
return;
}
try {
this.accountToShebaLoading = true;
this.accountToShebaError = null;
const response = await axios.post('/api/plugins/inquiry/account-to-sheba', {
bank_code: this.accountToShebaData.bankCode,
account_number: this.accountToShebaData.accountNumber
});
if (response.data.success) {
// نمایش پیام مناسب بر اساس منبع داده
const message = response.data.from_cache
? 'اطلاعات حساب از حافظه موقت دریافت شد (بدون کسر کارمزد)'
: 'اطلاعات حساب با موفقیت دریافت شد';
// ذخیره نتیجه
this.inquiryResults.accountToSheba = {
bankCode: this.accountToShebaData.bankCode,
accountNumber: this.accountToShebaData.accountNumber,
IBAN: response.data.data.IBAN,
fromCache: response.data.from_cache,
message: response.data.message
};
this.showSnackbar(message, 'success');
// به‌روزرسانی اعتبار کاربر
if (!response.data.from_cache) {
this.businessInfo.smsCharge = Math.max(0, (this.businessInfo.smsCharge || 0) - this.inquirySettings.accountToShebaFee);
}
// this.accountToShebaDialog = false; // حذف بستن دیالوگ
} else {
// مدیریت خطاهای خاص
let errorMessage = response.data.message || 'خطا در استعلام';
// تبدیل کدهای خطا به پیام‌های فارسی
if (response.data.error_code) {
switch (response.data.error_code) {
case 'ACCOUNT_NOT_ACTIVE':
errorMessage = 'حساب غیر فعال است';
break;
}
}
this.accountToShebaError = errorMessage;
this.showSnackbar(errorMessage, 'error');
}
} catch (error) {
console.error('خطا در استعلام حساب به شبا:', error);
this.accountToShebaError = 'خطا در برقراری ارتباط با سرور';
this.showSnackbar('خطا در برقراری ارتباط با سرور', 'error');
} finally {
this.accountToShebaLoading = false;
}
},
},
async mounted() {
await this.loadInquirySettings();
await this.loadBusinessInfo();
2025-07-16 18:41:53 +03:30
}
}
</script>
<style scoped>
2025-07-17 12:37:31 +03:30
/* کارت اعتبار */
.credit-card {
position: relative;
overflow: hidden;
border-radius: 16px !important;
transition: all 0.3s ease;
}
.credit-card:hover {
transform: translateY(-4px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15) !important;
}
.credit-card-background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 0;
}
.credit-card-pattern {
position: absolute;
top: -50%;
right: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 1px, transparent 1px);
background-size: 20px 20px;
animation: float 6s ease-in-out infinite;
}
@keyframes float {
0%,
100% {
transform: translateY(0px) rotate(0deg);
}
50% {
transform: translateY(-10px) rotate(180deg);
}
}
.credit-card-primary {
background: linear-gradient(135deg, #1976d2 0%, #42a5f5 100%);
}
.credit-card-success {
background: linear-gradient(135deg, #2e7d32 0%, #66bb6a 100%);
}
.credit-card-error {
background: linear-gradient(135deg, #d32f2f 0%, #ef5350 100%);
}
.credit-icon-wrapper {
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
padding: 12px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.add-credit-btn {
backdrop-filter: blur(10px);
border: 2px solid rgba(255, 255, 255, 0.3) !important;
font-weight: 600;
transition: all 0.3s ease;
}
.add-credit-btn:hover {
background: rgba(255, 255, 255, 0.1) !important;
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
}
.credit-amount-section {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20px;
}
.credit-amount-display {
flex: 1;
}
.amount-label {
font-size: 14px;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 8px;
font-weight: 500;
}
.amount-value {
display: flex;
align-items: baseline;
gap: 12px;
}
.currency-symbol {
font-size: 18px;
color: rgba(255, 255, 255, 0.9);
font-weight: 500;
}
.amount-number {
font-size: 32px;
font-weight: 700;
color: white;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
font-family: 'Courier New', monospace;
}
.credit-status-indicator {
text-align: right;
}
.status-chip {
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
font-weight: 600;
}
.credit-alert {
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.1) !important;
}
/* کارت‌های سرویس */
.service-card {
transition: all 0.3s ease;
border: 2px solid transparent;
position: relative;
overflow: hidden;
cursor: pointer;
}
.service-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1) !important;
}
.service-card-header {
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
position: relative;
}
.service-card-header::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(0, 0, 0, 0.1), transparent);
}
/* انیمیشن برای chip ها */
.v-chip {
transition: all 0.3s ease;
}
.v-chip:hover {
transform: scale(1.05);
}
/* استایل برای آیکون‌ها */
.service-card .v-icon {
transition: transform 0.3s ease;
}
.service-card:hover .v-icon {
transform: scale(1.1);
}
/* استایل برای دکمه‌ها */
.v-btn {
transition: all 0.3s ease;
}
.v-btn:hover {
transform: translateY(-1px);
}
/* ریسپانسیو */
@media (max-width: 768px) {
.credit-amount-section {
flex-direction: column;
align-items: flex-start;
gap: 16px;
}
.credit-status-indicator {
text-align: left;
}
.amount-number {
font-size: 24px;
}
.currency-symbol {
font-size: 16px;
}
.credit-card .v-card-text {
padding: 20px !important;
}
.credit-icon-wrapper {
padding: 8px;
}
.credit-icon-wrapper .v-icon {
font-size: 32px !important;
}
.add-credit-btn {
width: 100%;
max-width: 200px;
}
}
@media (max-width: 480px) {
.amount-number {
font-size: 20px;
}
.currency-symbol {
font-size: 14px;
}
.credit-card .v-card-text {
padding: 16px !important;
}
.amount-value {
gap: 8px;
}
}
2025-07-16 18:41:53 +03:30
</style>