807 lines
29 KiB
Vue
807 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 { useResearchStore } from "~/stores/researchStore";
|
|||
|
//
|
|||
|
import { use } from "echarts/core";
|
|||
|
import { TreeChart } from "echarts/charts";
|
|||
|
import { TooltipComponent, ToolboxComponent } from "echarts/components";
|
|||
|
import { CanvasRenderer } from "echarts/renderers";
|
|||
|
import { removeData } from "jquery";
|
|||
|
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(useResearchStore, [
|
|||
|
"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>
|