修复demo和编译/运行警告问题
This commit is contained in:
+199
-87
@@ -69,6 +69,14 @@ const taskListConfig = computed<TaskListConfig>(() => ({
|
|||||||
maxWidth: taskListWidth.value.maxWidth,
|
maxWidth: taskListWidth.value.maxWidth,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
// 配置面板折叠状态
|
||||||
|
const isConfigPanelCollapsed = ref(false)
|
||||||
|
|
||||||
|
// 切换配置面板折叠状态
|
||||||
|
const toggleConfigPanel = () => {
|
||||||
|
isConfigPanelCollapsed.value = !isConfigPanelCollapsed.value
|
||||||
|
}
|
||||||
|
|
||||||
// 切换列显示状态
|
// 切换列显示状态
|
||||||
const toggleColumn = (columnKey: string, event: Event) => {
|
const toggleColumn = (columnKey: string, event: Event) => {
|
||||||
const target = event.target as HTMLInputElement
|
const target = event.target as HTMLInputElement
|
||||||
@@ -670,92 +678,103 @@ function onTimerStopped(task: Task) {
|
|||||||
</h1>
|
</h1>
|
||||||
<VersionHistoryDrawer :visible="showVersionDrawer" @close="showVersionDrawer = false" />
|
<VersionHistoryDrawer :visible="showVersionDrawer" @close="showVersionDrawer = false" />
|
||||||
|
|
||||||
<!-- TaskList配置面板 -->
|
<!-- TaskList配置面板 - 可折叠 -->
|
||||||
<div class="config-panel">
|
<div class="config-panel" :class="{ 'collapsed': isConfigPanelCollapsed }">
|
||||||
<h3 class="config-title">
|
<div class="config-header" @click="toggleConfigPanel">
|
||||||
<svg class="config-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<h3 class="config-title">
|
||||||
<path d="M12 15l3-3H9l3 3z" fill="currentColor"/>
|
<svg class="config-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M3 6h18v2H3V6zm0 5h18v2H3v-2zm0 5h18v2H3v-2z" fill="currentColor"/>
|
|
||||||
</svg>
|
|
||||||
TaskList 配置
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<!-- 宽度配置区域 -->
|
|
||||||
<div class="config-section">
|
|
||||||
<h4 class="section-title">
|
|
||||||
<svg class="section-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<rect
|
|
||||||
x="3"
|
|
||||||
y="6"
|
|
||||||
width="18"
|
|
||||||
height="12"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="2"
|
|
||||||
fill="none"
|
|
||||||
/>
|
|
||||||
<path d="M8 12h8M8 9l-2 3 2 3M16 9l2 3-2 3" stroke="currentColor" stroke-width="1.5" fill="none"/>
|
|
||||||
</svg>
|
|
||||||
宽度设置
|
|
||||||
</h4>
|
|
||||||
<div class="width-controls">
|
|
||||||
<div class="width-control">
|
|
||||||
<label class="width-label">默认宽度:</label>
|
|
||||||
<input
|
|
||||||
v-model.number="taskListWidth.defaultWidth"
|
|
||||||
type="number"
|
|
||||||
:min="taskListWidth.minWidth"
|
|
||||||
:max="taskListWidth.maxWidth"
|
|
||||||
step="10"
|
|
||||||
class="width-input"
|
|
||||||
/>
|
|
||||||
<span class="width-unit">px</span>
|
|
||||||
</div>
|
|
||||||
<div class="width-control">
|
|
||||||
<label class="width-label">最小宽度:</label>
|
|
||||||
<input
|
|
||||||
v-model.number="taskListWidth.minWidth"
|
|
||||||
type="number"
|
|
||||||
min="280"
|
|
||||||
:max="taskListWidth.defaultWidth"
|
|
||||||
step="10"
|
|
||||||
class="width-input"
|
|
||||||
/>
|
|
||||||
<span class="width-unit">px</span>
|
|
||||||
</div>
|
|
||||||
<div class="width-control">
|
|
||||||
<label class="width-label">最大宽度:</label>
|
|
||||||
<input
|
|
||||||
v-model.number="taskListWidth.maxWidth"
|
|
||||||
type="number"
|
|
||||||
:min="taskListWidth.defaultWidth"
|
|
||||||
max="2000"
|
|
||||||
step="10"
|
|
||||||
class="width-input"
|
|
||||||
/>
|
|
||||||
<span class="width-unit">px</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 列配置区域 -->
|
|
||||||
<div class="config-section">
|
|
||||||
<h4 class="section-title">
|
|
||||||
<svg class="section-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M3 6h18v2H3V6zm0 5h18v2H3v-2zm0 5h18v2H3v-2z" fill="currentColor"/>
|
<path d="M3 6h18v2H3V6zm0 5h18v2H3v-2zm0 5h18v2H3v-2z" fill="currentColor"/>
|
||||||
</svg>
|
</svg>
|
||||||
列显示
|
TaskList 配置
|
||||||
</h4>
|
</h3>
|
||||||
<div class="column-controls">
|
<button class="collapse-button" :class="{ 'collapsed': isConfigPanelCollapsed }">
|
||||||
<label v-for="column in availableColumns" :key="column.key" class="column-control">
|
<svg class="collapse-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<input
|
<path d="M7 10l5 5 5-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
type="checkbox"
|
</svg>
|
||||||
:checked="column.visible"
|
</button>
|
||||||
@change="toggleColumn(column.key, $event)"
|
|
||||||
/>
|
|
||||||
<span class="column-label">{{ column.label }}</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 可折叠内容区域 -->
|
||||||
|
<transition name="config-content">
|
||||||
|
<div v-show="!isConfigPanelCollapsed" class="config-content">
|
||||||
|
<!-- 宽度配置区域 -->
|
||||||
|
<div class="config-section">
|
||||||
|
<h4 class="section-title">
|
||||||
|
<svg class="section-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect
|
||||||
|
x="3"
|
||||||
|
y="6"
|
||||||
|
width="18"
|
||||||
|
height="12"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
fill="none"
|
||||||
|
/>
|
||||||
|
<path d="M8 12h8M8 9l-2 3 2 3M16 9l2 3-2 3" stroke="currentColor" stroke-width="1.5" fill="none"/>
|
||||||
|
</svg>
|
||||||
|
宽度设置
|
||||||
|
</h4>
|
||||||
|
<div class="width-controls">
|
||||||
|
<div class="width-control">
|
||||||
|
<label class="width-label">默认宽度:</label>
|
||||||
|
<input
|
||||||
|
v-model.number="taskListWidth.defaultWidth"
|
||||||
|
type="number"
|
||||||
|
:min="taskListWidth.minWidth"
|
||||||
|
:max="taskListWidth.maxWidth"
|
||||||
|
step="10"
|
||||||
|
class="width-input"
|
||||||
|
/>
|
||||||
|
<span class="width-unit">px</span>
|
||||||
|
</div>
|
||||||
|
<div class="width-control">
|
||||||
|
<label class="width-label">最小宽度:</label>
|
||||||
|
<input
|
||||||
|
v-model.number="taskListWidth.minWidth"
|
||||||
|
type="number"
|
||||||
|
min="280"
|
||||||
|
:max="taskListWidth.defaultWidth"
|
||||||
|
step="10"
|
||||||
|
class="width-input"
|
||||||
|
/>
|
||||||
|
<span class="width-unit">px</span>
|
||||||
|
</div>
|
||||||
|
<div class="width-control">
|
||||||
|
<label class="width-label">最大宽度:</label>
|
||||||
|
<input
|
||||||
|
v-model.number="taskListWidth.maxWidth"
|
||||||
|
type="number"
|
||||||
|
:min="taskListWidth.defaultWidth"
|
||||||
|
max="2000"
|
||||||
|
step="10"
|
||||||
|
class="width-input"
|
||||||
|
/>
|
||||||
|
<span class="width-unit">px</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 列配置区域 -->
|
||||||
|
<div class="config-section">
|
||||||
|
<h4 class="section-title">
|
||||||
|
<svg class="section-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M3 6h18v2H3V6zm0 5h18v2H3v-2zm0 5h18v2H3v-2z" fill="currentColor"/>
|
||||||
|
</svg>
|
||||||
|
列显示
|
||||||
|
</h4>
|
||||||
|
<div class="column-controls">
|
||||||
|
<label v-for="column in availableColumns" :key="column.key" class="column-control">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="column.visible"
|
||||||
|
@change="toggleColumn(column.key, $event)"
|
||||||
|
/>
|
||||||
|
<span class="column-label">{{ column.label }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gantt-wrapper">
|
<div class="gantt-wrapper">
|
||||||
@@ -827,23 +846,98 @@ function onTimerStopped(task: Task) {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TaskList列配置面板样式 */
|
/* TaskList列配置面板样式 - 可折叠 */
|
||||||
.config-panel {
|
.config-panel {
|
||||||
background: var(--gantt-bg-primary, #ffffff);
|
background: var(--gantt-bg-primary, #ffffff);
|
||||||
border: 1px solid var(--gantt-border-color, #e4e7ed);
|
border: 1px solid var(--gantt-border-color, #e4e7ed);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 16px;
|
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.config-panel:hover {
|
.config-panel:hover {
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.config-panel.collapsed {
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
border-bottom: 1px solid var(--gantt-border-color, #e4e7ed);
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-panel.collapsed .config-header {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-header:hover {
|
||||||
|
background-color: var(--gantt-hover-bg, #f8f9fa);
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-content {
|
||||||
|
padding: 0 16px 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
color: var(--gantt-text-secondary, #666);
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-button:hover {
|
||||||
|
background-color: var(--gantt-hover-bg, #e8f4fd);
|
||||||
|
color: var(--gantt-primary-color, #409eff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse-button.collapsed .collapse-icon {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 过渡动画 */
|
||||||
|
.config-content-enter-active,
|
||||||
|
.config-content-leave-active {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-content-enter-from,
|
||||||
|
.config-content-leave-to {
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-content-enter-to,
|
||||||
|
.config-content-leave-from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.config-title {
|
.config-title {
|
||||||
margin: 0 0 12px 0;
|
margin: 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--gantt-text-primary, #333);
|
color: var(--gantt-text-primary, #333);
|
||||||
@@ -882,7 +976,7 @@ function onTimerStopped(task: Task) {
|
|||||||
|
|
||||||
.width-controls {
|
.width-controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1110,6 +1204,24 @@ function onTimerStopped(task: Task) {
|
|||||||
color: var(--gantt-primary-color, #66b3ff);
|
color: var(--gantt-primary-color, #66b3ff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 暗色主题下的折叠面板样式 */
|
||||||
|
:global(html[data-theme='dark']) .config-header {
|
||||||
|
border-bottom-color: var(--gantt-border-color, #4a5568);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html[data-theme='dark']) .config-header:hover {
|
||||||
|
background-color: var(--gantt-hover-bg, #2d3748);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html[data-theme='dark']) .collapse-button {
|
||||||
|
color: var(--gantt-text-secondary, #a0aec0);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html[data-theme='dark']) .collapse-button:hover {
|
||||||
|
background-color: var(--gantt-hover-bg, #2d3748);
|
||||||
|
color: var(--gantt-primary-color, #66b3ff);
|
||||||
|
}
|
||||||
|
|
||||||
/* 暗黑模式下的版本标签 */
|
/* 暗黑模式下的版本标签 */
|
||||||
:global(html[data-theme='dark']) .version-badge {
|
:global(html[data-theme='dark']) .version-badge {
|
||||||
background: linear-gradient(135deg, #1a73e8 0%, #00bcd4 50%, #3f51b5 100%);
|
background: linear-gradient(135deg, #1a73e8 0%, #00bcd4 50%, #3f51b5 100%);
|
||||||
|
|||||||
@@ -6,14 +6,12 @@ interface Props {
|
|||||||
type: 'task-row' | 'task-bar'
|
type: 'task-row' | 'task-bar'
|
||||||
}
|
}
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
color: '#409eff',
|
|
||||||
progress: 0,
|
|
||||||
})
|
})
|
||||||
// console.error('props', props)
|
// console.error('props', props)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="html-content-card" :style="{ borderColor: color }">
|
<div class="html-content-card">
|
||||||
<div v-if="type==='task-row'" class="task-row" v-html="task.name" />
|
<div v-if="type==='task-row'" class="task-row" v-html="task.name" />
|
||||||
<div v-else-if="type==='task-bar'" class="task-bar" v-html="task.name" />
|
<div v-else-if="type==='task-bar'" class="task-bar" v-html="task.name" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch, defineProps, defineEmits, computed } from 'vue'
|
import { ref, watch, computed } from 'vue'
|
||||||
import { useI18n } from '../composables/useI18n'
|
import { useI18n } from '../composables/useI18n'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: Boolean,
|
visible: Boolean,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onUnmounted, onMounted, computed, watch, nextTick, defineEmits } from 'vue'
|
import { ref, onUnmounted, onMounted, computed, watch, nextTick } from 'vue'
|
||||||
import TaskList from './TaskList.vue'
|
import TaskList from './TaskList.vue'
|
||||||
import Timeline from './Timeline.vue'
|
import Timeline from './Timeline.vue'
|
||||||
import GanttToolbar from './GanttToolbar.vue'
|
import GanttToolbar from './GanttToolbar.vue'
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineProps, defineEmits } from 'vue'
|
|
||||||
import '../styles/app.css'
|
import '../styles/app.css'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: Boolean,
|
visible: Boolean,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const emit = defineEmits([
|
|||||||
'add-predecessor',
|
'add-predecessor',
|
||||||
'add-successor',
|
'add-successor',
|
||||||
'delete',
|
'delete',
|
||||||
'contextmenu', // 添加原生contextmenu事件声明
|
'context-menu',
|
||||||
])
|
])
|
||||||
|
|
||||||
const slots = useSlots()
|
const slots = useSlots()
|
||||||
@@ -1331,9 +1331,9 @@ onUnmounted(() => {
|
|||||||
:row-height="rowHeight"
|
:row-height="rowHeight"
|
||||||
:day-width="dayWidth"
|
:day-width="dayWidth"
|
||||||
/>
|
/>
|
||||||
<block v-else>
|
<template v-else>
|
||||||
{{ task.name }} ({{ task.progress || 0 }}%)
|
{{ task.name }} ({{ task.progress || 0 }}%)
|
||||||
</block>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 完成进度条(非父级任务) -->
|
<!-- 完成进度条(非父级任务) -->
|
||||||
|
|||||||
Reference in New Issue
Block a user