feat: 卡片选中效果(activeSplitId) + 埋点只在打开工作区时计数
This commit is contained in:
@@ -53,6 +53,10 @@ const SNAP_PX = 32
|
||||
const MARKET_URL = 'https://github.com/hikariming/dshfind'
|
||||
/** 已报到卡片的 CSS order 偏移:未上报(order=0)的 v1 卡片永远排在已上报卡片之前。 */
|
||||
const ORDER_OFFSET = 1000
|
||||
/** 自带分栏实现的遗留项目(如 travelatlas,未接入 openSplit 引擎):埋点用冷却去重,避免每次点击置顶 */
|
||||
const LEGACY_SPLIT_IDS = new Set(['travelatlas'])
|
||||
/** 遗留项目埋点冷却(毫秒):同 id 两次计使用的最小间隔 */
|
||||
const LEGACY_BUMP_COOLDOWN = 15000
|
||||
/** 落点判定余量:松手时指针越出有效落点区(超出底部/顶部/侧边)即视为「无有效落点」。 */
|
||||
const OVER_BOTTOM_PX = 24
|
||||
const OVER_TOP_PX = 24
|
||||
@@ -168,6 +172,9 @@ function WorktableSection(props: any) {
|
||||
const [bottomInset, setBottomInset] = useState(0)
|
||||
const bottomInsetRef = useRef(0)
|
||||
const [floatGeo, setFloatGeo] = useState<{ left: number; width: number | null } | null>(null)
|
||||
const [activeSplitId, setActiveSplitId] = useState<string | null>(() =>
|
||||
splitStore.active && splitStore.spec ? splitStore.spec.id : null,
|
||||
)
|
||||
const floatRef = useRef<FloatRect | null>(null)
|
||||
|
||||
const persistView = (patch: Partial<ViewState>) => {
|
||||
@@ -193,6 +200,11 @@ function WorktableSection(props: any) {
|
||||
return () => { registryStore.listeners.delete(sync) }
|
||||
}, [])
|
||||
|
||||
// 分栏引擎激活态 → activeSplitId(卡片据此显示选中效果)
|
||||
useEffect(() => splitStore.subscribe(() => {
|
||||
setActiveSplitId(splitStore.active && splitStore.spec ? splitStore.spec.id : null)
|
||||
}), [])
|
||||
|
||||
// 侧边栏折叠/展开:保持原停靠位置(不再回弹 footer);折叠态由项目图标框承载。
|
||||
// 折叠且浮动时:等折叠动画结束(320/750ms 双次重测,取收敛后的几何)再以 fixed 定位
|
||||
// 图标框到拖前高度——避免在过渡帧上测得展开态宽度导致图标框偏离窄栏中心。
|
||||
@@ -264,17 +276,40 @@ function WorktableSection(props: any) {
|
||||
})
|
||||
}, [])
|
||||
|
||||
const engineIdsRef = useRef<Set<string>>(new Set())
|
||||
const lastLegacyBumpRef = useRef<Record<string, number>>({})
|
||||
|
||||
/** 使用埋点:仅「工作区真正打开」计一次使用;点击关闭/重复点击不计(避免每次点击置顶) */
|
||||
const reportUsed = useCallback((id: string) => {
|
||||
if (typeof id !== 'string' || !id) return
|
||||
const now = Date.now()
|
||||
persistProjects((prev) => {
|
||||
if (prev.lastUsed[id] === now) return prev
|
||||
return { ...prev, lastUsed: { ...prev.lastUsed, [id]: now } }
|
||||
})
|
||||
const bump = () => {
|
||||
persistProjects((prev) => {
|
||||
if (prev.lastUsed[id] === now) return prev
|
||||
return { ...prev, lastUsed: { ...prev.lastUsed, [id]: now } }
|
||||
})
|
||||
}
|
||||
const engineOpen = splitStore.active && splitStore.spec?.id === id
|
||||
const knownEngine = engineIdsRef.current.has(id)
|
||||
if (engineOpen) {
|
||||
bump() // 引擎项目:本次点击打开了工作区 → 计一次使用
|
||||
} else if (knownEngine) {
|
||||
// 引擎项目:本次是关闭/重复点击 → 不计
|
||||
return
|
||||
} else if (LEGACY_SPLIT_IDS.has(id)) {
|
||||
// 遗留自带分栏的项目:冷却去重(打开计一次;快速开关/关闭点击不重复计)
|
||||
if (now - (lastLegacyBumpRef.current[id] ?? 0) > LEGACY_BUMP_COOLDOWN) {
|
||||
lastLegacyBumpRef.current[id] = now
|
||||
bump()
|
||||
}
|
||||
} else {
|
||||
bump() // 无判定依据的普通项目:保持原行为
|
||||
}
|
||||
}, [])
|
||||
|
||||
/** 分栏工作区入口(M1 引擎):项目卡片调用 openSplit(spec) 打开声明式布局 */
|
||||
const openSplit = useCallback((spec: LayoutSpec) => {
|
||||
engineIdsRef.current.add(spec.id)
|
||||
splitStore.open(spec)
|
||||
}, [])
|
||||
|
||||
@@ -305,6 +340,7 @@ function WorktableSection(props: any) {
|
||||
reportMeta,
|
||||
reportUsed,
|
||||
openSplit,
|
||||
activeSplitId,
|
||||
}
|
||||
|
||||
// ── 拖动(≡ 手柄,与 v1 相同)──
|
||||
|
||||
@@ -246,3 +246,17 @@
|
||||
(覆盖「先开审图再点旅行」的反向场景)。
|
||||
- 验证:构建 + node --check 通过;服务端实时下发(含 split-claim/yieldObserver/ta_splitClose
|
||||
标记);待用户刷新后实测两个方向与反选。
|
||||
|
||||
## 补记(卡片选中效果 + 埋点收敛)
|
||||
|
||||
- 用户反馈:① 建筑审图打开后卡片无「选中」效果(旅行 Atlas 有);② 「最近」排序下每次点击
|
||||
都置顶,体验差——应只在工作区真正打开(有改动)时计一次使用。
|
||||
- 实现:
|
||||
① owner props 新增 activeSplitId(工作台订阅 splitStore 激活态下发);planreview 卡片
|
||||
data-on=active 高亮(蓝边 + 名称高亮),样式与旅行 Atlas 同类;
|
||||
② 埋点收敛(worktable reportUsed 过滤):引擎项目(调用过 openSplit 的 id)仅在本次点击
|
||||
导致工作区打开时计使用,关闭/重复点击不计;遗留自带分栏的项目(travelatlas,不改其代码)
|
||||
用 15s 冷却去重;无判定依据的普通项目保持原行为;
|
||||
③ planreview 无需改埋点逻辑(引擎内统一过滤)。
|
||||
- 验证:两插件构建 + node --check 通过;服务端实时下发(含 activeSplitId/
|
||||
LEGACY_BUMP_COOLDOWN 标记);待用户刷新实测。
|
||||
|
||||
Reference in New Issue
Block a user