From 7426a3328288dcd45d9b0d7aee87cf16962e7f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=A5=E4=BA=89=E9=B8=A3?= Date: Wed, 12 Mar 2025 09:13:41 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=A8=E8=BE=B07=E6=97=A5gantt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/timer.js | 45 ++ .../EventList/components/EventDdConfig.jsx | 0 .../EventList/components/MainEventEdit.jsx | 66 +- .../EventList/components/SubEventEdit.jsx | 87 ++- .../EventList/components/useEventDdConfig.jsx | 0 .../Gantt/components/EventList/hooks.jsx | 58 +- .../Gantt/components/EventList/index.jsx | 5 +- .../components/Gantt/components/VRender.jsx | 0 .../Gantt/components/Gantt/hooks/gantt.ts | 101 ++- .../Gantt/components/Gantt/hooks/infoBox.jsx | 57 ++ src/views/Gantt/components/Gantt/index.jsx | 65 +- .../components/Gantt1/components/VRender.jsx | 0 .../Gantt/components/Gantt1/hooks/gantt.ts | 0 src/views/Gantt/components/Gantt1/index.jsx | 0 .../components/Gantt2/components/VRender.jsx | 0 .../Gantt/components/Gantt2/hooks/gantt.ts | 0 src/views/Gantt/components/Gantt2/index.jsx | 6 +- .../components/GanttEdit/hooks/ganttEdit.ts | 0 .../Gantt/components/GanttEdit/index.jsx | 0 .../Gantt/components/MainGantt/index.jsx | 9 +- .../Gantt/components/MainGantt1/index.jsx | 2 +- .../Gantt/components/MainGantt2/index.jsx | 43 +- .../Gantt/components/MainGanttEdit/index.jsx | 6 +- src/views/Gantt/components/SubGantt/index.jsx | 0 .../Gantt/components/SubGanttEdit/index.jsx | 0 .../TaskList/components/NewTask/hooks.ts | 0 .../TaskList/components/NewTask/index.jsx | 0 src/views/Gantt/components/TaskList/index.jsx | 0 src/views/Gantt/index copy.vue | 2 +- src/views/Gantt/index.jsx | 2 +- src/views/Gantt/index.vue | 0 .../EventList/components/EventDdConfig.jsx | 94 +++ .../EventList/components/MainEventEdit.jsx | 130 ++++ .../EventList/components/SubEventEdit.jsx | 155 +++++ .../EventList/components/useEventDdConfig.jsx | 103 +++ .../Gantt0305/components/EventList/hooks.jsx | 106 +++ .../Gantt0305/components/EventList/index.jsx | 296 +++++++++ .../components/Gantt/components/VRender.jsx | 47 ++ .../Gantt0305/components/Gantt/hooks/gantt.ts | 608 ++++++++++++++++++ .../Gantt0305/components/Gantt/index.jsx | 88 +++ .../components/Gantt1/components/VRender.jsx | 47 ++ .../components/Gantt1/hooks/gantt.ts | 452 +++++++++++++ .../Gantt0305/components/Gantt1/index.jsx | 51 ++ .../components/Gantt2/components/VRender.jsx | 47 ++ .../components/Gantt2/hooks/gantt.ts | 461 +++++++++++++ .../Gantt0305/components/Gantt2/index.jsx | 66 ++ .../components/GanttEdit/hooks/ganttEdit.ts | 389 +++++++++++ .../Gantt0305/components/GanttEdit/index.jsx | 29 + .../Gantt0305/components/MainGantt/index.jsx | 75 +++ .../Gantt0305/components/MainGantt1/index.jsx | 48 ++ .../Gantt0305/components/MainGantt2/index.jsx | 83 +++ .../components/MainGanttEdit/index.jsx | 45 ++ .../Gantt0305/components/SubGantt/index.jsx | 33 + .../components/SubGanttEdit/index.jsx | 33 + .../TaskList/components/NewTask/hooks.ts | 15 + .../TaskList/components/NewTask/index.jsx | 118 ++++ .../Gantt0305/components/TaskList/index.jsx | 172 +++++ src/views/Gantt0305/index copy.vue | 531 +++++++++++++++ src/views/Gantt0305/index.jsx | 179 ++++++ src/views/Gantt0305/index.vue | 7 + 60 files changed, 4927 insertions(+), 135 deletions(-) create mode 100644 src/utils/timer.js mode change 100755 => 100644 src/views/Gantt/components/EventList/components/EventDdConfig.jsx mode change 100755 => 100644 src/views/Gantt/components/EventList/components/MainEventEdit.jsx mode change 100755 => 100644 src/views/Gantt/components/EventList/components/SubEventEdit.jsx mode change 100755 => 100644 src/views/Gantt/components/EventList/components/useEventDdConfig.jsx mode change 100755 => 100644 src/views/Gantt/components/EventList/hooks.jsx mode change 100755 => 100644 src/views/Gantt/components/EventList/index.jsx mode change 100755 => 100644 src/views/Gantt/components/Gantt/components/VRender.jsx mode change 100755 => 100644 src/views/Gantt/components/Gantt/hooks/gantt.ts create mode 100644 src/views/Gantt/components/Gantt/hooks/infoBox.jsx mode change 100755 => 100644 src/views/Gantt/components/Gantt/index.jsx mode change 100755 => 100644 src/views/Gantt/components/Gantt1/components/VRender.jsx mode change 100755 => 100644 src/views/Gantt/components/Gantt1/hooks/gantt.ts mode change 100755 => 100644 src/views/Gantt/components/Gantt1/index.jsx mode change 100755 => 100644 src/views/Gantt/components/Gantt2/components/VRender.jsx mode change 100755 => 100644 src/views/Gantt/components/Gantt2/hooks/gantt.ts mode change 100755 => 100644 src/views/Gantt/components/Gantt2/index.jsx mode change 100755 => 100644 src/views/Gantt/components/GanttEdit/hooks/ganttEdit.ts mode change 100755 => 100644 src/views/Gantt/components/GanttEdit/index.jsx mode change 100755 => 100644 src/views/Gantt/components/MainGantt/index.jsx mode change 100755 => 100644 src/views/Gantt/components/MainGantt1/index.jsx mode change 100755 => 100644 src/views/Gantt/components/MainGantt2/index.jsx mode change 100755 => 100644 src/views/Gantt/components/MainGanttEdit/index.jsx mode change 100755 => 100644 src/views/Gantt/components/SubGantt/index.jsx mode change 100755 => 100644 src/views/Gantt/components/SubGanttEdit/index.jsx mode change 100755 => 100644 src/views/Gantt/components/TaskList/components/NewTask/hooks.ts mode change 100755 => 100644 src/views/Gantt/components/TaskList/components/NewTask/index.jsx mode change 100755 => 100644 src/views/Gantt/components/TaskList/index.jsx mode change 100755 => 100644 src/views/Gantt/index copy.vue mode change 100755 => 100644 src/views/Gantt/index.jsx mode change 100755 => 100644 src/views/Gantt/index.vue create mode 100755 src/views/Gantt0305/components/EventList/components/EventDdConfig.jsx create mode 100755 src/views/Gantt0305/components/EventList/components/MainEventEdit.jsx create mode 100755 src/views/Gantt0305/components/EventList/components/SubEventEdit.jsx create mode 100755 src/views/Gantt0305/components/EventList/components/useEventDdConfig.jsx create mode 100755 src/views/Gantt0305/components/EventList/hooks.jsx create mode 100755 src/views/Gantt0305/components/EventList/index.jsx create mode 100755 src/views/Gantt0305/components/Gantt/components/VRender.jsx create mode 100755 src/views/Gantt0305/components/Gantt/hooks/gantt.ts create mode 100755 src/views/Gantt0305/components/Gantt/index.jsx create mode 100755 src/views/Gantt0305/components/Gantt1/components/VRender.jsx create mode 100755 src/views/Gantt0305/components/Gantt1/hooks/gantt.ts create mode 100755 src/views/Gantt0305/components/Gantt1/index.jsx create mode 100755 src/views/Gantt0305/components/Gantt2/components/VRender.jsx create mode 100755 src/views/Gantt0305/components/Gantt2/hooks/gantt.ts create mode 100755 src/views/Gantt0305/components/Gantt2/index.jsx create mode 100755 src/views/Gantt0305/components/GanttEdit/hooks/ganttEdit.ts create mode 100755 src/views/Gantt0305/components/GanttEdit/index.jsx create mode 100755 src/views/Gantt0305/components/MainGantt/index.jsx create mode 100755 src/views/Gantt0305/components/MainGantt1/index.jsx create mode 100755 src/views/Gantt0305/components/MainGantt2/index.jsx create mode 100755 src/views/Gantt0305/components/MainGanttEdit/index.jsx create mode 100755 src/views/Gantt0305/components/SubGantt/index.jsx create mode 100755 src/views/Gantt0305/components/SubGanttEdit/index.jsx create mode 100755 src/views/Gantt0305/components/TaskList/components/NewTask/hooks.ts create mode 100755 src/views/Gantt0305/components/TaskList/components/NewTask/index.jsx create mode 100755 src/views/Gantt0305/components/TaskList/index.jsx create mode 100755 src/views/Gantt0305/index copy.vue create mode 100755 src/views/Gantt0305/index.jsx create mode 100755 src/views/Gantt0305/index.vue diff --git a/src/utils/timer.js b/src/utils/timer.js new file mode 100644 index 000000000..30ba72b4f --- /dev/null +++ b/src/utils/timer.js @@ -0,0 +1,45 @@ +export const useTimer = () => { + return { + Interval, + } +} + +class Interval { + constructor(callback, interval, options = {}) { + this.callback = callback + this.interval = interval + this.timer = null + this.options = options + } + + immediateRun() { + if (this.options.immediate) { + this.callback() + } + } + + startInterval() { + this.immediateRun() + let expectedTime = performance.now() + this.interval + + const self = this + function loop(currentTime) { + const deltaTime = currentTime - expectedTime + // console.log(deltaTime) + if (deltaTime >= 0) { + self.callback() + expectedTime += self.interval + } + + self.timer = requestAnimationFrame(loop) + } + + this.timer = requestAnimationFrame(loop) + + return self.timer + } + + stopInterval() { + cancelAnimationFrame(this.timer) + } +} diff --git a/src/views/Gantt/components/EventList/components/EventDdConfig.jsx b/src/views/Gantt/components/EventList/components/EventDdConfig.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/EventList/components/MainEventEdit.jsx b/src/views/Gantt/components/EventList/components/MainEventEdit.jsx old mode 100755 new mode 100644 index 6e6470263..bfe979d88 --- a/src/views/Gantt/components/EventList/components/MainEventEdit.jsx +++ b/src/views/Gantt/components/EventList/components/MainEventEdit.jsx @@ -19,7 +19,7 @@ export default defineComponent({ setup() { const imageValue = ref() const { - universalRules, + mainEventRules, showMainEvent, mainEventData, targetId, @@ -28,6 +28,8 @@ export default defineComponent({ const close = () => { showMainEvent.value = false + uploadImg.value = [] + timeRange.value = null } const changeFile = async file => { console.log(uploadImg) @@ -36,34 +38,55 @@ export default defineComponent({ const res = await uploadImage(formData) imageValue.value = res.data.path } - const sure = async () => { + const formRef = ref(null) + async function sure(e) { + e.preventDefault() const data = { ...mainEventData.value, targetId: targetId.value, fileUrl: imageValue.value, - startTime: new Date(timeRange.value[0]).toISOString(), - endTime: new Date(timeRange.value[0]).toISOString(), + startTime: mainEventData.value.timeRange + ? mainEventData.value.timeRange[0] + : null, + endTime: mainEventData.value.timeRange + ? mainEventData.value.timeRange[1] + : null, } - const res = mainEventData.value.id - ? await updateSimp(data) - : await addSimp(data) - if (res.code === 200) { - showMainEvent.value = false - searchTreeList() + // formRef.value?.validate(async erros => { + // if (!erros) { + // const res = mainEventData.value.id + // ? await updateSimp(data) + // : await addSimp(data) + // if (res.code === 200) { + // close() + // searchTreeList() + // } + // } + // }) + if (mainEventData.value.name && mainEventData.value.timeRange) { + const res = mainEventData.value.id + ? await updateSimp(data) + : await addSimp(data) + if (res.code === 200) { + close() + searchTreeList() + } + } else { + formRef.value?.validate(erros => {}) } } watch( [ - () => mainEventData.value.startTime, - () => mainEventData.value.endTime, () => mainEventData.value.fileUrl, + // () => mainEventData.value.startTime, + // () => mainEventData.value.endTime, ], - ([start, end, fileUrl]) => { - timeRange.value = start - ? [new Date(start).getTime(), new Date(end).getTime()] - : null + ([fileUrl, start, end]) => { + // timeRange.value = start + // ? [new Date(start).getTime(), new Date(end).getTime()] + // : null if (fileUrl) { uploadImg.value = [ { @@ -87,19 +110,20 @@ export default defineComponent({ title={`${mainEventData.value.id ? '编辑' : '添加'}事件`} > - + diff --git a/src/views/Gantt/components/EventList/components/SubEventEdit.jsx b/src/views/Gantt/components/EventList/components/SubEventEdit.jsx old mode 100755 new mode 100644 index 0c7fb875b..5156e314d --- a/src/views/Gantt/components/EventList/components/SubEventEdit.jsx +++ b/src/views/Gantt/components/EventList/components/SubEventEdit.jsx @@ -19,6 +19,8 @@ export default defineComponent({ // }, setup() { const { + subEventRules, + showNewEvent, eventData, sonOptions, @@ -27,6 +29,9 @@ export default defineComponent({ } = useEvent() const imageValue = ref() const close = () => { + timeRange.value = null + uploadImg.value = [] + showNewEvent.value = false } const changeFile = async file => { @@ -35,7 +40,11 @@ export default defineComponent({ const res = await uploadImage(formData) imageValue.value = res.data.path } - const sure = async () => { + + const formRef = ref(null) + async function sure(e) { + e.preventDefault() + const data = { // id: eventData.value.id ?? null, // activityId: oneClassData.value.activityId ?? null, @@ -43,32 +52,53 @@ export default defineComponent({ activityId: oneClassData.value?.pid ?? null, oneType: oneClassData.value?.id, ...eventData.value, - twoType: twoTypeId.value, + // twoType: twoTypeId.value, fileUrl: imageValue.value, - startTime: new Date(timeRange.value[0]).toISOString(), - endTime: new Date(timeRange.value[1]).toISOString(), + startTime: eventData.value.timeRange + ? eventData.value.timeRange[0] + : null, + endTime: eventData.value.timeRange + ? eventData.value.timeRange[1] + : null, } + + // eventData.value.startTime = data.startTime + // formRef.value?.validate(async erros => { + // console.log(erros, eventData, '') + + // if (!erros) { + if ( + eventData.value.name && + eventData.value.timeRange && + eventData.value.twoType + ) { + const res = eventData.value.id + ? await updateSon(data) + : await addSon(data) + if (res.code === 200) { + close() + searchTreeList() + } + } else { + formRef.value?.validate(erros => {}) + } + + // } + // }) // console.log(data, 'data') - const res = eventData.value.id - ? await updateSon(data) - : await addSon(data) - if (res.code === 200) { - showNewEvent.value = false - searchTreeList() - } } watch( [ - () => eventData.value.startTime, - () => eventData.value.endTime, () => eventData.value.fileUrl, - () => eventData.value.twoType, + // () => eventData.value.startTime, + // () => eventData.value.endTime, + // () => eventData.value.twoType, ], - ([start, end, fileUrl, twoType]) => { - timeRange.value = start - ? [new Date(start).getTime(), new Date(end).getTime()] - : null + ([fileUrl, start, end, twoType]) => { + // timeRange.value = start + // ? [new Date(start).getTime(), new Date(end).getTime()] + // : null if (fileUrl) { uploadImg.value = [ { @@ -80,15 +110,15 @@ export default defineComponent({ ] console.log(uploadImg.value) } - console.log(twoType, 'twoType') + // console.log(twoType, 'twoType') - twoType && (twoTypeId.value = twoType) + // twoType && (twoTypeId.value = twoType) } ) const timeRange = ref(null) const uploadImg = ref([]) - const twoTypeId = ref(null) + // const twoTypeId = ref(null) return () => ( - + - + diff --git a/src/views/Gantt/components/EventList/components/useEventDdConfig.jsx b/src/views/Gantt/components/EventList/components/useEventDdConfig.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/EventList/hooks.jsx b/src/views/Gantt/components/EventList/hooks.jsx old mode 100755 new mode 100644 index 53bf3d850..defb07663 --- a/src/views/Gantt/components/EventList/hooks.jsx +++ b/src/views/Gantt/components/EventList/hooks.jsx @@ -1,8 +1,26 @@ import { getSimpTreeList, getTwoClass } from '@/api/Gantt' -const universalRules = { - name: { required: true, message: '请输入', trigger: 'blur' }, - startTime: { required: true, message: '请输入', trigger: 'blur' }, +const subEventRules = { + name: { required: true, message: '请输入名称', trigger: ['blur', 'input'] }, + timeRange: { + required: true, + message: '请选择时间', + trigger: ['blur', 'input'], + }, + twoType: { + required: true, + message: '请选择二级分类', + trigger: ['blur', 'change'], + }, +} +const mainEventRules = { + name: { required: true, message: '请输入名称', trigger: ['blur', 'input'] }, + + timeRange: { + required: true, + message: '请选择时间', + trigger: ['blur', 'input'], + }, } const showMainEvent = ref(false) @@ -14,26 +32,25 @@ watch(showMainEvent, show => { const mainEventData = ref({ name: '', - startTime: '', - endTime: '', + timeRange: null, + // type: 'mainEvent', describe: '', fileUrl: '', }) function resetMainEventData() { - mainEventData.value = ref({ + mainEventData.value = { name: '', - startTime: '', - endTime: '', - // type: 'mainEvent', + timeRange: null, + describe: '', fileUrl: '', - }) + } } const targetId = ref(null) -const range = ref([new Date('2000-01-01').getTime(), Date.now()]) +const range = ref(null) const showNewEvent = ref(false) @@ -46,25 +63,25 @@ watch(showNewEvent, show => { const eventData = ref({ name: '', - startTime: '', - endTime: '', + timeRange: null, fileUrl: '', describe: '', equipModel: '', reportSite: '', + twoType: '', // type: 'subEvent', }) function resetEventData() { - eventData.value = ref({ + eventData.value = { name: '', - startTime: '', - endTime: '', + timeRange: null, fileUrl: '', describe: '', equipModel: '', reportSite: '', - }) + twoType: '', + } } const tableData = ref([]) @@ -75,8 +92,8 @@ async function searchTreeList() { const res = await getSimpTreeList({ targetId: targetId.value, - startTime: new Date(range.value[0]).toISOString(), - endTime: new Date(range.value[1]).toISOString(), + startTime: range.value ? range.value[0] : null, + endTime: range.value ? range.value[1] : null, }) tableData.value = res.data.list // console.log('searchTreeList', tableData) @@ -90,7 +107,8 @@ async function getTwoClassList(oneTypeId) { // const getSonList = async() export const useEvent = () => { return { - universalRules, + subEventRules, + mainEventRules, showMainEvent, mainEventData, showNewEvent, diff --git a/src/views/Gantt/components/EventList/index.jsx b/src/views/Gantt/components/EventList/index.jsx old mode 100755 new mode 100644 index c395300c8..bcb95289a --- a/src/views/Gantt/components/EventList/index.jsx +++ b/src/views/Gantt/components/EventList/index.jsx @@ -222,7 +222,10 @@ export default defineComponent({ function editSubEvent(row) { showNewEvent.value = true - eventData.value = cloneDeep(row) + eventData.value = cloneDeep({ + ...row, + timeRange: [row.startTime, row.endTime], + }) getTwoClassList(row.oneType) console.log('子事件编辑:', row, 'onClassData', oneClassData) } diff --git a/src/views/Gantt/components/Gantt/components/VRender.jsx b/src/views/Gantt/components/Gantt/components/VRender.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/Gantt/hooks/gantt.ts b/src/views/Gantt/components/Gantt/hooks/gantt.ts old mode 100755 new mode 100644 index b6ca6d2f1..a57f47b61 --- a/src/views/Gantt/components/Gantt/hooks/gantt.ts +++ b/src/views/Gantt/components/Gantt/hooks/gantt.ts @@ -4,7 +4,8 @@ import { Gantt, tools, TYPES } from '@visactor/vtable-gantt' import { getMainGantt, getSubGantt } from '@/api/Gantt/gantt' import { getSon } from '@/api/Gantt' import { useTree } from '@/utils/tree' -import * as dayjs from 'dayjs' +import { useInfoBox } from './infoBox.jsx' +import dayjs from 'dayjs' type GanttParams = { route?: any @@ -35,7 +36,6 @@ const useGantt = ({ router, route }: GanttParams) => { : await getMainGantt(params) if (code === 200) { // records.value = data.list - console.log(subId, ',,,,,') if (subId) { records.value = data.list .reduce((acc, cur) => { @@ -67,7 +67,7 @@ const useGantt = ({ router, route }: GanttParams) => { return acc }, []) .flat() - console.log(records.value) + // console.log(records.value) records.value.length > 0 && (timeRange.value = getTimeRangeForTree(records.value)) @@ -91,19 +91,15 @@ const useGantt = ({ router, route }: GanttParams) => { month, lastDayOfMonth.getDate() ) - endOfMonth.setHours(23, 59, 59, 9999) - // new Date().toISOString() - + endOfMonth.setHours(23, 59, 59, 0) // console.log( - // mainEvent.startTime, - // startOfMonth.toISOString(), - // endOfMonth.toISOString() + // startOfMonth.toLocaleString(), + // endOfMonth.toLocaleString() // ) - return { ...mainEvent, - start: startOfMonth.toISOString(), - end: endOfMonth.toISOString(), + start: startOfMonth, + end: endOfMonth, } }), } @@ -200,10 +196,10 @@ const useGantt = ({ router, route }: GanttParams) => { maxDate: timeRange.value[1], markLine: [ { - date: '2024-01-14T21:12:40', + date: new Date(), style: { lineWidth: 1, - lineColor: 'blue', + lineColor: 'rgb(13, 255, 255)', lineDash: [8, 4], }, }, @@ -337,6 +333,8 @@ const useGantt = ({ router, route }: GanttParams) => { return taskListTable } + const { createInfoBox, updatePosition, removeInfoBox } = useInfoBox() + function renderTaskBar(subId: string | number) { // console.log(subId, '------'); const taskBar = { @@ -353,20 +351,43 @@ const useGantt = ({ router, route }: GanttParams) => { const container = new Group({ width, height, - fill: 'transparent', - // fill: textColor, + // fill: 'transparent', + // fill: '#ff0', // fillOpacity: 0.1, // stroke: textColor, // strokeOpacity: 0.2, - // lineWidth: 4, + lineWidth: 4, display: 'flex', flexDirection: 'column', justifyContent: 'center', cursor: 'pointer', }) + container.addEventListener('mouseenter', event => { + // const { x, y } = useMouse() + createInfoBox({ + x: event.client.x, + y: event.client.y, + content: taskRecord.describe, + target: event.target, + }) + }) + + container.addEventListener('mouseleave', event => { + removeInfoBox() + }) + + container.addEventListener('mousemove', event => { + updatePosition({ + x: event.client.x, + y: event.client.y, + content: taskRecord.describe, + target: event.target, + }) + }) + container.addEventListener('click', async () => { - console.log(taskRecord, 'ooooooo') + removeInfoBox() if (!subId) { router.push({ path: `/gantt/sub/${taskRecord.id}`, @@ -434,6 +455,10 @@ const useGantt = ({ router, route }: GanttParams) => { y: 10, boundsPadding: [0, 0, 10, 0], cursor: 'pointer', + // texture: 'rect', + // textureColor: '#0006', + // html: { dom: `` }, + opacity: taskRecord.status === 2 ? 0.3 : 1, }) container.add(image) image.addEventListener('click', e => { @@ -485,6 +510,8 @@ const useGantt = ({ router, route }: GanttParams) => { fontWeight: 'bold', maxLineWidth: width, textAlign: 'center', + opacity: taskRecord.status === 2 ? 0.3 : 1, + // boundsPadding: [10, 0, 0, 0], }) nameContainer.add(name) @@ -495,6 +522,7 @@ const useGantt = ({ router, route }: GanttParams) => { fontFamily: 'sans-serif', fill: textColor, boundsPadding: [10, 0, 0, 0], + opacity: taskRecord.status === 2 ? 0.3 : 1, }) container.add(start) const end = new Text({ @@ -503,6 +531,7 @@ const useGantt = ({ router, route }: GanttParams) => { fontFamily: 'sans-serif', fill: textColor, boundsPadding: [10, 0, 0, 0], + opacity: taskRecord.status === 2 ? 0.3 : 1, }) container.add(end) const rect = new Rect({ @@ -526,6 +555,7 @@ const useGantt = ({ router, route }: GanttParams) => { ], }, boundsPadding: [10, 0, 0, 0], + opacity: taskRecord.status === 2 ? 0.3 : 1, }) container.add(rect) @@ -546,6 +576,20 @@ const useGantt = ({ router, route }: GanttParams) => { // console.log(taskBar, '0000000'); return taskBar } + + function updateMarkLine() { + ganttInstance?.updateMarkLine([ + { + date: new Date(), + style: { + lineWidth: 1, + lineColor: 'rgb(13, 255, 255)', + lineDash: [8, 4], + }, + }, + ]) + console.log(ganttInstance) + } function renderGroup(opt: IGroupGraphicAttribute) { return new Group(opt) } @@ -583,7 +627,9 @@ const useGantt = ({ router, route }: GanttParams) => { }) const day = new Text({ - text: startDate.toLocaleDateString(), + text: subId + ? dayjs(startDate).format('YYYY年M月D日') + : dayjs(startDate).format('YYYY年M月'), // scale === 'day' // ? startDate.toLocaleDateString() // : startDate.toLocaleTimeString(), @@ -600,9 +646,24 @@ const useGantt = ({ router, route }: GanttParams) => { } }, }, + // { + // unit: 'hour', + // step: 1, + // style: { + // fontSize: 10, + // fontWeight: 'normal', + // }, + // visible: false, + // }, ] } - return { renderMainTask, changeTimeScales, currentImage } + return { + getGanttData, + renderMainTask, + changeTimeScales, + currentImage, + updateMarkLine, + } } export default useGantt diff --git a/src/views/Gantt/components/Gantt/hooks/infoBox.jsx b/src/views/Gantt/components/Gantt/hooks/infoBox.jsx new file mode 100644 index 000000000..de451cb0e --- /dev/null +++ b/src/views/Gantt/components/Gantt/hooks/infoBox.jsx @@ -0,0 +1,57 @@ +// import { NCard } from 'naive-ui' + +let infoBox +export const useInfoBox = () => { + function createInfoBox({ x, y, content, target }) { + if (!content) return + if (!infoBox) { + infoBox = document.createElement('div') + + infoBox.id = 'infoBox' + infoBox.className = `absolute z-50 shadow-sm bg-[var(--color-bg)] max-w-[300px] text-sm p-2` + document.body.appendChild(infoBox) + + infoBox.innerHTML = `

${content}

` + + infoBox.offsetHeight + } + + updatePosition({ x, y }) + } + + function updatePosition({ x, y }) { + if (!infoBox) return + const pageWidth = window.innerWidth + const pageHeight = window.innerHeight + + let topPosition = y + 20 + let leftPosition = x + 20 + + let rightPosition = 0 + let bottomPosition = 0 + + if ( + pageWidth - x < infoBox.offsetWidth + 20 || + pageHeight - y < infoBox.offsetHeight + 20 + ) { + leftPosition = 0 + rightPosition = infoBox.offsetWidth + 20 + // topPosition = 0 + // bottomPosition = pageHeight - infoBox.offsetHeight + 10 + } + + infoBox.style.top = topPosition ? `${topPosition}px` : null + infoBox.style.left = leftPosition ? `${leftPosition}px` : null + infoBox.style.right = rightPosition ? `${rightPosition}px` : null + infoBox.style.bottom = bottomPosition ? `${bottomPosition}px` : null + } + + function removeInfoBox() { + if (infoBox) { + infoBox.remove() + infoBox = null + } + } + + return { createInfoBox, updatePosition, removeInfoBox } +} diff --git a/src/views/Gantt/components/Gantt/index.jsx b/src/views/Gantt/components/Gantt/index.jsx old mode 100755 new mode 100644 index af99e32c6..2986b3f09 --- a/src/views/Gantt/components/Gantt/index.jsx +++ b/src/views/Gantt/components/Gantt/index.jsx @@ -1,6 +1,8 @@ import { NImage } from 'naive-ui' import useGantt from './hooks/gantt' import { useRouter, useRoute } from 'vue-router' +import { useTimer } from '@/utils/timer.js' +import { onBeforeUnmount } from 'vue' export default defineComponent({ props: { @@ -20,26 +22,33 @@ export default defineComponent({ setup(props, { expose }) { const router = useRouter() const route = useRoute() - const { renderMainTask, changeTimeScales, currentImage } = useGantt({ + const { + getGanttData, + renderMainTask, + changeTimeScales, + currentImage, + updateMarkLine, + } = useGantt({ route, router, }) + const { Interval } = useTimer() + + let intervalTimer = null + // let markLineIntervalTimer = null + const refresh = ref(false) expose({ refresh }) watch(refresh, val => { if (val) { - renderMainTask(document.querySelector('#tableContainer'), { - ids: props.types, - startTime: props.dateRange - ? new Date(props.dateRange[0]).toISOString() - : null, - endTime: props.dateRange - ? new Date(props.dateRange[1]).toISOString() - : null, - }) + stopRefresh() + + intervalTimer = new Interval(startRefresh, 5000, { immediate: true }) + intervalTimer && intervalTimer.startInterval() + refresh.value = false } }) @@ -47,15 +56,16 @@ export default defineComponent({ onMounted(() => { nextTick(() => { // console.log(props); + renderMainTask(document.querySelector('#tableContainer'), { ids: props.types, - startTime: props.dateRange - ? new Date(props.dateRange[0]).toISOString() - : null, - endTime: props.dateRange - ? new Date(props.dateRange[1]).toISOString() - : null, + startTime: props.dateRange ? props.dateRange[0] : null, + endTime: props.dateRange ? props.dateRange[1] : null, }) + + stopRefresh() + intervalTimer = new Interval(startRefresh, 5000, { immediate: true }) + intervalTimer.startInterval() refresh.value = false }) }) @@ -74,6 +84,29 @@ export default defineComponent({ } }) }) + + async function startRefresh() { + await getGanttData({ + ids: props.types, + startTime: props.dateRange ? props.dateRange[0] : null, + endTime: props.dateRange ? props.dateRange[1] : null, + }) + + updateMarkLine() + } + + function stopRefresh() { + console.log(intervalTimer, 'stop!!!!!!!!!!!!!!!!!!!!!!!!!!!') + intervalTimer && intervalTimer.stopInterval() + intervalTimer = null + + // markLineIntervalTimer && markLineIntervalTimer.stopInterval() + // intervalTimer = null + } + + onBeforeUnmount(() => { + stopRefresh() + }) return () => ( <>
diff --git a/src/views/Gantt/components/Gantt1/components/VRender.jsx b/src/views/Gantt/components/Gantt1/components/VRender.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/Gantt1/hooks/gantt.ts b/src/views/Gantt/components/Gantt1/hooks/gantt.ts old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/Gantt1/index.jsx b/src/views/Gantt/components/Gantt1/index.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/Gantt2/components/VRender.jsx b/src/views/Gantt/components/Gantt2/components/VRender.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/Gantt2/hooks/gantt.ts b/src/views/Gantt/components/Gantt2/hooks/gantt.ts old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/Gantt2/index.jsx b/src/views/Gantt/components/Gantt2/index.jsx old mode 100755 new mode 100644 index f86361399..a35ca77e7 --- a/src/views/Gantt/components/Gantt2/index.jsx +++ b/src/views/Gantt/components/Gantt2/index.jsx @@ -15,7 +15,7 @@ export default defineComponent({ types: { type: Array, require: true, - } + }, }, setup(props, { expose }) { const router = useRouter() @@ -32,8 +32,8 @@ export default defineComponent({ // console.log(props); renderMainTask(document.querySelector('#tableContainer'), { ids: props.types, - startTime: props.dateRange ? new Date(props.dateRange[0]).toISOString() : null, - endTime: props.dateRange ? new Date(props.dateRange[1]).toISOString() : null + startTime: props.dateRange ? props.dateRange[0] : null, + endTime: props.dateRange ? props.dateRange[1] : null, }) }) }) diff --git a/src/views/Gantt/components/GanttEdit/hooks/ganttEdit.ts b/src/views/Gantt/components/GanttEdit/hooks/ganttEdit.ts old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/GanttEdit/index.jsx b/src/views/Gantt/components/GanttEdit/index.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/MainGantt/index.jsx b/src/views/Gantt/components/MainGantt/index.jsx old mode 100755 new mode 100644 index e20aacfb3..9f0e9e1d1 --- a/src/views/Gantt/components/MainGantt/index.jsx +++ b/src/views/Gantt/components/MainGantt/index.jsx @@ -12,7 +12,7 @@ import { onBeforeMount } from 'vue' export default defineComponent({ setup() { - const range = ref([new Date('2000-01-01').getTime(), Date.now()]) + const range = ref([new Date('2000-01-01 00:00:00').getTime(), Date.now()]) const value = ref('year') const types = ref([]) @@ -43,7 +43,12 @@ export default defineComponent({ return () => ( <>
- + {/* diff --git a/src/views/Gantt/components/MainGantt1/index.jsx b/src/views/Gantt/components/MainGantt1/index.jsx old mode 100755 new mode 100644 index 5c683c890..1388ce7d3 --- a/src/views/Gantt/components/MainGantt1/index.jsx +++ b/src/views/Gantt/components/MainGantt1/index.jsx @@ -24,7 +24,7 @@ export default defineComponent({
diff --git a/src/views/Gantt/components/MainGantt2/index.jsx b/src/views/Gantt/components/MainGantt2/index.jsx old mode 100755 new mode 100644 index 2e3d5ea5f..92d377b57 --- a/src/views/Gantt/components/MainGantt2/index.jsx +++ b/src/views/Gantt/components/MainGantt2/index.jsx @@ -1,4 +1,4 @@ - import { useRouter } from 'vue-router' +import { useRouter } from 'vue-router' import { NDatePicker, NRadioButton, @@ -7,12 +7,12 @@ import { NSelect, } from 'naive-ui' import GanttCom from '../Gantt' -import {getDDList}from '@/api/Gantt/gantt' +import { getDDList } from '@/api/Gantt/gantt' import { onBeforeMount } from 'vue' export default defineComponent({ setup() { - const range = ref([new Date('2000-01-01').getTime(), Date.now()]) + const range = ref([new Date('2000-01-01 00:00:00').getTime(), Date.now()]) const value = ref('year') const types = ref([]) @@ -22,40 +22,36 @@ export default defineComponent({ router.push('/gantt/mainEdit') } - onBeforeMount(async ()=>{ + onBeforeMount(async () => { await getDDOptions() }) const ddOptions = ref([]) - async function getDDOptions (){ - const {code,data} = await getDDList() - if(code === 200) { + async function getDDOptions() { + const { code, data } = await getDDList() + if (code === 200) { ddOptions.value = data.list - types.value = ddOptions.value.map(item=>item.id) + types.value = ddOptions.value.map(item => item.id) } - } - + } const ganttRef = ref(null) - function searchGanttData(){ + function searchGanttData() { // console.log(ganttRef); - renderMainTask(document.querySelector('#tableContainer'),{ + renderMainTask(document.querySelector('#tableContainer'), { ids: types.value, - startTime: new Date(range.value[0]).toISOString(), - endTime: new Date(range.value[1]).toISOString() + startTime: range.value[0], + endTime: range.value[1], }) } - - return () => ( <>
{/* @@ -65,9 +61,9 @@ export default defineComponent({ v-model:value={types.value} multiple options={ddOptions.value} - label-field='name' + label-field="name" clearable - value-field='id' + value-field="id" > {/* 编辑事件 @@ -76,7 +72,12 @@ export default defineComponent({ 搜索
- + ) }, diff --git a/src/views/Gantt/components/MainGanttEdit/index.jsx b/src/views/Gantt/components/MainGanttEdit/index.jsx old mode 100755 new mode 100644 index 22bc882fb..b87aacb50 --- a/src/views/Gantt/components/MainGanttEdit/index.jsx +++ b/src/views/Gantt/components/MainGanttEdit/index.jsx @@ -21,7 +21,11 @@ export default defineComponent({ return () => ( <>
- + diff --git a/src/views/Gantt/components/SubGantt/index.jsx b/src/views/Gantt/components/SubGantt/index.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/SubGanttEdit/index.jsx b/src/views/Gantt/components/SubGanttEdit/index.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/TaskList/components/NewTask/hooks.ts b/src/views/Gantt/components/TaskList/components/NewTask/hooks.ts old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/TaskList/components/NewTask/index.jsx b/src/views/Gantt/components/TaskList/components/NewTask/index.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/components/TaskList/index.jsx b/src/views/Gantt/components/TaskList/index.jsx old mode 100755 new mode 100644 diff --git a/src/views/Gantt/index copy.vue b/src/views/Gantt/index copy.vue old mode 100755 new mode 100644 index e1deeaf9a..5cf29606d --- a/src/views/Gantt/index copy.vue +++ b/src/views/Gantt/index copy.vue @@ -519,7 +519,7 @@ onMounted(() => {
- + diff --git a/src/views/Gantt/index.jsx b/src/views/Gantt/index.jsx old mode 100755 new mode 100644 index 8a59ad0d0..2d6fcabf5 --- a/src/views/Gantt/index.jsx +++ b/src/views/Gantt/index.jsx @@ -141,7 +141,7 @@ export default defineComponent({ > diff --git a/src/views/Gantt/index.vue b/src/views/Gantt/index.vue old mode 100755 new mode 100644 diff --git a/src/views/Gantt0305/components/EventList/components/EventDdConfig.jsx b/src/views/Gantt0305/components/EventList/components/EventDdConfig.jsx new file mode 100755 index 000000000..76698f59b --- /dev/null +++ b/src/views/Gantt0305/components/EventList/components/EventDdConfig.jsx @@ -0,0 +1,94 @@ +import { NTabs, NTabPane, NButton, NScrollbar } from 'naive-ui' +import TrajTable from '@/views/Daodan/components/TrajTable' + +import TrajUpload from '@/views/Daodan/components/TrajUpload' + +import { useEventDdConfig } from './useEventDdConfig' + +const panels = ['手动配置', 'STK轨迹文件配置'] +export default defineComponent({ + name: 'EventDaodan', + props: { + data: { + type: Object, + default: () => ({}), + }, + }, + setup() { + const name = ref('手动配置') + + const { trajData, interceptData, addIntercept } = useEventDdConfig() + + // const { trajData, interceptData, updateInterceptData } = useEvent() + const removeIntercept = id => { + interceptData.value.splice( + interceptData.value.findIndex(item => item.id === id), + 1 + ) + } + const showOrHideDdConfig = () => {} + return () => ( +
+ + {panels.map(panel => ( + + +
+
+ {panel === '手动配置' ? ( + <> +
+ +
+
+ {interceptData.value.map(data => ( + + ))} +
+ + 添加拦截 + +
+
+ + ) : ( + <> + + + + )} +
+
+
+
+ ))} +
+
+ + 确认 + + showOrHideDdConfig({})}>取消 +
+
+ ) + }, +}) diff --git a/src/views/Gantt0305/components/EventList/components/MainEventEdit.jsx b/src/views/Gantt0305/components/EventList/components/MainEventEdit.jsx new file mode 100755 index 000000000..6e6470263 --- /dev/null +++ b/src/views/Gantt0305/components/EventList/components/MainEventEdit.jsx @@ -0,0 +1,130 @@ +import { + NForm, + NFormItem, + NInput, + NButton, + NDatePicker, + NUpload, +} from 'naive-ui' +import ModalCom from '@/components/Modal/index.vue' +import { useEvent } from '../hooks' +import { addSimp, updateSimp, uploadImage } from '@/api/Gantt' +export default defineComponent({ + // props: { + // show: { + // type: Boolean, + // default: false, + // }, + // }, + setup() { + const imageValue = ref() + const { + universalRules, + showMainEvent, + mainEventData, + targetId, + searchTreeList, + } = useEvent() + + const close = () => { + showMainEvent.value = false + } + const changeFile = async file => { + console.log(uploadImg) + const formData = new FormData() + formData.append('file', file.file.file) + const res = await uploadImage(formData) + imageValue.value = res.data.path + } + const sure = async () => { + const data = { + ...mainEventData.value, + targetId: targetId.value, + fileUrl: imageValue.value, + startTime: new Date(timeRange.value[0]).toISOString(), + endTime: new Date(timeRange.value[0]).toISOString(), + } + + const res = mainEventData.value.id + ? await updateSimp(data) + : await addSimp(data) + if (res.code === 200) { + showMainEvent.value = false + searchTreeList() + } + } + + watch( + [ + () => mainEventData.value.startTime, + () => mainEventData.value.endTime, + () => mainEventData.value.fileUrl, + ], + ([start, end, fileUrl]) => { + timeRange.value = start + ? [new Date(start).getTime(), new Date(end).getTime()] + : null + if (fileUrl) { + uploadImg.value = [ + { + id: '1', + name: fileUrl, + url: `${window.settings.imgServer}${fileUrl}`, + status: 'finished', + }, + ] + } + } + ) + + const timeRange = ref(null) + const uploadImg = ref([]) + // const desc = ref () + + return () => ( + + + + + + + + + + + + + + + +
+ 取消 + + 确认 + +
+
+ ) + }, +}) diff --git a/src/views/Gantt0305/components/EventList/components/SubEventEdit.jsx b/src/views/Gantt0305/components/EventList/components/SubEventEdit.jsx new file mode 100755 index 000000000..0c7fb875b --- /dev/null +++ b/src/views/Gantt0305/components/EventList/components/SubEventEdit.jsx @@ -0,0 +1,155 @@ +import { + NForm, + NFormItem, + NInput, + NButton, + NDatePicker, + NUpload, + NSelect, +} from 'naive-ui' +import ModalCom from '@/components/Modal/index.vue' +import { useEvent } from '../hooks' +import { addSon, updateSon, uploadImage } from '@/api/gantt' +export default defineComponent({ + // props: { + // show: { + // type: Boolean, + // default: false, + // }, + // }, + setup() { + const { + showNewEvent, + eventData, + sonOptions, + oneClassData, + searchTreeList, + } = useEvent() + const imageValue = ref() + const close = () => { + showNewEvent.value = false + } + const changeFile = async file => { + const formData = new FormData() + formData.append('file', file.file.file) + const res = await uploadImage(formData) + imageValue.value = res.data.path + } + const sure = async () => { + const data = { + // id: eventData.value.id ?? null, + // activityId: oneClassData.value.activityId ?? null, + // name: eventData.value.name, + activityId: oneClassData.value?.pid ?? null, + oneType: oneClassData.value?.id, + ...eventData.value, + twoType: twoTypeId.value, + fileUrl: imageValue.value, + startTime: new Date(timeRange.value[0]).toISOString(), + endTime: new Date(timeRange.value[1]).toISOString(), + } + // console.log(data, 'data') + const res = eventData.value.id + ? await updateSon(data) + : await addSon(data) + if (res.code === 200) { + showNewEvent.value = false + searchTreeList() + } + } + + watch( + [ + () => eventData.value.startTime, + () => eventData.value.endTime, + () => eventData.value.fileUrl, + () => eventData.value.twoType, + ], + ([start, end, fileUrl, twoType]) => { + timeRange.value = start + ? [new Date(start).getTime(), new Date(end).getTime()] + : null + if (fileUrl) { + uploadImg.value = [ + { + id: fileUrl, + name: fileUrl, + url: `${window.settings.imgServer}${fileUrl}`, + status: 'finished', + }, + ] + console.log(uploadImg.value) + } + console.log(twoType, 'twoType') + + twoType && (twoTypeId.value = twoType) + } + ) + + const timeRange = ref(null) + const uploadImg = ref([]) + const twoTypeId = ref(null) + + return () => ( + + + + + + {/* + + + + + */} + + + + + + + + + + + + + + + + + + + +
+ 取消 + + 确认 + +
+
+ ) + }, +}) diff --git a/src/views/Gantt0305/components/EventList/components/useEventDdConfig.jsx b/src/views/Gantt0305/components/EventList/components/useEventDdConfig.jsx new file mode 100755 index 000000000..6acc3786e --- /dev/null +++ b/src/views/Gantt0305/components/EventList/components/useEventDdConfig.jsx @@ -0,0 +1,103 @@ +export const useEventDdConfig = () => { + const trajData = ref({ + id: 'dd', + data: [ + { + name: '起始点', + lon: 120, + lat: 21, + alt: 0, + time: 1183135260000, + }, + { + name: '中间特征点', + lon: 122, + lat: 21, + alt: 1000000, + time: 1183135265000, + detached: true, + }, + { + name: '中间特征点', + lon: 124, + lat: 21, + alt: 1500000, + time: 1183135270000, + detached: true, + }, + { + name: '中间特征点', + lon: 128, + lat: 21, + alt: 2000000, + time: 1183135280000, + detached: true, + }, + { + name: '落点', + lon: 135, + lat: 21, + alt: 1500000, + time: 1183135290000, + }, + ], + }) + const interceptData = ref([ + { + id: 'dd1', + data: [ + { + name: '起始点', + lon: 137, + lat: 25, + alt: 0, + time: 1183135270000, + }, + { + name: '中间特征点', + lon: 138, + lat: 24, + alt: 1000000, + time: 1183135280000, + detached: true, + }, + { + name: '落点', + lon: 135, + lat: 21, + alt: 1500000, + time: 1183135290000, + }, + ], + }, + ]) + + function addIntercept() { + // 添加拦截d + interceptData.value.push({ + data: [ + { + name: '起始点', + lon: 120, + lat: 21, + alt: 0, + time: 1183135260000, + }, + { + name: '中间特征点', + lon: 120, + lat: 21, + alt: 0, + time: 1183135260000, + detached: false, + }, + trajData.value.data.at(-1), + ], + }) + } + return { + trajData, + interceptData, + addIntercept, + } +} diff --git a/src/views/Gantt0305/components/EventList/hooks.jsx b/src/views/Gantt0305/components/EventList/hooks.jsx new file mode 100755 index 000000000..53bf3d850 --- /dev/null +++ b/src/views/Gantt0305/components/EventList/hooks.jsx @@ -0,0 +1,106 @@ +import { getSimpTreeList, getTwoClass } from '@/api/Gantt' + +const universalRules = { + name: { required: true, message: '请输入', trigger: 'blur' }, + startTime: { required: true, message: '请输入', trigger: 'blur' }, +} +const showMainEvent = ref(false) + +watch(showMainEvent, show => { + if (!show) { + resetMainEventData() + } +}) + +const mainEventData = ref({ + name: '', + startTime: '', + endTime: '', + // type: 'mainEvent', + describe: '', + fileUrl: '', +}) + +function resetMainEventData() { + mainEventData.value = ref({ + name: '', + startTime: '', + endTime: '', + // type: 'mainEvent', + describe: '', + fileUrl: '', + }) +} + +const targetId = ref(null) +const range = ref([new Date('2000-01-01').getTime(), Date.now()]) + +const showNewEvent = ref(false) + +watch(showNewEvent, show => { + if (!show) { + oneClassData.value = null + resetEventData() + } +}) + +const eventData = ref({ + name: '', + startTime: '', + endTime: '', + fileUrl: '', + describe: '', + equipModel: '', + reportSite: '', + // type: 'subEvent', +}) + +function resetEventData() { + eventData.value = ref({ + name: '', + startTime: '', + endTime: '', + fileUrl: '', + describe: '', + equipModel: '', + reportSite: '', + }) +} + +const tableData = ref([]) + +const oneClassData = ref(null) +async function searchTreeList() { + tableData.value = [] + + const res = await getSimpTreeList({ + targetId: targetId.value, + startTime: new Date(range.value[0]).toISOString(), + endTime: new Date(range.value[1]).toISOString(), + }) + tableData.value = res.data.list + // console.log('searchTreeList', tableData) +} + +const sonOptions = ref([]) +async function getTwoClassList(oneTypeId) { + const res = await getTwoClass({ oneType: oneTypeId }) + sonOptions.value = res.data.list +} +// const getSonList = async() +export const useEvent = () => { + return { + universalRules, + showMainEvent, + mainEventData, + showNewEvent, + eventData, + targetId, + searchTreeList, + tableData, + range, + oneClassData, + sonOptions, + getTwoClassList, + } +} diff --git a/src/views/Gantt0305/components/EventList/index.jsx b/src/views/Gantt0305/components/EventList/index.jsx new file mode 100755 index 000000000..c395300c8 --- /dev/null +++ b/src/views/Gantt0305/components/EventList/index.jsx @@ -0,0 +1,296 @@ +import { NDataTable, NIcon, NButton, useDialog, NTag } from 'naive-ui' +import { + getEventListByDDType, + deleteSimp, + getTwoClass, + deleteSon, +} from '@/api/gantt' +import { useTree } from '@/utils/tree' +import { + HelpCircleOutline, + CreateOutline, + TrashBinOutline, + AddCircleOutline, + EnterOutline, +} from '@vicons/ionicons5' + +import { cloneDeep } from 'es-toolkit' + +import MainEventEdit from './components/MainEventEdit' +import SubEventEdit from './components/SubEventEdit' + +import EventDdConfig from './components/EventDdConfig' + +import { useEvent } from './hooks' + +export default defineComponent({ + props: { + dd: { + type: Number, + require: true, + }, + tableData: { + type: Array, + require: true, + }, + }, + setup(props) { + const { + showMainEvent, + mainEventData, + showNewEvent, + eventData, + searchTreeList, + oneClassData, + // sonOptions, + getTwoClassList, + } = useEvent() + const dict = window.settings.gantt + const columns = [ + { + title: '事件名称', + key: 'name', + // width: 'auto', + render: row => { + return ( +
+ {/* + + */} + + {dict[row.level].label} + + {row.name} +
+ ) + }, + }, + { + title: '开始时间', + key: 'startTime', + width: '300', + }, + { + title: '结束时间', + key: 'endTime', + width: '300', + }, + // { + // title: '类型', + // key: 'type', + // render(row) { + // return ( + // + // {dict[row.type].label} + // + // ) + // }, + // }, + { + title: '图片', + key: 'filePath', + width: '200', + render(row) { + if (row.fileUrl) { + return ( + + ) + } else { + return - + } + }, + }, + { + title: '操作', + key: 'action', + width: '240', + render(row, rowIndex) { + // console.log(row, rowIndex) + return ( +
+ {row.level === 1 && ( + editMainEvent(row)} + > + + + + 编辑事件 + + )} + {row.level === 2 ? ( + addSubEvent(row)} + > + + + + 添加子事件 + + ) : null} + {row.level === 4 && ( + editSubEvent(row)} + > + + + + 编辑子事件 + + )} + {Reflect.has(row, 'trajData') && ( + ddConfig(row)} + > + + + + 编辑DD轨迹 + + )} + {/* {row.level == 4 && ( + editSubEvent(row)} + > + + + + 编辑子事件 + + )} */} + {![2, 3].includes(row.level) ? ( + deleteEvent(row)} + > + + + + + ) : ( + <> + )} +
+ ) + }, + }, + ] + + function editMainEvent(row) { + showMainEvent.value = true + mainEventData.value = cloneDeep(row) + } + + const addSubEvent = async row => { + console.log(row, 'row') + oneClassData.value = row + showNewEvent.value = true + // eventData.value = {} + await getTwoClassList(row.id) + } + + function editSubEvent(row) { + showNewEvent.value = true + eventData.value = cloneDeep(row) + getTwoClassList(row.oneType) + console.log('子事件编辑:', row, 'onClassData', oneClassData) + } + + const dialog = useDialog() + function deleteEvent(row) { + console.log(row, 'row') + dialog.warning({ + title: '删除事件', + content: `确定删除事件 ${row.name} 吗?`, + positiveText: '确定', + negativeText: '取消', + onPositiveClick: async () => { + //await deleteEventById(row.id) + if (row.level == 1) { + await deleteSimp({ id: row.id }) + } else if (row.level == 4) { + await deleteSon({ id: row.id }) + } + searchTreeList() + }, + }) + } + + function ddConfig(row) { + console.log(row) + dialog.create({ + style: 'width:auto;height:90vh', + maskClosable: false, + class: 'flex flex-col', + title: 'DD轨迹', + contentClass: 'flex-1 h-0', + content: () => , + // positiveText: '确定', + // negativeText: '取消', + // onPositiveClick: () => {}, + }) + } + + const { getAllKeys } = useTree() + const expandedRowKeys = ref([]) + + watch( + () => props.tableData, + () => { + expandedRowKeys.value = getAllKeys(props.tableData, 'name') || [] + }, + { + immediate: true, + } + ) + + return () => ( + <> + row.name} + /> + + + + + ) + }, +}) diff --git a/src/views/Gantt0305/components/Gantt/components/VRender.jsx b/src/views/Gantt0305/components/Gantt/components/VRender.jsx new file mode 100755 index 000000000..4f0174da4 --- /dev/null +++ b/src/views/Gantt0305/components/Gantt/components/VRender.jsx @@ -0,0 +1,47 @@ +import { VImage, VGroup, VRect, VText } from '@visactor/vtable/es/vrender' + +const textColor = '#65c5e7' +export default defineComponent({ + props: { + width: { + type: Number, + default: 0, + }, + height: { + type: Number, + default: 0, + }, + taskRecord: { + type: Object, + default: () => ({}), + }, + }, + setup(props) { + const { width, height, taskRecord } = props + return () => ( + + + + ) + }, +}) diff --git a/src/views/Gantt0305/components/Gantt/hooks/gantt.ts b/src/views/Gantt0305/components/Gantt/hooks/gantt.ts new file mode 100755 index 000000000..b6ca6d2f1 --- /dev/null +++ b/src/views/Gantt0305/components/Gantt/hooks/gantt.ts @@ -0,0 +1,608 @@ +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' +import { getSon } from '@/api/Gantt' +import { useTree } from '@/utils/tree' +import * as dayjs from 'dayjs' + +type GanttParams = { + route?: any + router?: any +} +let ganttInstance: null | Gantt = null +const bgColor = '#1c202c' +const headerBgColor = '#33566f22' +const textColor = '#65c5e7' +const textColorWithOp = '#75fbfd22' + +const { getTimeRangeForTree } = useTree() + +const useGantt = ({ router, route }: GanttParams) => { + const currentImage = ref() + const { subId } = route.params + const records = ref([]) + + const timeRange = ref([]) + // onMounted(() => { + // getGanttData() + // }) + async function getGanttData(params: Record) { + timeRange.value = [params.startTime, params.endTime] + console.log('%csubId', 'color:red;font-size:20px', subId) + const { code, data } = subId + ? await getSubGantt({ activityId: subId }) + : await getMainGantt(params) + if (code === 200) { + // records.value = data.list + console.log(subId, ',,,,,') + if (subId) { + records.value = data.list + .reduce((acc, cur) => { + if (Array.isArray(cur.children) && cur.children.length > 0) { + acc.push( + cur.children.map(twoType => { + return { + ...twoType, + children: + twoType.children && + twoType.children.map(eventItem => { + console.log( + eventItem.startTime, + eventItem.endTime + // new Date(eventItem.startTime).getMonth() + ) + return { + ...eventItem, + start: eventItem.startTime, + end: eventItem.endTime, + } + }), + parentName: cur.name, + childrenLengthForParent: cur.children.length, + } + }) + ) + } + return acc + }, []) + .flat() + console.log(records.value) + + records.value.length > 0 && + (timeRange.value = getTimeRangeForTree(records.value)) + } else { + // console.log(data.list, '------') + records.value = data.list.map(item => { + return { + ...item, + children: + item.children && + item.children.map(mainEvent => { + const date = new Date(mainEvent.startTime) + const year = date.getFullYear() + const month = date.getMonth() + const startOfMonth = new Date(year, month, 1) + startOfMonth.setHours(0, 0, 0, 0) + + const lastDayOfMonth = new Date(year, month + 1, 0) + const endOfMonth = new Date( + year, + month, + lastDayOfMonth.getDate() + ) + endOfMonth.setHours(23, 59, 59, 9999) + // new Date().toISOString() + + // console.log( + // mainEvent.startTime, + // startOfMonth.toISOString(), + // endOfMonth.toISOString() + // ) + + return { + ...mainEvent, + start: startOfMonth.toISOString(), + end: endOfMonth.toISOString(), + } + }), + } + }) + } + records.value.length > 0 && ganttInstance?.setRecords(records.value) + } + } + async function renderMainTask( + dom: HTMLElement, + params: Record + ) { + // console.log(subId, 'renderMainTask') + await getGanttData(params) + const option = getOption() + + // if (ganttInstance) { + // ganttInstance.setRecords(records.value) + // } else { + if (records.value.length === 0) return + ganttInstance && ganttInstance?.release() + ganttInstance = new Gantt(dom, option) + window['ganttInstance'] = ganttInstance + // } + } + function getOption(): TYPES.GanttConstructorOptions { + // console.log(records.value); + const option = { + records: records.value, + taskListTable: renderTaskListTable(), + tasksShowMode: TYPES.TasksShowMode.Sub_Tasks_Arrange, + // groupBy: 'name', + // groupField: 'name', + // widthMode: 'standard', + // groupTitleFieldFormat: (record, col, row, table) => { + // console.log(record, col, row, table, '----') + // const groupData = table.getGroupData(record); // 获取分组数据 + // const count = groupData ? groupData.length : 0; // 计算分组下的记录数量 + // return `${record.name} (${count})`; // 返回格式化的分组标题 + // }, + 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(subId), + timelineHeader: { + backgroundColor: headerBgColor, + colWidth: 150, + // colWidth: 1040, + // verticalLine: { + // lineColor: textColorWithOp, + // lineWidth: 1, + // lineDash: [4, 2], + // }, + horizontalLine: { + lineColor: textColorWithOp, + lineWidth: 1, + lineDash: [4, 2], + }, + scales: getTimeScales(subId ? 'day' : 'month'), + }, + minDate: timeRange.value[0], + maxDate: timeRange.value[1], + markLine: [ + { + date: '2024-01-14T21:12:40', + style: { + lineWidth: 1, + lineColor: 'blue', + lineDash: [8, 4], + }, + }, + // { + // date: '2024-08-17', + // style: { + // lineWidth: 2, + // lineColor: 'red', + // lineDash: [8, 4], + // }, + // }, + ], + scrollStyle: { + scrollRailColor: 'RGBA(246,246,246,0)', + visible: 'focus', + width: 10, + 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, + customLayout: args => { + // console.log(args, 'srgs') + const { table, row, col, rect, dataValue } = args + const { height, width } = rect ?? table.getCellRect(col, row) + const container = new Group({ + width, + height, + fill: 'transparent', + // fill: textColor, + // fillOpacity: 0.1, + // stroke: textColor, + // strokeOpacity: 0.2, + // lineWidth: 4, + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + cursor: 'pointer', + boundsPadding: [10, 0, 0, 0], + }) + + // console.log('args:-----', args); + + const count = + table.records.find(r => dataValue === r.name)?.children?.length || 0 + const values = new Text({ + text: `${dataValue}`, + fontSize: 16, + fontFamily: 'sans-serif', + fill: textColor, + textAlign: 'center', + maxLineWidth: width, + whiteSpace: 'normal', + // boundsPadding: [10, 10, 10, 10], + }) + const counts = new Text({ + text: `( ${count} )`, + fontSize: 13, + fontFamily: 'sans-serif', + fill: textColor, + boundsPadding: [10, 0, 0, 0], + }) + container.add(values) + container.add(counts) + return { + rootContainer: container, + } + }, + }, + ] + if (subId) { + columns.unshift({ + field: 'parentName', + title: '事件分类', + width: '120', + mergeCell: true, + }) + 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(subId: string | number) { + // console.log(subId, '------'); + const taskBar = { + resizable: false, + moveable: false, + startDateField: 'start', + endDateField: 'end', + // progressField: 'progress', + barStyle: { width: subId ? 200 : 80 }, + customLayout: args => { + // console.log(args, 'args'); + const { width, height, startDate, endDate, taskRecord } = args + // console.log(taskRecord, 'taskRecord'); + const container = new Group({ + width, + height, + fill: 'transparent', + // fill: textColor, + // fillOpacity: 0.1, + // stroke: textColor, + // strokeOpacity: 0.2, + // lineWidth: 4, + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + cursor: 'pointer', + }) + + container.addEventListener('click', async () => { + console.log(taskRecord, 'ooooooo') + if (!subId) { + router.push({ + path: `/gantt/sub/${taskRecord.id}`, + }) + } else { + const { code, data } = await getSon({ id: taskRecord.id }) + + if (code === 200) { + const showData = { + 事件名称: data.name, + 事件时间: `${data.startTime} - ${data.endTime}`, + 装备型号: data.equipModel, + 上报站点: data.reportSite, + 事件描述: data.describe, + } + window.$dialog.info({ + title: '子事件详情', + class: '!w-[40vw]', + content: () => { + return h( + 'div', + { class: 'flex flex-col gap-4 w-full h-full' }, + [ + ...Object.keys(showData).map(key => { + return h('div', { class: 'flex w-full h-full ' }, [ + h('div', { class: 'w-[120px]' }, key), + h( + 'div', + { class: 'flex-1 text-wrap' }, + showData[key] + ), + ]) + }), + h('div', { class: 'flex w-full h-full' }, [ + h('div', { class: 'w-[120px]' }, '图片'), + h('img', { + src: `${window.settings.imgServer}${data.fileUrl}`, + }), + ]), + ] + ) + }, + positiveText: '确定', + }) + } + } + }) + // if (!subId) { + // container.addEventListener('click', () => { + // console.log(taskRecord, 'ooooooo') + // router.push({ + // path: `/gantt/sub/${taskRecord.id}`, + // }) + // }) + // } + + if (subId) { + const imgUrl = `${window.settings.imgServer}${taskRecord.fileUrl}` + // console.log(imgUrl); + const image = new Image({ + image: imgUrl, + width: 100, + height: 100, + x: 10, + y: 10, + boundsPadding: [0, 0, 10, 0], + cursor: 'pointer', + }) + container.add(image) + image.addEventListener('click', e => { + e.stopPropagation() + + currentImage.value = [imgUrl, Date.now()] + // console.log(currentImage, 'currentImage') + }) + } + // const checkbox = new CheckBox({ + // width: 20, + // height: 20, + // checked: false, + // }) + // container.add(checkbox) + + // checkbox.addEventListener('click', event => { + // console.log(event, 'event') + // }) + // console.log(taskRecord, 'taskRecord') + const nameContainer = new Group({ + fill: 'transparent', + display: 'flex', + // flexDirection: 'column', + // justifyContent: 'center', + alignItems: 'center', + }) + + container.add(nameContainer) + + if ('trajData' in taskRecord && taskRecord.trajData) { + const taskRecordSymbol = new Image({ + width: 20, + height: 20, + fill: '#ff0', + image: + '', + boundsPadding: [-3, 10, 0, 0], + cursor: 'pointer', + }) + nameContainer.add(taskRecordSymbol) + } + + const name = new Text({ + text: taskRecord.name, + fontSize: 16, + fontFamily: 'sans-serif', + fill: textColor, + fontWeight: 'bold', + maxLineWidth: width, + textAlign: 'center', + // boundsPadding: [10, 0, 0, 0], + }) + nameContainer.add(name) + + const start = new Text({ + text: `${taskRecord.startTime}`, + fontSize: 13, + fontFamily: 'sans-serif', + fill: textColor, + boundsPadding: [10, 0, 0, 0], + }) + container.add(start) + const end = new Text({ + text: `${taskRecord.endTime}`, + fontSize: 13, + fontFamily: 'sans-serif', + fill: textColor, + boundsPadding: [10, 0, 0, 0], + }) + container.add(end) + 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, + }, + } + // console.log(taskBar, '0000000'); + 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: startDate.toLocaleDateString(), + // scale === 'day' + // ? startDate.toLocaleDateString() + // : startDate.toLocaleTimeString(), + fontSize: 14, + fontWeight: 'bold', + fontFamily: 'sans-serif', + fill: textColor, + textAlign: 'right', + maxLineWidth: width, + }) + container.add(day) + return { + rootContainer: container, + } + }, + }, + ] + } + return { renderMainTask, changeTimeScales, currentImage } +} + +export default useGantt diff --git a/src/views/Gantt0305/components/Gantt/index.jsx b/src/views/Gantt0305/components/Gantt/index.jsx new file mode 100755 index 000000000..af99e32c6 --- /dev/null +++ b/src/views/Gantt0305/components/Gantt/index.jsx @@ -0,0 +1,88 @@ +import { NImage } from 'naive-ui' +import useGantt from './hooks/gantt' +import { useRouter, useRoute } from 'vue-router' + +export default defineComponent({ + props: { + scale: { + type: String, + default: 'day', + }, + dateRange: { + type: Array, + require: true, + }, + types: { + type: Array, + require: true, + }, + }, + setup(props, { expose }) { + const router = useRouter() + const route = useRoute() + const { renderMainTask, changeTimeScales, currentImage } = useGantt({ + route, + router, + }) + + const refresh = ref(false) + + expose({ refresh }) + + watch(refresh, val => { + if (val) { + renderMainTask(document.querySelector('#tableContainer'), { + ids: props.types, + startTime: props.dateRange + ? new Date(props.dateRange[0]).toISOString() + : null, + endTime: props.dateRange + ? new Date(props.dateRange[1]).toISOString() + : null, + }) + refresh.value = false + } + }) + + onMounted(() => { + nextTick(() => { + // console.log(props); + renderMainTask(document.querySelector('#tableContainer'), { + ids: props.types, + startTime: props.dateRange + ? new Date(props.dateRange[0]).toISOString() + : null, + endTime: props.dateRange + ? new Date(props.dateRange[1]).toISOString() + : null, + }) + refresh.value = false + }) + }) + watch( + () => props.scale, + val => { + changeTimeScales(val) + } + ) + + const imgRef = ref(null) + watch(currentImage, imgUrl => { + nextTick(() => { + if (imgUrl) { + imgRef.value.click() + } + }) + }) + return () => ( + <> +
+ + + ) + }, +}) diff --git a/src/views/Gantt0305/components/Gantt1/components/VRender.jsx b/src/views/Gantt0305/components/Gantt1/components/VRender.jsx new file mode 100755 index 000000000..4f0174da4 --- /dev/null +++ b/src/views/Gantt0305/components/Gantt1/components/VRender.jsx @@ -0,0 +1,47 @@ +import { VImage, VGroup, VRect, VText } from '@visactor/vtable/es/vrender' + +const textColor = '#65c5e7' +export default defineComponent({ + props: { + width: { + type: Number, + default: 0, + }, + height: { + type: Number, + default: 0, + }, + taskRecord: { + type: Object, + default: () => ({}), + }, + }, + setup(props) { + const { width, height, taskRecord } = props + return () => ( + + + + ) + }, +}) diff --git a/src/views/Gantt0305/components/Gantt1/hooks/gantt.ts b/src/views/Gantt0305/components/Gantt1/hooks/gantt.ts new file mode 100755 index 000000000..d6552fe88 --- /dev/null +++ b/src/views/Gantt0305/components/Gantt1/hooks/gantt.ts @@ -0,0 +1,452 @@ +import { Group, Image, Text, CheckBox, Rect } from '@visactor/vtable/es/vrender' + +import { Gantt, tools, TYPES } from '@visactor/vtable-gantt' +import { getMainGantt, getSubGantt } from '@/api/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 useGantt = ({ router, route }: GanttParams) => { + const currentImage = ref() + const { subId } = route.params + const records = ref([]) + 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, + // groupBy: 'name', + // groupField: 'name', + // widthMode: 'standard', + // groupTitleFieldFormat: (record, col, row, table) => { + // console.log(record, col, row, table, '----') + // const groupData = table.getGroupData(record); // 获取分组数据 + // const count = groupData ? groupData.length : 0; // 计算分组下的记录数量 + // return `${record.name} (${count})`; // 返回格式化的分组标题 + // }, + 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(subId), + timelineHeader: { + backgroundColor: headerBgColor, + colWidth: 140, + // colWidth: 1040, + // 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', + markLine: [ + { + date: '2024-07-29', + style: { + lineWidth: 1, + lineColor: 'blue', + lineDash: [8, 4], + }, + }, + // { + // date: '2024-08-17', + // style: { + // lineWidth: 2, + // lineColor: 'red', + // lineDash: [8, 4], + // }, + // }, + ], + 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, + customLayout: args => { + const { table, row, col, rect, dataValue } = args + // console.log( + // table, + // '1', + // row, + // '2', + // col, + // '3', + // rect, + // '4', + // dataValue, + // '5', + // '-----------' + // ) + const { height, width } = rect ?? table.getCellRect(col, row) + const container = new Group({ + width, + height, + fill: 'transparent', + // fill: textColor, + // fillOpacity: 0.1, + // stroke: textColor, + // strokeOpacity: 0.2, + // lineWidth: 4, + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + cursor: 'pointer', + }) + console.log(args) + const count = table.records.find(r => dataValue === r.name)?.children + ?.length + const values = new Text({ + text: `${dataValue}`, + fontSize: 16, + fontFamily: 'sans-serif', + fill: textColor, + textAlign: 'center', + // boundsPadding: [10, 0, 0, 0], + }) + const counts = new Text({ + text: `( ${count} )`, + fontSize: 13, + fontFamily: 'sans-serif', + fill: textColor, + boundsPadding: [10, 0, 0, 0], + }) + container.add(values) + container.add(counts) + return { + rootContainer: container, + } + }, + }, + ] + 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', + // fill: textColor, + // fillOpacity: 0.1, + // stroke: textColor, + // strokeOpacity: 0.2, + // lineWidth: 4, + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + cursor: 'pointer', + }) + if (!subId) { + container.addEventListener('click', () => { + console.log(taskRecord, 'ooooooo') + router.push({ + path: `/gantt/sub/${taskRecord.id}`, + }) + }) + } + + if (subId) { + const image = new Image({ + image: taskRecord.avatar, + width: 100, + height: 100, + x: 10, + y: 10, + boundsPadding: [0, 0, 10, 0], + cursor: 'pointer', + }) + container.add(image) + image.addEventListener('click', () => { + currentImage.value = [taskRecord.avatar, Date.now()] + // console.log(currentImage, 'currentImage') + }) + } + // const checkbox = new CheckBox({ + // width: 20, + // height: 20, + // checked: false, + // }) + // container.add(checkbox) + + // checkbox.addEventListener('click', event => { + // console.log(event, 'event') + // }) + // console.log(taskRecord, 'taskRecord') + const nameContainer = new Group({ + fill: 'transparent', + display: 'flex', + // flexDirection: 'column', + // justifyContent: 'center', + alignItems: 'center', + }) + + container.add(nameContainer) + + if ('trajData' in taskRecord && taskRecord.trajData) { + const taskRecordSymbol = new Image({ + width: 20, + height: 20, + fill: '#ff0', + image: + '', + boundsPadding: [-3, 10, 0, 0], + cursor: 'pointer', + }) + nameContainer.add(taskRecordSymbol) + } + + const name = new Text({ + text: taskRecord.name, + fontSize: 16, + fontFamily: 'sans-serif', + fill: textColor, + fontWeight: 'bold', + maxLineWidth: width, + textAlign: 'center', + // boundsPadding: [10, 0, 0, 0], + }) + nameContainer.add(name) + + 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: startDate.toLocaleDateString(), + // scale === 'day' + // ? startDate.toLocaleDateString() + // : startDate.toLocaleTimeString(), + fontSize: 14, + fontWeight: 'bold', + fontFamily: 'sans-serif', + fill: textColor, + textAlign: 'right', + maxLineWidth: width, + }) + container.add(day) + return { + rootContainer: container, + } + }, + }, + ] + } + return { renderMainTask, changeTimeScales, currentImage } +} + +export default useGantt diff --git a/src/views/Gantt0305/components/Gantt1/index.jsx b/src/views/Gantt0305/components/Gantt1/index.jsx new file mode 100755 index 000000000..aaf153917 --- /dev/null +++ b/src/views/Gantt0305/components/Gantt1/index.jsx @@ -0,0 +1,51 @@ +import { NImage } from 'naive-ui' +import useGantt from './hooks/gantt' +import { useRouter, useRoute } from 'vue-router' + +export default defineComponent({ + props: { + scale: { + type: String, + default: 'day', + }, + }, + setup(props) { + const router = useRouter() + const route = useRoute() + const { renderMainTask, changeTimeScales, currentImage } = useGantt({ + route, + router, + }) + + onMounted(() => { + nextTick(() => { + renderMainTask(document.querySelector('#tableContainer')) + }) + }) + watch( + () => props.scale, + val => { + changeTimeScales(val) + } + ) + + const imgRef = ref(null) + watch(currentImage, imgUrl => { + nextTick(() => { + if (imgUrl) { + imgRef.value.click() + } + }) + }) + return () => ( + <> +
+ + + ) + }, +}) diff --git a/src/views/Gantt0305/components/Gantt2/components/VRender.jsx b/src/views/Gantt0305/components/Gantt2/components/VRender.jsx new file mode 100755 index 000000000..4f0174da4 --- /dev/null +++ b/src/views/Gantt0305/components/Gantt2/components/VRender.jsx @@ -0,0 +1,47 @@ +import { VImage, VGroup, VRect, VText } from '@visactor/vtable/es/vrender' + +const textColor = '#65c5e7' +export default defineComponent({ + props: { + width: { + type: Number, + default: 0, + }, + height: { + type: Number, + default: 0, + }, + taskRecord: { + type: Object, + default: () => ({}), + }, + }, + setup(props) { + const { width, height, taskRecord } = props + return () => ( + + + + ) + }, +}) diff --git a/src/views/Gantt0305/components/Gantt2/hooks/gantt.ts b/src/views/Gantt0305/components/Gantt2/hooks/gantt.ts new file mode 100755 index 000000000..54d0f44a6 --- /dev/null +++ b/src/views/Gantt0305/components/Gantt2/hooks/gantt.ts @@ -0,0 +1,461 @@ +import { Group, Image, Text, CheckBox, Rect } from '@visactor/vtable/es/vrender' + +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 useGantt = ({ router, route }: GanttParams) => { + const currentImage = ref() + const { subId } = route.params + const records = ref([]) + + const timeRange = ref([]) + // onMounted(() => { + // getGanttData() + // }) + async function getGanttData(params: Record) { + timeRange.value = [params.startTime, params.endTime] + console.log('%csubId', 'color:red;font-size:20px', subId); + const { code, data } = subId ? await getSubGantt({ activityId: subId }) : await getMainGantt(params) + if (code === 200) { + records.value = data.list + ganttInstance?.setRecords(records.value) + + } + } + async function renderMainTask(dom: HTMLElement, params: Record) { + await getGanttData(params) + const option = getOption() + ganttInstance = new Gantt(dom, option) + window['ganttInstance'] = ganttInstance + } + function getOption(): TYPES.GanttConstructorOptions { + console.log(records.value); + const option = { + records: records.value, + taskListTable: renderTaskListTable(), + tasksShowMode: TYPES.TasksShowMode.Sub_Tasks_Arrange, + // groupBy: 'name', + // groupField: 'name', + // widthMode: 'standard', + // groupTitleFieldFormat: (record, col, row, table) => { + // console.log(record, col, row, table, '----') + // const groupData = table.getGroupData(record); // 获取分组数据 + // const count = groupData ? groupData.length : 0; // 计算分组下的记录数量 + // return `${record.name} (${count})`; // 返回格式化的分组标题 + // }, + 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(subId), + timelineHeader: { + backgroundColor: headerBgColor, + colWidth: 4000, + // colWidth: 1040, + // verticalLine: { + // lineColor: textColorWithOp, + // lineWidth: 1, + // lineDash: [4, 2], + // }, + horizontalLine: { + lineColor: textColorWithOp, + lineWidth: 1, + lineDash: [4, 2], + }, + scales: getTimeScales('month'), + }, + minDate: timeRange.value[0], + maxDate: timeRange.value[1], + markLine: [ + { + date: '2024-03-13T13:15:10', + style: { + lineWidth: 1, + lineColor: 'blue', + lineDash: [8, 4], + }, + }, + // { + // date: '2024-08-17', + // style: { + // lineWidth: 2, + // lineColor: 'red', + // lineDash: [8, 4], + // }, + // }, + ], + scrollStyle: { + scrollRailColor: 'RGBA(246,246,246,0)', + visible: 'focus', + width: 10, + 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, + customLayout: args => { + // console.log(args, 'srgs') + const { table, row, col, rect, dataValue } = args + // console.log( + // table, + // '1', + // row, + // '2', + // col, + // '3', + // rect, + // '4', + // dataValue, + // '5', + // '-----------' + // ) + const { height, width } = rect ?? table.getCellRect(col, row) + const container = new Group({ + width, + height, + fill: 'transparent', + // fill: textColor, + // fillOpacity: 0.1, + // stroke: textColor, + // strokeOpacity: 0.2, + // lineWidth: 4, + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + cursor: 'pointer', + boundsPadding: [10, 0, 0, 0], + }) + // console.log('args:-----', args); + + const count = table.records.find(r => dataValue === r.name)?.children + ?.length || 0 + const values = new Text({ + text: `${dataValue}`, + fontSize: 16, + fontFamily: 'sans-serif', + fill: textColor, + textAlign: 'center', + maxLineWidth: width, + whiteSpace: 'normal' + // boundsPadding: [10, 10, 10, 10], + }) + const counts = new Text({ + text: `( ${count} )`, + fontSize: 13, + fontFamily: 'sans-serif', + fill: textColor, + boundsPadding: [10, 0, 0, 0], + }) + container.add(values) + container.add(counts) + return { + rootContainer: container, + } + }, + }, + ] + 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(subId: string | number) { + // console.log(subId, '------'); + const taskBar = { + resizable: false, + moveable: false, + startDateField: 'startTime', + endDateField: 'endTime', + // progressField: 'progress', + barStyle: { width: subId ? 180 : 60 }, + customLayout: args => { + + const { width, height, startDate, endDate, taskRecord } = args + // console.log(taskRecord, 'taskRecord'); + const container = new Group({ + width, + height, + fill: 'transparent', + // fill: textColor, + // fillOpacity: 0.1, + // stroke: textColor, + // strokeOpacity: 0.2, + // lineWidth: 4, + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + cursor: 'pointer', + }) + if (!subId) { + container.addEventListener('click', () => { + console.log(taskRecord, 'ooooooo') + router.push({ + path: `/gantt/sub/${taskRecord.id}`, + }) + }) + } + + if (subId) { + const image = new Image({ + image: taskRecord.avatar, + width: 100, + height: 100, + x: 10, + y: 10, + boundsPadding: [0, 0, 10, 0], + cursor: 'pointer', + }) + container.add(image) + image.addEventListener('click', () => { + currentImage.value = [taskRecord.avatar, Date.now()] + // console.log(currentImage, 'currentImage') + }) + } + // const checkbox = new CheckBox({ + // width: 20, + // height: 20, + // checked: false, + // }) + // container.add(checkbox) + + // checkbox.addEventListener('click', event => { + // console.log(event, 'event') + // }) + // console.log(taskRecord, 'taskRecord') + const nameContainer = new Group({ + fill: 'transparent', + display: 'flex', + // flexDirection: 'column', + // justifyContent: 'center', + alignItems: 'center', + }) + + container.add(nameContainer) + + if ('trajData' in taskRecord && taskRecord.trajData) { + const taskRecordSymbol = new Image({ + width: 20, + height: 20, + fill: '#ff0', + image: + '', + boundsPadding: [-3, 10, 0, 0], + cursor: 'pointer', + }) + nameContainer.add(taskRecordSymbol) + } + + const name = new Text({ + text: taskRecord.name, + fontSize: 16, + fontFamily: 'sans-serif', + fill: textColor, + fontWeight: 'bold', + maxLineWidth: width, + textAlign: 'center', + // boundsPadding: [10, 0, 0, 0], + }) + nameContainer.add(name) + + 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, + }, + } + console.log(taskBar, '0000000'); + 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: startDate.toLocaleDateString(), + // scale === 'day' + // ? startDate.toLocaleDateString() + // : startDate.toLocaleTimeString(), + fontSize: 14, + fontWeight: 'bold', + fontFamily: 'sans-serif', + fill: textColor, + textAlign: 'right', + maxLineWidth: width, + }) + container.add(day) + return { + rootContainer: container, + } + }, + }, + ] + } + return { renderMainTask, changeTimeScales, currentImage } +} + +export default useGantt diff --git a/src/views/Gantt0305/components/Gantt2/index.jsx b/src/views/Gantt0305/components/Gantt2/index.jsx new file mode 100755 index 000000000..f86361399 --- /dev/null +++ b/src/views/Gantt0305/components/Gantt2/index.jsx @@ -0,0 +1,66 @@ +import { NImage } from 'naive-ui' +import useGantt from './hooks/gantt' +import { useRouter, useRoute } from 'vue-router' + +export default defineComponent({ + props: { + scale: { + type: String, + default: 'day', + }, + dateRange: { + type: Array, + require: true, + }, + types: { + type: Array, + require: true, + } + }, + setup(props, { expose }) { + const router = useRouter() + const route = useRoute() + const { renderMainTask, changeTimeScales, currentImage } = useGantt({ + route, + router, + }) + + expose({ renderMainTask }) + + onMounted(() => { + nextTick(() => { + // console.log(props); + renderMainTask(document.querySelector('#tableContainer'), { + ids: props.types, + startTime: props.dateRange ? new Date(props.dateRange[0]).toISOString() : null, + endTime: props.dateRange ? new Date(props.dateRange[1]).toISOString() : null + }) + }) + }) + watch( + () => props.scale, + val => { + changeTimeScales(val) + } + ) + + const imgRef = ref(null) + watch(currentImage, imgUrl => { + nextTick(() => { + if (imgUrl) { + imgRef.value.click() + } + }) + }) + return () => ( + <> +
+ + + ) + }, +}) diff --git a/src/views/Gantt0305/components/GanttEdit/hooks/ganttEdit.ts b/src/views/Gantt0305/components/GanttEdit/hooks/ganttEdit.ts new file mode 100755 index 000000000..35292b58c --- /dev/null +++ b/src/views/Gantt0305/components/GanttEdit/hooks/ganttEdit.ts @@ -0,0 +1,389 @@ +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' + +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 diff --git a/src/views/Gantt0305/components/GanttEdit/index.jsx b/src/views/Gantt0305/components/GanttEdit/index.jsx new file mode 100755 index 000000000..6fec90029 --- /dev/null +++ b/src/views/Gantt0305/components/GanttEdit/index.jsx @@ -0,0 +1,29 @@ +import useGanttEdit from './hooks/ganttEdit' +import { useRouter, useRoute } from 'vue-router' + +export default defineComponent({ + props: { + scale: { + type: String, + default: 'day', + }, + }, + setup(props) { + const router = useRouter() + const route = useRoute() + const { renderMainTask, changeTimeScales } = useGanttEdit({ route, router }) + + onMounted(() => { + nextTick(() => { + renderMainTask(document.querySelector('#tableContainer')) + }) + }) + watch( + () => props.scale, + val => { + changeTimeScales(val) + } + ) + return () =>
+ }, +}) diff --git a/src/views/Gantt0305/components/MainGantt/index.jsx b/src/views/Gantt0305/components/MainGantt/index.jsx new file mode 100755 index 000000000..e20aacfb3 --- /dev/null +++ b/src/views/Gantt0305/components/MainGantt/index.jsx @@ -0,0 +1,75 @@ +import { useRouter } from 'vue-router' +import { + NDatePicker, + NRadioButton, + NRadioGroup, + NButton, + NSelect, +} from 'naive-ui' +import GanttCom from '../Gantt' +import { getDDList } from '@/api/Gantt/gantt' +import { onBeforeMount } from 'vue' + +export default defineComponent({ + setup() { + const range = ref([new Date('2000-01-01').getTime(), Date.now()]) + const value = ref('year') + const types = ref([]) + + const router = useRouter() + const editEvent = () => { + console.log(router) + router.push('/gantt/mainEdit') + } + + onBeforeMount(async () => { + await getDDOptions() + }) + + const ddOptions = ref([]) + async function getDDOptions() { + const { code, data } = await getDDList() + if (code === 200) { + ddOptions.value = data.list + // types.value = ddOptions.value.map(item => item.id) + } + } + + const ganttRef = ref(null) + function searchGanttData() { + ganttRef.value.refresh = true + } + + return () => ( + <> +
+ + {/* + + + */} + + {/* + 编辑事件 + */} + + 搜索 + +
+ + + ) + }, +}) diff --git a/src/views/Gantt0305/components/MainGantt1/index.jsx b/src/views/Gantt0305/components/MainGantt1/index.jsx new file mode 100755 index 000000000..5c683c890 --- /dev/null +++ b/src/views/Gantt0305/components/MainGantt1/index.jsx @@ -0,0 +1,48 @@ +import { useRouter } from 'vue-router' +import { + NDatePicker, + NRadioButton, + NRadioGroup, + NButton, + NSelect, +} from 'naive-ui' +import GanttCom from '../Gantt' + +export default defineComponent({ + setup() { + const range = ref() + const value = ref('day') + const type = ref() + + const router = useRouter() + const editEvent = () => { + console.log(router) + router.push('/gantt/mainEdit') + } + return () => ( + <> +
+ + + + + + + {/* + 编辑事件 + */} +
+ + + ) + }, +}) diff --git a/src/views/Gantt0305/components/MainGantt2/index.jsx b/src/views/Gantt0305/components/MainGantt2/index.jsx new file mode 100755 index 000000000..2e3d5ea5f --- /dev/null +++ b/src/views/Gantt0305/components/MainGantt2/index.jsx @@ -0,0 +1,83 @@ + import { useRouter } from 'vue-router' +import { + NDatePicker, + NRadioButton, + NRadioGroup, + NButton, + NSelect, +} from 'naive-ui' +import GanttCom from '../Gantt' +import {getDDList}from '@/api/Gantt/gantt' +import { onBeforeMount } from 'vue' + +export default defineComponent({ + setup() { + const range = ref([new Date('2000-01-01').getTime(), Date.now()]) + const value = ref('year') + const types = ref([]) + + const router = useRouter() + const editEvent = () => { + console.log(router) + router.push('/gantt/mainEdit') + } + + onBeforeMount(async ()=>{ + await getDDOptions() + }) + + const ddOptions = ref([]) + async function getDDOptions (){ + const {code,data} = await getDDList() + if(code === 200) { + ddOptions.value = data.list + types.value = ddOptions.value.map(item=>item.id) + } + } + + + const ganttRef = ref(null) + function searchGanttData(){ + // console.log(ganttRef); + renderMainTask(document.querySelector('#tableContainer'),{ + ids: types.value, + startTime: new Date(range.value[0]).toISOString(), + endTime: new Date(range.value[1]).toISOString() + }) + } + + + + return () => ( + <> +
+ + {/* + + + */} + + {/* + 编辑事件 + */} + + 搜索 + +
+ + + ) + }, +}) diff --git a/src/views/Gantt0305/components/MainGanttEdit/index.jsx b/src/views/Gantt0305/components/MainGanttEdit/index.jsx new file mode 100755 index 000000000..22bc882fb --- /dev/null +++ b/src/views/Gantt0305/components/MainGanttEdit/index.jsx @@ -0,0 +1,45 @@ +import { NDatePicker, NRadioButton, NRadioGroup, NButton } from 'naive-ui' +import { useRouter } from 'vue-router' +import GanttCom from '../GanttEdit' + +export default defineComponent({ + setup() { + const range = ref() + const value = ref('day') + + const addEvent = () => { + console.log('tianjia --- event') + } + const addTask = () => { + console.log('tianjiarenwu') + } + + const router = useRouter() + const ok = () => { + router.push('/gantt') + } + return () => ( + <> +
+ + + + + +
+ + 添加事件 + + {/* + 添加任务 + */} + + 完成编辑 + +
+
+ + + ) + }, +}) diff --git a/src/views/Gantt0305/components/SubGantt/index.jsx b/src/views/Gantt0305/components/SubGantt/index.jsx new file mode 100755 index 000000000..a936b7cbe --- /dev/null +++ b/src/views/Gantt0305/components/SubGantt/index.jsx @@ -0,0 +1,33 @@ +import { NButton } from 'naive-ui' +import GanttCom from '../Gantt' +import { useRouter } from 'vue-router' + +export default defineComponent({ + setup() { + const router = useRouter() + + const value = ref('day') + + const showView = () => { + // getCheckboxState + const checked = ganttInstance.taskListTableInstance?.getCheckboxState() + console.log(checked) + } + + return () => ( + <> +
+ 态势展示 + { + router.go(-1) + }} + > + 返回 + +
+ + + ) + }, +}) diff --git a/src/views/Gantt0305/components/SubGanttEdit/index.jsx b/src/views/Gantt0305/components/SubGanttEdit/index.jsx new file mode 100755 index 000000000..e29c01365 --- /dev/null +++ b/src/views/Gantt0305/components/SubGanttEdit/index.jsx @@ -0,0 +1,33 @@ +import { NButton } from 'naive-ui' +import GanttCom from '../GanttEdit' +import { useRouter } from 'vue-router' + +export default defineComponent({ + setup() { + const router = useRouter() + + const value = ref('day') + + const showView = () => { + // getCheckboxState + const checked = ganttInstance.taskListTableInstance?.getCheckboxState() + console.log(checked) + } + + return () => ( + <> +
+ {/* 态势展示 */} + { + router.go(-1) + }} + > + 返回 + +
+ + + ) + }, +}) diff --git a/src/views/Gantt0305/components/TaskList/components/NewTask/hooks.ts b/src/views/Gantt0305/components/TaskList/components/NewTask/hooks.ts new file mode 100755 index 000000000..f441a577a --- /dev/null +++ b/src/views/Gantt0305/components/TaskList/components/NewTask/hooks.ts @@ -0,0 +1,15 @@ +const showNewTask = ref(false) + +const curTaskData = ref({ + name: '', + description: '', + checkedEvent: [], +}) +const useTask = () => { + return { + showNewTask, + curTaskData, + } +} + +export default useTask diff --git a/src/views/Gantt0305/components/TaskList/components/NewTask/index.jsx b/src/views/Gantt0305/components/TaskList/components/NewTask/index.jsx new file mode 100755 index 000000000..dada96a52 --- /dev/null +++ b/src/views/Gantt0305/components/TaskList/components/NewTask/index.jsx @@ -0,0 +1,118 @@ +import { NForm, NFormItem, NInput, NDataTable, NButton } from 'naive-ui' +import ModalCom from '@/components/Modal/index.vue' +import { getMainGantt } from '@/api/gantt' +import useTask from './hooks' +export default defineComponent({ + // props: { + // show: { + // type: Boolean, + // default: false, + // }, + // }, + setup() { + // const checkedRowKeys = ref([]) + // watch(checkedRowKeys, newval => { + // console.log(newval, '-----') + // }) + + const columns = [ + { type: 'selection' }, + { + title: '事件名称', + key: 'name', + width: 220, + // render: row => { + // return ( + //
+ // + // + // + // {row.name} + //
+ // ) + // }, + }, + { + title: '开始时间', + key: 'start', + }, + { + title: '结束时间', + key: 'end', + }, + // { + // title: '类型', + // key: 'type', + // }, + { + title: '图片', + key: 'avatar', + render(row) { + if (row.avatar) { + return + } else { + return - + } + }, + }, + ] + + const tableData = ref([]) + onMounted(async () => { + const res = await getMainGantt() + tableData.value = res + }) + const { showNewTask, curTaskData } = useTask() + + const close = () => { + showNewTask.value = false + console.log(curTaskData, '---') + } + + // watch( + // showNewTask, + // show => { + // if (show) { + // taskData.value = { + // name: '', + // description: '', + // checkedEvent: [], + // } + // } + // }, + // { immediate: true } + // ) + + return () => ( + + + + + + + + + + row.name} + /> + + +
+ 取消 + 确认 +
+
+ ) + }, +}) diff --git a/src/views/Gantt0305/components/TaskList/index.jsx b/src/views/Gantt0305/components/TaskList/index.jsx new file mode 100755 index 000000000..833da29b3 --- /dev/null +++ b/src/views/Gantt0305/components/TaskList/index.jsx @@ -0,0 +1,172 @@ +import { NDataTable, NIcon, NButton, NTag } from 'naive-ui' +import { useTree } from '@/utils/tree' +import { getTask } from '@/api/gantt' +import { + HelpCircleOutline, + CreateOutline, + TrashBinOutline, + AddCircleOutline, + EnterOutline, +} from '@vicons/ionicons5' +import useTask from './components/NewTask/hooks' + +export default defineComponent({ + setup() { + const dict = window.settings.gantt + const columns = [ + { + title: '任务名称/事件名称', + key: 'name', + width: 'auto', + render: row => { + return ( +
+ {row.type && ( + + {dict[row.type].label} + + )} + {row.name} +
+ ) + }, + }, + { + title: '开始时间', + key: 'start', + }, + { + title: '结束时间', + key: 'end', + }, + // { + // title: '类型', + // key: 'type', + // render(row) { + // return ( + // row.type && ( + // + // {dict[row.type].label} + // + // ) + // ) + // }, + // }, + { + title: '图片', + key: 'avatar', + render(row) { + if (row.avatar) { + return + } else { + return - + } + }, + }, + { + title: '操作', + key: 'action', + render(row) { + return ( +
+ {row.type === 'task' ? ( + <> + editTask(row)} + > + + + + 进入任务 + + editTask(row)} + > + + + + 编辑 + + + ) : null} + {/* {!row.avatar ? ( + handleEdit(row)} + > + + + + + ) : ( + <> + )} */} + + {/* handleEdit(row)} + > + + + + */} +
+ ) + }, + }, + ] + const tableData = ref([]) + const { getAllKeys } = useTree() + const expandedRowKeys = ref([]) + onMounted(async () => { + await getTaskList() + }) + + async function getTaskList() { + const res = await getTask() + tableData.value = res + expandedRowKeys.value = getAllKeys(tableData.value, 'name') + } + + const { showNewTask, curTaskData } = useTask() + function editTask(row) { + showNewTask.value = true + curTaskData.value = { + ...row, + checkedEvent: getAllKeys(row.children, 'name'), + } + } + + return () => ( + row.name} + /> + ) + }, +}) diff --git a/src/views/Gantt0305/index copy.vue b/src/views/Gantt0305/index copy.vue new file mode 100755 index 000000000..e1deeaf9a --- /dev/null +++ b/src/views/Gantt0305/index copy.vue @@ -0,0 +1,531 @@ + + + diff --git a/src/views/Gantt0305/index.jsx b/src/views/Gantt0305/index.jsx new file mode 100755 index 000000000..8a59ad0d0 --- /dev/null +++ b/src/views/Gantt0305/index.jsx @@ -0,0 +1,179 @@ +import { RouterView } from 'vue-router' +import { + NDatePicker, + NButton, + NFloatButton, + NIcon, + NDrawer, + NDrawerContent, + NTabs, + NTabPane, + NSelect, +} from 'naive-ui' +import { ArrowForward } from '@vicons/ionicons5' +import HeaderCom from '../Content/components/Header/index.vue' +import TaskList from './components/TaskList' +import EventList from './components/EventList' +import NewTask from './components/TaskList/components/NewTask' + +import useTask from './components/TaskList/components/NewTask/hooks' +import { useEvent } from './components/EventList/hooks' +import { getSimpList, getSimpTreeList } from '@/api/Gantt' +import { onBeforeMount, nextTick } from 'vue' +export default defineComponent({ + setup() { + const show = ref(false) + + const { showNewTask } = useTask() + + const addNewTask = () => { + showNewTask.value = true + } + async function getSimpListData() { + const res = await getSimpList() + ddList.value = res.data.list + targetId.value = res.data.list[0].id + } + + // const ddList = Array.from({ length: 8 }, (_, i) => ({ + // label: `DD-${i + 1}`, + // value: `DD-${i + 1}`, + // })) + const ddList = ref([]) + + const paneClass = `border-1 h-full border-l-0 border-[var(--n-tab-border-color)] !p-2` + + const { + showMainEvent, + mainEventData, + targetId, + range, + searchTreeList, + tableData, + } = useEvent() + const addNewMainEvent = async () => { + showMainEvent.value = true + // const res = await addNewMainEvent({ }) + mainEventData.value = {} + } + + onBeforeMount(() => { + nextTick(async () => { + await getSimpListData() + await searchTreeList() + }) + }) + + return () => ( +
+
+ +
+
+ +
+ { + show.value = true + }} + > + + + + + + +
+ {/* + +
+
+ + + 添加任务 + +
+
+ +
+
+
+ */} +
+
+ + + + 搜索 + + + 添加事件 + +
+
+ +
+
+ {/*
+
*/} + {/*
+ + +
+
+ +
*/} +
+
+
+ + +
+ ) + }, +}) diff --git a/src/views/Gantt0305/index.vue b/src/views/Gantt0305/index.vue new file mode 100755 index 000000000..4318161cf --- /dev/null +++ b/src/views/Gantt0305/index.vue @@ -0,0 +1,7 @@ + + +