feat: add profile, class unenroll, notify toggles, and keep sidebar width
Give admins a profile password page, class removal, and SMS/email/bot checkboxes, and stop the sidebar from shrinking on edit pages.
This commit is contained in:
@@ -52,6 +52,22 @@
|
||||
<Column header="موبایل">
|
||||
<template #body="{ data }"><span dir="ltr">{{ data.phoneNumber || '—' }}</span></template>
|
||||
</Column>
|
||||
<Column v-if="canManageStudents" header="عملیات" style="width: 90px">
|
||||
<template #body="{ data }">
|
||||
<PermissionGate permission="classes:register_users">
|
||||
<Button
|
||||
icon="pi pi-user-minus"
|
||||
text
|
||||
rounded
|
||||
size="small"
|
||||
severity="danger"
|
||||
v-tooltip.top="'حذف از کلاس'"
|
||||
:loading="removingUserId === String(data._id || data.id)"
|
||||
@click="confirmRemoveStudent(data)"
|
||||
/>
|
||||
</PermissionGate>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
|
||||
@@ -94,19 +110,30 @@
|
||||
</Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
|
||||
<ConfirmDeleteDialog
|
||||
v-model="removeDialogVisible"
|
||||
title="حذف از کلاس"
|
||||
:message="removeDialogMessage"
|
||||
:loading="!!removingUserId"
|
||||
@confirm="handleRemoveStudent"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { classApi } from '@/api/classApi';
|
||||
import { sessionApi } from '@/api/sessionApi';
|
||||
import { usePersianDate } from '@/composables/usePersianDate';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { usePermission } from '@/composables/usePermission';
|
||||
import PageHeader from '@/components/common/PageHeader.vue';
|
||||
import StatusTag from '@/components/common/StatusTag.vue';
|
||||
import TableSkeleton from '@/components/common/TableSkeleton.vue';
|
||||
import ConfirmDeleteDialog from '@/components/common/ConfirmDeleteDialog.vue';
|
||||
import PermissionGate from '@/components/common/PermissionGate.vue';
|
||||
import Button from 'primevue/button';
|
||||
import DataTable from 'primevue/datatable';
|
||||
import Column from 'primevue/column';
|
||||
@@ -114,11 +141,23 @@ import Column from 'primevue/column';
|
||||
const route = useRoute();
|
||||
const classId = route.params.id;
|
||||
const { toPersianDigits, formatJalali } = usePersianDate();
|
||||
const { showError } = useToast();
|
||||
const { showError, showSuccess } = useToast();
|
||||
const { hasPermission } = usePermission();
|
||||
const canManageStudents = computed(() => hasPermission('classes:register_users'));
|
||||
|
||||
const classData = ref(null);
|
||||
const sessions = ref([]);
|
||||
const loadingSessions = ref(false);
|
||||
const removeDialogVisible = ref(false);
|
||||
const removingUserId = ref('');
|
||||
const studentToRemove = ref(null);
|
||||
|
||||
const removeDialogMessage = computed(() => {
|
||||
const name = studentToRemove.value?.name;
|
||||
return name
|
||||
? `آیا «${name}» از این کلاس حذف شود؟`
|
||||
: 'آیا این دانشجو از کلاس حذف شود؟';
|
||||
});
|
||||
|
||||
const fetchClass = async () => {
|
||||
try {
|
||||
@@ -159,4 +198,26 @@ onMounted(() => {
|
||||
fetchClass();
|
||||
fetchSessions();
|
||||
});
|
||||
|
||||
const confirmRemoveStudent = (student) => {
|
||||
studentToRemove.value = student;
|
||||
removeDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleRemoveStudent = async () => {
|
||||
const userId = studentToRemove.value?._id || studentToRemove.value?.id;
|
||||
if (!userId) return;
|
||||
removingUserId.value = String(userId);
|
||||
try {
|
||||
const res = await classApi.removeUser(classId, userId);
|
||||
classData.value = res.data || res;
|
||||
removeDialogVisible.value = false;
|
||||
studentToRemove.value = null;
|
||||
showSuccess('دانشجو از کلاس حذف شد');
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
} finally {
|
||||
removingUserId.value = '';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -96,6 +96,10 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<NotifyChannelsField :notify="registerNotify" />
|
||||
</div>
|
||||
|
||||
<DataTable :value="students" class="p-datatable-sm text-sm" emptyMessage="هنوز دانشجویی ثبتنام نشده است">
|
||||
<Column header="#" style="width: 50px">
|
||||
<template #body="{ index }">{{ toPersianDigits(index + 1) }}</template>
|
||||
@@ -108,6 +112,22 @@
|
||||
<span dir="ltr">{{ data.phoneNumber || '—' }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column v-if="canManageStudents" header="عملیات" style="width: 90px">
|
||||
<template #body="{ data }">
|
||||
<PermissionGate permission="classes:register_users">
|
||||
<Button
|
||||
icon="pi pi-user-minus"
|
||||
text
|
||||
rounded
|
||||
size="small"
|
||||
severity="danger"
|
||||
v-tooltip.top="'حذف از کلاس'"
|
||||
:loading="removingUserId === String(data._id || data.id)"
|
||||
@click="confirmRemoveStudent(data)"
|
||||
/>
|
||||
</PermissionGate>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
|
||||
@@ -119,6 +139,14 @@
|
||||
:default-session-count="defaultSessionCount"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<ConfirmDeleteDialog
|
||||
v-model="removeDialogVisible"
|
||||
title="حذف از کلاس"
|
||||
:message="removeDialogMessage"
|
||||
:loading="!!removingUserId"
|
||||
@confirm="handleRemoveStudent"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -132,9 +160,13 @@ import { professorApi } from '@/api/professorApi';
|
||||
import { userApi } from '@/api/userApi';
|
||||
import { usePersianDate } from '@/composables/usePersianDate';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { usePermission } from '@/composables/usePermission';
|
||||
import PageHeader from '@/components/common/PageHeader.vue';
|
||||
import AdminNotesField from '@/components/common/AdminNotesField.vue';
|
||||
import ClassSessionsSection from '@/components/classes/ClassSessionsSection.vue';
|
||||
import NotifyChannelsField from '@/components/common/NotifyChannelsField.vue';
|
||||
import ConfirmDeleteDialog from '@/components/common/ConfirmDeleteDialog.vue';
|
||||
import PermissionGate from '@/components/common/PermissionGate.vue';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import InputNumber from 'primevue/inputnumber';
|
||||
import Dropdown from 'primevue/select';
|
||||
@@ -149,14 +181,20 @@ import DatePicker from 'vue3-persian-datetime-picker';
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { showSuccess, showError } = useToast();
|
||||
const { hasPermission } = usePermission();
|
||||
const { toPersianDigits, toLatinDigits } = usePersianDate();
|
||||
|
||||
const classId = route.params.id;
|
||||
const queryCourseId = route.query.courseId ? String(route.query.courseId) : null;
|
||||
const isEditMode = computed(() => !!classId);
|
||||
const canManageStudents = computed(() => hasPermission('classes:register_users'));
|
||||
const isSubmitting = ref(false);
|
||||
const registering = ref(false);
|
||||
const defaultSessionCount = ref(12);
|
||||
const registerNotify = reactive({ sms: true, email: true, bot: true });
|
||||
const removeDialogVisible = ref(false);
|
||||
const removingUserId = ref('');
|
||||
const studentToRemove = ref(null);
|
||||
|
||||
const courses = ref([]);
|
||||
const professors = ref([]);
|
||||
@@ -176,6 +214,13 @@ const form = reactive({
|
||||
adminNotes: []
|
||||
});
|
||||
|
||||
const removeDialogMessage = computed(() => {
|
||||
const name = studentToRemove.value?.name;
|
||||
return name
|
||||
? `آیا «${name}» از این کلاس حذف شود؟`
|
||||
: 'آیا این دانشجو از کلاس حذف شود؟';
|
||||
});
|
||||
|
||||
const availableUsers = computed(() => {
|
||||
const enrolled = new Set(students.value.map((s) => String(s._id)));
|
||||
return allUsers.value
|
||||
@@ -308,7 +353,7 @@ const registerSelected = async () => {
|
||||
if (!selectedUserIds.value.length) return;
|
||||
registering.value = true;
|
||||
try {
|
||||
const res = await classApi.registerUsers(classId, selectedUserIds.value);
|
||||
const res = await classApi.registerUsers(classId, selectedUserIds.value, { ...registerNotify });
|
||||
const data = res.data || res;
|
||||
students.value = data.students || [];
|
||||
selectedUserIds.value = [];
|
||||
@@ -320,5 +365,28 @@ const registerSelected = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const confirmRemoveStudent = (student) => {
|
||||
studentToRemove.value = student;
|
||||
removeDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleRemoveStudent = async () => {
|
||||
const userId = studentToRemove.value?._id || studentToRemove.value?.id;
|
||||
if (!userId) return;
|
||||
removingUserId.value = String(userId);
|
||||
try {
|
||||
const res = await classApi.removeUser(classId, userId);
|
||||
const data = res.data || res;
|
||||
students.value = data.students || [];
|
||||
removeDialogVisible.value = false;
|
||||
studentToRemove.value = null;
|
||||
showSuccess('دانشجو از کلاس حذف شد');
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
} finally {
|
||||
removingUserId.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(fetchData);
|
||||
</script>
|
||||
|
||||
@@ -120,6 +120,8 @@
|
||||
<label class="font-semibold text-sm">تاریخ سررسید *</label>
|
||||
<DatePicker v-model="createForm.dueDate" class="w-full text-sm" placeholder="1403/01/01" />
|
||||
</div>
|
||||
|
||||
<NotifyChannelsField :notify="createNotify" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button label="انصراف" text severity="secondary" @click="showCreateModal = false" />
|
||||
@@ -148,6 +150,7 @@ import DataTableWrapper from '@/components/common/DataTableWrapper.vue';
|
||||
import ConfirmDeleteDialog from '@/components/common/ConfirmDeleteDialog.vue';
|
||||
import PermissionGate from '@/components/common/PermissionGate.vue';
|
||||
import StatusTag from '@/components/common/StatusTag.vue';
|
||||
import NotifyChannelsField from '@/components/common/NotifyChannelsField.vue';
|
||||
import Button from 'primevue/button';
|
||||
import Column from 'primevue/column';
|
||||
import Tag from 'primevue/tag';
|
||||
@@ -182,6 +185,7 @@ const createForm = reactive({
|
||||
amount: 0,
|
||||
dueDate: ''
|
||||
});
|
||||
const createNotify = reactive({ sms: true, email: true, bot: true });
|
||||
|
||||
const deleteDialogVisible = ref(false);
|
||||
const selectedPayment = ref(null);
|
||||
@@ -238,6 +242,9 @@ const resetCreateForm = () => {
|
||||
createForm.classes = [];
|
||||
createForm.amount = 0;
|
||||
createForm.dueDate = '';
|
||||
createNotify.sms = true;
|
||||
createNotify.email = true;
|
||||
createNotify.bot = true;
|
||||
};
|
||||
|
||||
const openCreateModal = () => {
|
||||
@@ -270,7 +277,7 @@ const handleCreatePayment = async () => {
|
||||
|
||||
isCreating.value = true;
|
||||
try {
|
||||
await paymentApi.create(createForm);
|
||||
await paymentApi.create({ ...createForm, notify: { ...createNotify } });
|
||||
showSuccess('صورتحساب جدید با موفقیت ایجاد شد');
|
||||
showCreateModal.value = false;
|
||||
loadData();
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
<!-- /src/views/profile/ProfileView.vue -->
|
||||
<template>
|
||||
<div class="profile-view w-full max-w-4xl mx-auto">
|
||||
<PageHeader title="پروفایل من" subtitle="مشاهده اطلاعات حساب و تغییر رمز عبور" />
|
||||
|
||||
<div v-if="isLoading" class="surface-card p-5 border-round border-1 border-color shadow-sm">
|
||||
<p class="text-muted text-sm m-0">در حال بارگذاری پروفایل…</p>
|
||||
</div>
|
||||
|
||||
<template v-else-if="profile">
|
||||
<div class="surface-card p-4 sm:p-5 border-round border-1 border-color shadow-sm mb-4">
|
||||
<div class="flex align-items-center gap-3 mb-4 pb-3 border-bottom-1 border-color">
|
||||
<Avatar icon="pi pi-user" size="large" shape="circle" class="bg-primary text-white" />
|
||||
<div>
|
||||
<h2 class="text-lg font-bold text-color m-0">{{ profile.name || profile.username }}</h2>
|
||||
<p class="text-muted text-sm m-0 mt-1" dir="ltr">{{ profile.username }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 sm:col-6 md:col-4 mb-3">
|
||||
<span class="text-muted text-xs block mb-1">نام</span>
|
||||
<span class="font-semibold text-color text-sm">{{ profile.name || '—' }}</span>
|
||||
</div>
|
||||
<div class="col-12 sm:col-6 md:col-4 mb-3">
|
||||
<span class="text-muted text-xs block mb-1">نام کاربری</span>
|
||||
<span class="font-semibold text-color text-sm" dir="ltr">{{ profile.username || '—' }}</span>
|
||||
</div>
|
||||
<div class="col-12 sm:col-6 md:col-4 mb-3">
|
||||
<span class="text-muted text-xs block mb-1">نقش</span>
|
||||
<Tag :value="roleLabel" severity="info" />
|
||||
</div>
|
||||
<div class="col-12 sm:col-6 md:col-4 mb-3">
|
||||
<span class="text-muted text-xs block mb-1">شماره همراه</span>
|
||||
<span class="font-semibold text-color text-sm" dir="ltr">{{ profile.phoneNumber || '—' }}</span>
|
||||
</div>
|
||||
<div class="col-12 sm:col-6 md:col-4 mb-3">
|
||||
<span class="text-muted text-xs block mb-1">ایمیل</span>
|
||||
<span class="font-semibold text-color text-sm" dir="ltr">{{ profile.email || '—' }}</span>
|
||||
</div>
|
||||
<div class="col-12 sm:col-6 md:col-4 mb-3">
|
||||
<span class="text-muted text-xs block mb-1">وضعیت حساب</span>
|
||||
<StatusTag :status="profile.isActive !== false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-card p-4 sm:p-5 border-round border-1 border-color shadow-sm">
|
||||
<h2 class="text-lg font-bold text-color m-0 mb-1">تغییر رمز عبور</h2>
|
||||
<p class="text-muted text-sm mt-1 mb-4">
|
||||
برای تغییر رمز، ابتدا رمز فعلی را وارد کنید. پس از ذخیره، نشستهای دیگر از حساب خارج میشوند.
|
||||
</p>
|
||||
|
||||
<form @submit.prevent="handleChangePassword" class="grid">
|
||||
<div class="col-12 md:col-6 flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm" for="current-password">رمز عبور فعلی *</label>
|
||||
<Password
|
||||
inputId="current-password"
|
||||
v-model="passwordForm.currentPassword"
|
||||
toggleMask
|
||||
:feedback="false"
|
||||
class="w-full"
|
||||
inputClass="w-full text-sm"
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 md:col-6"></div>
|
||||
<div class="col-12 md:col-6 flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm" for="new-password">رمز عبور جدید *</label>
|
||||
<Password
|
||||
inputId="new-password"
|
||||
v-model="passwordForm.newPassword"
|
||||
toggleMask
|
||||
:feedback="false"
|
||||
class="w-full"
|
||||
inputClass="w-full text-sm"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
<span class="text-xs text-muted">حداقل ۶ نویسه</span>
|
||||
</div>
|
||||
<div class="col-12 md:col-6 flex flex-column gap-2">
|
||||
<label class="font-semibold text-sm" for="confirm-password">تکرار رمز عبور جدید *</label>
|
||||
<Password
|
||||
inputId="confirm-password"
|
||||
v-model="passwordForm.confirmPassword"
|
||||
toggleMask
|
||||
:feedback="false"
|
||||
class="w-full"
|
||||
inputClass="w-full text-sm"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 flex justify-content-end gap-2 mt-3 pt-3 border-top-1 border-color">
|
||||
<Button type="submit" label="تغییر رمز عبور" icon="pi pi-lock" :loading="isSubmitting" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { authApi } from '@/api/authApi';
|
||||
import { useAuthStore } from '@/stores/authStore';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import PageHeader from '@/components/common/PageHeader.vue';
|
||||
import StatusTag from '@/components/common/StatusTag.vue';
|
||||
import Avatar from 'primevue/avatar';
|
||||
import Tag from 'primevue/tag';
|
||||
import Password from 'primevue/password';
|
||||
import Button from 'primevue/button';
|
||||
|
||||
const MIN_PASSWORD_LENGTH = 6;
|
||||
const authStore = useAuthStore();
|
||||
const { showSuccess, showError } = useToast();
|
||||
|
||||
const isLoading = ref(true);
|
||||
const isSubmitting = ref(false);
|
||||
const profile = ref(null);
|
||||
|
||||
const passwordForm = reactive({
|
||||
currentPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
});
|
||||
|
||||
const roleLabel = computed(() => {
|
||||
const role = profile.value?.role;
|
||||
if (!role) return '—';
|
||||
return typeof role === 'object' ? (role.name || '—') : String(role);
|
||||
});
|
||||
|
||||
const resetPasswordForm = () => {
|
||||
passwordForm.currentPassword = '';
|
||||
passwordForm.newPassword = '';
|
||||
passwordForm.confirmPassword = '';
|
||||
};
|
||||
|
||||
const fetchProfile = async () => {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
const res = await authApi.getSelf();
|
||||
profile.value = res.data || res;
|
||||
if (profile.value) {
|
||||
authStore.setUser({
|
||||
...(authStore.user || {}),
|
||||
...profile.value
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangePassword = async () => {
|
||||
if (!passwordForm.currentPassword) {
|
||||
showError('رمز عبور فعلی را وارد کنید');
|
||||
return;
|
||||
}
|
||||
if (!passwordForm.newPassword || passwordForm.newPassword.length < MIN_PASSWORD_LENGTH) {
|
||||
showError('رمز عبور جدید باید حداقل ۶ نویسه باشد');
|
||||
return;
|
||||
}
|
||||
if (passwordForm.newPassword !== passwordForm.confirmPassword) {
|
||||
showError('رمز عبور جدید و تکرار آن یکسان نیستند');
|
||||
return;
|
||||
}
|
||||
if (passwordForm.newPassword === passwordForm.currentPassword) {
|
||||
showError('رمز عبور جدید باید با رمز فعلی متفاوت باشد');
|
||||
return;
|
||||
}
|
||||
|
||||
isSubmitting.value = true;
|
||||
try {
|
||||
await authApi.changePassword({
|
||||
currentPassword: passwordForm.currentPassword,
|
||||
newPassword: passwordForm.newPassword,
|
||||
refreshToken: authStore.refreshToken
|
||||
});
|
||||
resetPasswordForm();
|
||||
showSuccess('رمز عبور با موفقیت تغییر کرد');
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
} finally {
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(fetchProfile);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.p-password) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.p-password-input) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="user-form-view w-full max-w-4xl mx-auto">
|
||||
<PageHeader
|
||||
:title="isEditMode ? $t('users.editUser') : $t('users.addUser')"
|
||||
:subtitle="isEditMode ? 'ویرایش اطلاعات حساب کاربر' : 'ایجاد حساب کاربری جدید — نام کاربری و رمز عبور بهصورت خودکار ساخته و پیامک میشود'"
|
||||
:subtitle="isEditMode ? 'ویرایش اطلاعات حساب کاربر' : 'ایجاد حساب کاربری جدید — نام کاربری و رمز عبور بهصورت خودکار ساخته میشود'"
|
||||
>
|
||||
<Button label="انصراف" text severity="secondary" @click="$router.push('/users')" />
|
||||
</PageHeader>
|
||||
@@ -123,9 +123,13 @@
|
||||
<InputText v-model="form.password" type="password" class="w-full text-sm" dir="ltr" placeholder="در صورت عدم تغییر خالی بگذارید" />
|
||||
</div>
|
||||
|
||||
<div v-if="!isEditMode" class="col-12">
|
||||
<NotifyChannelsField :notify="createNotify" />
|
||||
</div>
|
||||
|
||||
<div v-if="!isEditMode" class="col-12">
|
||||
<p class="text-sm text-color-secondary m-0 line-height-3">
|
||||
نام کاربری و رمز عبور ساده بهصورت خودکار ساخته میشود و از طریق پیامک برای کاربر ارسال میگردد. بعداً میتوان رمز را تغییر داد.
|
||||
نام کاربری و رمز عبور ساده بهصورت خودکار ساخته میشود. اگر ارسال پیامک فعال باشد، اطلاعات ورود برای کاربر پیامک میگردد. بعداً میتوان رمز را تغییر داد.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -176,6 +180,7 @@ import { useToast } from '@/composables/useToast';
|
||||
import PageHeader from '@/components/common/PageHeader.vue';
|
||||
import AdminNotesField from '@/components/common/AdminNotesField.vue';
|
||||
import UserFilesSection from '@/components/uploader/UserFilesSection.vue';
|
||||
import NotifyChannelsField from '@/components/common/NotifyChannelsField.vue';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import Dropdown from 'primevue/select';
|
||||
import MultiSelect from 'primevue/multiselect';
|
||||
@@ -193,6 +198,7 @@ const filesSection = ref(null);
|
||||
const roles = ref([]);
|
||||
const credentialsVisible = ref(false);
|
||||
const createdCredentials = reactive({ username: '', password: '' });
|
||||
const createNotify = reactive({ sms: true, email: true, bot: true });
|
||||
|
||||
const messengerOptions = [
|
||||
{ label: 'پیامک (SMS)', value: 'SMS' },
|
||||
@@ -342,7 +348,7 @@ const handleSubmit = async () => {
|
||||
showSuccess('اطلاعات کاربر با موفقیت ویرایش شد');
|
||||
router.push('/users');
|
||||
} else {
|
||||
const res = await userApi.create(payload);
|
||||
const res = await userApi.create({ ...payload, notify: { ...createNotify } });
|
||||
const data = res.data || res;
|
||||
const creds = data.generatedCredentials || {};
|
||||
createdCredentials.username = creds.username || data.username || '';
|
||||
|
||||
Reference in New Issue
Block a user