<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"; import { useCommonStore } from "~/stores/commonStore"; /** * @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: { ...mapState(useCommonStore, ["activeEntityViewSchemaGetter"]), }, 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>