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

1159 lines
42 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.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<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 برای نمایش پیامها -->
<v-snackbar v-model="snackbar.show" :color="snackbar.color" :timeout="snackbar.timeout" location="top">
{{ snackbar.text }}
<template v-slot:actions>
<v-btn color="white" variant="text" @click="snackbar.show = false">
بستن
</v-btn>
</template>
</v-snackbar>
</template>
<script>
import axios from "axios";
export default {
name: 'panel',
data() {
return {
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: 'موسسه اعتباری توسعه' }
];
}
},
methods: {
// نمایش 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();
}
}
</script>
<style scoped>
/* کارت اعتبار */
.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;
}
}
</style>