重构: 拆Dashboard.vue仪表盘(strategy前端·Dashboard<500达标)
- 新建 components/dashboard/(StatCardRow 126 + ActiveProjectsPanel 174 + IdeasPanel 82): 统计卡+活跃项目+灵感池 - Dashboard.vue 563→238(<500达标): 头部+refresh+loadAll编排+共享样式 - store共享(useProjectStore单例, 子组件纯读, 无props/emit) strategy: 前端views, 子组件三拆; Dashboard<500达标(第四个继Ideas/Knowledge); scoped .df-panel父子各存(隔离必需)
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<section class="df-panel" style="animation-delay: 280ms">
|
||||
<div class="df-panel-head">
|
||||
<h2 class="df-panel-title">{{ $t('dashboard.ideaPool') }}</h2>
|
||||
<router-link to="/ideas" class="df-link">{{ $t('dashboard.viewAll') }}</router-link>
|
||||
</div>
|
||||
<div class="idea-rows">
|
||||
<div v-for="idea in displayIdeas" :key="idea.id" class="idea-row">
|
||||
<div class="idea-score-ring" :class="'ring-' + idea.tier">
|
||||
<span class="idea-score-num">{{ idea.score }}</span>
|
||||
</div>
|
||||
<div class="idea-body">
|
||||
<span class="idea-name">{{ idea.title }}</span>
|
||||
<span class="idea-status">{{ ideaStatusLabel(idea.statusLabel) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="displayIdeas.length === 0" class="empty-hint">{{ $t('dashboard.empty.noIdeas') }}</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 灵感池面板 — 从 Dashboard.vue 抽出(灵感列表 + 评分环 + tier 着色 + 空态)。
|
||||
// 共享 project store(全局单例),displayIdeas computed 直读 store.ideas(取前 4 条),无需父传 props。
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useProjectStore } from '@/stores/project'
|
||||
|
||||
const store = useProjectStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
const displayIdeas = computed(() =>
|
||||
store.ideas.slice(0, 4).map(i => ({
|
||||
id: i.id,
|
||||
title: i.title,
|
||||
score: i.score ?? 0,
|
||||
tier: (i.score ?? 0) >= 80 ? 'high' : (i.score ?? 0) >= 60 ? 'mid' : 'low',
|
||||
statusLabel: i.status,
|
||||
}))
|
||||
)
|
||||
|
||||
function ideaStatusLabel(status: string): string {
|
||||
return t('dashboard.ideaStatus.' + status)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 仅迁入灵感行自身样式;df-panel/df-link 等通用面板类留 Dashboard.vue(多面板共享) */
|
||||
.idea-rows { display: flex; flex-direction: column; }
|
||||
.idea-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 7px 0;
|
||||
border-bottom: 0.5px solid var(--df-border);
|
||||
}
|
||||
.idea-row:last-child { border-bottom: none; }
|
||||
|
||||
.idea-score-ring {
|
||||
width: 32px; height: 32px;
|
||||
border-radius: var(--df-radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ring-high { background: rgba(61,219,160,0.10); border: 0.5px solid rgba(61,219,160,0.15); }
|
||||
.ring-mid { background: rgba(240,199,94,0.08); border: 0.5px solid rgba(240,199,94,0.12); }
|
||||
.ring-low { background: rgba(240,101,101,0.08); border: 0.5px solid rgba(240,101,101,0.12); }
|
||||
|
||||
.idea-score-num {
|
||||
font-family: var(--df-font-mono);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.ring-high .idea-score-num { color: var(--df-success); }
|
||||
.ring-mid .idea-score-num { color: var(--df-warning); }
|
||||
.ring-low .idea-score-num { color: var(--df-danger); }
|
||||
|
||||
.idea-name { font-size: 12px; font-weight: 500; color: var(--df-text); display: block; }
|
||||
.idea-status { font-size: 10px; color: var(--df-text-dim); margin-top: 1px; display: block; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user