add change business to dashboard

This commit is contained in:
Hesabix 2025-08-06 22:26:26 +00:00
parent fd735320c3
commit a282e530d1
5 changed files with 362 additions and 6 deletions

View file

@ -0,0 +1,349 @@
<template>
<v-select
v-model="selectedBusiness"
:items="businesses"
item-title="name"
item-value="id"
:label="$t('drawer.business_switcher')"
density="comfortable"
variant="outlined"
hide-details
class="business-switcher"
@update:model-value="switchBusiness"
:loading="loading"
:disabled="businesses.length <= 1"
>
<template v-slot:prepend-inner>
<v-icon size="small">mdi-store</v-icon>
</template>
<template v-slot:selection="{ item }">
<span>{{ item.raw.name }}</span>
</template>
<template v-slot:item="{ props, item }">
<v-list-item v-bind="props">
<template v-slot:prepend>
<v-avatar size="32" :image="apiUrl + '/front/avatar/file/get/' + item.raw.id" />
</template>
<v-list-item-title>{{ item.raw.name }}</v-list-item-title>
<v-list-item-subtitle>{{ item.raw.owner }}</v-list-item-subtitle>
</v-list-item>
</template>
</v-select>
<!-- دیالوگ تأیید تغییر کسبوکار -->
<v-dialog v-model="confirmDialog" max-width="450" persistent>
<v-card class="rounded-lg elevation-8">
<v-toolbar color="primary" dark flat>
<v-toolbar-title class="d-flex align-center">
<v-icon class="me-2">mdi-store-switch</v-icon>
تغییر کسبوکار
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon @click="cancelSwitch" :disabled="switching">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-toolbar>
<v-card-text class="pa-6">
<div class="text-center mb-4">
<v-avatar size="80" color="primary-lighten-4" class="mb-3">
<v-icon size="40" color="primary">mdi-store</v-icon>
</v-avatar>
<div class="text-h6 mb-2">تأیید انتقال</div>
<div class="text-body-1 text-medium-emphasis">
آیا میخواهید به کسبوکار انتخاب شده منتقل شوید؟
</div>
</div>
</v-card-text>
<v-divider></v-divider>
<v-card-actions class="pa-4">
<v-spacer></v-spacer>
<v-btn
color="grey-darken-1"
variant="outlined"
@click="cancelSwitch"
class="me-2"
min-width="120"
:disabled="switching"
>
<v-icon start>mdi-close</v-icon>
انصراف
</v-btn>
<v-btn
color="primary"
@click="confirmSwitch"
min-width="120"
:loading="switching"
elevation="2"
>
<v-icon start>mdi-check</v-icon>
تأیید انتقال
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- دیالوگ لودینگ -->
<v-dialog v-model="loadingDialog" max-width="400" persistent>
<v-card class="rounded-lg elevation-8">
<v-toolbar color="primary" dark flat>
<v-toolbar-title class="d-flex align-center">
<v-icon class="me-2">mdi-loading</v-icon>
در حال انتقال
</v-toolbar-title>
</v-toolbar>
<v-card-text class="text-center pa-6">
<v-progress-circular indeterminate size="64" color="primary" class="mb-4"></v-progress-circular>
<div class="text-h6 mb-2">در حال انتقال...</div>
<div class="text-body-2 text-medium-emphasis">در حال انتقال به کسبوکار انتخاب شده</div>
</v-card-text>
</v-card>
</v-dialog>
<!-- دیالوگ موفقیت -->
<v-dialog v-model="successDialog" max-width="400">
<v-card class="rounded-lg elevation-8">
<v-toolbar color="success" dark flat>
<v-toolbar-title class="d-flex align-center">
<v-icon class="me-2">mdi-check-circle</v-icon>
انتقال موفق
</v-toolbar-title>
</v-toolbar>
<v-card-text class="text-center pa-6">
<v-avatar size="80" color="success-lighten-4" class="mb-3">
<v-icon size="40" color="success">mdi-check-circle</v-icon>
</v-avatar>
<div class="text-h6 mb-2">انتقال موفق</div>
<div class="text-body-1 text-medium-emphasis">به کسبوکار انتخاب شده منتقل شدید</div>
</v-card-text>
</v-card>
</v-dialog>
<!-- دیالوگ خطا -->
<v-dialog v-model="errorDialog" max-width="400">
<v-card class="rounded-lg elevation-8">
<v-toolbar color="error" dark flat>
<v-toolbar-title class="d-flex align-center">
<v-icon class="me-2">mdi-alert-circle</v-icon>
خطا
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon @click="errorDialog = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-toolbar>
<v-card-text class="text-center pa-6">
<v-avatar size="80" color="error-lighten-4" class="mb-3">
<v-icon size="40" color="error">mdi-alert-circle</v-icon>
</v-avatar>
<div class="text-h6 mb-2">خطا</div>
<div class="text-body-1 text-medium-emphasis">{{ errorMessage }}</div>
</v-card-text>
<v-card-actions class="pa-4">
<v-spacer></v-spacer>
<v-btn color="error" variant="outlined" @click="errorDialog = false" min-width="100">
<v-icon start>mdi-close</v-icon>
بستن
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import axios from "axios";
import { getApiUrl } from "@/hesabixConfig";
import { nextTick } from "vue";
export default {
name: "BusinessSwitcher",
data() {
return {
businesses: [],
selectedBusiness: null,
loading: false,
apiUrl: '',
confirmDialog: false,
loadingDialog: false,
successDialog: false,
errorDialog: false,
switching: false,
errorMessage: '',
pendingSwitchBid: null,
};
},
computed: {
selectedBusinessName() {
if (!this.pendingSwitchBid) return '';
const business = this.businesses.find(b => b.id === this.pendingSwitchBid);
return business ? business.name : '';
},
},
methods: {
async loadBusinesses() {
this.loading = true;
try {
const response = await axios.post('/api/business/list');
this.businesses = response.data;
// تنظیم selectedMoney برای هر کسبوکار
this.businesses.forEach(business => {
if (!business.selectedMoney && business.arzmain) {
business.selectedMoney = business.arzmain;
}
});
// تنظیم کسبوکار فعلی
const currentBid = localStorage.getItem('activeBid');
if (currentBid && this.businesses.length > 0) {
// تبدیل به عدد برای مقایسه صحیح
const currentBidNum = parseInt(currentBid);
// بررسی وجود کسبوکار در لیست
const exists = this.businesses.find(b => b.id === currentBidNum);
if (exists) {
this.selectedBusiness = currentBidNum;
} else {
// اگر کسبوکار فعلی در لیست نباشد، اولین را انتخاب کن
this.selectedBusiness = this.businesses[0].id;
}
} else if (this.businesses.length > 0) {
// اگر هیچ کسبوکاری انتخاب نشده، اولین را انتخاب کن
this.selectedBusiness = this.businesses[0].id;
}
} catch (error) {
console.error('خطا در دریافت لیست کسب‌وکارها:', error);
} finally {
this.loading = false;
}
},
async switchBusiness(newBid) {
if (!newBid || newBid === localStorage.getItem('activeBid')) {
return;
}
// پیدا کردن اطلاعات کسبوکار انتخاب شده
const selectedBusiness = this.businesses.find(b => b.id === newBid);
if (!selectedBusiness) {
this.errorMessage = 'کسب‌وکار یافت نشد';
this.errorDialog = true;
this.selectedBusiness = localStorage.getItem('activeBid');
return;
}
// نمایش دیالوگ تأیید
this.pendingSwitchBid = newBid;
this.confirmDialog = true;
},
async confirmSwitch() {
this.switching = true;
this.confirmDialog = false;
this.loadingDialog = true;
try {
const newBid = this.pendingSwitchBid;
const selectedBusiness = this.businesses.find(b => b.id === newBid);
// ذخیره اطلاعات کسبوکار جدید
localStorage.setItem('activeBid', newBid);
// بررسی وجود selectedMoney
if (selectedBusiness.selectedMoney) {
localStorage.setItem('activeMoney', selectedBusiness.selectedMoney.name);
localStorage.setItem('activeMoneySymbol', selectedBusiness.selectedMoney.symbol);
localStorage.setItem('activeMoneyShortName', selectedBusiness.selectedMoney.shortName);
localStorage.setItem('activeMoneyLabel', selectedBusiness.selectedMoney.label);
} else if (selectedBusiness.arzmain) {
// استفاده از arzmain به عنوان پشتیبان
localStorage.setItem('activeMoney', selectedBusiness.arzmain.name);
localStorage.setItem('activeMoneySymbol', selectedBusiness.arzmain.symbol);
localStorage.setItem('activeMoneyShortName', selectedBusiness.arzmain.shortName);
localStorage.setItem('activeMoneyLabel', selectedBusiness.arzmain.label);
} else {
// مقدار پیشفرض
localStorage.setItem('activeMoney', 'IRR');
localStorage.setItem('activeMoneySymbol', 'ریال');
localStorage.setItem('activeMoneyShortName', 'IRR');
localStorage.setItem('activeMoneyLabel', 'ریال ایران');
}
// دریافت سالهای مالی
const yearResponse = await axios.post('/api/year/list', {}, {
headers: {
activeBid: newBid
}
});
yearResponse.data.forEach((item) => {
if (item.head == '1') {
localStorage.setItem('activeYear', item.id);
}
});
// تنظیم هدرهای axios
axios.defaults.headers.common['activeBid'] = localStorage.getItem('activeBid');
axios.defaults.headers.common['activeYear'] = localStorage.getItem('activeYear');
axios.defaults.headers.common['activeMoney'] = localStorage.getItem('activeMoney');
// نمایش دیالوگ موفقیت
this.loadingDialog = false;
// اطمینان از بهروزرسانی DOM
await nextTick();
this.successDialog = true;
// رفرش صفحه بعد از 2 ثانیه
setTimeout(() => {
window.location.reload();
}, 2000);
} catch (error) {
console.error('خطا در تغییر کسب‌وکار:', error);
this.loadingDialog = false;
this.errorMessage = 'خطا در تغییر کسب‌وکار. لطفاً دوباره تلاش کنید.';
this.errorDialog = true;
// بازگرداندن مقدار قبلی
this.selectedBusiness = localStorage.getItem('activeBid');
} finally {
this.switching = false;
this.pendingSwitchBid = null;
}
},
cancelSwitch() {
this.confirmDialog = false;
this.pendingSwitchBid = null;
// بازگرداندن مقدار قبلی
this.selectedBusiness = localStorage.getItem('activeBid');
}
},
mounted() {
this.apiUrl = getApiUrl();
this.loadBusinesses();
}
};
</script>
<style scoped>
.business-switcher {
width: 100%;
max-width: 100%;
}
@media (max-width: 768px) {
.business-switcher {
width: 100%;
}
}
</style>

