Files
kanban/components/Board.vue
xiaomai 485d75820b feat(ui): overhaul interface with Nuxt UI
Integrate the Nuxt UI component library and completely revamp the application's user interface to improve usability, aesthetics, and maintainability.

- Replace all custom components and native browser dialogs (`alert`, `prompt`, `confirm`) with Nuxt UI components like `UCard`, `UButton`, `UModal`, and `UNotifications`.
- Refactor the main page by extracting the sidebar into dedicated panel components: `CategoryPanel`, `BoardSummaryPanel`, and `HistoryPanel`.
- Redesign all major components (Toolbar, Board, Stage, Task) for a cleaner layout and improved information hierarchy.
- Implement user-friendly modals for all creation, editing, and deletion flows, providing a more consistent user experience.
- Add toast notifications to provide immediate feedback for user actions.
2025-10-22 17:52:17 +08:00

96 lines
3.4 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<UCard class="flex h-full flex-col">
<template #header>
<div class="flex flex-wrap items-center gap-3">
<div class="flex flex-col">
<span class="text-sm font-medium text-slate-200">看板阶段</span>
<span class="text-xs text-slate-400">
{{ totalStages }} 个阶段分布在 {{ columns.length }}
</span>
</div>
<div class="flex-1" />
<UTooltip text="新增阶段">
<UButton color="primary" icon="i-heroicons-plus-circle-20-solid" @click="openStageModal()">
添加阶段
</UButton>
</UTooltip>
<UTooltip text="新增列(用于分组阶段)">
<UButton color="neutral" variant="soft" icon="i-heroicons-view-columns-20-solid" @click="addColumn">
添加列
</UButton>
</UTooltip>
</div>
</template>
<div class="relative flex-1">
<div class="flex h-full gap-4 overflow-x-auto pb-6 pr-2">
<div
v-for="(col, colIndex) in columns"
:key="`column-${colIndex}`"
class="flex min-w-[320px] flex-col gap-4"
>
<div class="flex items-center justify-between text-xs uppercase tracking-wide text-slate-400">
<span> {{ colIndex + 1 }}</span>
<UBadge color="neutral" variant="soft" :label="`${col.length} 个阶段`" />
</div>
<StageColumn
v-for="sid in col"
:key="sid"
:stage-id="sid"
:query="query"
:category="category"
:column-index="colIndex"
/>
</div>
</div>
<div
v-if="!columns.length || !totalStages"
class="absolute inset-0 flex flex-col items-center justify-center gap-4 text-slate-400"
>
<UIcon name="i-heroicons-queue-list-20-solid" class="h-10 w-10 text-slate-600" />
<div class="text-sm">暂无阶段点击添加阶段开始构建看板</div>
</div>
</div>
</UCard>
<StageModal v-model:open="stageModalOpen" :default-column="stageModalColumn" @submit="createStage" />
</template>
<script setup lang="ts">
import { useBoardStore } from '~/stores/board'
import StageColumn from './StageColumn.vue'
import StageModal from '~/components/dialogs/StageModal.vue'
const store = useBoardStore()
const props = defineProps<{ query: string; category: string | '' }>()
const toast = useToast()
const columns = computed(() => store.board.layout?.columns || [])
const totalStages = computed(() => store.board.stages.length)
const stageModalOpen = ref(false)
const stageModalColumn = ref(0)
function openStageModal(column = 0) {
stageModalColumn.value = column
stageModalOpen.value = true
}
function createStage(payload: { title: string; column: number }) {
stageModalOpen.value = false
const column = Math.max(0, Math.min(payload.column, columns.value.length ? columns.value.length - 1 : 0))
store.addStage(payload.title.trim(), column)
toast.add({ color: 'primary', title: `已创建阶段「${payload.title}` })
}
function addColumn() {
if (!store.board.layout.columns) store.board.layout.columns = []
store.board.layout.columns.push([])
store.log('column-add', { count: store.board.layout.columns.length })
toast.add({ color: 'neutral', title: `新增列,当前共有 ${store.board.layout.columns.length}` })
}
</script>