You've already forked agentic-coding-workflow
修改
This commit is contained in:
+155
-5
@@ -1,16 +1,166 @@
|
||||
<template>
|
||||
<AppShell>
|
||||
<div class="space-y-4">
|
||||
<h2 class="text-xl font-semibold">
|
||||
欢迎,{{ auth.user?.display_name }}
|
||||
</h2>
|
||||
<p>这是占位 dashboard。后续 plan 会接入项目/工作区/Issue。</p>
|
||||
<div class="space-y-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-xl font-semibold">
|
||||
欢迎,{{ auth.user?.display_name }}
|
||||
</h2>
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="router.push({ name: 'project-list' })"
|
||||
>
|
||||
新建 / 管理项目
|
||||
</NButton>
|
||||
</div>
|
||||
|
||||
<!-- 统计卡片 -->
|
||||
<NGrid
|
||||
:cols="3"
|
||||
:x-gap="12"
|
||||
>
|
||||
<NGi>
|
||||
<NCard>
|
||||
<NStatistic
|
||||
label="活跃项目"
|
||||
:value="activeCount"
|
||||
/>
|
||||
</NCard>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<NCard>
|
||||
<NStatistic
|
||||
label="归档项目"
|
||||
:value="archivedCount"
|
||||
/>
|
||||
</NCard>
|
||||
</NGi>
|
||||
<NGi>
|
||||
<NCard>
|
||||
<NStatistic
|
||||
label="分配给我的待办议题"
|
||||
:value="myIssues.length"
|
||||
/>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<!-- 分配给我的议题 -->
|
||||
<NCard title="分配给我的议题(未关闭)">
|
||||
<NSpin :show="loading">
|
||||
<div
|
||||
v-if="myIssues.length === 0"
|
||||
class="text-sm text-gray-400 py-2"
|
||||
>
|
||||
暂无分配给你的未关闭议题。
|
||||
</div>
|
||||
<ul
|
||||
v-else
|
||||
class="divide-y"
|
||||
>
|
||||
<li
|
||||
v-for="row in myIssues"
|
||||
:key="row.issue.id"
|
||||
class="py-2 flex items-center justify-between cursor-pointer hover:bg-gray-50 px-1"
|
||||
@click="goIssue(row)"
|
||||
>
|
||||
<span class="text-sm">
|
||||
<span class="font-mono text-gray-500 mr-2">{{ row.projectSlug }}#{{ row.issue.number }}</span>
|
||||
{{ row.issue.title }}
|
||||
</span>
|
||||
<span class="text-xs text-gray-400">{{ row.projectName }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</NSpin>
|
||||
</NCard>
|
||||
|
||||
<!-- 最近项目 -->
|
||||
<NCard title="项目">
|
||||
<NSpin :show="loading">
|
||||
<div
|
||||
v-if="activeProjects.length === 0"
|
||||
class="text-sm text-gray-400 py-2"
|
||||
>
|
||||
还没有项目,去创建一个吧。
|
||||
</div>
|
||||
<ul
|
||||
v-else
|
||||
class="divide-y"
|
||||
>
|
||||
<li
|
||||
v-for="p in activeProjects"
|
||||
:key="p.id"
|
||||
class="py-2 flex items-center justify-between cursor-pointer hover:bg-gray-50 px-1"
|
||||
@click="router.push({ name: 'project-home', params: { slug: p.slug } })"
|
||||
>
|
||||
<span class="text-sm font-medium">{{ p.name }}</span>
|
||||
<span class="font-mono text-xs text-gray-400">{{ p.slug }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</NSpin>
|
||||
</NCard>
|
||||
</div>
|
||||
</AppShell>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { NButton, NCard, NGrid, NGi, NStatistic, NSpin } from 'naive-ui'
|
||||
|
||||
import AppShell from '@/layouts/AppShell.vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { projectsApi, type Project, type Issue } from '@/api/projects'
|
||||
|
||||
const auth = useAuthStore()
|
||||
const router = useRouter()
|
||||
|
||||
const projects = ref<Project[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
interface MyIssueRow {
|
||||
issue: Issue
|
||||
projectSlug: string
|
||||
projectName: string
|
||||
}
|
||||
const myIssues = ref<MyIssueRow[]>([])
|
||||
|
||||
const activeProjects = computed(() => projects.value.filter((p) => !p.archived_at))
|
||||
const activeCount = computed(() => activeProjects.value.length)
|
||||
const archivedCount = computed(() => projects.value.filter((p) => p.archived_at).length)
|
||||
|
||||
onMounted(async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const out = await projectsApi.list(true)
|
||||
projects.value = out.items
|
||||
const uid = auth.user?.id
|
||||
if (uid) {
|
||||
// 跨活跃项目聚合“分配给我且未关闭”的议题。项目数通常较小,直接并发查询。
|
||||
const lists = await Promise.all(
|
||||
activeProjects.value.map(async (p) => {
|
||||
try {
|
||||
const res = await projectsApi.listIssues(p.slug, { assignee: uid, status: 'open' })
|
||||
return res.items.map((issue) => ({
|
||||
issue,
|
||||
projectSlug: p.slug,
|
||||
projectName: p.name,
|
||||
}))
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}),
|
||||
)
|
||||
myIssues.value = lists.flat()
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
|
||||
function goIssue(row: MyIssueRow) {
|
||||
router.push({
|
||||
name: 'issue-detail',
|
||||
params: { slug: row.projectSlug, number: row.issue.number },
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user