optimize(projects): optimize plugin gantt

This commit is contained in:
Soybean 2024-08-06 10:21:46 +08:00
parent f86bca063a
commit bbacff0581
5 changed files with 246 additions and 290 deletions

View File

@ -44,6 +44,9 @@ importers:
dayjs: dayjs:
specifier: 1.11.12 specifier: 1.11.12
version: 1.11.12 version: 1.11.12
dhtmlx-gantt:
specifier: 8.0.9
version: 8.0.9
dompurify: dompurify:
specifier: 3.1.6 specifier: 3.1.6
version: 3.1.6 version: 3.1.6
@ -2282,6 +2285,9 @@ packages:
devlop@1.1.0: devlop@1.1.0:
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
dhtmlx-gantt@8.0.9:
resolution: {integrity: sha512-DONbnIjmVv7KiuHPmSEjZA2/XoSVGOviqx2vxRk/Vml+m8/YWMhoW+vP/rfkGEL8N764Gay41hI1ztfiNjWIVQ==}
diff-match-patch@1.0.5: diff-match-patch@1.0.5:
resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==}
@ -7187,6 +7193,8 @@ snapshots:
dependencies: dependencies:
dequal: 2.0.3 dequal: 2.0.3
dhtmlx-gantt@8.0.9: {}
diff-match-patch@1.0.5: {} diff-match-patch@1.0.5: {}
dir-glob@3.0.1: dir-glob@3.0.1:

View File

