base_ui/components/charts/Gantt.vue

260 lines
7.7 KiB
Vue
Raw Normal View History

2025-02-01 09:34:55 +00:00
<template>
<div ref="chart" style="width: 100%; height: 400px"></div>
</template>
<script>
import * as echarts from "echarts";
import entityApi from "~/apis/entityApi.js";
import { mapState } from "pinia";
2025-02-11 07:08:54 +00:00
import { useCommonStore } from "~/stores/commonStore";
2025-02-01 09:34:55 +00:00
/**
* @vue-prop {Object|null} [selectedItem=null] - آیتم انتخاب شده
* @vue-prop {String} [title="تغییرات زمانی"] - عنوان
* @vue-prop {String} [time_unit="day"] - واحد زمانی
* @vue-data {String} [gantt_time_unit="day"] - واحد زمانی گانت
* @vue-data {Array} [gantt_data=[]] - دادههای گانت
* @vue-data {Object|null} [httpService=null] - سرویس HTTP
* @vue-data {Number} [x_min=0] - حداقل مقدار محور x
* @vue-data {Number} [x_max=10] - حداکثر مقدار محور x
* @vue-data {Object|undefined} [entity=undefined] - موجودیت
*
* * @vue-computed {Function} [mapState.activeEntityViewSchemaGetter] - دریافتکننده طرح نمای موجودیت فعال
*/
export default {
props: {
selectedItem: {
default: null,
},
title: {
default: "تغییرات زمانی",
},
time_unit: {
default: "day",
},
},
data() {
return {
gantt_time_unit: "day",
gantt_data: [],
x_min: 0,
x_max: 10,
entity: undefined,
};
},
computed: {
2025-02-11 07:08:54 +00:00
...mapState(useCommonStore, ["activeEntityViewSchemaGetter"]),
2025-02-01 09:34:55 +00:00
},
mounted() {
if (this.selectedItem) {
this.entity = this.selectedItem;
this.gantt_time_unit = "month";
this.getGanttData();
} else {
this.gantt_title = this.title;
this.gantt_time_unit = this.time_unit;
this.gantt_data = this.data;
// this.setChartOptions(this.gantt_time_unit);
}
},
watch: {
selectedItem: {
handler(newVal) {
if (newVal) {
this.getGanttData();
}
},
},
},
methods: {
/**
* دریافت دادههای نمودار گانت.
* این متد با ارسال درخواست به سرور، دادههای نمودار گانت را دریافت کرده و سپس نمودار را با استفاده از دادههای دریافتی رندر میکند.
*/
async getGanttData() {
if (!this.selectedItem) {
this.renderChart();
return;
}
let payload = {
id: this.selectedItem._id,
};
let url = entityApi.chart.ganttchart;
let key = this.activeEntityViewSchemaGetter?.key;
url = url.replace("{{index_key}}", key);
if (key === "qasection" || key === "rgsection") {
payload.qanon_id = this.selectedItem.qanon_id;
}
try {
const { $api } = useNuxtApp();
const res = await $api(url, {
method: "post",
baseURL: baseUrl(),
body: payload,
});
this.x_min = res.meta.min;
this.x_max = res.meta.max;
this.gantt_data = res.data[0].data.map((item) => ({
...item,
start: new Date(item.start),
end: new Date(item.end),
}));
} catch (err) {
} finally {
this.renderChart();
}
// this.httpService
// .postRequest(url, payload)
// .then((res) => {
// this.x_min = res.meta.min;
// this.x_max = res.meta.max;
// this.gantt_data = res.data[0].data.map((item) => ({
// ...item,
// start: new Date(item.start),
// end: new Date(item.end),
// }));
// })
// .finally(() => {
// this.renderChart();
// })
// .catch((error) => {
// console.error("Error fetching Gantt data:", error);
// });
},
/**
* رندر کردن نمودار.
* این متد با استفاده از دادههای نمودار گانت، نمودار را در DOM رندر میکند.
*/
renderChart() {
const chartDom = this.$refs.chart;
const myChart = echarts.init(chartDom);
const categories = this.gantt_data.map((item) => item.name);
myChart.setOption({
title: {
text: this.title,
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
grid: {
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
xAxis: {
type: "time",
},
yAxis: {
type: "category",
data: categories,
},
series: [
{
name: "Gantt",
type: "custom",
renderItem: function (params, api) {
var categoryIndex = api.value(1);
var start = api.coord([api.value(0), categoryIndex]);
var end = api.coord([api.value(2), categoryIndex]);
var height = api.size([0, 1])[1] * 0.6;
return {
type: "rect",
shape: echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height,
},
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height,
}
),
style: {
fill: this.getRandomColor(),
transition: "fill 1s cubicInOut",
},
};
}.bind(this),
data: this.gantt_data.map((item) => {
return [
item.start.getTime(),
categories.indexOf(item.name),
item.end.getTime(),
];
}),
animationDurationUpdate: 1000,
animationEasingUpdate: "cubicInOut",
},
],
});
},
/**
* دریافت یک رنگ تصادفی.
* این متد یک رنگ تصادفی از یک لیست از پیش تعیین شده برمیگرداند.
*
* @returns {string} - یک رشته حاوی کد رنگ به فرمت rgb
*/
getRandomColor() {
const colors = [
"rgb(255, 99, 71)", // Tomato
"rgb(255, 140, 0)", // Dark Orange
"rgb(34, 139, 34)", // Forest Green
"rgb(30, 144, 255)", // Dodger Blue
"rgb(138, 43, 226)", // Blue Violet
"rgb(255, 20, 147)", // Deep Pink
"rgb(0, 191, 255)", // Deep Sky Blue
"rgb(218, 165, 32)", // Goldenrod
"rgb(220, 20, 60)", // Crimson
"rgb(75, 0, 130)", // Indigo
];
const randomIndex = Math.floor(Math.random() * colors.length);
return colors[randomIndex];
},
/**
* دریافت فرمت محور X.
* این متد فرمت تاریخ و زمان محور X را بر اساس واحد زمانی گانت تعیین میکند.
*
* @returns {object} - یک شیء حاوی فرمت تاریخ و زمان
*/
getXAxisFormat() {
let format = {
day: '%e<br><span style="opacity: 0.5; font-size: 1em">%a</span>',
};
if (this.gantt_time_unit == "day")
format = {
day: '%e<br><span style="opacity: 0.5; font-size: 1em">%a</span>',
};
else if (this.gantt_time_unit == "week") format = { week: "%e. %b" };
else if (this.gantt_time_unit == "month") format = { month: "%b '%y" };
else if (this.gantt_time_unit == "year") format = { year: "%Y" };
return format;
},
},
};
</script>
<style>
/* افزودن هرگونه سبک مورد نیاز */
</style>