import { Group, Image, Text, CheckBox, Rect } from '@visactor/vtable/es/vrender' import { useDialog } from 'naive-ui' import { Gantt, tools, TYPES } from '@visactor/vtable-gantt' import { getMainGantt, getSubGantt } from '@/api/Gantt/gantt' type GanttParams = { route?: any router?: any } let ganttInstance: null | Gantt = null const bgColor = '#1c202c' const headerBgColor = '#33566f22' const textColor = '#65c5e7' const textColorWithOp = '#75fbfd22' const useGanttEdit = ({ router, route }: GanttParams) => { const { subId } = route.params const records = ref([]) const dialog = useDialog() onMounted(() => { getGanttData() }) async function getGanttData() { if (subId) { const res = await getSubGantt(subId) records.value = res ganttInstance?.setRecords(records.value) } else { const res = await getMainGantt() // console.log(res, '----') records.value = res ganttInstance?.setRecords(records.value) } } function renderMainTask(dom: HTMLElement) { const option = getOption() ganttInstance = new Gantt(dom, option) window['ganttInstance'] = ganttInstance console.log(ganttInstance) } function getOption(): TYPES.GanttConstructorOptions { const option = { records: records.value, taskListTable: renderTaskListTable(), tasksShowMode: TYPES.TasksShowMode.Sub_Tasks_Arrange, frame: { outerFrameStyle: { borderLineWidth: 2, borderColor: textColor, cornerRadius: 3, }, // verticalSplitLineHighlight: { // lineColor: 'green', // lineWidth: 3 // } }, grid: { // backgroundColor: bgColor, horizontalLine: { lineWidth: 1, lineColor: textColorWithOp, }, verticalLine: { lineWidth: 1, lineColor: textColorWithOp, lineDash: [4, 8], }, }, taskList: { // backgroundColor: bgColor, headerStyle: { borderColor: '#e1e4e8', borderLineWidth: 0, fontSize: 18, fontWeight: 'bold', color: 'red', }, }, headerRowHeight: 59, rowHeight: subId ? 200 : 100, taskBar: renderTaskBar(), timelineHeader: { backgroundColor: headerBgColor, colWidth: 150, verticalLine: { lineColor: textColorWithOp, lineWidth: 1, lineDash: [4, 2], }, horizontalLine: { lineColor: textColorWithOp, lineWidth: 1, lineDash: [4, 2], }, scales: getTimeScales('day'), }, minDate: '2024-11-14', maxDate: '2024-12-30', scrollStyle: { scrollRailColor: 'RGBA(246,246,246,0)', visible: 'focus', width: 6, scrollSliderCornerRadius: 2, scrollSliderColor: 'rgba(255,255,255,0.25)', }, underlayBackgroundColor: bgColor, } return option as TYPES.GanttConstructorOptions } function renderColumn() { const columns = [ { field: 'name', title: subId ? '事件类型' : '事件主体', width: '120', mergeCell: true, }, ] // if (subId) { // columns.unshift({ // field: 'isChecked', // title: '', // width: '60', // headerType: 'checkbox', // cellType: 'checkbox', // }) // } return columns } function renderTaskListTable() { const taskListTable = { columns: renderColumn(), // tableWidth: 'auto', theme: { underlayBackgroundColor: bgColor, headerStyle: { borderColor: textColorWithOp, borderLineWidth: 1, fontWeight: 'bold', color: textColor, bgColor: headerBgColor, textAlign: 'center', fontSize: 20, hover: { cellBgColor: 'transparent', }, }, bodyStyle: { borderColor: textColorWithOp, textAlign: 'center', borderLineWidth: 1, autoWrapText: true, fontSize: 16, color: textColor, bgColor: bgColor, hover: { cellBgColor: textColorWithOp, }, }, }, } return taskListTable } function renderTaskBar() { const taskBar = { resizable: false, moveable: false, startDateField: 'start', endDateField: 'end', // progressField: 'progress', barStyle: { width: subId ? 180 : 60 }, customLayout: args => { const { width, height, startDate, endDate, taskRecord } = args const container = new Group({ width, height, fill: 'transparent', display: 'flex', flexDirection: 'column', justifyContent: 'center', // alignItems: 'center', cursor: 'pointer', }) if (!subId) { container.addEventListener('click', event => { router.push({ path: `/gantt/subEdit/${taskRecord.id}`, }) }) } if (subId) { const image = new Image({ image: taskRecord.avatar, width: 100, height: 100, x: 10, y: 10, boundsPadding: [0, 0, 10, 0], }) container.add(image) } const checkBoxGroup = new Group({ width, //height, fill: 'transparent', display: 'flex', }) container.add(checkBoxGroup) // const checkbox = new CheckBox({ // id: taskRecord.id, // text: '', // checked: false, // }) // checkBoxGroup.add(checkbox) // checkbox.addEventListener('click', event => { // event.stopPropagation() // console.log(checkbox, 'checkbox') // }) const name = new Text({ text: taskRecord.name, fontSize: 16, fontFamily: 'sans-serif', fill: textColor, fontWeight: 'bold', maxLineWidth: width, textAlign: 'center', // boundsPadding: [0, 0, 0, 10], }) checkBoxGroup.add(name) const editSymbol = new Image({ width: 20, height: 20, fill: '#fff', image: '', boundsPadding: [-2, 0, 0, 10], cursor: 'pointer', }) checkBoxGroup.add(editSymbol) editSymbol.addEventListener('click', event => { event.stopPropagation() console.log(editSymbol, 'editSymbol') }) const deleteSymbol = new Image({ width: 20, height: 20, fill: '#fff', image: '', boundsPadding: [-2, 0, 0, 10], cursor: 'pointer', }) checkBoxGroup.add(deleteSymbol) deleteSymbol.addEventListener('click', event => { event.stopPropagation() // console.log(dialog, '----') dialog.warning({ title: '警告', content: '确认删除当前事件?', positiveText: '确定', negativeText: '取消', onPositiveClick: () => {}, onNegativeClick: () => {}, }) console.log(deleteSymbol, 'deleteSymbol') }) const days = new Text({ text: `${startDate.toLocaleDateString()} ~ ${endDate.toLocaleDateString()}`, fontSize: 13, fontFamily: 'sans-serif', fill: textColor, boundsPadding: [10, 0, 0, 0], }) container.add(days) const rect = new Rect({ width: width, height: 7, fill: { gradient: 'linear', x0: 0, y0: 0, x1: 1, y1: 0, stops: [ { offset: 0, color: textColor, }, { offset: 1, color: textColorWithOp, }, ], }, boundsPadding: [10, 0, 0, 0], }) container.add(rect) return { rootContainer: container, } }, hoverBarStyle: { cornerRadius: 2, barOverlayColor: textColorWithOp, }, selectedBarStyle: { // cornerRadius: 2, borderColor: textColorWithOp, borderLineWidth: 2, }, } return taskBar } function renderGroup(opt: IGroupGraphicAttribute) { return new Group(opt) } function renderText(opt: ITextGraphicAttribute) { return new Text(opt) } function renderImage(opt: IImageGraphicAttribute) { return new Image(opt) } function changeTimeScales(scale: TYPES.ITimelineScale['unit']) { const scales = getTimeScales(scale) ganttInstance && ganttInstance.updateScales(scales) } function getTimeScales( scale: TYPES.ITimelineScale['unit'] ): TYPES.ITimelineScale[] { return [ { unit: scale, step: 1, customLayout: args => { const { width, height, startDate } = args const container = new Group({ width, height, display: 'flex', flexDirection: 'row', justifyContent: 'center', alignItems: 'center', flexWrap: 'nowrap', }) const day = new Text({ text: scale === 'day' ? startDate.toLocaleDateString() : startDate.toLocaleTimeString(), fontSize: 14, fontWeight: 'bold', fontFamily: 'sans-serif', fill: textColor, textAlign: 'center', maxLineWidth: width, // boundsPadding: [25, 12, 10, 12], }) container.add(day) return { rootContainer: container, } }, }, ] } return { renderMainTask, changeTimeScales } } export default useGanttEdit