2025-05-12 08:24:39 +00:00
|
|
|
|
<template>
|
2025-06-07 23:29:17 +00:00
|
|
|
|
<div>
|
|
|
|
|
<!-- Section Description -->
|
|
|
|
|
<div class="section-description">
|
|
|
|
|
<div class="section-title">مدیریت اعضا</div>
|
|
|
|
|
<p>در این بخش میتوانید اتاقها، فایلها و جلسات را با همکاران خود به اشتراک بگذارید و تیم خود را مدیریت کنید.</p>
|
2025-05-18 13:45:35 +00:00
|
|
|
|
</div>
|
2025-06-07 23:29:17 +00:00
|
|
|
|
|
|
|
|
|
<!-- Tab Buttons -->
|
|
|
|
|
<div class="tab-buttons">
|
|
|
|
|
<button
|
|
|
|
|
:class="['tab-btn', { active: activeTab === 'users' }]"
|
|
|
|
|
@click="activeTab = 'users'"
|
|
|
|
|
>کاربران</button>
|
|
|
|
|
<button
|
|
|
|
|
:class="['tab-btn', { active: activeTab === 'buy-subscription' }]"
|
|
|
|
|
@click="activeTab = 'buy-subscription'"
|
|
|
|
|
>خرید اشتراک</button>
|
|
|
|
|
<button
|
|
|
|
|
:class="['tab-btn', { active: activeTab === 'membership' }]"
|
|
|
|
|
@click="activeTab = 'membership'"
|
|
|
|
|
>اشتراکها</button>
|
|
|
|
|
<button
|
|
|
|
|
:class="['tab-btn', { active: activeTab === 'details' }]"
|
|
|
|
|
@click="activeTab = 'details'"
|
|
|
|
|
>جزئیات</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Tab Content -->
|
|
|
|
|
<div v-if="activeTab === 'users'">
|
|
|
|
|
<TeamUser
|
|
|
|
|
:user-list="userList"
|
|
|
|
|
:team-member-capacity="teamMemberCapacity"
|
|
|
|
|
:subscription-count="subscriptionCount"
|
|
|
|
|
:has-active-subscription="hasActiveSubscription"
|
|
|
|
|
@add-user="submitNewUser"
|
|
|
|
|
@change-tab="changeTab"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="activeTab === 'membership'">
|
|
|
|
|
<Membership
|
|
|
|
|
:subscription-count="subscriptionCount"
|
|
|
|
|
:team-member-capacity="teamMemberCapacity"
|
|
|
|
|
:is-billing-modal-visible="isBillingModalVisible"
|
|
|
|
|
@change-tab="changeTab"
|
|
|
|
|
@update:is-billing-modal-visible="isBillingModalVisible = $event"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="activeTab === 'details'">
|
|
|
|
|
<TeamDetails @update:team-data="handleTeamData" />
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="activeTab === 'buy-subscription'">
|
|
|
|
|
<BuySubscription
|
|
|
|
|
:member-count="memberCount"
|
|
|
|
|
:available-member-options="availableMemberOptions"
|
|
|
|
|
:base-url="baseUrl"
|
|
|
|
|
:has-active-subscription="hasActiveSubscription"
|
|
|
|
|
:has-expired-subscription="hasExpiredSubscription"
|
|
|
|
|
@update:member-count="memberCount = $event"
|
|
|
|
|
@payment-success="handlePaymentSuccess"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2025-05-12 08:24:39 +00:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
2025-05-27 00:01:58 +00:00
|
|
|
|
import TeamUser from '@/components/TeamUser.vue';
|
2025-05-28 14:06:19 +00:00
|
|
|
|
import BuySubscription from '@/components/BuySubscription.vue';
|
|
|
|
|
import Membership from '@/components/Membership.vue';
|
|
|
|
|
import TeamDetails from '@/components/TeamDetails.vue';
|
2025-05-27 00:01:58 +00:00
|
|
|
|
import axios from 'axios';
|
2025-05-12 08:24:39 +00:00
|
|
|
|
|
|
|
|
|
export default {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
name: 'Team',
|
|
|
|
|
components: { TeamUser, BuySubscription, Membership, TeamDetails },
|
2025-05-12 08:24:39 +00:00
|
|
|
|
data() {
|
|
|
|
|
return {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
activeTab: 'users',
|
|
|
|
|
userList: [],
|
2025-05-18 13:45:35 +00:00
|
|
|
|
memberCount: 5,
|
|
|
|
|
availableMemberOptions: [5, 10, 20, 100],
|
2025-05-28 08:42:55 +00:00
|
|
|
|
teamMemberCapacity: 0,
|
|
|
|
|
subscriptionCount: 0,
|
2025-06-07 23:29:17 +00:00
|
|
|
|
hasActiveSubscription: false,
|
|
|
|
|
hasExpiredSubscription: false, // جدید: بررسی اشتراک منقضیشده
|
|
|
|
|
subscriptionEndTime: null, // جدید: ذخیره تاریخ انقضای اشتراک
|
2025-06-05 17:33:09 +00:00
|
|
|
|
teamId: null,
|
2025-06-07 23:29:17 +00:00
|
|
|
|
subscriptionId: null,
|
|
|
|
|
isBillingModalVisible: false,
|
|
|
|
|
baseUrl: 'http://my.xroomapp.com:8000',
|
2025-05-27 00:01:58 +00:00
|
|
|
|
};
|
2025-05-12 08:24:39 +00:00
|
|
|
|
},
|
|
|
|
|
created() {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
this.initializeData();
|
2025-05-12 08:24:39 +00:00
|
|
|
|
},
|
|
|
|
|
methods: {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
async initializeData() {
|
|
|
|
|
const tab = this.$route.query.tab;
|
|
|
|
|
if (tab) this.activeTab = tab;
|
|
|
|
|
await Promise.all([
|
|
|
|
|
this.fetchUserData(),
|
|
|
|
|
this.fetchTeamMemberInfo(),
|
|
|
|
|
this.fetchTeamData(),
|
|
|
|
|
]);
|
|
|
|
|
},
|
2025-05-27 00:01:58 +00:00
|
|
|
|
changeTab(tabName) {
|
|
|
|
|
this.activeTab = tabName;
|
|
|
|
|
},
|
2025-06-05 17:33:09 +00:00
|
|
|
|
async fetchTeamData() {
|
|
|
|
|
try {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
const response = await this.axiosGet('/get_team');
|
2025-06-05 17:33:09 +00:00
|
|
|
|
const team = response.data.teams[0];
|
2025-06-07 23:29:17 +00:00
|
|
|
|
this.teamId = team?.id || null;
|
2025-06-05 17:33:09 +00:00
|
|
|
|
} catch (error) {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
console.error('Error fetching team data:', error);
|
|
|
|
|
alert('خطا در بارگذاری اطلاعات تیم.');
|
2025-06-05 17:33:09 +00:00
|
|
|
|
}
|
|
|
|
|
},
|
2025-05-28 08:42:55 +00:00
|
|
|
|
async fetchTeamMemberInfo() {
|
|
|
|
|
try {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
const response = await this.axiosGet('/get_all_team_members');
|
|
|
|
|
this.userList = response.data.members.map(member => ({
|
|
|
|
|
name: `${member.user.first_name} ${member.user.last_name}`,
|
|
|
|
|
email: member.user.username,
|
|
|
|
|
role: member.semat || 'کاربر',
|
2025-06-05 17:33:09 +00:00
|
|
|
|
version: 'نسخه آزمایشی',
|
2025-06-07 23:29:17 +00:00
|
|
|
|
avatar: member.profile_img || 'https://models.readyplayer.me/681f59760bc631a87ad25172.png',
|
2025-06-05 17:33:09 +00:00
|
|
|
|
}));
|
|
|
|
|
this.teamMemberCapacity = response.data.members.length;
|
2025-05-28 08:42:55 +00:00
|
|
|
|
} catch (error) {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
console.error('Error fetching team members:', error);
|
|
|
|
|
alert('خطا در بارگذاری اطلاعات اعضای تیم.');
|
2025-06-05 17:33:09 +00:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async fetchUserData() {
|
|
|
|
|
try {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
const response = await this.axiosGet('/get_user_subscriptions');
|
|
|
|
|
const subscriptions = response.data.subscriptions || [];
|
|
|
|
|
this.subscriptionCount = subscriptions.reduce((total, sub) => total + sub.user_count, 0);
|
|
|
|
|
this.subscriptionId = subscriptions[0]?.id || null;
|
|
|
|
|
this.subscriptionEndTime = subscriptions[0]?.endTime || null; // جدید: تاریخ انقضا
|
|
|
|
|
const now = new Date();
|
|
|
|
|
const isExpiredByTime = this.subscriptionEndTime && new Date(this.subscriptionEndTime) < now;
|
|
|
|
|
const isExpiredByCapacity = this.subscriptionCount <= this.teamMemberCapacity;
|
|
|
|
|
this.hasActiveSubscription = subscriptions.length > 0 && !isExpiredByTime && !isExpiredByCapacity;
|
|
|
|
|
this.hasExpiredSubscription = subscriptions.length > 0 && (isExpiredByTime || isExpiredByCapacity);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error fetching user data:', error);
|
|
|
|
|
alert('خطا در بارگذاری اطلاعات اشتراک.');
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async handlePaymentSuccess({ subscriptionId }) {
|
|
|
|
|
try {
|
|
|
|
|
this.subscriptionId = subscriptionId;
|
|
|
|
|
await Promise.all([
|
|
|
|
|
this.fetchUserData(),
|
|
|
|
|
this.fetchTeamMemberInfo(),
|
|
|
|
|
this.fetchTeamData(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if (!this.teamId && this.subscriptionId) {
|
|
|
|
|
await this.createTeam();
|
|
|
|
|
alert('اشتراک و تیم به درستی ساخته شد.');
|
|
|
|
|
} else if (this.teamId) {
|
|
|
|
|
alert('تیم از قبل وجود دارد.');
|
2025-06-05 17:33:09 +00:00
|
|
|
|
}
|
2025-06-07 23:29:17 +00:00
|
|
|
|
this.activeTab = 'membership';
|
2025-06-05 17:33:09 +00:00
|
|
|
|
} catch (error) {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
console.error('Error handling payment success:', error);
|
|
|
|
|
alert('خطا در پردازش پرداخت یا ساخت تیم.');
|
2025-05-28 08:42:55 +00:00
|
|
|
|
}
|
|
|
|
|
},
|
2025-06-07 23:29:17 +00:00
|
|
|
|
async createTeam() {
|
|
|
|
|
const teamData = {
|
|
|
|
|
name: 'تیم 1',
|
|
|
|
|
description: 'فعالیت',
|
|
|
|
|
max_persons: this.subscriptionCount.toString(),
|
|
|
|
|
subscriptionId: this.subscriptionId,
|
|
|
|
|
};
|
|
|
|
|
await this.axiosPost('/add_team', teamData);
|
|
|
|
|
await this.fetchTeamData();
|
|
|
|
|
},
|
2025-05-28 08:42:55 +00:00
|
|
|
|
async submitNewUser(newUser) {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
if (this.subscriptionCount - this.teamMemberCapacity <= 0) {
|
|
|
|
|
alert('اشتراک فعالی ندارید , اشتراک تهیه نمایید.');
|
2025-05-28 08:42:55 +00:00
|
|
|
|
this.activeTab = 'buy-subscription';
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-06-05 17:33:09 +00:00
|
|
|
|
if (!this.teamId) {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
alert('خطا: اطلاعات تیم یافت نشد.');
|
2025-06-05 17:33:09 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2025-05-28 08:42:55 +00:00
|
|
|
|
try {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
await this.axiosPost('/add_teamMember/', { ...newUser, teamId: this.teamId });
|
2025-05-28 08:42:55 +00:00
|
|
|
|
this.userList.push({
|
|
|
|
|
...newUser,
|
|
|
|
|
avatar: 'https://models.readyplayer.me/681f59760bc631a87ad25172.png',
|
|
|
|
|
role: newUser.role || 'کاربر',
|
|
|
|
|
version: newUser.version || 'نسخه آزمایشی',
|
|
|
|
|
});
|
2025-05-28 14:06:19 +00:00
|
|
|
|
this.teamMemberCapacity++;
|
2025-05-28 08:42:55 +00:00
|
|
|
|
await this.fetchTeamMemberInfo();
|
2025-06-07 23:29:17 +00:00
|
|
|
|
alert('کاربر با موفقیت اضافه شد.');
|
2025-05-28 08:42:55 +00:00
|
|
|
|
} catch (error) {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
console.error('Error adding user:', error);
|
|
|
|
|
alert('خطا در اضافه کردن کاربر.');
|
2025-05-28 08:42:55 +00:00
|
|
|
|
}
|
2025-05-27 00:01:58 +00:00
|
|
|
|
},
|
2025-06-07 23:29:17 +00:00
|
|
|
|
handleTeamData(data) {
|
|
|
|
|
console.log('Team data updated:', data);
|
2025-05-27 00:01:58 +00:00
|
|
|
|
},
|
2025-06-07 23:29:17 +00:00
|
|
|
|
async axiosGet(endpoint) {
|
|
|
|
|
const token = localStorage.getItem('token');
|
|
|
|
|
if (!token) throw new Error('توکن احراز هویت یافت نشد.');
|
|
|
|
|
return await axios.get(`${this.baseUrl}${endpoint}`, {
|
|
|
|
|
headers: { Authorization: `Token ${token}`, 'Content-Type': 'application/json' },
|
2025-05-27 00:01:58 +00:00
|
|
|
|
});
|
2025-05-12 08:24:39 +00:00
|
|
|
|
},
|
2025-06-07 23:29:17 +00:00
|
|
|
|
async axiosPost(endpoint, data) {
|
|
|
|
|
const token = localStorage.getItem('token');
|
|
|
|
|
if (!token) throw new Error('توکن احراز هویت یافت نشد.');
|
|
|
|
|
return await axios.post(`${this.baseUrl}${endpoint}`, data, {
|
|
|
|
|
headers: { Authorization: `Token ${token}`, 'Content-Type': 'application/json' },
|
|
|
|
|
});
|
2025-05-27 00:01:58 +00:00
|
|
|
|
},
|
|
|
|
|
},
|
2025-06-03 23:27:19 +00:00
|
|
|
|
watch: {
|
|
|
|
|
'$route.query.tab'(newTab) {
|
2025-06-07 23:29:17 +00:00
|
|
|
|
if (newTab) this.activeTab = newTab;
|
2025-06-05 17:33:09 +00:00
|
|
|
|
},
|
|
|
|
|
},
|
2025-05-27 00:01:58 +00:00
|
|
|
|
};
|
2025-05-12 08:24:39 +00:00
|
|
|
|
</script>
|
2025-05-28 14:06:19 +00:00
|
|
|
|
|
2025-06-07 23:29:17 +00:00
|
|
|
|
|
2025-05-28 14:06:19 +00:00
|
|
|
|
<style scoped>
|
2025-05-12 08:24:39 +00:00
|
|
|
|
|
|
|
|
|
.section-title {
|
2025-06-11 15:42:22 +00:00
|
|
|
|
font-weight: 700;
|
|
|
|
|
color: #101010;
|
|
|
|
|
font-size: 19px;
|
|
|
|
|
line-height: 26.6px;
|
2025-05-30 15:41:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-description {
|
2025-06-11 15:42:22 +00:00
|
|
|
|
margin: 1rem 0 3rem;
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #2d3748;
|
2025-05-30 15:41:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-description p {
|
2025-06-11 15:42:22 +00:00
|
|
|
|
line-height: 190%;
|
|
|
|
|
color: #4f5a69;
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
margin-top: 1rem;
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
text-align: justify;
|
2025-05-12 08:24:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-12 13:14:57 +00:00
|
|
|
|
.tab-buttons {
|
|
|
|
|
display: flex;
|
2025-05-28 14:06:19 +00:00
|
|
|
|
gap: 25px;
|
|
|
|
|
margin-top: 2rem;
|
|
|
|
|
margin-bottom: 2rem;
|
2025-06-11 15:42:22 +00:00
|
|
|
|
justify-content: space-between;
|
|
|
|
|
padding : 8px;
|
2025-05-12 13:14:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-btn {
|
|
|
|
|
background: none;
|
|
|
|
|
border: none;
|
|
|
|
|
color: gray;
|
2025-06-11 15:42:22 +00:00
|
|
|
|
font-size: 16px;
|
2025-05-12 13:14:57 +00:00
|
|
|
|
padding: 8px 16px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
border-bottom: 2px solid transparent;
|
|
|
|
|
transition: all 0.2s ease-in-out;
|
2025-06-11 15:42:22 +00:00
|
|
|
|
padding-right: 0px;
|
|
|
|
|
padding-left: 0;
|
2025-05-12 13:14:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-btn.active {
|
|
|
|
|
color: #3a57e8;
|
|
|
|
|
border-bottom: 2px solid #3a57e8;
|
2025-06-11 15:42:22 +00:00
|
|
|
|
font-size: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (min-width: 600px) and (max-width: 1024px) {
|
|
|
|
|
.tab-buttons {
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@media (min-width: 1024px) and (max-width: 1280px) {
|
|
|
|
|
.section-title {
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #101010;
|
|
|
|
|
margin: 20px 0 10px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@media (min-width: 1280px) {
|
|
|
|
|
.section-title {
|
|
|
|
|
font-size: 21px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-description p {
|
|
|
|
|
font-size: 17.5px;
|
|
|
|
|
}
|
|
|
|
|
.tab-btn {
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
padding: 8px 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-btn.active {
|
|
|
|
|
font-size: 21px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-buttons {
|
|
|
|
|
padding: 0;
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
}
|
2025-05-12 13:14:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-27 00:01:58 +00:00
|
|
|
|
|
2025-05-28 14:06:19 +00:00
|
|
|
|
</style>
|