提交 02714a38 authored 作者: 张伊明's avatar 张伊明

fix 修改深度挖掘-流程概要样式

上级 a71756d8
流水线 #254 已通过 于阶段
in 1 分 35 秒
...@@ -2,68 +2,93 @@ ...@@ -2,68 +2,93 @@
<div class="process-overview-wrap"> <div class="process-overview-wrap">
<AnalysisBox title="流程概要" :showAllBtn="false"> <AnalysisBox title="流程概要" :showAllBtn="false">
<div class="main"> <div class="main">
<div class="left" :style="{ width: (maxLineWidth + 250) + 'px' }"> <div class="left" :style="{ width: boardWidth + 'px' }">
<div class="top"> <div class="top">
<div class="top-line" :style="{ width: lineWidth }"> <div class="top-line" :style="{ width: lineWidth }">
<div class="top-line1" ref="topLineEndRef"></div> <div class="arrow-track">
<div
class="arrow-segment arrow-segment-top"
v-for="i in mainArrowCount"
:key="`top-main-${i}`"
></div>
</div>
<div class="top-line1" ref="topLineEndRef">
<div class="arrow-track">
<div
class="arrow-segment arrow-segment-top"
v-for="i in diagonalArrowCount"
:key="`top-diagonal-${i}`"
></div>
</div>
</div>
</div> </div>
<div class="start"> <div class="start">
<div class="icon"> <div class="icon">
<img src="./assets/images/logo1.png" alt="" /> <img src="./assets/images/logo1.png" alt="" />
</div> </div>
<div class="name">{{ "参议院" }}</div> <div class="name">参议院</div>
</div> </div>
<div class="content-box" :style="senateBoxStyle"> <div class="content-box" :style="senateBoxStyle">
<div <div
class="item-box" class="item-box"
v-for="slot in senateSlots" v-for="slot in senateEventsPositioned"
:key="slot.key" :key="slot.key"
style="width: 280px; flex-shrink: 0;" :style="{ left: slot.left + 'px', width: TIMELINE_ITEM_WIDTH_PX + 'px' }"
> >
<template v-if="slot.item"> <div class="item-box-dot">
<div class="item-box-dot"> <img src="./assets/images/top-line-dot.png" alt="" />
<img src="./assets/images/top-line-dot.png" alt="" /> </div>
</div> <div class="item-content">
<div class="item-content"> <div class="item-header">
<div class="item-header"> <div class="item-title" :title="slot.item.actionTitle">
<div class="item-title" :title="slot.item.actionTitle"> {{ slot.item.actionTitle }} <span v-if="slot.item.versionId">({{ slot.item.versionId }})</span>
{{ slot.item.actionTitle }} <span v-if="slot.item.versionId">({{ slot.item.versionId }})</span>
</div>
<div class="item-header-icon" @click="handleClickDetail(true, slot.item, $event)">
<img src="./assets/images/item-header-icon.png" alt="" />
</div>
</div> </div>
<div class="item-info" v-if="slot.item.agreeVote !== null || slot.item.disagreeVote !== null"> <div class="item-header-icon" @click="handleClickDetail(true, slot.item, $event)">
{{ formatVoteText(slot.item) }} <img src="./assets/images/item-header-icon.png" alt="" />
</div>
<div class="item-main" v-if="slot.item.fynrList && slot.item.fynrList.length">
<div
class="item-main-item"
v-for="(sub, subIndex) in slot.item.fynrList"
:key="`${slot.item.id}-${subIndex}-${sub}`"
>
<div class="icon"></div>
<CommonPrompt :content="sub">
<div class="text">{{ sub }}</div>
</CommonPrompt>
</div>
</div> </div>
</div> </div>
<div class="item-time"> <div class="item-info" v-if="slot.item.agreeVote !== null || slot.item.disagreeVote !== null">
{{ slot.item.actionDate }} {{ formatVoteText(slot.item) }}
</div> </div>
</template> <div class="item-main" v-if="slot.item.fynrList && slot.item.fynrList.length">
<div
class="item-main-item"
v-for="(sub, subIndex) in slot.item.fynrList"
:key="`${slot.item.id}-${subIndex}-${sub}`"
>
<div class="icon"></div>
<CommonPrompt :content="sub">
<div class="text">{{ sub }}</div>
</CommonPrompt>
</div>
</div>
</div>
<div class="item-time">{{ slot.item.actionDate }}</div>
</div> </div>
</div> </div>
</div> </div>
<div class="bottom"> <div class="bottom">
<div class="bottom-line" :style="{ width: lineWidth }"> <div class="bottom-line" :style="{ width: lineWidth }">
<div class="bottom-line1" ref="bottomLineEndRef"></div> <div class="arrow-track">
<div
class="arrow-segment arrow-segment-bottom"
v-for="i in mainArrowCount"
:key="`bottom-main-${i}`"
></div>
</div>
<div class="bottom-line1" ref="bottomLineEndRef">
<div class="arrow-track">
<div
class="arrow-segment arrow-segment-bottom"
v-for="i in diagonalArrowCount"
:key="`bottom-diagonal-${i}`"
></div>
</div>
</div>
</div> </div>
<div class="start"> <div class="start">
<div class="name">{{ "众议院" }}</div> <div class="name">众议院</div>
<div class="icon"> <div class="icon">
<img src="./assets/images/logo2.png" alt="" /> <img src="./assets/images/logo2.png" alt="" />
</div> </div>
...@@ -71,51 +96,93 @@ ...@@ -71,51 +96,93 @@
<div class="content-box" :style="houseBoxStyle"> <div class="content-box" :style="houseBoxStyle">
<div <div
class="item-box" class="item-box"
v-for="slot in houseSlots" v-for="slot in houseEventsPositioned"
:key="slot.key" :key="slot.key"
style="width: 280px; flex-shrink: 0;" :style="{ left: slot.left + 'px', width: TIMELINE_ITEM_WIDTH_PX + 'px' }"
> >
<template v-if="slot.item"> <div class="item-time">{{ slot.item.actionDate }}</div>
<div class="item-time"> <div class="item-box-dot">
{{ slot.item.actionDate }} <img src="./assets/images/bottom-line-dot.png" alt="" />
</div> </div>
<div class="item-box-dot"> <div class="item-content">
<img src="./assets/images/bottom-line-dot.png" alt="" /> <div class="item-header">
</div> <div class="item-title" :title="slot.item.actionTitle">
<div class="item-content"> {{ slot.item.actionTitle }} <span v-if="slot.item.versionId">({{ slot.item.versionId }})</span>
<div class="item-header">
<div class="item-title" :title="slot.item.actionTitle">
{{ slot.item.actionTitle }} <span v-if="slot.item.versionId">({{ slot.item.versionId }})</span>
</div>
<div class="item-header-icon" @click="handleClickDetail(true, slot.item, $event)">
<img src="./assets/images/item-header-icon.png" alt="" />
</div>
</div> </div>
<div class="item-info" v-if="slot.item.agreeVote !== null || slot.item.disagreeVote !== null"> <div class="item-header-icon" @click="handleClickDetail(true, slot.item, $event)">
{{ formatVoteText(slot.item) }} <img src="./assets/images/item-header-icon.png" alt="" />
</div> </div>
<div class="item-main" v-if="slot.item.fynrList && slot.item.fynrList.length"> </div>
<div <div class="item-info" v-if="slot.item.agreeVote !== null || slot.item.disagreeVote !== null">
class="item-main-item" {{ formatVoteText(slot.item) }}
v-for="(sub, subIndex) in slot.item.fynrList" </div>
:key="`${slot.item.id}-${subIndex}-${sub}`" <div class="item-main" v-if="slot.item.fynrList && slot.item.fynrList.length">
> <div
<div class="icon"></div> class="item-main-item"
<CommonPrompt :content="sub"> v-for="(sub, subIndex) in slot.item.fynrList"
<div class="text">{{ sub }}</div> :key="`${slot.item.id}-${subIndex}-${sub}`"
</CommonPrompt> >
</div> <div class="icon"></div>
<CommonPrompt :content="sub">
<div class="text">{{ sub }}</div>
</CommonPrompt>
</div> </div>
</div> </div>
</template> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="right" :style="{ left: rightPos, top: rightTop }"> <div class="right" :style="{ left: rightPos, top: rightTop }">
<div class="junction-dot"> <div class="junction-dot">
<div class="inner-dot"></div> <div class="inner-dot"></div>
</div> </div>
<div class="right-line"></div> <div class="right-line" :style="{ width: sharedLineWidth + 'px' }">
<div class="arrow-track">
<div
class="arrow-segment arrow-segment-shared"
v-for="i in rightArrowCount"
:key="`right-${i}`"
></div>
</div>
</div>
</div>
<div class="shared-content-box" :style="sharedBoxStyle">
<div
class="item-box"
v-for="item in sharedEvents"
:key="`shared-${item.id}`"
style="width: 280px; flex-shrink: 0;"
>
<div class="item-time">{{ item.actionDate }}</div>
<div class="item-box-dot"></div>
<div class="item-content">
<div class="item-header">
<div class="item-title" :title="item.actionTitle">
{{ item.actionTitle }} <span v-if="item.versionId">({{ item.versionId }})</span>
</div>
<div class="item-header-icon" @click="handleClickDetail(true, item, $event)">
<img src="./assets/images/item-header-icon.png" alt="" />
</div>
</div>
<div class="item-info" v-if="item.agreeVote !== null || item.disagreeVote !== null">
{{ formatVoteText(item) }}
</div>
<div class="item-main" v-if="item.fynrList && item.fynrList.length">
<div
class="item-main-item"
v-for="(sub, subIndex) in item.fynrList"
:key="`shared-${item.id}-${subIndex}-${sub}`"
>
<div class="icon"></div>
<CommonPrompt :content="sub">
<div class="text">{{ sub }}</div>
</CommonPrompt>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -136,38 +203,54 @@ import { getBillDyqkSummary } from "@/api/bill"; ...@@ -136,38 +203,54 @@ import { getBillDyqkSummary } from "@/api/bill";
import CommonPrompt from "../../commonPrompt/index.vue"; import CommonPrompt from "../../commonPrompt/index.vue";
import ProcessOverviewDetailDialog from "../../ProcessOverviewDetailDialog.vue"; import ProcessOverviewDetailDialog from "../../ProcessOverviewDetailDialog.vue";
// 获取法案流程
const actionList = ref([]); const actionList = ref([]);
const isShowDetailDialog = ref(false);
const currentDetailItem = ref({});
const dialogPos = ref({ left: "0px", top: "0px" });
const ORG_SENATE = "参议院";
const ORG_HOUSE = "众议院";
const PRESIDENT_KEYWORD = "呈递给总统";
const TIMELINE_ITEM_WIDTH_PX = 280;
const ARROW_SEGMENT_TOTAL_PX = 16;
const DIAGONAL_LINE_WIDTH_PX = 127;
const getBillDyqkSummaryList = async () => { const getBillDyqkSummaryList = async () => {
try { try {
const billId = window.sessionStorage.getItem("billId"); const billId = window.sessionStorage.getItem("billId");
if (!billId) return; // 防止 id 为空 if (!billId) {
const params = {
id: billId
};
const res = await getBillDyqkSummary(params);
if (res && res.code === 200) {
// 确保赋值的是数组,如果 data 为 null 则给空数组
actionList.value = Array.isArray(res.data) ? res.data : [];
} else {
actionList.value = []; actionList.value = [];
return;
} }
const res = await getBillDyqkSummary({ id: billId });
actionList.value = res && res.code === 200 && Array.isArray(res.data) ? res.data : [];
} catch (error) { } catch (error) {
actionList.value = []; // 出错时也重置为空数组 actionList.value = [];
} }
}; };
const ORG_SENATE = "参议院";
const ORG_HOUSE = "众议院";
const PRESIDENT_KEYWORD = "呈递给总统";
const TIMELINE_ITEM_WIDTH_PX = 280;
const getTime = (actionDate) => { const getTime = (actionDate) => {
const t = new Date(actionDate).getTime(); const t = new Date(actionDate).getTime();
return Number.isFinite(t) ? t : 0; return Number.isFinite(t) ? t : 0;
}; };
const isDualEvent = (item) => {
const type = String(item?.congressType || "");
return type.includes("双院");
};
const isSenateEvent = (item) => {
const org = String(item?.orgName || "");
const type = String(item?.congressType || "");
return org === ORG_SENATE || type.includes(ORG_SENATE);
};
const isHouseEvent = (item) => {
const org = String(item?.orgName || "");
const type = String(item?.congressType || "");
return org === ORG_HOUSE || type.includes(ORG_HOUSE);
};
const formatVoteText = (item) => { const formatVoteText = (item) => {
if (!item) return ""; if (!item) return "";
const agree = item.agreeVote ?? 0; const agree = item.agreeVote ?? 0;
...@@ -175,130 +258,140 @@ const formatVoteText = (item) => { ...@@ -175,130 +258,140 @@ const formatVoteText = (item) => {
return `${agree}赞成:${disagree}反对`; return `${agree}赞成:${disagree}反对`;
}; };
// 总统交汇节点(用于确定两条时间线的汇合位置)
const presidentAction = computed(() => {
return (
actionList.value.find(
(item) => item.actionTitle && item.actionTitle.includes(PRESIDENT_KEYWORD)
) || null
);
});
// 全局时间排序后的“时间步”
const sortedTimeline = computed(() => { const sortedTimeline = computed(() => {
return [...actionList.value].sort((a, b) => { return [...actionList.value].sort((a, b) => {
const tA = getTime(a.actionDate); const tA = getTime(a.actionDate);
const tB = getTime(b.actionDate); const tB = getTime(b.actionDate);
if (tA !== tB) return tA - tB; if (tA !== tB) return tA - tB;
return String(a.id ?? "").localeCompare(String(b.id ?? ""));
// 时间相同的情况下用 id 保证稳定排序,避免节点在不同渲染中漂移
const idA = String(a.id ?? "");
const idB = String(b.id ?? "");
return idA.localeCompare(idB);
}); });
}); });
// 交汇点(总统节点)在全局时间线里的位置:slice endIndexExclusive 用来排除总统节点本身
const mergeIndexExclusive = computed(() => { const mergeIndexExclusive = computed(() => {
if (!sortedTimeline.value.length) return 0; if (!sortedTimeline.value.length) return 0;
if (!presidentAction.value) return sortedTimeline.value.length; const idx = sortedTimeline.value.findIndex(
(item) => item.actionTitle && item.actionTitle.includes(PRESIDENT_KEYWORD)
const idx = sortedTimeline.value.findIndex((item) => item.id === presidentAction.value.id); );
return idx >= 0 ? idx : sortedTimeline.value.length; return idx >= 0 ? idx : sortedTimeline.value.length;
}); });
// 两条时间线共享同一组时间步(每个时间步只展示属于该阵营的事件;其他阵营用空占位对齐) const dualLaneTimeline = computed(() => {
const timelineSlots = computed(() => { return sortedTimeline.value
return sortedTimeline.value.slice(0, mergeIndexExclusive.value); .slice(0, mergeIndexExclusive.value)
.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,
item,
left: slotIndex * TIMELINE_ITEM_WIDTH_PX
});
slotIndex += 1;
});
return list;
}); });
const senateSlots = computed(() => { const houseEventsPositioned = computed(() => {
return timelineSlots.value.map((step) => ({ const list = [];
key: step.id, let slotIndex = 0;
item: step.orgName === ORG_SENATE ? step : null dualLaneTimeline.value.forEach((item) => {
})); if (!isHouseEvent(item)) return;
list.push({
key: item.id,
item,
left: slotIndex * TIMELINE_ITEM_WIDTH_PX
});
slotIndex += 1;
});
return list;
}); });
const houseSlots = computed(() => { const sharedEvents = computed(() => {
return timelineSlots.value.map((step) => ({ return sortedTimeline.value.filter((item, idx) => {
key: step.id, return isDualEvent(item) || idx >= mergeIndexExclusive.value;
item: step.orgName === ORG_HOUSE ? step : null });
}));
}); });
const timelineCount = computed(() => timelineSlots.value.length); const dualLaneCount = computed(() => {
return Math.max(senateEventsPositioned.value.length, houseEventsPositioned.value.length);
});
// 计算最大线条宽度数值(两条线共享时间步长度)
const maxLineWidth = computed(() => { const maxLineWidth = computed(() => {
const senateWidth = 254 + timelineCount.value * TIMELINE_ITEM_WIDTH_PX; const senateWidth = 254 + dualLaneCount.value * TIMELINE_ITEM_WIDTH_PX;
const houseWidth = 150 + timelineCount.value * TIMELINE_ITEM_WIDTH_PX; const houseWidth = 150 + dualLaneCount.value * TIMELINE_ITEM_WIDTH_PX;
return Math.max(senateWidth, houseWidth); return Math.max(senateWidth, houseWidth);
}); });
// 绑定给线条的样式 const lineWidth = computed(() => `${maxLineWidth.value}px`);
const lineWidth = computed(() => {
return maxLineWidth.value + 'px'; const sharedLineWidth = computed(() => {
const w = sharedEvents.value.length * TIMELINE_ITEM_WIDTH_PX;
return Math.max(70, w);
}); });
// 参议院容器宽度:线条总长 + 线条左偏移(110) - 容器左偏移(254) const boardWidth = computed(() => {
const senateBoxStyle = computed(() => { return maxLineWidth.value + 90 + 24 + sharedLineWidth.value + 180;
return {
width: (maxLineWidth.value + 110 - 254) + 'px',
justifyContent: 'flex-start'
};
}); });
// 众议院容器宽度:线条总长 + 线条左偏移(110) - 容器左偏移(150) const mainArrowCount = computed(() => {
const houseBoxStyle = computed(() => { return Math.max(1, Math.ceil(maxLineWidth.value / ARROW_SEGMENT_TOTAL_PX));
return {
width: (maxLineWidth.value + 110 - 150) + 'px',
justifyContent: 'flex-start'
};
}); });
const rightPos = computed(() => { const diagonalArrowCount = computed(() => {
// 右侧节点位置 = 线条宽度 + 斜线水平投影长度(约90px) return Math.max(1, Math.ceil(DIAGONAL_LINE_WIDTH_PX / ARROW_SEGMENT_TOTAL_PX));
return (maxLineWidth.value + 90) + 'px';
}); });
const rightArrowCount = computed(() => {
return Math.max(1, Math.ceil(sharedLineWidth.value / ARROW_SEGMENT_TOTAL_PX));
});
const senateBoxStyle = computed(() => ({
width: `${maxLineWidth.value + 110 - 254}px`,
justifyContent: "flex-start"
}));
const houseBoxStyle = computed(() => ({
width: `${maxLineWidth.value + 110 - 150}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 topLineEndRef = ref(null); const topLineEndRef = ref(null);
const bottomLineEndRef = ref(null); const bottomLineEndRef = ref(null);
const rightTop = ref('370px'); const rightTop = ref("370px");
const isShowDetailDialog = ref(false);
const currentDetailItem = ref({});
const dialogPos = ref({ left: '0px', top: '0px' });
const handleClickDetail = (isShow, item = {}, event = null) => { const handleClickDetail = (isShow, item = {}, event = null) => {
isShowDetailDialog.value = isShow; isShowDetailDialog.value = isShow;
if (isShow) { if (!isShow) return;
currentDetailItem.value = item;
if (event) {
// 计算弹窗位置,出现在点击位置附近(偏移一些避免挡住鼠标)
const x = event.clientX;
const y = event.clientY;
// 获取包裹容器的偏移量,因为弹窗是 absolute 定位在 wrap 里的
const wrap = document.querySelector('.process-overview-wrap');
const rect = wrap.getBoundingClientRect();
let left = x - rect.left + 20;
let top = y - rect.top - 50;
// 边界处理:防止超出右边界
if (left + 480 > rect.width) {
left = x - rect.left - 500;
}
dialogPos.value = { currentDetailItem.value = item;
left: left + 'px', if (!event) return;
top: top + 'px'
}; const wrap = document.querySelector(".process-overview-wrap");
} if (!wrap) return;
const rect = wrap.getBoundingClientRect();
let left = event.clientX - rect.left + 20;
let top = event.clientY - rect.top - 50;
if (left + 480 > rect.width) {
left = event.clientX - rect.left - 500;
} }
dialogPos.value = { left: `${left}px`, top: `${top}px` };
}; };
// 挂载阶段调用
onMounted(async () => { onMounted(async () => {
await getBillDyqkSummaryList(); await getBillDyqkSummaryList();
await nextTick(); await nextTick();
...@@ -306,9 +399,7 @@ onMounted(async () => { ...@@ -306,9 +399,7 @@ onMounted(async () => {
}); });
const updateRightTop = () => { const updateRightTop = () => {
// 交汇点需要精确对齐上下两条斜线端点在页面中的 y 坐标 const wrap = document.querySelector(".process-overview-wrap");
// rightTop 是相对 .process-overview-wrap 的 absolute top
const wrap = document.querySelector('.process-overview-wrap');
if (!wrap) return; if (!wrap) return;
const topLineEndEl = topLineEndRef.value; const topLineEndEl = topLineEndRef.value;
...@@ -319,22 +410,12 @@ const updateRightTop = () => { ...@@ -319,22 +410,12 @@ const updateRightTop = () => {
const topRect = topLineEndEl.getBoundingClientRect(); const topRect = topLineEndEl.getBoundingClientRect();
const bottomRect = bottomLineEndEl.getBoundingClientRect(); const bottomRect = bottomLineEndEl.getBoundingClientRect();
// 根据 CSS 的旋转原点:
// - top-line1: rotate(45deg) 且 transform-origin: 0 0,因此左侧“尖端”约等于 rect.top
// - bottom-line1: rotate(-45deg) 且 transform-origin: 0 100%,因此左侧“尖端”约等于 rect.bottom
// 但我们对齐的是“斜线中心线”,而不是外包矩形边缘。
// 该斜线块在样式里高度为 8px,所以中心线偏移 4px
const LINE_THICKNESS_PX = 8; const LINE_THICKNESS_PX = 8;
const topLineCenterY = topRect.top + LINE_THICKNESS_PX / 2; const topLineCenterY = topRect.top + LINE_THICKNESS_PX / 2;
const bottomLineCenterY = bottomRect.bottom - LINE_THICKNESS_PX / 2; const bottomLineCenterY = bottomRect.bottom - LINE_THICKNESS_PX / 2;
const desiredCenterY = (topLineCenterY + bottomLineCenterY) / 2; const desiredCenterY = (topLineCenterY + bottomLineCenterY) / 2;
rightTop.value = `${desiredCenterY - wrapRect.top - 12 - 49}px`;
// .right 里 junction-dot 高度为 24px,flex 会让 right-line 与其垂直居中
const junctionCenterOffsetY = 12;
// 经验补偿:整体向上平移约 49px,使视觉交汇点精确落在两条斜线交点
const VISUAL_OFFSET_Y = -49;
rightTop.value = (desiredCenterY - wrapRect.top - junctionCenterOffsetY + VISUAL_OFFSET_Y) + 'px';
}; };
</script> </script>
...@@ -345,51 +426,6 @@ const updateRightTop = () => { ...@@ -345,51 +426,6 @@ const updateRightTop = () => {
margin-top: 16px; margin-top: 16px;
position: relative; position: relative;
.box-header {
width: 100%;
height: 56px;
display: flex;
position: relative;
.header-left {
margin-top: 18px;
width: 8px;
height: 20px;
border-radius: 0 4px 4px 0;
background: var(--color-main-active);
}
.title {
margin-left: 14px;
margin-top: 14px;
height: 26px;
line-height: 26px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 20px;
font-weight: 700;
}
.header-right {
position: absolute;
top: 14px;
right: 12px;
display: flex;
justify-content: flex-end;
gap: 4px;
.icon {
width: 28px;
height: 28px;
img {
width: 100%;
height: 100%;
}
}
}
}
.main { .main {
margin-left: 24px; margin-left: 24px;
margin-right: 24px; margin-right: 24px;
...@@ -398,7 +434,6 @@ const updateRightTop = () => { ...@@ -398,7 +434,6 @@ const updateRightTop = () => {
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: hidden;
/* 自定义滚动条样式,模拟进度条 */
&::-webkit-scrollbar { &::-webkit-scrollbar {
height: 8px; height: 8px;
} }
...@@ -423,10 +458,37 @@ const updateRightTop = () => { ...@@ -423,10 +458,37 @@ const updateRightTop = () => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
/* 确保内容区域宽度足够展示所有节点和右侧汇合点 */
min-width: fit-content; min-width: fit-content;
padding-right: 150px; padding-right: 150px;
.arrow-track {
width: 100%;
height: 8px;
display: flex;
align-items: center;
overflow: hidden;
}
.arrow-segment {
width: 14px;
height: 8px;
margin-right: 2px;
flex-shrink: 0;
clip-path: polygon(0 0, 80% 0, 100% 50%, 80% 100%, 0 100%, 14% 50%);
}
.arrow-segment-top {
background: #3c8bf7;
}
.arrow-segment-bottom {
background: #ffac4d;
}
.arrow-segment-shared {
background: #5f656c;
}
.top { .top {
height: 260px; height: 260px;
display: flex; display: flex;
...@@ -437,8 +499,6 @@ const updateRightTop = () => { ...@@ -437,8 +499,6 @@ const updateRightTop = () => {
left: 110px; left: 110px;
top: 242px; top: 242px;
height: 8px; height: 8px;
width: 1100px;
background: url("./assets/images/top-line-icon.png");
.top-line1 { .top-line1 {
position: absolute; position: absolute;
...@@ -446,7 +506,6 @@ const updateRightTop = () => { ...@@ -446,7 +506,6 @@ const updateRightTop = () => {
top: 0; top: 0;
height: 8px; height: 8px;
width: 127px; width: 127px;
background: url("./assets/images/top-line-icon.png");
transform: rotate(45deg); transform: rotate(45deg);
transform-origin: 0 0; transform-origin: 0 0;
} }
...@@ -475,211 +534,32 @@ const updateRightTop = () => { ...@@ -475,211 +534,32 @@ const updateRightTop = () => {
width: 100px; width: 100px;
height: 30px; height: 30px;
display: flex; display: flex;
flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
gap: 8;
padding: 1px 8px; padding: 1px 8px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(186, 224, 255, 1); border: 1px solid rgba(186, 224, 255, 1);
border-radius: 4px; border-radius: 4px;
background: rgba(230, 244, 255, 1); background: rgba(230, 244, 255, 1);
color: rgba(22, 119, 255, 1); color: rgba(22, 119, 255, 1);
font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
line-height: 20px;
} }
} }
.content-box { .content-box {
display: flex; position: relative;
margin-left: 134px; margin-left: 134px;
margin-bottom: 19px; margin-bottom: 19px;
.item-box { .item-box {
padding: 2px 15px; position: absolute;
display: flex;
flex-direction: column;
justify-content: flex-end;
position: relative;
.item-time {
position: absolute;
bottom: -50px;
left: 30px;
height: 30px;
color: rgba(20, 89, 187, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 30px;
}
.item-box-dot {
position: absolute;
z-index: 9999;
left: 10px;
bottom: -7px;
width: 12px;
height: 12px;
img {
width: 100%;
height: 100%;
}
}
.item-content {
border-left: 1px solid rgb(20, 89, 187);
}
.item-header {
display: flex;
align-items: center;
height: 30px;
padding: 0 10px;
margin-bottom: 8px;
.item-title {
line-height: 26px;
color: rgb(59, 65, 75);
font-family: Microsoft YaHei;
font-size: 20px;
font-weight: 700;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
span {
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
}
.item-header-icon {
margin-left: 5px;
width: 16px;
height: 16px;
cursor: pointer;
flex-shrink: 0;
img {
width: 100%;
height: 100%;
}
}
}
.item-info {
padding: 0 10px;
color: rgb(59, 65, 75);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
margin-bottom: 4px;
}
.item-main {
padding: 5px 10px;
.item-main-item {
display: flex;
align-items: baseline;
width: 269px;
margin-bottom: 4px;
.icon {
margin: 9px 12px;
width: 6px;
height: 6px;
border-radius: 3px;
background: #84888e;
}
.text {
width: 240px;
color: rgb(59, 65, 75);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
height: 48px;
}
:deep(.text-ellipsis) {
white-space: normal !important;
}
}
}
.item-footer {
border-left: 1px solid rgb(20, 89, 187);
display: flex;
padding: 8px 15px;
justify-content: space-between;
.item-footer-box {
display: flex;
margin-left: 12px;
.icon {
position: relative;
width: 24px;
height: 24px;
img {
width: 100%;
height: 100%;
}
.inner-icon {
position: absolute;
right: -5px;
top: 0;
width: 12px;
height: 12px;
border-radius: 6px;
background: rgba(255, 255, 255, 0.8);
display: flex;
box-sizing: border-box;
padding: 1px;
img {
width: 10px;
height: 10px;
}
}
}
.text {
margin-left: 9px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 24px;
}
}
}
} }
} }
} }
.bottom { .bottom {
margin-top: 150px; margin-top: 150px;
// height: 300px;
display: flex; display: flex;
position: relative; position: relative;
...@@ -688,8 +568,6 @@ const updateRightTop = () => { ...@@ -688,8 +568,6 @@ const updateRightTop = () => {
left: 110px; left: 110px;
top: 11px; top: 11px;
height: 8px; height: 8px;
width: 1100px;
background: url("./assets/images/bottom-line-icon.png");
.bottom-line1 { .bottom-line1 {
position: absolute; position: absolute;
...@@ -697,7 +575,6 @@ const updateRightTop = () => { ...@@ -697,7 +575,6 @@ const updateRightTop = () => {
top: 0; top: 0;
height: 8px; height: 8px;
width: 127px; width: 127px;
background: url("./assets/images/bottom-line-icon.png");
transform: rotate(-45deg); transform: rotate(-45deg);
transform-origin: 0 100%; transform-origin: 0 100%;
} }
...@@ -705,7 +582,6 @@ const updateRightTop = () => { ...@@ -705,7 +582,6 @@ const updateRightTop = () => {
.start { .start {
width: 120px; width: 120px;
// height: 260px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-start; justify-content: flex-start;
...@@ -726,542 +602,228 @@ const updateRightTop = () => { ...@@ -726,542 +602,228 @@ const updateRightTop = () => {
width: 100px; width: 100px;
height: 30px; height: 30px;
display: flex; display: flex;
flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
gap: 8;
padding: 1px 8px; padding: 1px 8px;
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
border: 1px solid rgba(255, 229, 143, 1); border: 1px solid rgba(255, 229, 143, 1);
background: rgba(255, 251, 230, 1); background: rgba(255, 251, 230, 1);
color: rgba(250, 173, 20, 1); color: rgba(250, 173, 20, 1);
font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
line-height: 20px;
} }
} }
.content-box { .content-box {
display: flex; position: relative;
margin-left: 30px; margin-left: 30px;
.item-box { .item-box {
padding: 20px 15px; position: absolute;
display: flex;
flex-direction: column;
justify-content: flex-start;
position: relative;
.item-time {
position: absolute;
top: -30px;
left: 30px;
height: 30px;
color: rgba(255, 172, 77, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 30px;
}
.item-box-dot {
position: absolute;
z-index: 9999;
left: 10px;
top: 7px;
width: 12px;
height: 12px;
img {
width: 100%;
height: 100%;
}
}
.item-content {
border-left: 1px solid rgba(255, 172, 77, 1);
}
.item-header {
display: flex;
align-items: center;
height: 30px;
padding: 5px 10px;
margin-top: 8px;
.item-title {
line-height: 26px;
color: rgb(59, 65, 75);
font-family: Microsoft YaHei;
font-size: 20px;
font-weight: 700;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
span {
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
}
.item-header-icon {
margin-left: 5px;
width: 16px;
height: 16px;
cursor: pointer;
flex-shrink: 0;
img {
width: 100%;
height: 100%;
}
}
}
.item-info {
padding: 0 10px;
color: rgb(59, 65, 75);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
margin-top: 8px;
}
.item-main {
padding: 5px 10px;
.item-main-item {
display: flex;
align-items: baseline;
width: 269px;
margin-top: 4px;
.icon {
margin: 9px 12px;
width: 6px;
height: 6px;
border-radius: 3px;
background: #84888e;
}
.text {
width: 240px;
color: rgb(59, 65, 75);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
height: 48px;
}
:deep(.text-ellipsis) {
white-space: normal !important;
}
}
}
.item-footer {
border-left: 1px solid rgba(255, 172, 77, 1);
display: flex;
padding: 8px 15px;
justify-content: space-between;
.item-footer-box {
display: flex;
margin-left: 12px;
.icon {
position: relative;
width: 24px;
height: 24px;
img {
width: 100%;
height: 100%;
}
.inner-icon {
position: absolute;
right: -5px;
top: 0;
width: 12px;
height: 12px;
border-radius: 6px;
background: rgba(255, 255, 255, 0.8);
display: flex;
box-sizing: border-box;
padding: 1px;
img {
width: 10px;
height: 10px;
}
}
}
.text {
margin-left: 9px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 24px;
}
}
}
} }
} }
} }
.right { .item-box {
position: absolute; padding: 2px 15px;
top: 370px;
margin-left: 90px;
display: flex; display: flex;
align-items: center; flex-direction: column;
position: relative;
.junction-dot { .item-time {
width: 24px; position: absolute;
height: 24px; left: 30px;
height: 30px;
color: rgba(95, 101, 108, 1);
font-size: 16px;
font-weight: 700;
line-height: 30px;
}
.item-box-dot {
position: absolute;
z-index: 5;
left: 10px;
width: 12px;
height: 12px;
border-radius: 50%; border-radius: 50%;
background: #5f656c; background: #5f656c;
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
margin-right: -4px; // 稍微重叠
.inner-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: #fff;
}
} }
.right-line { .item-content {
width: 70px; border-left: 1px solid #919191;
height: 8px;
background: url("./assets/images/right-line-icon.png");
} }
}
}
}
.footer {
width: 1710px;
height: 76px;
display: flex;
border: 1px solid rgba(231, 241, 255, 1);
border-radius: 4px;
background: rgba(246, 251, 255, 1);
margin-left: 13px;
.footer-left {
margin-top: 28px;
margin-left: 12px;
width: 19px;
height: 20px;
img {
width: 100%;
height: 100%;
}
}
.footer-center { .item-header {
margin-left: 13px; display: flex;
margin-top: 8px; align-items: center;
width: 1617px; height: 30px;
height: 60px; padding: 0 10px;
color: var(--color-main-active); margin-bottom: 8px;
font-family: Microsoft YaHei;
font-size: 14px; .item-title {
font-weight: 400; line-height: 26px;
line-height: 24px; color: rgb(59, 65, 75);
} font-size: 20px;
font-weight: 700;
.footer-right { white-space: nowrap;
margin-left: 13px; overflow: hidden;
margin-top: 28px; text-overflow: ellipsis;
width: 24px;
height: 24px;
background: rgba(231, 241, 255, 1);
border-radius: 12px;
background: #e7f1ff;
box-sizing: border-box;
padding: 3px;
img {
width: 100%;
height: 100%;
}
}
}
.dialog-wrapper1 {
position: absolute;
z-index: 9999;
top: -120px;
width: 1600px;
height: 1000px;
box-sizing: border-box;
border: 1px solid rgba(230, 231, 232, 1);
border-radius: 10px;
background: rgba(255, 255, 255, 1);
.dialog-header {
height: 48px;
box-sizing: border-box;
border-bottom: 1px solid rgba(240, 242, 244, 1);
display: flex;
justify-content: space-between;
.header-left { span {
display: flex; color: rgba(132, 136, 142, 1);
font-size: 14px;
font-weight: 400;
}
}
.icon { .item-header-icon {
width: 20px; margin-left: 5px;
height: 20px; width: 16px;
margin-left: 14px; height: 16px;
margin-top: 14px; cursor: pointer;
flex-shrink: 0;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
}
} }
} }
.title { .item-info {
margin-left: 11px; padding: 0 10px;
margin-top: 16px; color: rgb(59, 65, 75);
height: 14px; font-size: 16px;
color: rgba(95, 101, 108, 1); line-height: 24px;
font-family: Microsoft YaHei; margin-bottom: 4px;
font-size: 14px;
font-weight: 400;
line-height: 14px;
} }
}
.header-right { .item-main {
width: 16px; padding: 5px 10px;
height: 16px;
margin-top: 16px;
margin-right: 16px;
cursor: pointer;
img { .item-main-item {
width: 100%; display: flex;
height: 100%; align-items: baseline;
} width: 269px;
} margin-bottom: 4px;
}
.icon {
.dialog-info { margin: 9px 12px;
display: flex; width: 6px;
width: 1552px; height: 6px;
height: 64px; border-radius: 3px;
margin: 12px auto; background: #84888e;
}
.info-box1 {
span {
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 14px;
}
}
.info-box2 { .text {
margin-left: 24px; width: 240px;
color: rgb(59, 65, 75);
font-size: 16px;
line-height: 24px;
display: -webkit-box;
line-clamp: 2;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
height: 48px;
}
span { :deep(.text-ellipsis) {
color: rgba(95, 101, 108, 1); white-space: normal !important;
font-family: Microsoft YaHei; }
font-size: 14px; }
font-weight: 400;
line-height: 14px;
} }
} }
.info-box3 { .top .item-box {
display: flex; justify-content: flex-end;
.icon1 { .item-time {
margin-left: 25px; bottom: -50px;
margin-top: 8px; color: rgba(20, 89, 187, 1);
width: 14px;
height: 14px;
border-radius: 4px;
border: 1px solid #333;
} }
.icon2 { .item-box-dot {
margin-left: 25px; bottom: -7px;
margin-top: 8px; background: #1677ff;
width: 18px;
height: 18px;
border-radius: 4px;
img {
width: 18px;
height: 18px;
}
} }
.text { .item-content {
margin-left: 9px; border-left: 1px solid rgb(20, 89, 187);
margin-top: 9px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 14px;
} }
} }
.info-box4 { .bottom .item-box {
margin-left: 500px; padding-top: 20px;
margin-top: 5px; justify-content: flex-start;
position: relative;
.icon { .item-time {
position: absolute; top: -30px;
right: 5px; color: rgba(255, 172, 77, 1);
top: 5px;
width: 16px;
height: 16px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
} }
}
}
.dialog-main {
height: 750px;
width: 1505px;
margin: 0 auto;
border-bottom: 1px solid #e9e9e9;
.dialog-main-header { .item-box-dot {
width: 1505px; top: 7px;
height: 54px; background: #faad14;
display: flex;
background: rgba(59, 65, 75, 1);
color: #fff;
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 54px;
.dialog-main-header-left {
flex: 1;
padding-left: 16px;
} }
.dialog-main-header-right { .item-content {
flex: 1; border-left: 1px solid rgba(255, 172, 77, 1);
} }
} }
.dialog-main-item { .right {
width: 1505px; position: absolute;
top: 370px;
margin-left: 90px;
display: flex; display: flex;
padding: 16px; align-items: center;
height: 139px;
box-sizing: border-box;
.dialog-main-left {
flex: 1;
.dialog-main-item-title {
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 30px;
display: flex;
.title-left {
width: 96px;
}
.title-right { .junction-dot {
flex: 1; width: 24px;
} height: 24px;
} border-radius: 50%;
background: #5f656c;
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
margin-right: -4px;
.dialog-main-item-content { .inner-dot {
margin-left: 96px; width: 10px;
color: rgba(132, 136, 142, 1); height: 10px;
font-family: Microsoft YaHei; border-radius: 50%;
font-size: 14px; background: #fff;
font-weight: 400;
line-height: 18px;
} }
} }
.dialog-main-right { .right-line {
flex: 1; height: 8px;
}
}
.dialog-main-item-title { .shared-content-box {
color: rgba(59, 65, 75, 1); position: absolute;
font-family: Microsoft YaHei; top: 170px;
font-size: 16px; display: flex;
font-weight: 700;
line-height: 30px;
display: flex;
.title-left { .item-box {
width: 96px; justify-content: flex-end;
}
.title-right { .item-time {
flex: 1; bottom: -50px;
}
} }
.dialog-main-item-content { .item-box-dot {
margin-left: 96px; bottom: -7px;
color: rgba(132, 136, 142, 1); background: #5f656c;
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 18px;
} }
} }
} }
.dialog-main-item:nth-child(2n-1) {
border-radius: 4px;
background: rgba(248, 249, 250, 1);
}
}
.dialog-footer {
height: 100px;
display: flex;
justify-content: center;
align-items: center;
} }
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论