提交 18368a91 authored 作者: 张伊明's avatar 张伊明

feat 重构深度挖掘-流程概要全部样式

上级 02714a38
流水线 #269 已通过 于阶段
in 1 分 45 秒
......@@ -153,7 +153,7 @@
class="item-box"
v-for="item in sharedEvents"
:key="`shared-${item.id}`"
style="width: 280px; flex-shrink: 0;"
:style="{ width: TIMELINE_ITEM_WIDTH_PX + 'px', flexShrink: 0 }"
>
<div class="item-time">{{ item.actionDate }}</div>
<div class="item-box-dot"></div>
......@@ -211,7 +211,15 @@ const dialogPos = ref({ left: "0px", top: "0px" });
const ORG_SENATE = "参议院";
const ORG_HOUSE = "众议院";
const PRESIDENT_KEYWORD = "呈递给总统";
/** 卡片宽度;同一条时间线上相邻圆点间距 ≥ 此值,避免同轨卡片横向重叠 */
const TIMELINE_ITEM_WIDTH_PX = 280;
/** 时间线锚点为圆点;与样式 .item-box-dot { left: 10px } 一致 */
const DOT_LEFT_IN_ITEM_BOX_PX = 10;
/** 与 scoped 样式中 .top/.bottom .content-box 的 margin-left 一致,用于跨轨圆点与「两密点中点」对齐 */
const SENATE_CONTENT_BOX_MARGIN_LEFT_PX = 134;
const HOUSE_CONTENT_BOX_MARGIN_LEFT_PX = 30;
/** 双轨主线在最后一个圆点/卡片之后保留的空白(原先用整卡宽 W 导致尾部过长) */
const TIMELINE_LINE_TAIL_PADDING_PX = 48;
const ARROW_SEGMENT_TOTAL_PX = 16;
const DIAGONAL_LINE_WIDTH_PX = 127;
......@@ -281,50 +289,98 @@ const dualLaneTimeline = computed(() => {
.filter((item) => !isDualEvent(item));
});
const senateEventsPositioned = computed(() => {
const list = [];
let slotIndex = 0;
dualLaneTimeline.value.forEach((item) => {
if (!isSenateEvent(item)) return;
list.push({
key: item.id,
/**
* 双轨事件已按时间排好(dualLaneTimeline)。依次放置:与前一条同轨则绝对 x + W,
* 异轨则以前一条圆点绝对位置为锚 + 0.5W(方案 C)。单轨(灰线)仍用 sharedEvents 顺序定宽。
*/
const dualLaneLayout = computed(() => {
const U = dualLaneTimeline.value;
const W = TIMELINE_ITEM_WIDTH_PX;
const chamberRowSenate = (item) => {
const s = isSenateEvent(item);
const h = isHouseEvent(item);
if (s && !h) return true;
if (h && !s) return false;
return Boolean(s);
};
const idxInU = (item) => U.indexOf(item);
const toSlots = (list, posByItem) =>
list.map((item) => ({
key: `${idxInU(item)}-${item.id ?? "e"}`,
item,
left: slotIndex * TIMELINE_ITEM_WIDTH_PX
});
slotIndex += 1;
});
return list;
});
left: (posByItem.get(item) ?? 0) - DOT_LEFT_IN_ITEM_BOX_PX
}));
const houseEventsPositioned = computed(() => {
const list = [];
let slotIndex = 0;
dualLaneTimeline.value.forEach((item) => {
if (!isHouseEvent(item)) return;
list.push({
key: item.id,
item,
left: slotIndex * TIMELINE_ITEM_WIDTH_PX
});
slotIndex += 1;
});
return list;
if (!U.length) {
return { senateSlots: [], houseSlots: [], maxDualLaneRightPx: 0 };
}
const posByItem = new Map();
let prevAbs = null;
let prevSenate = null;
for (const item of U) {
const sen = chamberRowSenate(item);
const margin = sen ? SENATE_CONTENT_BOX_MARGIN_LEFT_PX : HOUSE_CONTENT_BOX_MARGIN_LEFT_PX;
const absDot =
prevAbs === null ? margin : prevAbs + (sen === prevSenate ? W : W / 2);
posByItem.set(item, absDot - margin);
prevAbs = absDot;
prevSenate = sen;
}
/** 相对 content-box 左缘:卡片右边界 = layoutDotX - DOT_LEFT + W */
let maxDualLaneRightPx = 0;
for (const item of U) {
const layoutDotX = posByItem.get(item) ?? 0;
const rightPx = layoutDotX - DOT_LEFT_IN_ITEM_BOX_PX + W;
maxDualLaneRightPx = Math.max(maxDualLaneRightPx, rightPx);
}
return {
senateSlots: toSlots(
U.filter((item) => isSenateEvent(item)),
posByItem
),
houseSlots: toSlots(
U.filter((item) => isHouseEvent(item)),
posByItem
),
maxDualLaneRightPx
};
});
const senateEventsPositioned = computed(() => dualLaneLayout.value.senateSlots);
const houseEventsPositioned = computed(() => dualLaneLayout.value.houseSlots);
const sharedEvents = computed(() => {
return sortedTimeline.value.filter((item, idx) => {
return isDualEvent(item) || idx >= mergeIndexExclusive.value;
});
});
const dualLaneCount = computed(() => {
return Math.max(senateEventsPositioned.value.length, houseEventsPositioned.value.length);
/** 双轨 content-box 内所需宽度:最后卡片右缘 + 尾部留白(与 maxLineWidth 中的 extent 一致) */
const dualLaneContentExtentPx = computed(() => {
if (!dualLaneTimeline.value.length) return 0;
return (
dualLaneLayout.value.maxDualLaneRightPx + TIMELINE_LINE_TAIL_PADDING_PX
);
});
/**
* 双轨横线(top-line / bottom-line 共用)宽度:起点 left:110,需画到与卡片区右缘对齐。
* 右缘 x = 120 + 参院 margin + extent = 254 + extent,故宽度 = 254 + extent - 110 = 144 + extent。
* 旧式 254+extent 多 110px,导致上下线都偏长。
*/
const maxLineWidth = computed(() => {
const senateWidth = 254 + dualLaneCount.value * TIMELINE_ITEM_WIDTH_PX;
const houseWidth = 150 + dualLaneCount.value * TIMELINE_ITEM_WIDTH_PX;
return Math.max(senateWidth, houseWidth);
if (!dualLaneTimeline.value.length) {
return Math.max(254, 150);
}
const extent = dualLaneContentExtentPx.value;
return 120 + SENATE_CONTENT_BOX_MARGIN_LEFT_PX + extent - 110;
});
const lineWidth = computed(() => `${maxLineWidth.value}px`);
......@@ -350,22 +406,41 @@ const rightArrowCount = computed(() => {
return Math.max(1, Math.ceil(sharedLineWidth.value / ARROW_SEGMENT_TOTAL_PX));
});
/** 参院 content 起点更靠右(margin 134 vs 30),众院 box 需多 104px 才能与参院右缘对齐 */
const CONTENT_BOX_WIDTH_DELTA_SENATE_HOUSE_PX =
SENATE_CONTENT_BOX_MARGIN_LEFT_PX - HOUSE_CONTENT_BOX_MARGIN_LEFT_PX;
const senateBoxStyle = computed(() => ({
width: `${maxLineWidth.value + 110 - 254}px`,
width: `${
dualLaneTimeline.value.length
? dualLaneContentExtentPx.value
: 110
}px`,
justifyContent: "flex-start"
}));
const houseBoxStyle = computed(() => ({
width: `${maxLineWidth.value + 110 - 150}px`,
width: `${
dualLaneTimeline.value.length
? dualLaneContentExtentPx.value + CONTENT_BOX_WIDTH_DELTA_SENATE_HOUSE_PX
: 214
}px`,
justifyContent: "flex-start"
}));
const rightPos = computed(() => `${maxLineWidth.value + 90}px`);
const sharedBoxStyle = computed(() => ({
left: `${maxLineWidth.value + 219}px`,
width: `${Math.max(sharedLineWidth.value, sharedEvents.value.length * TIMELINE_ITEM_WIDTH_PX)}px`
}));
const sharedBoxStyle = computed(() => {
const rightTopPx = Number.parseFloat(String(rightTop.value)) || 0;
const rightCenterY = rightTopPx + 12;
return {
left: `${maxLineWidth.value + 230}px`,
top: `${rightCenterY}px`,
transform: "translateY(-100%)",
width: `${Math.max(sharedLineWidth.value, sharedEvents.value.length * TIMELINE_ITEM_WIDTH_PX)}px`
};
});
const topLineEndRef = ref(null);
const bottomLineEndRef = ref(null);
......@@ -547,13 +622,18 @@ const updateRightTop = () => {
}
}
/* .top 高 260px,时间线 top:242px;卡片下缘应对齐线顶:距容器底 18px */
.content-box {
position: relative;
margin-left: 134px;
margin-bottom: 19px;
margin-bottom: 0;
align-self: stretch;
min-height: 0;
.item-box {
position: absolute;
top: auto;
bottom: 18px;
}
}
}
......@@ -808,7 +888,7 @@ const updateRightTop = () => {
.shared-content-box {
position: absolute;
top: 170px;
top: 254px;
display: flex;
.item-box {
......
......@@ -834,6 +834,7 @@ onMounted(() => {
flex-shrink: 1;
max-width: 170px;
text-align: center;
margin-bottom: 10px;
}
.nameItemActive {
......
......@@ -46,7 +46,7 @@
<div class="chart-ai-wrap">
<div :class="['right-box2-main', { 'right-box-main--full': !domainFooterText }]" id="chart2"></div>
<div class="overview-tip-row">
<TipTab class="overview-tip" />
<TipTab class="overview-tip" :text="'涉华科技法案数量及通过率变化趋势,数据来源:美国国会官网'"/>
<AiButton class="overview-tip-action" @mouseenter="handleShowAiPane('domain')" />
</div>
<div v-if="aiPaneVisible.domain" class="overview-ai-pane"
......@@ -72,7 +72,7 @@
<div class="chart-ai-wrap">
<div :class="['right-box1-main', { 'right-box-main--full': !limitFooterText }]" id="chart1"></div>
<div class="overview-tip-row">
<TipTab class="overview-tip" />
<TipTab class="overview-tip" :text="'涉华科技法案数量及通过率变化趋势,数据来源:美国国会官网'"/>
<AiButton class="overview-tip-action" @mouseenter="handleShowAiPane('limit')" />
</div>
<div v-if="aiPaneVisible.limit" class="overview-ai-pane"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论