add some option and bug fix in business list and wallet controll

This commit is contained in:
Hesabix 2025-04-03 10:46:18 +00:00
parent 58b97be2ae
commit b794ea76b7
8 changed files with 678 additions and 292 deletions

View file

@ -112,4 +112,25 @@ export default {
background: rgba(0, 0, 0, 0.4);
/* رنگ هنگام هاور */
}
.v-data-table {
overflow-x: auto;
}
.expanded-row {
background-color: #f5f5f5 !important;
padding: 8px;
}
.custom-header {
background-color: #213e8b !important;
color: #ffffff !important;
text-align: center !important;
}
.v-data-table, .v-data-table-server, .v-data-table-header__content {
margin: 0 auto;
width: fit-content;
text-align: center !important;
}
</style>

View file

@ -3,8 +3,12 @@
<v-text-field v-model="displayDate" :label="label" prepend-inner-icon="mdi-calendar" persistent-placeholder
:class="['v-date-input', `date-input-${uniqueId}`]" :rules="rules" @input="updateDateFromInput" @click:prepend="togglePicker"></v-text-field>
<date-picker v-model="displayDate" type="date" format="jYYYY/jMM/jDD" display-format="jYYYY/jMM/jDD"
:min="minDatePersian" :max="maxDatePersian" :custom-input="`.date-input-${uniqueId}`" :input-mode="true"
:editable="pickerActive" @close="pickerActive = false"></date-picker>
:min="ignoreYearRange ? (min || null) : minDatePersian"
:max="ignoreYearRange ? null : maxDatePersian"
:custom-input="`.date-input-${uniqueId}`"
:input-mode="true"
:editable="pickerActive"
@close="pickerActive = false"></date-picker>
</div>
</template>
@ -26,6 +30,14 @@ export default {
type: Array,
default: () => [],
},
ignoreYearRange: {
type: Boolean,
default: false
},
min: {
type: String,
default: null
}
},
data() {
return {
@ -79,15 +91,7 @@ export default {
updateDateFromInput(value) {
// بررسی و اعتبارسنجی تاریخ وارد شده توسط کاربر
if (value && moment(value, 'YYYY/MM/DD', 'fa', true).isValid()) {
const parsedDate = moment(value, 'YYYY/MM/DD').locale('fa');
if (
parsedDate.isSameOrAfter(moment(this.minDatePersian, 'YYYY/MM/DD')) &&
parsedDate.isSameOrBefore(moment(this.maxDatePersian, 'YYYY/MM/DD'))
) {
this.displayDate = value;
} else {
this.displayDate = ''; // یا خطا نمایش بدید
}
this.displayDate = value;
}
},
togglePicker() {

View file

@ -90,6 +90,7 @@ const fa_lang = {
}
},
drawer: {
wallets: "کیف پول‌ها",
ultimate_package: 'بسته‌های نامحدود',
sell_chart: "فروش هفته گذشته",
bankaccounts_transactions: "کارت حساب بانک",

View file

@ -146,6 +146,14 @@ const router = createRouter({
'login': true
}
},
{
path: 'manager/wallet/list',
component: () => import('../views/user/manager/wallet/list.vue'),
meta: {
'title': 'کیف پول',
'login': true
}
},
{
path: 'manager/changes/list',
component: () => import('../views/user/manager/reportchange/list.vue'),

View file

@ -970,18 +970,4 @@ export default {
.shortcut-input {
max-width: 60px;
}
.v-data-table {
overflow-x: auto;
}
.expanded-row {
background-color: #f5f5f5 !important;
padding: 8px;
}
.custom-header {
background-color: #213e8b !important;
color: #ffffff !important;
}
</style>

View file

@ -24,9 +24,6 @@
<v-tab value="2">
{{ $t('dialog.global_settings') }}
</v-tab>
<v-tab value="3">
{{ $t('dialog.gate_pay') }}
</v-tab>
</v-tabs>
</template>
</v-toolbar>
@ -37,140 +34,161 @@
<v-card>
<v-card-text>
<h3 class="text-primary">اطلاعات کسب و کار</h3>
<div class="row">
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating required">
<input class="form-control" type="text" v-model="content.name">
<label class="form-label">نام کسب و کار</label>
</div>
</div>
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating required">
<input class="form-control" type="text" v-model="content.legal_name">
<label class="form-label">نام قانونی کسب و کار</label>
</div>
</div>
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating">
<input class="form-control" type="text" v-model="content.field">
<label>زمینه فعالیت</label>
</div>
</div>
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating">
<select v-model="content.type" class="form-select">
<option value="شرکت">شرکت</option>
<option value="مغازه">مغازه</option>
<option value="فروشگاه">فروشگاه</option>
<option value="اتحادیه">اتحادیه</option>
<option value="باشگاه">باشگاه</option>
<option value="موسسه">موسسه</option>
<option value="شخصی">شخصی</option>
</select>
<label>نوع فعالیت</label>
</div>
</div>
</div>
<h3 class="text-primary">اطلاعات اقتصادی</h3>
<div class="row">
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating">
<input v-model="content.shenasemeli" type="text" class="form-control">
<label class="form-label">شناسه ملی</label>
</div>
</div>
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating">
<input v-model="content.codeeqtesadi" type="text" class="form-control">
<label class="form-label">کد اقتصادی</label>
</div>
</div>
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating">
<input v-model="content.shomaresabt" type="text" class="form-control">
<label class="form-label">شماره ثبت</label>
</div>
</div>
</div>
<h3 class="text-primary">اطلاعات تماس</h3>
<div class="row">
<div class="col-sm-12 col-md-4 mb-2">
<div class="form-floating">
<input v-model="content.country" type="text" class="form-control">
<label class="form-label">کشور</label>
</div>
</div>
<div class="col-sm-12 col-md-4 mb-2">
<div class="form-floating">
<input v-model="content.ostan" type="text" id="business_new_ostan" name="business_new[ostan]"
maxlength="50" class="form-control form-control-sm">
<label class="form-label">استان</label>
</div>
</div>
<div class="col-sm-12 col-md-4 mb-2">
<div class="form-floating">
<input v-model="content.shahrestan" type="text" id="business_new_shahr" name="business_new[shahr]"
maxlength="50" class="form-control form-control-sm">
<label class="form-label">شهر</label>
</div>
</div>
<div class="col-sm-12 col-md-4 mb-2">
<div class="form-floating">
<input v-model="content.postalcode" type="text" id="business_new_codeposti"
name="business_new[codeposti]" maxlength="10" class="form-control form-control-sm">
<label class="form-label">کد پستی</label>
</div>
</div>
<div class="col-sm-12 col-md-4 mb-2">
<div class="form-floating">
<input v-model="content.tel" type="text" id="business_new_tel" name="business_new[tel]"
maxlength="15" class="form-control form-control-sm">
<label class="form-label">تلفن</label>
</div>
</div>
<div class="col-sm-12 col-md-4 mb-2">
<div class="form-floating">
<input v-model="content.mobile" type="tel" id="business_new_fax" name="business_new[fax]"
maxlength="15" class="form-control form-control-sm">
<label class="form-label">موبایل</label>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-12 mb-2">
<div class="form-floating">
<input type="text" v-model="content.address" id="business_new_address" name="business_new[address]"
maxlength="255" class="form-control form-control-sm">
<label class="form-label">آدرس</label>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating">
<input v-model="content.website" type="url" id="business_new_website" name="business_new[website]"
inputmode="url" class="form-control form-control-sm">
<label class="form-label">وبسایت</label>
</div>
</div>
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating">
<input v-model="content.email" type="email" id="business_new_email" name="business_new[email]"
maxlength="255" class="form-control form-control-sm">
<label class="form-label">پست الکترونیکی</label>
</div>
</div>
</div>
<h3 class="text-primary">اطلاعات مالی</h3>
<div class="row">
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-floating required">
<input v-model="content.maliyatafzode" type="number" id="business_new_maliyatafzode"
name="business_new[maliyatafzode]" required="required" class="form-control form-control-sm">
<label class="form-label">مالیات بر ارزش افزوده</label>
</div>
</div>
</div>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="content.name"
label="نام کسب و کار"
variant="outlined"
required
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="content.legal_name"
label="نام قانونی کسب و کار"
variant="outlined"
required
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="content.field"
label="زمینه فعالیت"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-select
v-model="content.type"
:items="['شرکت', 'مغازه', 'فروشگاه', 'اتحادیه', 'باشگاه', 'موسسه', 'شخصی']"
label="نوع فعالیت"
variant="outlined"
density="compact"
></v-select>
</v-col>
</v-row>
<h3 class="text-primary mt-4">اطلاعات اقتصادی</h3>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="content.shenasemeli"
label="شناسه ملی"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="content.codeeqtesadi"
label="کد اقتصادی"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="content.shomaresabt"
label="شماره ثبت"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
</v-row>
<h3 class="text-primary mt-4">اطلاعات تماس</h3>
<v-row>
<v-col cols="12" md="4">
<v-text-field
v-model="content.country"
label="کشور"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="content.ostan"
label="استان"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="content.shahrestan"
label="شهر"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="content.postalcode"
label="کد پستی"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="content.tel"
label="تلفن"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="content.mobile"
label="موبایل"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
v-model="content.address"
label="آدرس"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="content.website"
label="وب‌سایت"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="content.email"
label="پست الکترونیکی"
variant="outlined"
density="compact"
></v-text-field>
</v-col>
</v-row>
<h3 class="text-primary mt-4">اطلاعات مالی</h3>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="content.maliyatafzode"
label="مالیات بر ارزش افزوده"
type="number"
variant="outlined"
required
density="compact"
></v-text-field>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-tabs-window-item>
@ -178,37 +196,34 @@
<v-card>
<v-card-text>
<h3 class="text-primary">سال مالی</h3>
<div class="row">
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-control">
<label class="form-label">
<span class="text-danger">*</span>
شروع سال مالی
</label>
<date-picker class="" v-model="content.year.startShamsi" format="jYYYY/jMM/jDD"
display-format="jYYYY/jMM/jDD" />
</div>
</div>
<div class="col-sm-12 col-md-6 mb-2">
<div class="form-control">
<label class="form-label">
<span class="text-danger">*</span>
اتمام سال مالی
</label>
<date-picker class="" v-model="content.year.endShamsi" format="jYYYY/jMM/jDD"
display-format="jYYYY/jMM/jDD" :min="content.year.startShamsi" />
</div>
</div>
<div class="col-sm-12 col-md-12">
<div class="form-control mb-2">
<label class="form-label">
<span class="text-danger">*</span>
عنوان سال مالی
</label>
<input v-model="content.year.label" class="form-control" type="text">
</div>
</div>
</div>
<v-row>
<v-col cols="12" md="6">
<Hdatepicker
v-model="content.year.startShamsi"
label="شروع سال مالی"
:rules="[v => !!v || 'این فیلد الزامی است']"
:ignore-year-range="true"
/>
</v-col>
<v-col cols="12" md="6">
<Hdatepicker
v-model="content.year.endShamsi"
label="اتمام سال مالی"
:rules="[v => !!v || 'این فیلد الزامی است']"
:ignore-year-range="true"
:min="content.year.startShamsi"
/>
</v-col>
<v-col cols="12">
<v-text-field
v-model="content.year.label"
label="عنوان سال مالی"
variant="outlined"
required
density="compact"
></v-text-field>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-tabs-window-item>
@ -216,108 +231,95 @@
<v-card>
<v-card-text>
<h3 class="text-primary">نمایش پیوند یکتا</h3>
<div class="row">
<div class="col-sm-12 col-md-8 mb-2">
<div class="space-y-2">
<div class="form-check form-switch">
<input v-model="content.shortlinks" class="form-check-input" type="checkbox">
<label class="form-check-label">فعالسازی پیوندهای یکتا</label>
<br>
<label class="text-muted">این قابلیت برای تولید پیوندهای یکتا برای ارسال به مشتری جهت مشاهده
فاکتورها است.</label>
</div>
<v-row>
<v-col cols="12" md="8">
<v-switch
v-model="content.shortlinks"
label="فعال‌سازی پیوند‌های یکتا"
color="primary"
hide-details
></v-switch>
<div class="text-caption text-medium-emphasis mt-1">
این قابلیت برای تولید پیوندهای یکتا برای ارسال به مشتری جهت مشاهده فاکتورها است.
</div>
</div>
</div>
<h3 class="text-primary">دریافت مبلغ فاکتور از طریق کیف پول</h3>
<div class="row">
<div class="col-sm-12 col-md-12 mb-2">
<div class="space-y-2">
<div class="form-check form-switch">
<input @change="checkBanksExist()" v-model="content.walletEnabled" class="form-check-input"
type="checkbox">
<label class="form-check-label">فعالسازی دریافت آنلاین از طریق کیف پول</label>
<br>
<label class="text-muted">با فعال سازی این قابلیت قادر خواهید بود مبالغ فاکتورهای ثبت شده را
به صورت آنلاین از مشتریان خود دریافت کنید.</label>
</div>
</div>
<div class="row" v-show="content.walletEnabled">
<div class="col-sm-12 col-md-6">
<label class="mb-2">حساب بانکی متصل به کیف پول</label>
<div class="col">
<v-cob dir="rtl" :options="listBanks" label="name" v-model="content.walletMatchBank"
@option:deselecting="" @search:focus="" @option:selecting="">
<template #no-options="{ search, searching, loading }">
نتیجهای یافت نشد!
</template>
</v-cob>
</div>
</div>
<label class="text-muted">برای تسویه اتوماتیک به حساب انتخاب شده حتما باید تمام موارد از جمله
شماره شبا و شماره کارت و
... به درستی تکمیل شده باشد در غیر این صورت تراکنش با خطا مواجه خواهد شد.</label>
</v-col>
</v-row>
<h3 class="text-primary mt-4">دریافت مبلغ فاکتور از طریق کیف پول</h3>
<v-row>
<v-col cols="12">
<v-switch
v-model="content.walletEnabled"
label="فعال‌سازی دریافت آنلاین از طریق کیف پول"
color="primary"
@change="checkBanksExist"
hide-details
></v-switch>
<div class="text-caption text-medium-emphasis mt-1">
با فعال سازی این قابلیت قادر خواهید بود مبالغ فاکتورهای ثبت شده را به صورت آنلاین از مشتریان خود دریافت کنید.
</div>
</div>
</div>
<h3 class="text-primary">کالا و خدمات</h3>
<div class="row">
<div class="col-sm-12 col-md-8 mb-2">
<div class="space-y-2">
<div class="form-check form-switch">
<input v-model="content.updateBuyPrice" class="form-check-input" type="checkbox">
<label class="form-check-label">به روز رسانی قیمت خرید هنگام صدور فاکتور</label>
<br>
<label class="text-muted">با صدور فاکتور خرید یا برگشت از خرید قیمت خرید کالا و خدمات به
روزرسانی خواهد
شد.</label>
</div>
<v-row v-if="content.walletEnabled" class="mt-4">
<v-col cols="12" md="6">
<v-select
v-model="content.walletMatchBank"
:items="listBanks"
item-title="name"
item-value="id"
label="حساب بانکی متصل به کیف پول"
variant="outlined"
density="compact"
></v-select>
</v-col>
<v-col cols="12">
<div class="text-caption text-medium-emphasis">
برای تسویه اتوماتیک به حساب انتخاب شده حتما باید تمام موارد از جمله شماره شبا و شماره کارت و ... به درستی تکمیل شده باشد در غیر این صورت تراکنش با خطا مواجه خواهد شد.
</div>
</v-col>
</v-row>
</v-col>
</v-row>
<h3 class="text-primary mt-4">کالا و خدمات</h3>
<v-row>
<v-col cols="12" md="8">
<v-switch
v-model="content.updateBuyPrice"
label="به روز رسانی قیمت خرید هنگام صدور فاکتور"
color="primary"
hide-details
></v-switch>
<div class="text-caption text-medium-emphasis mt-1">
با صدور فاکتور خرید یا برگشت از خرید قیمت خرید کالا و خدمات به روزرسانی خواهد شد.
</div>
</div>
<div class="col-sm-12 col-md-8 mb-2">
<div class="space-y-2">
<div class="form-check form-switch">
<input v-model="content.updateSellPrice" class="form-check-input" type="checkbox">
<label class="form-check-label">به روز رسانی قیمت فروش هنگام صدور فاکتور</label>
<br>
<label class="text-muted">با صدور فاکتور فروش یا برگشت از فروش قیمت خرید کالا و خدمات به
روزرسانی خواهد
شد.</label>
</div>
</v-col>
<v-col cols="12" md="8">
<v-switch
v-model="content.updateSellPrice"
label="به روز رسانی قیمت فروش هنگام صدور فاکتور"
color="primary"
hide-details
></v-switch>
<div class="text-caption text-medium-emphasis mt-1">
با صدور فاکتور فروش یا برگشت از فروش قیمت خرید کالا و خدمات به روزرسانی خواهد شد.
</div>
</div>
<div class="col-sm-12 col-md-8 mb-2">
<div class="space-y-2">
<div class="form-floating">
<select class="form-select" v-model="content.profitCalcType">
<option value="simple">بر اساس اختلاف قیمت خرید و فروش</option>
<option value="lis">بر اساس آخرین قیمت ورود به انبار</option>
<option value="avgis">بر اساس میانگین قیمت ورود به انبار</option>
</select>
<label for="floatingSelect">نحوه محاسبه سود فاکتور</label>
</div>
</div>
</div>
</div>
</v-card-text>
</v-card>
</v-tabs-window-item>
<v-tabs-window-item value="3">
<v-card>
<v-card-text>
<h3 class="text-primary">درگاه پرداخت زرین پال</h3>
<div class="row">
<div class="col-sm-12 col-md-8 mb-2">
<div class="form-floating required">
<input class="form-control" type="text" v-model="content.zarinpal">
<label class="form-label">کد شناسایی: مثال a1104652-18b9-4b63-911c-0a5046e61be1</label>
</div>
<label class="text-muted mt-2">برای غیر فعال کردن درگاه پرداخت آن را خالی بگذارید. در صورت اشتباه
بودن کد وارد
شده × مشتری در هنگام تسویه فاکتورها با خطا مواجه خواهد شد.</label>
</div>
</div>
</v-col>
<v-col cols="12" md="8">
<v-select
v-model="content.profitCalcType"
:items="[
{ title: 'بر اساس اختلاف قیمت خرید و فروش', value: 'simple' },
{ title: 'بر اساس آخرین قیمت ورود به انبار', value: 'lis' },
{ title: 'بر اساس میانگین قیمت ورود به انبار', value: 'avgis' }
]"
item-title="title"
item-value="value"
label="نحوه محاسبه سود فاکتور"
variant="outlined"
density="compact"
></v-select>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-tabs-window-item>
@ -329,9 +331,13 @@
<script>
import axios from "axios";
import Swal from "sweetalert2";
import Hdatepicker from "@/components/forms/Hdatepicker.vue";
export default {
name: "bussiness",
components: {
Hdatepicker
},
data: () => {
return {
tabs: '',
@ -356,7 +362,6 @@ export default {
email: '',
arzmain: [],
maliyatafzode: 9,
zarinpalCode: '',
shortlinks: false,
walletEnabled: false,
walletMatchBank: '',
@ -425,7 +430,6 @@ export default {
'email': this.content.email,
'arzmain': this.content.arzmain,
'maliyatafzode': this.content.maliyatafzode,
'zarinpalCode': this.content.zarinpalCode,
'shortlinks': this.content.shortlinks,
'walletEnabled': this.content.walletEnabled,
'walletMatchBank': this.content.walletMatchBank,

View file

@ -0,0 +1,360 @@
<template>
<v-toolbar color="toolbar" :title="$t('drawer.wallets')">
<v-spacer />
<template v-slot:extension>
<v-tabs v-model="activeTab" color="primary" fixed-tabs>
<v-tab value="wallets">کیف پولها</v-tab>
<v-tab value="transactions">تراکنشها</v-tab>
</v-tabs>
</template>
</v-toolbar>
<v-window v-model="activeTab">
<!-- تب کیف پولها -->
<v-window-item value="wallets">
<v-card :loading="loading ? 'red' : null" :disabled="loading">
<v-card-text>
<v-row>
<v-col cols="12" sm="4" md="3">
<v-text-field v-model="search" label="جستجو..." prepend-inner-icon="mdi-magnify" single-line hide-details
density="compact" variant="outlined"></v-text-field>
</v-col>
<v-col cols="12" sm="4" md="3">
<v-select v-model="statusFilter" :items="statusOptions" label="وضعیت" density="compact" variant="outlined"
hide-details clearable></v-select>
</v-col>
</v-row>
<v-row>
<v-col>
<v-data-table :headers="headers" :items="filteredItems" :loading="loading" class="elevation-1"
no-data-text="اطلاعاتی برای نمایش وجود ندارد" loading-text="در حال بارگذاری..." :items-per-page="10"
:items-per-page-text="'تعداد سطر'" :header-props="{ class: 'custom-header' }">
<template v-slot:item="{ item }">
<tr>
<td>{{ item.bidName }}</td>
<td>{{ item.bankAcName }}</td>
<td>{{ item.bankAcOwner }}</td>
<td>{{ item.bankAcShaba }}</td>
<td>{{ item.bankAcCardNum }}</td>
<td>{{ item.totalPays }}</td>
<td>{{ item.totalIncome }}</td>
<td>{{ calculateStatus(item) }}</td>
<td>
<v-tooltip v-if="calculateStatus(item) === 'در صف تسویه'" location="top">
<template v-slot:activator="{ props }">
<v-btn variant="text" icon v-bind="props" @click="openTransactionDialog(item)">
<v-icon>mdi-cash-register</v-icon>
</v-btn>
</template>
<span>ثبت تراکنش</span>
</v-tooltip>
</td>
</tr>
</template>
</v-data-table>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-window-item>
<!-- تب تراکنشها -->
<v-window-item value="transactions">
<v-card :loading="transactionsLoading ? 'red' : null" :disabled="transactionsLoading">
<v-card-text>
<v-row>
<v-col cols="12" sm="4" md="3">
<v-text-field v-model="transactionSearch" label="جستجو..." prepend-inner-icon="mdi-magnify" single-line
hide-details density="compact" variant="outlined"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col>
<v-data-table :headers="transactionHeaders" :items="filteredTransactions" :loading="transactionsLoading"
class="elevation-1" no-data-text="اطلاعاتی برای نمایش وجود ندارد" loading-text="در حال بارگذاری..."
:items-per-page="10" :items-per-page-text="'تعداد سطر'" :header-props="{ class: 'custom-header' }">
<template v-slot:item="{ item }">
<tr>
<td>{{ item.bidName }}</td>
<td>{{ item.bankAcName }}</td>
<td>{{ item.type === 'pay' ? 'پرداخت' : 'دریافت' }}</td>
<td>{{ item.gatePay }}</td>
<td>{{ item.refID }}</td>
<td>{{ item.shaba }}</td>
<td>{{ item.cardPan }}</td>
<td>{{ item.dateSubmit }}</td>
</tr>
</template>
</v-data-table>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-window-item>
</v-window>
<v-dialog v-model="dialogVisible" max-width="500px">
<v-card>
<v-card-title>ثبت تراکنش تسویه کیف پول</v-card-title>
<v-card-text>
<v-form ref="form" v-model="formValid" @submit.prevent="submitTransaction">
<v-row>
<v-col cols="12">
<v-select v-model="transaction.bank" :items="bankOptions" label="بانک پرداخت کننده"
:rules="[v => !!v || 'بانک الزامی است']" variant="outlined" required></v-select>
</v-col>
<v-col cols="12">
<v-text-field v-model="transaction.refID" label="شناسه تراکنش"
:rules="[v => !!v || 'شناسه تراکنش الزامی است']" variant="outlined" required></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field v-model="transaction.amount" label="مبلغ (ریال)" type="number"
:rules="[v => !!v || 'مبلغ الزامی است']" variant="outlined" required></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field v-model="selectedItemShaba" label="شبا" disabled variant="outlined"></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field v-model="selectedItemCard" label="شماره کارت" disabled variant="outlined"></v-text-field>
</v-col>
</v-row>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="error" @click="dialogVisible = false">انصراف</v-btn>
<v-btn color="primary" :loading="submitting" @click="submitTransaction">ثبت تراکنش</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import axios from "axios";
import Swal from "sweetalert2";
export default {
name: "dashboard",
data() {
return {
activeTab: 'wallets',
loading: true,
transactionsLoading: true,
submitting: false,
formValid: false,
items: [],
transactions: [],
search: '',
transactionSearch: '',
statusFilter: null,
transaction: {
bank: null,
refID: '',
amount: '',
shaba: '',
card: '',
bid: null
},
bankOptions: [
{ title: 'بانک ملی', value: 'بانک ملی' },
{ title: 'بانک ملت', value: 'بانک ملت' },
{ title: 'بانک صادرات', value: 'بانک صادرات' },
{ title: 'بانک تجارت', value: 'بانک تجارت' },
{ title: 'بانک پاسارگاد', value: 'بانک پاسارگاد' },
{ title: 'بانک سامان', value: 'بانک سامان' }
],
statusOptions: [
{ title: 'تسویه شده', value: 'تسویه شده' },
{ title: 'در صف تسویه', value: 'در صف تسویه' },
{ title: 'در انتظار پرداخت', value: 'در انتظار پرداخت' },
],
dialogVisible: false,
selectedItem: null,
headers: [
{ title: "کسب‌و‌کار", key: "bidName", sortable: false, align: 'center' },
{ title: "بانک", key: "bankAcName", sortable: false, align: 'center' },
{ title: "حساب", key: "bankAcOwner", sortable: false, align: 'center' },
{ title: "شبا", key: "bankAcShaba", sortable: false, align: 'center' },
{ title: "شماره کارت", key: "bankAcCardNum", sortable: false, align: 'center' },
{ title: "مبلغ پرداختی", key: "totalPays", sortable: false, align: 'center' },
{ title: "مبلغ دریافتی", key: "totalIncome", sortable: false, align: 'center' },
{ title: "وضعیت", key: "status", sortable: false, align: 'center' },
{ title: "عملیات", key: "operations", sortable: false, align: 'center' },
],
transactionHeaders: [
{ title: "کسب‌و‌کار", key: "bidName", sortable: false, align: 'center' },
{ title: "بانک", key: "bankAcName", sortable: false, align: 'center' },
{ title: "نوع", key: "type", sortable: false, align: 'center' },
{ title: "درگاه پرداخت", key: "gatePay", sortable: false, align: 'center' },
{ title: "شناسه تراکنش", key: "refID", sortable: false, align: 'center' },
{ title: "شبا", key: "shaba", sortable: false, align: 'center' },
{ title: "شماره کارت", key: "cardPan", sortable: false, align: 'center' },
{ title: "تاریخ", key: "dateSubmit", sortable: false, align: 'center' },
],
}
},
computed: {
filteredItems() {
let filtered = [...this.items];
// اعمال فیلتر جستجو
if (this.search) {
const searchLower = this.search.toLowerCase();
filtered = filtered.filter(item =>
item.bidName?.toLowerCase().includes(searchLower) ||
item.bankAcName?.toLowerCase().includes(searchLower) ||
item.bankAcOwner?.toLowerCase().includes(searchLower) ||
item.bankAcShaba?.toLowerCase().includes(searchLower) ||
item.bankAcCardNum?.toLowerCase().includes(searchLower)
);
}
// اعمال فیلتر وضعیت
if (this.statusFilter) {
filtered = filtered.filter(item =>
this.calculateStatus(item) === this.statusFilter
);
}
return filtered;
},
filteredTransactions() {
if (!this.transactionSearch) {
// مرتبسازی بر اساس تاریخ (جدیدترین اول)
return [...this.transactions].sort((a, b) => {
return a.dateSubmit < b.dateSubmit ? 1 : -1;
});
}
const searchLower = this.transactionSearch.toLowerCase();
return this.transactions.filter(item =>
item.bidName?.toLowerCase().includes(searchLower) ||
item.bankAcName?.toLowerCase().includes(searchLower) ||
item.refID?.toLowerCase().includes(searchLower) ||
item.shaba?.toLowerCase().includes(searchLower) ||
item.cardPan?.toLowerCase().includes(searchLower) ||
item.gatePay?.toLowerCase().includes(searchLower)
).sort((a, b) => {
return a.dateSubmit < b.dateSubmit ? 1 : -1;
});
},
selectedItemShaba() {
return this.selectedItem ? this.selectedItem.bankAcShaba : '';
},
selectedItemCard() {
return this.selectedItem ? this.selectedItem.bankAcCardNum : '';
}
},
watch: {
activeTab(newVal) {
if (newVal === 'transactions' && this.transactions.length === 0) {
this.loadTransactions();
}
}
},
methods: {
loadData() {
axios.post('/api/admin/wallets/list').then((response) => {
this.items = response.data;
this.loading = false;
});
},
loadTransactions() {
this.transactionsLoading = true;
axios.post('/api/admin/wallets/transactions/list').then((response) => {
this.transactions = response.data;
this.transactionsLoading = false;
}).catch(error => {
console.error('Error loading transactions:', error);
this.transactionsLoading = false;
});
},
calculateStatus(item) {
if (!item) {
return 'نامشخص';
}
const totalPays = Number(item.totalPays || 0);
const totalIncome = Number(item.totalIncome || 0);
if (totalPays === totalIncome) {
return 'تسویه شده';
} else if (totalPays > totalIncome) {
return 'در صف تسویه';
} else {
return 'در انتظار پرداخت';
}
},
openTransactionDialog(item) {
this.selectedItem = item;
// محاسبه مبلغ قابل پرداخت (مبلغ دریافتی - پرداختی)
const amount = Number(item.totalIncome || 0) - Number(item.totalPays || 0);
// تنظیم مقادیر پیشفرض فرم
this.transaction = {
bank: null,
refID: '',
amount: Math.abs(amount),
shaba: item.bankAcShaba,
card: item.bankAcCardNum,
bid: { id: item.id }
};
this.dialogVisible = true;
},
submitTransaction() {
if (!this.$refs.form.validate()) {
return;
}
this.submitting = true;
axios.post('/api/admin/wallets/transactions/insert', this.transaction)
.then(response => {
if (response.data.result === 1) {
this.dialogVisible = false;
Swal.fire({
icon: 'success',
title: 'موفق',
text: 'تراکنش با موفقیت ثبت شد',
confirmButtonText: 'تایید'
});
// بارگذاری مجدد دادهها
this.loadData();
this.loadTransactions();
} else {
throw new Error('خطا در ثبت تراکنش');
}
})
.catch(error => {
console.error('Error submitting transaction:', error);
Swal.fire({
icon: 'error',
title: 'خطا',
text: 'خطا در ثبت تراکنش. لطفا مجددا تلاش کنید.',
confirmButtonText: 'تایید'
});
})
.finally(() => {
this.submitting = false;
});
}
},
mounted() {
this.loadData();
},
beforeUnmount() {
if (this.intervalId) {
clearInterval(this.intervalId);
}
},
}
</script>
<style scoped>
.v-window {
margin-top: 16px;
}
</style>

View file

@ -105,6 +105,8 @@ export default defineComponent({
{ text: 'به روز رسانی هسته', url: '/profile/manager/update-core', icon: 'mdi-undo', visible: true },
{ text: 'تغییرات', url: '/profile/manager/changes/list', icon: 'mdi-cellphone-arrow-down', visible: true },
{ text: 'تاریخچه سیستم', url: '/profile/manager/logs/list', icon: 'mdi-history', visible: true },
{ text: 'کیف پول', url: '/profile/manager/wallet/list', icon: 'mdi-wallet', visible: true },
],
adminSettings: [
{ text: 'پیامک', url: '/profile/manager/system/sms/settings', icon: 'mdi-message-alert', visible: true },