base_ui/components/other/PropertyBuilder.vue

471 lines
15 KiB
Vue
Raw Normal View History

2025-02-01 09:34:55 +00:00
<template>
<div class="accordion" id="accordionExample">
<div
class="card rounded-0 mb-2"
v-for="(innerGroupItem, j) in propertyBuilderForm"
:key="j"
>
<!-- v-if="innerGroupItem.key != 'organhMeta'" -->
<div
class="card-header p-3"
:id="'heading' + j"
type="button"
data-bs-toggle="collapse"
:data-bs-target="'#collapse' + j"
aria-expanded="false"
:aria-controls="'collapse' + j"
>
<div class="d-flex justify-content-between align-items-center">
<p class="p-0 m-0">
{{ innerGroupItem.title }}
</p>
<span class="tavasi tavasi-Component-358--1"></span>
</div>
</div>
<div
:id="'collapse' + j"
class="collapse"
:aria-labelledby="'heading' + j"
data-parent="#accordionExample"
>
<div class="card-body">
<form :key="render">
<div class="container-fluid">
<div class="row">
<div
v-for="(formElement, index) in refactorItems(
innerGroupItem.items
)"
:class="formElement.colClass ?? 'col-12'"
>
<component
:key="index"
:formElement="getValueToFormElement(formElement)"
:inputClass="formElement.inputClass"
:labelClass="formElement.labelClass"
:is="
returnComponentName(
innerGroupItem,
formElement.type,
formElement.key
)
"
@take-value="saveComponentValue($event, formElement)"
@keydown="saveKeydown($event)"
@openModalTags="openModalTags"
class="component inside-entity"
></component>
</div>
</div>
</div>
<div
v-if="
isEditable(innerGroupItem?.key, innerGroupItem.submit_label)
"
class="d-flex justify-content-end"
>
<button
type="submit"
class="btn btn-primary mt-3 px-3"
@click.prevent="saveProperty(innerGroupItem)"
>
<span>{{ innerGroupItem.submit_label ?? "ثبت" }}</span>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import repoApi from "~/apis/repoApi";
import { mapState } from "pinia";
import { useEntityStore } from "~/stores/entityStore";
import SelectComponentDefault from "~/components/SelectComponentDefault.vue";
import SelectComponent from "~/components/SelectComponent.vue";
import InputComponent from "~/components/InputComponent.vue";
import LabelComponent from "~/components/LabelComponent.vue";
import tagsComponent from "~/components/tagsComponent.vue";
import DateComponent from "~/components/DateComponent.vue";
import TextareaComponent from "~/components/TextareaComponent.vue";
/**
* @vue-data {Object} [listUpdatedText = {}] - متنهای بهروزشده در لیست.
* @vue-data {undefined} [httpService = undefined] - سرویس HTTP برای درخواستها.
* @vue-computed {Object} [mapState.entity.selectedItemEntityGetter] - مورد انتخاب شده
* @vue-computed {Object} [mapState.userPermisionGetter] - دریافت کننده مجوز کاربر
* @vue-computed {Object} [mapState.currentUser] - اطلاعات کاربر
* @vue-event {Function} [mapMutations.SET_ITEM_ENTITY] - تابع برای قرار دادن موجودیتهای آیتم
*/
export default {
// props: ["propertyBuilderForm"],
props: {
propertyBuilderForm: {
default() {
return [];
},
type: Array,
},
entityProp: {
default() {
return undefined;
},
},
readOnly: {
default: false,
},
},
beforeMount() {
this.httpService = useNuxtApp()["$http"];
},
mounted() {
console.log("property builder");
if (this.entityProp) {
this.entity_source = this.entityProp;
this.entity_id = this.entityProp._id ?? undefined;
this.render++;
} else this.getEntityBase();
},
watch: {
activeTabGetter(newVal) {
if (newVal.key == "meta") {
this.getEntityBase();
}
},
},
data() {
return {
fetchingData: false,
httpService: undefined,
entity_source: undefined,
entity_id: undefined,
render: 1,
selectedCard: null,
listUpdatedText: {},
};
},
computed: {
...mapState(useEntityStore, [
// "selectedItemEntityGetter",
"activeTabGetter",
]),
...mapState(useCommonStore, ["userPermisionGetter", "currentUser"]),
},
methods: {
// ...mapMutations("entity", ["SET_ITEM_ENTITY"]),
openModalTags(item) {
this.$emit("editPropertyTags", item);
},
refactorItems(items) {
let res = [];
items.forEach((el) => {
res.push(el);
});
return res;
},
toggleCard(j) {
if (this.selectedCard === j) {
this.selectedCard = null; // اگر کارت فعال است، غیرفعال شود
} else {
this.selectedCard = j; // اگر کارت فعال نیست، فعال شود
}
},
getEntityBase() {
let self = this;
this.getEntityInfo().then(() => {
// if (!self.entity) {
// self.entity = self.selectedItemEntityGetter;
// }
self.render++;
});
},
/**
* بررسی امکان ویرایش بر اساس کلید داده شده.
* @param {String} key - کلیدی که نیاز به بررسی دارد.
* @returns {Boolean} نتیجه بررسی امکان ویرایش.
* @description این متد بر اساس کلید داده شده و بررسی سطح دسترسی، امکان ویرایش را تعیین میکند.
* @example
* const editable = this.isEditable("example_key"); // true or false
*/
isEditable(key, label = "ثبت") {
if (this.readOnly) return false;
if (label == "") return false;
let res = key ? false : true;
if (key) {
let key_root = this.$route.params.key;
// console.log(key_root)
res = this.hasPermission(key_root + "_property");
if (!res) res = this.hasPermission(key + "_edit");
}
return res;
},
/**
* بررسی سطح دسترسی کاربر برای یک مجوز خاص.
* @param {String} permission - مجوزی که نیاز به بررسی دارد.
* @returns {Boolean} نتیجه بررسی سطح دسترسی.
* @description این متد سطح دسترسی کاربر فعلی را برای یک مجوز خاص بررسی میکند.
* @example
* const hasAccess = this.hasPermission("admin_edit"); // true or false
*/
hasPermission(permission) {
if (this.currentUser?.user_level > 1) return true;
if (this.userPermisionGetter && this.userPermisionGetter.length)
return this.userPermisionGetter.includes(permission);
return false;
},
/**
* بازگشت نام کامپوننت بر اساس نوع و امکان ویرایش.
* @param {Object} innerGroupItem - آیتمی که نیاز به بررسی دارد.
* @param {String} type - نوع ورودی (مثل textarea, select, date).
* @returns {String} نام کامپوننت مناسب.
* @description این متد بر اساس نوع ورودی و امکان ویرایش، نام کامپوننت مناسب را برمیگرداند.
* @example
* const componentName = this.returnComponentName({ key: "description" }, "textarea"); // "TextareaComponent"
*/
returnComponentName(innerGroupItem, type, key) {
if (!this.isEditable(innerGroupItem?.key)) return "LabelComponent";
if (type == "textarea") return "TextareaComponent";
else if (type == "select") return "SelectComponentDefault";
else if (type == "date") return "DateComponent";
else if (type == "tags") return "tagsComponent";
else return "InputComponent";
},
// /**
// * تبدیل تاریخ به فرمت فارسی.
// * @param {Object} item - آیتمی که شامل تاریخ است.
// * @returns {String} تاریخ به فرمت فارسی.
// * @description این متد تاریخ موجود در آیتم را به فرمت فارسی تبدیل می‌کند.
// * @example
// * const persianDate = this.datefa({ begin_date: "2023-05-29T00:00:00Z" }); // "۱۴۰۲/۳/۸"
// */
// // datefa(item) {
// var m = this.selectedItemEntityGetter.begin_date;
// var d = new Date(m).toLocaleDateString("fa-IR");
// return d;
// },
/**
* دریافت مقادیر فرم برای عناصر فرم.
* @param {Object} elements - عناصر فرم که نیاز به مقداردهی دارند.
* @returns {Object} عناصر فرم با مقادیر تنظیم شده.
* @description این متد مقادیر مناسب را به عناصر فرم اختصاص میدهد.
* @example
* const formElements = this.getValueToFormElement({ key: "name", value: "" });
* // formElements.value برابر با مقدار موجود در entity است.
*/
getValueToFormElement(elements) {
let source = this.entity_source;
Object.keys(elements).forEach((key, index) => {
if (source) {
let key = elements.key.replace("__", ".");
let value = undefined;
if (key.includes(".")) {
let keys = key.split(".");
let elemntKey = source;
let kk = "";
for (var i = 0; i < keys.length - 1; i++) {
kk = keys[i];
if (elemntKey[kk]) elemntKey = elemntKey[kk];
}
kk = keys[keys.length - 1];
if (elemntKey[kk]) value = elemntKey[kk];
} else {
value = source[key];
}
elements["value"] = value;
}
});
return elements;
},
/**
* ذخیره مقدار کامپوننت به صورت موقت.
* @param {any} value - مقدار جدید کامپوننت.
* @param {Object} formElement - عنصر فرم که مقدار جدید برای آن تنظیم شده است.
* @description این متد مقدار جدید کامپوننت را به صورت موقت در لیست بهروزرسانیها ذخیره میکند.
* @example
* this.saveComponentValue("new value", { key: "description" });
*/
saveComponentValue(value, formElement) {
//در صورت تغییر نگهداری می شود تا وقتی کلید ثبت زد، ذخیره شود
if (this.entity_source && this.entity_source[formElement.key] != value) {
this.listUpdatedText[formElement.key] = value;
}
},
async getEntityInfo() {
if (this.fetchingData) return;
let key = this.$route.params.key;
let entityId = this.$route.params.id ?? this.entity_id;
if (key == "qasection" || key == "rgsection") key = "qaqanon";
// console.log("qaqanon", entityId)
//if (!(key == "qasection" || key == "rgsection") || !entityId) {
if (!entityId) {
return;
}
// "public/get/byid/{{index_key}}/{{entity_id}}"
this.fetchingData = true;
let url = repoUrl() + repoApi.public.get;
url = url.replace("{{index_key}}", key);
url = url.replace("{{entity_id}}", entityId);
// console.log(url)
let self = this;
return await this.httpService
.getRequest(url)
.then((res) => {
// console.log(res);
self.entity_source = res._source;
self.entity_id = res._id ?? undefined;
this.fetchingData = false;
this.$emit("entityUpdate", this.entity_source);
})
.finally(() => {
this.fetchingData = false;
});
},
/**
* ذخیره تغییرات در سرور.
* @description این متد تغییرات موقتی را به سرور ارسال و ذخیره میکند.
* @example
* this.saveProperty();
*/
saveProperty(innerGroupItem) {
// console.log("saveProperty");
let id = this.$route.params.id ?? this.entity_id;
let key = this.$route.params.key;
if (!id) {
console.log("not id in route params");
return;
}
// اگر تغییری نداشته باشیم، meta به صورت "{}" خواهد بود.
if (JSON.stringify(this.listUpdatedText).length > 2) {
if (this.fetchingData) return;
this.fetchingData = true;
let formData = {
id: id,
meta: JSON.stringify(this.listUpdatedText),
};
let url = "";
if (key == "qasection" || key == "rgsection") {
//در این حالت چون مخزن اصل قانون با اجزاء قانون متفاوت هست ، تغییرات در هر دو به نحو خاصی باید إعمال شود.
url =
this.repoMicroServiceName + repoApi.public.updateProperty_byRelated;
url = url.replace("{{appname}}", this.buildName());
url = url.replace("{{sub_key}}", key);
key = "qaqanon";
} else {
url = repoUrl() + repoApi.public.updateEntity;
}
url = url.replace("{{index_key}}", key);
url = url.replace("{{id}}", id);
this.httpService.postRequest(url, formData).then((res) => {
this.fetchingData = false;
this.mySwalToast({
html: res?.message ?? "با موفقیت ثبت شد.",
});
this.getEntityInfo();
});
} else {
this.mySwalToast({
html: "تغییری جهت ذخیره یافت نشد.",
icon: "error",
});
}
},
/**
* هندلر برای رویداد فشردن کلید.
* @param {Event} event - رویداد فشردن کلید.
* @description این متد به عنوان هندلر برای رویداد فشردن کلید استفاده میشود.
* @example
* // در قالب رویداد keydown در یک المنت
* <input @keydown="saveKeydown" />
*/
saveKeydown(event) {
// console.log(event);
},
},
components: {
SelectComponentDefault,
SelectComponent,
InputComponent,
LabelComponent,
tagsComponent,
DateComponent,
TextareaComponent,
},
};
</script>
<style lang="scss" scoped>
.card-header {
div {
span {
transform: rotate(90deg);
transition: transform 0.3s ease;
color: #000;
}
}
}
.card {
border-radius: 0.6em !important;
border: none;
}
.card-header {
border-bottom: none;
border-radius: 0.6em !important;
&[aria-expanded="true"] {
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
background-color: var(--header-color);
div {
p {
color: #fff;
}
span {
transform: rotate(-90deg) !important;
transition: transform 0.3s ease;
color: #fff;
}
}
}
}
.btn-primary {
color: #fff;
}
.show {
border: 1px solid var(--header-color) !important;
margin-bottom: 5px;
border-radius: 0 0 0.6em 0.6em !important;
}
</style>