v1.0.10 - UX upgrades

This commit is contained in:
LINING-PC\lining
2025-07-06 11:03:03 +08:00
parent 94ee66cbb4
commit af4a35254f
20 changed files with 2026 additions and 191 deletions
+195
View File
@@ -0,0 +1,195 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import type { Task } from '../models/classes/Task'
interface Props {
modelValue?: number[]
tasks: Task[]
currentTaskId?: number
label?: string
placeholder?: string
}
const props = withDefaults(defineProps<Props>(), {
modelValue: () => [],
currentTaskId: undefined,
label: '前置任务',
placeholder: '请选择前置任务',
})
const emit = defineEmits<{
'update:modelValue': [value: number[]]
}>()
const selectedValue = ref('')
// 当前选中的前置任务ID数组
const selectedPredecessorIds = computed(() => {
return props.modelValue || []
})
// 已选择的前置任务对象
const selectedPredecessors = computed(() => {
return selectedPredecessorIds.value
.map(id => props.tasks.find(task => task.id === id))
.filter(task => task) as Task[]
})
// 可选择的任务列表(排除当前任务和已选择的任务)
const availableTasks = computed(() => {
return props.tasks.filter(
task =>
task.type === 'task' &&
task.id !== props.currentTaskId &&
!selectedPredecessorIds.value.includes(task.id),
)
})
// 添加前置任务
const addPredecessor = () => {
if (selectedValue.value) {
const newId = Number(selectedValue.value)
if (!selectedPredecessorIds.value.includes(newId)) {
const newIds = [...selectedPredecessorIds.value, newId]
emit('update:modelValue', newIds)
}
selectedValue.value = ''
}
}
// 移除前置任务
const removePredecessor = (taskId: number) => {
const newIds = selectedPredecessorIds.value.filter(id => id !== taskId)
emit('update:modelValue', newIds)
}
// 监听modelValue变化,更新内部状态
watch(
() => props.modelValue,
() => {
selectedValue.value = ''
},
{ immediate: true },
)
</script>
<template>
<div class="multi-select-predecessor">
<label class="form-label">{{ label }}</label>
<div class="predecessor-selector">
<!-- 已选择的前置任务标签 -->
<div v-if="selectedPredecessors.length > 0" class="selected-tags">
<span v-for="pred in selectedPredecessors" :key="pred.id" class="predecessor-tag">
{{ pred.name }} ({{ pred.id }})
<button type="button" class="remove-tag-btn" @click="removePredecessor(pred.id)">
×
</button>
</span>
</div>
<!-- 下拉选择器 -->
<div class="select-wrapper">
<select v-model="selectedValue" class="form-select" @change="addPredecessor">
<option value="">{{ placeholder }}</option>
<option v-for="task in availableTasks" :key="task.id" :value="task.id">
{{ task.name }} (ID: {{ task.id }})
</option>
</select>
</div>
</div>
</div>
</template>
<style scoped>
.multi-select-predecessor {
display: flex;
flex-direction: column;
gap: 8px;
}
.form-label {
font-size: 14px;
font-weight: 500;
color: var(--gantt-text-secondary, #606266);
line-height: 1.4;
}
.predecessor-selector {
display: flex;
flex-direction: column;
gap: 8px;
}
.selected-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.predecessor-tag {
display: inline-flex;
align-items: center;
padding: 4px 8px;
background: var(--gantt-primary, #409eff);
color: white;
font-size: 12px;
border-radius: 14px;
gap: 6px;
}
.remove-tag-btn {
background: none;
border: none;
color: white;
font-size: 14px;
font-weight: bold;
cursor: pointer;
padding: 0;
width: 16px;
height: 16px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.2s;
}
.remove-tag-btn:hover {
background: rgba(255, 255, 255, 0.2);
}
.select-wrapper {
width: 100%;
}
.form-select {
padding: 12px 16px;
border: 1px solid var(--gantt-border-medium, #dcdfe6);
border-radius: 4px;
font-size: 14px;
color: var(--gantt-text-primary, #303133);
background: var(--gantt-bg-primary, white);
transition: border-color 0.2s;
outline: none;
width: 100%;
}
.form-select:focus {
border-color: var(--gantt-primary, #409eff);
}
/* 暗黑模式 */
:global(html[data-theme='dark']) .predecessor-tag {
background: var(--gantt-primary-dark, #337ecc);
}
:global(html[data-theme='dark']) .form-select {
background: var(--gantt-bg-primary, #2b2b2b);
border-color: var(--gantt-border-medium, #4c4d4f);
color: var(--gantt-text-primary, #e5eaf3);
}
:global(html[data-theme='dark']) .form-select:focus {
border-color: var(--gantt-primary, #409eff);
}
</style>