@ -45,7 +45,6 @@ declare module 'vue' {
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default'] LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
LookForward: typeof import('./../components/custom/look-forward.vue')['default'] LookForward: typeof import('./../components/custom/look-forward.vue')['default']
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default'] MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
NAlert: typeof import('naive-ui')['NAlert']
NBreadcrumb: typeof import('naive-ui')['NBreadcrumb'] NBreadcrumb: typeof import('naive-ui')['NBreadcrumb']
NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem'] NBreadcrumbItem: typeof import('naive-ui')['NBreadcrumbItem']
NButton: typeof import('naive-ui')['NButton'] NButton: typeof import('naive-ui')['NButton']
@ -69,7 +68,6 @@ declare module 'vue' {
NFormItemGi: typeof import('naive-ui')['NFormItemGi'] NFormItemGi: typeof import('naive-ui')['NFormItemGi']
NGi: typeof import('naive-ui')['NGi'] NGi: typeof import('naive-ui')['NGi']
NGrid: typeof import('naive-ui')['NGrid'] NGrid: typeof import('naive-ui')['NGrid']
NGridItem: typeof import('naive-ui')['NGridItem']
NInput: typeof import('naive-ui')['NInput'] NInput: typeof import('naive-ui')['NInput']
NInputGroup: typeof import('naive-ui')['NInputGroup'] NInputGroup: typeof import('naive-ui')['NInputGroup']
NInputNumber: typeof import('naive-ui')['NInputNumber'] NInputNumber: typeof import('naive-ui')['NInputNumber']

View File

@ -0,0 +1,173 @@
import type { Task } from 'dhtmlx-gantt';
export const ganttTasks: Task[] = [
{
id: 11,
text: 'Soybean 架构设计',
type: 'project',
progress: 0,
open: true,
start_date: new Date('2024-01-10 00:00'),
duration: 12,
parent: 0
},
{
id: 12,
text: '测试版本',
start_date: new Date('2024-03-20 00:00'),
type: 'project',
duration: 5,
render: 'split',
parent: '11',
progress: 0,
open: true
},
{
id: 99,
text: '测试版本1 发布',
start_date: new Date('2024-03-20 00:00'),
end_date: new Date('2024-03-25 00:00'),
parent: '12',
progress: 0,
open: true
},
{
id: 98,
text: '测试版本2 发布',
start_date: new Date('2024-03-26 00:00'),
duration: 4,
parent: '12',
progress: 0,
open: true
},
{
id: 97,
text: '测试版本3 发布',
start_date: new Date('2024-03-31 00:00'),
duration: 10,
parent: '12',
progress: 0,
open: true
},
{
id: 13,
text: '1.0 版本',
start_date: new Date('2024-03-31 00:00'),
type: 'project',
render: 'split',
parent: '11',
progress: 0.5,
open: false,
duration: 11
},
{
id: 17,
text: '1.0正式发布',
start_date: new Date('2024-03-31 00:00'),
end_date: new Date('2024-04-03 00:00'),
parent: '13',
progress: 0,
open: true
},
{
id: 18,
text: '1.0.1 版本',
start_date: new Date('2024-04-03 00:00'),
duration: 5,
parent: '13',
progress: 0,
open: true
},
{
id: 19,
text: '1.0.2 版本',
start_date: new Date('2024-04-08 00:00'),
duration: 6,
parent: '13',
progress: 0,
open: true
},
{
id: 20,
text: '1.0.3 版本',
start_date: new Date('2024-04-16 00:00'),
duration: 8,
parent: '13',
progress: 0,
open: true
},
{
id: 31,
text: '1.0.4 版本',
start_date: new Date('2024-04-17 00:00'),
duration: 8,
parent: '13',
progress: 0,
open: true
},
{
id: 32,
text: '1.0.5 版本',
start_date: new Date('2024-04-26 00:00'),
duration: 9,
parent: '13',
progress: 0,
open: true
},
{
id: 33,
text: '1.0.9 版本',
start_date: new Date('2024-05-05 00:00'),
duration: 2,
parent: '13',
progress: 0,
open: true
},
{
id: 14,
text: '1.1 版本',
start_date: new Date('2024-05-07 00:00'),
duration: 30,
parent: '11',
progress: 0,
open: true
},
{
id: 15,
text: '1.2 版本',
start_date: new Date('2024-06-06 00:00'),
duration: 46,
parent: '11',
progress: 0,
open: true
},
{
id: 16,
text: '1.3版本',
type: 'project',
render: 'split',
parent: '11',
progress: 0,
open: true,
start_date: new Date('2024-07-22 00:00'),
duration: 11
},
{
id: 21,
text: '1.3.1版本',
start_date: new Date('2024-07-22 00:00'),
duration: 7,
parent: '16',
progress: 0,
open: true
},
{
id: 22,
text: '1.3.2版本',
start_date: new Date('2024-07-29 00:00'),
duration: 7,
parent: '16',
progress: 0,
open: true
}
];

View File

@ -1,173 +0,0 @@
export const demoData = {
data: [
{
id: 11,
text: 'Soybean 架构设计',
type: 'project',
progress: 0,
open: true,
start_date: '2024-01-10 00:00',
duration: 12,
parent: 0
},
{
id: 12,
text: '测试版本',
start_date: '2024-03-20 00:00',
type: 'project',
duration: 5,
render: 'split',
parent: '11',
progress: 0,
open: true
},
{
id: 99,
text: '测试版本1 发布',
start_date: '2024-03-20 00:00',
end_date: '2024-03-25 00:00',
parent: '12',
progress: 0,
open: true
},
{
id: 98,
text: '测试版本2 发布',
start_date: '2024-03-26 00:00',
duration: 4,
parent: '12',
progress: 0,
open: true
},
{
id: 97,
text: '测试版本3 发布',
start_date: '2024-03-31 00:00',
duration: 10,
parent: '12',
progress: 0,
open: true
},
{
id: 13,
text: '1.0 版本',
start_date: '2024-03-31 00:00',
type: 'project',
render: 'split',
parent: '11',
progress: 0.5,
open: false,
duration: 11
},
{
id: 17,
text: '1.0正式发布',
start_date: '2024-03-31 00:00',
end_date: '2024-04-03 00:00',
parent: '13',
progress: 0,
open: true
},
{
id: 18,
text: '1.0.1 版本',
start_date: '2024-04-03 00:00',
duration: 5,
parent: '13',
progress: 0,
open: true
},
{
id: 19,
text: '1.0.2 版本',
start_date: '2024-04-08 00:00',
duration: 6,
parent: '13',
progress: 0,
open: true
},
{
id: 20,
text: '1.0.3 版本',
start_date: '2024-04-16 00:00',
duration: 8,
parent: '13',
progress: 0,
open: true
},
{
id: 31,
text: '1.0.4 版本',
start_date: '2024-04-17 00:00',
duration: 8,
parent: '13',
progress: 0,
open: true
},
{
id: 32,
text: '1.0.5 版本',
start_date: '2024-04-26 00:00',
duration: 9,
parent: '13',
progress: 0,
open: true
},
{
id: 33,
text: '1.0.9 版本',
start_date: '2024-05-05 00:00',
duration: 2,
parent: '13',
progress: 0,
open: true
},
{
id: 14,
text: '1.1 版本',
start_date: '2024-05-07 00:00',
duration: 30,
parent: '11',
progress: 0,
open: true
},
{
id: 15,
text: '1.2 版本',
start_date: '2024-06-06 00:00',
duration: 46,
parent: '11',
progress: 0,
open: true
},
{
id: 16,
text: '1.3版本',
type: 'project',
render: 'split',
parent: '11',
progress: 0,
open: true,
start_date: '2024-07-22 00:00',
duration: 11
},
{
id: 21,
text: '1.3.1版本',
start_date: '2024-07-22 00:00',
duration: 7,
parent: '16',
progress: 0,
open: true
},
{
id: 22,
text: '1.3.2版本',
start_date: '2024-07-29 00:00',
duration: 7,
parent: '16',
progress: 0,
open: true
}
]
};

View File

@ -1,17 +1,22 @@
<script setup lang="tsx"> <script setup lang="tsx">
import { onMounted, shallowRef } from 'vue'; import { onMounted, shallowRef } from 'vue';
import { gantt } from 'dhtmlx-gantt'; import { gantt } from 'dhtmlx-gantt';
import type { ZoomLevels } from 'dhtmlx-gantt'; import type { GanttConfigOptions, ZoomLevels } from 'dhtmlx-gantt';
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'; import 'dhtmlx-gantt/codebase/dhtmlxgantt.css';
import { demoData } from './ganntData'; import { ganttTasks } from './data';
type ZoomConfig = { const ganttRef = shallowRef<HTMLElement>();
levels: ZoomLevels[];
};
const schema = shallowRef('quarter'); type TimeType = 'day' | 'week' | 'month' | 'quarter' | 'year';
const data = [ const timeType = shallowRef<TimeType>('quarter');
interface TimeData {
name: string;
code: TimeType;
}
const data: TimeData[] = [
{ {
name: '天', name: '天',
code: 'day' code: 'day'
@ -34,8 +39,40 @@ const data = [
} }
]; ];
const zoomConfig: ZoomConfig = { function initGantt() {
levels: [ if (!ganttRef.value) return;
const config: Partial<GanttConfigOptions> = {
grid_width: 350,
add_column: false,
autofit: false,
row_height: 60,
bar_height: 34,
auto_types: true,
xml_date: '%Y-%m-%d',
columns: [
{
name: 'text',
label: '项目名称',
tree: true,
width: '*'
},
{
name: 'start_date',
label: '开始时间',
align: 'center',
width: 150
}
]
};
Object.assign(gantt.config, config);
gantt.i18n.setLocale('cn');
gantt.init(ganttRef.value);
gantt.parse({ data: ganttTasks });
const zoomLevels: ZoomLevels[] = [
{ {
name: 'day', name: 'day',
scale_height: 60, scale_height: 60,
@ -121,77 +158,16 @@ const zoomConfig: ZoomConfig = {
{ unit: 'month', format: '%Y-%m' } { unit: 'month', format: '%Y-%m' }
] ]
} }
]
};
function scrollInit() {
const nav = document.querySelector<HTMLElement>('.gantt_task')!;
const parNav = document.querySelector<HTMLElement>('.gantt_hor_scroll')!;
parNav.scrollLeft = 0;
let flag: boolean = false;
let downX: number = 0;
let scrollLeft: number = 0;
nav.addEventListener('mousedown', event => {
flag = true;
downX = event.clientX;
scrollLeft = event.offsetX;
});
nav.addEventListener('mousemove', event => {
if (flag) {
const moveX = event.clientX;
const scrollX = moveX - downX;
parNav.scrollLeft = scrollLeft - scrollX;
}
});
nav.addEventListener('mouseup', () => {
flag = false;
});
nav.addEventListener('mouseleave', () => {
flag = false;
});
}
function initGantt() {
gantt.config.grid_width = 350;
gantt.config.add_column = false;
gantt.config.autofit = false;
gantt.config.row_height = 60;
gantt.config.bar_height = 34;
gantt.config.auto_types = true;
gantt.config.xml_date = '%Y-%m-%d';
gantt.config.columns = [
{
name: 'text',
label: '项目名称',
tree: true,
width: '*'
},
{
name: 'start_date',
label: '开始时间',
align: 'center',
width: 150
}
]; ];
gantt.i18n.setLocale('cn'); gantt.ext.zoom.init({
gantt.init('gantt_here'); levels: zoomLevels
gantt.parse(demoData); });
gantt.ext.zoom.setLevel(timeType.value);
scrollInit();
gantt.ext.zoom.init(zoomConfig);
gantt.ext.zoom.setLevel(schema.value);
} }
function changeTime(value: string) { function changeTime(value: TimeType) {
schema.value = value; timeType.value = value;
gantt.ext.zoom.setLevel(value); gantt.ext.zoom.setLevel(value);
} }
@ -201,58 +177,32 @@ onMounted(() => {
</script> </script>
<template> <template>
<div class="my-gantt min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto"> <div class="overflow-hidden lt-sm:overflow-auto">
<NCard <NCard
title="甘特图演示" title="甘特图演示"
:bordered="false" :bordered="false"
size="small" size="small"
content-class="flex-x-center" content-class="overflow-y-hidden overflow-x-auto"
class="sm:flex-1-hidden card-wrapper" class="h-full card-wrapper"
> >
<template #header-extra> <template #header-extra>
<NTabs :value="schema" type="segment" animated size="small" class="relative w-320px" @update:value="changeTime"> <NTabs
:value="timeType"
type="segment"
animated
size="small"
class="relative w-320px"
@update:value="changeTime"
>
<NTab v-for="item in data" :key="item.code" :name="item.code"> <NTab v-for="item in data" :key="item.code" :name="item.code">
{{ item.name }} {{ item.name }}
</NTab> </NTab>
</NTabs> </NTabs>
</template> </template>
<div id="gantt_here" class="gantt-container h-full w-full container"></div> <div ref="ganttRef" class="size-full min-w-800px"></div>
</NCard> </NCard>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss"></style>
.my-gantt {
::v-deep .gantt-container {
border-radius: 8px;
overflow: hidden;
height: 100%;
.gantt_task_content {
border-radius: 17px;
}
.gantt_task_line.gantt_project {
border-radius: 17px;
border: none;
--uno: bg-primary;
}
.gantt_task_line {
--uno: bg-primary-400;
border: none;
border-radius: 15px;
}
.gantt_grid_data .gantt_row.odd:hover,
.gantt_grid_data .gantt_row:hover {
--uno: bg-warning;
}
.gantt_task_row.gantt_selected .gantt_task_cell {
--uno: bg-warning;
}
.gantt_grid_data .gantt_row.gantt_selected,
.gantt_grid_data .gantt_row.odd.gantt_selected,
.gantt_task_row.gantt_selected {
--uno: bg-warning;
}
}
}
</style>