重构: 前端DRY(style全局沉淀 + ts/js公共沉淀)
style-dry: - 新增 src/styles/components.css: .info-item*/.panel/.panel-header/.tech-tag/.card-tags 全局 - main.ts 注册 import - 删重复: ProjectDetail/TaskDetail/TaskOutputCard/ProjectCard/Projects(scoped删重复, 全局对子组件生效) - 未使用清理: Projects .card-progress dead(1处保守核对) tsjs-dry: - aiShared.ts: resolveAiLang(合并useAiSend.resolveLang + useAiContext.resolveLanguage) - stores/knowledge.ts: kindText/kindLabel/kindIcon/knowledgeStatusLabel/knowledgeConfidenceLabel(5公共) - 删重复: useAiSend/useAiContext(resolveLang) + Knowledge/KnowledgeDetail(4+5 helper) + ActiveProjectsPanel(formatLastActivity→formatRelativeZh复用) strategy: DRY收口, 公共沉淀(utils/store/shared); relativeTime非纯重复保留; .btn/.empty-hint局部override WATCH未动
This commit is contained in:
@@ -145,7 +145,14 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useKnowledgeStore, KNOWLEDGE_KINDS } from '@/stores/knowledge'
|
||||
import {
|
||||
useKnowledgeStore,
|
||||
KNOWLEDGE_KINDS,
|
||||
kindText,
|
||||
kindLabel,
|
||||
knowledgeStatusLabel as statusLabel,
|
||||
knowledgeConfidenceLabel as confidenceLabel,
|
||||
} from '@/stores/knowledge'
|
||||
import { useRendered } from '@/composables/useMarkdown'
|
||||
import { stripMd } from '@/utils/markdown'
|
||||
import KnowledgeDetail from '@/components/knowledge/KnowledgeDetail.vue'
|
||||
@@ -165,10 +172,6 @@ const categories = [
|
||||
function catLabel(key: string): string {
|
||||
return key === 'all' ? t('knowledge.categoryAll') : kindText(key)
|
||||
}
|
||||
// 纯类型文案(无 icon),用于下拉/分类
|
||||
function kindText(key: string): string {
|
||||
return t(`knowledge.kind.${key}`)
|
||||
}
|
||||
const activeKind = ref('all')
|
||||
const searchQuery = ref('')
|
||||
let searchTimer: ReturnType<typeof setTimeout> | null = null
|
||||
@@ -331,20 +334,7 @@ async function submitCreate() {
|
||||
}
|
||||
|
||||
// ===== 列表卡片标签辅助(详情相关 label/时间解析已迁移至 KnowledgeDetail 子组件)=====
|
||||
function kindLabel(key: string): string {
|
||||
const k = KNOWLEDGE_KINDS.find(c => c.key === key)
|
||||
return k ? `${k.icon} ${kindText(key)}` : key
|
||||
}
|
||||
function statusLabel(status: string): string {
|
||||
const key = `knowledge.status.${status}`
|
||||
const msg = t(key)
|
||||
return msg === key ? status : msg
|
||||
}
|
||||
function confidenceLabel(c: string): string {
|
||||
const key = `knowledge.confidence.${c}`
|
||||
const msg = t(key)
|
||||
return msg === key ? c : msg
|
||||
}
|
||||
// kindText/kindLabel/statusLabel/confidenceLabel 由 @/stores/knowledge 提供(列表/详情共用,单一来源)
|
||||
|
||||
onMounted(() => {
|
||||
ensureLoaded() // 后台预热 Markdown 渲染器(模块单例,与 AiChat/TaskDetail 共享),不阻塞
|
||||
|
||||
@@ -435,26 +435,9 @@ onUnmounted(() => {
|
||||
gap: var(--df-gap-grid);
|
||||
}
|
||||
|
||||
/* B-260615-31:字段同行布局(label 固定宽 + 值占余),描述字段 info-block 保持块状 */
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
gap: 12px;
|
||||
}
|
||||
.info-item.info-block {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.info-item .label {
|
||||
font-size: 12px;
|
||||
color: var(--df-text-dim);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
min-width: 88px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* B-260615-31:字段同行布局(label 固定宽 + 值占余),描述字段 info-block 保持块状)
|
||||
基础 .info-item/.label/.value 已收敛至全局 components.css(DRY 收口 B-260619),
|
||||
此处仅保留本组件特有覆盖。 */
|
||||
.info-item a.idea-link {
|
||||
color: var(--df-accent);
|
||||
text-decoration: none;
|
||||
@@ -489,11 +472,8 @@ onUnmounted(() => {
|
||||
.path-ok { color: var(--df-success); font-size: 12px; }
|
||||
.path-missing { color: var(--df-danger); font-size: 12px; }
|
||||
.info-tags { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||
.info-tags .tech-tag {
|
||||
font-size: 11px; padding: 2px 8px; border-radius: var(--df-radius-xs);
|
||||
background: rgba(108, 99, 255, 0.08); color: var(--df-text-secondary);
|
||||
border: 0.5px solid var(--df-border);
|
||||
}
|
||||
/* .info-tags .tech-tag 与全局 .tech-tag(components.css)逐字一致,移除局部冗余,
|
||||
标签样式由全局提供。 */
|
||||
|
||||
/* ===== 项目描述 Markdown 渲染(B-260615-25,基础样式收敛至全局 ai-md.css) ===== */
|
||||
.description.ai-md { font-size: 14px; color: var(--df-text); line-height: 1.6; }
|
||||
@@ -614,19 +594,8 @@ onUnmounted(() => {
|
||||
.right-column { display: flex; flex-direction: column; gap: var(--df-gap-grid); }
|
||||
|
||||
/* ===== 面板 ===== */
|
||||
.panel {
|
||||
background: var(--df-bg-card);
|
||||
border: 0.5px solid var(--df-border);
|
||||
border-radius: var(--df-radius-lg);
|
||||
padding: var(--df-pad-panel);
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--df-gap-head);
|
||||
}
|
||||
.panel-header h2 { font-size: 15px; font-weight: 500; }
|
||||
/* .panel / .panel-header 基础样式已收敛至全局 components.css(DRY 收口 B-260619),
|
||||
此处仅保留本组件特有 .task-count。 */
|
||||
.task-count { font-size: 12px; color: var(--df-text-dim); }
|
||||
|
||||
/* ===== 任务卡片 ===== */
|
||||
|
||||
@@ -446,7 +446,6 @@ async function runImport() {
|
||||
|
||||
/* ===== 进度条 ===== */
|
||||
.card-progress { margin-bottom: 16px; }
|
||||
.card-progress { margin-bottom: 16px; }
|
||||
.progress-label-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -467,20 +466,8 @@ async function runImport() {
|
||||
transition: width 0.3s;
|
||||
}
|
||||
|
||||
/* ===== 技术栈标签(创建/导入模态复用,保留;卡片自身样式随 ProjectCard.vue 迁出) ===== */
|
||||
.card-tags {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.tech-tag {
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--df-radius-xs);
|
||||
background: rgba(108, 99, 255, 0.08);
|
||||
color: var(--df-text-secondary);
|
||||
border: 0.5px solid var(--df-border);
|
||||
}
|
||||
/* ===== 技术栈标签:基础样式已收敛至全局 components.css(DRY 收口 B-260619),
|
||||
创建/导入模态与本页 ProjectCard 渲染的标签均走全局 .tech-tag/.card-tags。 ===== */
|
||||
|
||||
/* ===== 目录选择行 ===== */
|
||||
.dir-row { display: flex; gap: 8px; align-items: center; }
|
||||
|
||||
@@ -536,19 +536,7 @@ onBeforeUnmount(() => {
|
||||
/* ===== 面板 ===== */
|
||||
.detail-grid { display: grid; grid-template-columns: 1fr; gap: var(--df-gap-grid); }
|
||||
|
||||
.panel {
|
||||
background: var(--df-bg-card);
|
||||
border: 0.5px solid var(--df-border);
|
||||
border-radius: var(--df-radius-lg);
|
||||
padding: var(--df-pad-panel);
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--df-gap-head);
|
||||
}
|
||||
.panel-header h2 { font-size: 15px; font-weight: 500; }
|
||||
/* .panel / .panel-header 基础样式已收敛至全局 components.css(DRY 收口 B-260619)。 */
|
||||
|
||||
/* ===== 信息列表 ===== */
|
||||
.task-info {
|
||||
@@ -556,25 +544,9 @@ onBeforeUnmount(() => {
|
||||
flex-direction: column;
|
||||
gap: var(--df-gap-grid);
|
||||
}
|
||||
/* B-260615-31:字段同行布局(label 固定宽 + value 占余),描述字段 info-block 保持块状 */
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
gap: 12px;
|
||||
}
|
||||
.info-item.info-block {
|
||||
flex-direction: column;
|
||||
}
|
||||
.info-item .label {
|
||||
font-size: 12px;
|
||||
color: var(--df-text-dim);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
min-width: 88px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.info-item .value { font-size: 14px; color: var(--df-text); flex: 1; min-width: 0; }
|
||||
/* B-260615-31:字段同行布局(label 固定宽 + value 占余),描述字段 info-block 保持块状)
|
||||
基础 .info-item/.label/.value 已收敛至全局 components.css(DRY 收口 B-260619),
|
||||
此处仅保留本组件特有覆盖。 */
|
||||
/* B-24 漏 white-space 覆盖致 v-html 后 HTML 标签间 \n 被 pre-wrap 渲染为空行间距——移除 pre-wrap,描述由 .ai-md 接管(line-height 1.5 对齐 AiChat li) */
|
||||
.info-item .value.description { line-height: 1.5; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user