优化: 会话入口与对话交互打磨
- 完成卡点开子代理轨迹浮层,任务抽屉关联会话跳转 - 提及片段编辑差分三向判定,不再错位 - 长回复折叠完成瞬间锚定消息顶,视口不跳 - 空编辑/技能无匹配/回填覆盖草稿均有提示确认 - 队列编辑态切会话重置,刷新快捷键不再误触 - git 变更面板去重缓存,项目卡骨架与溢出重测
This commit is contained in:
@@ -24,7 +24,10 @@
|
||||
<div class="card-footer">
|
||||
<div class="footer-stat">
|
||||
<span class="stat-icon">📁</span>
|
||||
<span>{{ moduleCount }}</span>
|
||||
<!-- UX走查 P3-6: 工程数异步入场,加载中显骨架条占位(对齐 GitChanges shimmer 范式),
|
||||
防未加载数先显 0 再跳变——真 0 与"还没加载"不可混淆 -->
|
||||
<span v-if="moduleCountLoading" class="stat-skeleton" aria-hidden="true"></span>
|
||||
<span v-else>{{ moduleCount }}</span>
|
||||
</div>
|
||||
<div class="footer-stat">
|
||||
<span class="stat-icon">📅</span>
|
||||
@@ -48,7 +51,7 @@
|
||||
// 依赖均为无副作用纯函数 + 共享常量;删除走 emit 交回父组件处理(confirm 弹层 + store 调用)。
|
||||
// view prop:'list'(紧凑,默认)/'card'(宽松);描述 max-height 截断 + 展开/收起。
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ref, onMounted, watch, nextTick } from 'vue'
|
||||
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
|
||||
import { formatDate } from '@/utils/time'
|
||||
import { parseStack } from '@/utils/project'
|
||||
import { stripMd } from '@/utils/markdown'
|
||||
@@ -71,11 +74,14 @@ const router = useRouter()
|
||||
|
||||
// 工程数(异步拉取,展示在卡片底部)
|
||||
const moduleCount = ref(0)
|
||||
// UX走查 P3-6: 加载态标记,模板据此显骨架占位而非 0(成功/失败都收 loading,失败仍显 0 属既有约定)
|
||||
const moduleCountLoading = ref(true)
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const list = await moduleApi.listProjectModules(props.project.id)
|
||||
moduleCount.value = list.length
|
||||
} catch { /* 老项目无工程记录不报错 */ }
|
||||
moduleCountLoading.value = false
|
||||
// DOM 渲染完成后测描述是否溢出(决定是否显示「展开」)
|
||||
await nextTick()
|
||||
measureDesc()
|
||||
@@ -91,6 +97,8 @@ const descExpanded = ref(false)
|
||||
function measureDesc() {
|
||||
const el = descRef.value
|
||||
if (!el) return
|
||||
// 展开态无行截断,测出的一律是"未溢出",会误收起按钮致无法「收起」;展开期间维持原判定
|
||||
if (descExpanded.value) return
|
||||
// scrollHeight > clientHeight 说明被 max-height 截断了
|
||||
descOverflow.value = el.scrollHeight - el.clientHeight > 1
|
||||
}
|
||||
@@ -98,6 +106,13 @@ function measureDesc() {
|
||||
// 描述/视图模式变化后重新测量(描述异步入库或切 view 行数阈值变,按钮显隐需重算)
|
||||
watch(() => props.project.description, () => nextTick(measureDesc))
|
||||
watch(() => props.view, () => nextTick(measureDesc))
|
||||
// 收起后重测:展开期间判定被冻结,若窗口已放宽到不溢出,收起时自校正防残留多余「展开」按钮
|
||||
watch(descExpanded, (v) => { if (!v) nextTick(measureDesc) })
|
||||
|
||||
// UX走查 P3-6: 窗口尺寸变化会改描述可用宽度,截断与否需重测,否则「展开」按钮显隐失准
|
||||
function onWinResize() { measureDesc() }
|
||||
onMounted(() => window.addEventListener('resize', onWinResize))
|
||||
onBeforeUnmount(() => window.removeEventListener('resize', onWinResize))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -196,6 +211,22 @@ watch(() => props.view, () => nextTick(measureDesc))
|
||||
}
|
||||
.stat-icon { font-size: 13px; }
|
||||
|
||||
/* UX走查 P3-6: 工程数加载占位骨架条(shimmer 配方对齐 GitChanges .gc-skeleton-row),
|
||||
宽度约两位数字占位,高度对齐 12px 字号,防 0 起显跳变 */
|
||||
.stat-skeleton {
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 12px;
|
||||
border-radius: 3px;
|
||||
background: linear-gradient(90deg, rgba(255,255,255,0.04) 0%, rgba(255,255,255,0.08) 50%, rgba(255,255,255,0.04) 100%);
|
||||
background-size: 200% 100%;
|
||||
animation: pc-shimmer 1.5s infinite linear;
|
||||
}
|
||||
@keyframes pc-shimmer {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
.card-top-actions { display: flex; align-items: center; gap: 8px; }
|
||||
.card-del-btn {
|
||||
background: transparent; border: none; cursor: pointer;
|
||||
|
||||
Reference in New Issue
Block a user