390 lines
12 KiB
TypeScript
390 lines
12 KiB
TypeScript
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:
|
|
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16"><g fill="none"><path d="M4.5 2A2.5 2.5 0 0 0 2 4.5v7A2.5 2.5 0 0 0 4.5 14h1.547l.25-1H4.5A1.5 1.5 0 0 1 3 11.5V5h10v1.036c.331-.058.671-.05 1 .023V4.5A2.5 2.5 0 0 0 11.5 2h-7zM3.085 4A1.5 1.5 0 0 1 4.5 3h7a1.5 1.5 0 0 1 1.415 1h-9.83zm11.46 3.455a1.56 1.56 0 0 0-2.207 0l-4.289 4.288a2.777 2.777 0 0 0-.73 1.29l-.303 1.212a.61.61 0 0 0 .739.739l1.211-.303a2.777 2.777 0 0 0 1.29-.73l4.289-4.289a1.56 1.56 0 0 0 0-2.207z" fill="#5c8e9e"></path></g></svg>',
|
|
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:
|
|
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><g fill="none"><path d="M16.5 12a5.5 5.5 0 1 1 0 11a5.5 5.5 0 0 1 0-11zM12 1.75a3.25 3.25 0 0 1 3.245 3.066L15.25 5h5.25a.75.75 0 0 1 .102 1.493L20.5 6.5h-.796l-.5 5.087c-.46-.21-.95-.37-1.46-.468l.453-4.619H5.802l1.267 12.872a1.25 1.25 0 0 0 1.117 1.122l.127.006h2.42c.286.551.65 1.056 1.076 1.5H8.313a2.75 2.75 0 0 1-2.714-2.307l-.023-.174L4.295 6.5H3.5a.75.75 0 0 1-.743-.648L2.75 5.75a.75.75 0 0 1 .648-.743L3.5 5h5.25A3.25 3.25 0 0 1 12 1.75zm1.716 12.839l-.07.057l-.057.07a.5.5 0 0 0 0 .568l.057.07l2.147 2.146l-2.147 2.146l-.057.07a.5.5 0 0 0 0 .568l.057.07l.07.057a.5.5 0 0 0 .568 0l.07-.057l2.146-2.147l2.146 2.147l.07.057a.5.5 0 0 0 .568 0l.07-.057l.057-.07a.5.5 0 0 0 0-.568l-.057-.07l-2.147-2.146l2.147-2.146l.057-.07a.5.5 0 0 0 0-.568l-.057-.07l-.07-.057a.5.5 0 0 0-.568 0l-.07.057l-2.146 2.147l-2.146-2.147l-.07-.057a.5.5 0 0 0-.492-.044l-.076.044zM12 3.25a1.75 1.75 0 0 0-1.744 1.606L10.25 5h3.5A1.75 1.75 0 0 0 12 3.25z" fill="#933"></path></g></svg>',
|
|
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
|