优化: 前端u-agent令牌对齐与组件拆分续批
- 全局样式类(df-sec-h/df-toast族)替换散装实现,主题token去硬编码兜底 - 拆分子组件:ai-chat/queue-panel(队列时钟与编辑随迁)、 conversation-sidebar/ConversationList、settings/provider-panel - 父组件死副本清理(队列编辑/时钟/键位表,TS6133清零)并补 fill-draft父侧转发(重构半成品断链修复) - 验收:vue-tsc EXIT 0
This commit is contained in:
+25
-48
@@ -129,9 +129,10 @@
|
||||
{{ $t('aiChat.popupOpenPanel') }}
|
||||
</button>
|
||||
|
||||
<!-- P1-e-d:审批失败 toast(窗口内自包含 useToast;独立 WebviewWindow 无根 toast,自管渲染) -->
|
||||
<Transition name="ai-toast">
|
||||
<div v-if="toast.visible" class="ai-toast" :class="'ai-toast-' + toast.type">{{ toast.msg }}</div>
|
||||
<!-- P1-e-d:审批失败 toast(窗口内自包含 useToast;独立 WebviewWindow 无根 toast,自管渲染);
|
||||
样式消费全局 .df-toast 族,error 映射 danger,定位经 scoped 覆写让出 header -->
|
||||
<Transition name="df-toast">
|
||||
<div v-if="toast.visible" class="df-toast" :class="toast.type === 'error' ? 'df-toast--danger' : 'df-toast--' + toast.type">{{ toast.msg }}</div>
|
||||
</Transition>
|
||||
|
||||
<!-- M5:path 类 deny 二次确认(拒绝不可逆,与 ToolCard 同款;独立窗口本地 ConfirmDialog,
|
||||
@@ -527,11 +528,11 @@ function onDragEnd() { isDragging.value = false }
|
||||
border: 0.5px solid var(--df-accent);
|
||||
border-left: 3px solid var(--df-accent);
|
||||
border-radius: var(--df-radius-md);
|
||||
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px var(--df-accent-soft);
|
||||
box-shadow: var(--df-shadow-md), 0 0 0 1px var(--df-accent-soft);
|
||||
overflow: hidden;
|
||||
}
|
||||
.popup-shell[data-dragging="true"] {
|
||||
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6), 0 0 0 2px var(--df-accent);
|
||||
box-shadow: var(--df-shadow-md), 0 0 0 2px var(--df-accent);
|
||||
}
|
||||
|
||||
/* 顶部拖动条 */
|
||||
@@ -541,7 +542,7 @@ function onDragEnd() { isDragging.value = false }
|
||||
gap: 8px;
|
||||
padding: 8px 10px;
|
||||
background: linear-gradient(135deg, var(--df-accent-bg), transparent);
|
||||
border-bottom: 0.5px solid var(--df-border, rgba(123, 111, 240, 0.2));
|
||||
border-bottom: 0.5px solid var(--df-border);
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
}
|
||||
@@ -632,9 +633,9 @@ function onDragEnd() { isDragging.value = false }
|
||||
transition: background 0.15s var(--df-ease);
|
||||
}
|
||||
.popup-item--path { border-left-color: var(--df-accent); }
|
||||
.popup-item--risk { border-left-color: var(--df-warning, #f0a020); }
|
||||
.popup-item--risk { border-left-color: var(--df-warning); }
|
||||
.popup-item:hover {
|
||||
background: var(--df-sidebar-active, rgba(123, 111, 240, 0.12));
|
||||
background: var(--df-sidebar-active);
|
||||
}
|
||||
|
||||
.popup-item-header {
|
||||
@@ -666,8 +667,8 @@ function onDragEnd() { isDragging.value = false }
|
||||
color: var(--df-accent);
|
||||
}
|
||||
.popup-item-tag--risk {
|
||||
background: rgba(240, 160, 32, 0.18);
|
||||
color: var(--df-warning, #f0a020);
|
||||
background: var(--df-warning-bg);
|
||||
color: var(--df-warning);
|
||||
}
|
||||
|
||||
.popup-item-reason {
|
||||
@@ -695,16 +696,16 @@ function onDragEnd() { isDragging.value = false }
|
||||
margin-bottom: 6px;
|
||||
font-size: 10px;
|
||||
font-family: var(--df-font-mono);
|
||||
color: var(--df-text-dim, #888);
|
||||
border-radius: var(--df-radius-sm, 4px);
|
||||
background: var(--df-bg-card, transparent);
|
||||
color: var(--df-text-dim);
|
||||
border-radius: var(--df-radius-sm);
|
||||
background: var(--df-bg-card);
|
||||
}
|
||||
.popup-item-wait.is-long {
|
||||
color: var(--df-warning, #d97706);
|
||||
color: var(--df-warning);
|
||||
animation: pulseGlow 1.5s ease-in-out infinite;
|
||||
}
|
||||
.popup-item-wait.is-urgent {
|
||||
color: var(--df-danger, #e5484d);
|
||||
color: var(--df-danger);
|
||||
animation: pulseGlow 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@@ -741,7 +742,7 @@ function onDragEnd() { isDragging.value = false }
|
||||
height: 13px;
|
||||
padding: 0 3px;
|
||||
margin-left: 1px;
|
||||
border-radius: var(--df-radius-xs, 3px);
|
||||
border-radius: var(--df-radius-xs);
|
||||
font-family: var(--df-font-mono);
|
||||
font-size: 9px;
|
||||
font-weight: 500;
|
||||
@@ -754,7 +755,7 @@ function onDragEnd() { isDragging.value = false }
|
||||
color: #fff;
|
||||
}
|
||||
.popup-btn--approve:hover:not(:disabled) {
|
||||
background: var(--df-accent-hover, #6558d8);
|
||||
background: var(--df-accent-hover);
|
||||
}
|
||||
/* M4:session 按钮(弱填充态,介于 approve 强填充与 always 描边之间,视觉层级 once>session>always) */
|
||||
.popup-btn--session {
|
||||
@@ -776,11 +777,11 @@ function onDragEnd() { isDragging.value = false }
|
||||
.popup-btn--reject {
|
||||
background: var(--df-sidebar-hover);
|
||||
color: var(--df-text-dim);
|
||||
border: 0.5px solid var(--df-border, rgba(255, 255, 255, 0.1));
|
||||
border: 0.5px solid var(--df-border);
|
||||
}
|
||||
.popup-btn--reject:hover:not(:disabled) {
|
||||
background: rgba(255, 80, 80, 0.15);
|
||||
color: var(--df-danger, #e5484d);
|
||||
background: var(--df-danger-bg);
|
||||
color: var(--df-danger);
|
||||
}
|
||||
.popup-btn-spinner {
|
||||
width: 10px;
|
||||
@@ -800,7 +801,7 @@ function onDragEnd() { isDragging.value = false }
|
||||
gap: 6px;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-top: 0.5px solid var(--df-border, rgba(123, 111, 240, 0.2));
|
||||
border-top: 0.5px solid var(--df-border);
|
||||
background: var(--df-accent-bg);
|
||||
color: var(--df-accent);
|
||||
font-size: 12px;
|
||||
@@ -813,31 +814,7 @@ function onDragEnd() { isDragging.value = false }
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@keyframes df-spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* P1-e-d:审批失败 toast(自包含 useToast;独立窗口无根 toast 自管渲染。fixed 相对本窗口视口,
|
||||
top 让出 header,不遮挡审批按钮区。样式对齐 AiChat .ai-toast 同款,scoped 防冲突) */
|
||||
.ai-toast {
|
||||
position: fixed;
|
||||
top: 44px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 6px 12px;
|
||||
border-radius: var(--df-radius);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
z-index: 100;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35);
|
||||
max-width: 80%;
|
||||
overflow-wrap: anywhere;
|
||||
text-align: center;
|
||||
}
|
||||
.ai-toast-error { background: var(--df-danger-bg); color: var(--df-danger); border: 0.5px solid var(--df-danger); }
|
||||
.ai-toast-warning { background: var(--df-warning-bg); color: var(--df-warning); border: 0.5px solid var(--df-warning); }
|
||||
.ai-toast-info { background: var(--df-accent-bg); color: var(--df-accent); border: 0.5px solid var(--df-accent); }
|
||||
.ai-toast-success { background: var(--df-success-bg); color: var(--df-success); border: 0.5px solid var(--df-success); }
|
||||
.ai-toast-enter-active, .ai-toast-leave-active { transition: opacity 0.2s, transform 0.2s; }
|
||||
.ai-toast-enter-from, .ai-toast-leave-to { opacity: 0; transform: translate(-50%, -8px); }
|
||||
/* P1-e-d:审批失败 toast:消费 global.css .df-toast 四色族+过渡(2026-10-18 整洁波并轨),
|
||||
仅覆写浮窗上下文定位——top 让出拖动条 header,窄窗(380px)限宽防长错误文案溢出窗口 */
|
||||
.df-toast { top: 44px; max-width: 80%; overflow-wrap: anywhere; }
|
||||
</style>
|
||||
|
||||
+23
-40
@@ -12,11 +12,11 @@
|
||||
|
||||
<!-- Tab 导航 -->
|
||||
<nav class="detail-tabs audit-tabs">
|
||||
<button class="tab-btn" :class="{ 'tab-active': activeTab === 'audit' }" type="button" @click="switchTab('audit')">
|
||||
<button class="df-tab" :class="{ 'df-tab--active': activeTab === 'audit' }" type="button" @click="switchTab('audit')">
|
||||
<svg aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
|
||||
{{ t('auditLog.tabAudit') }}
|
||||
</button>
|
||||
<button class="tab-btn" :class="{ 'tab-active': activeTab === 'conversations' }" type="button" @click="switchTab('conversations')">
|
||||
<button class="df-tab" :class="{ 'df-tab--active': activeTab === 'conversations' }" type="button" @click="switchTab('conversations')">
|
||||
<svg aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>
|
||||
{{ t('auditLog.tabConversations') }}
|
||||
</button>
|
||||
@@ -91,11 +91,11 @@
|
||||
<td colspan="7">
|
||||
<div class="audit-detail">
|
||||
<div class="detail-section">
|
||||
<span class="detail-label">{{ t('auditLog.col.args') }}</span>
|
||||
<span class="df-sec-h">{{ t('auditLog.col.args') }}</span>
|
||||
<pre class="detail-pre">{{ r.arguments_brief || '—' }}</pre>
|
||||
</div>
|
||||
<div class="detail-section">
|
||||
<span class="detail-label">{{ t('auditLog.col.result') }}</span>
|
||||
<span class="df-sec-h">{{ t('auditLog.col.result') }}</span>
|
||||
<!-- 外置句柄(D2a):显「结果已外置」+ 展开经 IPC 读回原文全文 -->
|
||||
<template v-if="offloadHandle">
|
||||
<OffloadedResultBar
|
||||
@@ -512,12 +512,9 @@ onMounted(() => {
|
||||
/* ===== 加载/错误状态 ===== */
|
||||
.audit-loading { display: flex; align-items: center; justify-content: center; padding: 40px; }
|
||||
.audit-error { color: var(--df-danger); }
|
||||
.audit-spinner { animation: audit-spin 0.9s linear infinite; }
|
||||
/* 消费 global.css df-spin(原本地 audit-spin 重复定义已删,2026-10-18 整洁波) */
|
||||
.audit-spinner { animation: df-spin 0.9s linear infinite; }
|
||||
.audit-spinner--lg { color: var(--df-text-dim); }
|
||||
@keyframes audit-spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* ===== 表格 ===== */
|
||||
.audit-table-wrap {
|
||||
@@ -550,9 +547,9 @@ onMounted(() => {
|
||||
vertical-align: top;
|
||||
}
|
||||
.audit-table tbody tr:last-child td { border-bottom: none; }
|
||||
.audit-table tbody tr:hover td { background: var(--df-bg-hover, rgba(255,255,255,0.03)); }
|
||||
.audit-table tbody tr:hover td { background: var(--df-hover); }
|
||||
/* 展开/hover 行高亮由 .audit-row:hover/.expanded 管理,避免选择器冲突 */
|
||||
.audit-table tbody tr.audit-row:hover td { background: var(--df-bg-hover, rgba(255,255,255,0.03)); }
|
||||
.audit-table tbody tr.audit-row:hover td { background: var(--df-hover); }
|
||||
|
||||
.col-time { min-width: 120px; }
|
||||
.col-tool { min-width: 130px; }
|
||||
@@ -573,14 +570,14 @@ onMounted(() => {
|
||||
|
||||
/* 可点击行 */
|
||||
.audit-row { cursor: pointer; transition: background 0.12s; }
|
||||
.audit-row:hover td { background: var(--df-bg-hover, rgba(255,255,255,0.03)); }
|
||||
.audit-row.expanded td { background: var(--df-bg-hover, rgba(255,255,255,0.04)); }
|
||||
.audit-row:hover td { background: var(--df-hover); }
|
||||
.audit-row.expanded td { background: var(--df-hover); }
|
||||
|
||||
/* 展开详情行 */
|
||||
.audit-detail-row td { padding: 0 !important; border-bottom: 0.5px solid var(--df-border); }
|
||||
.audit-detail { padding: 12px 16px; display: flex; flex-direction: column; gap: 10px; }
|
||||
.detail-section { display: flex; flex-direction: column; gap: 4px; }
|
||||
.detail-label { font-size: 11px; color: var(--df-text-dim); text-transform: uppercase; letter-spacing: 0.5px; }
|
||||
/* 小节头走公共 .df-sec-h */
|
||||
.detail-pre {
|
||||
margin: 0; padding: 8px 10px;
|
||||
background: var(--df-bg);
|
||||
@@ -604,7 +601,7 @@ onMounted(() => {
|
||||
font-size: 11px;
|
||||
color: var(--df-accent);
|
||||
background: var(--df-accent-bg);
|
||||
padding: 1px 6px;
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
}
|
||||
|
||||
@@ -621,7 +618,7 @@ onMounted(() => {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
padding: 1px 7px;
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
background: var(--df-warning-bg);
|
||||
color: var(--df-warning);
|
||||
@@ -636,7 +633,7 @@ onMounted(() => {
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--df-radius-xs);
|
||||
}
|
||||
.risk-low { background: rgba(90,99,128,0.2); color: var(--df-text-dim); }
|
||||
.risk-low { background: var(--df-neutral-bg); color: var(--df-text-dim); }
|
||||
.risk-medium { background: var(--df-warning-bg); color: var(--df-warning); }
|
||||
.risk-high { background: var(--df-danger-bg); color: var(--df-danger); }
|
||||
|
||||
@@ -645,7 +642,7 @@ onMounted(() => {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
padding: 3px 10px;
|
||||
padding: var(--df-pad-badge);
|
||||
border-radius: var(--df-radius-sm);
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -655,7 +652,7 @@ onMounted(() => {
|
||||
.status-executing { background: var(--df-info-bg); color: var(--df-info); }
|
||||
.status-completed { background: var(--df-success-bg); color: var(--df-success); }
|
||||
.status-failed { background: var(--df-danger-bg); color: var(--df-danger); }
|
||||
.status-interrupted { background: rgba(90,99,128,0.2); color: var(--df-text-dim); }
|
||||
.status-interrupted { background: var(--df-neutral-bg); color: var(--df-text-dim); }
|
||||
|
||||
/* 决策者 tag */
|
||||
.decided-tag {
|
||||
@@ -667,7 +664,7 @@ onMounted(() => {
|
||||
white-space: nowrap; /* 窄列防 CJK 逐字竖排(对齐 .status-tag) */
|
||||
}
|
||||
.decided-human { background: var(--df-accent-bg); color: var(--df-accent); }
|
||||
.decided-auto { background: rgba(90,99,128,0.2); color: var(--df-text-dim); }
|
||||
.decided-auto { background: var(--df-neutral-bg); color: var(--df-text-dim); }
|
||||
.decided-none { color: var(--df-text-dim); }
|
||||
|
||||
/* ===== 分页 ===== */
|
||||
@@ -691,29 +688,15 @@ onMounted(() => {
|
||||
|
||||
/* empty-state 已提取到 global.css 全局 */
|
||||
|
||||
/* ===== Tab 导航(对齐 ProjectDetail 同款交互) ===== */
|
||||
/* ===== Tab 导航(公共 .df-tab 下划线范式,此处仅补底线叠齐/hover) ===== */
|
||||
.audit-tabs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
border-bottom: 0.5px solid var(--df-border);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.audit-tabs .tab-btn {
|
||||
padding: 8px 16px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
color: var(--df-text-dim);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
margin-bottom: -0.5px;
|
||||
}
|
||||
.audit-tabs .tab-btn:hover { color: var(--df-text); }
|
||||
.audit-tabs .tab-btn.tab-active {
|
||||
color: var(--df-text);
|
||||
border-bottom-color: var(--df-accent);
|
||||
}
|
||||
.audit-tabs .df-tab { margin-bottom: -0.5px; }
|
||||
.audit-tabs .df-tab:hover { color: var(--df-text); }
|
||||
|
||||
/* ===== 对话历史 ===== */
|
||||
.conv-split {
|
||||
@@ -782,9 +765,9 @@ onMounted(() => {
|
||||
}
|
||||
.conv-msg-role { font-size: 12px; font-weight: 500; color: var(--df-text); }
|
||||
.conv-msg-model, .conv-msg-toolname, .conv-msg-token {
|
||||
font-size: 10px; padding: 1px 6px;
|
||||
font-size: 10px; padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
background: rgba(90,99,128,0.2); color: var(--df-text-dim);
|
||||
background: var(--df-neutral-bg); color: var(--df-text-dim);
|
||||
}
|
||||
.conv-msg-token { font-family: var(--df-font-mono); color: var(--df-info); background: var(--df-info-bg); }
|
||||
.conv-msg-time { font-size: 10px; color: var(--df-text-dim); margin-left: auto; }
|
||||
@@ -818,7 +801,7 @@ onMounted(() => {
|
||||
padding: 6px 10px;
|
||||
border-radius: var(--df-radius-sm);
|
||||
background: var(--df-warning-bg);
|
||||
border: 0.5px solid rgba(240,199,94,0.2);
|
||||
border: 0.5px solid var(--df-warning-bd);
|
||||
}
|
||||
.conv-msg-toolcall-head {
|
||||
display: flex; align-items: center; gap: 8px; margin-bottom: 4px;
|
||||
|
||||
+7
-25
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="dashboard">
|
||||
<!-- ═══ Header ═══ -->
|
||||
<header class="dash-header">
|
||||
<!-- ═══ Header(全局 .page-header 46px 紧凑单行,标题/间距不再自造) ═══ -->
|
||||
<header class="page-header">
|
||||
<div class="dash-header-left">
|
||||
<h1 class="dash-title">{{ $t('dashboard.title') }}</h1>
|
||||
<h1>{{ $t('dashboard.title') }}</h1>
|
||||
<span class="dash-subtitle">{{ $t('dashboard.subtitle') }}</span>
|
||||
</div>
|
||||
<div class="dash-header-right">
|
||||
<div class="header-actions">
|
||||
<button class="btn btn-ghost btn-sm dash-refresh-btn" @click="refresh" :disabled="loading" :title="$t('dashboard.refresh')" :aria-label="$t('dashboard.refresh')">
|
||||
<svg aria-hidden="true" v-if="loading" class="dash-spinner" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M21 12a9 9 0 11-6.219-8.56"/></svg>
|
||||
<svg aria-hidden="true" v-else width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg>
|
||||
@@ -111,20 +111,7 @@ onMounted(() => {
|
||||
<style scoped>
|
||||
.dashboard { padding: 16px 20px 20px; }
|
||||
|
||||
/* ═══ Header ═══ */
|
||||
.dash-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.dash-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
letter-spacing: -0.4px;
|
||||
color: var(--df-text);
|
||||
line-height: 1.2;
|
||||
}
|
||||
/* ═══ Header(容器/标题走全局 .page-header,此处仅保留副标题装饰) ═══ */
|
||||
.dash-subtitle {
|
||||
font-size: 11px;
|
||||
color: var(--df-text-dim);
|
||||
@@ -140,14 +127,9 @@ onMounted(() => {
|
||||
background: var(--df-success);
|
||||
display: inline-block;
|
||||
}
|
||||
.dash-header-right { display: flex; gap: 6px; align-items: center; }
|
||||
|
||||
/* 刷新按钮图标旋转动画(加载中反馈) */
|
||||
.dash-spinner { animation: dash-spin 0.9s linear infinite; }
|
||||
@keyframes dash-spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
/* 刷新按钮图标旋转动画(加载中反馈);消费 global.css df-spin(原本地 dash-spin 重复定义已删) */
|
||||
.dash-spinner { animation: df-spin 0.9s linear infinite; }
|
||||
|
||||
/* ═══ Grid Layout ═══ */
|
||||
.dash-grid {
|
||||
|
||||
+4
-9
@@ -606,12 +606,6 @@ watch(() => route.params.id, (id) => {
|
||||
.idea-card:hover { background: var(--df-accent-bg); }
|
||||
.idea-card.selected { background: var(--df-accent-soft); border: 0.5px solid var(--df-accent); }
|
||||
|
||||
.idea-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.idea-title { font-size: 14px; font-weight: 500; color: var(--df-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
|
||||
.idea-score {
|
||||
@@ -620,9 +614,10 @@ watch(() => route.params.id, (id) => {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
border-radius: var(--df-radius-sm);
|
||||
}
|
||||
.score-high { background: rgba(100,255,218,0.15); color: var(--df-success); }
|
||||
.score-mid { background: rgba(255,217,61,0.15); color: var(--df-warning); }
|
||||
.score-low { background: rgba(255,107,107,0.15); color: var(--df-danger); }
|
||||
/* 评分徽章底统一走语义 token(双主题自适应) */
|
||||
.score-high { background: var(--df-success-bg); color: var(--df-success); }
|
||||
.score-mid { background: var(--df-warning-bg); color: var(--df-warning); }
|
||||
.score-low { background: var(--df-danger-bg); color: var(--df-danger); }
|
||||
|
||||
.idea-desc-preview { font-size: 12px; color: var(--df-text-dim); margin-bottom: 8px; line-height: 1.4; }
|
||||
|
||||
|
||||
+23
-38
@@ -8,9 +8,9 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- ⑤ 操作反馈 toast(保存/发布/拒绝/归档/创建成功 + 保存失败)-->
|
||||
<Transition name="toast">
|
||||
<div v-if="toast.visible" class="toast" :class="'toast-' + toast.type">{{ toast.msg }}</div>
|
||||
<!-- ⑤ 操作反馈 toast(保存/发布/拒绝/归档/创建成功 + 保存失败);样式消费全局 .df-toast 族,error 映射 danger -->
|
||||
<Transition name="df-toast">
|
||||
<div v-if="toast.visible" class="df-toast" :class="toast.type === 'error' ? 'df-toast--danger' : 'df-toast--' + toast.type">{{ toast.msg }}</div>
|
||||
</Transition>
|
||||
|
||||
<!-- 错误条:消费 store.error(样式全局 .error-banner,仅间距用页面变量) -->
|
||||
@@ -21,20 +21,20 @@
|
||||
|
||||
<!-- 顶层 Tab: 知识库 / 审核收件箱 -->
|
||||
<div class="top-tabs">
|
||||
<button class="top-tab" :class="{ active: topTab === 'library' }" @click="switchTopTab('library')">
|
||||
<button class="df-tab" :class="{ 'df-tab--active': topTab === 'library' }" @click="switchTopTab('library')">
|
||||
{{ $t('knowledge.tab.library') }}
|
||||
</button>
|
||||
<button class="top-tab" :class="{ active: topTab === 'inbox' }" @click="switchTopTab('inbox')">
|
||||
<button class="df-tab" :class="{ 'df-tab--active': topTab === 'inbox' }" @click="switchTopTab('inbox')">
|
||||
{{ $t('knowledge.tab.inbox') }}
|
||||
<span v-if="store.candidates.length" class="inbox-badge">{{ store.candidates.length }}</span>
|
||||
</button>
|
||||
<!-- 归档箱(2026-10-05 归档功能尾巴):低频可见可恢复,与回收站/正式库分池 -->
|
||||
<button class="top-tab" :class="{ active: topTab === 'archived' }" @click="switchTopTab('archived')">
|
||||
<button class="df-tab" :class="{ 'df-tab--active': topTab === 'archived' }" @click="switchTopTab('archived')">
|
||||
🗄️ {{ $t('knowledge.tab.archived') }}
|
||||
<span v-if="store.archived.length" class="inbox-badge">{{ store.archived.length }}</span>
|
||||
</button>
|
||||
<!-- 拒绝池(2026-10-05 分池):审核否决独立可见,与归档分池 -->
|
||||
<button class="top-tab" :class="{ active: topTab === 'rejected' }" @click="switchTopTab('rejected')">
|
||||
<button class="df-tab" :class="{ 'df-tab--active': topTab === 'rejected' }" @click="switchTopTab('rejected')">
|
||||
🚫 {{ $t('knowledge.tab.rejected') }}
|
||||
<span v-if="store.rejected.length" class="inbox-badge">{{ store.rejected.length }}</span>
|
||||
</button>
|
||||
@@ -487,35 +487,19 @@ onMounted(() => {
|
||||
<style scoped>
|
||||
.knowledge { padding: 16px 20px 20px; height: 100%; display: flex; flex-direction: column; container-type: inline-size; }
|
||||
|
||||
/* ===== 顶部 Toast 提示(⑤ 操作反馈,对齐 Settings.vue)===== */
|
||||
.toast {
|
||||
position: fixed; top: 16px; left: 50%; transform: translateX(-50%);
|
||||
z-index: 1000; padding: 8px 16px; border-radius: var(--df-radius-sm);
|
||||
font-size: 13px; box-shadow: 0 4px 16px rgba(0,0,0,0.3);
|
||||
}
|
||||
.toast-error { background: var(--df-danger-bg); color: var(--df-danger); border: 0.5px solid var(--df-danger); }
|
||||
.toast-warning { background: var(--df-warning-bg); color: var(--df-warning); border: 0.5px solid var(--df-warning); }
|
||||
.toast-info { background: var(--df-accent-bg); color: var(--df-accent); border: 0.5px solid var(--df-accent); }
|
||||
.toast-success { background: var(--df-success-bg); color: var(--df-success); border: 0.5px solid var(--df-success); }
|
||||
.toast-enter-active, .toast-leave-active { transition: opacity 0.2s, transform 0.2s; }
|
||||
.toast-enter-from, .toast-leave-to { opacity: 0; transform: translate(-50%, -8px); }
|
||||
/* 顶部 Toast 提示:已消费 global.css .df-toast 四色族+过渡(2026-10-18 整洁波并轨) */
|
||||
|
||||
/* page-header / btn / modal 等已提取到 global.css 全局 */
|
||||
|
||||
/* ===== 错误条样式已提取到 styles/components.css 全局(.error-banner) ===== */
|
||||
|
||||
/* ===== 顶层 Tab ===== */
|
||||
/* ===== 顶层 Tab(公共 .df-tab 下划线范式,此处仅补本页布局/hover) ===== */
|
||||
.top-tabs { display: flex; gap: 4px; margin-bottom: var(--df-gap-page); border-bottom: 0.5px solid var(--df-border); }
|
||||
.top-tab {
|
||||
padding: 8px 16px; border: none; background: transparent; color: var(--df-text-secondary);
|
||||
font-size: 13px; cursor: pointer; border-bottom: 2px solid transparent; transition: color 0.15s, border-color 0.15s;
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
}
|
||||
.top-tab:hover { color: var(--df-text); }
|
||||
.top-tab.active { color: var(--df-accent); border-bottom-color: var(--df-accent); }
|
||||
.top-tabs .df-tab { display: flex; align-items: center; gap: 6px; }
|
||||
.top-tabs .df-tab:hover { color: var(--df-text); }
|
||||
.inbox-badge {
|
||||
font-size: 11px; background: var(--df-danger); color: #fff;
|
||||
padding: 1px 6px; border-radius: var(--df-radius); min-width: 16px; text-align: center;
|
||||
padding: var(--df-pad-chip); border-radius: var(--df-radius); min-width: 16px; text-align: center;
|
||||
}
|
||||
|
||||
/* ===== 左右分栏 ===== */
|
||||
@@ -524,7 +508,7 @@ onMounted(() => {
|
||||
flex: 1; min-height: 0;
|
||||
}
|
||||
.kn-list-panel, .kn-detail-panel {
|
||||
background: var(--df-bg-panel, var(--df-bg-card));
|
||||
background: var(--df-bg-card);
|
||||
border: 0.5px solid var(--df-border);
|
||||
border-radius: var(--df-radius-lg);
|
||||
overflow: hidden; display: flex; flex-direction: column;
|
||||
@@ -564,7 +548,7 @@ onMounted(() => {
|
||||
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
||||
}
|
||||
.kn-card-meta { display: flex; gap: 8px; align-items: center; font-size: 11px; color: var(--df-text-dim); flex-wrap: wrap; }
|
||||
.meta-kind { background: rgba(90,99,128,0.2); padding: 1px 6px; border-radius: var(--df-radius-sm); }
|
||||
.meta-kind { background: var(--df-neutral-bg); padding: var(--df-pad-chip); border-radius: var(--df-radius-sm); }
|
||||
.meta-reuse { color: var(--df-info); }
|
||||
.list-empty { text-align: center; padding: 40px 0; color: var(--df-text-dim); font-size: 13px; }
|
||||
|
||||
@@ -574,14 +558,15 @@ onMounted(() => {
|
||||
|
||||
/* 状态徽章 / 置信度(列表卡片复用,详情由子组件 scoped 自带) */
|
||||
.kn-card-status { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: var(--df-radius-xs); white-space: nowrap; }
|
||||
.st-candidate { background: rgba(255,217,61,0.15); color: var(--df-warning); }
|
||||
.st-pending_review { background: rgba(108,159,255,0.15); color: var(--df-info); }
|
||||
.st-published { background: rgba(100,255,218,0.15); color: var(--df-success); }
|
||||
.st-archived { background: rgba(90,99,128,0.2); color: var(--df-text-dim); }
|
||||
.st-rejected { background: rgba(240,84,110,0.15); color: var(--df-danger); }
|
||||
.conf-high { background: rgba(100,255,218,0.15); color: var(--df-success); padding: 1px 6px; border-radius: var(--df-radius-xs); }
|
||||
.conf-medium { background: rgba(255,217,61,0.15); color: var(--df-warning); padding: 1px 6px; border-radius: var(--df-radius-xs); }
|
||||
.conf-low { background: rgba(255,107,107,0.15); color: var(--df-danger); padding: 1px 6px; border-radius: var(--df-radius-xs); }
|
||||
/* 状态/置信度徽章底统一走语义 token(双主题自适应) */
|
||||
.st-candidate { background: var(--df-warning-bg); color: var(--df-warning); }
|
||||
.st-pending_review { background: var(--df-info-bg); color: var(--df-info); }
|
||||
.st-published { background: var(--df-success-bg); color: var(--df-success); }
|
||||
.st-archived { background: var(--df-neutral-bg); color: var(--df-text-dim); }
|
||||
.st-rejected { background: var(--df-danger-bg); color: var(--df-danger); }
|
||||
.conf-high { background: var(--df-success-bg); color: var(--df-success); padding: var(--df-pad-chip); border-radius: var(--df-radius-xs); }
|
||||
.conf-medium { background: var(--df-warning-bg); color: var(--df-warning); padding: var(--df-pad-chip); border-radius: var(--df-radius-xs); }
|
||||
.conf-low { background: var(--df-danger-bg); color: var(--df-danger); padding: var(--df-pad-chip); border-radius: var(--df-radius-xs); }
|
||||
|
||||
/* form-row / form-input / form-select / form-textarea 已随新建/编辑弹层随 KnowledgeDetail 子组件迁移,此处仅保留本壳所需特有覆盖。 */
|
||||
.form-row { margin-bottom: 12px; }
|
||||
|
||||
+57
-57
@@ -66,24 +66,24 @@
|
||||
<!-- Tab 导航(概览 / 文件浏览器) -->
|
||||
<nav class="detail-tabs">
|
||||
<button
|
||||
class="tab-btn"
|
||||
:class="{ 'tab-active': activeTab === 'overview' }"
|
||||
class="df-tab"
|
||||
:class="{ 'df-tab--active': activeTab === 'overview' }"
|
||||
type="button"
|
||||
@click="setActiveTab('overview')"
|
||||
>
|
||||
{{ $t('projectDetail.tabOverview') }}
|
||||
</button>
|
||||
<button
|
||||
class="tab-btn"
|
||||
:class="{ 'tab-active': activeTab === 'files' }"
|
||||
class="df-tab"
|
||||
:class="{ 'df-tab--active': activeTab === 'files' }"
|
||||
type="button"
|
||||
@click="setActiveTab('files')"
|
||||
>
|
||||
{{ $t('fileExplorer.tabTitle') }}
|
||||
</button>
|
||||
<button
|
||||
class="tab-btn"
|
||||
:class="{ 'tab-active': activeTab === 'graph' }"
|
||||
class="df-tab"
|
||||
:class="{ 'df-tab--active': activeTab === 'graph' }"
|
||||
type="button"
|
||||
@click="setActiveTab('graph')"
|
||||
>
|
||||
@@ -177,7 +177,7 @@
|
||||
|
||||
<!-- 工程列表(hover 显行内操作) -->
|
||||
<div v-else class="module-list-overview">
|
||||
<div v-for="m in modules" :key="m.id" class="module-row-overview">
|
||||
<div v-for="m in modules" :key="m.id" class="module-row-overview df-row">
|
||||
<div class="module-row-head">
|
||||
<span class="module-name-overview">{{ m.name }}</span>
|
||||
<span v-if="moduleStatusOf(m) === 'archived'" class="module-status-badge module-status-archived">{{ $t('projectDetail.moduleStatusArchived') }}</span>
|
||||
@@ -1335,17 +1335,13 @@ onBeforeUnmount(() => {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
/* 发丝线分隔行走全局 .df-row(8px 0 + border-bottom + 末行无线),此处只管行内布局 */
|
||||
.module-row-overview {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid var(--df-border, rgba(0, 0, 0, 0.06));
|
||||
min-width: 0;
|
||||
}
|
||||
.module-row-overview:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.module-row-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
@@ -1387,30 +1383,31 @@ onBeforeUnmount(() => {
|
||||
gap: 4px;
|
||||
}
|
||||
.module-stack-overview .tech-tag {
|
||||
font-size: 11px;
|
||||
padding: 1px 6px;
|
||||
font-size: var(--df-fs-aux);
|
||||
padding: var(--df-pad-chip);
|
||||
}
|
||||
.module-status-badge {
|
||||
font-size: 11px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 8px;
|
||||
font-size: var(--df-fs-aux);
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* 模块状态徽章底统一语义 token(双主题自适应) */
|
||||
.module-status-active {
|
||||
color: var(--df-success, #16a34a);
|
||||
background: rgba(22, 163, 74, 0.1);
|
||||
color: var(--df-success);
|
||||
background: var(--df-success-bg);
|
||||
}
|
||||
.module-status-archived {
|
||||
color: var(--df-text-dim, #888);
|
||||
background: rgba(136, 136, 136, 0.12);
|
||||
color: var(--df-text-dim);
|
||||
background: var(--df-neutral-bg);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--df-radius-lg);
|
||||
font-size: 11px;
|
||||
padding: var(--df-pad-badge);
|
||||
border-radius: var(--df-radius-xs);
|
||||
font-size: var(--df-fs-aux);
|
||||
font-weight: 500;
|
||||
background: var(--df-accent-bg);
|
||||
color: var(--df-accent);
|
||||
@@ -1499,30 +1496,26 @@ onBeforeUnmount(() => {
|
||||
.project-detail { padding: 16px 20px 20px; display: flex; flex-direction: column; height: 100%; min-height: 0; max-height: 100%; overflow: hidden; }
|
||||
|
||||
/* ===== Tab 导航(Batch 10 文件浏览器) ===== */
|
||||
/* 按钮走全局 .df-tab/.df-tab--active(下划线范式),此处仅归零 button 默认样式;
|
||||
不动 border-bottom,激活底线交由全局 --active 染色 */
|
||||
.detail-tabs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
border-bottom: 0.5px solid var(--df-border);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.tab-btn {
|
||||
padding: 8px 16px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
color: var(--df-text-dim);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
.detail-tabs .df-tab {
|
||||
background: none;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
font-family: inherit;
|
||||
margin-bottom: -0.5px; /* 压盖容器发丝线,激活底线与容器边线重合 */
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
margin-bottom: -0.5px;
|
||||
}
|
||||
.tab-btn:hover {
|
||||
.detail-tabs .df-tab:hover {
|
||||
color: var(--df-text);
|
||||
}
|
||||
.tab-btn.tab-active {
|
||||
color: var(--df-text);
|
||||
border-bottom-color: var(--df-accent);
|
||||
}
|
||||
|
||||
/* 文件浏览器容器(弹性填充,内部 FileExplorer 自管布局) */
|
||||
.file-explorer-wrap {
|
||||
@@ -1536,9 +1529,9 @@ onBeforeUnmount(() => {
|
||||
/* .back-link / .back-link:hover 已提取到 styles/global.css 全局 */
|
||||
|
||||
.stage-badge {
|
||||
font-size: 12px;
|
||||
padding: 3px 10px;
|
||||
border-radius: var(--df-radius-lg);
|
||||
font-size: var(--df-fs-ctrl);
|
||||
padding: var(--df-pad-badge);
|
||||
border-radius: var(--df-radius-xs);
|
||||
font-weight: 500;
|
||||
}
|
||||
/* 阶段色全走语义 token(对齐全站约定:releasing/completed=success,见 ActiveProjectsPanel dot-release) */
|
||||
@@ -1554,6 +1547,13 @@ onBeforeUnmount(() => {
|
||||
|
||||
/* .btn 系列(btn/btn-primary/btn-ghost/btn-sm/btn-danger)已提取到 styles/global.css 全局 */
|
||||
|
||||
/* 同步/扫描/保存按钮内 spinner(此前本页无 .spinner 定义致加载态不可见;消费全局 df-spin) */
|
||||
.spinner {
|
||||
width: 12px; height: 12px;
|
||||
border: 1.5px solid var(--df-border); border-top-color: var(--df-accent);
|
||||
border-radius: 50%; animation: df-spin 0.8s linear infinite; display: inline-block;
|
||||
}
|
||||
|
||||
/* ===== 概览布局(P1-g+ 问题10②:三栏拥挤 → 两栏 + 日志下方)=====
|
||||
.detail-overview 整体滚动;内部 .detail-grid 两栏(项目信息 + 任务列表),
|
||||
.workflow-log-panel 跨整宽放下方。无日志记录时折叠为摘要不占整栏。 */
|
||||
@@ -1602,12 +1602,12 @@ onBeforeUnmount(() => {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
padding: 2px 8px;
|
||||
padding: var(--df-pad-badge);
|
||||
border: 0.5px solid var(--df-border);
|
||||
border-radius: 10px;
|
||||
border-radius: var(--df-radius-xs);
|
||||
background: transparent;
|
||||
color: var(--df-text-dim);
|
||||
font-size: 10px;
|
||||
font-size: var(--df-fs-meta);
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, color 0.15s, border-color 0.15s;
|
||||
white-space: nowrap;
|
||||
@@ -1624,13 +1624,13 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
/* 状态色类已全局化至 components.css,scoped 不重复定义 */
|
||||
|
||||
/* A2[PD-P1-3]:工作流日志「全局事件」标注(次要小字标签) */
|
||||
/* A2[PD-P1-3]:工作流日志「全局事件」标注(次要小字标签,背景走中性徽章 token) */
|
||||
.global-event-tag {
|
||||
font-size: 10px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 8px;
|
||||
font-size: var(--df-fs-meta);
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
color: var(--df-text-dim);
|
||||
background: rgba(136, 136, 136, 0.12);
|
||||
background: var(--df-neutral-bg);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -1674,7 +1674,7 @@ onBeforeUnmount(() => {
|
||||
.task-card:last-child { border-bottom: none; }
|
||||
.task-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
|
||||
.task-title { font-size: 14px; font-weight: 500; color: var(--df-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.task-status { font-size: 11px; padding: 4px 10px; border-radius: var(--df-radius-sm); }
|
||||
.task-status { font-size: var(--df-fs-aux); padding: var(--df-pad-badge); border-radius: var(--df-radius-xs); }
|
||||
/* 状态色类已全局化至 components.css;此处仅保留本视图特有的进度覆盖 */
|
||||
.status-progress { background: var(--df-accent-soft); color: var(--df-accent); }
|
||||
|
||||
@@ -1686,12 +1686,12 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
.branch-icon { color: var(--df-accent); font-size: 13px; }
|
||||
.branch-name {
|
||||
font-size: 12px;
|
||||
font-size: var(--df-fs-ctrl);
|
||||
font-family: 'SF Mono', 'Fira Code', monospace;
|
||||
color: var(--df-text-secondary);
|
||||
background: var(--df-accent-bg);
|
||||
padding: 1px 6px;
|
||||
border-radius: var(--df-radius-sm);
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
}
|
||||
.task-meta {
|
||||
display: flex;
|
||||
@@ -1711,7 +1711,7 @@ onBeforeUnmount(() => {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 5px 0;
|
||||
border-bottom: 0.5px solid rgba(42,42,74,0.5);
|
||||
border-bottom: 0.5px solid var(--df-border);
|
||||
}
|
||||
.log-item:last-child { border-bottom: none; }
|
||||
.log-time { color: var(--df-text-dim); min-width: 64px; }
|
||||
@@ -1719,9 +1719,9 @@ onBeforeUnmount(() => {
|
||||
min-width: 42px;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
font-size: 10px;
|
||||
padding: 1px 4px;
|
||||
border-radius: var(--df-radius-sm);
|
||||
font-size: var(--df-fs-meta);
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
text-align: center;
|
||||
}
|
||||
.log-info .log-level { color: var(--df-info); }
|
||||
|
||||
+8
-38
@@ -206,8 +206,8 @@
|
||||
<!-- 确认弹层(删除/彻底删除,替代原生 window.confirm) -->
|
||||
<ConfirmDialog :visible="confirmState.visible" :msg="confirmState.msg" @result="answerConfirm" />
|
||||
|
||||
<!-- 批量导入结果 toast -->
|
||||
<div v-if="toast.visible" class="toast" :class="'toast-' + toast.type">{{ toast.msg }}</div>
|
||||
<!-- 批量导入结果 toast(全局 .df-toast 族+底部变体;error 映射 danger) -->
|
||||
<div v-if="toast.visible" class="df-toast df-toast--bottom" :class="toast.type === 'error' ? 'df-toast--danger' : 'df-toast--' + toast.type">{{ toast.msg }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -524,8 +524,8 @@ async function runImport() {
|
||||
|
||||
/* page-header / btn / modal 系列已提取到 global.css 全局 */
|
||||
/* 本页特有:.btn-danger(全局尚未提供)、.btn:disabled(全局仅 .btn-primary:disabled) */
|
||||
.btn-danger { background: transparent; color: var(--df-danger); border: 0.5px solid rgba(240,101,101,0.4); }
|
||||
.btn-danger:hover { background: rgba(240,101,101,0.12); }
|
||||
.btn-danger { background: transparent; color: var(--df-danger); border: 0.5px solid var(--df-danger-bd); }
|
||||
.btn-danger:hover { background: var(--df-danger-bg); }
|
||||
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
|
||||
|
||||
/* ===== 卡片网格 ===== */
|
||||
@@ -565,27 +565,7 @@ async function runImport() {
|
||||
color: var(--df-accent);
|
||||
}
|
||||
|
||||
/* ===== 进度条 ===== */
|
||||
.card-progress { margin-bottom: 16px; }
|
||||
.progress-label-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.progress-stage { font-size: 12px; color: var(--df-text-dim); }
|
||||
.progress-pct { font-size: 12px; font-weight: 500; color: var(--df-text); }
|
||||
.progress-bar {
|
||||
height: 6px;
|
||||
background: var(--df-border);
|
||||
border-radius: var(--df-radius-sm);
|
||||
overflow: hidden;
|
||||
}
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: var(--df-accent);
|
||||
border-radius: var(--df-radius-sm);
|
||||
transition: width 0.3s;
|
||||
}
|
||||
/* 进度条族(.card-progress/.progress-*)已随卡片渲染迁至 ProjectCard.vue,本页残留定义已删(2026-10-18 整洁波) */
|
||||
|
||||
/* ===== 技术栈标签:基础样式已收敛至全局 components.css(DRY 收口 ),
|
||||
创建/导入模态与本页 ProjectCard 渲染的标签均走全局 .tech-tag/.card-tags。 ===== */
|
||||
@@ -606,7 +586,7 @@ async function runImport() {
|
||||
.error-banner {
|
||||
display: flex; align-items: center; justify-content: space-between; gap: 12px;
|
||||
padding: 8px 12px; margin-bottom: var(--df-gap-page);
|
||||
background: rgba(255,107,107,0.12); border: 0.5px solid var(--df-danger);
|
||||
background: var(--df-danger-bg); border: 0.5px solid var(--df-danger);
|
||||
border-radius: var(--df-radius-sm); color: var(--df-danger); font-size: 12px;
|
||||
}
|
||||
.error-text { word-break: break-word; }
|
||||
@@ -653,20 +633,10 @@ async function runImport() {
|
||||
.import-table .col-path { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--df-font-mono, monospace); font-size: 11px; }
|
||||
.row-disabled { opacity: 0.5; }
|
||||
.imp-name { font-weight: 500; color: var(--df-text); }
|
||||
.mono-tag { margin-left: 6px; font-size: 10px; padding: 1px 6px; border-radius: var(--df-radius-xs); background: rgba(255,217,61,0.15); color: var(--df-warning); border: 0.5px solid var(--df-border); }
|
||||
.mono-tag { margin-left: 6px; font-size: 10px; padding: var(--df-pad-chip); border-radius: var(--df-radius-xs); background: var(--df-warning-bg); color: var(--df-warning); border: 0.5px solid var(--df-border); }
|
||||
.bound-mark { color: var(--df-success); font-weight: 600; }
|
||||
.selection-count { margin-right: auto; font-size: 12px; color: var(--df-text-dim); }
|
||||
.import-box .modal-actions { align-items: center; }
|
||||
|
||||
/* ===== Toast ===== */
|
||||
.toast {
|
||||
position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
|
||||
padding: 10px 18px; border-radius: var(--df-radius-sm);
|
||||
font-size: 13px; z-index: 200; max-width: 80vw;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||
}
|
||||
.toast-info { background: var(--df-accent); color: #fff; }
|
||||
.toast-error { background: var(--df-danger); color: #fff; }
|
||||
/* ToastType 新增 'success' 兜底样式(本视图当前未用,补全避免裸类) */
|
||||
.toast-success { background: var(--df-success); color: #fff; }
|
||||
/* toast 样式已统一到全局 global.css .df-toast 族(+--bottom 底部变体) */
|
||||
</style>
|
||||
|
||||
+4
-22
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="settings">
|
||||
<Transition name="toast">
|
||||
<div v-if="toast.visible" class="toast" :class="'toast-' + toast.type">{{ toast.msg }}</div>
|
||||
<Transition name="df-toast">
|
||||
<div v-if="toast.visible" class="df-toast" :class="toast.type === 'error' ? 'df-toast--danger' : 'df-toast--' + toast.type">{{ toast.msg }}</div>
|
||||
</Transition>
|
||||
<ConfirmDialog :visible="confirmState.visible" :msg="confirmState.msg" :danger-label="$t('common.delete')" @result="answerConfirm" />
|
||||
<!-- 页面头部 -->
|
||||
@@ -313,25 +313,7 @@ onUnmounted(() => {
|
||||
<style scoped>
|
||||
.settings { padding: 16px 20px 20px; }
|
||||
|
||||
/* ===== 顶部 Toast 提示 ===== */
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: 16px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 1000;
|
||||
padding: 8px 16px;
|
||||
border-radius: var(--df-radius-sm);
|
||||
font-size: 13px;
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.3);
|
||||
}
|
||||
.toast-error { background: var(--df-danger-bg); color: var(--df-danger); border: 0.5px solid var(--df-danger); }
|
||||
.toast-warning { background: var(--df-warning-bg); color: var(--df-warning); border: 0.5px solid var(--df-warning); }
|
||||
.toast-info { background: var(--df-accent-bg); color: var(--df-accent); border: 0.5px solid var(--df-accent); }
|
||||
/* P0-2: 保存成功明确反馈(绿色),与 info(中性强调)区分 */
|
||||
.toast-success { background: var(--df-success-bg); color: var(--df-success); border: 0.5px solid var(--df-success); }
|
||||
.toast-enter-active, .toast-leave-active { transition: opacity 0.2s, transform 0.2s; }
|
||||
.toast-enter-from, .toast-leave-to { opacity: 0; transform: translate(-50%, -8px); }
|
||||
/* 顶部 Toast 提示:已消费 global.css .df-toast 四色族+过渡(2026-10-18 整洁波并轨) */
|
||||
|
||||
/* 确认弹层已替换为 ConfirmDialog 组件(不再需要自建 CSS) */
|
||||
|
||||
@@ -354,7 +336,7 @@ onUnmounted(() => {
|
||||
}
|
||||
|
||||
/* .btn / .btn-primary / .btn-ghost / .btn-sm 已迁移到 settings.css 全局,
|
||||
本壳的 toast/confirm 内联按钮沿用全局基础样式;此处仅保留全局未定义的 .btn-danger。 */
|
||||
本壳无特有按钮样式(.btn-danger 由 Projects/AdvancedSection 等使用处各自定义)。 */
|
||||
|
||||
/* ===== 窄屏响应式:nav 折叠为顶部横向 tab(由 SettingsNav is-horizontal 渲染) ===== */
|
||||
@media (max-width: 768px) {
|
||||
|
||||
+21
-24
@@ -123,12 +123,12 @@
|
||||
<!-- 基础分支(空值不显行) -->
|
||||
<div v-if="task.base_branch" class="info-item">
|
||||
<span class="label">{{ $t('taskDetail.baseBranch') }}</span>
|
||||
<span class="value mono">{{ task.base_branch }}</span>
|
||||
<span class="value df-mono">{{ task.base_branch }}</span>
|
||||
</div>
|
||||
<!-- 工作流定义(空值不显行) -->
|
||||
<div v-if="task.workflow_def_id" class="info-item">
|
||||
<span class="label">{{ $t('taskDetail.workflowDef') }}</span>
|
||||
<span class="value mono">{{ task.workflow_def_id }}</span>
|
||||
<span class="value df-mono">{{ task.workflow_def_id }}</span>
|
||||
</div>
|
||||
<!-- 创建/更新时间:最底小字(Problem4 ⑥) -->
|
||||
<div class="info-item timestamps">
|
||||
@@ -835,21 +835,18 @@ onBeforeUnmount(() => {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Problem4 ① 吸顶 header(推进按钮始终可见) */
|
||||
/* Problem4 ① 吸顶 header(推进按钮始终可见)
|
||||
高度/对齐交给全局 .page-header(46px 定高),此处仅保留吸顶所需的
|
||||
背景铺满/出血负边距/底部分割线,不再自造 padding 堆高度 */
|
||||
.task-detail-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: var(--df-bg);
|
||||
/* 留底部细分割线,与全局 page-header margin-bottom 协同(0.5px 边框规范) */
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 0.5px solid var(--df-border);
|
||||
/* 顶负 padding 抵消 .task-detail 的 16px 顶 padding,吸顶贴顶 */
|
||||
/* 负 margin 抵消 .task-detail 的内边距,吸顶时背景全宽贴顶 */
|
||||
margin: -16px -20px 0;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
padding-top: 16px;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
/* header-actions 内多个推进按钮 + refresh 排列(对齐全局 .header-actions gap:10px) */
|
||||
.task-detail-header .header-actions { flex-wrap: wrap; justify-content: flex-end; }
|
||||
@@ -869,12 +866,12 @@ onBeforeUnmount(() => {
|
||||
.wf-progress-hint { color: var(--df-success); }
|
||||
.wf-progress-hint-fail { color: var(--df-danger); }
|
||||
|
||||
/* F-04 review 轮次徽章 */
|
||||
/* F-04 review 轮次徽章(背景走 warning 语义 token) */
|
||||
.review-rounds-badge {
|
||||
font-size: 11px;
|
||||
font-size: var(--df-fs-aux);
|
||||
color: var(--df-warning);
|
||||
background: rgba(255,217,61,0.12);
|
||||
padding: 3px 8px;
|
||||
background: var(--df-warning-bg);
|
||||
padding: var(--df-pad-badge);
|
||||
border-radius: var(--df-radius-xs);
|
||||
margin-left: 8px;
|
||||
white-space: nowrap;
|
||||
@@ -884,8 +881,8 @@ onBeforeUnmount(() => {
|
||||
/* 状态色类已全局化至 components.css(scoped 删除,消除漂移) */
|
||||
|
||||
.priority-badge {
|
||||
font-size: 10px; font-weight: 500;
|
||||
padding: 1px 6px;
|
||||
font-size: var(--df-fs-meta); font-weight: 500;
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
}
|
||||
/* 四档统一 color-mix 派生自语义 token(对齐 Tasks.vue 列表同款,主题切换语义不变) */
|
||||
@@ -977,16 +974,16 @@ onBeforeUnmount(() => {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
font-size: 12px;
|
||||
font-size: var(--df-fs-ctrl);
|
||||
color: var(--df-text-secondary);
|
||||
background: var(--df-accent-bg);
|
||||
padding: 2px 8px;
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
font-family: monospace;
|
||||
font-family: var(--df-font-mono);
|
||||
}
|
||||
.branch-icon { color: var(--df-accent); }
|
||||
|
||||
.mono { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 12px; }
|
||||
/* mono 数据字走全局 .df-mono(模板类名已并轨,本地副本删除) */
|
||||
|
||||
.empty-hint {
|
||||
text-align: center; padding: 24px 12px;
|
||||
@@ -1086,7 +1083,7 @@ onBeforeUnmount(() => {
|
||||
background: var(--df-bg-card);
|
||||
border: 0.5px solid var(--df-border);
|
||||
border-radius: var(--df-radius-sm);
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.25);
|
||||
box-shadow: var(--df-shadow-sm);
|
||||
z-index: 20;
|
||||
padding: 6px 0;
|
||||
}
|
||||
@@ -1111,7 +1108,7 @@ onBeforeUnmount(() => {
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
.quick-menu-item:hover { background: rgba(255,255,255,0.06); }
|
||||
.quick-menu-item:hover { background: var(--df-hover); }
|
||||
.quick-menu-divider {
|
||||
height: 0.5px;
|
||||
background: var(--df-border);
|
||||
@@ -1152,9 +1149,9 @@ onBeforeUnmount(() => {
|
||||
.detail-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
/* 窄屏 header-actions 内推进按钮可能换行,允许并压缩间距 */
|
||||
/* 窄屏 header-actions 内推进按钮可能换行,允许并压缩间距(定高改自适应防溢出) */
|
||||
@media (max-width: 720px) {
|
||||
.task-detail-header { flex-wrap: wrap; }
|
||||
.task-detail-header { flex-wrap: wrap; height: auto; padding-top: 8px; padding-bottom: 8px; }
|
||||
.task-detail-header .header-left { flex: 1 1 100%; margin-bottom: 8px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
+30
-45
@@ -151,14 +151,14 @@
|
||||
<button class="task-quick-btn" :title="$t('tasks.quickActions')" :aria-label="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(row.task.id)">⚙️</button>
|
||||
<div v-if="quickMenuId === row.task.id" class="quick-menu" @click.stop>
|
||||
<div class="quick-menu-section">
|
||||
<div class="quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
|
||||
<div class="df-sec-h quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
|
||||
<button v-for="s in quickStatusesFor(row.task)" :key="s.key" class="quick-menu-item" @click="quickAdvance(row.task.id, s.key)">
|
||||
<span>{{ s.icon }}</span>{{ s.label }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="quick-menu-divider"></div>
|
||||
<div class="quick-menu-section">
|
||||
<div class="quick-menu-label">{{ $t('tasks.quickPriority') }}</div>
|
||||
<div class="df-sec-h quick-menu-label">{{ $t('tasks.quickPriority') }}</div>
|
||||
<button v-for="p in quickPriorities" :key="p.value" class="quick-menu-item" @click="quickPriority(row.task.id, p.value)">
|
||||
<span :class="p.cls">●</span>{{ p.label }}
|
||||
</button>
|
||||
@@ -208,14 +208,14 @@
|
||||
<button class="task-quick-btn" :title="$t('tasks.quickActions')" :aria-label="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(child.id)">⚙️</button>
|
||||
<div v-if="quickMenuId === child.id" class="quick-menu" @click.stop>
|
||||
<div class="quick-menu-section">
|
||||
<div class="quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
|
||||
<div class="df-sec-h quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
|
||||
<button v-for="s in quickStatusesFor(child)" :key="s.key" class="quick-menu-item" @click="quickAdvance(child.id, s.key)">
|
||||
<span>{{ s.icon }}</span>{{ s.label }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="quick-menu-divider"></div>
|
||||
<div class="quick-menu-section">
|
||||
<div class="quick-menu-label">{{ $t('tasks.quickPriority') }}</div>
|
||||
<div class="df-sec-h quick-menu-label">{{ $t('tasks.quickPriority') }}</div>
|
||||
<button v-for="p in quickPriorities" :key="p.value" class="quick-menu-item" @click="quickPriority(child.id, p.value)">
|
||||
<span :class="p.cls">●</span>{{ p.label }}
|
||||
</button>
|
||||
@@ -256,14 +256,14 @@
|
||||
<button class="task-quick-btn" :title="$t('tasks.quickActions')" :aria-label="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(row.task.id)">⚙️</button>
|
||||
<div v-if="quickMenuId === row.task.id" class="quick-menu" @click.stop>
|
||||
<div class="quick-menu-section">
|
||||
<div class="quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
|
||||
<div class="df-sec-h quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
|
||||
<button v-for="s in quickStatusesFor(row.task)" :key="s.key" class="quick-menu-item" @click="quickAdvance(row.task.id, s.key)">
|
||||
<span>{{ s.icon }}</span>{{ s.label }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="quick-menu-divider"></div>
|
||||
<div class="quick-menu-section">
|
||||
<div class="quick-menu-label">{{ $t('tasks.quickPriority') }}</div>
|
||||
<div class="df-sec-h quick-menu-label">{{ $t('tasks.quickPriority') }}</div>
|
||||
<button v-for="p in quickPriorities" :key="p.value" class="quick-menu-item" @click="quickPriority(row.task.id, p.value)">
|
||||
<span :class="p.cls">●</span>{{ p.label }}
|
||||
</button>
|
||||
@@ -405,8 +405,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 快捷操作失败 toast(WK-13,对齐 Projects.vue 操作反馈) -->
|
||||
<div v-if="toast.visible" class="toast" :class="'toast-' + toast.type">{{ toast.msg }}</div>
|
||||
<!-- 快捷操作失败 toast(WK-13,对齐 Projects.vue 操作反馈;全局 .df-toast 族+底部变体) -->
|
||||
<div v-if="toast.visible" class="df-toast df-toast--bottom" :class="toast.type === 'error' ? 'df-toast--danger' : 'df-toast--' + toast.type">{{ toast.msg }}</div>
|
||||
|
||||
<!-- 确认弹层(删除任务,替代原生 window.confirm) -->
|
||||
<ConfirmDialog :visible="confirmState.visible" :msg="confirmState.msg" @result="answerConfirm" />
|
||||
@@ -1041,8 +1041,8 @@ onUnmounted(() => {
|
||||
margin-bottom: 12px;
|
||||
padding: 8px 10px;
|
||||
border-radius: var(--df-radius-sm);
|
||||
background: var(--df-danger-bg, rgba(220, 38, 38, 0.08));
|
||||
color: var(--df-danger, #dc2626);
|
||||
background: var(--df-danger-bg);
|
||||
color: var(--df-danger);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@@ -1132,14 +1132,13 @@ onUnmounted(() => {
|
||||
border-bottom: 0.5px solid var(--df-border);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.kanban-col-icon { font-size: 13px; }
|
||||
.kanban-col-name { font-size: 13px; font-weight: 500; color: var(--df-text); flex: 1; }
|
||||
.kanban-col-count {
|
||||
font-size: 11px;
|
||||
color: var(--df-text-dim);
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
padding: 1px 8px;
|
||||
border-radius: 8px;
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
}
|
||||
.kanban-col-body {
|
||||
flex: 1;
|
||||
@@ -1169,7 +1168,7 @@ onUnmounted(() => {
|
||||
cursor: pointer;
|
||||
transition: box-shadow 0.15s, border-color 0.15s;
|
||||
}
|
||||
.task-card:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); border-color: var(--df-accent); }
|
||||
.task-card:hover { box-shadow: var(--df-shadow-sm); border-color: var(--df-accent); }
|
||||
.task-card.sortable-ghost { opacity: 0.5; }
|
||||
/* 父卡禁拖:去掉抓取光标、左侧描边提示这是聚合容器卡 */
|
||||
.task-card--parent { cursor: default; border-left: 2px solid var(--df-accent); }
|
||||
@@ -1195,9 +1194,9 @@ onUnmounted(() => {
|
||||
.parent-tag {
|
||||
font-size: 11px;
|
||||
color: var(--df-text-dim);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 1px 6px;
|
||||
border-radius: 6px;
|
||||
background: var(--df-hover);
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
max-width: 140px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -1207,8 +1206,8 @@ onUnmounted(() => {
|
||||
font-size: 11px;
|
||||
color: var(--df-text-dim);
|
||||
border: 0.5px solid var(--df-border);
|
||||
padding: 1px 6px;
|
||||
border-radius: 6px;
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
}
|
||||
|
||||
/* page-header / page-header h1 / header-actions 已提取到全局 global.css */
|
||||
@@ -1269,7 +1268,7 @@ onUnmounted(() => {
|
||||
gap: 3px;
|
||||
padding: 2px 8px;
|
||||
border: 0.5px solid var(--df-border);
|
||||
border-radius: 10px;
|
||||
border-radius: var(--df-radius-xs);
|
||||
background: transparent;
|
||||
color: var(--df-text-dim);
|
||||
font-size: 11px;
|
||||
@@ -1330,8 +1329,8 @@ onUnmounted(() => {
|
||||
font-size: 11px;
|
||||
color: var(--df-text-dim);
|
||||
background: rgba(255,255,255,0.06);
|
||||
padding: 1px 8px;
|
||||
border-radius: 8px;
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
}
|
||||
|
||||
/* 任务条目(紧凑) */
|
||||
@@ -1344,7 +1343,7 @@ onUnmounted(() => {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 14px;
|
||||
border-bottom: 0.5px solid rgba(255,255,255,0.03);
|
||||
border-bottom: 0.5px solid var(--df-hover);
|
||||
transition: background 0.1s;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1372,7 +1371,7 @@ onUnmounted(() => {
|
||||
.priority-badge {
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
padding: 1px 6px;
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -1446,8 +1445,8 @@ onUnmounted(() => {
|
||||
font-weight: 600;
|
||||
color: var(--df-text-dim);
|
||||
background: rgba(255,255,255,0.06);
|
||||
padding: 1px 6px;
|
||||
border-radius: 8px;
|
||||
padding: var(--df-pad-chip);
|
||||
border-radius: var(--df-radius-xs);
|
||||
flex-shrink: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -1488,18 +1487,13 @@ onUnmounted(() => {
|
||||
background: var(--df-bg-card);
|
||||
border: 0.5px solid var(--df-border);
|
||||
border-radius: var(--df-radius-sm);
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,0.25);
|
||||
box-shadow: var(--df-shadow-sm);
|
||||
z-index: 20;
|
||||
padding: 6px 0;
|
||||
}
|
||||
.quick-menu-section { padding: 4px 0; }
|
||||
.quick-menu-label {
|
||||
font-size: 10px;
|
||||
color: var(--df-text-dim);
|
||||
padding: 2px 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
/* 小节头公共类 .df-sec-h,此处仅补菜单内缩进 */
|
||||
.quick-menu-label { padding: 2px 12px; }
|
||||
.quick-menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1513,7 +1507,7 @@ onUnmounted(() => {
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
.quick-menu-item:hover { background: rgba(255,255,255,0.06); }
|
||||
.quick-menu-item:hover { background: var(--df-hover); }
|
||||
.quick-menu-divider {
|
||||
height: 0.5px;
|
||||
background: var(--df-border);
|
||||
@@ -1521,16 +1515,7 @@ onUnmounted(() => {
|
||||
}
|
||||
.quick-menu-danger { color: var(--df-danger); }
|
||||
|
||||
/* ===== 快捷操作失败 toast(WK-13,对齐 Projects.vue 操作反馈) ===== */
|
||||
.toast {
|
||||
position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
|
||||
padding: 10px 18px; border-radius: var(--df-radius-sm);
|
||||
font-size: 13px; z-index: 200; max-width: 80vw;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||
}
|
||||
.toast-info { background: var(--df-accent); color: #fff; }
|
||||
.toast-error { background: var(--df-danger); color: #fff; }
|
||||
.toast-success { background: var(--df-success); color: #fff; }
|
||||
/* 快捷操作失败 toast 样式已统一到全局 global.css .df-toast 族(+--bottom 底部变体) */
|
||||
|
||||
/* 空态 */
|
||||
/* empty-state 已提取到全局 global.css */
|
||||
|
||||
Reference in New Issue
Block a user