View file

@ -68,7 +68,7 @@ async function fetchAndCache(url, localStorageKey, defaultValue) {
export async function getSiteName() {
return fetchAndCache(
`${getApiUrl()}/system/getname`,
`${getApiUrl()}system/getname`,
KEYS.SITE_NAME,
DEFAULTS.SITE_NAME
);
@ -76,7 +76,7 @@ export async function getSiteName() {
export async function getSiteSlogan() {
return fetchAndCache(
`${getApiUrl()}/system/getslogon`,
`${getApiUrl()}system/getslogon`,
KEYS.SITE_SLOGON,
DEFAULTS.SITE_SLOGON
);

View file

@ -91,6 +91,7 @@ const en_lang = {
hrm_docs: 'Payroll Document',
warranty_system: 'Warranty System',
warranty_serials: 'Warranty Serials',
business_switcher: 'Switch Business',
},
};
export default en_lang

View file

@ -143,6 +143,7 @@ const fa_lang = {
recs_today: "دریافت‌های امروز",
sends_today: "پرداخت‌های امروز",
exit_bus: "ترک کسب‌و‌کار",
business_switcher: "تغییر کسب‌وکار",
persons_list: "فهرست اشخاص",
gets: "دریافت‌‌ها",
pays: "پرداخت‌ها",
@ -408,8 +409,8 @@ const fa_lang = {
fiscal_year: "سال مالی",
currency: "واحد پولی",
notifications: "اعلانات",
fiscal_settings: "تنظیمات مالی",
fiscal_settings_info: "در این بخش می‌توانید تنظیمات مربوط به موارد مالی کسب و کار را تغییر دهید.",
fiscal_settings: "تنظیمات کارتابل",
fiscal_settings_info: "در این بخش می‌توانید موارد مربوط به تنظیمات سریع کسب‌وکار را تغییر دهید.",
unread_notifications: "اعلانات خوانده نشده",
no_notification: "درحال حاضر هیچ اعلانی برای نمایش وجود ندارد !",
show_notifications: "مشاهده اعلانات",

View file

@ -9,6 +9,7 @@ import Profile_btn from '@/components/application/buttons/profile_btn.vue';
import Notifications_btn from '@/components/application/buttons/notifications_btn.vue';
import Year_cob from '@/components/application/combobox/year_cob.vue';
import Currency_cob from '@/components/application/combobox/currency_cob.vue';
import BusinessSwitcher from '@/components/application/combobox/business_switcher.vue';
import clock from '@/components/application/clock.vue';
import CalculatorDialog from '@/components/application/buttons/CalculatorDialog.vue'
import SecretDialog from '@/components/application/buttons/SecretDialog.vue';
@ -302,6 +303,7 @@ export default {
Notifications_btn,
Year_cob,
Currency_cob,
BusinessSwitcher,
clock,
CalculatorDialog,
SecretDialog,
@ -1084,10 +1086,13 @@ export default {
:title="$t('dialog.fiscal_settings')">
<v-card-text>
<v-row class="text-center">
<v-col cols="12" sm="12" md="6">
<v-col cols="12" sm="12" md="4">
<BusinessSwitcher />
</v-col>
<v-col cols="12" sm="12" md="4">
<Year_cob />
</v-col>
<v-col cols="12" sm="12" md="6">
<v-col cols="12" sm="12" md="4">
<Currency_cob />
</v-col>
</v-row>