From bef9ec556f9080b46495705e506e3296462c2e32 Mon Sep 17 00:00:00 2001 From: "jlj05024111@163.com" Date: Sun, 28 Sep 2025 21:02:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schedule-table/schedule-table.scss | 66 +-- .../schedule-table/schedule-table.tsx | 182 +++++--- .../schedule-toolbar/schedule-toolbar.scss | 76 ++++ .../schedule-toolbar/schedule-toolbar.tsx | 399 ++++++++++++++++++ .../hooks/use-schedule-table.ts | 144 +++++-- .../hooks/use-schedule-toolbar.ts | 135 ++++++ 6 files changed, 882 insertions(+), 120 deletions(-) create mode 100644 src/resource-scheduler/components/schedule-toolbar/schedule-toolbar.scss create mode 100644 src/resource-scheduler/components/schedule-toolbar/schedule-toolbar.tsx create mode 100644 src/resource-scheduler/hooks/use-schedule-toolbar.ts diff --git a/src/resource-scheduler/components/schedule-table/schedule-table.scss b/src/resource-scheduler/components/schedule-table/schedule-table.scss index 417cf12..370d79e 100644 --- a/src/resource-scheduler/components/schedule-table/schedule-table.scss +++ b/src/resource-scheduler/components/schedule-table/schedule-table.scss @@ -1,32 +1,36 @@ -.schedule-table { - - width: 100%; - height: 100%; - - - .schedule-table-body { - position: relative; - overflow-y: auto; - padding: 0; - margin: 0; - border: none; - - .absolute-item { - position: absolute; - box-sizing: border-box; - margin: 0; - padding: 0; - } - - .task-item{ - background-color: red; - color: blue; - } - } - - .schedule-bg-layer { - display: block; - width: 100%; - min-height: 100%; - } +.schedule-table { + + width: 100%; + height: 100%; + + + .schedule-table-body { + position: relative; + overflow-y: auto; + padding: 0; + margin: 0; + border: none; + + .absolute-item { + position: absolute; + box-sizing: border-box; + margin: 0; + padding: 0; + } + + .task-item{ + background-color: red; + color: blue; + } + } + + .schedule-bg-layer { + display: block; + width: 100%; + min-height: 100%; + } + + .schedule-toolbar-extra{ + height: 40px; + } } \ No newline at end of file diff --git a/src/resource-scheduler/components/schedule-table/schedule-table.tsx b/src/resource-scheduler/components/schedule-table/schedule-table.tsx index 5964503..3129b83 100644 --- a/src/resource-scheduler/components/schedule-table/schedule-table.tsx +++ b/src/resource-scheduler/components/schedule-table/schedule-table.tsx @@ -1,13 +1,26 @@ -import { computed, defineComponent, onMounted, PropType, ref } from "vue"; -import { IResourceViewModel, IScheduleResource, IScheduleTask, ITaskViewModel } from "../../interface"; -import Variables from "../../constant/vars"; -import { initStore } from "../../store"; -import { useInitScheduleTable, useScheduleTableReSize, useScheduleTableStyle, useVirtualScroll } from "../../hooks/use-schedule-table"; +import { computed, defineComponent, PropType, ref, useSlots } from 'vue'; +import { + IResourceViewModel, + IScheduleResource, + IScheduleTask, + ITaskViewModel, +} from '../../interface'; +import Variables from '../../constant/vars'; +import { initStore } from '../../store'; +import { + useInitScheduleTable, + useScheduleTableReSize, + useScheduleTableStyle, + useVirtualScroll, +} from '../../hooks/use-schedule-table'; +import { ScheduleToolbar } from '../schedule-toolbar/schedule-toolbar'; import './schedule-table.scss'; - export const ScheduleTable = defineComponent({ name: 'ScheduleTable', + components: { + ScheduleToolbar, + }, props: { resources: { type: Array as PropType, @@ -58,7 +71,7 @@ export const ScheduleTable = defineComponent({ default: Variables.default.scaleColumnWidth, }, scaleRange: { - type: Array as PropType, + type: Array as PropType, default: Variables.default.scaleRange, }, scaleValue: { @@ -78,10 +91,8 @@ export const ScheduleTable = defineComponent({ default: Variables.default.gridLineColor, }, }, - emits: [ - ], + emits: [], setup(props, { emit }) { - // 头部canvas实例 const headerCanvas = ref(null); @@ -95,10 +106,23 @@ export const ScheduleTable = defineComponent({ initStore(props, emit); // 初始化表格 - const { resourceViewModels, taskViewModels } = useInitScheduleTable(headerCanvas, bodyCanvas, coordinateElement); + const { + resourceViewModels, + taskViewModels, + onRefresh, + onSave, + onSaveAs, + onConfigRefresh, + } = useInitScheduleTable(headerCanvas, bodyCanvas, coordinateElement); + + // 插槽 + const slots = useSlots(); // 计算表格样式 - const { headerStyle, bodyStyle } = useScheduleTableStyle(props); + const { headerStyle, bodyStyle } = useScheduleTableStyle( + props, + slots && !!slots.extraToolbar, + ); // 监听视图大小变化 useScheduleTableReSize(props, headerCanvas, bodyCanvas, coordinateElement); @@ -109,15 +133,23 @@ export const ScheduleTable = defineComponent({ // 过滤可见的资源 const visibleResourceViewModels = computed(() => { if (!resourceViewModels.value) return []; - return resourceViewModels.value.slice(visibleRange.value.start, visibleRange.value.end); + return resourceViewModels.value.slice( + visibleRange.value.start, + visibleRange.value.end, + ); }); // 过滤可见的任务 const visibleTaskViewModels = computed(() => { if (!taskViewModels.value) return []; - return taskViewModels.value.filter((task:ITaskViewModel) => { - const resourceIndex = props.resources.findIndex(res => res.id === task.resourceId); - return resourceIndex >= visibleRange.value.start && resourceIndex < visibleRange.value.end; + return taskViewModels.value.filter((task: ITaskViewModel) => { + const resourceIndex = props.resources.findIndex( + res => res.id === task.resourceId, + ); + return ( + resourceIndex >= visibleRange.value.start && + resourceIndex < visibleRange.value.end + ); }); }); @@ -130,41 +162,95 @@ export const ScheduleTable = defineComponent({ visibleResourceViewModels, visibleTaskViewModels, handleScroll, - visibleRange + visibleRange, + onRefresh, + onSave, + onSaveAs, + onConfigRefresh, }; }, render() { - return
-
- -
-
- -
- { - this.visibleResourceViewModels.length > 0 ? <> - { - this.visibleResourceViewModels.map((resourceViewModel: IResourceViewModel) => { - return
- {resourceViewModel.data.name} -
- }) - } - : null - } - { - this.visibleTaskViewModels.length > 0 ? <> - { - this.visibleTaskViewModels.map((taskViewModel: ITaskViewModel) => { - return
- {taskViewModel.data.name} -
- }) - } - : null - } + return ( +
+
+ + {this.$slots.extraToolbar ? ( +
+ {this.$slots.extraToolbar()} +
+ ) : null} +
+
+ +
+
+ +
+ {this.visibleResourceViewModels.length > 0 ? ( + <> + {this.visibleResourceViewModels.map( + (resourceViewModel: IResourceViewModel) => { + return ( +
+ {resourceViewModel.data.name} +
+ ); + }, + )} + + ) : null} + {this.visibleTaskViewModels.length > 0 ? ( + <> + {this.visibleTaskViewModels.map( + (taskViewModel: ITaskViewModel) => { + return ( +
+ {taskViewModel.data.name} +
+ ); + }, + )} + + ) : null} +
-
+ ); }, -}); \ No newline at end of file +}); diff --git a/src/resource-scheduler/components/schedule-toolbar/schedule-toolbar.scss b/src/resource-scheduler/components/schedule-toolbar/schedule-toolbar.scss new file mode 100644 index 0000000..72c5d9b --- /dev/null +++ b/src/resource-scheduler/components/schedule-toolbar/schedule-toolbar.scss @@ -0,0 +1,76 @@ +.schedule-toolbar { + display: flex; + flex-wrap: nowrap; + gap: 8px; + align-items: center; + justify-content: left; + height: 40px; + padding: 4px; +} + +.schedule-toolbar-item { + display: flex; + align-items: center; + justify-content: center; + min-width: 32px; + height: 100%; + font-size: 16px; + cursor: pointer; + border-radius: 4px; + + &.is-btn{ + border: 1px solid lightgray; + } + + &.is-btn:hover { + background-color: #f5f5f5; + } +} + +.schedule-toolbar-days { + display: flex; + gap: 4px; + align-items: center; + + .schedule-toolbar-days-reduce, + .schedule-toolbar-days-add { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + text-align: center; + border-radius: 4px; + + &:hover { + background-color: #f5f5f5; + } + } +} + +.schedule-toolbar-trains-standards { + display: flex; + gap: 8px; + align-items: center; +} + +.schedule-toolbar-scale-list { + display: flex; + gap: 8px; + align-items: center; +} + +.schedule-toolbar-date-picker-container{ + position: relative; + cursor: pointer; +} + +.schedule-toolbar-date-picker{ + position: absolute; + top: 0; + left: 0; + z-index: -10; + width: 100%; + height: 100%; + opacity: 0; +} diff --git a/src/resource-scheduler/components/schedule-toolbar/schedule-toolbar.tsx b/src/resource-scheduler/components/schedule-toolbar/schedule-toolbar.tsx new file mode 100644 index 0000000..006b6fc --- /dev/null +++ b/src/resource-scheduler/components/schedule-toolbar/schedule-toolbar.tsx @@ -0,0 +1,399 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { defineComponent, ref } from 'vue'; +import './schedule-toolbar.scss'; +import { any } from 'ramda'; +import { useInitScheduleToolbar } from '../../hooks/use-schedule-toolbar'; + +export const ScheduleToolbar = defineComponent({ + props: { + parentProps: { + type: any, + }, + }, + emits: ['save', 'save-as', 'refresh', 'config-change'], + setup(props, { emit }) { + // 默认小时间隔 + const hours = ref(1); + // 默认显示天数 + const days = ref(7); + + // 日期选择器 + const datePickerRef = ref(); + + // 是否显示日期选择器 + const isShowDatePicker = ref(false); + + // 开始时间 + const tempStartTime = ref(3); + // 结束时间 + const tempEndTime = ref(3); + + // 训练日标准 + const trainsStandards = ref(); + + const { + currentDay, + scale, + onRefresh, + onJupmToNow, + onMonthChange, + onWeekChange, + onDateChange, + onLockClick, + onHoursChange, + onDaysChange, + onDaysClickChange, + onScaleChange, + onDatePickerChange, + onSave, + onSaveAs, + } = useInitScheduleToolbar(emit); + + // 渲染小时列表 + const renderHoursList = (_hours: number = 24) => { + const options = []; + for (let i = 1; i <= _hours; i++) { + options.push({ + value: i, + label: `${i}小时`, + }); + } + return ( + + {options.map(item => { + return ( + + ); + })} + + ); + }; + + // 渲染显示天数列表 + const renderDaysList = (_days: number = 7) => { + const options = []; + for (let i = 1; i <= _days; i++) { + options.push({ + value: i, + label: `${i}天`, + }); + } + return ( +
+
onDaysClickChange(1)} + > +