Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
480f4b5e
提交
480f4b5e
authored
3月 31, 2026
作者:
张伊明
浏览文件
操作
浏览文件
下载
差异文件
合并分支 'zym-dev' 到 'pre'
Zym dev 查看合并请求
!281
上级
c7a4e758
ca4247e0
流水线
#220
已通过 于阶段
in 2 分 36 秒
变更
5
流水线
1
显示空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
214 行增加
和
77 行删除
+214
-77
forsee-icon.svg
src/views/bill/billLayout/assets/icons/forsee-icon.svg
+3
-0
writting-icon.svg
src/views/bill/billLayout/assets/icons/writting-icon.svg
+3
-0
BillHeader.vue
src/views/bill/billLayout/components/BillHeader.vue
+35
-20
index.vue
src/views/bill/billLayout/index.vue
+20
-13
index.vue
src/views/bill/deepDig/processOverview/index.vue
+153
-44
没有找到文件。
src/views/bill/billLayout/assets/icons/forsee-icon.svg
0 → 100644
浏览文件 @
480f4b5e
<svg
viewBox=
"0 0 12 13"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"12.000000"
height=
"13.000000"
fill=
"none"
customFrame=
"#000000"
>
<path
id=
"矢量 1651"
d=
"M8.05031 2.15239e-07C8.33835 2.69049e-07 8.61901 0.0965686 8.85205 0.275865C9.08508 0.455161 9.25853 0.70798 9.34755 0.998087C9.43656 1.28819 9.43656 1.6007 9.34755 1.8908C9.25853 2.18091 9.08508 2.43373 8.85205 2.61303C8.61901 2.79232 8.33835 2.88889 8.05031 2.88889L3.9583 2.88889C3.69558 2.88873 3.43848 2.80821 3.21793 2.65703C2.99737 2.50585 2.82274 2.29043 2.71502 2.03667C2.35984 2.08328 2.0252 2.23849 1.752 2.48332C1.4788 2.72814 1.27889 3.05197 1.17673 3.41519C1.07456 3.77842 1.07456 4.1653 1.17673 4.52853C1.27889 4.89176 1.4788 5.21558 1.752 5.46041C2.0252 5.70523 2.35984 5.86044 2.71502 5.90706C2.82284 5.65343 2.99751 5.43816 3.21806 5.28711C3.43861 5.13606 3.69565 5.05566 3.9583 5.05556L8.05031 5.05556C8.31755 5.05563 8.57888 5.13883 8.80185 5.29483C9.02483 5.45084 9.19961 5.67276 9.3045 5.93306C9.88944 5.98317 10.4467 6.21802 10.9042 6.60722C11.3618 6.99642 11.6985 7.52206 11.8708 8.11613C12.0431 8.7102 12.0431 9.34536 11.8708 9.93943C11.6985 10.5335 11.3618 11.0591 10.9042 11.4483C10.4467 11.8375 9.88944 12.0724 9.3045 12.1225C9.19961 12.3828 9.02483 12.6047 8.80185 12.7607C8.57888 12.9167 8.31755 12.9999 8.05031 13L3.9583 13C3.71881 13.0001 3.48352 12.9334 3.27608 12.8067C3.06865 12.6799 2.89638 12.4976 2.77661 12.2779C2.65684 12.0583 2.59378 11.8092 2.59378 11.5556C2.59378 11.3019 2.65684 11.0528 2.77661 10.8332C2.89638 10.6136 3.06865 10.4312 3.27608 10.3044C3.48352 10.1777 3.71881 10.111 3.9583 10.1111L8.05031 10.1111C8.60409 10.1111 9.07944 10.4607 9.29291 10.9626C9.64884 10.9171 9.98445 10.7624 10.2585 10.5177C10.5326 10.273 10.7333 9.94881 10.8358 9.58501C10.9384 9.22121 10.9384 8.83362 10.8358 8.46982C10.7333 8.10603 10.5326 7.78186 10.2585 7.53714C9.98445 7.29241 9.64884 7.13778 9.29291 7.09222C9.18531 7.34593 9.0108 7.56132 8.79036 7.71251C8.56992 7.86369 8.31294 7.94423 8.05031 7.94444L3.9583 7.94444C3.69087 7.94445 3.42933 7.86121 3.20622 7.70506C2.9831 7.54892 2.80826 7.32676 2.70342 7.06622C2.11732 7.01784 1.55849 6.78394 1.09952 6.39491C0.640554 6.00587 0.302655 5.47968 0.129709 4.88468C-0.0432364 4.28967 -0.0432363 3.65334 0.129709 3.05833C0.302654 2.46332 0.640554 1.93713 1.09952 1.54809C1.55849 1.15906 2.11732 0.925163 2.70342 0.876778C2.80847 0.616508 2.9834 0.394654 3.2065 0.238777C3.4296 0.0829001 3.69102 -0.000130273 3.9583 2.15239e-07L8.05031 2.15239e-07Z"
fill=
"rgb(95,101,108)"
fill-rule=
"nonzero"
/>
</svg>
src/views/bill/billLayout/assets/icons/writting-icon.svg
0 → 100644
浏览文件 @
480f4b5e
<svg
viewBox=
"0 0 12 13.3145"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"12.000000"
height=
"13.314453"
fill=
"none"
customFrame=
"#000000"
>
<path
id=
"矢量 52"
d=
"M2.47123 9.11862L8.566 3.02386C8.82631 2.76355 8.82631 2.3415 8.566 2.08119C8.30569 1.82088 7.88364 1.82088 7.62333 2.08119L1.52857 8.17595C1.40356 8.30096 1.33333 8.4705 1.33333 8.64729C1.33333 9.01542 1.63176 9.31385 1.9999 9.31385C2.17668 9.31385 2.34623 9.24363 2.47123 9.11862ZM2.82867 10.6472L1 10.6472C0.447715 10.6472 0 10.1995 0 9.64719L0 8.23273C0 7.96752 0.105357 7.71316 0.292894 7.52563L7.62333 0.195193C7.74833 0.0702133 7.91787 0 8.09467 0C8.27147 0 8.441 0.0702133 8.566 0.195193L10.452 2.08119C10.577 2.20621 10.6472 2.37575 10.6472 2.55253C10.6472 2.7293 10.577 2.89884 10.452 3.02386L2.82867 10.6472L2.82867 10.6472ZM0.666666 11.9805L11.3333 11.9805C11.7015 11.9805 12 12.279 12 12.6472C12 13.0154 11.7015 13.3139 11.3333 13.3139L0.666667 13.3139C0.298477 13.3139 0 13.0154 0 12.6472C0 12.279 0.298477 11.9805 0.666666 11.9805Z"
fill=
"rgb(255,255,255)"
fill-rule=
"evenodd"
/>
</svg>
src/views/bill/billLayout/components/BillHeader.vue
浏览文件 @
480f4b5e
...
@@ -38,13 +38,9 @@
...
@@ -38,13 +38,9 @@
</div>
</div>
</
template
>
</
template
>
<
template
v-else
>
<
template
v-else
>
<div
<div
class=
"left-box-bottom-item"
class=
"left-box-bottom-item"
:class=
"
{ leftBoxBottomItemActive: activeTitle === item.name }" v-for="item in tabs"
:class=
"
{ leftBoxBottomItemActive: activeTitle === item.name }"
:key="item.path" @click="emit('tab-click', item)">
v-for="item in tabs"
:key="item.path"
@click="emit('tab-click', item)"
>
<div
class=
"icon"
>
<div
class=
"icon"
>
<img
v-if=
"activeTitle === item.name"
:src=
"item.activeIcon"
alt=
""
/>
<img
v-if=
"activeTitle === item.name"
:src=
"item.activeIcon"
alt=
""
/>
<img
v-else
:src=
"item.icon"
alt=
""
/>
<img
v-else
:src=
"item.icon"
alt=
""
/>
...
@@ -88,7 +84,13 @@
...
@@ -88,7 +84,13 @@
</div>
</div>
</
template
>
</
template
>
<
template
v-else
>
<
template
v-else
>
<div
class=
"btn3"
@
click=
"emit('open-analysis')"
>
<div
class=
"btn2"
@
click=
"emit('open-analysis', 'forsee')"
>
<div
class=
"icon"
>
<img
:src=
"btnIconForsee"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
"进展预测"
}}
</div>
</div>
<div
class=
"btn3"
@
click=
"emit('open-analysis', 'analysis')"
>
<div
class=
"icon"
>
<div
class=
"icon"
>
<img
:src=
"btnIconAnalysis"
alt=
""
/>
<img
:src=
"btnIconAnalysis"
alt=
""
/>
</div>
</div>
...
@@ -103,7 +105,8 @@
...
@@ -103,7 +105,8 @@
<
script
setup
>
<
script
setup
>
import
{
computed
}
from
"vue"
;
import
{
computed
}
from
"vue"
;
import
btnIconAnalysis
from
"@/views/thinkTank/ReportDetail/images/btn-icon3.png"
;
import
btnIconAnalysis
from
"@/views/bill/billLayout/assets/icons/writting-icon.svg"
;
import
btnIconForsee
from
"@/views/bill/billLayout/assets/icons/forsee-icon.svg"
;
const
props
=
defineProps
({
const
props
=
defineProps
({
billInfo
:
{
billInfo
:
{
...
@@ -347,6 +350,29 @@ const emit = defineEmits(["tab-click", "open-analysis"]);
...
@@ -347,6 +350,29 @@ const emit = defineEmits(["tab-click", "open-analysis"]);
justify-content
:
flex-end
;
justify-content
:
flex-end
;
gap
:
8px
;
gap
:
8px
;
.icon
{
width
:
16px
;
height
:
16px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.btn2
{
cursor
:
pointer
;
width
:
120px
;
height
:
36px
;
border-radius
:
6px
;
background
:
var
(
--
bg-white-100
);
border
:
1px
solid
var
(
--
bg-black-10
);
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
gap
:
8px
;
}
.btn3
{
.btn3
{
cursor
:
pointer
;
cursor
:
pointer
;
width
:
120px
;
width
:
120px
;
...
@@ -358,16 +384,6 @@ const emit = defineEmits(["tab-click", "open-analysis"]);
...
@@ -358,16 +384,6 @@ const emit = defineEmits(["tab-click", "open-analysis"]);
align-items
:
center
;
align-items
:
center
;
gap
:
8px
;
gap
:
8px
;
.icon
{
width
:
16px
;
height
:
16px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.text
{
.text
{
height
:
24px
;
height
:
24px
;
color
:
rgba
(
255
,
255
,
255
,
1
);
color
:
rgba
(
255
,
255
,
255
,
1
);
...
@@ -387,4 +403,3 @@ const emit = defineEmits(["tab-click", "open-analysis"]);
...
@@ -387,4 +403,3 @@ const emit = defineEmits(["tab-click", "open-analysis"]);
}
}
}
}
</
style
>
</
style
>
src/views/bill/billLayout/index.vue
浏览文件 @
480f4b5e
...
@@ -2,16 +2,9 @@
...
@@ -2,16 +2,9 @@
<div
class=
"layout-container"
>
<div
class=
"layout-container"
>
<!-- 导航菜单 -->
<!-- 导航菜单 -->
<div
class=
"layout-main"
>
<div
class=
"layout-main"
>
<BillHeader
<BillHeader
:billInfo=
"billInfoGlobal"
:defaultLogo=
"USALogo"
:tabs=
"mainHeaderBtnList"
:billInfo=
"billInfoGlobal"
:activeTitle=
"activeTitle"
:showTabs=
"showHeaderTabs"
:showActions=
"showHeaderActions"
:defaultLogo=
"USALogo"
@
tab-click=
"handleClickMainHeaderBtn"
@
open-analysis=
"handleAnalysisClick"
/>
:tabs=
"mainHeaderBtnList"
:activeTitle=
"activeTitle"
:showTabs=
"showHeaderTabs"
:showActions=
"showHeaderActions"
@
tab-click=
"handleClickMainHeaderBtn"
@
open-analysis=
"handleAnalysisClick"
/>
<div
class=
"layout-main-center"
>
<div
class=
"layout-main-center"
>
<router-view
/>
<router-view
/>
...
@@ -115,12 +108,24 @@ const handleClickMainHeaderBtn = item => {
...
@@ -115,12 +108,24 @@ const handleClickMainHeaderBtn = item => {
});
});
};
};
const
handleAnalysisClick
=
()
=>
{
const
handleAnalysisClick
=
analysisType
=>
{
const
billId
=
route
.
query
.
billId
;
if
(
!
billId
)
return
;
// 进展预测 -> 法案简介页(法案进展)
if
(
analysisType
===
"forsee"
)
{
router
.
push
({
path
:
`/billLayout/ProgressForecast/
${
billId
}
`
,
});
return
;
}
// 分析报告 -> 写作助手
router
.
push
({
router
.
push
({
path
:
"/writtingAsstaint"
,
path
:
"/writtingAsstaint"
,
query
:
{
query
:
{
topic
:
"法案"
,
topic
:
"法案"
,
fileId
:
route
.
query
.
billId
fileId
:
String
(
billId
)
}
}
});
});
};
};
...
@@ -149,11 +154,13 @@ watch(
...
@@ -149,11 +154,13 @@ watch(
// height: 1016px;
// height: 1016px;
background
:
rgba
(
249
,
250
,
252
,
1
);
background
:
rgba
(
249
,
250
,
252
,
1
);
position
:
relative
;
position
:
relative
;
// margin: 0 auto;
// margin: 0 auto;
.layout-main
{
.layout-main
{
width
:
100%
;
width
:
100%
;
height
:
calc
(
100vh
-
72px
)
;
height
:
100vh
;
overflow-y
:
auto
;
overflow-y
:
auto
;
.layout-main-center
{
.layout-main-center
{
// height: calc(100% - 137px);
// height: calc(100% - 137px);
width
:
1600px
;
width
:
1600px
;
...
...
src/views/bill/deepDig/processOverview/index.vue
浏览文件 @
480f4b5e
...
@@ -5,7 +5,7 @@
...
@@ -5,7 +5,7 @@
<div
class=
"left"
:style=
"
{ width: (maxLineWidth + 250) + 'px' }">
<div
class=
"left"
:style=
"
{ width: (maxLineWidth + 250) + '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"
></div>
<div
class=
"top-line1"
ref=
"topLineEndRef"
></div>
</div>
</div>
<div
class=
"start"
>
<div
class=
"start"
>
<div
class=
"icon"
>
<div
class=
"icon"
>
...
@@ -14,25 +14,34 @@
...
@@ -14,25 +14,34 @@
<div
class=
"name"
>
{{
"参议院"
}}
</div>
<div
class=
"name"
>
{{
"参议院"
}}
</div>
</div>
</div>
<div
class=
"content-box"
:style=
"senateBoxStyle"
>
<div
class=
"content-box"
:style=
"senateBoxStyle"
>
<div
class=
"item-box"
v-for=
"(item, index) in senateList"
:key=
"item.id"
<div
style=
"width: 280px; flex-shrink: 0;"
>
class=
"item-box"
v-for=
"slot in senateSlots"
:key=
"slot.key"
style=
"width: 280px; flex-shrink: 0;"
>
<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=
"
item.actionTitle"
>
<div
class=
"item-title"
:title=
"slot.
item.actionTitle"
>
{{
item
.
actionTitle
}}
<span
v-if=
"item.versionId"
>
(
{{
item
.
versionId
}}
)
</span>
{{
slot
.
item
.
actionTitle
}}
<span
v-if=
"slot.item.versionId"
>
(
{{
slot
.
item
.
versionId
}}
)
</span>
</div>
</div>
<div
class=
"item-header-icon"
@
click=
"handleClickDetail(true,
item, $event)"
>
<div
class=
"item-header-icon"
@
click=
"handleClickDetail(true, slot.
item, $event)"
>
<img
src=
"./assets/images/item-header-icon.png"
alt=
""
/>
<img
src=
"./assets/images/item-header-icon.png"
alt=
""
/>
</div>
</div>
</div>
</div>
<div
class=
"item-info"
v-if=
"item.agreeVote !== null ||
item.disagreeVote !== null"
>
<div
class=
"item-info"
v-if=
"slot.item.agreeVote !== null || slot.
item.disagreeVote !== null"
>
{{
(
item
.
agreeVote
||
0
)
+
"赞成:"
+
(
item
.
disagreeVote
||
0
)
+
"反对"
}}
{{
formatVoteText
(
slot
.
item
)
}}
</div>
</div>
<div
class=
"item-main"
v-if=
"item.fynrList && item.fynrList.length"
>
<div
class=
"item-main"
v-if=
"slot.item.fynrList && slot.item.fynrList.length"
>
<div
class=
"item-main-item"
v-for=
"(sub, subIndex) in item.fynrList"
:key=
"subIndex"
>
<div
class=
"item-main-item"
v-for=
"(sub, subIndex) in slot.item.fynrList"
:key=
"`$
{slot.item.id}-${subIndex}-${sub}`"
>
<div
class=
"icon"
></div>
<div
class=
"icon"
></div>
<CommonPrompt
:content=
"sub"
>
<CommonPrompt
:content=
"sub"
>
<div
class=
"text"
>
{{
sub
}}
</div>
<div
class=
"text"
>
{{
sub
}}
</div>
...
@@ -41,15 +50,16 @@
...
@@ -41,15 +50,16 @@
</div>
</div>
</div>
</div>
<div
class=
"item-time"
>
<div
class=
"item-time"
>
{{
item
.
actionDate
}}
{{
slot
.
item
.
actionDate
}}
</div>
</div>
</
template
>
</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"
></div>
<div
class=
"bottom-line1"
ref=
"bottomLineEndRef"
></div>
</div>
</div>
<div
class=
"start"
>
<div
class=
"start"
>
<div
class=
"name"
>
{{ "众议院" }}
</div>
<div
class=
"name"
>
{{ "众议院" }}
</div>
...
@@ -59,28 +69,37 @@
...
@@ -59,28 +69,37 @@
</div>
</div>
</div>
</div>
<div
class=
"content-box"
:style=
"houseBoxStyle"
>
<div
class=
"content-box"
:style=
"houseBoxStyle"
>
<div
class=
"item-box"
v-for=
"(item, index) in houseList"
:key=
"item.id"
<div
style=
"width: 280px; flex-shrink: 0;"
>
class=
"item-box"
v-for=
"slot in houseSlots"
:key=
"slot.key"
style=
"width: 280px; flex-shrink: 0;"
>
<
template
v-if=
"slot.item"
>
<div
class=
"item-time"
>
<div
class=
"item-time"
>
{{
item
.
actionDate
}}
{{
slot
.
item
.
actionDate
}}
</div>
</div>
<div
class=
"item-box-dot"
>
<div
class=
"item-box-dot"
>
<img
src=
"./assets/images/bottom-line-dot.png"
alt=
""
/>
<img
src=
"./assets/images/bottom-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=
"
item.actionTitle"
>
<div
class=
"item-title"
:title=
"slot.
item.actionTitle"
>
{{
item
.
actionTitle
}}
<span
v-if=
"item.versionId"
>
(
{{
item
.
versionId
}}
)
</span>
{{
slot
.
item
.
actionTitle
}}
<span
v-if=
"slot.item.versionId"
>
(
{{
slot
.
item
.
versionId
}}
)
</span>
</div>
</div>
<div
class=
"item-header-icon"
@
click=
"handleClickDetail(true,
item, $event)"
>
<div
class=
"item-header-icon"
@
click=
"handleClickDetail(true, slot.
item, $event)"
>
<img
src=
"./assets/images/item-header-icon.png"
alt=
""
/>
<img
src=
"./assets/images/item-header-icon.png"
alt=
""
/>
</div>
</div>
</div>
</div>
<div
class=
"item-info"
v-if=
"item.agreeVote !== null ||
item.disagreeVote !== null"
>
<div
class=
"item-info"
v-if=
"slot.item.agreeVote !== null || slot.
item.disagreeVote !== null"
>
{{
(
item
.
agreeVote
||
0
)
+
"赞成:"
+
(
item
.
disagreeVote
||
0
)
+
"反对"
}}
{{
formatVoteText
(
slot
.
item
)
}}
</div>
</div>
<div
class=
"item-main"
v-if=
"item.fynrList && item.fynrList.length"
>
<div
class=
"item-main"
v-if=
"slot.item.fynrList && slot.item.fynrList.length"
>
<div
class=
"item-main-item"
v-for=
"(sub, subIndex) in item.fynrList"
:key=
"subIndex"
>
<div
class=
"item-main-item"
v-for=
"(sub, subIndex) in slot.item.fynrList"
:key=
"`$
{slot.item.id}-${subIndex}-${sub}`"
>
<div
class=
"icon"
></div>
<div
class=
"icon"
></div>
<CommonPrompt
:content=
"sub"
>
<CommonPrompt
:content=
"sub"
>
<div
class=
"text"
>
{{
sub
}}
</div>
<div
class=
"text"
>
{{
sub
}}
</div>
...
@@ -88,10 +107,11 @@
...
@@ -88,10 +107,11 @@
</div>
</div>
</div>
</div>
</div>
</div>
</
template
>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"right"
:style=
"
{ left: rightPos }">
<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>
...
@@ -111,7 +131,7 @@
...
@@ -111,7 +131,7 @@
</template>
</template>
<
script
setup
>
<
script
setup
>
import
{
ref
,
onMounted
,
computed
}
from
"vue"
;
import
{
ref
,
onMounted
,
computed
,
nextTick
}
from
"vue"
;
import
{
getBillDyqkSummary
}
from
"@/api/bill"
;
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"
;
...
@@ -138,30 +158,81 @@ const getBillDyqkSummaryList = async () => {
...
@@ -138,30 +158,81 @@ const getBillDyqkSummaryList = async () => {
}
}
};
};
// 总统签署节点
const
ORG_SENATE
=
"参议院"
;
const
ORG_HOUSE
=
"众议院"
;
const
PRESIDENT_KEYWORD
=
"呈递给总统"
;
const
TIMELINE_ITEM_WIDTH_PX
=
280
;
const
getTime
=
(
actionDate
)
=>
{
const
t
=
new
Date
(
actionDate
).
getTime
();
return
Number
.
isFinite
(
t
)
?
t
:
0
;
};
const
formatVoteText
=
(
item
)
=>
{
if
(
!
item
)
return
""
;
const
agree
=
item
.
agreeVote
??
0
;
const
disagree
=
item
.
disagreeVote
??
0
;
return
`
${
agree
}
赞成:
${
disagree
}
反对`
;
};
// 总统交汇节点(用于确定两条时间线的汇合位置)
const
presidentAction
=
computed
(()
=>
{
const
presidentAction
=
computed
(()
=>
{
return
actionList
.
value
.
find
(
item
=>
item
.
actionTitle
&&
item
.
actionTitle
.
includes
(
"呈递给总统"
))
||
null
;
return
(
actionList
.
value
.
find
(
(
item
)
=>
item
.
actionTitle
&&
item
.
actionTitle
.
includes
(
PRESIDENT_KEYWORD
)
)
||
null
);
});
});
// 参议院列表
// 全局时间排序后的“时间步”
const
senateList
=
computed
(()
=>
{
const
sortedTimeline
=
computed
(()
=>
{
return
actionList
.
value
return
[...
actionList
.
value
].
sort
((
a
,
b
)
=>
{
.
filter
(
item
=>
item
.
orgName
===
"参议院"
&&
(
!
presidentAction
.
value
||
item
.
id
!==
presidentAction
.
value
.
id
))
const
tA
=
getTime
(
a
.
actionDate
);
.
sort
((
a
,
b
)
=>
new
Date
(
a
.
actionDate
)
-
new
Date
(
b
.
actionDate
));
const
tB
=
getTime
(
b
.
actionDate
);
if
(
tA
!==
tB
)
return
tA
-
tB
;
// 时间相同的情况下用 id 保证稳定排序,避免节点在不同渲染中漂移
const
idA
=
String
(
a
.
id
??
""
);
const
idB
=
String
(
b
.
id
??
""
);
return
idA
.
localeCompare
(
idB
);
});
});
});
// 众议院列表
// 交汇点(总统节点)在全局时间线里的位置:slice endIndexExclusive 用来排除总统节点本身
const
houseList
=
computed
(()
=>
{
const
mergeIndexExclusive
=
computed
(()
=>
{
return
actionList
.
value
if
(
!
sortedTimeline
.
value
.
length
)
return
0
;
.
filter
(
item
=>
item
.
orgName
===
"众议院"
&&
(
!
presidentAction
.
value
||
item
.
id
!==
presidentAction
.
value
.
id
))
if
(
!
presidentAction
.
value
)
return
sortedTimeline
.
value
.
length
;
.
sort
((
a
,
b
)
=>
new
Date
(
a
.
actionDate
)
-
new
Date
(
b
.
actionDate
));
const
idx
=
sortedTimeline
.
value
.
findIndex
((
item
)
=>
item
.
id
===
presidentAction
.
value
.
id
);
return
idx
>=
0
?
idx
:
sortedTimeline
.
value
.
length
;
});
// 两条时间线共享同一组时间步(每个时间步只展示属于该阵营的事件;其他阵营用空占位对齐)
const
timelineSlots
=
computed
(()
=>
{
return
sortedTimeline
.
value
.
slice
(
0
,
mergeIndexExclusive
.
value
);
});
});
// 计算最大线条宽度数值
const
senateSlots
=
computed
(()
=>
{
return
timelineSlots
.
value
.
map
((
step
)
=>
({
key
:
step
.
id
,
item
:
step
.
orgName
===
ORG_SENATE
?
step
:
null
}));
});
const
houseSlots
=
computed
(()
=>
{
return
timelineSlots
.
value
.
map
((
step
)
=>
({
key
:
step
.
id
,
item
:
step
.
orgName
===
ORG_HOUSE
?
step
:
null
}));
});
const
timelineCount
=
computed
(()
=>
timelineSlots
.
value
.
length
);
// 计算最大线条宽度数值(两条线共享时间步长度)
const
maxLineWidth
=
computed
(()
=>
{
const
maxLineWidth
=
computed
(()
=>
{
const
senateWidth
=
254
+
senateList
.
value
.
length
*
280
;
const
senateWidth
=
254
+
timelineCount
.
value
*
TIMELINE_ITEM_WIDTH_PX
;
const
houseWidth
=
150
+
houseList
.
value
.
length
*
280
;
const
houseWidth
=
150
+
timelineCount
.
value
*
TIMELINE_ITEM_WIDTH_PX
;
return
Math
.
max
(
1100
,
senateWidth
,
houseWidth
);
return
Math
.
max
(
senateWidth
,
houseWidth
);
});
});
// 绑定给线条的样式
// 绑定给线条的样式
...
@@ -173,7 +244,7 @@ const lineWidth = computed(() => {
...
@@ -173,7 +244,7 @@ const lineWidth = computed(() => {
const
senateBoxStyle
=
computed
(()
=>
{
const
senateBoxStyle
=
computed
(()
=>
{
return
{
return
{
width
:
(
maxLineWidth
.
value
+
110
-
254
)
+
'px'
,
width
:
(
maxLineWidth
.
value
+
110
-
254
)
+
'px'
,
justifyContent
:
'
space-between
'
justifyContent
:
'
flex-start
'
};
};
});
});
...
@@ -181,7 +252,7 @@ const senateBoxStyle = computed(() => {
...
@@ -181,7 +252,7 @@ const senateBoxStyle = computed(() => {
const
houseBoxStyle
=
computed
(()
=>
{
const
houseBoxStyle
=
computed
(()
=>
{
return
{
return
{
width
:
(
maxLineWidth
.
value
+
110
-
150
)
+
'px'
,
width
:
(
maxLineWidth
.
value
+
110
-
150
)
+
'px'
,
justifyContent
:
'
space-between
'
justifyContent
:
'
flex-start
'
};
};
});
});
...
@@ -190,6 +261,10 @@ const rightPos = computed(() => {
...
@@ -190,6 +261,10 @@ const rightPos = computed(() => {
return
(
maxLineWidth
.
value
+
90
)
+
'px'
;
return
(
maxLineWidth
.
value
+
90
)
+
'px'
;
});
});
const
topLineEndRef
=
ref
(
null
);
const
bottomLineEndRef
=
ref
(
null
);
const
rightTop
=
ref
(
'370px'
);
const
isShowDetailDialog
=
ref
(
false
);
const
isShowDetailDialog
=
ref
(
false
);
const
currentDetailItem
=
ref
({});
const
currentDetailItem
=
ref
({});
const
dialogPos
=
ref
({
left
:
'0px'
,
top
:
'0px'
});
const
dialogPos
=
ref
({
left
:
'0px'
,
top
:
'0px'
});
...
@@ -224,9 +299,43 @@ const handleClickDetail = (isShow, item = {}, event = null) => {
...
@@ -224,9 +299,43 @@ const handleClickDetail = (isShow, item = {}, event = null) => {
};
};
// 挂载阶段调用
// 挂载阶段调用
onMounted
(()
=>
{
onMounted
(
async
()
=>
{
getBillDyqkSummaryList
();
await
getBillDyqkSummaryList
();
await
nextTick
();
updateRightTop
();
});
});
const
updateRightTop
=
()
=>
{
// 交汇点需要精确对齐上下两条斜线端点在页面中的 y 坐标
// rightTop 是相对 .process-overview-wrap 的 absolute top
const
wrap
=
document
.
querySelector
(
'.process-overview-wrap'
);
if
(
!
wrap
)
return
;
const
topLineEndEl
=
topLineEndRef
.
value
;
const
bottomLineEndEl
=
bottomLineEndRef
.
value
;
if
(
!
topLineEndEl
||
!
bottomLineEndEl
)
return
;
const
wrapRect
=
wrap
.
getBoundingClientRect
();
const
topRect
=
topLineEndEl
.
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
topLineCenterY
=
topRect
.
top
+
LINE_THICKNESS_PX
/
2
;
const
bottomLineCenterY
=
bottomRect
.
bottom
-
LINE_THICKNESS_PX
/
2
;
const
desiredCenterY
=
(
topLineCenterY
+
bottomLineCenterY
)
/
2
;
// .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
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论