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:
xiaomai
2025-10-22 17:52:17 +08:00
parent 2384e42933
commit 485d75820b
19 changed files with 1823 additions and 318 deletions

View File

@@ -0,0 +1,76 @@
<template>
<UModal v-model="open">
<UCard>
<template #header>
<div class="flex items-center gap-2">
<UIcon name="i-heroicons-plus-circle-20-solid" class="h-5 w-5 text-sky-400" />
<span class="font-semibold">添加阶段</span>
</div>
</template>
<form class="space-y-4" @submit.prevent="handleSubmit">
<UFormGroup label="阶段名称" name="title">
<UInput v-model="form.title" placeholder="例如:待办、进行中、已完成…" autofocus />
</UFormGroup>
<UFormGroup v-if="columnOptions.length" label="放置到列" name="column">
<USelectMenu
v-model="form.column"
:options="columnOptions"
value-attribute="value"
option-attribute="label"
/>
</UFormGroup>
<p v-else class="text-xs text-slate-400">
尚未创建列新增阶段时系统会自动建立第一列
</p>
<div class="flex justify-end gap-2">
<UButton color="neutral" variant="ghost" @click="open = false">取消</UButton>
<UButton type="submit" color="primary">创建阶段</UButton>
</div>
</form>
</UCard>
</UModal>
</template>
<script setup lang="ts">
import { useBoardStore } from '~/stores/board'
const store = useBoardStore()
const toast = useToast()
const props = defineProps<{ defaultColumn?: number }>()
const open = defineModel<boolean>('open', { required: true })
const emit = defineEmits<{ (e: 'submit', payload: { title: string; column: number }): void }>()
const form = reactive({
title: '',
column: 0
})
const columnOptions = computed(() =>
(store.board.layout?.columns || []).map((_, index) => ({
label: `${index + 1}`,
value: index
}))
)
watch(
() => open.value,
(value) => {
if (!value) return
form.title = ''
const defaultColumn = props.defaultColumn ?? 0
form.column = columnOptions.value[defaultColumn] ? defaultColumn : 0
}
)
function handleSubmit() {
if (!form.title.trim()) {
toast.add({ color: 'rose', title: '请输入阶段名称' })
return
}
emit('submit', { title: form.title.trim(), column: form.column })
}
</script>