806 lines
29 KiB
Vue
806 lines
29 KiB
Vue
<template>
|
||
<div>
|
||
<v-chart
|
||
:key="treeCounter"
|
||
:option="option"
|
||
style="height: 90dvh; width: 90%"
|
||
ref="chart"
|
||
@mouseover="handleChartClick"
|
||
lazy
|
||
></v-chart>
|
||
<template v-if="showDiv">
|
||
<div
|
||
v-if="showButtons"
|
||
class="rounded shadow container-fluid p-2"
|
||
@mouseenter="onMouseEnter"
|
||
@mouseleave="onMouseLeave"
|
||
:style="{
|
||
position: 'absolute',
|
||
top: position.top,
|
||
left: position.left,
|
||
backgroundColor: 'white',
|
||
border: '1px solid #dee2e6',
|
||
padding: '5px',
|
||
width: '15em',
|
||
}"
|
||
>
|
||
<div class="row me-auto tooltip-button">
|
||
<div class="col-9 d-flex border-bottom mb-1">
|
||
<button
|
||
v-tooltip="`افزودن فرزند`"
|
||
class="btn"
|
||
style="color: #dee2e6"
|
||
@click="onButtonClick('add')"
|
||
>
|
||
<svg class="icon icon-Component-133--1">
|
||
<use xlink:href="#icon-Component-133--1"></use>
|
||
</svg>
|
||
</button>
|
||
<button
|
||
v-tooltip="`ویرایش کردن`"
|
||
class="btn"
|
||
@click="onButtonClick('edit')"
|
||
>
|
||
<svg class="icon icon-Component-242--1">
|
||
<use xlink:href="#icon-Component-242--1"></use>
|
||
</svg>
|
||
</button>
|
||
<button
|
||
v-tooltip="`پاک کردن`"
|
||
class="btn"
|
||
@click="onButtonClick('delete')"
|
||
>
|
||
<svg class="icon icon-Component-295--1">
|
||
<use xlink:href="#icon-Component-295--1"></use>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<div class="col-3 mb-1">
|
||
<button v-tooltip="`خارج شدن`" class="btn" @click="closeButtons">
|
||
<svg class="icon icon-Component-21--1">
|
||
<use xlink:href="#icon-Component-21--1"></use>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="row my-3">
|
||
<div v-if="buttonAction == 'add'" class="col w-90 px-3">
|
||
<form>
|
||
<div class="row align-items-center">
|
||
<div class="col-8 m-0">
|
||
<input
|
||
type="text"
|
||
class="form-control"
|
||
id="inlineFormInputName"
|
||
placeholder="کلمه جدید"
|
||
v-model="addText"
|
||
/>
|
||
</div>
|
||
|
||
<div class="col-2">
|
||
<button
|
||
class="btn accept-button"
|
||
@click.prevent="addNewChildren(addText)"
|
||
>
|
||
<svg class="icon icon-Component-233--1">
|
||
<use xlink:href="#icon-Component-233--1"></use>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<div class="col-2">
|
||
<button class="btn reject-button" @click="buttonAction = ''">
|
||
<svg class="icon icon-Component-21--1">
|
||
<use xlink:href="#icon-Component-21--1"></use>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
<div v-else-if="buttonAction == 'edit'" class="col w-90 px-3">
|
||
<form>
|
||
<div class="row align-items-center">
|
||
<div class="col-8">
|
||
<input
|
||
type="text"
|
||
class="form-control"
|
||
id="inlineFormInputName"
|
||
:placeholder="tooltipText"
|
||
v-model="editText"
|
||
/>
|
||
</div>
|
||
|
||
<div class="col-2">
|
||
<button
|
||
class="btn accept-button"
|
||
@click.prevent="editNode(editText)"
|
||
>
|
||
<svg class="icon icon-Component-233--1">
|
||
<use xlink:href="#icon-Component-233--1"></use>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<div class="col-2">
|
||
<button class="btn reject-button" @click="buttonAction = ''">
|
||
<svg class="icon icon-Component-21--1">
|
||
<use xlink:href="#icon-Component-21--1"></use>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
<div v-else class="col">
|
||
<p>{{ tooltipText }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import researchApi from "@apis/researchApi";
|
||
import HttpService from "@services/httpService";
|
||
import { mapActions, mapState } from "pinia";
|
||
import { useCommonStore } from "~/stores/commonStore";
|
||
//
|
||
import { use } from "echarts/core";
|
||
import { TreeChart } from "echarts/charts";
|
||
import { TooltipComponent, ToolboxComponent } from "echarts/components";
|
||
import { CanvasRenderer } from "echarts/renderers";
|
||
use([TooltipComponent, TreeChart, CanvasRenderer, ToolboxComponent]);
|
||
/**
|
||
* @vue-prop {Array} [dataTreeMap=] - آرایهای از دادههای نقشه درخت
|
||
*
|
||
* @vue-data {Number} treeCounter - شمارنده درخت
|
||
* @vue-data {Boolean} showButtons - وضعیت نمایش دکمهها
|
||
* @vue-data {Boolean} showDiv - وضعیت نمایش divدکمه ها
|
||
* @vue-data {String} buttonAction - اقدام دکمه
|
||
* @vue-data {String} addText - متن افزودن
|
||
* @vue-data {String} editText - متن ویرایش
|
||
* @vue-data {undefined|Object} httpService - سرویس HTTP
|
||
* @vue-data {Object} itemData - داده آیتم
|
||
* @vue-data {String} tooltipText - متن ابزارک راهنما
|
||
* @vue-data {Object} position - موقعیت ابزارک راهنما
|
||
* @vue-data {String} position.top - موقعیت عمودی ابزارک راهنما
|
||
* @vue-data {String} position.left - موقعیت افقی ابزارک راهنما
|
||
* @vue-data {Object} option - گزینههای پیکربندی نمودار
|
||
* @vue-data {Object} option.tooltip - تنظیمات ابزارک راهنما
|
||
* @vue-data {String} option.tooltip.trigger - نوع راهاندازی ابزارک راهنما
|
||
* @vue-data {String} option.tooltip.triggerOn - رویدادی که ابزارک راهنما بر اساس آن راهاندازی میشود
|
||
* @vue-data {Array} option.series - آرایهای از سریهای نمودار
|
||
* @vue-data {Object} option.series[0] - سری اول نمودار
|
||
* @vue-data {String} option.series[0].type - نوع سری (درخت)
|
||
* @vue-data {Number} option.series[0].id - شناسه سری
|
||
* @vue-data {String} option.series[0].name - نام سری
|
||
* @vue-data {Array} option.series[0].data - دادههای سری
|
||
* @vue-data {String} option.series[0].top - موقعیت بالای نمودار
|
||
* @vue-data {String} option.series[0].left - موقعیت چپ نمودار
|
||
* @vue-data {String} option.series[0].bottom - موقعیت پایین نمودار
|
||
* @vue-data {String} option.series[0].right - موقعیت راست نمودار
|
||
* @vue-data {String} option.series[0].while - عرض نمودار
|
||
* @vue-data {String} option.series[0].height - ارتفاع نمودار
|
||
* @vue-data {Number} option.series[0].zoom - میزان بزرگنمایی نمودار
|
||
* @vue-data {Number} option.series[0].symbolSize - اندازه نماد
|
||
* @vue-data {String} option.series[0].edgeForkPosition - موقعیت شاخههای لبه
|
||
* @vue-data {String} option.series[0].edgeShape - شکل لبه
|
||
* @vue-data {Number} option.series[0].initialTreeDepth - عمق اولیه درخت
|
||
* @vue-data {String} option.series[0].orient - جهت نمودار
|
||
* @vue-data {Object} option.series[0].lineStyle - سبک خط
|
||
* @vue-data {Number} option.series[0].lineStyle.width - عرض خط
|
||
* @vue-data {Object} option.series[0].label - برچسبها
|
||
* @vue-data {String} option.series[0].label.backgroundColor - رنگ پسزمینه برچسب
|
||
* @vue-data {Array} option.series[0].label.position - موقعیت برچسب
|
||
* @vue-data {Number} option.series[0].label.distance - فاصله برچسب
|
||
* @vue-data {String} option.series[0].label.verticalAlign - تراز عمودی برچسب
|
||
* @vue-data {String} option.series[0].label.align - تراز برچسب
|
||
* @vue-data {Number} option.series[0].label.borderWidth - عرض مرز برچسب
|
||
* @vue-data {Number} option.series[0].label.borderDashOffset - فاصله نقطهچین مرز برچسب
|
||
* @vue-data {Array} option.series[0].label.borderRadius - شعاع گوشههای مرز برچسب
|
||
* @vue-data {Array} option.series[0].label.padding - پدینگ برچسب
|
||
* @vue-data {Number} option.series[0].label.lineHeight - ارتفاع خط برچسب
|
||
* @vue-data {Object} option.series[0].leaves - برگها
|
||
* @vue-data {Object} option.series[0].leaves.label - برچسبهای برگ
|
||
* @vue-data {String} option.series[0].leaves.label.position - موقعیت برچسب برگ
|
||
* @vue-data {String} option.series[0].leaves.label.verticalAlign - تراز عمودی برچسب برگ
|
||
* @vue-data {String} option.series[0].leaves.label.align - تراز برچسب برگ
|
||
* @vue-data {Object} option.series[0].emphasis - تاکید
|
||
* @vue-data {String} option.series[0].emphasis.focus - تمرکز تاکید
|
||
* @vue-data {String} option.series[0].emphasis.blurScope - محدوده مات شدن تاکید
|
||
* @vue-data {Boolean} option.series[0].expandAndCollapse - وضعیت باز و بسته شدن
|
||
* @vue-data {Number} option.series[0].animationDuration - مدت زمان انیمیشن
|
||
* @vue-data {Number} option.series[0].animationDurationUpdate - مدت زمان بهروزرسانی انیمیشن
|
||
*/
|
||
|
||
export default {
|
||
props: {
|
||
dataTreeMap: {
|
||
default() {
|
||
return [];
|
||
},
|
||
type: Array,
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
treeCounter: 1,
|
||
showButtons: false,
|
||
showDiv: false,
|
||
buttonAction: "",
|
||
addText: "",
|
||
editText: "",
|
||
httpService: undefined,
|
||
|
||
itemData: {},
|
||
tooltipText: "",
|
||
position: { top: "0px", left: "0px" },
|
||
option: {
|
||
tooltip: {
|
||
trigger: "item",
|
||
triggerOn: "mousemove",
|
||
},
|
||
toolbox: {
|
||
show: true,
|
||
itemSize: 15,
|
||
feature: {
|
||
myTool1: {
|
||
show: true,
|
||
title: " نمایش ",
|
||
icon: '<path d="M19.017 16.243c-1.431-0.009-2.588-1.166-2.597-2.596v-0.001c0.004-0.466 0.133-0.902 0.354-1.276l-0.006 0.012c-0.112-0.009-0.229-0.035-0.349-0.035-2.152 0-3.896 1.744-3.896 3.896s1.744 3.896 3.896 3.896c2.152 0 3.896-1.744 3.896-3.896v0c0-0.12-0.025-0.231-0.035-0.348-0.362 0.215-0.797 0.344-1.261 0.348h-0.001z"></path><path d="M16.42 7.152c-0.067-0.001-0.146-0.002-0.225-0.002-5.746 0-10.661 3.558-12.662 8.591l-0.032 0.092-0.133 0.411 0.133 0.411c2.035 5.125 6.951 8.683 12.697 8.683 0.079 0 0.157-0.001 0.236-0.002h-0.012c0.067 0.001 0.146 0.002 0.225 0.002 5.746 0 10.661-3.558 12.662-8.591l0.032-0.092 0.133-0.411-0.133-0.411c-2.035-5.125-6.951-8.683-12.697-8.683-0.079 0-0.157 0.001-0.236 0.002h0.012zM16.42 22.737c-0.107 0.004-0.234 0.006-0.36 0.006-4.417 0-8.218-2.642-9.907-6.432l-0.027-0.069c1.718-3.858 5.518-6.499 9.935-6.499 0.127 0 0.253 0.002 0.378 0.006l-0.018-0.001c0.107-0.004 0.234-0.006 0.36-0.006 4.417 0 8.218 2.642 9.907 6.432l0.027 0.069c-1.718 3.858-5.518 6.499-9.935 6.499-0.127 0-0.253-0.002-0.378-0.006h0.018z"></path>',
|
||
|
||
onclick: function () {
|
||
this.myToolClick("نمایش");
|
||
}.bind(this),
|
||
|
||
iconStyle: {
|
||
color: "",
|
||
},
|
||
},
|
||
myTool2: {
|
||
show: true,
|
||
title: " ویرایش ",
|
||
icon: '<path d="M9.333 25.856c-0.001 0-0.001 0-0.002 0-0.127 0-0.246-0.031-0.352-0.085l0.004 0.002-0.027 0.019-0.123-0.117c-0.024-0.021-0.046-0.041-0.066-0.064l-0-0-3.249-3.105 2.035-3.256 4.533 4.38-1.007 0.695h12.192c0.423 0 0.765 0.343 0.765 0.765s-0.343 0.765-0.765 0.765v0zM8.332 17.375l11.501-10.416c0.521-0.631 1.304-1.031 2.18-1.031 0.735 0 1.404 0.281 1.906 0.741l-0.002-0.002 1.333 1.5c0.385 0.41 0.621 0.963 0.621 1.571 0 0.714-0.325 1.351-0.836 1.773l-0.004 0.003-10.74 11.569z"></path>',
|
||
|
||
onclick: function () {
|
||
this.myToolClick("ویرایش");
|
||
}.bind(this),
|
||
iconStyle: {
|
||
color: "black",
|
||
},
|
||
},
|
||
},
|
||
},
|
||
series: [
|
||
{
|
||
type: "tree",
|
||
id: 0,
|
||
name: "tree1",
|
||
data: [],
|
||
top: "0%",
|
||
left: "40%",
|
||
bottom: "30%",
|
||
right: "5%",
|
||
while: "100%",
|
||
height: "100%",
|
||
zoom: 1,
|
||
symbolSize: 10,
|
||
// roam: true,
|
||
edgeForkPosition: "30%",
|
||
|
||
edgeShape: "curve",
|
||
// expandAndCollapse: true,
|
||
initialTreeDepth: 5,
|
||
orient: "RL",
|
||
// symbol: "none",
|
||
lineStyle: {
|
||
width: 2,
|
||
},
|
||
|
||
label: {
|
||
color: "#fff",
|
||
fontFamily: "sahel",
|
||
fontSize: 15,
|
||
align: "center",
|
||
position: "left",
|
||
verticalAlign: "middle",
|
||
borderRadius: 3,
|
||
padding: 6,
|
||
borderWidth: 2,
|
||
// shadowColor: "rgba(51, 41, 41, 1)",
|
||
// shadowBlur: 2.5,
|
||
// shadowOffsetX: 2,
|
||
// shadowOffsetY: 2,
|
||
width: 140,
|
||
height: 12,
|
||
backgroundColor: "#ee6666",
|
||
distance: 80,
|
||
formatter: function (params) {
|
||
const maxLength = 15;
|
||
const text =
|
||
params.name.length > maxLength
|
||
? params.name.substring(0, maxLength) + "..."
|
||
: params.name;
|
||
return text;
|
||
},
|
||
},
|
||
leaves: {
|
||
label: {
|
||
distance: 80,
|
||
color: "#fff",
|
||
fontFamily: "sahel",
|
||
fontSize: 15,
|
||
align: "center",
|
||
position: "left",
|
||
verticalAlign: "middle",
|
||
borderRadius: 3,
|
||
padding: 6,
|
||
borderWidth: 2,
|
||
// shadowColor: "rgba(51, 41, 41, 1)",
|
||
// shadowBlur: 2.5,
|
||
// shadowOffsetX: 2,
|
||
// shadowOffsetY: 2,
|
||
width: 140,
|
||
height: 12,
|
||
backgroundColor: "#fff",
|
||
formatter: function (params) {
|
||
const maxLength = 15;
|
||
const text =
|
||
params.name.length > maxLength
|
||
? params.name.substring(0, maxLength) + "..."
|
||
: params.name;
|
||
return text;
|
||
},
|
||
},
|
||
},
|
||
lineStyle: {
|
||
curveness: 0.6,
|
||
},
|
||
emphasis: {
|
||
focus: "relative",
|
||
blurScope: "coordinateSystem",
|
||
},
|
||
expandAndCollapse: true,
|
||
animationDuration: 550,
|
||
animationDurationUpdate: 750,
|
||
symbolOffset: [30, 0],
|
||
},
|
||
],
|
||
},
|
||
};
|
||
},
|
||
watch: {
|
||
dataTreeMap: {
|
||
handler(newData) {
|
||
this.option.series[0].data = newData;
|
||
this.treeCounter++;
|
||
},
|
||
deep: true,
|
||
immediate: true,
|
||
},
|
||
dataForTreeMapGetter(newValue) {
|
||
this.option.series[0].data = newValue;
|
||
this.treeCounter++;
|
||
},
|
||
},
|
||
beforeMount() {
|
||
this.httpService = new HttpService();
|
||
},
|
||
mounted() {
|
||
this.option.series[0].data = this.dataForTreeMapGetter;
|
||
this.option.toolbox.feature.myTool1.iconStyle.color = "black";
|
||
this.option.toolbox.feature.myTool2.iconStyle.color = "#fff";
|
||
},
|
||
computed: {
|
||
...mapState(useCommonStore, [
|
||
// "dataForTreeMapGetter",
|
||
"researchTermsGetter",
|
||
]),
|
||
},
|
||
|
||
methods: {
|
||
// ...mapActions(useResearchStore, ["dataForTreeMapSetter"]),
|
||
/**
|
||
*تغیرات مربوط به حالت نمایش و ویرایش در چارت
|
||
|
||
*/
|
||
myToolClick(item) {
|
||
if (item == "نمایش") {
|
||
this.showDiv = false;
|
||
this.option.toolbox.feature.myTool1.iconStyle.color = "black";
|
||
this.option.toolbox.feature.myTool2.iconStyle.color = "#fff";
|
||
} else {
|
||
this.showDiv = true;
|
||
this.option.toolbox.feature.myTool1.iconStyle.color = "#fff";
|
||
this.option.toolbox.feature.myTool2.iconStyle.color = "black";
|
||
}
|
||
},
|
||
/**
|
||
* نشان دادن دکمهها در هنگام وارد شدن ماوس
|
||
|
||
*/
|
||
onMouseEnter() {
|
||
this.showButtons = true;
|
||
},
|
||
/**
|
||
* پنهان کردن دکمهها در هنگام خارج شدن ماوس
|
||
|
||
*/
|
||
onMouseLeave() {
|
||
this.showButtons = false;
|
||
},
|
||
/**
|
||
* وقتی کاربر روی نقاط چارت کلیک میکند، این تابع وظیفه نمایش اطلاعات مربوط به آن نقطه را دارد.
|
||
* @param {Object} params - اطلاعات مربوط به کلیک شده روی چارت
|
||
*/
|
||
handleChartClick(params) {
|
||
const { offsetX, offsetY } = params.event;
|
||
// تنظیم موقعیت نمایش اطلاعات
|
||
this.position = { top: `${offsetY - 150}px`, left: `${offsetX}px` };
|
||
// نمایش متن توضیحات
|
||
this.tooltipText = params.name || "No data";
|
||
// ذخیره اطلاعات آیتم کلیک شده
|
||
this.itemData = params;
|
||
this.buttonAction = "";
|
||
this.addText = "";
|
||
this.editText = "";
|
||
// نمایش دکمههای مربوط به این آیتم
|
||
this.showButtons = true;
|
||
},
|
||
|
||
/**
|
||
* وقتی کاربر روی دکمههای اضافه کردن یا حذف کلیک میکند، این تابع عملکرد متناسب با دکمه انجام میدهد.
|
||
* @param {string} buttonName - نام دکمهای که کلیک شده است ('add' یا 'delete')
|
||
*/
|
||
onButtonClick(buttonName) {
|
||
this.buttonAction = buttonName;
|
||
// تعیین عملیات اضافه کردن یا حذف بر اساس دکمه انتخاب شده
|
||
if (buttonName == "add") this.fetchingExistingChildren();
|
||
else if (buttonName == "delete") this.removeNode();
|
||
// else if (buttonName == "edit") this.editNode();
|
||
},
|
||
|
||
/**
|
||
* این تابع دکمههای نمایش داده شده بر روی چارت را پنهان میکند.
|
||
*/
|
||
closeButtons() {
|
||
this.showButtons = false;
|
||
},
|
||
|
||
/**
|
||
* این تابع مسئول اضافه کردن آیتمهای جدید به چارت است.
|
||
* @param {string} item - عنوان آیتم جدید
|
||
*/
|
||
addNewChildren(item) {
|
||
let data = this.itemData.data;
|
||
// تهیه پارامترهای مورد نیاز برای ارسال درخواست
|
||
const payload = {
|
||
projectid: this.researchTermsGetter?.id,
|
||
parent: "",
|
||
listtype: 0,
|
||
title: item,
|
||
listid: "",
|
||
id: "",
|
||
};
|
||
// تنظیم مقادیر پارامترها بر اساس شرایط
|
||
if (data.pid === "Root") {
|
||
payload.id = undefined;
|
||
payload.parent = 0;
|
||
delete payload.listid;
|
||
} else {
|
||
payload.listid = data?.id;
|
||
payload.parent = data?.id;
|
||
delete payload.id;
|
||
}
|
||
// ارسال درخواست به سرور
|
||
let url = researchApi.subject.add;
|
||
this.httpService
|
||
.postRequest(url, payload)
|
||
.then((res) => {
|
||
// نمایش پیام موفقیت
|
||
this.mySwalToast({
|
||
title: "موفق",
|
||
html: " با موفقیت انجام شد ",
|
||
icon: "success",
|
||
});
|
||
// اضافه کردن آیتمهای جدید به دادههای مربوطه
|
||
res.data.forEach((element, index) => {
|
||
var node = {
|
||
item: element,
|
||
text: element.title,
|
||
name: element.title,
|
||
id: element.id,
|
||
pid: 0,
|
||
opened: false,
|
||
selected: false,
|
||
disabled: false,
|
||
loading: false,
|
||
children: [],
|
||
};
|
||
|
||
data.children.push(node);
|
||
// اضافه کردن آیتم به چارت
|
||
if (payload.parent === 0) {
|
||
this.option.series[0].data[0].children.push(node);
|
||
} else {
|
||
this.addChildToParent(
|
||
this.option.series[0].data[0],
|
||
payload.parent,
|
||
node
|
||
);
|
||
}
|
||
this.treeCounter++;
|
||
});
|
||
})
|
||
.catch((error) => {
|
||
// نمایش پیام خطا
|
||
console.error("Error adding new children:", error);
|
||
this.mySwalToast({
|
||
title: "خطا",
|
||
html: "مشکلی پیش آمد",
|
||
icon: "error",
|
||
});
|
||
})
|
||
.finally(() => {
|
||
this.buttonAction = "";
|
||
});
|
||
},
|
||
|
||
/**
|
||
* این تابع مسئول اضافه کردن یک آیتم فرزند به آیتم پدر میباشد.
|
||
* @param {Object} node - آیتم پدر
|
||
* @param {string} parentId - شناسه آیتم پدر
|
||
* @param {Object} newChild - آیتم فرزند جدید
|
||
* @returns {boolean} - مقدار منطقی True در صورت موفقیت آمیز بودن اضافه کردن، در غیر این صورت False
|
||
*/
|
||
addChildToParent(node, parentId, newChild) {
|
||
if (node.id === parentId) {
|
||
node.children.push(newChild);
|
||
return true;
|
||
}
|
||
|
||
if (node.children) {
|
||
for (let child of node.children) {
|
||
if (this.addChildToParent(child, parentId, newChild)) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
},
|
||
/**
|
||
* این تابع مسئول دریافت و نمایش آیتمهای موجود زیر یک آیتم پدر است.
|
||
*/
|
||
fetchingExistingChildren() {
|
||
let dataParent = this.itemData.data;
|
||
if (dataParent.children.length > 1) {
|
||
return;
|
||
}
|
||
try {
|
||
// دریافت لیست آیتمهای زیر یک آیتم پدر از سرور
|
||
this.getListTree(dataParent.id).then((list) => {
|
||
// اضافه کردن هر آیتم به لیست فرزندان آیتم پدر
|
||
list.forEach((element, index) => {
|
||
const dataColor = dataParent.label.backgroundColor;
|
||
|
||
var node = {
|
||
item: element,
|
||
text: element.title,
|
||
name: element.title,
|
||
id: element.id,
|
||
pid: dataParent.id,
|
||
opened: false,
|
||
selected: false,
|
||
disabled: false,
|
||
loading: false,
|
||
children: [],
|
||
label: {
|
||
backgroundColor: dataColor,
|
||
},
|
||
itemStyle: {
|
||
color: dataColor,
|
||
},
|
||
};
|
||
dataParent.children.push(node);
|
||
// اضافه کردن آیتم به چارت
|
||
if (dataParent.id === 0) {
|
||
this.option.series[0].data[0].children.push(node);
|
||
} else {
|
||
this.addChildToParent(
|
||
this.option.series[0].data[0],
|
||
dataParent.id,
|
||
node
|
||
);
|
||
}
|
||
this.treeCounter++;
|
||
});
|
||
});
|
||
} catch (error) {
|
||
console.error("Error fetching children nodes:", error);
|
||
}
|
||
},
|
||
/**
|
||
* این تابع مسئول حذف یک آیتم از چارت میباشد.
|
||
*/
|
||
removeNode() {
|
||
let removeData = this.itemData.data;
|
||
if (removeData.pid === "Root") return;
|
||
this.mySwalConfirm({
|
||
title: "هشدار!!!",
|
||
html: `از حذف <b>${removeData.text}</b> اطمینان دارید؟ `,
|
||
icon: "warning",
|
||
}).then((result) => {
|
||
if (result.isConfirmed) {
|
||
this.getRemov(removeData);
|
||
this.closeButtons();
|
||
}
|
||
});
|
||
},
|
||
|
||
/**
|
||
* این تابع مسئول حذف یک آیتم از چارت میباشد.
|
||
* @param {Object} nodeToRemove - آیتمی که قرار است حذف شود
|
||
*/
|
||
removeNodeFromChart(nodeToRemove) {
|
||
// حذف آیتم از چارت
|
||
if (nodeToRemove.pid === 0) {
|
||
let index = this.option.series[0].data[0].children.findIndex(
|
||
(child) => child.item.id === nodeToRemove.item.id
|
||
);
|
||
if (index !== -1) {
|
||
this.option.series[0].data[0].children.splice(index, 1);
|
||
}
|
||
} else {
|
||
let parentData = this.getParentData(nodeToRemove);
|
||
if (parentData) {
|
||
let index = parentData.children.findIndex(
|
||
(child) => child.item.id === nodeToRemove.item.id
|
||
);
|
||
if (index !== -1) {
|
||
parentData.children.splice(index, 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
this.treeCounter++; // افزایش شمارنده درخت
|
||
},
|
||
/**
|
||
* این تابع مسئول یافتن و بازگشت آیتم پدر مربوط به یک آیتم است.
|
||
* @param {Object} node - آیتم فرزند
|
||
* @returns {Object} - آیتم پدر
|
||
*/
|
||
getParentData(node) {
|
||
let parentData = null;
|
||
// جستجوی آیتم پدر با استفاده از شناسه آن
|
||
function findParent(nodeId, data) {
|
||
for (let i = 0; i < data.length; i++) {
|
||
if (data[i].id === nodeId) {
|
||
parentData = data[i];
|
||
break;
|
||
} else if (data[i].children && data[i].children.length) {
|
||
findParent(nodeId, data[i].children);
|
||
}
|
||
}
|
||
}
|
||
// فراخوانی تابع جستجوی آیتم پدر
|
||
findParent(node.pid, this.option.series[0].data[0].children);
|
||
return parentData;
|
||
},
|
||
/**
|
||
* این تابع مسئول دریافت لیست آیتمهای زیر یک آیتم پدر از سرور است.
|
||
* @param {string} parentId - شناسه آیتم پدر
|
||
* @returns {Promise} - لیست آیتمهای زیر آیتم پدر
|
||
*/
|
||
getListTree(parentId = 0) {
|
||
const payload = {
|
||
projectid: this.researchTermsGetter?.id,
|
||
parent: parentId,
|
||
sortby: "id",
|
||
offset: 0,
|
||
limit: 100,
|
||
listtype: 0,
|
||
};
|
||
let url = researchApi.subject.list;
|
||
// ارسال درخواست به سرور و بازگشت پاسخ به صورت Promise
|
||
return this.httpService.formDataRequest(url, payload).then((res) => {
|
||
return res.data;
|
||
});
|
||
},
|
||
/**
|
||
* این تابع مسئول حذف یک آیتم از چارت میباشد.
|
||
* @param {Object} item - آیتمی که قرار است حذف شود
|
||
*/
|
||
getRemov(item) {
|
||
const payload = {
|
||
subjectid: item.id,
|
||
projectid: this.researchTermsGetter?.id,
|
||
listid: item.id,
|
||
};
|
||
let url = researchApi.subject.delete;
|
||
this.httpService.postRequest(url, payload).then((res) => {
|
||
this.mySwalToast({
|
||
title: "موفق",
|
||
html: "با موفقیت حذف شد",
|
||
icon: "success",
|
||
});
|
||
// حذف آیتم از چارت
|
||
this.removeNodeFromChart(item);
|
||
});
|
||
},
|
||
/**
|
||
* این تابع مسئول ویرایش یک آیتم از چارت میباشد.
|
||
* @param {string} item - عنوان جدید آیتم
|
||
*/
|
||
editNode(item) {
|
||
let data = this.itemData.data;
|
||
const payload = {
|
||
subjectid: data.id,
|
||
projectid: this.researchTermsGetter?.id,
|
||
title: item,
|
||
};
|
||
let url = researchApi.subject.edit;
|
||
this.httpService
|
||
.formDataRequest(url, payload)
|
||
.then((res) => {
|
||
this.mySwalToast({
|
||
title: "موفق",
|
||
html: "تغییر نام با موفقیت انجام شد ",
|
||
icon: "success",
|
||
});
|
||
data.name = item;
|
||
data.text = item;
|
||
|
||
// پیدا کردن و بهروز رسانی آیتم در چارت
|
||
const updateNodeText = (node, id, newText) => {
|
||
if (node.id === id) {
|
||
node.name = newText;
|
||
node.text = newText;
|
||
return true;
|
||
}
|
||
if (node.children) {
|
||
for (let child of node.children) {
|
||
if (updateNodeText(child, id, newText)) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
updateNodeText(this.option.series[0].data[0], data.id, item);
|
||
|
||
this.treeCounter++;
|
||
this.closeButtons();
|
||
})
|
||
.finally(() => {
|
||
this.buttonAction = "";
|
||
});
|
||
},
|
||
},
|
||
|
||
};
|
||
</script>
|
||
<style lang="scss">
|
||
.tooltip-button {
|
||
button {
|
||
color: #dee2e6 !important;
|
||
&:hover {
|
||
color: black !important;
|
||
}
|
||
}
|
||
}
|
||
.reject-button {
|
||
color: #dee2e6 !important;
|
||
&:hover {
|
||
color: rgb(231, 10, 10) !important;
|
||
}
|
||
}
|
||
.accept-button {
|
||
color: #dee2e6 !important;
|
||
&:hover {
|
||
color: rgb(37, 223, 12) !important;
|
||
}
|
||
}
|
||
</style>
|