Merge branch 'shadi/develop' of https://git2.tavasi.ir/front/base_ui into main

This commit is contained in:
mustafa-rezae 2025-02-23 08:47:05 +03:30
commit 28bd8de77a
49 changed files with 8025 additions and 3379 deletions

View File

@ -0,0 +1,276 @@
<template>
<div>
<div class="mb-5">
<select
name="project_id"
id="project_id"
v-model="project_id"
class="form-control text__14"
>
<option class="text-black-50" disabled :value="undefined" selected>
{{ $t("ProjectSelection") }}
</option>
<option
v-for="(project, index1) in projects"
:key="index1"
:value="project.id"
>
{{ project.title }}
</option>
</select>
</div>
<div class="accordion" id="permission-accordion">
<div
v-for="(item, key, index) in groupbyList"
:key="index"
class="card border-0"
>
<div class="card-header border-bottom-0 p-0" :id="'heading' + index">
<button
class="btn btn-link btn-block has-indicator"
type="button"
data-bs-toggle="collapse"
:data-bs-target="'#collapse' + index"
:aria-expanded="!collapseAll"
:class="{ collapsed: collapseAll }"
:aria-controls="'collapse' + index"
>
{{ key }}
</button>
</div>
<div
:id="'collapse' + index"
class="collapse"
:class="{ show: !collapseAll }"
:aria-labelledby="'heading' + index"
data-parent="#permission-accordion"
>
<div class="card-body">
<ul class="list-group list-group-flush">
<li
:key="index"
v-for="(action, index2) in groupItems(key)"
class="list-group-item text__14"
>
<div class="form-check d-flex align-items-center">
<input
v-can.checkbox="canEdit"
@change.prevent="changePermission(action)"
class="form-check-input"
type="checkbox"
value=""
:checked="action.check"
:value="action.check"
:id="'role-' + index2"
/>
<label class="form-check-label mt-2" :for="'role-' + index">
{{ action.action_title }}
</label>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import apis from "~/apis/permitApi";
// import { mapGetters, mapMutations, mapActions } from "vuex";
import { mapActions, mapState } from "pinia";
import { usePermitStore } from "~/stores/permitStore";
export default {
props: {
user_id: {
type: Number,
default: undefined,
},
role_id: {
type: Number,
default: undefined,
},
canEdit: {
type: String,
default(val) {},
},
},
data() {
return {
listUserPermission: [],
collapseAll: false,
grouplist: [],
groupbyList: {},
roles: [],
httpService: {},
};
},
computed: {
// ...mapGetters("permit", ["projectsGetter", "projectGetter"]),
...mapState(usePermitStore, ["projectGetter", "projectsGetter"]),
projects() {
return this.projectsGetter ?? [];
},
project_id: {
get() {
return this.projectGetter?.id;
},
set(newVal) {
this.setProject(newVal);
},
},
},
mounted() {
this.getRoles();
},
created() {
this.httpService = useNuxtApp()["$http"];
},
methods: {
// ...mapMutations("permit", ["SET_PROJECT"]),
// ...mapActions("permit", ["getProjects"]),
...mapActions(usePermitStore, ["SET_PROJECT"]),
...mapActions(usePermitStore, ["getProjects"]),
getRoles() {
const payload = {
user_id: this.user_id,
role_id: this.role_id,
project_id: this.projectGetter?.id,
};
const { listUserPermission, listRolePermission } = apis.permissions;
const url = this.user_id ? listUserPermission : listRolePermission;
this.httpService.postRequest(permitUrl() + url, payload).then(({ data }) => {
this.listUserPermission = data;
this.groupbyList = this.groupBy(data, "section_title");
});
},
toggleRolesPanel() {},
groupBy(arrayToGroup, key) {
return arrayToGroup.reduce(function (previousValue, currentValue) {
(previousValue[currentValue[key]] =
previousValue[currentValue[key]] || []).push({
action_title: currentValue.action_title,
check: currentValue.check,
section_title: currentValue.section_title,
section_id: currentValue.id,
section_user_id: currentValue?.section_user_id,
section_role_id: currentValue?.section_role_id,
});
return previousValue;
}, {});
},
groupItems(section_title) {
return this.groupbyList[section_title];
},
changePermission(action) {
action.check
? this.deletePermission(action)
: this.addOrUpdatePermission(action);
},
addOrUpdatePermission(action) {
const payload = {
user_id: this.user_id,
role_id: this.role_id,
project_id: this.projectGetter?.id,
section_id: action.section_id,
state: 0,
section_user_id: action.section_user_id ?? undefined,
section_role_id: action.section_role_id ?? undefined,
};
const {
addOrEditUserPermission,
addOrEditRolePermission,
addOrEditLoginRolePermission,
} = apis.permissions;
let url = this.user_id
? addOrEditUserPermission
: addOrEditRolePermission;
// حالت دسترسی تشویقی
if (this.role_id === -1) url = addOrEditLoginRolePermission;
this.httpService.postRequest(url, payload).then(({ data }) => {
mySwalToast({
title: "تبریک",
html: data.message,
icon: "success",
});
this.getRoles();
// action.check = true;
});
},
deletePermission(action) {
const payload = {
project_id: this.projectGetter?.id,
id: action.section_user_id ?? undefined,
};
if (action.section_role_id) payload.id = action.section_role_id;
const { deleteUserPermission, deleteRolePermission } = apis.permissions;
const url = this.user_id ? deleteUserPermission : deleteRolePermission;
this.httpService.postRequest(url, payload).then(({ data }) => {
mySwalToast({
title: "تبریک",
html: data.message,
icon: "success",
});
this.getRoles();
// action.check = false;
});
},
async getProjects() {
return await this.httpService
.postRequest(permitUrl() + apis.projects.list)
.then((res) => {
this.SET_PROJECT(res.data[0]);
});
},
setProject(id) {
// const id = +$ev.target.value;
const result = this.projects.findIndex((item) => item.id === id);
const project = this.projects[result];
this.SET_PROJECT(project);
this.getRoles();
},
},
watch: {
role_id() {
this.getRoles();
},
user_id() {
this.getRoles();
},
},
};
</script>
<style lang="scss" scoped>
.role-permission {
.form-check {
padding-right: 0;
}
.form-check-input {
margin-left: 1em;
margin-top: 0em !important;
&::before {
content: "";
right: unset;
top: unset;
}
}
}
</style>

View File

@ -9,7 +9,7 @@
<ul class="list-unstyled components">
<li class="active">
<a href="#homeSubmenu" data-toggle="collapse" aria-expanded="false" class="dropdown-toggle">
<a href="#homeSubmenu" data-bs-toggle="collapse" aria-expanded="false" class="dropdown-toggle">
<i class="fas fa-home"></i>
Home
</a>
@ -30,7 +30,7 @@
<i class="fas fa-briefcase"></i>
About
</a>
<a href="#pageSubmenu" data-toggle="collapse" aria-expanded="false" class="dropdown-toggle">
<a href="#pageSubmenu" data-bs-toggle="collapse" aria-expanded="false" class="dropdown-toggle">
<i class="fas fa-copy"></i>
Pages
</a>

View File

@ -0,0 +1,86 @@
<template>
<div class="side-panel">
<div class="side-panel-header">
<h6 class="text-center">
مشخصات کامل مورد جاری
</h6>
</div>
<div class="border redios-castom px-3 py-2 ">
<div class="side-panel-content">
<form-builder
:previewMode="true"
:formElements="clonedFormElements"
:formData="selectedItem"
></form-builder>
</div>
<div class="d-flex justify-content-between">
<button-component
classes="d-inline-flex btn-default"
@click="closeFormShow"
buttonText=""
>
<span class="tavasi tavasi-Component-71--1"></span>
</button-component>
<button-component
classes="d-inline-flex btn-default"
@click="editItem"
buttonText=""
>
<i class="tavasi tavasi-Component-242--1"></i>
</button-component>
</div>
</div>
</div>
</template>
<script>
export default {
props: ["selectedItem"],
emits: ["close-form-show", "edit-item"],
data() {
return {
clonedFormElements: {
items: [
{
key: "title",
label: "عنوان",
type: "label",
placeholder: "عنوان مختصری وارد کنید",
required: "0",
validation_regex: "",
validation_error: "",
multi_select: "0",
options: [],
value: null,
},
{
key: "comment",
label: "توضیح",
type: "label",
placeholder: "توضیح مختصری وارد کنید",
required: "0",
validation_regex: "",
validation_error: "",
multi_select: "0",
options: [],
value: null,
},
],
title: "فرم جزییات",
},
};
},
methods: {
closeFormShow() {
this.$emit("close-form-show");
},
editItem() {
this.$emit("edit-item", this.selectedItem);
},
},
};
</script>

View File

@ -0,0 +1,183 @@
<template>
<div class="side-panel">
<div class="side-panel-header">
<h6 class="text-center">
افزودن آیتم جدید
</h6>
</div>
<div class="redios-castom px-3 py-2 ">
<div class="side-panel-content">
<form @submit.prevent="saveNewItemForm()" class="text__14">
<form-builder
ref="newFormItemBuilder"
:formElements="formElement"
:formData="formData"
></form-builder>
<div class="mb-3">
<button-component
type="submit"
classes="btn-outline-primary mx-3"
buttonText="افزودن"
:buttonLoading="buttonLoading"
></button-component>
<button-component
classes="btn-danger"
buttonText="انصراف"
:buttonLoading="buttonLoading"
@click="closeNewFormItem"
></button-component>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
export default {
emits: ["close-new-form-item","add-item-content"],
props: {
editFormData: {
default() {
return {};
},
},
},
watch: {
editFormData: {
handler(newVal) {
this.formData = newVal;
},
},
},
mounted(){
this.formData = this.editFormData;
},
data() {
return {
buttonLoading: false,
formData: {
name: "",
key: "",
placeholder: "",
type: "",
},
formElement: {
title: "مشخصات اصلی",
items: [
{
key: "label",
label: "عنوان",
type: "string",
placeholder: "عنوان را وارد کنید",
required: "1",
validation_regex: "{3-100}",
validation_error: "عبارت باید حداقل 3 و حداکثر 100 حرف باشد",
multi_select: "0",
options: [],
},
{
key: "key",
label: "کلیدواژه",
type: "string",
placeholder: "کلیدواژه را وارد کنید",
required: "1",
validation_regex: "{3-100}",
validation_error: "عبارت باید حداقل 3 و حداکثر 100 حرف باشد",
multi_select: "0",
options: [],
},
{
key: "placeholder",
label: "راهنما",
type: "string",
placeholder: "راهنمای اولیه مختصر را وارد کنید",
required: "1",
validation_regex: "{3-100}",
validation_error: "عبارت باید حداقل 3 و حداکثر 100 حرف باشد",
multi_select: "0",
options: [],
},
{
key: "value",
label: "مقدار",
type: "string",
placeholder: "مقدار را وارد کنید",
required: "1",
validation_regex: "{3-100}",
validation_error: "عبارت باید حداقل 3 و حداکثر 100 حرف باشد",
multi_select: "0",
options: [],
},
{
key: "type",
label: "نوع",
type: "select",
placeholder: "نوع را وارد کنید",
required: "1",
validation_regex: "{3-100}",
validation_error: "عبارت باید حداقل 3 و حداکثر 100 حرف باشد",
multi_select: "0",
options: [
{
title: "صوتی",
value: "sound",
},
{
title: "فیلم",
value: "video",
},
{
title: "تصویر",
value: "img",
},
{
title: "عبارت(نمایشی)",
value: "label",
},
{
title: "متن",
value: "textarea",
},
{
title: "انتخابی",
value: "select",
},
{
title: "متن کوتاه",
value: "string",
},
],
},
],
},
};
},
methods: {
closeNewFormItem() {
this.$emit("close-new-form-item");
},
saveNewItemForm() {
const formData = this.$refs.newFormItemBuilder.localFormData;
this.$emit("add-item-content", formData);
},
resetForm() {
this.formData = {
name: "",
key: "",
placeholder: "",
type: "",
};
},
},
};
</script>
<style lang="scss"></style>

View File

@ -0,0 +1,79 @@
<template>
<div class="position-relative ms-5">
<my-table
height="auto"
maxHeight="calc(100vh - 15em)"
:isSortable="true"
:isDraggable="true"
:hasSearch="false"
:hasPagination="false"
:fetchingData="fetchingData"
:items="localMainFormElements[currentTab]?.items"
:tableColumns="tableColumns"
:tableActions="formTableActions"
@delete-table-item="deleteItem"
@edit-table-item="editNewFormItem"
@onSort="onSort"
@on-linked-title-click="onLinkedTitleClick"
/>
<button-component
classes="d-inline-flex add-new-form-item"
@click="openNewFormItem"
buttonText=""
>
<span class="tavasi tavasi-Component-220--1"
><span class="path1"></span><span class="path2"></span
><span class="path3"></span
></span>
</button-component>
</div>
</template>
<script>
import newFormExtension from "@forms/extensions/newFormExtension";
export default {
extends: newFormExtension,
props: ["newFormItem", "formTitleData"],
mounted() {
const form = [
{
title: "فرم ساده",
items: [],
active: true,
},
];
this.localMainFormElements = this.formTitleData.meta ?? form;
},
data() {
return {
localMainFormElements: [
{
title: "فرم ساده",
items: [],
active: true,
},
],
};
},
components: {
LabelComponent: () =>
import(
"@components/forms/LabelComponent.vue"
),
},
};
</script>
<style scoped lang="scss">
.add-new-form-item {
position: absolute;
left: -3em;
bottom: 0;
}
</style>

View File

@ -0,0 +1,337 @@
<template>
<div>
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li
v-for="(groupItem, index) in localMainFormElements"
:key="index"
@click="setTab(index)"
class="nav-item"
role="presentation"
>
<a
class="nav-link position-relative ms-3"
id="home-tab"
data-bs-toggle="tab"
:href="'#' + groupItem.key"
role="tab"
:aria-controls="groupItem.key"
aria-selected="true"
:class="{ active: groupItem.active ?? false }"
>{{ groupItem.title }}
<button-component
classes="d-inline-flex tab-remove-btn"
@click="removeTab(index)"
buttonText=""
>
<span class="tavasi tavasi-Component-21--1"></span>
</button-component>
<button-component
classes="d-inline-flex tab-edit-btn"
@click="openEditTabFormModal(index)"
buttonText=""
title="ویرایش"
>
<span class="tavasi tavasi-Component-242--1"></span>
</button-component>
</a>
</li>
<li class="nav-item" role="presentation">
<!-- add button -->
<button-component
classes="nav-link d-inline-flex"
@click="openNewTabFormModal()"
buttonText="بخش جدید"
>
<span class="tavasi tavasi-Component-220--1 ms-1"
><span class="path1"></span><span class="path2"></span
><span class="path3"></span
></span>
</button-component>
</li>
</ul>
<div
class="tab-content"
id="myTabContent"
v-if="localMainFormElements?.length"
>
<div
class="tab-pane fade show active p-3"
id="home"
role="tabpanel"
aria-labelledby="home-tab"
>
<div
v-if="localMainFormElements[currentTab]?.hasChildren"
class="accordion"
id="accordionExample"
>
<div
v-for="(innerGroupItem, j) in localMainFormElements[currentTab]
?.items"
:key="j"
class="card"
>
<div class="card-header" :id="'heading' + j">
<h2 class="mb-0 d-flex">
<!-- حذف تب داخلی یا فرزند -->
<button-component
classes="d-inline-flex p-0"
@click="removeChildTab(j)"
buttonText=""
title="حذف"
>
<span class="tavasi tavasi-Component-295--1"></span>
</button-component>
<!-- باز کردن مودال ویرایش تب داخلی یا فرزند -->
<button-component
classes="d-inline-flex p-0"
@click="openChildTabEditModal(j)"
buttonText=""
title="ویرایش"
>
<span class="tavasi tavasi-Component-242--1"></span>
</button-component>
<button
class="btn btn-link btn-block has-indicator"
type="button"
data-bs-toggle="collapse"
:data-bs-target="'#collapse' + j"
:aria-expanded="innerGroupItem.active ?? false"
:aria-controls="'collapse' + j"
:class="{ active: innerGroupItem.active ?? false }"
>
{{ innerGroupItem.title }}
</button>
</h2>
</div>
<div
:id="'collapse' + j"
class="collapse"
:class="{ show: innerGroupItem.active ?? false }"
:aria-labelledby="'heading' + j"
data-parent="#accordionExample"
>
<div class="card-body">
<div class="position-relative ms-5">
<my-table
height="auto"
maxHeight="calc(100vh - 15em)"
:isSortable="true"
:isDraggable="true"
:hasSearch="false"
:hasPagination="false"
:fetchingData="fetchingData"
:items="localMainFormElements[currentTab]?.items[j]?.items"
:tableColumns="tableColumns"
:tableActions="formTableActions"
@delete-table-item="deleteChildItem($event, j)"
@edit-table-item="childEditNewFormItem($event, j)"
@onSort="onSort"
@on-linked-title-click="onLinkedTitleClick"
/>
<button-component
classes="d-inline-flex add-new-form-item"
@click="openChildNewFormItem(j)"
buttonText=""
>
<span class="tavasi tavasi-Component-220--1"
><span class="path1"></span><span class="path2"></span
><span class="path3"></span
></span>
</button-component>
</div>
</div>
</div>
</div>
</div>
<div v-else class="position-relative ms-5">
<my-table
height="auto"
maxHeight="calc(100vh - 15em)"
:isSortable="true"
:isDraggable="true"
:hasSearch="false"
:hasPagination="false"
:fetchingData="fetchingData"
:items="localMainFormElements[currentTab]?.items"
:tableColumns="tableColumns"
:tableActions="formTableActions"
@delete-table-item="deleteItem"
@edit-table-item="editNewFormItem"
@onSort="onSort"
@on-linked-title-click="onLinkedTitleClick"
/>
<button-component
classes="d-inline-flex add-new-form-item"
@click="openNewFormItem"
buttonText=""
>
<span class="tavasi tavasi-Component-220--1"
><span class="path1"></span><span class="path2"></span
><span class="path3"></span
></span>
</button-component>
</div>
</div>
</div>
<!-- new tab modal -->
<base-modal
v-if="showNewTabFormModal"
modalSize="modal-md"
modalTitle="فرم جدید"
@close="closeNewTabFormModal"
@save="addTab"
>
<form-builder
ref="tabFormBuilder"
:formElements="formTabElement"
:formData="formTabData"
></form-builder>
</base-modal>
</div>
</template>
<script>
import newFormExtension from "@forms/extensions/newFormExtension";
export default {
extends: newFormExtension,
props: ["newFormItem", "formTitleData"],
mounted() {
this.localMainFormElements = this.formTitleData.meta ?? [];
if (this.localMainFormElements && this.localMainFormElements[0])
this.localMainFormElements[0].active = true;
},
data() {
return {
prevActiveTabIndex: undefined,
localMainFormElements: [],
showNewTabFormModal: false,
// form title elemnets and data.
formTabData: {
title: null,
},
formTabElement: {
title: "",
items: [
{
key: "parent",
label: "والد",
type: "select",
placeholder: "والد را وارد کنید",
required: "1",
validation_regex: "{3-100}",
validation_error: "عبارت باید حداقل 3 و حداکثر 100 حرف باشد",
multi_select: "0",
options: [],
},
{
key: "title",
label: "عنوان",
type: "string",
placeholder: "عنوان را وارد کنید",
required: "1",
validation_regex: "{3-100}",
validation_error: "عبارت باید حداقل 3 و حداکثر 100 حرف باشد",
multi_select: "0",
options: [],
},
{
key: "key",
label: "کلیدواژه",
type: "string",
placeholder: "کلیدواژه را وارد کنید",
required: "1",
validation_regex: "{3-100}",
validation_error: "عبارت باید حداقل 3 و حداکثر 100 حرف باشد",
multi_select: "0",
options: [],
},
// {
// key: "newButtonText",
// label: "عنوان دکمه ایجاد",
// type: "string",
// placeholder: "عنوان دکمه ایجاد را وارد کنید",
// required: "1",
// validation_regex: "{3-100}",
// validation_error: "عبارت باید حداقل 3 و حداکثر 100 حرف باشد",
// multi_select: "0",
// options: [],
// },
],
},
};
},
components: {
LabelComponent: () =>
import(
"@components/forms/LabelComponent.vue"
),
NewTabForm: () =>
import(
"@forms/forms/NewTabForm.vue"
),
},
};
</script>
<style scoped lang="scss">
.tab-remove-btn {
position: absolute;
left: -0.5em;
top: -0.5em;
background-color: #fff;
justify-content: center;
align-items: center;
padding: 0;
span {
color: var(--danger);
}
&:hover {
background-color: var(--danger);
span {
color: #fff;
}
}
}
.tab-edit-btn {
position: absolute;
left: -0.5em;
bottom: 0em;
background-color: #fff;
justify-content: center;
align-items: center;
padding: 0;
&:hover {
background-color: #ddd;
span {
color: #fff;
}
}
}
.add-new-form-item {
position: absolute;
left: -3em;
bottom: 0;
}
</style>
<style>
.accordion .card .card-body .btn::after {
content: none;
}
</style>

View File

@ -39,7 +39,7 @@
<!-- <button
class="btn dropdown-toggle"
type="button"
data-toggle="dropdown"
data-bs-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
@ -69,7 +69,7 @@
<!-- <button
@click.prevent="showSearchs()"
type="button"
class="btn close-search p-0 pr-1"
class="btn close-search p-0 pe-1"
>
<svg class="icon icon-Component-71--1">
<use xlink:href="#icon-Component-71--1"></use>

View File

