Web优化 2

This commit is contained in:
2026-06-12 14:36:41 +08:00
parent 7e9df04bf8
commit 61a1a4d368
31 changed files with 551 additions and 918 deletions
@@ -1,10 +1,7 @@
<template>
<NCard title="产物与会话历史">
<NSpin :show="loading">
<NCollapse
v-if="hasAnyContent"
:default-expanded-names="defaultExpandedNames"
>
<NCollapse v-if="hasAnyContent" :default-expanded-names="defaultExpandedNames">
<!-- 产物按阶段分组 -->
<NCollapseItem
v-for="phase in ARTIFACT_PHASES"
@@ -15,81 +12,46 @@
<template #header>
<div class="flex items-center gap-2">
<span class="font-medium">{{ PHASE_TITLE[phase] }}产物</span>
<NTag
size="tiny"
:type="phase === currentPhase ? 'primary' : 'default'"
>
<NTag size="tiny" :type="phase === currentPhase ? 'primary' : 'default'">
{{ artifactsByPhase[phase].length }}
</NTag>
<span
v-if="phase === currentPhase"
class="text-xs text-blue-500"
>当前</span>
<span v-if="phase === currentPhase" class="text-xs text-blue-500">当前</span>
</div>
</template>
<NList
v-if="artifactsByPhase[phase].length > 0"
:show-divider="false"
>
<NListItem
v-for="a in artifactsByPhase[phase]"
:key="a.id"
>
<NThing
class="cursor-pointer"
@click="toggleArtifact(a)"
>
<NList v-if="artifactsByPhase[phase].length > 0" :show-divider="false">
<NListItem v-for="a in artifactsByPhase[phase]" :key="a.id">
<NThing class="cursor-pointer" @click="toggleArtifact(a)">
<template #header>
<span
class="text-sm font-medium"
:class="selectedArtifact?.id === a.id ? 'text-blue-600' : ''"
>v{{ a.version }}</span>
<NTag
v-if="a.source_message_id"
size="tiny"
class="ml-1"
>v{{ a.version }}</span
>
AI
</NTag>
<NTag v-if="a.source_message_id" size="tiny" class="ml-1"> AI </NTag>
</template>
<template #header-extra>
<span class="text-xs text-gray-400">
{{ formatDate(a.created_at) }}
</span>
</template>
<span
v-if="a.note"
class="text-xs text-gray-500"
>{{ a.note }}</span>
<span v-if="a.note" class="text-xs text-gray-500">{{ a.note }}</span>
</NThing>
</NListItem>
</NList>
<NEmpty
v-else
description="暂无产物"
size="small"
/>
<NEmpty v-else description="暂无产物" size="small" />
<!-- 选中产物内容预览 -->
<div
v-if="selectedArtifact && selectedArtifact.phase === phase"
class="mt-3"
>
<div v-if="selectedArtifact && selectedArtifact.phase === phase" class="mt-3">
<NDivider />
<!-- eslint-disable-next-line vue/no-v-html -->
<div
class="prose prose-sm max-w-none"
v-html="renderedArtifact"
/>
<!-- eslint-disable vue/no-v-html -->
<div class="prose prose-sm max-w-none" v-html="renderedArtifact" />
<!-- eslint-enable vue/no-v-html -->
</div>
</NCollapseItem>
<!-- AI 对话 -->
<NCollapseItem
name="conversations"
:disabled="conversations.length === 0"
>
<NCollapseItem name="conversations" :disabled="conversations.length === 0">
<template #header>
<div class="flex items-center gap-2">
<span class="font-medium">AI 对话</span>
@@ -99,18 +61,9 @@
</div>
</template>
<NList
v-if="conversations.length > 0"
:show-divider="false"
>
<NListItem
v-for="c in conversations"
:key="c.id"
>
<NThing
class="cursor-pointer"
@click="goConversation(c)"
>
<NList v-if="conversations.length > 0" :show-divider="false">
<NListItem v-for="c in conversations" :key="c.id">
<NThing class="cursor-pointer" @click="goConversation(c)">
<template #header>
<span
class="text-sm font-medium"
@@ -127,18 +80,11 @@
</NThing>
</NListItem>
</NList>
<NEmpty
v-else
description="暂无对话"
size="small"
/>
<NEmpty v-else description="暂无对话" size="small" />
</NCollapseItem>
<!-- ACP 会话 -->
<NCollapseItem
name="acp-sessions"
:disabled="acpSessions.length === 0"
>
<NCollapseItem name="acp-sessions" :disabled="acpSessions.length === 0">
<template #header>
<div class="flex items-center gap-2">
<span class="font-medium">ACP 会话</span>
@@ -148,14 +94,8 @@
</div>
</template>
<NList
v-if="acpSessions.length > 0"
:show-divider="false"
>
<NListItem
v-for="s in acpSessions"
:key="s.id"
>
<NList v-if="acpSessions.length > 0" :show-divider="false">
<NListItem v-for="s in acpSessions" :key="s.id">
<NThing
:class="workspaceSlug ? 'cursor-pointer' : ''"
@click="workspaceSlug ? goAcpSession(s) : undefined"
@@ -173,19 +113,11 @@
</NThing>
</NListItem>
</NList>
<NEmpty
v-else
description="暂无会话"
size="small"
/>
<NEmpty v-else description="暂无会话" size="small" />
</NCollapseItem>
</NCollapse>
<NEmpty
v-else-if="!loading"
description="暂无历史产物与会话"
size="small"
/>
<NEmpty v-else-if="!loading" description="暂无历史产物与会话" size="small" />
</NSpin>
</NCard>
</template>
@@ -210,6 +142,7 @@ import { chatApi, type Conversation } from '@/api/chat'
import { acpApi, type AcpSession } from '@/api/acp'
import type { Artifact, ArtifactPhase, Phase } from '@/api/projects'
import { md } from '@/utils/markdown'
import { formatDate, formatDateTime } from '@/utils/date'
import { useRequirementsStore } from '@/stores/requirements'
import SessionStatusBadge from '@/components/acp/SessionStatusBadge.vue'
@@ -258,8 +191,9 @@ const artifactsByPhase = computed(() => {
return map
})
const hasAnyContent = computed(() =>
artifacts.value.length > 0 || conversations.value.length > 0 || acpSessions.value.length > 0,
const hasAnyContent = computed(
() =>
artifacts.value.length > 0 || conversations.value.length > 0 || acpSessions.value.length > 0,
)
// 默认展开有内容的第一项(优先当前阶段)
@@ -313,14 +247,6 @@ function goAcpSession(s: AcpSession) {
})
}
function formatDate(d: string) {
return new Date(d).toLocaleDateString('zh-CN')
}
function formatDateTime(d: string) {
return new Date(d).toLocaleString('zh-CN', { hour12: false })
}
async function refresh() {
loading.value = true
try {