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.
This commit is contained in:
@@ -1,44 +1,95 @@
|
||||
<template>
|
||||
<div class="p-3 overflow-auto grid gap-3" :style="gridStyle">
|
||||
<div v-for="(col, colIndex) in columns" :key="colIndex" class="flex flex-col gap-3 min-w-[320px]">
|
||||
<StageColumn v-for="sid in col" :key="sid" :stage-id="sid" :query="query" :category="category" />
|
||||
<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>
|
||||
</div>
|
||||
<div v-if="!columns.length || !columns[0]?.length" class="text-center text-slate-400 py-10">
|
||||
暂无阶段。点击左侧“添加阶段”创建。
|
||||
</div>
|
||||
<div class="px-3 pb-3">
|
||||
<button class="px-3 py-1 rounded bg-slate-800/60 border border-border hover:bg-slate-800" @click="addColumn">添加列</button>
|
||||
</div>
|
||||
<div class="px-3 pb-3">
|
||||
<button class="px-3 py-1 rounded bg-slate-800/60 border border-border hover:bg-slate-800" @click="addStage">添加阶段</button>
|
||||
</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 columns = computed(() => store.board.layout?.columns || [])
|
||||
|
||||
const gridStyle = computed(() => ({
|
||||
gridAutoFlow: 'column',
|
||||
gridAutoRows: '1fr'
|
||||
}))
|
||||
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 })
|
||||
}
|
||||
function addStage() {
|
||||
const title = prompt('阶段名称?')
|
||||
if (!title) return
|
||||
const colIndex = store.board.layout.columns.length ? 0 : 0
|
||||
store.addStage(title.trim(), colIndex)
|
||||
toast.add({ color: 'neutral', title: `新增列,当前共有 ${store.board.layout.columns.length} 列` })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user