@ -10,7 +10,7 @@
class="form-control"
id="title"
name="title"
v-model="form?._source.title"
v-model="form._source.title"
/>
</div>
@ -75,12 +75,18 @@
<div class="form-group">
<label for="title">متن</label>
<my-quill
<!-- <my-quill
ref="quill-editor"
:parentButtonLoading="buttonLoading"
:tinyText="form?._source.description"
:showSaveButton="false"
></my-quill>
></my-quill> -->
<quill-editor
ref="quill-editor"
v-model="form._source.description"
content-type="html"
:options="editorOptions"
></quill-editor>
</div>
<div class="form-group d-flex">
@ -142,6 +148,9 @@ export default {
mounted() {
if (this.formData) this.form = this.formData;
},
created() {
this.httpService = useNuxtApp()["$http"];
},
computed: {
imageBaseUrl() {
return import.meta.env.VITE_BASE_URL;
@ -181,9 +190,26 @@ export default {
time_edit: 1111111111,
},
},
httpService: {},
hasImage: false,
imageUrl: undefined,
uploading: false,
editorOptions: {
theme: "snow", // تم ویرایشگر: 'snow' یا 'bubble'
placeholder: "متن خود را بنویسید...",
modules: {
toolbar: [
[{ header: [1, 2, 3, false] }], // سطح هدینگها
["bold", "italic", "underline", "strike"], // دکمههای استایل متن
[{ color: [] }, { background: [] }], // رنگ متن و پسزمینه
[{ list: "ordered" }, { list: "bullet" }], // لیستهای شمارهدار و نقطهای
["blockquote", "code-block"], // نقلقول و کد
[{ align: [] }], // تراز بندی متن
["link", "image", "video"], // افزودن لینک، تصویر، و ویدیو
["clean"], // حذف فرمتها
],
},
},
};
},
computed: {
@ -265,7 +291,7 @@ export default {
.then((res) => {
this.$emit("close-modal", true);
this.mySwalToast({
mySwalToast({
title: "تبریک",
html: res.message,
icon: "success",
@ -277,7 +303,7 @@ export default {
});
},
onDeleteItem(item) {
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار!!!",
html: "از حذف این مورد مطمئن هستید؟",
}).then((result) => {
@ -289,7 +315,6 @@ export default {
});
},
},
};
</script>
<style lang="scss">

View File

@ -0,0 +1,664 @@
<template>
<!-- <div class="modal-dialog"> -->
<div class="modal-content">
<div class="popUp-tab__content tab-content share-modal__content">
<div class="share-modal__search-content">
<div class="share-modal__content">
<div class="share-modal__search">
<span>با </span>
<input
type="text"
placeholder="نام کاربر یا email@exaple.com"
id="searchForName"
v-model="query"
@keyup="showSearchResult"
/>
</div>
<div
id="user-search-recommend"
class="share-modal__search-recommend"
:class="{ show: suggestionMode }"
>
<div class="search-recommend">
<div
class="search-users__item d-flex justify-content-between align-items-center mx-2"
v-for="(user, i) in userSuggestions"
:key="'h' + i"
>
<div class="search-users__pic">
<img :src="userAvatar(user)" alt="" />
</div>
<div class="search-users__content">
<div class="search-users__name">
{{ user.full_name }}
</div>
<div class="search-users__id">@{{ user.username }}</div>
</div>
<div class="search-users__type">
<div class="order-select main-page__date-select">
<select
@change="addUser($event, user)"
class="form-control d-block"
>
<option selected disabled :value="undefined">
انتخاب نقش
</option>
<option
v-for="role in roles"
:key="role.id"
:value="role.id"
>
{{ role.title }}
</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- </div> -->
</template>
<script>
// import HttpService from "@services/httpService";
export default {
name: "sharemodal",
props: ["item", "itemType", "roles"],
mounted() {
// this.httpService = new HttpService();
this.httpService = useNuxtApp()["$http"];
},
data() {
return {
httpService: {},
newItemType: 0,
suggestionMode: false,
query: "",
userSuggestions: [],
userToAdd: [],
};
},
methods: {
// formData(url, data = []) {
// const formData = new FormData();
// for (const [key, value] of Object.entries(data)) {
// if (value !== undefined && value !== null) formData.append(key, value);
// }
// return axios.post(url, formData);
// },
showSearchResult() {
var vm = this;
let url = loginUrl() + "user/suggestion";
if (this.query.length > 2) {
this.httpService
.postRequest(url, { query: this.query })
.then((response) => {
var items = response.data;
vm.userSuggestions = items;
vm.suggestionMode = true;
});
} else {
vm.userSuggestions = [];
vm.suggestionMode = false;
}
},
deleteUser: function (index) {
this.userToAdd.splice(index, 1);
},
addUser(ev, item) {
this.userToAdd.push(item);
this.suggestionMode = false;
this.$emit("update-user-role", {
user_id: item.user_id,
role_id: +ev.target.value,
});
// this.addPerm(ev, item);
},
addPerm(ev, item) {
// var guid = this.item.guid;
// this.userToAdd.forEach(function (item) {
// ApiService.post(this, "perm/set", {
// pid: guid,
// act: "add",
// read: 1,
// write: 0,
// username: item.username,
// });
// });
},
},
};
</script>
<style lang="scss">
@import "../../../assets/permit/scss/permit.scss";
</style>
<style scoped lang="scss">
.share-modal {
height: 20em;
background-color: #fff;
top: 7em;
left: 2em;
}
.search-users__pic {
display: flex;
margin-left: 15px;
position: relative;
img {
width: 32px;
height: 32px;
border-radius: 50%;
overflow: hidden;
}
}
.share-modal__content{
width: 100%;
}
.share-modal__search-top {
background-color: #eee;
padding-bottom: 1em;
font-size: 15px;
font-weight: 500;
}
.share-modal__search-recommend {
opacity: 1;
display: block;
position: static;
visibility: visible;
height: calc(100% - 12.5em);
overflow: auto;
/* display: none; */
/* opacity: unset; */
/* visibility: hidden; */
/* top: 117px; */
/* right: 0px; */
/* width: 100%; */
/* background: white; */
/* -webkit-transition: all 0.3s ease-in-out; */
/* transition: all 0.3s ease-in-out; */
/* opacity: 0; */
/* visibility: hidden; */
/* display: none; */
/* z-index: 10; */
&.show {
position: static !important;
opacity: 1 !important;
display: block !important;
visibility: visible !important;
}
}
// .share-modal {
// width: 337px;
// height: 385px;
// background-color: #fff;
// border: 1px solid #bac4ce;
// border-radius: 20px;
// top: 63px;
// left: 253px;
// transform: unset;
// &__modal {
// .modal-dialog {
// transform: unset !important;
// transition: unset !important;
// }
// }
// &__content {
// position: relative;
// width: 337px;
// height: 385px;
// display: flex;
// flex-direction: column;
// }
// &__search-content {
// position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// height: 100%;
// transition: all 0.3s ease-in-out;
// }
// &__search {
// border-bottom: 1px solid #f1f1f1;
// display: flex;
// align-items: center;
// padding-top: 15px;
// padding-bottom: 15px;
// span {
// font-size: 16px;
// // color: var(--color-2);
// width: 50px;
// display: flex;
// justify-content: center;
// i {
// cursor: pointer;
// color: #92a2b2;
// font-size: 24px;
// width: 70px;
// display: flex;
// justify-content: center;
// align-items: center;
// }
// }
// #get-back {
// width: 70px;
// }
// input {
// flex-grow: 2;
// border: unset;
// outline: unset;
// // color: var(--color-2);
// font-size: 14px;
// &::placeholder {
// color: #92a2b2;
// font-size: 14px;
// }
// }
// }
// &__add-person {
// width: 50px;
// display: flex;
// justify-content: center;
// i {
// font-size: 24px;
// -webkit-transition: all 0.5s ease-in-out;
// transition: all 0.5s ease-in-out;
// font-size: 23px;
// background: -webkit-linear-gradient(#a9bdc4 0%, #c6cfda 100%);
// background-clip: border-box;
// -webkit-background-clip: text;
// -webkit-text-fill-color: transparent;
// }
// &:hover {
// i {
// background: -webkit-linear-gradient(#00b6e3 0%, #81e6ff 100%);
// background-clip: border-box;
// -webkit-background-clip: text;
// -webkit-text-fill-color: transparent;
// }
// }
// }
// &__search-recommend {
// display: none;
// opacity: unset;
// visibility: hidden;
// position: absolute;
// top: 57px;
// right: 0px;
// width: 100%;
// height: calc(100% - 57px);
// background: white;
// transition: all 0.3s ease-in-out;
// opacity: 0;
// visibility: hidden;
// display: none;
// z-index: 10;
// .os-host {
// height: 100%;
// }
// .os-host-resize-disabled.os-host-scrollbar-horizontal-hidden > .os-scrollbar-vertical {
// bottom: 0;
// right: 7px;
// top: 17px;
// width: 0px;
// }
// .os-theme-dark > .os-scrollbar > .os-scrollbar-track > .os-scrollbar-handle {
// background: rgba(0, 0, 0, 0.16);
// }
// }
// &__users {
// flex-grow: 1;
// max-height: 259px;
// .os-scrollbar-vertical {
// width: 0;
// }
// }
// &__icon {
// display: flex;
// justify-content: center;
// align-items: center;
// margin-bottom: 18px;
// img {
// width: 142px;
// padding-top: 42px;
// }
// }
// &__text {
// color: #92a2b2;
// font-size: 14px;
// padding-bottom: 37px;
// width: 246px;
// text-align: center;
// margin-right: auto;
// margin-left: auto;
// }
// &__search-content-footer {
// display: flex;
// align-items: flex-end;
// justify-content: space-between;
// padding-top: 15px;
// padding-bottom: 15px;
// border-top: 1px solid #bac4ce;
// padding-right: 22px;
// padding-left: 22px;
// }
// &__sign {
// display: flex;
// flex-direction: column;
// span {
// font-size: 12px;
// color: #92a2b2;
// display: block;
// margin-bottom: 2px;
// }
// a {
// // color: var(--color-1);
// font-size: 12px;
// }
// }
// &__settings {
// a {
// }
// }
// &__settings-btn {
// font-size: 14px;
// // color: var(--color-1);
// }
// &__settings-content {
// position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// height: 100%;
// transition: all 0.3s ease-in-out;
// opacity: 0;
// visibility: hidden;
// display: none;
// }
// &__title {
// padding-top: 15px;
// padding-bottom: 15px;
// border-bottom: 1px solid #f1f1f1;
// padding-right: 22px;
// padding-left: 22px;
// h4 {
// font-size: 16px;
// }
// }
// &__form {
// padding-right: 22px;
// padding-left: 22px;
// &-question {
// font-size: 14px;
// font-weight: 500;
// text-shadow: 0 -0.75px #6b6b6b;
// margin-bottom: 17px;
// color: #444444;
// }
// &-item {
// padding-top: 17px;
// &:last-child {
// margin-bottom: 17px;
// }
// }
// &-radio-item {
// display: flex;
// align-items: center;
// &:not(:last-child) {
// margin-bottom: 20px;
// }
// input {
// }
// label {
// color: #444444;
// font-size: 14px;
// margin-right: 16px;
// margin-bottom: 0;
// }
// }
// &-btn {
// min-width: 57px;
// height: 32px;
// border-radius: 20px;
// display: flex;
// justify-content: center;
// align-items: center;
// margin-right: 10px;
// }
// &-radio {
// position: relative;
// input {
// position: absolute;
// opacity: 0;
// cursor: pointer;
// height: 20px;
// width: 20px;
// z-index: 5;
// }
// span {
// display: flex;
// height: 20px;
// width: 20px;
// border-radius: 50%;
// border: 2px solid #bac4ce;
// transition: all 0.3s ease-in-out;
// display: flex;
// justify-content: center;
// align-items: center;
// &::before {
// content: " ";
// width: 10px;
// height: 10px;
// border-radius: 50%;
// display: flex;
// background: linear-gradient(#3def90 0%, #1ed975 100%);
// opacity: 0;
// transition: all 0.3s ease-in-out;
// }
// }
// input:checked ~ span::before {
// opacity: 1;
// }
// }
// }
// &__form-btn--deactive {
// font-size: 14px;
// // color: var(--color-2);
// &:hover {
// opacity: 0.8;
// }
// }
// &__from-btn--active {
// // border: 2px solid var(--color-1);
// // color: var(--color-1);
// font-size: 14px;
// &:hover {
// color: white;
// // background: var(--color-1);
// }
// }
// &__setting-footer {
// margin-top: auto;
// border-top: 1px solid #f1f1f1;
// display: flex;
// align-items: center;
// justify-content: flex-end;
// padding: 16px;
// }
// &__people-search {
// background: #fff;
// position: absolute;
// top: 0;
// display: none;
// left: 0;
// width: 100%;
// height: 100%;
// transition: all 0.3s ease-in-out;
// opacity: 0;
// visibility: hidden;
// .os-host {
// height: 100%;
// }
// .os-host-resize-disabled.os-host-scrollbar-horizontal-hidden > .os-scrollbar-vertical {
// bottom: 0;
// right: 7px;
// top: 17px;
// width: 0px;
// }
// .os-theme-dark > .os-scrollbar > .os-scrollbar-track > .os-scrollbar-handle {
// background: rgba(0, 0, 0, 0.16);
// }
// }
// &__user-search-content {
// opacity: unset;
// width: 100%;
// height: calc(100% - 57px);
// background: white;
// transition: all 0.3s ease-in-out;
// top: 57px;
// display: none;
// .os-host {
// height: 100%;
// }
// .os-host-resize-disabled.os-host-scrollbar-horizontal-hidden > .os-scrollbar-vertical {
// bottom: 0;
// right: 7px;
// top: 17px;
// width: 0px;
// }
// .os-theme-dark > .os-scrollbar > .os-scrollbar-track > .os-scrollbar-handle {
// background: rgba(0, 0, 0, 0.16);
// }
// }
// &__users-footer {
// display: flex;
// flex-direction: column;
// }
// &__textarea {
// border-top: 1px solid #f1f1f1;
// padding-top: 12px;
// padding-bottom: 12px;
// padding-right: 22px;
// padding-left: 22px;
// }
// &__invite-row {
// border-top: 1px solid #f1f1f1;
// display: flex;
// align-items: center;
// padding-top: 17.5px;
// padding-bottom: 26px;
// justify-content: space-between;
// padding-right: 22px;
// padding-left: 22px;
// }
// &__select {
// font-size: 14px;
// .main-page__date-select .select-selected {
// border: unset;
// padding: 0;
// }
// .main-page__date-select .select-selected {
// height: 32px;
// }
// .select-items {
// width: 160px;
// }
// .main-page__date-select .select-items {
// top: unset;
// bottom: calc(5px + 100%);
// }
// }
// &__send-invite {
// a {
// display: flex;
// justify-content: center;
// align-items: center;
// min-width: 120px;
// border-radius: 20px;
// // border: 2px solid var(--color-1);
// height: 32px;
// font-size: 14px;
// &:hover {
// color: white;
// // background: var(--color-1);
// }
// }
// }
// }
</style>

View File

@ -271,7 +271,7 @@ export default {
</script>
<style lang="scss">
@import "../assets/majles/scss/majles";
@import "../../../assets/majles/scss/majles";
.custom-class {
.dropdown-toggle {

View File

@ -0,0 +1,106 @@
<template>
<div class="side-panel">
<div class="side-panel-header">
<h6>
انتخاب ستونها در حالت نمایش فهرستی(جدولی)
</h6>
</div>
<div class="side-panel-content">
<form @submit.prevent="saveColumn">
<div class="row form-group">
<label for="key" class="col-md-3">کلیدواژه: </label>
<select
class="form-control col-md-9"
placeholder="کلیدواژه"
type="key"
id="key"
name="key"
v-model="localFormElement.key"
>
<option
v-for="option in selectedForm.flatedItems"
:value="option.key"
>{{ option.label }}({{ option.key }})</option
>
</select>
</div>
<div class="row form-group">
<label for="title" class="col-md-3">عنوان: </label>
<input
class="form-control col-md-9"
placeholder="عنوان"
type="title"
id="title"
name="title"
v-model="localFormElement.title"
/>
</div>
<div class="row form-group">
<label for="width" class="col-md-3">وزن: </label>
<input
class="form-control col-md-9"
placeholder="وزن"
type="width"
id="width"
name="width"
v-model="localFormElement.width"
/>
</div>
<div class="row form-group">
<div class="d-flex justify-content-between">
<button-component
classes="btn btn-primary d-inline-flex btn-default"
buttonText="افزودن"
type="submit"
>
</button-component>
<button-component
classes="d-inline-flex btn-danger"
@click="closeFormShow"
buttonText="بستن"
>
<!-- <span class="tavasi tavasi-Component-71--1"></span> -->
</button-component>
</div>
</div>
</form>
</div>
</div>
</template>
<script>
export default {
props: ["selectedItem", "selectedForm"],
emits: ["close-form-show", "update-column"],
data() {
return {
displayMode:'table',
localFormElement: {
title: null,
key: null,
width: 1,
},
};
},
mounted() {
this.localFormElement = structuredClone(this.selectedItem);
},
watch: {
selectedItem(newval) {
this.localFormElement = structuredClone(newval);
},
},
methods: {
closeFormShow() {
this.$emit("close-form-show");
},
saveColumn() {
const clonedLocalFormElement = structuredClone(this.localFormElement);
this.$emit("update-column", clonedLocalFormElement);
},
},
};
</script>

View File

@ -0,0 +1,72 @@
[
{
"showOutside": true,
"show": true,
"icon": "tavasi tavasi-Component-71--1",
"title": "جزییات",
"to": {
"name": "undefined"
},
"selected": false,
"disabled": false,
"howToOpen": "",
"href": "",
"class": "btn show-detail-btn -rotate-180",
"action": "showDetails",
"can": ""
},
{
"showOutside": false,
"show": true,
"icon": "default",
"title": "ویرایش",
"to": {
"name": "undefined"
},
"selected": false,
"disabled": false,
"howToOpen": "",
"href": "",
"class": "edit-btn",
"action": "edit-table-item",
"can": ""
},
{
"showOutside": false,
"show": true,
"icon": "default",
"title": "حذف",
"to": {
"name": "undefined"
},
"selected": false,
"disabled": false,
"howToOpen": "",
"href": "",
"class": "delete-btn",
"action": "delete-table-item",
"can": ""
},
{
"showOutside": false,
"show": true,
"icon": "default",
"title": "ستون های فهرست",
"to": {
"name": "undefined"
},
"selected": false,
"disabled": false,
"howToOpen": "",
"href": "",
"class": "",
"action": "select-list-columns",
"can": ""
}
]

View File

@ -14,6 +14,174 @@
"link": "admin",
"title": "پیشخوان مدیر",
"translateKey": "AdminDashboard"
},
{
"color": 2,
"icon": "settings",
"link": "dataSettingAboutUs",
"title": "تنظیمات",
"translateKey": "Settings",
"subMenu": [
{
"color": 2,
"icon": "profile",
"link": "dataSettingAboutUs",
"title": "متن در باره ما",
"translateKey": "AboutUsText"
},
{
"color": 2,
"icon": "contact",
"link": "dataSettingContactUs",
"title": "متن تماس با ما",
"translateKey": "ContactUsText"
},
{
"color": 2,
"icon": "Component-295--1",
"link": "stopWord",
"title": "کلمات حذفی",
"translateKey": "DeletedWords"
},
{
"color": 2,
"icon": "search-iconldpi",
"link": "searchAmplify",
"title": "جستجوی مفهومی",
"translateKey": "ConceptualSearch"
},
{
"color": 2,
"icon": "Component-285--2",
"link": "adminNotifications",
"title": "اعلانات",
"translateKey": "Notifications"
}
]
},
{
"color": 3,
"icon": "access",
"link": "sections",
"title": "دسترسی",
"translateKey": "Access",
"subMenu": [
{
"icon": "panel-sectioned",
"color": 3,
"link": "sections",
"title": "بخش ها",
"translateKey": "Sections"
},
{
"icon": "portal-roles",
"color": 3,
"link": "Roles",
"title": "نقش ها",
"translateKey": "Roles"
},
{
"icon": "access",
"color": 3,
"link": "rolePermission",
"title": "دسترسی نقش",
"translateKey": "RoleAccess"
},
{
"icon": "user-role",
"color": 3,
"link": "UserPermission",
"title": "نقش کاربر",
"translateKey": "UserRole"
}
]
},
{
"color": 3,
"icon": "Group-7932",
"link": "adminUsers",
"title": "مدیریت ",
"translateKey": "Management",
"subMenu": [
{
"color": 3,
"icon": "Component-259--1",
"link": "adminUsers",
"title": "کاربران",
"translateKey": "Users"
},
{
"color": 3,
"icon": "Component-259--1",
"link": "userModifications",
"title": " اصلاحیات کاربران",
"translateKey": "UserModifications"
},
{
"color": 3,
"icon": "groups",
"link": "groupsWithoutAdmin",
"title": " گروه های آزاد",
"translateKey": "FreeGroups"
}
]
},
{
"color": 3,
"icon": "doc-outline",
"link": "formList",
"title": "فرم ها",
"translateKey": "forms",
"subMenu": [
{
"icon": "doc-outline",
"color": 3,
"link": "formList",
"title": "فرم ها",
"translateKey": "forms"
},
{
"icon": "folder-plus",
"color": 3,
"link": "newForm",
"title": "فرم جدید",
"translateKey": "NewForm"
},
{
"icon": "Component-68--1",
"color": 3,
"link": "selectListColumnsCreate",
"title": "انتخاب ستون های فهرست",
"translateKey": "SelectColumnsOfList"
}
]
},
{
"color": 2,
"icon": "question",
"link": "adminGuides",
"title": " راهنما",
"translateKey": "Help",
"subMenu": [
{
"color": 2,
"icon": "Component-220--11",
"link": "adminGuides",
"title": "جدید",
"translateKey": "New"
},
{
"color": 2,
"icon": "Component-68--1",
"link": "guidesList",
"title": "فهرست ",
"translateKey": "Contents"
}
]
}
]
}
}

View File

@ -0,0 +1,37 @@
[
{
"showOutside": true,
"show": true,
"icon": "tavasi tavasi-Component-242--1",
"title": "ویرایش",
"to": {
"name": "undefined"
},
"selected": false,
"disabled": false,
"howToOpen": "",
"href": "",
"class": "edit-btn",
"action": "edit-table-item",
"can": ""
},
{
"showOutside": true,
"show": true,
"icon": "tavasi tavasi-Component-295--1",
"title": "حذف",
"to": {
"name": "undefined"
},
"selected": false,
"disabled": false,
"howToOpen": "",
"href": "",
"class": "delete-btn",
"action": "delete-table-item",
"can": ""
}
]

3065
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@
"@popperjs/core": "^2.11.8",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"@vueup/vue-quill": "^1.2.0",
"axios": "^1.7.7",
"bootstrap": "^5.3.3",
"docx": "^9.1.1",
@ -38,6 +39,7 @@
"jquery": "^3.7.1",
"mammoth": "^1.8.0",
"mitt": "^3.0.1",
"npm": "^11.1.0",
"nuxt": "^3.15.4",
"nuxt-echarts": "^0.2.3",
"pinia-plugin-persistedstate": "^4.1.1",

View File

@ -1,4 +1,5 @@
<template>
<NuxtLayout name="default" :menu="adminMenu">
<div class="container-fluid">
<div class="row">
<div class="col-12">
@ -143,29 +144,35 @@
:hasFooter="false"
@close="closeModal"
>
<admin-notification-form
<AdminNotificationForm
ref="tabFormBuilder"
:formData="notificationItem"
@close-modal="closeModal"
></admin-notification-form>
></AdminNotificationForm>
</base-modal>
</div>
</NuxtLayout>
</template>
<script>
import notificationMixin from "~/mixins/notifications/notificationMixin";
import adminMenu from "~/json/admin/json/menu.json";
import { defineAsyncComponent } from "vue";
export default {
name: "adminNotifications",
setup() {
definePageMeta({
name: "adminNotifications",
layout: false,
});
},
extends: notificationMixin,
mounted() {
// this.canView = true;
this.checkPermisionBeforGetList("notification_edit").then(() => {
this.checkPermisionBeforGetList("notification_edit" ).then(() => {
this.getList();
this.numberOfMark();
});
@ -182,6 +189,7 @@ export default {
data() {
return {
showModal: false,
adminMenu: adminMenu,
};
},
@ -191,7 +199,7 @@ export default {
this.openModal();
},
onDeleteItem(item) {
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار!!!",
html: "از حذف این مورد مطمئن هستید؟",
}).then((result) => {
@ -208,13 +216,13 @@ export default {
openModal() {
this.showModal = true;
setTimeout(() => {
$("#base-modal").modal({ backdrop: "static", keyboard: false }, "show");
}, 500);
// setTimeout(() => {
// $("#base-modal").modal({ backdrop: "static", keyboard: false }, "show");
// }, 500);
},
closeModal(isCreate = false) {
$("#base-modal").modal("hide");
// $("#base-modal").modal("hide");
this.showModal = false;
if (isCreate)
setTimeout(() => {
this.showModal = false;
@ -229,7 +237,12 @@ export default {
}, 500);
},
},
components: {
AdminNotificationForm: defineAsyncComponent(() =>
import("@/components/admin/modal/AdminNotificationForm.vue")
),
},
};
</script>

View File

@ -0,0 +1,131 @@
<template>
<NuxtLayout name="default" :menu="adminMenu">
<div class="m-2">
<the-content-loading v-if="fetchingData"></the-content-loading>
<!-- <my-quill
:parentButtonLoading="buttonLoading"
v-else
:tinyText="tinyText"
@input="onSave"
@on-save="onSave"
></my-quill> -->
<quill-editor
v-else
v-model="tinyText"
content-type="html"
:options="editorOptions"
></quill-editor>
<button @click="onSave" type="button" class="btn btn-primary mt-3">
ذخیره
</button>
</div>
</NuxtLayout>
</template>
<script>
import settingsApi from "~/apis/settingsApi";
import adminMenu from "~/json/admin/json/menu.json";
export default {
name: "dataSettingContactUs",
setup() {
definePageMeta({
name: "dataSettingContactUs",
layout: false,
});
},
created() {
this.httpService = useNuxtApp()["$http"];
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
data() {
return {
adminMenu: adminMenu,
httpService: {},
buttonLoading: false,
tinyText: "",
fetchingData: false,
data: undefined,
editorOptions: {
theme: "snow", // تم ویرایشگر: 'snow' یا 'bubble'
placeholder: "متن خود را بنویسید...",
modules: {
toolbar: [
[{ header: [1, 2, 3, false] }], // سطح هدینگها
["bold", "italic", "underline", "strike"], // دکمههای استایل متن
[{ color: [] }, { background: [] }], // رنگ متن و پسزمینه
[{ list: "ordered" }, { list: "bullet" }], // لیستهای شمارهدار و نقطهای
["blockquote", "code-block"], // نقلقول و کد
[{ align: [] }], // تراز بندی متن
["link", "image", "video"], // افزودن لینک، تصویر، و ویدیو
["clean"], // حذف فرمتها
],
},
},
};
},
methods: {
getData() {
var vm = this;
this.fetchingData = true;
var url = settingsApi.app.getByKey;
url = url.replace("{{key_option}}", "conect_text");
// let url = apis.admin.get.replace('{{system}}', this.$route.meta.apiKey)
this.httpService
.getRequest(url)
.then((response) => {
vm.fetchingData = false;
this.tinyText = response.data.hits.hits[0]._source.value;
this.data = response.data.hits.hits[0]._source;
})
.catch((error) => {})
.finally(() => {
vm.fetchingData = false;
});
},
onSave(newContent) {
if (this.buttonLoading) return;
this.buttonLoading = true;
// var url = apis.admin.save;
// const payload = { ...this.data, ...{ value: newContent } }
var url = settingsApi.app.saveByKey;
url = url.replace("{{key_option}}", "conect_text");
const payload = { value: newContent };
this.httpService
.postRequest(url, payload)
.then((response) => {
mySwalToast({
title: "تبریک",
html: response.data.message,
icon: "success",
});
})
.catch((error) => {})
.finally(() => {
this.buttonLoading = false;
});
},
},
};
</script>

143
pages/admin/about/index.vue Normal file
View File

@ -0,0 +1,143 @@
<template>
<NuxtLayout name="default" :menu="adminMenu">
<div class="m-2">
<the-content-loading v-if="fetchingData"></the-content-loading>
<!--
<my-quillr
:parentButtonLoading="buttonLoading"
v-else
:tinyText="tinyText"
@input="onSave"
@on-save="onSave"
></my-quillr> -->
<quill-editor
v-else
:content="tinyText"
ref="quillEditor"
content-type="html"
theme="snow"
@input="onInputChange"
:options="editorOptions"
></quill-editor>
<button @click="onSave" type="button" class="btn btn-primary mt-3">
ذخیره
</button>
</div>
</NuxtLayout>
</template>
<script>
import { render } from "vue";
import settingsApi from "~/apis/settingsApi";
import adminMenu from "~/json/admin/json/menu.json";
export default {
name: "dataSettingAboutUs",
setup() {
definePageMeta({
name: "dataSettingAboutUs",
layout: false,
});
},
created() {
this.httpService = useNuxtApp()["$http"];
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
data() {
return {
adminMenu: adminMenu,
httpService: {},
buttonLoading: false,
tinyText: "",
render: 0,
fetchingData: false,
data: undefined,
editorOptions: {
theme: "snow", // تم ویرایشگر: 'snow' یا 'bubble'
placeholder: "متن خود را بنویسید...",
modules: {
toolbar: [
[{ header: [1, 2, 3, false] }], // سطح هدینگها
["bold", "italic", "underline", "strike"], // دکمههای استایل متن
[{ color: [] }, { background: [] }], // رنگ متن و پسزمینه
[{ list: "ordered" }, { list: "bullet" }], // لیستهای شمارهدار و نقطهای
["blockquote", "code-block"], // نقلقول و کد
[{ align: [] }, { direction: "rtl" }], // تراز بندی متن
["link", "image", "video"], // افزودن لینک، تصویر، و ویدیو
["clean"], // حذف فرمتها
],
},
},
};
},
methods: {
getData() {
var vm = this;
this.fetchingData = true;
var url = settingsApi.app.getByKey;
url = url.replace("{{key_option}}", "about_text");
// let url = apis.admin.get.replace('{{system}}', this.$route.meta.apiKey)
this.httpService
.getRequest(repoUrl() + url)
.then((response) => {
console.log("🚀 ~ .then ~ response:", response);
vm.fetchingData = false;
this.tinyText = response.hits.hits[0]._source.value;
this.data = response.hits.hits[0]._source;
})
.catch((error) => {})
.finally(() => {
vm.fetchingData = false;
});
},
onInputChange(event) {
// console.log("🚀 ~ onInputChange ~ event:", event);
// this.tinyText = event
},
onSave(newContent) {
if (this.buttonLoading) return;
this.buttonLoading = true;
// var url = apis.admin.save;
// const payload = { ...this.data, ...{ value: newContent } }
var url = settingsApi.app.saveByKey;
url = url.replace("{{key_option}}", "about_text");
const payload = { value: newContent };
this.httpService
.postRequest(url, payload)
.then((response) => {
mySwalToast({
title: "تبریک",
html: response.data.message,
icon: "success",
});
})
.catch((error) => {})
.finally(() => {
this.buttonLoading = false;
});
},
},
};
</script>

View File

@ -1,4 +1,5 @@
<template>
<NuxtLayout name="default" :menu="adminMenu">
<div>
<the-content-loading v-if="fetchingData"></the-content-loading>
@ -24,20 +25,40 @@
</div>
</div>
</NuxtLayout>
</template>
<script>
import settingsApi from "~/apis/settingsApi";
import adminMenu from "~/json/admin/json/menu.json";
export default {
name: "searchAmplify",
setup() {
definePageMeta({
name: "searchAmplify",
layout: false,
});
},
created() {
this.httpService = useNuxtApp()["$http"];
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
data() {
return {
adminMenu: adminMenu,
httpService: {},
stopWords: '',
fetchingData: false,
buttonLoading: false,
@ -57,7 +78,7 @@ export default {
url = url.replace("{{key_option}}", "search_amplify");
// let url = apis.admin.get.replace('{{system}}', this.$route.meta.apiKey)
ApiService.getRequest(url)
this.httpService.getRequest(url)
.then((response) => {
this.payload = response.data.hits.hits[0]._source;
this.properties = JSON.parse(response.data.hits.hits[0]._source.value);
@ -79,9 +100,9 @@ export default {
const payload = { value: JSON.stringify(this.properties) }
ApiService.postRequest(url, payload)
this.httpService.postRequest(url, payload)
.then((response) => {
this.mySwalToast({
mySwalToast({
title: "تبریک",
html: response.data.message,
icon: "success",
@ -93,17 +114,6 @@ export default {
})
}
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
};
</script>

View File

@ -1,5 +1,6 @@
<template>
<div>
<NuxtLayout name="default" :menu="adminMenu">
<div class="m-3">
<the-content-loading v-if="fetchingData"></the-content-loading>
<form v-else @submit.prevent="onSave()">
@ -17,23 +18,41 @@
<button-component
type="submit"
classes="btn-primary"
class="mt-2"
:buttonText="saveButtonText"
>
</button-component>
</form>
</div>
</NuxtLayout>
</template>
<script>
import settingsApi from "~/apis/settingsApi";
import adminMenu from "~/json/admin/json/menu.json";
export default {
name: "stopWord",
setup() {
definePageMeta({
name: "stopWord",
layout: false,
});
},
created() {
this.httpService = useNuxtApp()["$http"];
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
props: {
saveButtonText: {
default: "ذخیره",
@ -41,6 +60,8 @@ export default {
},
data() {
return {
adminMenu: adminMenu,
httpService: {},
stopWords: "",
fetchingData: false,
data: undefined,
@ -57,7 +78,7 @@ export default {
url = url.replace("{{key_option}}", "words_stop");
// let url = apis.admin.get.replace("{{system}}", this.$route.meta.apiKey);
ApiService.getRequest(url)
this.httpService.getRequest(url)
.then((response) => {
vm.fetchingData = false;
@ -80,9 +101,9 @@ export default {
url = url.replace("{{key_option}}", "words_stop");
const payload = { value: this.stopWords };
ApiService.postRequest(url, payload)
this.httpService.postRequest(url, payload)
.then((response) => {
this.mySwalToast({
mySwalToast({
title: "تبریک",
html: response.data.message,
icon: "success",
@ -94,17 +115,6 @@ export default {
});
},
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
};
</script>

View File

@ -1,74 +1,84 @@
<template>
<div class="pages">
<sub-header
myClass="mt-0 mb-3"
:hasViewMode="false"
:showDetailsPanel="false"
title="فهرست فرم‌ها"
@show-details="newForm"
></sub-header>
<NuxtLayout name="default" :menu="adminMenu">
<div class="pages">
<sub-header
myClass="mt-0 mb-3"
:hasViewMode="false"
:showDetailsPanel="false"
title="فهرست فرم‌ها"
@show-details="newForm"
></sub-header>
<div class="pages-content ps-1">
<template v-if="canView">
<my-table
height="calc(100vh - 15em)"
:isDraggable="false"
:items="items"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:tableActions="tableActions"
:paginationInfo="pagination"
:sortingInfo="sorting"
@delete-table-item="deleteItem"
@edit-table-item="editItem"
@select-list-columns="selectListColumnsEdit"
@show-details="showDetails"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
@on-linked-title-click="onLinkedTitleClick"
/>
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div class="pages-content ps-1">
<template v-if="canView">
<my-table
height="calc(100vh - 15em)"
:isDraggable="false"
:items="items"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:tableActions="tableActions"
:paginationInfo="pagination"
:sortingInfo="sorting"
@delete-table-item="deleteItem"
@edit-table-item="editItem"
@select-list-columns="selectListColumnsEdit"
@show-details="showDetails"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
@on-linked-title-click="onLinkedTitleClick"
/>
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</div>
</no-data>
</no-data>
<form-show
v-if="shwoPreviewForm"
:selectedItem="rowItem"
:tableColumns="tableColumns"
@edit-item="formShowEditItem"
@close-form-show="closeFormShow"
></form-show>
<FormShow
v-if="shwoPreviewForm"
:selectedItem="rowItem"
:tableColumns="tableColumns"
@edit-item="formShowEditItem"
@close-form-show="closeFormShow"
></FormShow>
</div>
</div>
</div>
</NuxtLayout>
</template>
<script>
import keyValueApi from "@apis/keyValueApi";
import HttpService from "@services/httpService";
import tableActions from "@forms/json/formListTableAction";
import { mapGetters, mapMutations, mapActions } from "vuex";
import keyValueApi from "~/apis/keyValueApi";
import adminMenu from "~/json/admin/json/menu.json";
// import HttpService from "@services/httpService";
import tableActions from "~/json/admin/json/formListTableAction";
// import { mapGetters, mapMutations, mapActions } from "vuex";
import { mapState, mapActions } from "pinia";
import { defineAsyncComponent } from "vue";
import { useCommonStore } from "~/stores/commonStore";
import { usePermitStore } from "~/stores/permitStore";
export default {
name: "formList",
setup() {
definePageMeta({
name: "formList",
layout: false,
});
},
beforeMount() {
this.httpService = useNuxtApp()["$http"];
},
mounted() {
this.httpService = new HttpService();
this.checkPermisionBeforGetList();
},
watch: {
@ -79,6 +89,7 @@ export default {
},
data() {
return {
adminMenu: adminMenu,
canView: true,
rowItem: {},
shwoPreviewForm: false,
@ -107,11 +118,13 @@ export default {
};
},
computed: {
...mapGetters(["getPanelStatus"]),
...mapState(useCommonStore, ["getPanelStatus"]),
},
methods: {
...mapMutations(["TOGGLE_PANEL"]),
...mapActions(["checkPermissions"]),
// ...mapMutations(["TOGGLE_PANEL"]),
...mapActions(useCommonStore, ["TOGGLE_PANEL"]),
...mapActions(useCommonStore, ["checkPermissions"]),
// ...mapActions(["checkPermissions"]),
checkPermisionBeforGetList() {
this.checkPermissions({ permission: "forms_list", _this: this })
.then(() => {
@ -166,7 +179,7 @@ export default {
...this.sorting,
...this.pagination,
};
let url = this.keyValueMicroServiceName + keyValueApi.forms.list;
let url = keyValueUrl() + keyValueApi.forms.list;
return await this.httpService
.postRequest(url, formData)
.then((response) => {
@ -214,7 +227,7 @@ export default {
id: this.items[index].id,
};
let url = this.keyValueMicroServiceName + keyValueApi.forms.delete;
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار!!!",
html: "از حذف این مورد مطمئن هستید؟",
}).then((result) => {
@ -274,8 +287,10 @@ export default {
},
},
components: {
FormShow: () =>
import( "@forms/forms/FormShow.vue"),
// FormShow: () => import("@forms/forms/FormShow.vue"),
FormShow: defineAsyncComponent(() =>
import("@/components/admin/components/FormShow.vue")
),
},
};
</script>

View File

@ -1,138 +1,149 @@
<template>
<div class="container-fluid">
<div class="row justify-content-center">
<template v-if="canView">
<!--start: show content if user entered the from title or is edit mode -->
<div v-if="isFormTitleEntered" class="col">
<h5 class="mb-4">
{{ keyValue?.value ?? "عنوان فرم وارد نشده است." }}
<NuxtLayout name="default" :menu="adminMenu">
<div class="container-fluid">
<div class="row justify-content-center">
<template v-if="canView">
<!--start: show content if user entered the from title or is edit mode -->
<div v-if="isFormTitleEntered" class="col">
<h5 class="mb-4">
{{ keyValue?.value ?? "عنوان فرم وارد نشده است." }}
<button-component
classes="d-inline-flex"
@click="openNewFormModal"
buttonText=""
>
<span class="tavasi tavasi-Component-242--1"></span>
</button-component>
</h5>
<button-component
classes="d-inline-flex"
@click="openNewFormModal"
buttonText=""
>
<span class="tavasi tavasi-Component-242--1"></span>
</button-component>
</h5>
<div class="row no-gutters justify-content-center">
<div class="col">
<div class="list-and-actions-container">
<!-- load Simple/Tab component -->
<keep-alive>
<component
:ref="formMode"
:is="formMode"
:formTitleData="form"
:newFormItem="newFormItem"
@open-new-form-item="openNewFormItem"
></component>
</keep-alive>
<div class="row no-gutters justify-content-center">
<div class="col">
<div class="list-and-actions-container">
<!-- load Simple/Tab component -->
<keep-alive>
<component
:ref="formMode"
:is="formMode"
:formTitleData="form"
:newFormItem="newFormItem"
@open-new-form-item="openNewFormItem"
></component>
</keep-alive>
<!--start: form actions ( save/preview form) -->
<div class="d-flex justify-content-end mt-5 ms-3 form-actions">
<button-component
classes="btn btn-secondary mx-2"
@click="showFormPreView"
buttonText="پیش نمایش فرم"
<!--start: form actions ( save/preview form) -->
<div
class="d-flex justify-content-end mt-5 ms-3 form-actions"
>
</button-component>
<button-component
classes="btn btn-secondary mx-2"
@click="showFormPreView"
buttonText="پیش نمایش فرم"
>
</button-component>
<button-component
classes="btn btn-primary"
@click="saveFinalForm"
buttonText="ذخیره"
>
</button-component>
<button-component
classes="btn btn-primary"
@click="saveFinalForm"
buttonText="ذخیره"
>
</button-component>
</div>
<!--end: form actions ( save/preview form) -->
</div>
<!--end: form actions ( save/preview form) -->
</div>
<!-- start: create new form element -->
<div class="col-auto" v-if="showNewFormItem">
<NewFormItem
:key="changeDetectionCounter"
@close-new-form-item="closeNewFormItem"
@add-item-content="addFormItemToFormElements"
:editFormData="editFormData"
></NewFormItem>
</div>
<!-- end: create new form element -->
</div>
<!-- start: create new form element -->
<div class="col-auto" v-if="showNewFormItem">
<new-form-item
:key="changeDetectionCounter"
@close-new-form-item="closeNewFormItem"
@add-item-content="addFormItemToFormElements"
:editFormData="editFormData"
></new-form-item>
</div>
<!-- end: create new form element -->
</div>
</div>
<!--end: show content if user entered the from title or is edit mode -->
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<!--end: show content if user entered the from title or is edit mode -->
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</div>
</no-data>
</no-data>
</div>
<!-- create new form modal -->
<base-modal
v-if="showNewFormTitleModal"
modalSize="modal-md"
modalTitle="فرم جدید"
@close="closeFormModal"
@save="saveFormTitle"
>
<form-builder
ref="titleFormBuilder"
:formElements="formItem"
:formData="form"
></form-builder>
</base-modal>
<!--form preview modal -->
<base-modal
v-if="showPreviewModal"
:showSaveButton="false"
modalSize="modal-lg"
modalTitle="فرم پیش نمایش"
@close="closePreviewModal"
@save="saveFinalForm"
>
<!-- displayMode : horizontal | vertical -->
<form-builder
ref="previewFormBuilder"
displayMode="horizontal"
:formElements="previewFormItems"
:formData="previewFormItemsData"
></form-builder>
</base-modal>
</div>
<!-- create new form modal -->
<base-modal
v-if="showNewFormTitleModal"
modalSize="modal-md"
modalTitle="فرم جدید"
@close="closeFormModal"
@save="saveFormTitle"
>
<form-builder
ref="titleFormBuilder"
:formElements="formItem"
:formData="form"
></form-builder>
</base-modal>
<!--form preview modal -->
<base-modal
v-if="showPreviewModal"
:showSaveButton="false"
modalSize="modal-lg"
modalTitle="فرم پیش نمایش"
@close="closePreviewModal"
@save="saveFinalForm"
>
<!-- displayMode : horizontal | vertical -->
<form-builder
ref="previewFormBuilder"
displayMode="horizontal"
:formElements="previewFormItems"
:formData="previewFormItemsData"
></form-builder>
</base-modal>
</div>
</NuxtLayout>
</template>
<script>
import keyValueApi from "@apis/keyValueApi";
import HttpService from "@services/httpService";
import { mapActions } from "vuex";
import keyValueApi from "~/apis/keyValueApi";
import adminMenu from "~/json/admin/json/menu.json";
// import HttpService from "@services/httpService";
// import { mapActions } from "vuex";
import { mapState, mapActions } from "pinia";
import { useCommonStore } from "~/stores/commonStore";
import { defineAsyncComponent } from "vue";
export default {
name: "newForm",
setup() {
definePageMeta({
name: "newForm",
layout: false,
});
},
beforeMount() {
this.httpService = new HttpService();
// this.httpService = new HttpService();
this.httpService = useNuxtApp()["$http"];
},
mounted() {
this.checkPermisionBeforGetList();
},
data() {
return {
adminMenu: adminMenu,
canView: false,
changeDetectionCounter: 0,
isFormTitleEntered: false,
@ -221,7 +232,8 @@ export default {
};
},
methods: {
...mapActions(["checkPermissions"]),
// ...mapActions(["checkPermissions"]),
...mapActions(useCommonStore, ["checkPermissions"]),
checkPermisionBeforGetList() {
const isEditMode = Boolean(this.$route.params.id);
this.checkPermissions({
@ -260,7 +272,7 @@ export default {
this.buttonLoading = true;
const url =
this.keyValueMicroServiceName + this.$route.params.id
this.keyValueUrl() + this.$route.params.id
? keyValueApi.forms.edit
: keyValueApi.forms.add;
@ -279,7 +291,7 @@ export default {
this.httpService
.postRequest(url, formData)
.then((res) => {
this.mySwalToast({
mySwalToast({
title: res.message,
html: null,
icon: "success",
@ -331,7 +343,7 @@ export default {
if (this.fetchingData) return;
this.fetchingData = true;
const url = this.keyValueMicroServiceName + keyValueApi.forms.get;
const url = this.keyValueUrl()+ keyValueApi.forms.get;
return await this.httpService
.getRequest(url + "/" + formId)
.then((res) => {
@ -358,7 +370,7 @@ export default {
this.form = this.$refs.titleFormBuilder.localFormData;
const url =
this.keyValueMicroServiceName + this.$route.params.id
this.keyValueUrl() + this.$route.params.id
? keyValueApi.forms.edit
: keyValueApi.forms.add;
@ -373,7 +385,7 @@ export default {
this.httpService
.postRequest(url, formData)
.then((res) => {
this.mySwalToast({
mySwalToast({
title: "تبریک",
html: res.message,
icon: "success",
@ -415,17 +427,18 @@ export default {
},
},
components: {
NewFormItem: () =>
import(
"@forms/forms/NewFormItem.vue"
),
SimpleForm: () =>
import(
"@forms/components/SimpleForm.vue"
),
TabForm: () =>
import( "@forms/components/TabForm.vue"),
// NewFormItem: () => import("@forms/forms/NewFormItem.vue"),
// SimpleForm: () => import("@forms/components/SimpleForm.vue"),
// TabForm: () => import("@forms/components/TabForm.vue"),
TabForm: defineAsyncComponent(() =>
import("@/components/admin/components/TabForm.vue")
),
SimpleForm: defineAsyncComponent(() =>
import("@/components/admin/components/SimpleForm.vue")
),
NewFormItem: defineAsyncComponent(() =>
import("@/components/admin/components/NewFormItem.vue")
),
},
};
</script>

View File

@ -1,106 +1,107 @@
<template>
<div class="container-fluid">
<div class="row justify-content-center">
<template v-if="canView">
<div class="col-12">
<div class="sub-header mb-3">
<div class="d-flex">
<NuxtLayout name="default" :menu="adminMenu">
<div class="container-fluid">
<div class="row justify-content-center">
<template v-if="canView">
<div class="col-12">
<div class="sub-header mb-3">
<div class="d-flex">
<label class="ms-2" for="form_id">فرم: </label>
<select
name="form_id"
id="form_id"
v-model="formId"
class="form-control text__14"
@change="showFormItem"
<div class="d-flex">
<label class="ms-2" for="form_id">فرم: </label>
<select
name="form_id"
id="form_id"
v-model="formId"
class="form-control text__14"
@change="showFormItem"
>
<template v-if="forms.length">
<option disabled :value="undefined" selected>
انتخاب مورد
</option>
<option
v-for="(form, index) in forms"
:key="index"
:value="form.id"
>
{{ form.title }}
</option>
</template>
<option v-else :value="undefined" selected>
موردی ثبت نشده است.
</option>
</select>
</div>
<div class="select-diplay-mode">
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="displayMode"
id="table"
:value="0"
v-model="selectedForm.listType"
/>
<label class="form-check-label" for="table">جدولی</label>
</div>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="displayMode"
id="list"
:value="1"
v-model="selectedForm.listType"
/>
<label class="form-check-label" for="list">فهرستی</label>
</div>
</div>
</div>
<div class="subset-sub-header">
<button-component
title="ایجاد"
classes="btn d-inline-flex px-2 "
@click="openForm"
buttonText=""
>
<template v-if="forms.length">
<option disabled :value="undefined" selected>
انتخاب مورد
</option>
<option
v-for="(form, index) in forms"
:key="index"
:value="form.id"
>
{{ form.title }}
</option>
</template>
<option v-else :value="undefined" selected>
موردی ثبت نشده است.
</option>
</select>
<span class="tavasi tavasi-Component-212--1"
><span class="path1"></span><span class="path2"></span
><span class="path3"></span
></span>
</button-component>
</div>
<div class="select-diplay-mode">
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="displayMode"
id="table"
:value="0"
v-model="selectedForm.listType"
/>
<label class="form-check-label" for="table">جدولی</label>
</div>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="displayMode"
id="list"
:value="1"
v-model="selectedForm.listType"
/>
<label class="form-check-label" for="list">فهرستی</label>
</div>
</div>
</div>
<div class="subset-sub-header">
<button-component
title="ایجاد"
classes="btn d-inline-flex px-2 "
@click="openForm"
buttonText=""
>
<span class="tavasi tavasi-Component-212--1"
><span class="path1"></span><span class="path2"></span
><span class="path3"></span
></span>
</button-component>
</div>
</div>
</div>
<div class="col">
<div class="list-and-actions-container">
<my-table
:key="changeDetectionCounter"
height="auto"
maxHeight="calc(100vh - 15em)"
:isDraggable="true"
:isSortable="true"
:items="
selectedForm[LIST_TYPES[selectedForm.listType]]?.items ?? []
"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:tableActions="tableActions"
:paginationInfo="pagination"
@edit-table-item="editItem"
@delete-table-item="deleteItem"
@onSort="onSort"
@on-linked-title-click="onLinkedTitleClick"
/>
<div class="col">
<div class="list-and-actions-container">
<my-table
:key="changeDetectionCounter"
height="auto"
maxHeight="calc(100vh - 15em)"
:isDraggable="true"
:isSortable="true"
:items="
selectedForm[LIST_TYPES[selectedForm.listType]]?.items ?? []
"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:tableActions="tableActions"
:paginationInfo="pagination"
@edit-table-item="editItem"
@delete-table-item="deleteItem"
@onSort="onSort"
@on-linked-title-click="onLinkedTitleClick"
/>
<div
class="d-flex justify-content-end mt-5 ms-3 form-actions"
v-if="showSaveButton"
>
<!-- <button
<div
class="d-flex justify-content-end mt-5 ms-3 form-actions"
v-if="showSaveButton"
>
<!-- <button
@click.prevent="resetForm()"
type="button"
class="btn btn-secondary mx-2"
@ -108,49 +109,54 @@
>
باز نشانی
</button> -->
<button
@click.prevent="saveFinalForm()"
type="button"
class="btn btn-primary"
>
ذخیره
</button>
<button
@click.prevent="saveFinalForm()"
type="button"
class="btn btn-primary"
>
ذخیره
</button>
</div>
</div>
</div>
</div>
<!-- new form item to create new element -->
<div class="col-auto" v-if="shwoPreviewForm">
<table-column-select-form
:selectedItem="rowItem"
:selectedForm="selectedForm"
@close-form-show="closeFormShow"
@update-column="updateColumn"
></table-column-select-form>
</div>
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
<!-- new form item to create new element -->
<div class="col-auto" v-if="shwoPreviewForm">
<table-column-select-form
:selectedItem="rowItem"
:selectedForm="selectedForm"
@close-form-show="closeFormShow"
@update-column="updateColumn"
></table-column-select-form>
</div>
</div>
</no-data>
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</no-data>
</div>
</div>
</div>
</NuxtLayout>
</template>
<script>
import apis from "@apis/adminApi";
import HttpService from "@services/httpService";
// import tableActions from "@forms/json/selectListColumnAction";
import apis from "~/apis/adminApi";
import adminMenu from "~/json/admin/json/menu.json";
import { mapState, mapActions } from "pinia";
import { useCommonStore } from "~/stores/commonStore";
import { defineAsyncComponent } from "vue";
// import HttpService from "@services/httpService";
import tableActions from "~/json/admin/json/selectListColumnAction.json";
// import { mapActions } from "vuex";
const LIST_TYPES = {
@ -163,16 +169,18 @@ export default {
setup() {
definePageMeta({
name: "selectListColumnsCreate",
layout: false,
});
},
mounted() {
this.httpService = new HttpService();
// this.httpService = new HttpService();
this.httpService = useNuxtApp()["$http"];
this.checkPermisionBeforGetList();
},
data() {
return {
canView: false,
adminMenu: adminMenu,
changeDetectionCounter: 0,
LIST_TYPES: LIST_TYPES,
rowItem: {},
@ -215,7 +223,8 @@ export default {
},
methods: {
...mapActions(["checkPermissions"]),
...mapActions(useCommonStore, ["checkPermissions"]),
// ...mapActions(["checkPermissions"]),
checkPermisionBeforGetList() {
this.checkPermissions({
permission: "forms_select-list-columns",
@ -282,7 +291,7 @@ export default {
this.httpService
.postRequest(url, formData)
.then((res) => {
this.mySwalToast({
mySwalToast({
title: res.message,
html: null,
icon: "success",
@ -307,7 +316,7 @@ export default {
...this.pagination,
};
let url = this.keyValueMicroServiceName + apis.projectForm.list;
let url = keyValueUrl() + apis.projectForm.list;
return await this.httpService
.postRequest(url, formData)
.then((response) => {
@ -364,7 +373,7 @@ export default {
].items.filter((item) => item.key == updatedColumn.key);
if (res.length)
this.mySwalToast({
mySwalToast({
title: "ستونی با چنین مشخصاتی قبلا ایجاد شده است.",
html: null,
icon: "error",
@ -414,7 +423,7 @@ export default {
this.selectedForm[this.LIST_TYPES[this.selectedForm.listType]].items
.length > 1
) {
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار!!!",
html: "از حذف این مورد مطمئن هستید؟",
}).then((result) => {
@ -425,7 +434,7 @@ export default {
}
});
} else
this.mySwalToast({
mySwalToast({
title: "حداقل تعداد ستون های جدول یک می باشد.",
html: null,
icon: "error",
@ -439,7 +448,7 @@ export default {
components: {
TableColumnSelectForm: defineAsyncComponent(() =>
import("@components/forms/TableColumnSelectForm.vue")
)
),
},
};
</script>

View File

@ -1,77 +1,85 @@
<template>
<div>
<Multiselect
:allow-empty="false"
:searchable="true"
:close-on-select="true"
:show-labels="false"
:value="value"
:options="options"
class="multi mb-2"
@select="select"
label="label"
track-by="key"
placeholder="دسته"
:hide-selected="false"
:max-height="200"
:max-width="200"
>
</Multiselect>
<MyTable
height="auto"
maxHeight="calc(100vh - 9em)"
class="my-table"
ref="sectionsTable"
:hasSearch="false"
:tableActions="tableActions"
:items="sections"
:tableColumns="tableColumns"
:paginationInfo="pagination"
:totalPages="pagination.pages"
@delete-table-item="deleteItem"
@edit-table-item="editTableItem"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<!-- :fetchingData="fetchingData" :totalPages="pagination.pages"
<NuxtLayout name="default" :menu="adminMenu">
<div>
<Multiselect
:allow-empty="false"
:searchable="true"
:close-on-select="true"
:show-labels="false"
:value="value"
:options="options"
class="multi mb-2"
@select="select"
label="label"
track-by="key"
placeholder="دسته"
:hide-selected="false"
:max-height="200"
:max-width="200"
>
</Multiselect>
<my-table
height="auto"
maxHeight="calc(100vh - 9em)"
class="my-table"
ref="sectionsTable"
:hasSearch="false"
:tableActions="tableActions"
:items="sections"
:tableColumns="tableColumns"
:paginationInfo="pagination"
:totalPages="pagination.pages"
@delete-table-item="deleteItem"
@edit-table-item="editTableItem"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<!-- :fetchingData="fetchingData" :totalPages="pagination.pages"
@delete-table-item="deleteItem" @edit-table-item="toggleRolesPanel"
@page-changed="pageChanged" @page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged" -->
<!-- :paginationInfo="pagination"
<!-- :paginationInfo="pagination"
:sortingInfo="sorting -->
</MyTable>
<base-modal
v-if="openSubjectForm"
modalSize="modal-lg"
:hasFooter="false"
@close="closeModal"
>
<component
:is="slotComponentName"
:editList="editList"
</my-table>
<base-modal
v-if="openSubjectForm"
modalSize="modal-lg"
:hasFooter="false"
@close="closeModal"
></component>
</base-modal>
</div>
>
<component
:is="slotComponentName"
:editList="editList"
@close="closeModal"
></component>
</base-modal>
</div>
</NuxtLayout>
</template>
<script>
import settingsApi from "~/apis/settingsApi";
import adminMenu from "~/json/admin/json/menu.json";
import { mapState, mapActions } from "pinia";
import searchApi from "~/apis/searchApi";
import { useStorage } from "@vueuse/core";
import { useCommonStore } from "~/stores/commonStore";
import { useSearchStore } from "~/stores/searchStore";
export default {
name: "guidesList",
setup() {
definePageMeta({
name: "guidesList",
layout: false,
});
},
computed: {
...mapState(useSearchStore, ["helpSchemaGetter"]),
...mapState(["organNameGetter"]),
...mapState(useCommonStore, ["organNameGetter"]),
// ...mapState(["organNameGetter"]),
myActiveSchema() {
return this.helpSchemaGetter?.find((item) => {
return item.key == "help";
@ -79,7 +87,7 @@ export default {
},
},
mounted() {
let localStoageHelpSchema = useStorage("settingSchema",undefined).value;
let localStoageHelpSchema = useStorage("settingSchema", undefined).value;
if (localStoageHelpSchema) {
let helpSchema = JSON.parse(localStoageHelpSchema);
@ -93,6 +101,7 @@ export default {
},
data() {
return {
adminMenu: adminMenu,
options: [{ name: "جستجو" }, { name: "محتوا" }, { name: "مطالعه" }],
httpService: undefined,
value: "",
@ -160,11 +169,12 @@ export default {
};
},
beforeMount() {
this.httpService = new HttpService(import.meta.env.VITE_REPO_BASE_URL);
// this.httpService = new HttpService(import.meta.env.VITE_REPO_BASE_URL);
this.httpService = useNuxtApp()["$http"];
},
methods: {
...mapActions("search", ["helpSchemaSetter"]),
// ...mapActions("search", ["helpSchemaSetter"]),
...mapActions(useSearchStore, ["helpSchemaSetter"]),
openModal(componentName, title) {
this.openSubjectForm = true;
this.slotComponentName = componentName;
@ -191,7 +201,7 @@ export default {
this.openModal("editModalItem", "فیلتر ها");
},
deleteItem(item) {
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار!!!",
html: "تمامی اطلاعات پاک خواهد. آیا مطمئن هستید؟ ",
}).then((result) => {
@ -199,8 +209,8 @@ export default {
var id = this.listSections[item]?._id;
let url = settingsApi.help.delete;
url = url.replace("{{id}}", id);
this.httpService.postRequest(url).then((response) => {
this.mySwalToast({
this.httpService.postRequest(repoUrl() + url).then((response) => {
mySwalToast({
title: "با موفقیت حذف شد",
// html: response.data.message,
icon: "success",
@ -215,7 +225,7 @@ export default {
url = url.replace("{{key_option}}", this.value?.key);
url = url.replace("{{offset}}", this.pagination?.offset);
url = url.replace("{{limit}}", this.pagination?.limit);
this.httpService.getRequest(url).then((response) => {
this.httpService.getRequest(repoUrl() + url).then((response) => {
let list = response.hits?.hits;
this.listSections = list;
if (this.sections.length >= 0) this.sections = [];
@ -239,7 +249,7 @@ export default {
},
getSchemas() {
this.httpService
.postRequest(searchApi.schema.list, {
.postRequest(repoUrl() + searchApi.schema.list, {
organ: this.organNameGetter,
system: "setting",
build_state: buildState(),

View File

@ -0,0 +1,242 @@
<template>
<NuxtLayout name="default" :menu="adminMenu">
<div class="page">
<div class="container">
<form>
<div class="form-row">
<div class="col-3">
<label for=""> انتخاب بخش:</label>
<multiselect
:allow-empty="false"
:searchable="true"
:close-on-select="true"
:show-labels="false"
:value="value"
:options="options"
class="multi"
@select="select"
label="label"
track-by="key"
placeholder="دسته"
:hide-selected="false"
:max-height="200"
>
</multiselect>
</div>
</div>
<div class="form-row">
<div class="col-6">
<label for="">عنوان سوال:</label>
<input
type="text"
class="form-control"
placeholder="عنوان سوال را کوتاه و واضح وارد نمایید"
v-model="title"
/>
</div>
<div class="col-6">
<label for="">نشانی صفحه:</label>
<input
type="text"
class="form-control"
placeholder="نشانی از همین سامانه انتخاب کنید"
v-model="link"
/>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="">توضیح کوتاه:</label>
<input
type="text"
placeholder="توضیح مختصر حداکثر یک خط باشد"
v-model="description"
maxlength="500"
/>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="" class="mt-2">توضیح مفصل:</label>
<quill-editor
v-model="editorData"
content-type="html"
:options="editorOptions"
></quill-editor>
<!-- <VueEditor
dir="rtl"
v-model="editorData"
:editorOptions="editorOptions"
></VueEditor> -->
</div>
</div>
</form>
<button class="btn-save" @click="saveData">ذخیره</button>
</div>
</div>
</NuxtLayout>
</template>
<script>
import searchApi from "~/apis/searchApi";
import settingsApi from "~/apis/settingsApi";
import adminMenu from "~/json/admin/json/menu.json";
// import { VueEditor } from "vue2-editor";
import { mapState, mapActions } from "pinia";
import { useStorage } from "@vueuse/core";
import { useCommonStore } from "~/stores/commonStore";
import { useSearchStore } from "~/stores/searchStore";
export default {
name: "adminGuides",
setup() {
definePageMeta({
name: "adminGuides",
layout: false,
});
},
beforeMount() {
// this.httpService = new HttpService(import.meta.env.VITE_REPO_BASE_URL);
this.httpService = useNuxtApp()["$http"];
},
computed: {
...mapState(useSearchStore, ["helpSchemaGetter"]),
...mapState(useCommonStore, ["organNameGetter"]),
},
mounted() {
let localStoageHelpSchema = useStorage("settingSchema", undefined).value;
if (localStoageHelpSchema) {
let helpSchema = JSON.parse(localStoageHelpSchema);
this.helpSchemaSetter(helpSchema);
this.options = this.helpSchemaGetter[0].category;
} else this.getSchemas();
},
data() {
return {
adminMenu: adminMenu,
value: "",
editorData: "",
title: "",
link: "",
description: "",
fullDesc: "",
httpService: undefined,
options: [{ name: "جستجو" }, { name: "محتوا" }, { name: "مطالعه" }],
editorOptions: {
theme: "snow", // تم ویرایشگر: 'snow' یا 'bubble'
placeholder: "متن خود را بنویسید...",
modules: {
toolbar: [
[{ header: [1, 2, 3, false] }], // سطح هدینگها
["bold", "italic", "underline", "strike"], // دکمههای استایل متن
[{ color: [] }, { background: [] }], // رنگ متن و پسزمینه
[{ list: "ordered" }, { list: "bullet" }], // لیستهای شمارهدار و نقطهای
["blockquote", "code-block"], // نقلقول و کد
[{ align: [] }], // تراز بندی متن
["link", "image", "video"], // افزودن لینک، تصویر، و ویدیو
["clean"], // حذف فرمتها
],
},
},
};
},
methods: {
// ...mapActions("search", ["helpSchemaSetter"]),
...mapActions(useSearchStore, ["helpSchemaSetter"]),
// searchStore
select(e) {
this.value = e;
},
getSchemas() {
this.httpService
.postRequest(repoUrl() + searchApi.schema.list, {
organ: this.organNameGetter,
system: "setting",
build_state: buildState(),
})
.then((response) => {
this.helpSchemaSetter(response.data.setting);
this.options = this.helpSchemaGetter[0].category;
// this.options = response;
});
},
saveData() {
var origin = location.origin;
let cleaned = this.link;
if (this.link.startsWith(origin) || this.link == "") {
cleaned = this.link.replace(origin, "");
} else {
let errorMessage = "نشانی پیوند باید با " + origin + "شروع شود";
mySwalToast({
title: errorMessage,
// html: response.data.message,
icon: "error",
timer: 7000,
});
return "";
}
let payload = {
value_key: this.value.key,
value: this.editorData,
meta: {
title: this.title,
link: cleaned,
description: this.description,
},
};
this.httpService
.postRequest(repoUrl() + settingsApi.help.addItem, payload)
.then((response) => {
mySwalToast({
title: "با موفقیت ثبت شد",
// html: response.data.message,
icon: "success",
});
this.resetItem();
// this.helpSchemaSetter(response.data.setting);
// this.options = response;
});
},
resetItem() {
this.title = "";
this.link = "";
this.description = "";
this.editorData = "";
},
},
};
</script>
<style scoped lang="scss">
input {
border-radius: 0.5rem;
border: 2px solid rgb(127, 170, 170);
font-size: 14px;
height: 3em;
width: 100%;
&::placeholder {
color: #a7a098;
}
}
.multi {
// width: 200px;
border: 2px solid rgb(127, 170, 170);
border-radius: 0.5rem;
}
.btn-save {
width: 100px;
height: 2.5em;
float: left;
background-color: white;
margin-top: 0.8em;
border-radius: 0.5rem;
border: 2px solid rgb(127, 170, 170);
}
.page {
height: calc(100vh - 5em);
}
</style>

View File

@ -1,56 +0,0 @@
<template>
<div class="main" id="top">
<header>
<the-navbar></the-navbar>
</header>
<the-sidebar :menu="menu"></the-sidebar>
<main
class="pages-content-container p-3"
:class="{ 'expanded': !isSidebarCollapsed }"
>
<router-view></router-view>
</main>
</div>
</template>
<script>
import { mapState, mapActions } from "pinia";
import menu from "~/json/admin/json/menu.json";
export default {
data() {
return {
menu: menu,
};
},
computed: {
...mapState(["isSidebarCollapsed"]),
},
methods: {
...mapActions(["TOGGLE_PANEL"]),
toggleSidebarMenu() {
this.$store.commit('TOGGLE_SIDEBAR_MENU')
},
},
beforeCreate() {
ApiService.init(import.meta.env.VITE_REPO_BASE_URL);
},
mounted() {
this.TOGGLE_PANEL(false);
},
};
</script>
<style scoped lang="scss">
.navbar-2 {
// background: linear-gradient(45deg, #7ce2fb, #51d3f3);
// color: #fff;
background-color: #fbfafd;
// border-bottom: 1px solid #e9e9e9;
}
</style>

View File

@ -1,437 +0,0 @@
<template>
<div>
<!-- <header>
<the-navbar></the-navbar>
</header>
<the-sidebar :menu="menu"></the-sidebar> -->
<main class="pages-content-container">
<div class="pages-content mt-4 mt-lg-0">
<div class="p-3" :class="{ 'd-flex': showPanel }">
<div v-if="canView">
<my-table
:tableActions="tableActions"
height="calc(100vh - 17em)"
:hasSearch="true"
minHeight="25em"
maxHeight="calc(100dvh - 5em)"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="groups"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@search="searchGroups"
@reset-form="searchGroups"
@delete-table-item="deleteItem"
@edit-table-item="toggleUsersPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<slot name="tableHeaderActions">
<div class="dropdown">
<button
class="btn dropdown-toggle"
type="button"
data-toggle="dropdown"
aria-expanded="false"
>
{{ groupsTranslation[searchType] }}
</button>
<div class="dropdown-menu text-right">
<button
class="dropdown-item"
type="button"
@click.prevent="setSearchType('getGroupsWithoutAdmin')"
:class="{ active: searchType == 'getGroupsWithoutAdmin' }"
value="getGroupsWithoutAdmin"
>
{{ groupsTranslation["getGroupsWithoutAdmin"] }}
</button>
<button
class="dropdown-item"
type="button"
@click.prevent="setSearchType('getGroupsWithAdmin')"
:class="{ active: searchType == 'getGroupsWithAdmin' }"
value="getGroupsWithAdmin"
>
{{ groupsTranslation["getGroupsWithAdmin"] }}
</button>
</div>
</div>
</slot>
</my-table>
</div>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div
v-else
class="d-flex justify-content-center align-items-center"
>
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ml-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</no-data>
<div class="side-panel" v-if="showPanel">
<div
class="side-panel-header d-flex mb-3 pb-3 border-bottom align-items-center"
>
<h5 class="m-0">جستجو و انتخاب مدیر گروه</h5>
<button
@click.prevent="toggleUsersPanel(undefined)"
class="btn mr-auto"
type="button"
>
<svg class="icon icon-Component-294--1">
<use xlink:href="#icon-Component-294--1"></use>
</svg>
</button>
</div>
<div class="side-panel-content">
<users-search
v-if="showPanel"
:searchResults="users"
@on-send="searchUsers"
@set-as-admin="setAsAdmin"
></users-search>
</div>
</div>
</div>
</div>
</main>
</div>
</template>
<script>
import { mapState, mapActions } from "pinia";
import menu from "~/json/admin/json/menu.json";
import adminApi from "~/apis/adminApi";
import permitApis from "~/apis/permitApi";
export default {
beforeMount() {
this.httpService = new HttpService(import.meta.env.VITE_BASE_URL);
},
mounted() {
this.checkPermisionBeforGetList();
},
data() {
return {
searchType: "getGroupsWithoutAdmin",
groupsTranslation: {
getGroupsWithoutAdmin: "گروه های بدون مدیر",
getGroupsWithAdmin: "گروه های دارای مدیر",
},
groups: [],
menu: menu,
firstTimeSearching: false,
httpService: undefined,
tableActions: [
{
showOutside: true,
show: true,
icon: "tavasi tavasi-Component-242--1",
title: "تعیین مدیر",
to: {
name: "undefined",
},
selected: false,
disabled: false,
howToOpen: "",
href: "",
class: "edit-btn",
action: "edit-table-item",
},
{
showOutside: true,
show: true,
icon: "tavasi tavasi-Component-295--1",
title: "حذف",
to: {
name: "undefined",
},
selected: false,
disabled: false,
howToOpen: "",
href: "",
class: "delete-btn",
action: "delete-table-item",
},
],
canView: false,
fetchingData: false,
tableColumns: [
{
isLink: true,
key: "title",
title: "عنوان",
width: "2",
},
{
isLink: true,
key: "desc",
title: "توضیحات",
width: "2",
},
],
pagination: {
page: 1,
pages: 0,
total: 0,
offset: 0,
limit: 10,
},
sorting: {
sortby: "title",
sortorder: "asc", // asc | desc | none
},
users: [],
loading: false,
showPanel: false,
selectedItemClone: undefined,
prevSelectedItemIndex: undefined,
};
},
methods: {
...mapState(["isSidebarCollapsed"]),
...mapActions(["checkPermissions"]),
checkPermisionBeforGetList() {
if (this.fetchingData) return;
this.fetchingData = true;
this.checkPermissions({ _this: this, permission: "groups_view" })
.then(() => {
this.getGroupsWithoutAdmin()
.then(() => {
this.canView = true;
this.fetchingData = false;
})
.catch(() => {
this.canView = false;
this.fetchingData = false;
});
})
.catch(() => {
this.canView = false;
this.fetchingData = false;
});
},
async getGroupsWithoutAdmin(query = "") {
let url = `${messageUrl()}/${adminApi.groups.groupsWithoutAdmin}`;
return await this.httpService
.getRequest(this.updateUrl(url, query))
.then((res) => {
this.groups = res.data;
this.pagination = { ...this.pagination, ...res.pagination };
});
},
getGroupsWithAdmin() {
if (this.fetchingData) return;
this.fetchingData = true;
let url = `${messageUrl()}/${adminApi.groups.groupsWithAdmin}`;
this.httpService
.getRequest(this.updateUrl(url))
.then((response) => {
this.groups = response.data;
this.pagination = { ...this.pagination, ...response.pagination };
})
.finally(() => {
this.fetchingData = false;
});
},
updateUrl(url, query = "") {
url = url.replace("@offset", this.pagination.offset);
url = url.replace("@limit", this.pagination.limit);
url = url.replace("@sortby", this.sorting.sortby);
url = url.replace("@sortorder", this.sorting.sortorder);
// for searching groups.
if (query?.length) url = url.replace("@query", query);
else url = url.replace("/@query", query);
return url;
},
async searchUsers(query = "") {
// this.resetPagination();
let url = loginUrl() + permitApis.users.search;
url = url.replace("{{offset}}", 0);
url = url.replace("{{limit}}", 50);
url = url.replace("{{sortby}}", "username");
url = url.replace("{{sortorder}}", "desc");
// removing '/' before query if query is empty.
if (query) url = url.replace("{{query}}", query);
else url = url.replace("/{{query}}", query);
return await this.httpService.getRequest(url).then((res) => {
this.users = res.data;
// this.pagination = { ...this.pagination, ...res.pagination };
});
},
// searchUsers(query = "") {
// this.resetPagination();
// this[this.searchType](query);
// // this.getGroupsWithoutAdmin(query);
// },
searchGroups(query) {
this.resetPagination();
this[this.searchType](query);
},
setSearchType(groupType) {
this.searchType = groupType;
this.resetPagination();
this[groupType]();
},
removeGroupMember() {},
setAsAdmin(user) {
if (this.loading) return;
this.loading = true;
const url = messageUrl() + "/" + chatApi.groups.setAdmin;
let payload = {
user_id: user.id,
group_id: this.selectedItemClone.id,
};
this.httpService
.postRequest(url, payload)
.then((res) => {
this.getGroupsWithoutAdmin().then(() => {
this.loading = false;
});
this.mySwalToast({
html: res.message,
});
this.showPanel = false;
this.resetForm();
})
.finally(() => {
this.loading = false;
});
},
toggleUsersPanel(index = undefined) {
if (index !== undefined) {
if (this.prevSelectedItemIndex !== undefined)
this.groups[this.prevSelectedItemIndex].active = false;
this.prevSelectedItemIndex = index;
this.$set(this.groups[index], "active", true);
this.selectedItemClone = structuredClone(this.groups[index]);
this.showPanel = true;
} else {
this.resetForm();
}
},
resetForm() {
this.selectedItemClone = undefined;
this.users = [];
this.showPanel = false;
},
// pagination and sorting
resetPagination() {
this.pagination = {
pages: 0,
total: 0,
page: 1,
offset: 0,
limit: 10,
};
},
pageLimitChanged(paging) {
this.resetPagination();
this.pagination.limit = paging.limit;
this[this.searchType]();
},
pageChanged(paging) {
let page = paging.pageNumber;
page -= 1;
this.pagination.offset = page * paging.limit;
this.pagination.limit = paging.limit;
this.pagination.page = paging.pageNumber;
this[this.searchType]();
},
sortChanged(sorting) {
this.pagination.page = this.pagination.offset = 0;
this.sorting = sorting;
this[this.searchType]();
},
// not used yet.
deleteItem(index) {
if (this.loading) return;
this.loading = true;
let groupId = this.groups[index].id;
const payload = {
group_id: groupId,
};
const url = `${messageUrl()}/${adminApi.groups.delete}`;
this.mySwalConfirm({
title: "هشدار",
html: "با حذف گروه، تمامی مسائل و پاسخ های آن نیز حذف خواهد شد.",
icon: "warning",
}).then((result) => {
if (result.isConfirmed) {
this.httpService.postRequest(url, payload).then((res) => {
this[this.searchType]().then(() => {
this.loading = false;
// this.showPanel = false;
});
this.mySwalToast({
html: res.message,
});
});
}
});
},
openCreatePanel() {
this.selectedItemClone = undefined;
this.showPanel = true;
},
},
};
</script>
<style scoped lang="scss">
.side-panel {
padding: 1em;
width: 30em;
max-width: 100%;
background-color: #fafafa;
border-right: 1px solid #eee;
}
</style>

View File

@ -1,387 +0,0 @@
<template>
<div>
<!-- <header>
<the-navbar></the-navbar>
</header>
<the-sidebar :menu="menu"></the-sidebar> -->
<main class="pages-content-container">
<div class="pages-content mt-4 mt-lg-0">
<div class="p-3" :class="{ 'd-flex': showPanel }">
<div v-if="canView">
<my-table
:tableActions="tableActions"
height="calc(100vh - 17em)"
:hasSearch="true"
maxHeight="calc(100dvh - 5em)"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="users"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@search="searchGroups"
@reset-form="searchUsers"
@delete-table-item="deleteItem"
@edit-table-item="toggleUsersPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<template #tableHeaderActions>
<button
v-if="!showPanel"
@click.prevent="openCreatePanel()"
class="btn btn-primary"
type="button"
>
ایجاد
</button>
</template>
</my-table>
</div>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div
v-else
class="d-flex justify-content-center align-items-center"
>
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ml-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</no-data>
<div class="side-panel mx-5" v-if="showPanel">
<div class="side-panel-header d-flex mb-3 pb-3 border-bottom">
<h6 class="m-0">مدیریت کاربران</h6>
<button
@click.prevent="toggleUsersPanel(undefined)"
class="btn btn-outline-primary mr-auto"
type="button"
>
x
</button>
</div>
<div class="side-panel-content">
<new-user-form
:parentLoading="loading"
:userData="selectedItemClone"
@on-pass-by-emit="save"
></new-user-form>
</div>
</div>
</div>
</div>
</main>
</div>
</template>
<script>
import apis from "~/apis/permitApi";
import { mapState, mapActions } from "pinia";
import menu from "~/json/admin/json/menu.json";
export default {
beforeMount() {
this.httpService = new HttpService(
import.meta.env.VITE_BASE_URL + loginUrl()
);
},
mounted() {
this.checkPermisionBeforGetList();
},
// watch: {
// projectGetter() {
// this.showPanel = false;
// this.checkPermisionBeforGetList();
// },
// },
data() {
return {
menu: menu,
firstTimeSearching: false,
httpService: undefined,
tableActions: [
{
showOutside: true,
show: true,
icon: "tavasi tavasi-Component-242--1",
title: "ویرایش",
to: {
name: "undefined",
},
selected: false,
disabled: false,
howToOpen: "",
href: "",
class: "edit-btn",
action: "edit-table-item",
},
{
showOutside: true,
show: true,
icon: "tavasi tavasi-Component-295--1",
title: "حذف",
to: {
name: "undefined",
},
selected: false,
disabled: false,
howToOpen: "",
href: "",
class: "delete-btn",
action: "delete-table-item",
},
],
canView: false,
fetchingData: false,
tableColumns: [
{
isLink: true,
key: "name",
title: "نام",
width: "2",
},
{
isLink: true,
key: "lastname",
title: "نام خانوادگی",
width: "2",
},
{
key: "username",
title: "نام کاربری",
width: "2",
},
{
key: "email",
title: "ایمیل",
width: "2",
},
{
key: "is_active",
title: "فعال",
width: "2",
},
{
key: "admin",
title: "مدیر",
width: "2",
},
{
key: "mobile",
title: "موبایل",
width: "2",
},
{
key: "date_c",
title: "ایجاد",
width: "2",
},
{
key: "last-signed-int",
title: "آخرین ورود",
width: "2",
},
],
pagination: {
page: 1,
pages: 0,
total: 0,
offset: 0,
limit: 10,
},
sorting: {
sortby: "name",
sortorder: "asc", // asc | desc | none
},
users: [],
loading: false,
showPanel: false,
selectedItemClone: undefined,
prevSelectedItemIndex: undefined,
};
},
methods: {
...mapState(["isSidebarCollapsed"]),
...mapActions(["checkPermissions"]),
checkPermisionBeforGetList() {
if (this.fetchingData) return;
this.fetchingData = true;
this.checkPermissions({ _this: this, permission: "modifications_view" })
.then(() => {
this.getUsers()
.then(() => {
this.canView = true;
this.fetchingData = false;
})
.catch(() => {
this.canView = false;
this.fetchingData = false;
});
})
.catch(() => {
this.canView = false;
this.fetchingData = false;
});
},
async searchUsers(query = "") {
this.resetPagination();
let url = apis.users.search;
url = url.replace("{{offset}}", this.pagination.offset);
url = url.replace("{{limit}}", this.pagination.limit);
url = url.replace("{{sortby}}", this.sorting.sortby);
url = url.replace("{{sortorder}}", this.sorting.sortorder);
// removing '/' before query if query is empty.
if (query) url = url.replace("{{query}}", query);
else url = url.replace("/{{query}}", query);
return await this.httpService.getRequest(url).then((res) => {
this.users = res.data;
this.pagination = { ...this.pagination, ...res.pagination };
});
},
async getUsers() {
let url = apis.users.list;
url = url.replace("{{offset}}", this.pagination.offset);
url = url.replace("{{limit}}", this.pagination.limit);
url = url.replace("{{sortby}}", this.sorting.sortby);
url = url.replace("{{sortorder}}", this.sorting.sortorder);
return await this.httpService.getRequest(url).then((res) => {
this.users = res.data;
this.pagination = { ...this.pagination, ...res.pagination };
});
},
save(formData = undefined) {
if (this.loading) return;
this.loading = true;
const url = formData.id ? apis.users.update : apis.users.create;
formData;
this.httpService
.postRequest(url, formData)
.then((res) => {
this.getUsers().then(() => {
this.loading = false;
});
this.mySwalToast({
html: res.message,
});
this.showPanel = false;
this.resetForm();
})
.finally(() => {
this.loading = false;
});
},
deleteItem(index) {
if (this.loading) return;
this.loading = true;
let userId = this.users[index].id;
const payload = {
id: userId,
};
this.mySwalConfirm({
title: "هشدار",
html: "هشدار!!!!",
icon: "warning",
}).then((result) => {
if (result.isConfirmed) {
this.httpService
.postRequest(apis.users.delete, payload)
.then((res) => {
this.getUsers().then(() => {
this.loading = false;
this.showPanel = false;
});
this.mySwalToast({
html: res.message,
});
});
}
});
},
resetPagination() {
this.pagination = {
pages: 0,
total: 0,
page: 1,
offset: 0,
limit: 10,
};
},
pageLimitChanged(paging) {
this.resetPagination();
this.pagination.limit = paging.limit;
this.getUsers();
},
pageChanged(paging) {
let page = paging.pageNumber;
page -= 1;
this.pagination.offset = page * paging.limit;
this.pagination.limit = paging.limit;
this.pagination.page = paging.pageNumber;
this.getUsers();
},
sortChanged(sorting) {
this.pagination.page = this.pagination.offset = 0;
this.sorting = sorting;
this.getUsers();
},
openCreatePanel() {
this.selectedItemClone = undefined;
this.showPanel = true;
},
toggleUsersPanel(index = undefined) {
if (index !== undefined) {
if (this.prevSelectedItemIndex !== undefined)
this.users[this.prevSelectedItemIndex].active = false;
this.prevSelectedItemIndex = index;
this.$set(this.users[index], "active", true);
this.selectedItemClone = structuredClone(this.users[index]);
this.showPanel = true;
} else {
this.resetForm();
}
},
resetForm() {
this.selectedItemClone = undefined;
this.showPanel = false;
},
},
};
</script>
<style scoped lang="scss">
.side-panel-content {
min-width: 19em;
}
</style>

View File

@ -1,61 +0,0 @@
<template>
<div class="main" id="top">
<header>
<the-navbar></the-navbar>
</header>
<the-sidebar :menu="menu"></the-sidebar>
<main
class="pages-content-container p-3"
:class="{ 'expanded': !isSidebarCollapsed }"
>
<router-view></router-view>
</main>
</div>
</template>
<script>
import { mapState, mapActions } from "pinia";
import menu from "~/json/admin/json/menu.json";
export default {
name: "adminModuleLayout",
setup() {
definePageMeta({
name: "adminModuleLayout",
});
},
data() {
return {
menu: menu,
};
},
computed: {
...mapState(["isSidebarCollapsed"]),
},
methods: {
...mapActions(["TOGGLE_PANEL"]),
toggleSidebarMenu() {
this.$store.commit('TOGGLE_SIDEBAR_MENU')
},
},
beforeCreate() {
ApiService.init(import.meta.env.VITE_REPO_BASE_URL);
},
mounted() {
this.TOGGLE_PANEL(false);
},
};
</script>
<style scoped lang="scss">
.navbar-2 {
// background: linear-gradient(45deg, #7ce2fb, #51d3f3);
// color: #fff;
background-color: #fbfafd;
// border-bottom: 1px solid #e9e9e9;
}
</style>

View File

@ -39,84 +39,84 @@
</p>
</no-data>
<!-- <div class="side-panel" v-if="showRoles">
<div class="panel-form-header">
<h6 class="">{{ $t("DepartmentManagement") }}</h6>
</div>
<div class="side-panel" v-if="showRoles">
<div class="panel-form-header">
<h6 class="">{{ $t("DepartmentManagement") }}</h6>
</div>
<div class="side-panel-content">
<form class="form" role="section" @submit.prevent="save()">
<div class="form-group">
<label for="section_title">{{ $t("SectionTitle") }}</label>
<input
type="text"
class="form-control"
id="section_title"
name="section_title"
v-model="selectedItemClone.section_title"
/>
</div>
<div class="form-group">
<label for="action_title">{{ $t("ActionTitle") }} </label>
<input
type="text"
class="form-control"
id="action_title"
name="action_title"
v-model="selectedItemClone.action_title"
/>
</div>
<div class="form-group">
<label for="section_tag"> {{ $t("SectionTag") }}</label>
<input
type="text"
dir="ltr"
class="form-control"
id="section_tag"
name="section_tag"
v-model="selectedItemClone.section_tag"
/>
</div>
<div class="form-group">
<label for="action_tag"> {{ $t("ActionTag") }}</label>
<input
type="text"
dir="ltr"
class="form-control"
id="action_tag"
name="action_tag"
v-model="selectedItemClone.action_tag"
/>
</div>
<div class="side-panel-footer mt-4">
<div>
<button
type="submit"
class="btn btn-outline-primary"
:disabled="loading"
@click.prevent="save()"
>
<the-button-loading v-if="loading"></the-button-loading>
{{ $t("Submit") }}
</button>
<button
:disabled="loading"
@click.prevent="showRoles = false"
type="button"
class="btn btn-default"
data-dismiss="modal"
>
{{ $t("Cancel") }}
</button>
<div class="side-panel-content">
<form class="form" role="section" @submit.prevent="save()">
<div class="form-group">
<label for="section_title">{{ $t("SectionTitle") }}</label>
<input
type="text"
class="form-control"
id="section_title"
name="section_title"
v-model="selectedItemClone.section_title"
/>
</div>
</div>
</form>
<div class="form-group">
<label for="action_title">{{ $t("ActionTitle") }} </label>
<input
type="text"
class="form-control"
id="action_title"
name="action_title"
v-model="selectedItemClone.action_title"
/>
</div>
<div class="form-group">
<label for="section_tag"> {{ $t("SectionTag") }}</label>
<input
type="text"
dir="ltr"
class="form-control"
id="section_tag"
name="section_tag"
v-model="selectedItemClone.section_tag"
/>
</div>
<div class="form-group">
<label for="action_tag"> {{ $t("ActionTag") }}</label>
<input
type="text"
dir="ltr"
class="form-control"
id="action_tag"
name="action_tag"
v-model="selectedItemClone.action_tag"
/>
</div>
<div class="side-panel-footer mt-4">
<div>
<button
type="submit"
class="btn btn-outline-primary"
:disabled="loading"
@click.prevent="save()"
>
<the-button-loading v-if="loading"></the-button-loading>
{{ $t("Submit") }}
</button>
<button
:disabled="loading"
@click.prevent="showRoles = false"
type="button"
class="btn btn-default"
data-dismiss="modal"
>
{{ $t("Cancel") }}
</button>
</div>
</div>
</form>
</div>
</div>
</div> -->
</div>
</div>
</NuxtLayout>
@ -145,7 +145,6 @@ export default {
},
watch: {
projectGetter() {
this.showRoles = false;
this.checkPermisionBeforGetList();
},
getPanelStatus() {
@ -192,9 +191,7 @@ export default {
httpService: {},
canView: false,
fetchingData: false,
changeDetectionCounter: 1,
sections: [],
loading: false,
showRoles: false,
@ -212,7 +209,6 @@ export default {
sortby: "",
sortorder: "", // asc | desc
},
pagination: {
page: 1,
pages: 0,
@ -251,14 +247,11 @@ export default {
};
},
computed: {
// ...mapGetters("permit", ["projectGetter"]),
// ...mapGetters(["getPanelStatus"]),
...mapState(usePermitStore, ["projectGetter"]),
...mapState(useCommonStore, ["getPanelStatus"]),
},
methods: {
...mapActions(useCommonStore, ["checkPermissions"]),
// ...mapMutations("permit", ["SET_PROJECT"]),
...mapActions(usePermitStore, ["SET_PROJECT"]),
async getSections() {
@ -269,12 +262,12 @@ export default {
...this.sorting,
...this.pagination,
};
let url = "permit/" + apis.sections.list;
let url = permitUrl() + apis.sections.list;
return await this.httpService
.postRequest(url, payload)
.then((res) => {
this.sections = res.data.data;
this.pagination = { ...this.pagination, ...res.data.pagination };
this.sections = res.data;
this.pagination = { ...this.pagination, ...res.pagination };
})
.finally(() => {
@ -287,18 +280,20 @@ export default {
? apis.sections.edit
: apis.sections.add;
this.httpService.postRequest(url, this.selectedItemClone).then((res) => {
this.getSections();
this.httpService
.postRequest(permitUrl() + url, this.selectedItemClone)
.then((res) => {
this.getSections();
this.mySwalToast({
title: "تبریک",
html: "اطلاعات با موفقیت ذخیره شد.",
icon: "success",
mySwalToast({
title: "تبریک",
html: "اطلاعات با موفقیت ذخیره شد.",
icon: "success",
});
this.showRoles = false;
this.resetForm();
});
this.showRoles = false;
this.resetForm();
});
},
deleteItem(index) {
@ -309,18 +304,18 @@ export default {
id: sectionId,
};
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار",
html: "از حذف این بخش مطمئن هستید؟",
icon: "warning",
}).then((result) => {
if (result.isConfirmed) {
this.httpService
.postRequest(apis.sections.delete, data)
.postRequest(permitUrl() + apis.sections.delete, data)
.then((res) => {
this.getSections();
this.mySwalToast({
mySwalToast({
title: "تبریک",
html: "بخش با موفقیت حذف گردید.",
icon: "success",
@ -374,7 +369,7 @@ export default {
this.prevSelectedItemIndex = index;
this.sections[index].active = true;
this.selectedItemClone = structuredClone(this.sections[index]);
this.selectedItemClone = this.sections[index];
} else this.resetForm();
this.showRoles = true;
@ -392,7 +387,7 @@ export default {
checkPermisionBeforGetList() {
if (this.fetchingData) return;
this.fetchingData = true;
this.checkPermissions({ permission: "sections_view", _this: this })
.then(() => {
console.info("then");
@ -432,13 +427,13 @@ export default {
},
async getProjects() {
return await this.httpService
.postRequest(apis.projects.list)
.postRequest(permitUrl() + apis.projects.list)
.then((res) => {
console.log(
"🚀 ~ returnawaitthis.httpService.postRequest ~ res:",
res
);
this.SET_PROJECT(res.data.data[0]);
this.SET_PROJECT(res.data[0]);
});
},
},
@ -447,15 +442,6 @@ export default {
// SubHeaderWithSelect: defineAsyncComponent(() =>
// import("@/components/global/SubHeaderWithSelect.vue")
// ),
// TheContentLoading: defineAsyncComponent(() =>
// import("@/components/global/TheContentLoading.vue")
// ),
// MyTable: defineAsyncComponent(() =>
// import("@/components/global/MyTable.vue")
// ),
// NoData: defineAsyncComponent(() =>
// import("@/components/global/NoData.vue")
// ),
},
};
</script>

View File

@ -1,63 +1,63 @@
<template>
<NuxtLayout name="default" :menu="adminMenu">
<div class="pages role-section-page p-3">
<SubHeaderWithSelect
:enableNewButton="false"
:showProjectSelect="$attrs.showProjectSelect"
@open-form="toggleRolesPanel()"
title="دسترسی های کاربران"
>
</SubHeaderWithSelect>
<NuxtLayout name="default" :menu="adminMenu">
<div class="pages role-section-page p-3">
<SubHeaderWithSelect
:enableNewButton="false"
:showProjectSelect="$attrs.showProjectSelect"
@open-form="toggleRolesPanel()"
title="دسترسی های کاربران"
>
</SubHeaderWithSelect>
<div class="pages-content">
<template v-if="canView">
<div class="container">
<div class="row">
<div class="col-12 col-md-8 mx-auto">
<ul class="nav nav-tabs mb-3">
<li
v-for="({ id, title }, index) in roles"
:key="index"
:value="id"
class="nav-item"
>
<a
class="nav-link text-center"
:class="{ active: activeTabIndex == index }"
:href="title"
@click.prevent="onTabClick(id, index)"
<div class="pages-content">
<template v-if="canView">
<div class="container">
<div class="row">
<div class="col-12 col-md-8 mx-auto">
<ul class="nav nav-tabs mb-3">
<li
v-for="({ id, title }, index) in roles"
:key="index"
:value="id"
class="nav-item"
>
{{ title }}
</a>
</li>
</ul>
<a
class="nav-link text-center"
:class="{ active: activeTabIndex == index }"
:href="title"
@click.prevent="onTabClick(id, index)"
>
{{ title }}
</a>
</li>
</ul>
<Accordion
class="role-permission"
canEdit="role-permission_edit"
:role_id="role_id"
></Accordion>
<Accordion
class="role-permission"
canEdit="role-permission_edit"
:role_id="role_id"
></Accordion>
</div>
</div>
</div>
</div>
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</div>
</no-data>
</no-data>
</div>
</div>
</div>
</NuxtLayout>
</NuxtLayout>
</template>
<script>
@ -68,37 +68,26 @@ import { defineAsyncComponent } from "vue";
import { mapActions, mapState } from "pinia";
import { useCommonStore } from "~/stores/commonStore";
import { usePermitStore } from "~/stores/permitStore";
// import { DEFAULT_CONFIG } from "vue-codemirror";
// import { mapGetters, mapMutations, mapActions } from "vuex";
export default {
name:"rolePermission",
name: "rolePermission",
setup() {
definePageMeta({
name: "rolePermission",
layout: false,
});
},
mounted() {
this.checkPermisionBeforGetList();
},
watch: {
projectGetter() {
this.checkPermisionBeforGetList();
},
},
components: {
// BreadCrumb: () => import("@components/BreadCrumb.vue"),
// Accordion: () => import("@permission/components/Accordion.vue"),
// SubHeaderWithSelect: defineAsyncComponent(() =>
// import("@/components/global/SubHeaderWithSelect.vue")
// ),
// TheContentLoading: defineAsyncComponent(() =>
// import("@/components/global/TheContentLoading.vue")
// ),
// TheButtonLoading: defineAsyncComponent(() =>
// import("@/components/global/TheButtonLoading.vue")
// ),
// MyTable: defineAsyncComponent(() =>
// import("@/components/global/MyTable.vue")
// ),
// NoData: defineAsyncComponent(() =>
// import("@/components/global/NoData.vue")
// ),
// BreadCrumb: defineAsyncComponent(() =>
// import("@/components/global/BreadCrumb.vue")
// ),
Accordion: defineAsyncComponent(() =>
import("@/components/admin/components/Accordion.vue")
),
@ -108,7 +97,7 @@ export default {
},
data() {
return {
adminMenu:adminMenu,
adminMenu: adminMenu,
roles: [],
httpService: {},
collapseAll: false,
@ -140,7 +129,6 @@ export default {
// ...mapMutations("permit", ["SET_PROJECT"]),
// ...mapActions("permit", ["getProjects"]),
...mapActions(useCommonStore, ["checkPermissions"]),
...mapActions(usePermitStore, ["SET_PROJECT"]),
...mapActions(usePermitStore, ["getProjects"]),
@ -150,14 +138,17 @@ export default {
this.role_id = id;
},
async getRoles() {
return await ApiService.formData(apis.roles.list, {
project_id: this.projectGetter?.id,
}).then((response) => {
this.roles = response.data.data;
return await this.httpService
.postRequest(permitUrl() + apis.roles.list, {
project_id: this.projectGetter?.id,
})
.then((response) => {
this.roles = response?.data;
this.role_id =
this.roles && this.roles[0] ? this.roles[0].id : undefined;
});
this.role_id =
this.roles && this.roles[0] ? this.roles[0].id : undefined;
});
},
checkPermisionBeforGetList() {
if (this.fetchingData) return;
@ -195,9 +186,11 @@ export default {
});
},
async getProjects() {
return await ApiService.formData(apis.projects.list).then((res) => {
this.SET_PROJECT(res.data.data[0]);
});
return await this.httpService
.postRequest(permitUrl() + apis.projects.list)
.then((res) => {
this.SET_PROJECT(res.data[0]);
});
},
setProject(id) {
// const id = +$ev.target.value;
@ -207,13 +200,5 @@ export default {
this.SET_PROJECT(project);
},
},
mounted() {
this.checkPermisionBeforGetList();
},
// watch: {
// projectGetter() {
// this.checkPermisionBeforGetList();
// },
// },
};
</script>

View File

@ -1,120 +1,119 @@
<template>
<NuxtLayout name="default" :menu="adminMenu">
<div class="pages role-page px-3 pb-0 pt-2">
<sub-header-with-select
canCreate="roles_new"
@open-form="toggleRolesPanel"
:showProjectSelect="$attrs.showProjectSelect"
title="نقش ها"
></sub-header-with-select>
<NuxtLayout name="default" :menu="adminMenu">
<div class="pages role-page px-3 pb-0 pt-2">
<sub-header-with-select
canCreate="roles_new"
@open-form="toggleRolesPanel"
:showProjectSelect="$attrs.showProjectSelect"
title="نقش ها"
></sub-header-with-select>
<div class="pages-content pb-0 pt-2">
<template v-if="canView">
<my-table
:tableActions="tableActions"
height="auto"
maxHeight="calc(100vh - 9em)"
class="my-table"
ref="rolesTable"
:hasSearch="false"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="roles"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@delete-table-item="deleteItem"
@edit-table-item="toggleRolesPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
></my-table>
</template>
<NoData v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div class="pages-content pb-0 pt-2">
<template v-if="canView">
<my-table
:tableActions="tableActions"
height="auto"
maxHeight="calc(100vh - 9em)"
class="my-table"
ref="rolesTable"
:hasSearch="false"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="roles"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@delete-table-item="deleteItem"
@edit-table-item="toggleRolesPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
></my-table>
</template>
<NoData v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</NoData>
<div class="side-panel" v-if="showPanel">
<div class="side-panel-header">
<h6 class="">مدیریت نقش ها</h6>
</div>
</div>
</NoData>
<div class="side-panel" v-if="showPanel">
<div class="side-panel-header">
<h6 class="">مدیریت نقش ها</h6>
</div>
<div class="side-panel-content">
<form class="section-form" role="section" @submit.prevent="save()">
<div class="form-group">
<label for="title">عنوان نقش</label>
<input
type="text"
class="form-control"
id="title"
name="title"
v-model="selectedItemClone.title"
/>
</div>
<div class="side-panel-footer mt-4">
<div>
<button
type="submit"
class="btn btn-outline-primary"
:disabled="loading"
@click.prevent="save()"
>
<the-button-loading
v-if="loading"
:style="{ transform: 'scale(0.5)' }"
></the-button-loading>
ثبت
</button>
<button
:disabled="loading"
@click.prevent="showPanel = false"
type="button"
class="btn btn-default"
data-dismiss="modal"
>
لغو
</button>
<div class="side-panel-content">
<form class="section-form" role="section" @submit.prevent="save()">
<div class="form-group">
<label for="title">عنوان نقش</label>
<input
type="text"
class="form-control"
id="title"
name="title"
v-model="selectedItemClone.title"
/>
</div>
<div>
<button
v-if="selectedItemClone.id"
@click="deleteItem(selectedItemClone.id)"
title="حذف"
class="btn delete-btn btn-outline-danger"
type="button"
>
<svg class="icon icon-Component-295--1">
<use xlink:href="#icon-Component-295--1"></use>
</svg>
حذف
</button>
<div class="side-panel-footer mt-4">
<div>
<button
type="submit"
class="btn btn-outline-primary"
:disabled="loading"
@click.prevent="save()"
>
<the-button-loading
v-if="loading"
:style="{ transform: 'scale(0.5)' }"
></the-button-loading>
ثبت
</button>
<button
:disabled="loading"
@click.prevent="showPanel = false"
type="button"
class="btn btn-default"
data-dismiss="modal"
>
لغو
</button>
</div>
<div>
<button
v-if="selectedItemClone.id"
@click="deleteItemHandler(selectedItemClone.id)"
title="حذف"
class="btn delete-btn btn-outline-danger"
type="button"
>
<svg class="icon icon-Component-295--1">
<use xlink:href="#icon-Component-295--1"></use>
</svg>
حذف
</button>
</div>
</div>
</div>
</form>
</form>
</div>
</div>
</div>
</div>
</div>
</NuxtLayout>
</NuxtLayout>
</template>
<script>
// import permitApi from "@permission/permitApi";
import apis from "~/apis/permitApi";
import adminMenu from "~/json/admin/json/menu.json";
// import { mapGetters, mapMutations, mapActions } from "vuex";
import { defineAsyncComponent } from "vue";
import { mapActions, mapState } from "pinia";
import { useCommonStore } from "~/stores/commonStore";
@ -142,7 +141,7 @@ export default {
},
data() {
return {
adminMenu:adminMenu,
adminMenu: adminMenu,
httpService: {},
tableActions: [
{
@ -228,10 +227,11 @@ export default {
...this.sorting,
...this.pagination,
};
return await ApiService.formData(permitApi.roles.list, payload)
return await this.httpService
.postRequest(permitUrl() + apis.roles.list, payload)
.then((res) => {
this.roles = res.data.data;
this.pagination = { ...this.pagination, ...res.data.pagination };
this.roles = res.data;
this.pagination = { ...this.pagination, ...res.pagination };
})
.finally(() => {
@ -240,45 +240,55 @@ export default {
});
},
save() {
const url = this.selectedItemClone.id
? permitApi.roles.edit
: permitApi.roles.add;
const url = this.selectedItemClone.id ? apis.roles.edit : apis.roles.add;
ApiService.formData(url, this.selectedItemClone).then((res) => {
this.getRoles();
this.httpService
.postRequest(permitUrl() + url, this.selectedItemClone)
.then((res) => {
this.getRoles();
this.mySwalToast({
title: "تبریک",
html: res.data.message,
icon: "success",
mySwalToast({
title: "تبریک",
html: res.data.message,
icon: "success",
});
this.showPanel = false;
this.resetForm();
});
this.showPanel = false;
this.resetForm();
});
},
deleteItemHandler(id) {
// const foundObject = this.roles.find(obj => obj.id === id);
const index = this.roles.findIndex((obj) => obj.id === id);
this.deleteItem(index);
},
deleteItem(index) {
// debugger
let sectionId = this.roles[index].id;
const data = {
// project_id: this.projectGetter?.id,
id: sectionId,
};
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار",
html: "از حذف این بخش مطمئن هستید؟",
icon: "warning",
}).then((result) => {
if (result.isConfirmed) {
ApiService.formData(permitApi.roles.delete, data).then((res) => {
this.getRoles();
this.httpService
.postRequest(permitUrl() + apis.roles.delete, data)
.then((res) => {
this.getRoles();
this.mySwalToast({
title: "تبریک",
html: res.data.message,
icon: "success",
mySwalToast({
title: "تبریک",
html: res.data.message,
icon: "success",
});
});
});
}
});
},
@ -320,6 +330,7 @@ export default {
this.getRoles();
},
toggleRolesPanel(index = undefined) {
if (index !== undefined) {
if (this.prevSelectedItemIndex !== undefined)
this.roles[this.prevSelectedItemIndex].active = false;
@ -327,7 +338,7 @@ export default {
this.prevSelectedItemIndex = index;
this.roles[index].active = true;
this.selectedItemClone = structuredClone(this.roles[index]);
this.selectedItemClone = this.roles[index];
} else this.resetForm();
this.showPanel = true;
@ -375,9 +386,15 @@ export default {
});
},
async getProjects() {
return await ApiService.formData(permitApi.projects.list).then((res) => {
this.SET_PROJECT(res.data.data[0]);
});
return await this.httpService
.postRequest(permitUrl() + apis.projects.list)
.then((res) => {
console.log(
"🚀 ~ returnawaitthis.httpService.postRequest ~ res:",
res
);
this.SET_PROJECT(res.data[0]);
});
},
},
components: {

View File

@ -1,85 +1,94 @@
<template>
<NuxtLayout name="default" :menu="adminMenu">
<div class="pages user-role px-3 pb-0 pt-2">
<sub-header-with-select
canCreate="user-permission_new"
@open-form="showShareModal()"
:showProjectSelect="$attrs.showProjectSelect"
title="کاربران"
>
</sub-header-with-select>
<NuxtLayout name="default" :menu="adminMenu">
<div class="pages user-role px-3 pb-0 pt-2">
<sub-header-with-select
canCreate="user-permission_new"
@open-form="showShareModal()"
:showProjectSelect="$attrs.showProjectSelect"
title="کاربران"
>
</sub-header-with-select>
<div class="pages-content d-flex pb-0 pt-2">
<template v-if="canView">
<my-table
:tableActions="tableActions"
height="auto"
maxHeight="calc(100vh - 15em)"
class="my-table"
ref="userRolesTable"
:hasSearch="false"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="userRoles"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@delete-table-item="deleteItem"
@edit-table-item="toggleRolesPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
></my-table>
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div class="pages-content d-flex pb-0 pt-2">
<template v-if="canView">
<my-table
:tableActions="tableActions"
height="auto"
maxHeight="calc(100vh - 15em)"
class="my-table"
ref="userRolesTable"
:hasSearch="false"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="userRoles"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@delete-table-item="deleteItem"
@edit-table-item="toggleRolesPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
></my-table>
</template>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</no-data>
<div class="side-panel" v-if="showPanel">
<div class="side-panel-header">
<h6 class="">مدیریت نقش ها</h6>
</div>
</div>
</no-data>
<div class="side-panel" v-if="showPanel">
<div class="side-panel-header">
<h6 class="">مدیریت نقش ها</h6>
</div>
<div class="side-panel-content">
<Accordion
class="role-permission"
canEdit="user-permission_edit"
:user_id="user_id"
></Accordion>
<div class="side-panel-footer mt-4">
<div></div>
<div>
<button
@click.prevent="showPanel = false"
type="button"
class="btn btn-primary text-white"
>
بستن
</button>
<div class="side-panel-content">
<Accordion
class="role-permission"
canEdit="user-permission_edit"
:user_id="user_id"
></Accordion>
<div class="side-panel-footer mt-4">
<div></div>
<div>
<button
@click.prevent="showPanel = false"
type="button"
class="btn btn-primary text-white"
>
بستن
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<Share
@update-user-role="updateUserRole"
:roles="roles"
v-if="showModal"
:item="[]"
></Share>
</div>
</NuxtLayout>
<base-modal
v-if="showModal"
@close="closeModal"
:showHeaderCloseButton="true"
modalSize="modal-lg"
:modalTitle="modalTitle"
maxHeight="30em"
:showDeleteButton="false"
>
<Share
@update-user-role="updateUserRole"
:roles="roles"
:item="[]"
></Share>
</base-modal>
</div>
</NuxtLayout>
</template>
<script>
@ -101,6 +110,9 @@ export default {
layout: false,
});
},
created() {
this.httpService = useNuxtApp()["$http"];
},
mounted() {
this.checkPermisionBeforGetList();
this.getRoles();
@ -121,7 +133,9 @@ export default {
},
data() {
return {
adminMenu:adminMenu,
adminMenu: adminMenu,
httpService: {},
modalTitle: "اختصاص نقش به کاربر",
tableActions: [
{
showOutside: true,
@ -229,9 +243,10 @@ export default {
...{ project_id: this.projectGetter?.id },
};
ApiService.formData(apis.roleUser.AddRoleUser, formData)
this.httpService
.postRequest(permitUrl() + apis.roleUser.AddRoleUser, formData)
.then((response) => {
this.mySwalToast({
mySwalToast({
title: "تبریک",
html: response.data.message,
icon: "success",
@ -240,7 +255,7 @@ export default {
this.getUserRole();
})
.catch((err) => {
this.mySwalToast({
mySwalToast({
title: "خطا",
html: err.response.data.message ?? err.message,
icon: "error",
@ -269,15 +284,16 @@ export default {
const item = this.userRoles[index];
var vm = this;
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار!!!",
html: "از حذف این مورد مطمئن هستید؟",
}).then((result) => {
if (result.isConfirmed) {
ApiService.formData(apis.permissions.deleteUserRole, {
project_id: vm.projectGetter?.id,
id: item.id,
})
this.httpService
.postRequest(permitUrl() + apis.permissions.deleteUserRole, {
project_id: vm.projectGetter?.id,
id: item.id,
})
.then((response) => {
vm.getUserRole();
})
@ -301,9 +317,10 @@ export default {
...this.sorting,
...this.pagination,
};
return await ApiService.formData(apis.permissions.listUserRole, payload)
return await this.httpService
.postRequest(permitUrl() + apis.permissions.listUserRole, payload)
.then((response) => {
this.userRoles = response.data.data;
this.userRoles = response.data;
this.userRoles.forEach((item, key) => {
item["role_name"] =
@ -319,17 +336,17 @@ export default {
},
};
this.userRoles[key].created_at = this.convertUnixToPersianDateTime(
this.userRoles[key].created_at = convertUnixToPersianDateTime(
item.created_at
);
});
this.pagination = { ...this.pagination, ...response.data.pagination };
this.pagination = { ...this.pagination, ...response.pagination };
})
.catch((err) => {
this.mySwalToast({
mySwalToast({
title: "خطا",
html: err.response.data.message ?? err.message,
html: err.response.message ?? err.message,
icon: "error",
});
})
@ -346,11 +363,14 @@ export default {
this.getRoles().then(() => {
this.showModal = true;
setTimeout(() => {
$("#share-modal").modal("show");
}, 500);
// setTimeout(() => {
// $("#share-modal").modal("show");
// }, 500);
});
},
closeModal() {
this.showModal = false;
},
updateList() {
this.resetPagination();
this.getUserRole();
@ -399,9 +419,12 @@ export default {
this.showPanel = true;
},
async getSections() {
return await ApiService.formData(apis.sections.list, {
project_id: this.projectGetter?.id,
});
return await this.httpService.postRequest(
permitUrl() + apis.sections.list,
{
project_id: this.projectGetter?.id,
}
);
},
collapseAllPanels() {
@ -425,11 +448,13 @@ export default {
clearTimeout(this.typingTimer);
},
async getRoles() {
return await ApiService.formData(apis.roles.list, {
project_id: this.projectGetter?.id,
}).then((res) => {
this.roles = res.data.data;
});
return await this.httpService
.postRequest(permitUrl() + apis.roles.list, {
project_id: this.projectGetter?.id,
})
.then((res) => {
this.roles = res.data;
});
},
checkPermisionBeforGetList() {
if (this.fetchingData) return;
@ -467,9 +492,11 @@ export default {
});
},
async getProjects() {
return await ApiService.formData(apis.projects.list).then((res) => {
this.SET_PROJECT(res.data.data[0]);
});
return await this.httpService
.postRequest(permitUrl() + apis.projects.list)
.then((res) => {
this.SET_PROJECT(res.data[0]);
});
},
},
components: {

View File

@ -1,9 +1,10 @@
<template>
<NuxtLayout name="default" :menu="adminMenu">
<div>
<!-- <header>
<the-navbar></the-navbar>
</header>
<the-sidebar :menu="menu"></the-sidebar> -->
</header> -->
<main class="pages-content-container">
<div class="pages-content mt-4 mt-lg-0">
@ -29,7 +30,8 @@
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<slot name="tableHeaderActions">
<template v-slot:tableHeaderActions>
<div class="dropdown">
<button
class="btn dropdown-toggle"
@ -60,7 +62,7 @@
</button>
</div>
</div>
</slot>
</template>
</my-table>
</div>
<no-data v-else>
@ -98,49 +100,57 @@
</div>
<div class="side-panel-content">
<users-search
<UsersSearch
v-if="showPanel"
:searchResults="users"
@on-send="searchUsers"
@set-as-admin="setAsAdmin"
></users-search>
></UsersSearch>
</div>
</div>
</div>
</div>
</main>
</div>
</NuxtLayout>
</template>
<script>
import { mapState, mapActions } from "pinia";
import menu from "~/json/admin/json/menu.json";
import adminMenu from "~/json/admin/json/menu.json";
// import menu from "~/json/admin/json/menu.json";
import adminApi from "~/apis/adminApi";
import permitApis from "~/apis/permitApi";
import { defineAsyncComponent } from "vue";
import { useCommonStore } from "~/stores/commonStore";
import { usePermitStore } from "~/stores/permitStore";
export default {
name: "groupsWithoutAdmin",
setup() {
definePageMeta({
name: "groupsWithoutAdmin",
layout: false,
});
},
beforeMount() {
this.httpService = new HttpService(import.meta.env.VITE_BASE_URL);
// this.httpService = new HttpService(import.meta.env.VITE_BASE_URL);
this.httpService = useNuxtApp()["$http"];
},
mounted() {
this.checkPermisionBeforGetList();
},
data() {
return {
adminMenu: adminMenu,
searchType: "getGroupsWithoutAdmin",
groupsTranslation: {
getGroupsWithoutAdmin: "گروه های بدون مدیر",
getGroupsWithAdmin: "گروه های دارای مدیر",
},
groups: [],
menu: menu,
// menu: menu,
firstTimeSearching: false,
httpService: undefined,
tableActions: [
@ -210,10 +220,16 @@ export default {
prevSelectedItemIndex: undefined,
};
},
computed: {
...mapState(usePermitStore, ["projectGetter"]),
...mapState(useCommonStore, ["isSidebarCollapsed"]),
// ...mapState(["isSidebarCollapsed"]),
},
methods: {
...mapState(["isSidebarCollapsed"]),
...mapActions(["checkPermissions"]),
// ...mapState(["isSidebarCollapsed"]),
// ...mapActions(["checkPermissions"]),
...mapActions(useCommonStore, ["checkPermissions"]),
checkPermisionBeforGetList() {
if (this.fetchingData) return;
@ -328,7 +344,7 @@ export default {
this.loading = false;
});
this.mySwalToast({
mySwalToast({
html: res.message,
});
@ -405,7 +421,7 @@ export default {
const url = `${messageUrl()}/${adminApi.groups.delete}`;
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار",
html: "با حذف گروه، تمامی مسائل و پاسخ های آن نیز حذف خواهد شد.",
icon: "warning",
@ -417,7 +433,7 @@ export default {
// this.showPanel = false;
});
this.mySwalToast({
mySwalToast({
html: res.message,
});
});
@ -429,6 +445,11 @@ export default {
this.showPanel = true;
},
},
components: {
UsersSearch: defineAsyncComponent(() =>
import("@/components/admin/components/UsersSearch.vue")
),
},
};
</script>

View File

@ -1,118 +1,124 @@
<template>
<div class="main-users">
<!-- <header>
<the-navbar></the-navbar>
</header> -->
<!-- <the-sidebar :menu="menu"></the-sidebar> -->
<NuxtLayout name="default" :menu="adminMenu">
<div class="main-users">
<!-- <header>
<the-navbar></the-navbar>
</header> -->
<!-- <the-sidebar :menu="menu"></the-sidebar> -->
<main
class="pages-content-container"
<main class="pages-content-container">
<div class="pages-content mt-lg-0">
<div :class="{ 'd-flex': showPanel }">
<div v-if="canView">
<my-table
:tableActions="tableActions"
height="calc(100vh - 17em)"
:hasSearch="true"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="users"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@search="searchGroups"
@reset-form="searchUsers"
@delete-table-item="deleteItem"
@edit-table-item="toggleUsersPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<slot name="tableHeaderActions">
<button
v-if="!showPanel"
@click.prevent="openCreatePanel()"
class="btn btn-primary add-user-btn"
type="button"
>
ایجاد
</button>
<span
v-if="!showPanel"
@click.prevent="openCreatePanel()"
class="add-user-svg"
type="button"
>
<svg class="icon icon-Component-133--1">
<use xlink:href="#icon-Component-133--1"></use>
</svg>
</span>
</slot>
</my-table>
</div>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
>
<div class="pages-content mt-lg-0">
<div :class="{ 'd-flex': showPanel }">
<div v-if="canView">
<my-table
:tableActions="tableActions"
height="calc(100vh - 17em)"
:hasSearch="true"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="users"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@search="searchGroups"
@reset-form="searchUsers"
@delete-table-item="deleteItem"
@edit-table-item="toggleUsersPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<slot name="tableHeaderActions">
<button
v-if="!showPanel"
@click.prevent="openCreatePanel()"
class="btn btn-primary add-user-btn"
type="button"
>
ایجاد
</button>
<span
v-if="!showPanel"
@click.prevent="openCreatePanel()"
class=" add-user-svg"
type="button"
>
<svg class="icon icon-Component-133--1">
<use xlink:href="#icon-Component-133--1"></use>
</svg>
</span>
</slot>
</my-table>
</div>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div
v-else
class="d-flex justify-content-center align-items-center"
>
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
v-else
class="d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</div>
</no-data>
<div class="side-panel mx-5" v-if="showPanel">
<div class="side-panel-header d-flex mb-3 pb-3 border-bottom">
<h6 class="m-0">مدیریت کاربران</h6>
</no-data>
<div class="side-panel mx-5" v-if="showPanel">
<div class="side-panel-header d-flex mb-3 pb-3 border-bottom">
<h6 class="m-0">مدیریت کاربران</h6>
<button
@click.prevent="toggleUsersPanel(undefined)"
class="btn btn-outline-primary me-auto"
type="button"
>
x
</button>
</div>
<button
@click.prevent="toggleUsersPanel(undefined)"
class="btn btn-outline-primary me-auto"
type="button"
>
x
</button>
</div>
<div class="side-panel-content">
<new-user-form
:parentLoading="loading"
:userData="selectedItemClone"
@on-pass-by-emit="save"
></new-user-form>
<div class="side-panel-content">
<NewUserForm
:parentLoading="loading"
:userData="selectedItemClone"
@on-pass-by-emit="save"
></NewUserForm>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</main>
</div>
</NuxtLayout>
</template>
<script>
import apis from "~/apis/permitApi";
import { mapState, mapActions } from "pinia";
import adminMenu from "~/json/admin/json/menu.json";
import { defineAsyncComponent } from "vue";
import { useCommonStore } from "~/stores/commonStore";
import { usePermitStore } from "~/stores/permitStore";
import menu from "~/json/admin/json/menu.json";
// import menu from "~/json/admin/json/menu.json";
export default {
name: "adminUsers",
setup() {
definePageMeta({
name: "adminUsers",
layout: false,
});
},
beforeMount() {
this.httpService = new HttpService(
import.meta.env.VITE_BASE_URL + loginUrl()
);
// this.httpService = new HttpService(
// import.meta.env.VITE_BASE_URL + loginUrl()
// );
this.httpService = useNuxtApp()["$http"];
// this.httpService + loginUrl();
},
mounted() {
this.checkPermisionBeforGetList();
@ -125,7 +131,8 @@ export default {
// },
data() {
return {
menu: menu,
adminMenu: adminMenu,
// menu: menu,
firstTimeSearching: false,
httpService: undefined,
tableActions: [
@ -231,11 +238,13 @@ export default {
};
},
computed: {
...mapState("permit", ["projectGetter"]),
...mapState(["isSidebarCollapsed"]),
...mapState(usePermitStore, ["projectGetter"]),
...mapState(useCommonStore, ["isSidebarCollapsed"]),
// ...mapState(["isSidebarCollapsed"]),
},
methods: {
...mapActions(["checkPermissions"]),
// ...mapActions(["checkPermissions"]),
...mapActions(useCommonStore, ["checkPermissions"]),
checkPermisionBeforGetList() {
if (this.fetchingData) return;
this.fetchingData = true;
@ -283,7 +292,8 @@ export default {
url = url.replace("{{sortby}}", this.sorting.sortby);
url = url.replace("{{sortorder}}", this.sorting.sortorder);
return await this.httpService.getRequest(url).then((res) => {
return await this.httpService.getRequest(loginUrl() + url).then((res) => {
this.users = res.data;
this.pagination = { ...this.pagination, ...res.pagination };
});
@ -301,7 +311,7 @@ export default {
this.loading = false;
});
this.mySwalToast({
mySwalToast({
html: res.message,
});
@ -321,7 +331,7 @@ export default {
id: userId,
};
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار",
html: "هشدار!!!!",
icon: "warning",
@ -335,7 +345,7 @@ export default {
this.showPanel = false;
});
this.mySwalToast({
mySwalToast({
html: res.message,
});
});
@ -395,7 +405,11 @@ export default {
this.showPanel = false;
},
},
components: {
NewUserForm: defineAsyncComponent(() =>
import("@/components/admin/components/NewUserForm.vue")
),
},
};
</script>
<style scoped lang="scss">

View File

@ -1,106 +1,113 @@
<template>
<div>
<!-- <header>
<NuxtLayout name="default" :menu="adminMenu">
<div>
<!-- <header>
<the-navbar></the-navbar>
</header>
<the-sidebar :menu="menu"></the-sidebar> -->
<main class="pages-content-container">
<div class="pages-content mt-4 mt-lg-0">
<div class="p-3" :class="{ 'd-flex': showPanel }">
<div v-if="canView">
<my-table
:tableActions="tableActions"
height="calc(100vh - 17em)"
:hasSearch="true"
maxHeight="calc(100dvh - 5em)"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="users"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@search="searchGroups"
@reset-form="searchUsers"
@delete-table-item="deleteItem"
@edit-table-item="toggleUsersPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<template #tableHeaderActions>
<main class="pages-content-container">
<div class="pages-content mt-4 mt-lg-0">
<div class="p-3" :class="{ 'd-flex': showPanel }">
<div v-if="canView">
<my-table
:tableActions="tableActions"
height="calc(100vh - 17em)"
:hasSearch="true"
maxHeight="calc(100dvh - 5em)"
:paginationInfo="pagination"
:sortingInfo="sorting"
:items="users"
:fetchingData="fetchingData"
:tableColumns="tableColumns"
:totalPages="pagination.pages"
@search="searchGroups"
@reset-form="searchUsers"
@delete-table-item="deleteItem"
@edit-table-item="toggleUsersPanel"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<template #tableHeaderActions>
<button
v-if="!showPanel"
@click.prevent="openCreatePanel()"
class="btn btn-primary"
type="button"
>
ایجاد
</button>
</template>
</my-table>
</div>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div
v-else
class="d-flex justify-content-center align-items-center"
>
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</no-data>
<div class="side-panel mx-5" v-if="showPanel">
<div class="side-panel-header d-flex mb-3 pb-3 border-bottom">
<h6 class="m-0">مدیریت کاربران</h6>
<button
v-if="!showPanel"
@click.prevent="openCreatePanel()"
class="btn btn-primary"
@click.prevent="toggleUsersPanel(undefined)"
class="btn btn-outline-primary me-auto"
type="button"
>
ایجاد
x
</button>
</template>
</my-table>
</div>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div
v-else
class="d-flex justify-content-center align-items-center"
>
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ms-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</no-data>
<div class="side-panel mx-5" v-if="showPanel">
<div class="side-panel-header d-flex mb-3 pb-3 border-bottom">
<h6 class="m-0">مدیریت کاربران</h6>
<button
@click.prevent="toggleUsersPanel(undefined)"
class="btn btn-outline-primary me-auto"
type="button"
>
x
</button>
</div>
<div class="side-panel-content">
<new-user-form
:parentLoading="loading"
:userData="selectedItemClone"
@on-pass-by-emit="save"
></new-user-form>
<div class="side-panel-content">
<NewUserForm
:parentLoading="loading"
:userData="selectedItemClone"
@on-pass-by-emit="save"
></NewUserForm>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</main>
</div>
</NuxtLayout>
</template>
<script>
import apis from "~/apis/permitApi";
import { mapState, mapActions } from "pinia";
import menu from "~/json/admin/json/menu.json";
import adminMenu from "~/json/admin/json/menu.json";
// import menu from "~/json/admin/json/menu.json";
import { defineAsyncComponent } from "vue";
import { useCommonStore } from "~/stores/commonStore";
import { usePermitStore } from "~/stores/permitStore";
export default {
name: "userModifications",
setup() {
definePageMeta({
name: "userModifications",
layout: false,
});
},
beforeMount() {
this.httpService = new HttpService(
import.meta.env.VITE_BASE_URL + loginUrl()
);
// this.httpService = new HttpService(
// import.meta.env.VITE_BASE_URL + loginUrl()
// );
this.httpService = useNuxtApp()["$http"];
// this.httpService + loginUrl();
},
mounted() {
this.checkPermisionBeforGetList();
@ -113,7 +120,8 @@ export default {
// },
data() {
return {
menu: menu,
adminMenu: adminMenu,
// menu: menu,
firstTimeSearching: false,
httpService: undefined,
tableActions: [
@ -218,11 +226,15 @@ export default {
prevSelectedItemIndex: undefined,
};
},
computed: {
...mapState(usePermitStore, ["projectGetter"]),
...mapState(useCommonStore, ["isSidebarCollapsed"]),
},
methods: {
...mapState(["isSidebarCollapsed"]),
// ...mapState(["isSidebarCollapsed"]),
...mapActions(["checkPermissions"]),
// ...mapActions(["checkPermissions"]),
...mapActions(useCommonStore, ["checkPermissions"]),
checkPermisionBeforGetList() {
if (this.fetchingData) return;
this.fetchingData = true;
@ -270,7 +282,8 @@ export default {
url = url.replace("{{sortby}}", this.sorting.sortby);
url = url.replace("{{sortorder}}", this.sorting.sortorder);
return await this.httpService.getRequest(url).then((res) => {
return await this.httpService.getRequest(loginUrl()+ url).then((res) => {
console.log("🚀 ~ returnawaitthis.httpService.getRequest ~ res:", res)
this.users = res.data;
this.pagination = { ...this.pagination, ...res.pagination };
});
@ -281,7 +294,7 @@ export default {
const url = formData.id ? apis.users.update : apis.users.create;
formData;
// formData;
this.httpService
.postRequest(url, formData)
.then((res) => {
@ -289,7 +302,7 @@ export default {
this.loading = false;
});
this.mySwalToast({
mySwalToast({
html: res.message,
});
@ -309,7 +322,7 @@ export default {
id: userId,
};
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار",
html: "هشدار!!!!",
icon: "warning",
@ -323,7 +336,7 @@ export default {
this.showPanel = false;
});
this.mySwalToast({
mySwalToast({
html: res.message,
});
});
@ -383,7 +396,11 @@ export default {
this.showPanel = false;
},
},
components: {
NewUserForm: defineAsyncComponent(() =>
import("@/components/admin/components/NewUserForm.vue")
),
},
};
</script>
<style scoped lang="scss">

View File

@ -1,89 +0,0 @@
<template>
<div>
<the-content-loading v-if="fetchingData"></the-content-loading>
<my-quill :parentButtonLoading="buttonLoading" v-else :tinyText="tinyText" @input="onSave"
@on-save="onSave"></my-quill>
</div>
</template>
<script>
import settingsApi from "~/apis/settingsApi";
export default {
name: "dataSettingAboutUs",
setup() {
definePageMeta({
name: "dataSettingAboutUs",
});
},
data() {
return {
buttonLoading: false,
tinyText: '',
fetchingData: false,
data: undefined,
};
},
methods: {
getData() {
var vm = this;
this.fetchingData = true;
var url = settingsApi.app.getByKey;
url = url.replace("{{key_option}}", "about_text");
// let url = apis.admin.get.replace('{{system}}', this.$route.meta.apiKey)
ApiService.getRequest(url)
.then((response) => {
vm.fetchingData = false;
this.tinyText = response.data.hits.hits[0]._source.value;
this.data = response.data.hits.hits[0]._source;
})
.catch((error) => {
}).finally(() => {
vm.fetchingData = false;
})
},
onSave(newContent) {
if (this.buttonLoading) return;
this.buttonLoading = true;
// var url = apis.admin.save;
// const payload = { ...this.data, ...{ value: newContent } }
var url = settingsApi.app.saveByKey;
url = url.replace("{{key_option}}", "about_text");
const payload = { value: newContent }
ApiService.postRequest(url, payload)
.then((response) => {
this.mySwalToast({
title: "تبریک",
html: response.data.message,
icon: "success",
});
})
.catch((error) => {
}).finally(() => {
this.buttonLoading = false;
})
}
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
};
</script>

View File

@ -1,293 +0,0 @@
<template>
<div>
<Multiselect
:allow-empty="false"
:searchable="true"
:close-on-select="true"
:show-labels="false"
:value="value"
:options="options"
class="multi mb-2"
@select="select"
label="label"
track-by="key"
placeholder="دسته"
:hide-selected="false"
:max-height="200"
:max-width="200"
>
</Multiselect>
<MyTable
height="auto"
maxHeight="calc(100vh - 9em)"
class="my-table"
ref="sectionsTable"
:hasSearch="false"
:tableActions="tableActions"
:items="sections"
:tableColumns="tableColumns"
:paginationInfo="pagination"
:totalPages="pagination.pages"
@delete-table-item="deleteItem"
@edit-table-item="editTableItem"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
<!-- :fetchingData="fetchingData" :totalPages="pagination.pages"
@delete-table-item="deleteItem" @edit-table-item="toggleRolesPanel"
@page-changed="pageChanged" @page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged" -->
<!-- :paginationInfo="pagination"
:sortingInfo="sorting -->
</MyTable>
<base-modal
v-if="openSubjectForm"
modalSize="modal-lg"
:hasFooter="false"
@close="closeModal"
>
<component
:is="slotComponentName"
:editList="editList"
@close="closeModal"
></component>
</base-modal>
</div>
</template>
<script>
import settingsApi from "~/apis/settingsApi";
import { mapState, mapActions } from "pinia";
import searchApi from "~/apis/searchApi";
import { useStorage } from "@vueuse/core";
export default {
computed: {
...mapState(useSearchStore, ["helpSchemaGetter"]),
...mapState(["organNameGetter"]),
myActiveSchema() {
return this.helpSchemaGetter?.find((item) => {
return item.key == "help";
});
},
},
mounted() {
let localStoageHelpSchema = useStorage("settingSchema",undefined).value;
if (localStoageHelpSchema) {
let helpSchema = JSON.parse(localStoageHelpSchema);
this.helpSchemaSetter(helpSchema);
this.options = this.myActiveSchema?.category;
this.value = this.myActiveSchema?.category[0];
} else {
this.getSchemas();
}
this.getList();
},
data() {
return {
options: [{ name: "جستجو" }, { name: "محتوا" }, { name: "مطالعه" }],
httpService: undefined,
value: "",
editList: "",
slotComponentName: "",
modalTitle: "",
openSubjectForm: false,
listSections: [],
sections: [],
tableActions: [
{
showOutside: true,
show: true,
icon: "tavasi tavasi-Component-242--1",
title: this.$t("Edit"),
to: {
name: "undefined",
},
selected: false,
disabled: false,
howToOpen: "",
href: "",
class: "edit-btn",
action: "edit-table-item",
can: "item-info_edit",
},
{
showOutside: true,
show: true,
icon: "tavasi tavasi-Component-295--1",
title: this.$t("Delete"),
to: {
name: "undefined",
},
selected: false,
disabled: false,
howToOpen: "",
href: "",
class: "delete-btn",
action: "delete-table-item",
can: "item-list_delete",
},
],
tableColumns: [
{
isLink: true,
key: "title",
title: "عنوان سوال",
width: "1",
},
{
key: "description",
title: "توضیحات",
width: "6",
},
],
pagination: {
page: 1,
pages: 0,
total: 0,
offset: 0,
limit: 10,
},
sorting: "",
};
},
beforeMount() {
this.httpService = new HttpService(import.meta.env.VITE_REPO_BASE_URL);
},
methods: {
...mapActions("search", ["helpSchemaSetter"]),
openModal(componentName, title) {
this.openSubjectForm = true;
this.slotComponentName = componentName;
this.modalTitle = title;
setTimeout(() => {
$("#meta-item-modal").modal(
{ backdrop: "static", keyboard: false },
"show"
);
}, 500);
},
closeModal() {
$("#base-modal").modal({
show: false,
});
setTimeout(() => {
this.openSubjectForm = false;
this.getList();
}, 1000);
},
editTableItem(item) {
this.editList = this.listSections[item];
this.openModal("editModalItem", "فیلتر ها");
},
deleteItem(item) {
this.mySwalConfirm({
title: "هشدار!!!",
html: "تمامی اطلاعات پاک خواهد. آیا مطمئن هستید؟ ",
}).then((result) => {
if (result.isConfirmed) {
var id = this.listSections[item]?._id;
let url = settingsApi.help.delete;
url = url.replace("{{id}}", id);
this.httpService.postRequest(url).then((response) => {
this.mySwalToast({
title: "با موفقیت حذف شد",
// html: response.data.message,
icon: "success",
});
this.getList();
});
}
});
},
getList() {
let url = settingsApi.help.list;
url = url.replace("{{key_option}}", this.value?.key);
url = url.replace("{{offset}}", this.pagination?.offset);
url = url.replace("{{limit}}", this.pagination?.limit);
this.httpService.getRequest(url).then((response) => {
let list = response.hits?.hits;
this.listSections = list;
if (this.sections.length >= 0) this.sections = [];
// this.sections = response.hits.hits;
list.forEach((element) => {
this.sections.push(element?._source.meta);
});
const total = response.hits.total.value;
const pages = Math.ceil(total / this.pagination.limit);
const pagination = {
total: total,
pages: pages == 0 ? 1 : pages,
};
this.pagination = { ...this.pagination, ...pagination };
// this.pagination = { ...this.pagination, ...response.pagination };
});
},
getSchemas() {
this.httpService
.postRequest(searchApi.schema.list, {
organ: this.organNameGetter,
system: "setting",
build_state: buildState(),
})
.then((response) => {
this.helpSchemaSetter(response.data?.setting);
this.options = this.myActiveSchema?.category;
this.value = this.myActiveSchema?.category[0];
// this.options = response;
});
},
select(e) {
this.value = e;
this.getList();
},
resetPagination() {
this.pagination = {
pages: 0,
total: 0,
page: 1,
offset: 0,
limit: 10,
};
},
pageLimitChanged(paging) {
this.resetPagination();
this.pagination.limit = paging?.limit;
this.getList();
},
pageChanged(paging) {
let page = paging.pageNumber;
page -= 1;
this.pagination.offset = page * paging.limit;
this.pagination.limit = paging.limit;
this.pagination.page = paging.pageNumber;
this.getList();
},
sortChanged(sorting) {
this.pagination.page = this.pagination.offset = 0;
this.sorting = sorting;
this.getList();
},
},
};
</script>
<style scoped>
.multi {
width: 200px;
border: 2px solid rgb(127, 170, 170);
border-radius: 0.5rem;
}
</style>

View File

@ -1,219 +0,0 @@
<template>
<div class="page">
<div class="container">
<form>
<div class="form-row">
<div class="col-3">
<label for=""> انتخاب بخش:</label>
<multiselect
:allow-empty="false"
:searchable="true"
:close-on-select="true"
:show-labels="false"
:value="value"
:options="options"
class="multi"
@select="select"
label="label"
track-by="key"
placeholder="دسته"
:hide-selected="false"
:max-height="200"
>
</multiselect>
</div>
</div>
<div class="form-row">
<div class="col-6">
<label for="">عنوان سوال:</label>
<input
type="text"
class="form-control"
placeholder="عنوان سوال را کوتاه و واضح وارد نمایید"
v-model="title"
/>
</div>
<div class="col-6">
<label for="">نشانی صفحه:</label>
<input
type="text"
class="form-control"
placeholder="نشانی از همین سامانه انتخاب کنید"
v-model="link"
/>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="">توضیح کوتاه:</label>
<input
type="text"
placeholder="توضیح مختصر حداکثر یک خط باشد"
v-model="description"
maxlength="500"
/>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="" class="mt-2">توضیح مفصل:</label>
<VueEditor
dir="rtl"
v-model="editorData"
:editorOptions="editorOptions"
></VueEditor>
</div>
</div>
</form>
<button class="btn-save" @click="saveData">ذخیره</button>
</div>
</div>
</template>
<script>
import searchApi from "~/apis/searchApi";
import settingsApi from "~/apis/settingsApi";
import { VueEditor } from "vue2-editor";
import { mapState, mapActions } from "pinia";
import { useStorage } from "@vueuse/core";
export default {
beforeMount() {
this.httpService = new HttpService(import.meta.env.VITE_REPO_BASE_URL);
},
computed: {
...mapState(useSearchStore, ["helpSchemaGetter"]),
...mapState(["organNameGetter"]),
},
mounted() {
let localStoageHelpSchema = useStorage("settingSchema",undefined).value;
if (localStoageHelpSchema) {
let helpSchema = JSON.parse(localStoageHelpSchema);
this.helpSchemaSetter(helpSchema);
this.options = this.helpSchemaGetter[0].category;
} else this.getSchemas();
},
data() {
return {
value: "",
editorData: "",
title: "",
link: "",
description: "",
fullDesc: "",
httpService: undefined,
options: [{ name: "جستجو" }, { name: "محتوا" }, { name: "مطالعه" }],
editorOptions: {
formats: {
direction: "rtl",
align: "right",
},
placeholder: "توضیحات...",
// readOnly: true,
// theme: "snow",
},
};
},
methods: {
...mapActions("search", ["helpSchemaSetter"]),
select(e) {
this.value = e;
},
getSchemas() {
this.httpService
.postRequest(searchApi.schema.list, {
organ: this.organNameGetter,
system: "setting",
build_state: buildState(),
})
.then((response) => {
this.helpSchemaSetter(response.data.setting);
this.options = this.helpSchemaGetter[0].category;
// this.options = response;
});
},
saveData() {
var origin = location.origin;
let cleaned = this.link;
if (this.link.startsWith(origin) || this.link == "") {
cleaned = this.link.replace(origin, "");
} else {
let errorMessage = "نشانی پیوند باید با " + origin + "شروع شود";
this.mySwalToast({
title: errorMessage,
// html: response.data.message,
icon: "error",
timer: 7000,
});
return "";
}
let payload = {
value_key: this.value.key,
value: this.editorData,
meta : {
title: this.title,
link: cleaned,
description: this.description,
}
}
this.httpService
.postRequest(settingsApi.help.addItem, payload)
.then((response) => {
this.mySwalToast({
title: "با موفقیت ثبت شد",
// html: response.data.message,
icon: "success",
});
this.resetItem();
// this.helpSchemaSetter(response.data.setting);
// this.options = response;
});
},
resetItem() {
this.title = "";
this.link = "";
this.description = "";
this.editorData = "";
},
},
};
</script>
<style scoped lang="scss">
input {
border-radius: 0.5rem;
border: 2px solid rgb(127, 170, 170);
font-size: 14px;
height: 3em;
width: 100%;
&::placeholder {
color: #a7a098;
}
}
.multi {
// width: 200px;
border: 2px solid rgb(127, 170, 170);
border-radius: 0.5rem;
}
.btn-save {
width: 100px;
height: 2.5em;
float: left;
background-color: white;
margin-top: 0.8em;
border-radius: 0.5rem;
border: 2px solid rgb(127, 170, 170);
}
.page {
height: calc(100vh - 5em);
}
</style>

View File

@ -1,230 +0,0 @@
<template>
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div v-if="canView">
<div class="user__container">
<div class="d-flex justify-content-between align-items-center">
<div>
<h3>
{{ $t("Notifications") }}
</h3>
<p class="text__light text__13">
شما {{ list?.length }} اعلان خوانده نشده دارید.
</p>
</div>
<div>
<button-component
@click="openModal"
type="button"
classes="btn-primary"
buttonText="اعلان جدید"
title="اعلان جدید"
>
</button-component>
</div>
</div>
<ul class="nav nav-tabs">
<li class="nav-item">
<button
title="همه"
type="button"
@click.prevent="filterNotifications('all')"
class="btn nav-link"
:class="{
active: activeTab == 'all',
}"
>
<span class="badge badge-light">{{ counts?.all?.count }}</span>
همه
</button>
</li>
<li class="nav-item">
<button
title="جدید"
type="button"
@click.prevent="filterNotifications('new')"
class="btn nav-link"
:class="{
active: activeTab == 'new',
}"
>
<span class="badge badge-light">{{ counts?.new?.count }}</span>
جدید
</button>
</li>
<li class="nav-item">
<button
title="خوانده نشده ها"
type="button"
@click.prevent="filterNotifications('unseen')"
class="btn nav-link"
:class="{
active: activeTab == 'unseen',
}"
>
<span class="badge badge-light">{{ counts?.unseen?.count }}</span>
خوانده نشده ها
</button>
</li>
<li class="nav-item">
<button
title="خوانده شده ها"
type="button"
@click.prevent="filterNotifications('seen')"
class="btn nav-link"
:class="{
active: activeTab == 'seen',
}"
>
<span class="badge badge-light">{{ counts?.seen?.count }}</span>
خوانده شده ها
</button>
</li>
</ul>
<the-content-loading
class="absolute-positioning"
v-if="fetchingData"
></the-content-loading>
<div v-else>
<div v-if="list && list.length">
<div class="notif-list firefox-scrollbar">
<notification-item
v-for="(item, index) in list"
:item="item"
:index="index"
:key="item._id"
@getList="getList()"
@go-to-notification-show-page="
goToNotificationShowPage(item)
"
></notification-item>
</div>
<jahat-pagination
v-if="pagination.total"
:paginationInfo="pagination"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
>
</jahat-pagination>
</div>
<no-data v-else></no-data>
</div>
</div>
</div>
<no-data v-else>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div v-else class="d-flex justify-content-center align-items-center">
<div
class="alert alert-warning d-flex justify-content-center align-items-center"
>
<span
class="tavasi tavasi-warning-circle color-inherit ml-1 text__32"
></span>
عدم دسترسی
</div>
</div>
</no-data>
</div>
</div>
<base-modal
v-if="showModal"
modalSize="modal-lg"
modalTitle="اعلان جدید"
:hasFooter="false"
@close="closeModal"
>
<admin-notification-form
ref="tabFormBuilder"
:formData="notificationItem"
@close-modal="closeModal"
></admin-notification-form>
</base-modal>
</div>
</template>
<script>
import notificationMixin from "~/mixins/notifications/notificationMixin";
export default {
extends: notificationMixin,
mounted() {
// this.canView = true;
this.checkPermisionBeforGetList("notification_edit").then(() => {
this.getList();
this.numberOfMark();
});
},
// watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
// },
data() {
return {
showModal: false,
};
},
methods: {
onEditItem(item, index) {
this.notificationItem = item;
this.openModal();
},
onDeleteItem(item) {
this.mySwalConfirm({
title: "هشدار!!!",
html: "از حذف این مورد مطمئن هستید؟",
}).then((result) => {
if (result.isConfirmed) {
this.deleteItem(item).then(() => {
setTimeout(() => {
this.getList();
}, 1000);
});
}
});
},
openModal() {
this.showModal = true;
setTimeout(() => {
$("#base-modal").modal({ backdrop: "static", keyboard: false }, "show");
}, 500);
},
closeModal(isCreate = false) {
$("#base-modal").modal("hide");
if (isCreate)
setTimeout(() => {
this.showModal = false;
this.notificationItem = undefined;
this.getList();
}, 1000);
else
setTimeout(() => {
this.showModal = false;
this.notificationItem = undefined;
this.getList();
}, 500);
},
},
};
</script>

View File

@ -1,90 +0,0 @@
<template>
<div>
<the-content-loading v-if="fetchingData"></the-content-loading>
<my-quill :parentButtonLoading="buttonLoading" v-else :tinyText="tinyText" @input="onSave"
@on-save="onSave"></my-quill>
</div>
</template>
<script>
import settingsApi from "~/apis/settingsApi";
export default {
name: "dataSettingContactUs",
setup() {
definePageMeta({
name: "dataSettingContactUs",
});
},
data() {
return {
buttonLoading: false,
tinyText: '',
fetchingData: false,
data: undefined,
};
},
methods: {
getData() {
var vm = this;
this.fetchingData = true;
var url = settingsApi.app.getByKey;
url = url.replace("{{key_option}}", "conect_text");
// let url = apis.admin.get.replace('{{system}}', this.$route.meta.apiKey)
ApiService.getRequest(url)
.then((response) => {
vm.fetchingData = false;
this.tinyText = response.data.hits.hits[0]._source.value;
this.data = response.data.hits.hits[0]._source;
})
.catch((error) => {
}).finally(() => {
vm.fetchingData = false;
})
},
onSave(newContent) {
if (this.buttonLoading) return;
this.buttonLoading = true;
// var url = apis.admin.save;
// const payload = { ...this.data, ...{ value: newContent } }
var url = settingsApi.app.saveByKey;
url = url.replace("{{key_option}}", "conect_text");
const payload = { value: newContent }
ApiService.postRequest(url, payload)
.then((response) => {
this.mySwalToast({
title: "تبریک",
html: response.data.message,
icon: "success",
});
})
.catch((error) => {
}).finally(() => {
this.buttonLoading = false;
})
}
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
};
</script>

View File

@ -1,103 +0,0 @@
<template>
<div>
<the-content-loading v-if="fetchingData"></the-content-loading>
<div v-else>
<form v-if="properties.length" class="form" @submit.prevent="onSubmit()">
<div v-for="(property, index) in properties" :key="property.title" class="form-row form-group">
<label class="col-1" :for="'ta' + index">{{ property.title }} </label>
<div class="col">
<textarea class="form-control" :id="'ta' + index" :name="'ta' + index" :placeholder="property.title"
v-model.trim="property.keys" rows="1"></textarea>
</div>
</div>
<div class="form-row form-group mt-4">
<div class="col d-flex">
<button-component classes="btn-outline-primary" type="submit" :buttonText="'ذخیره'"
:buttonLoading="buttonLoading"></button-component>
</div>
</div>
</form>
<no-data v-else />
</div>
</div>
</template>
<script>
import settingsApi from "~/apis/settingsApi";
export default {
data() {
return {
stopWords: '',
fetchingData: false,
buttonLoading: false,
properties: [],
payload: {},
};
},
computed: {
},
methods: {
getData() {
if (this.fetchingData) return;
this.fetchingData = true;
var url = settingsApi.app.getByKey;
url = url.replace("{{key_option}}", "search_amplify");
// let url = apis.admin.get.replace('{{system}}', this.$route.meta.apiKey)
ApiService.getRequest(url)
.then((response) => {
this.payload = response.data.hits.hits[0]._source;
this.properties = JSON.parse(response.data.hits.hits[0]._source.value);
})
.catch((error) => {
}).finally(() => {
this.fetchingData = false;
})
},
onSubmit() {
if (this.buttonLoading) return;
this.buttonLoading = true;
// var url = apis.admin.save;
// const payload = { ...this.payload, ...{ value: JSON.stringify(this.properties) } }
var url = settingsApi.app.saveByKey;
url = url.replace("{{key_option}}", "search_amplify");
const payload = { value: JSON.stringify(this.properties) }
ApiService.postRequest(url, payload)
.then((response) => {
this.mySwalToast({
title: "تبریک",
html: response.data.message,
icon: "success",
});
})
.catch((error) => {
}).finally(() => {
this.buttonLoading = false;
})
}
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
};
</script>

View File

@ -1,107 +0,0 @@
<template>
<div>
<the-content-loading v-if="fetchingData"></the-content-loading>
<form v-else @submit.prevent="onSave()">
<div class="form-group">
<!-- <label for="stop-words"></label> -->
<textarea
v-model="stopWords"
class="form-control"
id="stop-words"
rows="10"
style="height: auto"
></textarea>
</div>
<button-component
type="submit"
classes="btn-primary"
:buttonText="saveButtonText"
>
</button-component>
</form>
</div>
</template>
<script>
import settingsApi from "~/apis/settingsApi";
export default {
props: {
saveButtonText: {
default: "ذخیره",
},
},
data() {
return {
stopWords: "",
fetchingData: false,
data: undefined,
buttonLoading: false,
};
},
methods: {
getData() {
var vm = this;
this.fetchingData = true;
var url = settingsApi.app.getByKey;
url = url.replace("{{key_option}}", "words_stop");
// let url = apis.admin.get.replace("{{system}}", this.$route.meta.apiKey);
ApiService.getRequest(url)
.then((response) => {
vm.fetchingData = false;
this.stopWords = response.data.hits.hits[0]._source.value;
this.data = response.data.hits.hits[0]._source;
})
.finally(() => {
vm.fetchingData = false;
});
},
onSave() {
if (this.buttonLoading) return;
this.buttonLoading = true;
// var url = apis.admin.save;
// const payload = { ...this.data, ...{ value: this.stopWords } };
var url = settingsApi.app.saveByKey;
url = url.replace("{{key_option}}", "words_stop");
const payload = { value: this.stopWords }
ApiService.postRequest(url, payload)
.then((response) => {
this.mySwalToast({
title: "تبریک",
html: response.data.message,
icon: "success",
});
})
.finally(() => {
this.buttonLoading = false;
});
},
},
mounted() {
this.getData();
},
watch: {
// $route: {
// handler: function () {
// this.$store.state.collapsed = false;
// },
// deep: true,
// immediate: true,
// },
},
};
</script>

View File

@ -1,224 +0,0 @@
<template>
<div class="page">
<div class="container">
<form>
<div class="form-row">
<div class="col-3">
<label for=""> انتخاب بخش:</label>
<multiselect
:allow-empty="false"
:searchable="true"
:close-on-select="true"
:show-labels="false"
:value="value"
:options="options"
class="multi"
@select="select"
label="label"
track-by="key"
placeholder="دسته"
:hide-selected="false"
:max-height="200"
>
</multiselect>
</div>
</div>
<div class="form-row">
<div class="col-6">
<label for="">عنوان سوال:</label>
<input
type="text"
class="form-control"
placeholder="عنوان سوال را کوتاه و واضح وارد نمایید"
v-model="title"
/>
</div>
<div class="col-6">
<label for="">نشانی صفحه:</label>
<input
type="text"
class="form-control"
placeholder="نشانی از همین سامانه انتخاب کنید"
v-model="link"
/>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="">توضیح کوتاه:</label>
<input
type="text"
placeholder="توضیح مختصر حداکثر یک خط باشد"
v-model="description"
maxlength="500"
/>
</div>
</div>
<div class="form-row">
<div class="col">
<label for="" class="mt-2">توضیح مفصل:</label>
<!-- <VueEditor
dir="rtl"
v-model="editorData"
:editorOptions="editorOptions"
></VueEditor> -->
</div>
</div>
</form>
<button class="btn-save" @click="saveData">ذخیره</button>
</div>
</div>
</template>
<script>
import searchApi from "~/apis/searchApi";
import settingsApi from "~/apis/settingsApi";
// import { VueEditor } from "vue2-editor";
import { mapState, mapActions } from "pinia";
import { useStorage } from "@vueuse/core";
export default {
name: "adminGuides",
setup() {
definePageMeta({
name: "adminGuides",
});
},
beforeMount() {
this.httpService = new HttpService(import.meta.env.VITE_REPO_BASE_URL);
},
computed: {
...mapState(useSearchStore, ["helpSchemaGetter"]),
...mapState(["organNameGetter"]),
},
mounted() {
let localStoageHelpSchema = useStorage("settingSchema",undefined).value;
if (localStoageHelpSchema) {
let helpSchema = JSON.parse(localStoageHelpSchema);
this.helpSchemaSetter(helpSchema);
this.options = this.helpSchemaGetter[0].category;
} else this.getSchemas();
},
data() {
return {
value: "",
editorData: "",
title: "",
link: "",
description: "",
fullDesc: "",
httpService: undefined,
options: [{ name: "جستجو" }, { name: "محتوا" }, { name: "مطالعه" }],
editorOptions: {
formats: {
direction: "rtl",
align: "right",
},
placeholder: "توضیحات...",
// readOnly: true,
// theme: "snow",
},
};
},
methods: {
...mapActions("search", ["helpSchemaSetter"]),
select(e) {
this.value = e;
},
getSchemas() {
this.httpService
.postRequest(searchApi.schema.list, {
organ: this.organNameGetter,
system: "setting",
build_state: buildState(),
})
.then((response) => {
this.helpSchemaSetter(response.data.setting);
this.options = this.helpSchemaGetter[0].category;
// this.options = response;
});
},
saveData() {
var origin = location.origin;
let cleaned = this.link;
if (this.link.startsWith(origin) || this.link == "") {
cleaned = this.link.replace(origin, "");
} else {
let errorMessage = "نشانی پیوند باید با " + origin + "شروع شود";
this.mySwalToast({
title: errorMessage,
// html: response.data.message,
icon: "error",
timer: 7000,
});
return "";
}
let payload = {
value_key: this.value.key,
value: this.editorData,
meta : {
title: this.title,
link: cleaned,
description: this.description,
}
}
this.httpService
.postRequest(settingsApi.help.addItem, payload)
.then((response) => {
this.mySwalToast({
title: "با موفقیت ثبت شد",
// html: response.data.message,
icon: "success",
});
this.resetItem();
// this.helpSchemaSetter(response.data.setting);
// this.options = response;
});
},
resetItem() {
this.title = "";
this.link = "";
this.description = "";
this.editorData = "";
},
},
};
</script>
<style scoped lang="scss">
input {
border-radius: 0.5rem;
border: 2px solid rgb(127, 170, 170);
font-size: 14px;
height: 3em;
width: 100%;
&::placeholder {
color: #a7a098;
}
}
.multi {
// width: 200px;
border: 2px solid rgb(127, 170, 170);
border-radius: 0.5rem;
}
.btn-save {
width: 100px;
height: 2.5em;
float: left;
background-color: white;
margin-top: 0.8em;
border-radius: 0.5rem;
border: 2px solid rgb(127, 170, 170);
}
.page {
height: calc(100vh - 5em);
}
</style>

View File

@ -147,7 +147,7 @@ export default {
cleaned = this.link.replace(origin, "");
} else {
let errorMessage = "نشانی پیوند باید با " + origin + "شروع شود";
this.mySwalToast({
mySwalToast({
title: errorMessage,
// html: response.data.message,

View File

@ -0,0 +1,33 @@
import { defineNuxtPlugin } from '#app';
import Swal from 'sweetalert2';
import 'sweetalert2/dist/sweetalert2.min.css';
export default defineNuxtPlugin(nuxtApp => {
const mySwalToast = (options:any) => {
return Swal.fire({
toast: true,
position: 'bottom-end',
showConfirmButton: false,
timerProgressBar: true,
timer: 5000,
icon: 'success',
...options,
});
};
const mySwalConfirm = (options:any) => {
return Swal.fire({
title: 'هشدار',
text: 'آیا مطمئن هستید؟',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'تایید',
cancelButtonText: 'انصراف',
...options,
});
};
// به جای استفاده از `provide()`
nuxtApp.$mySwalToast = mySwalToast;
nuxtApp.$mySwalConfirm = mySwalConfirm;
});

View File

@ -0,0 +1,7 @@
import { defineNuxtPlugin } from '#app'
import { QuillEditor } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.component('QuillEditor', QuillEditor)
})

1155
yarn.lock

File diff suppressed because it is too large Load Diff