Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
1
合并请求
1
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
2a5ddbf3
提交
2a5ddbf3
authored
4月 13, 2026
作者:
朱政
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'pre' into zz-dev
上级
379e1cf8
a6e7aeaa
流水线
#426
已通过 于阶段
in 1 分 31 秒
变更
23
流水线
1
显示空白字符变更
内嵌
并排
正在显示
23 个修改的文件
包含
2852 行增加
和
414 行删除
+2852
-414
index.js
src/api/ruleRestriction/index.js
+49
-34
index.vue
src/components/base/moduleHeader/index.vue
+2
-1
ruleRestrictions.js
src/router/modules/ruleRestrictions.js
+9
-8
tabs.scss
src/styles/tabs.scss
+37
-18
HistoryTimeline.vue
...omponents/memberOfCongress/components/HistoryTimeline.vue
+23
-2
BillList.vue
...ess/components/historicalProposal/components/BillList.vue
+394
-89
PotentialNewsAnalysis.vue
...s/historicalProposal/components/PotentialNewsAnalysis.vue
+7
-1
PotentialNewsList.vue
...nents/historicalProposal/components/PotentialNewsList.vue
+3
-2
index.vue
...views/characterPage/components/memberOfCongress/index.vue
+28
-33
config.js
src/views/characterPage/components/unified/config.js
+121
-0
index.vue
src/views/characterPage/components/unified/index.vue
+1748
-0
index.vue
src/views/characterPage/index.vue
+4
-9
background.png
...ationSubject/innovativeInstitutions/assets/background.png
+0
-0
index.vue
src/views/innovationSubject/innovativeInstitutions/index.vue
+77
-76
index.vue
src/views/ruleRestriction/alliance/index.vue
+85
-38
PersonNewsCard.vue
src/views/technologyFigures/component/PersonNewsCard.vue
+18
-0
PersonTable.vue
src/views/technologyFigures/component/PersonTable.vue
+10
-8
SourceLibrary.vue
src/views/technologyFigures/component/SourceLibrary.vue
+10
-6
TimelineMap.vue
src/views/technologyFigures/component/TimelineMap.vue
+6
-6
speechStance.vue
src/views/technologyFigures/component/speechStance.vue
+20
-11
index.vue
src/views/technologyFigures/index.vue
+190
-67
multiLineChart.js
src/views/technologyFigures/utils/multiLineChart.js
+10
-5
useCharacterNav.js
src/views/technologyFigures/utils/useCharacterNav.js
+1
-0
没有找到文件。
src/api/ruleRestriction/index.js
浏览文件 @
2a5ddbf3
...
...
@@ -3,41 +3,41 @@ import request from "@/api/request.js";
// 规则限制-首页统计接口
export
function
getStatCount
()
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/statCount`
})
});
}
// 规则限制-查询最新动态接口
export
function
getLatestUpdates
()
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getLatestUpdates`
})
});
}
// 规则限制-风险信号
export
function
getRiskSignal
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/commonFeature/riskSignal/
${
params
}
`
})
});
}
// 规则限制-查询新闻资讯
export
function
getNews
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/commonFeature/news/
${
params
}
`
})
});
}
// 规则限制-查询社交媒体
export
function
getRemarks
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/commonFeature/remarks/
${
params
}
`
})
});
}
// 规则限制-限制领域分布情况
...
...
@@ -48,10 +48,10 @@ export function getRemarks(params) {
*/
export
function
getAreaDistribution
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getAreaDistribution`
,
params
})
});
}
// 规则限制-受限实体数量变化趋势
...
...
@@ -63,10 +63,10 @@ export function getAreaDistribution(params) {
*/
export
function
getEntityChangeTrend
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getEntityChangeTrend`
,
params
})
});
}
// 规则限制-规则限制政令列表查询接口
...
...
@@ -83,10 +83,10 @@ export function getEntityChangeTrend(params) {
*/
export
function
getRuleLimitList
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getRuleLimitList`
,
params
})
});
}
// 规则限制-排华科技联盟列表接口
...
...
@@ -104,54 +104,51 @@ export function getRuleLimitList(params) {
*/
export
function
getACTAList
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getACTAList`
,
params
})
});
}
export
function
getAcTAAllcountry
()
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getACTAAllCountry/`
})
});
}
// 规则限制-规则限制基本详情
export
function
getSanctionOverview
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getSanctionOverview/
${
params
}
`
})
});
}
// 规则限制-背景分析
export
function
getBackGround
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getBackGround/
${
params
}
`
})
});
}
// 规则限制-限制条款
export
function
getLimitClause
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getLimitClause/
${
params
}
`
})
});
}
// 规则限制-相关举措
export
function
getRelevantMeasures
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getRelevantMeasures/
${
params
}
`
})
});
}
// // 实体清单-制裁概况-获取发布机构机构动态
// /**
// * @param {Object} data
...
...
@@ -168,7 +165,25 @@ export function getRelevantMeasures(params) {
export
function
getRuleOrg
(
params
)
{
return
request
({
method
:
'POST'
,
url
:
`/api/organization/relate/ruleOrg`
,
data
:
params
})
method
:
"POST"
,
url
:
`/api/organization/relate/ruleOrg`
,
data
:
params
});
}
// 排华联盟-联盟简介
export
function
getUnionIntroduction
(
unionId
)
{
return
request
({
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getUnionIntroduction/
${
unionId
}
`
});
}
// 排华联盟-联盟动态
export
function
getUnionDynamicList
(
params
)
{
return
request
({
method
:
"GET"
,
url
:
`/api/ruleLimitInfo/getUnionDynamicList/
${
params
.
unionId
}
`
,
params
:
{
currentPage
:
params
.
currentPage
,
pageSize
:
params
.
pageSize
}
});
}
src/components/base/moduleHeader/index.vue
浏览文件 @
2a5ddbf3
...
...
@@ -499,7 +499,8 @@ onMounted(() => {
<
style
lang=
"scss"
scoped
>
.module-header-wrapper
{
width
:
100%
;
// height: 64px;
position
:
relative
;
z-index
:
101
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
background
:
linear-gradient
(
180deg
,
rgba
(
246
,
250
,
255
,
0
.8
)
0%
,
rgba
(
255
,
255
,
255
,
0
.8
)
100%
);
...
...
src/router/modules/ruleRestrictions.js
浏览文件 @
2a5ddbf3
// 规则限制
const
RuleRestriction
=
()
=>
import
(
'@/views/ruleRestriction/index.vue'
)
const
RuleRestrictionDetail
=
()
=>
import
(
'@/views/ruleRestriction/detail/index.vue'
)
const
RuleRestrictionsAlliance
=
()
=>
import
(
'@/views/ruleRestriction/alliance/index.vue'
)
const
RuleRestriction
=
()
=>
import
(
"@/views/ruleRestriction/index.vue"
);
const
RuleRestrictionDetail
=
()
=>
import
(
"@/views/ruleRestriction/detail/index.vue"
);
const
RuleRestrictionsAlliance
=
()
=>
import
(
"@/views/ruleRestriction/alliance/index.vue"
);
const
ruleRestrictionsRoutes
=
[
// 规则限制
...
...
@@ -23,16 +23,17 @@ const ruleRestrictionsRoutes = [
title
:
"规则限制详情"
,
dynamicTitle
:
true
}
},
{
},
{
path
:
"/ruleRestrictions/alliance"
,
name
:
"RuleRestrictionsAlliance"
,
component
:
RuleRestrictionsAlliance
,
meta
:
{
title
:
"规则限制联盟详情"
,
isShowHeader
:
true
,
dynamicTitle
:
true
}
},
]
}
];
export
default
ruleRestrictionsRoutes
export
default
ruleRestrictionsRoutes
;
src/styles/tabs.scss
浏览文件 @
2a5ddbf3
...
...
@@ -54,41 +54,59 @@
}
/***tabs-bar左边悬浮***/
.left-float-nav-tabs
,
.left-float-nav-tabs
.el-tabs
{
overflow
:
visible
!
important
;
width
:
auto
!
important
;
}
.left-float-nav-tabs
{
position
:
relative
;
.el-tabs__header.is-left
{
position
:
absolute
;
left
:
-140px
;
top
:
0px
;
position
:
absolute
!
important
;
left
:
-160px
!
important
;
top
:
0
!
important
;
width
:
auto
!
important
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
overflow
:
visible
!
important
;
.el-tabs__nav
{
display
:
flex
;
flex-direction
:
column
;
gap
:
16px
;
align-items
:
center
;
overflow
:
visible
!
important
;
float
:
none
!
important
;
}
.el-tabs__active-bar
{
background-color
:
transparent
;
right
:
12px
;
top
:
11px
;
height
:
8px
!
important
;
border-top
:
6px
solid
transparent
;
/* 顶部边框透明 */
border-bottom
:
6px
solid
transparent
;
/* 底部边框透明 */
border-left
:
8px
solid
var
(
--
bg-white-100
);
/* 左侧边框有颜色 */
display
:
none
;
}
}
.el-tabs__content
{
display
:
none
;
}
.el-tabs__item.is-left
{
@extend
.text-tip-1
;
color
:
var
(
--
text-primary-65-color
);
height
:
32px
;
padding
:
4px
26px
4px
28
px
;
border-radius
:
16px
16px
16px
16px
;
padding
:
4px
16
px
;
border-radius
:
16px
;
justify-content
:
center
;
color
:
var
(
--
text-primary-65-color
);
background-color
:
var
(
--
bg-white-100
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
border
:
none
!
important
;
width
:
auto
;
}
.el-tabs__item.is-left.is-active
{
color
:
var
(
--
bg-white-100
);
background-color
:
var
(
--
color-primary-100
);
color
:
var
(
--
bg-white-100
)
!
important
;
background-color
:
var
(
--
color-primary-100
)
!
important
;
box-shadow
:
none
;
}
}
\ No newline at end of file
src/views/characterPage/components/memberOfCongress/components/HistoryTimeline.vue
浏览文件 @
2a5ddbf3
...
...
@@ -270,6 +270,8 @@ $axis-width: 2px;
.
axis
-
col
{
width
:
$node
-
size
;
flex
-
shrink
:
0
;
position
:
relative
;
// 修复:轴线不穿刺圆点 - 改为 flex-start,圆点用负margin浮在边界上
display
:
flex
;
flex
-
direction
:
column
;
align
-
items
:
center
;
...
...
@@ -281,7 +283,10 @@ $axis-width: 2px;
min
-
height
:
12
px
;
&
.
invisible
{
background
-
color
:
transparent
;
// 第一个节点上方无线:隐藏并占位,使圆点紧贴timeline起点
height
:
0
;
min
-
height
:
0
;
overflow
:
hidden
;
}
}
...
...
@@ -290,12 +295,28 @@ $axis-width: 2px;
height
:
$node
-
size
;
border
-
radius
:
50
%
;
flex
-
shrink
:
0
;
overflow
:
hidden
;
overflow
:
visible
;
// 改为 visible,使负 margin 不被裁剪
position
:
relative
;
z
-
index
:
1
;
display
:
flex
;
align
-
items
:
center
;
justify
-
content
:
center
;
// 第一个节点特殊处理:居顶,上方无线
&
:
first
-
child
{
margin
-
top
:
0
;
}
// 后续节点使用负 margin 浮在轴线上
&
:
not
(:
first
-
child
)
{
margin
-
top
:
-
$node
-
size
/
2
;
}
// 最后一个节点特殊处理:下方无线
&
:
last
-
child
{
margin
-
bottom
:
0
;
}
// 非首尾节点使用负 margin
&
:
not
(:
first
-
child
):
not
(:
last
-
child
)
{
margin
-
bottom
:
-
$node
-
size
/
2
;
}
&
.
highlight
{
background
-
color
:
rgba
(
245
,
34
,
45
,
1
);
...
...
src/views/characterPage/components/memberOfCongress/components/historicalProposal/components/BillList.vue
浏览文件 @
2a5ddbf3
<
template
>
<div
class=
"bill-list"
>
<div
v-if=
"loading"
class=
"bill-list-loading"
>
<div
v-for=
"i in 3"
:key=
"i"
class=
"
bill-list-
skeleton"
>
<div
class=
"
skeleton-left
"
/>
<div
class=
"
skeleton-righ
t"
>
<div
class=
"
skeleton-line w30"
/
>
<div
v-for=
"i in 3"
:key=
"i"
class=
"
right-main-box
skeleton"
>
<div
class=
"
bill-cover skeleton-cover
"
/>
<div
class=
"
bill-conten
t"
>
<div
class=
"
header"
>
<div
class=
"skeleton-line w50"
/>
<div
class=
"skeleton-divider"
/>
<div
class=
"skeleton-line w60"
/>
</div>
<div
class=
"main"
>
<div
class=
"skeleton-line w30"
/>
<div
class=
"skeleton-line w40"
/>
<div
class=
"skeleton-line w50"
/>
<div
class=
"skeleton-line w35"
/>
</div>
</div>
</div>
</div>
...
...
@@ -21,67 +26,109 @@
</div>
<template
v-else
>
<BillCard
v-for=
"bill in bills"
:key=
"bill.billId"
:bill=
"bill"
:progress-stages=
"progressStages"
@
click=
"handleBillMoreClick(bill.billId)"
/>
<div
class=
"right-main-box"
v-for=
"item in mappedBills"
:key=
"item.billId"
>
<div
v-if=
"item.riskSignal"
class=
"risk-tag"
:class=
"getRiskTagClass(item.riskSignal)"
>
{{
item
.
riskSignal
}}
</div>
<div
class=
"bill-cover"
>
<img
class=
"bill-image"
:src=
"item.imageUrl || defaultBillImage"
alt=
""
@
error=
"e =>
{ e.target.src = defaultBillImage }" />
<div
class=
"bill-id"
:title=
"item.billId"
>
{{
item
.
billId
||
"-"
}}
</div>
</div>
<div
class=
"bill-content"
>
<div
class=
"header"
>
<div
class=
"title"
@
click=
"handleBillMoreClick(item.billId)"
:title=
"item.name"
>
{{
item
.
name
}}
</div>
<div
class=
"en-title"
:title=
"item.eName"
>
{{
item
.
eName
}}
</div>
</div>
<div
class=
"main"
>
<div
class=
"item"
><div
class=
"item-left"
>
提案人:
</div><div
class=
"item-right"
>
{{
item
.
tcr
}}
</div></div>
<div
class=
"item"
><div
class=
"item-left"
>
委员会:
</div><div
class=
"item-right"
>
{{
item
.
wyh
}}
</div></div>
<div
class=
"item"
><div
class=
"item-left"
>
相关领域:
</div><div
class=
"item-right1"
><AreaTag
v-for=
"(val, idx) in item.areaList"
:key=
"`$
{item.billId}-${val}-${idx}`" :tagName="val" />
</div></div>
<div
class=
"item"
><div
class=
"item-left"
>
最新动议:
</div><div
class=
"item-right"
><CommonPrompt
:content=
"item.zxdy"
/></div></div>
<div
class=
"item"
>
<div
class=
"item-left"
>
法案进展:
</div>
<div
class=
"item-right2"
>
<div
class=
"tag"
v-for=
"(val, idx) in getReversedProgress(item.progress)"
:key=
"`$
{item.billId}-${val}-${idx}`" :style="{ zIndex: item.progress.length - idx }">
{{
val
}}
</div>
</div>
</div>
</div>
</div>
</div>
<div
v-if=
"total > 0"
class=
"bill-pagination"
>
<span
class=
"bill-pagination-total"
>
{{
'
\
u5171'
+
total
+
'
\
u9879
\
u6cd5
\
u6848'
}}
</span>
<div
v-if=
"total > 0"
class=
"right-footer"
>
<div
class=
"footer-left"
>
{{
`共 ${total
}
项`
}}
<
/div
>
<
div
class
=
"footer-right"
>
<
el
-
pagination
:current-page=
"currentPage
"
@
current
-
change
=
"$emit('page-change', $event)
"
:
page
-
size
=
"pageSize"
:total=
"total"
:pager-count=
"5"
layout=
"prev, pager, next"
:
current
-
page
=
"currentPage"
background
@
current-change=
"$emit('page-change', $event)"
layout
=
"prev, pager, next"
:
total
=
"total"
/>
<
/div
>
<
/div
>
<
/template
>
<
/div
>
<
/template
>
<
script
setup
>
import
BillCard
from
'./BillCard.vue'
import
{
useRouter
}
from
"vue-router"
;
const
router
=
useRouter
();
import
{
useRoute
}
from
"vue-router"
;
const
route
=
useRoute
();
defineProps
({
import
{
computed
}
from
'vue'
import
{
useRouter
}
from
"vue-router"
import
AreaTag
from
'@/components/base/AreaTag/index.vue'
import
CommonPrompt
from
'@/views/bill/commonPrompt/index.vue'
import
DocumentPreview
from
'./DocumentPreview.vue'
import
defaultBillImage
from
'@/views/bill/assets/images/image1.png'
const
router
=
useRouter
()
const
props
=
defineProps
({
bills
:
{
type
:
Array
,
required
:
true
}
,
loading
:
{
type
:
Boolean
,
default
:
false
}
,
total
:
{
type
:
Number
,
default
:
0
}
,
currentPage
:
{
type
:
Number
,
default
:
1
}
,
pageSize
:
{
type
:
Number
,
default
:
10
}
,
progressStages
:
{
type
:
Array
,
default
:
()
=>
[
'提出'
,
'众议院通过'
,
'参议院通过'
,
'分歧协调'
,
'提交总统'
,
'法案通过'
]
},
progressStages
:
{
type
:
Array
,
default
:
()
=>
[]
}
,
}
)
defineEmits
([
'page-change'
])
/** 政策建议关联法案:新标签页打开法案介绍页,billId 随接口 id 变化 */
const
handleBillMoreClick
=
(
bill
)
=>
{
const
billId
=
bill
;
// debugger
if
(
!
billId
)
{
return
;
}
const
route
=
router
.
resolve
({
// 将 historyBill 接口数据映射为 right-main 模板需要的格式
const
mappedBills
=
computed
(()
=>
{
return
props
.
bills
.
map
(
bill
=>
({
billId
:
bill
.
billId
,
name
:
bill
.
name
,
eName
:
bill
.
ename
,
tcr
:
bill
.
sponsorList
?.[
0
]
||
''
,
wyh
:
bill
.
congressName
||
''
,
areaList
:
bill
.
industryList
?.
map
(
i
=>
i
.
industryName
)
||
[],
zxdy
:
bill
.
latestAction
?.
replace
(
/
\b
null
\b
/gi
,
'至今'
).
trim
()
||
''
,
progress
:
bill
.
stageList
?.
map
(
s
=>
s
.
name
||
s
)
||
[],
riskSignal
:
bill
.
riskSignal
||
''
,
imageUrl
:
bill
.
imageUrl
||
''
,
}
))
}
)
const
handleBillMoreClick
=
(
billId
)
=>
{
if
(
!
billId
)
return
const
routeData
=
router
.
resolve
({
path
:
"/billLayout/bill/introduction"
,
query
:
{
billId
:
String
(
billId
)
}
});
window
.
open
(
route
.
href
,
"_blank"
);
};
}
)
window
.
open
(
routeData
.
href
,
"_blank"
)
}
const
getRiskTagClass
=
(
riskSignal
)
=>
{
if
(
riskSignal
?.
includes
(
'高'
))
return
'risk-tag-critical'
if
(
riskSignal
?.
includes
(
'中'
))
return
'risk-tag-high'
if
(
riskSignal
?.
includes
(
'低'
))
return
'risk-tag-medium'
return
'risk-tag-medium'
}
const
getReversedProgress
=
(
progress
)
=>
Array
.
isArray
(
progress
)
?
[...
progress
].
reverse
()
:
[]
<
/script
>
<
style
scoped
>
/* Bill List */
.
bill
-
list
{
display
:
flex
;
flex
-
direction
:
column
;
gap
:
16px
;
gap
:
0
;
}
.
bill
-
list
-
loading
{
...
...
@@ -90,92 +137,350 @@ const handleBillMoreClick = (bill) => {
gap
:
16
px
;
}
.bill-list-skeleton
{
display
:
flex
;
gap
:
24px
;
.
bill
-
list
-
empty
{
background
:
var
(
--
bg
-
white
-
100
);
border
-
radius
:
10
px
;
box
-
shadow
:
0
px
0
px
20
px
0
px
rgba
(
25
,
69
,
130
,
0.1
);
padding
:
24px
;
}
.skeleton-left
{
width
:
120px
;
height
:
190px
;
background
:
#f0f0f0
;
border-radius
:
4px
;
animation
:
pulse
1.5s
ease-in-out
infinite
;
}
.skeleton-right
{
flex
:
1
;
padding
:
48
px
;
text
-
align
:
center
;
color
:
#
bfbfbf
;
font
-
size
:
13
px
;
display
:
flex
;
flex
-
direction
:
column
;
align
-
items
:
center
;
gap
:
12
px
;
}
.skeleton-line
{
/* Skeleton */
.
skeleton
.
skeleton
-
line
{
height
:
16
px
;
background
:
#
f0f0f0
;
border
-
radius
:
4
px
;
animation
:
pulse
1.5
s
ease
-
in
-
out
infinite
;
}
.
skeleton
.
skeleton
-
cover
{
background
:
#
f0f0f0
;
animation
:
pulse
1.5
s
ease
-
in
-
out
infinite
;
}
.
skeleton
-
line
.
w30
{
width
:
30
%
;
}
.
skeleton
-
line
.
w35
{
width
:
35
%
;
}
.
skeleton
-
line
.
w40
{
width
:
40
%
;
}
.
skeleton
-
line
.
w50
{
width
:
50
%
;
}
.
skeleton
-
line
.
w60
{
width
:
60
%
;
}
.skeleton-divider
{
height
:
1px
;
background
:
#eaeced
;
@
keyframes
pulse
{
0
%
,
100
%
{
opacity
:
1
;
}
50
%
{
opacity
:
0.5
;
}
}
.bill-list-empty
{
background
:
var
(
--bg-white-100
);
/* ============ right-main-box 样式(与 billHome ResourceLibrarySection 完全一致) ============ */
.
right
-
main
-
box
{
position
:
relative
;
width
:
100
%
;
height
:
320
px
;
padding
:
12
px
16
px
;
box
-
sizing
:
border
-
box
;
border
-
radius
:
10
px
;
box
-
shadow
:
0
px
0
px
20
px
0
px
rgba
(
25
,
69
,
130
,
0.1
);
padding
:
48px
;
text-align
:
center
;
color
:
#bfbfbf
;
font-size
:
13px
;
background
:
var
(
--
bg
-
white
-
100
);
margin
-
bottom
:
16
px
;
overflow
:
hidden
;
display
:
flex
;
flex-direction
:
column
;
gap
:
16
px
;
align
-
items
:
center
;
gap
:
12px
;
}
@keyframes
pulse
{
0
%,
100
%
{
opacity
:
1
;
}
50
%
{
opacity
:
0.5
;
}
.
right
-
main
-
box
.
risk
-
tag
{
position
:
absolute
;
top
:
12
px
;
right
:
16
px
;
height
:
28
px
;
border
-
radius
:
20
px
;
display
:
inline
-
flex
;
align
-
items
:
center
;
gap
:
6
px
;
padding
:
0
10
px
;
box
-
sizing
:
border
-
box
;
font
-
family
:
"Microsoft YaHei"
;
font
-
size
:
14
px
;
font
-
weight
:
500
;
line
-
height
:
28
px
;
white
-
space
:
nowrap
;
}
.
right
-
main
-
box
.
risk
-
tag
::
before
{
content
:
""
;
width
:
5
px
;
height
:
5
px
;
border
-
radius
:
50
%
;
background
:
currentColor
;
flex
-
shrink
:
0
;
}
/* Pagination */
.bill-pagination
{
.
risk
-
tag
-
critical
{
background
:
var
(
--
color
-
red
-
10
);
color
:
var
(
--
color
-
red
-
100
);
}
.
risk
-
tag
-
high
{
background
:
var
(
--
color
-
orange
-
10
);
color
:
var
(
--
color
-
orange
-
100
);
}
.
risk
-
tag
-
medium
{
background
:
var
(
--
color
-
yellow
-
10
);
color
:
var
(
--
color
-
yellow
-
100
);
}
.
right
-
main
-
box
.
bill
-
cover
{
width
:
240
px
;
flex
-
shrink
:
0
;
position
:
relative
;
height
:
100
%
;
margin
:
0
;
overflow
:
hidden
;
}
.
right
-
main
-
box
.
bill
-
cover
::
after
{
content
:
""
;
position
:
absolute
;
left
:
0
;
right
:
0
;
bottom
:
0
;
height
:
33.333
%
;
background
:
linear
-
gradient
(
to
bottom
,
rgba
(
255
,
255
,
255
,
0
),
rgba
(
255
,
255
,
255
,
0.92
)
60
%
,
var
(
--
bg
-
white
-
100
));
pointer
-
events
:
none
;
}
.
right
-
main
-
box
.
bill
-
image
{
width
:
240
px
;
height
:
100
%
;
object
-
fit
:
none
;
display
:
block
;
}
.
right
-
main
-
box
.
bill
-
id
{
position
:
absolute
;
left
:
0
;
right
:
0
;
bottom
:
0
;
height
:
33.333
%
;
display
:
flex
;
align
-
items
:
center
;
justify-content
:
space-between
;
padding
:
16px
0
0
;
justify
-
content
:
center
;
padding
:
0
12
px
;
box
-
sizing
:
border
-
box
;
color
:
var
(
--
text
-
primary
-
80
-
color
);
font
-
family
:
"Source Han Sans CN"
;
font
-
size
:
20
px
;
font
-
weight
:
700
;
line
-
height
:
26
px
;
letter
-
spacing
:
0
px
;
text
-
align
:
center
;
max
-
width
:
100
%
;
white
-
space
:
nowrap
;
overflow
:
hidden
;
text
-
overflow
:
ellipsis
;
z
-
index
:
1
;
}
.bill-pagination-total
{
font-size
:
14px
;
font-family
:
'Microsoft YaHei'
,
sans-serif
;
.
right
-
main
-
box
.
bill
-
content
{
flex
:
1
;
min
-
width
:
0
;
overflow
:
hidden
;
box
-
sizing
:
border
-
box
;
}
.
right
-
main
-
box
.
header
{
width
:
100
%
;
border
-
bottom
:
1
px
solid
rgba
(
234
,
236
,
238
,
1
);
padding
-
bottom
:
14
px
;
padding
-
right
:
120
px
;
}
.
right
-
main
-
box
.
header
.
title
{
cursor
:
pointer
;
height
:
26
px
;
color
:
var
(
--
text
-
primary
-
80
-
color
);
font
-
family
:
Microsoft
YaHei
;
font
-
size
:
20
px
;
font
-
weight
:
700
;
line
-
height
:
26
px
;
letter
-
spacing
:
0
px
;
text
-
align
:
left
;
overflow
:
hidden
;
text
-
overflow
:
ellipsis
;
white
-
space
:
nowrap
;
}
.
right
-
main
-
box
.
header
.
title
:
hover
{
color
:
#
1459
bb
;
}
.
right
-
main
-
box
.
header
.
en
-
title
{
margin
-
top
:
8
px
;
height
:
24
px
;
color
:
var
(
--
text
-
primary
-
65
-
color
);
font
-
family
:
Microsoft
YaHei
;
font
-
size
:
var
(
--
font
-
size
-
base
);
font
-
weight
:
400
;
color
:
rgba
(
95
,
101
,
108
,
1
);
line
-
height
:
24
px
;
letter
-
spacing
:
0
px
;
text
-
align
:
left
;
overflow
:
hidden
;
text
-
overflow
:
ellipsis
;
white
-
space
:
nowrap
;
}
/* Override el-pagination to match design */
.bill-pagination
:deep
(
.el-pagination
)
{
.
right
-
main
-
box
.
main
{
width
:
100
%
;
margin
-
top
:
10
px
;
}
.
right
-
main
-
box
.
main
.
item
{
margin
-
top
:
12
px
;
display
:
flex
;
align
-
items
:
flex
-
start
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
left
{
width
:
88
px
;
color
:
var
(
--
text
-
primary
-
80
-
color
);
font
-
family
:
"Microsoft YaHei"
;
font
-
size
:
var
(
--
font
-
size
-
base
);
font
-
weight
:
700
;
line
-
height
:
24
px
;
letter
-
spacing
:
1
px
;
text
-
align
:
left
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right
{
max
-
width
:
1000
px
;
margin
-
left
:
10
px
;
color
:
var
(
--
text
-
primary
-
65
-
color
);
font
-
family
:
"Microsoft YaHei"
;
font
-
size
:
var
(
--
font
-
size
-
base
);
font
-
weight
:
400
;
line
-
height
:
24
px
;
letter
-
spacing
:
0
px
;
text
-
align
:
left
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right1
{
margin
-
left
:
10
px
;
display
:
flex
;
gap
:
8
px
;
flex
-
wrap
:
wrap
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right1
.
tag
{
height
:
24
px
;
line
-
height
:
24
px
;
padding
:
0
8
px
;
border
-
radius
:
4
px
;
background
:
var
(
--
color
-
primary
-
10
);
color
:
var
(
--
color
-
main
-
active
);
font
-
family
:
"Microsoft YaHei"
;
font
-
size
:
14
px
;
font
-
weight
:
400
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right2
{
margin
-
left
:
10
px
;
display
:
flex
;
align
-
items
:
center
;
flex
-
wrap
:
wrap
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right2
.
tag
{
height
:
24
px
;
line
-
height
:
22
px
;
padding
:
0
10
px
0
30
px
;
background
:
var
(
--
bg
-
white
-
100
);
color
:
var
(
--
text
-
primary
-
65
-
color
);
border
-
top
:
1
px
solid
rgb
(
234
,
236
,
238
);
border
-
bottom
:
1
px
solid
rgb
(
234
,
236
,
238
);
position
:
relative
;
margin
-
left
:
-
10
px
;
font
-
family
:
"Microsoft YaHei"
;
font
-
size
:
14
px
;
font
-
weight
:
400
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right2
.
tag
::
after
{
content
:
""
;
position
:
absolute
;
top
:
50
%
;
right
:
-
8.485
px
;
width
:
16.97
px
;
height
:
16.97
px
;
background
:
inherit
;
border
-
top
:
1
px
solid
rgb
(
234
,
236
,
238
);
border
-
right
:
1
px
solid
rgb
(
234
,
236
,
238
);
transform
:
translateY
(
-
50
%
)
rotate
(
45
deg
);
z
-
index
:
1
;
box
-
shadow
:
2
px
-
2
px
2
px
rgba
(
0
,
0
,
0
,
0.05
);
box
-
sizing
:
border
-
box
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right2
.
tag
:
first
-
child
{
margin
-
left
:
0
;
padding
-
left
:
10
px
;
border
-
left
:
1
px
solid
rgb
(
234
,
236
,
238
);
border
-
radius
:
4
px
0
0
4
px
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right2
.
tag
:
last
-
child
{
background
:
var
(
--
text
-
primary
-
80
-
color
);
color
:
var
(
--
bg
-
white
-
100
);
border
-
color
:
var
(
--
text
-
primary
-
80
-
color
);
padding
-
right
:
10
px
;
border
-
radius
:
0
;
border
-
right
:
none
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right2
.
tag
:
last
-
child
::
after
{
display
:
block
;
border
-
color
:
var
(
--
text
-
primary
-
80
-
color
);
box
-
shadow
:
none
;
}
.
right
-
main
-
box
.
main
.
item
.
item
-
right2
.
tag
:
first
-
child
:
last
-
child
{
margin
-
left
:
0
;
padding
:
0
10
px
;
border
-
radius
:
4
px
0
0
4
px
;
background
:
var
(
--
text
-
primary
-
80
-
color
);
color
:
var
(
--
bg
-
white
-
100
);
border
:
1
px
solid
var
(
--
text
-
primary
-
80
-
color
);
border
-
right
:
none
;
}
/* Footer */
.
right
-
footer
{
height
:
85
px
;
display
:
flex
;
justify
-
content
:
space
-
between
;
box
-
sizing
:
border
-
box
;
padding
-
top
:
12
px
;
}
.
right
-
footer
.
footer
-
left
{
color
:
var
(
--
text
-
primary
-
80
-
color
);
font
-
family
:
"Microsoft YaHei"
;
font
-
size
:
var
(
--
font
-
size
-
base
);
font
-
weight
:
400
;
line
-
height
:
32
px
;
}
.
right
-
footer
:
deep
(.
el
-
pagination
)
{
--
el
-
pagination
-
bg
-
color
:
var
(
--
bg
-
white
-
100
);
--
el
-
pagination
-
hover
-
color
:
rgba
(
5
,
95
,
194
,
1
);
padding
:
0
;
}
.
bill-pagination
:deep
(
.el-pagination.is-background
.btn-prev
),
.
bill-pagination
:deep
(
.el-pagination.is-background
.btn-next
),
.
bill-pagination
:deep
(
.el-pagination.is-background
.el-pager
li
)
{
.
right
-
footer
:
deep
(.
el
-
pagination
.
is
-
background
.
btn
-
prev
),
.
right
-
footer
:
deep
(.
el
-
pagination
.
is
-
background
.
btn
-
next
),
.
right
-
footer
:
deep
(.
el
-
pagination
.
is
-
background
.
el
-
pager
li
)
{
min
-
width
:
32
px
;
height
:
32
px
;
line
-
height
:
32
px
;
...
...
@@ -188,18 +493,18 @@ const handleBillMoreClick = (bill) => {
margin
:
0
3
px
;
}
.
bill-pagination
:deep
(
.el-pagination.is-background
.el-pager
li
:not
(
.is-disabled
)
.is-active
)
{
.
right
-
footer
:
deep
(.
el
-
pagination
.
is
-
background
.
el
-
pager
li
:
not
(.
is
-
disabled
).
is
-
active
)
{
background
:
var
(
--
bg
-
white
-
100
);
color
:
rgba
(
5
,
95
,
194
,
1
);
border
-
color
:
rgba
(
5
,
95
,
194
,
1
);
}
.
bill-pagination
:deep
(
.el-pagination.is-background
.el-pager
li
:not
(
.is-disabled
)
:hover
)
{
.
right
-
footer
:
deep
(.
el
-
pagination
.
is
-
background
.
el
-
pager
li
:
not
(.
is
-
disabled
):
hover
)
{
color
:
rgba
(
5
,
95
,
194
,
1
);
}
.
bill-pagination
:deep
(
.el-pagination.is-background
.btn-prev
:hover
),
.
bill-pagination
:deep
(
.el-pagination.is-background
.btn-next
:hover
)
{
.
right
-
footer
:
deep
(.
el
-
pagination
.
is
-
background
.
btn
-
prev
:
hover
),
.
right
-
footer
:
deep
(.
el
-
pagination
.
is
-
background
.
btn
-
next
:
hover
)
{
color
:
rgba
(
5
,
95
,
194
,
1
);
}
<
/style
>
src/views/characterPage/components/memberOfCongress/components/historicalProposal/components/PotentialNewsAnalysis.vue
浏览文件 @
2a5ddbf3
...
...
@@ -23,7 +23,10 @@
</div>
<!-- ECharts word cloud -->
<div
ref=
"chartRef"
class=
"pna-cloud"
></div>
<div
v-if=
"keywords.length > 0"
ref=
"chartRef"
class=
"pna-cloud"
></div>
<div
v-else
class=
"pna-cloud"
>
<el-empty
description=
"暂无数据"
:image-size=
"80"
/>
</div>
</div>
</
template
>
...
...
@@ -172,5 +175,8 @@ onBeforeUnmount(() => {
.pna-cloud
{
flex
:
1
;
min-height
:
400px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
</
style
>
src/views/characterPage/components/memberOfCongress/components/historicalProposal/components/PotentialNewsList.vue
浏览文件 @
2a5ddbf3
...
...
@@ -32,11 +32,12 @@
</div>
</div>
<div
class=
"pn-rows"
:class=
"
{ 'pn-rows-loading': loading }">
<div
class=
"pn-rows"
:class=
"
{ 'pn-rows-loading': loading
|| newsList.length === 0
}">
<div
v-if=
"loading"
class=
"pn-rows-spinner"
>
<div
class=
"pn-spinner-icon"
></div>
<span
class=
"pn-spinner-text"
>
加载中...
</span>
</div>
<el-empty
v-else-if=
"newsList.length === 0"
description=
"暂无数据"
:image-size=
"80"
/>
<div
v-for=
"(item, index) in newsList"
v-show=
"!loading"
...
...
@@ -52,7 +53,7 @@
</div>
</div>
<div
class=
"pn-footer"
>
<div
class=
"pn-footer"
v-if=
"newsList.length > 0"
>
<span
class=
"pn-footer-total"
>
共
{{
total
}}
条关键新闻
</span>
<div
class=
"pn-pagination"
>
<button
...
...
src/views/characterPage/components/memberOfCongress/index.vue
浏览文件 @
2a5ddbf3
...
...
@@ -95,6 +95,10 @@
</div>
</
template
>
<div
class=
"main"
>
<
template
v-if=
"CharacterLatestDynamic.length === 0"
>
<el-empty
description=
"暂无数据"
:image-size=
"80"
/>
</
template
>
<
template
v-else
>
<div
v-for=
"item in CharacterLatestDynamic"
:key=
"item"
class=
"main-item"
>
<div
class=
"time"
>
<div
class=
"year"
>
{{
item
.
time
.
split
(
"-"
)[
0
]
}}
</div>
...
...
@@ -127,9 +131,9 @@
</div>
</div>
</div>
<
!-- <div class="line-test"></div> --
>
<
/
template
>
</div>
<div
class=
"pagination"
>
<div
v-if=
"CharacterLatestDynamic.length > 0"
class=
"pagination"
>
<div
class=
"total"
>
{{ `共 ${total} 项` }}
</div>
<el-pagination
@
current-change=
"handleCurrentChange"
:page-size=
"pageSize"
:current-page=
"currentPage"
background
layout=
"prev, pager, next"
:total=
"total"
...
...
@@ -233,26 +237,22 @@
</div>
</div>
<!-- 历史提案 -->
<!-- 在 member-of-congress 同级的左侧添加标签栏 -->
<!-- 历史提案 tab 对应的内容区 -->
<div
v-if=
"infoActive === '历史提案'"
class=
"proposal-wrapper"
>
<div
class=
"proposal-tab-switcher"
>
<button
:class=
"['proposal-tab', { active: newsTab === 'history' }]"
@
click=
"newsTab = 'history'"
>
<span>
历史提案
</span>
<svg
v-if=
"newsTab === 'history'"
class=
"proposal-tab-arrow"
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"currentColor"
>
<path
d=
"M4 2l5 4-5 4V2z"
/>
<svg
v-if=
"newsTab === 'history'"
class=
"proposal-tab-arrow"
width=
"8"
height=
"8"
viewBox=
"0 0 8 8"
fill=
"currentColor"
>
<path
d=
"M4 0L8 4L4 8V0Z"
/>
</svg>
</button>
<button
:class=
"['proposal-tab', { active: newsTab === 'potential' }]"
@
click=
"newsTab = 'potential'"
>
<span>
潜在提案
</span>
<svg
v-if=
"newsTab === 'potential'"
class=
"proposal-tab-arrow"
width=
"12"
height=
"12"
viewBox=
"0 0 12 12"
fill=
"currentColor"
>
<path
d=
"M4 2l5 4-5 4V2z"
/>
<svg
v-if=
"newsTab === 'potential'"
class=
"proposal-tab-arrow"
width=
"8"
height=
"8"
viewBox=
"0 0 8 8"
fill=
"currentColor"
>
<path
d=
"M4 0L8 4L4 8V0Z"
/>
</svg>
</button>
</div>
<HistoricalProposal
v-if=
"newsTab === 'history'"
/>
<PotentialNews
v-else
/>
</div>
...
...
@@ -1837,45 +1837,40 @@ const handleClickTag = async (tag) => {
/* 作为定位参考 */
}
.proposal-tab.active
{
background
:
#055FC2
;
color
:
#fff
;
}
.proposal-tab-switcher
{
position
:
absolute
;
right
:
calc
(
100%
+
24px
)
;
left
:
24px
;
top
:
0
;
display
:
flex
;
flex-direction
:
column
;
gap
:
1
2
px
;
z-index
:
1
;
gap
:
1
6
px
;
align-items
:
center
;
}
.proposal-tab
{
width
:
1
20
px
;
width
:
1
12
px
;
height
:
32px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
padding
:
0
12px
;
font-family
:
'Source Han Sans CN'
,
'Noto Sans SC'
,
sans-serif
;
justify-content
:
center
;
gap
:
4px
;
padding
:
0
16px
;
border-radius
:
16px
;
border
:
none
;
font-size
:
16px
;
font-family
:
'Microsoft YaHei'
,
sans-serif
;
font-weight
:
400
;
color
:
#8c8c8c
;
background
:
none
;
border
:
none
;
border-radius
:
20px
;
color
:
var
(
--
text-primary-65-color
);
background-color
:
var
(
--
bg-white-100
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
cursor
:
pointer
;
white-space
:
nowrap
;
box-sizing
:
border-box
;
}
.proposal-tab.active
{
background
:
#055FC2
;
color
:
#fff
;
&
.active
{
color
:
var
(
--
bg-white-100
);
background-color
:
var
(
--
color-primary-100
);
box-shadow
:
none
;
}
}
.proposal-tab-arrow
{
...
...
src/views/characterPage/components/unified/config.js
0 → 100644
浏览文件 @
2a5ddbf3
/**
* 人物主页 - 类型配置
* type 1: 科技领袖, type 2: 国会议员, type 3: 智库研究人员
*/
export
const
CHARACTER_CONFIG
=
{
1
:
{
// 科技领袖
rootClass
:
"tech-leader"
,
tabs
:
[
"人物详情"
,
"人物关系"
],
tabWidth
:
"50%"
,
useImageProxy
:
false
,
headerTagType
:
"areaTag"
,
wordCloudTitle
:
"科技观点"
,
yearDefault
:
"全部时间"
,
yearBuildMode
:
"dynamic"
,
yearStaticOptions
:
[],
showFundSource
:
false
,
resumeMode
:
"inline"
,
resumeTitle
:
"职业履历"
,
resumeHeight
:
"1336px"
,
companySectionTitle
:
"实体信息"
,
basicInfoFields
:
[
{
label
:
"出生日期:"
,
key
:
"birthday"
,
type
:
"text"
},
{
label
:
"国籍:"
,
key
:
"country"
,
type
:
"text"
},
{
label
:
"教育背景:"
,
key
:
"educationList"
,
type
:
"education"
,
format
:
"school(major)"
},
{
label
:
"净资产:"
,
key
:
"assets"
,
type
:
"text"
},
{
label
:
"职业:"
,
key
:
"positionTitle"
,
type
:
"text"
},
{
label
:
"婚姻状况:"
,
key
:
"marital"
,
type
:
"text"
},
{
label
:
"出生地:"
,
key
:
"birthPlace"
,
type
:
"text"
}
],
boxHeightRules
:
[
{
condition
:
"undefined"
,
value
:
"605px"
},
{
condition
:
"empty"
,
value
:
"405px"
},
{
condition
:
"lte2"
,
value
:
"505px"
},
{
condition
:
"default"
,
value
:
"625px"
}
],
useAreaTypeApi
:
true
,
fieldViewMode
:
"areaList"
,
dialogTagPrefix
:
"#"
,
dialogTagSuffix
:
" 相关领域标签"
,
showRelevantSituation
:
false
,
historicalProposalType
:
null
},
2
:
{
// 国会议员
rootClass
:
"member-of-congress"
,
tabs
:
[
"人物详情"
,
"历史提案"
,
"人物关系"
],
tabWidth
:
"auto"
,
useImageProxy
:
true
,
headerTagType
:
"inline"
,
wordCloudTitle
:
"科技观点"
,
yearDefault
:
"全部"
,
yearBuildMode
:
"static"
,
yearStaticOptions
:
[
"全部"
,
"2025"
,
"2024"
,
"2023"
,
"2022"
,
"2021"
,
"2020"
],
showFundSource
:
true
,
resumeMode
:
"inline"
,
resumeTitle
:
"职业履历"
,
resumeHeight
:
"1556px"
,
companySectionTitle
:
"社交媒体"
,
basicInfoFields
:
[
{
label
:
"出生日期:"
,
key
:
"birthday"
,
type
:
"text"
},
{
label
:
"现任职位:"
,
key
:
"positionTitle"
,
type
:
"text"
},
{
label
:
"党派归属:"
,
key
:
"party"
,
type
:
"text"
},
{
label
:
"教育背景:"
,
key
:
"educationList"
,
type
:
"education"
,
format
:
"school+major"
},
{
label
:
"代表州/选区:"
,
key
:
"state"
,
type
:
"text"
,
titleClass
:
"address"
},
{
label
:
"政治立场:"
,
key
:
"political"
,
type
:
"text"
,
contentClass
:
"long"
},
{
label
:
"出生地:"
,
key
:
"birthPlace"
,
type
:
"text"
}
],
boxHeightRules
:
[
{
condition
:
"undefined"
,
value
:
"545px"
},
{
condition
:
"empty"
,
value
:
"495px"
},
{
condition
:
"lte2"
,
value
:
"445px"
},
{
condition
:
"default"
,
value
:
"545px"
}
],
useAreaTypeApi
:
false
,
fieldViewMode
:
"sessionStorage"
,
dialogTagPrefix
:
"#"
,
dialogTagSuffix
:
"相关领域标签"
,
showRelevantSituation
:
false
,
historicalProposalType
:
"bill"
},
3
:
{
// 智库研究人员
rootClass
:
"think-tank-person"
,
tabs
:
[
"人物详情"
,
"成果报告"
,
"人物关系"
],
tabWidth
:
"auto"
,
useImageProxy
:
false
,
headerTagType
:
"areaTag"
,
wordCloudTitle
:
"核心观点"
,
yearDefault
:
"全部"
,
yearBuildMode
:
"static"
,
yearStaticOptions
:
[
"全部"
,
"2026"
,
"2025"
,
"2024"
,
"2023"
,
"2022"
,
"2021"
],
showFundSource
:
false
,
resumeMode
:
"card"
,
resumeTitle
:
"政治履历"
,
resumeHeight
:
null
,
companySectionTitle
:
"社交媒体"
,
basicInfoFields
:
[
{
label
:
"出生日期:"
,
key
:
"birthday"
,
type
:
"text"
},
{
label
:
"现任职位:"
,
key
:
"positionTitle"
,
type
:
"text"
},
{
label
:
"兼任职位:"
,
key
:
"sideJob"
,
type
:
"text"
},
{
label
:
"政策倾向:"
,
key
:
"political"
,
type
:
"text"
},
{
label
:
"国籍:"
,
key
:
"country"
,
type
:
"text"
},
{
label
:
"教育背景:"
,
key
:
"educationList"
,
type
:
"education"
,
format
:
"school(major)"
},
{
label
:
"研究领域:"
,
key
:
"industryList"
,
type
:
"industry"
}
],
boxHeightRules
:
[
{
condition
:
"undefined"
,
value
:
"625px"
},
{
condition
:
"empty"
,
value
:
"425px"
},
{
condition
:
"lte2"
,
value
:
"525px"
},
{
condition
:
"default"
,
value
:
"625px"
}
],
useAreaTypeApi
:
false
,
fieldViewMode
:
"sessionStorage"
,
dialogTagPrefix
:
""
,
dialogTagSuffix
:
""
,
showRelevantSituation
:
false
,
historicalProposalType
:
"news"
}
};
src/views/characterPage/components/unified/index.vue
0 → 100644
浏览文件 @
2a5ddbf3
<
template
>
<div
:class=
"config.rootClass"
>
<!-- 人物基础 -->
<div
class=
"header"
>
<div
class=
"avatar"
>
<el-avatar
:size=
"160"
shape=
"circle"
:src=
"avatarUrl"
/>
</div>
<div
class=
"info"
>
<p
class=
"name-cn"
>
{{
characterInfo
.
name
}}
</p>
<p
class=
"name-en"
>
{{
characterInfo
.
ename
}}
</p>
<div
class=
"introduction"
>
<p>
{{
characterInfo
.
description
}}
</p>
</div>
<div
class=
"domain"
>
<template
v-if=
"config.headerTagType === 'areaTag'"
>
<AreaTag
v-for=
"tag in characterInfo.industryList"
:key=
"tag"
:tag-name=
"tag.industryName"
/>
</
template
>
<
template
v-else
>
<p
v-for=
"item in characterInfo.industryList"
:key=
"item"
class=
"cl1"
:class=
"
{
cl1: item.status === '1',
cl2: item.status === '2',
cl3: item.status === '3',
cl4: item.status === '4',
cl5: item.status === '5',
cl6: item.status === '6'
}">
{{
item
.
industryName
}}
</p>
</
template
>
</div>
</div>
</div>
<!-- 信息区分 -->
<div
class=
"info-divide"
>
<div
v-for=
"item in config.tabs"
:key=
"item"
:class=
"{ active: infoActive === item }"
:style=
"config.tabWidth === '50%' ? { width: '50%' } : {}"
@
click=
"infoActive = item"
>
{{ item }}
</div>
</div>
<!-- 人物详情 -->
<div
class=
"info-content"
v-show=
"infoActive === '人物详情'"
>
<div
class=
"left"
>
<!-- 科技观点 / 核心观点 - 统一使用 WordCloudChart -->
<AnalysisBox
:title=
"config.wordCloudTitle"
width=
"1064px"
height=
"300px"
:show-all-btn=
"false"
class=
"left-top"
>
<
template
#
header-btn
>
<el-select
v-model=
"numActive"
class=
"tab-select"
:teleported=
"true"
@
change=
"handleChangeYear"
>
<el-option
v-for=
"item in yearOptions"
:key=
"item"
:label=
"item"
:value=
"item"
/>
</el-select>
</
template
>
<div
class=
"chart-box"
>
<WordCloudChart
v-if=
"characterView.length > 0"
:key=
"wordCloudKey"
:data=
"characterView"
/>
<el-empty
v-else
description=
"暂无数据"
:image-size=
"80"
/>
</div>
</AnalysisBox>
<!-- 资金来源 (仅国会议员) -->
<
template
v-if=
"config.showFundSource"
>
<AnalysisBox
title=
" 资金来源"
width=
"1064px"
:show-all-btn=
"false"
class=
"left-center auto-height-box"
>
<template
#
header-btn
>
<el-select
v-model=
"selectedOption"
placeholder=
"请选择"
class=
"tab-select"
:teleported=
"true"
@
change=
"handleChangeYearList"
>
<el-option
v-for=
"item in yearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</
template
>
<div
class=
"fund-table-main"
>
<el-table
:data=
"CharacterFundSource"
style=
"width: 100%"
:header-cell-style=
"{
background: 'transparent',
color: 'rgba(59, 65, 75, 1)',
fontWeight: 700,
fontSize: '16px',
borderBottom: '1px solid rgba(234, 236, 238, 1)'
}"
:cell-style=
"{
fontSize: '16px',
fontWeight: 400,
color: 'rgba(59, 65, 75, 1)'
}"
:row-class-name=
"tableRowClassName"
:row-style=
"{ height: '50px' }"
size=
"large"
>
<el-table-column
prop=
"rank"
label=
"排名"
width=
"80"
align=
"center"
/>
<el-table-column
prop=
"contributor"
label=
"贡献者"
min-width=
"300"
/>
<el-table-column
prop=
"totalAmount"
label=
"总捐款"
width=
"150"
align=
"right"
/>
<el-table-column
prop=
"individualAmount"
label=
"个人捐款"
width=
"150"
align=
"right"
/>
<el-table-column
prop=
"pacsAmount"
label=
"PACs捐款"
width=
"150"
align=
"right"
/>
</el-table>
<div
class=
"table-pagination"
>
<span
class=
"table-pagination-total"
>
共{{ fundTotal }}项
</span>
<el-pagination
v-if=
"fundTotal / fundPageSize >= 2"
:current-page=
"fundCurrentPage"
:page-size=
"fundPageSize"
:total=
"fundTotal"
:pager-count=
"4"
layout=
"prev, pager, next"
background
@
current-change=
"handleFundPageChange"
/>
</div>
</div>
</AnalysisBox>
</template>
<!-- 最新动态 -->
<AnalysisBox
title=
"最新动态"
width=
"1064px"
:show-all-btn=
"false"
class=
"left-bottom auto-height-box"
>
<
template
#
header-btn
>
<div
class=
"input"
>
<input
type=
"checkbox"
v-model=
"isChecked"
@
change=
"handleChange"
style=
"padding-top: 2px;"
/><span
style=
"margin-left: 8px"
>
只看涉华动态
</span>
</div>
</
template
>
<div
class=
"dynamic-main"
>
<
template
v-if=
"CharacterLatestDynamic.length === 0"
>
<el-empty
description=
"暂无数据"
:image-size=
"80"
style=
"margin-bottom: 125px;"
/>
</
template
>
<
template
v-else
>
<div
v-for=
"(item, idx) in CharacterLatestDynamic"
:key=
"item"
class=
"main-item"
>
<div
class=
"time"
>
<div
class=
"year"
>
{{
item
.
time
.
split
(
"-"
)[
0
]
}}
</div>
<div
class=
"date"
>
{{
item
.
time
.
split
(
"-"
)[
1
]
+
"月"
+
item
.
time
.
split
(
"-"
)[
2
]
+
"日"
}}
</div>
</div>
<div
class=
"timeline-col"
>
<div
class=
"timeline-line-top"
v-if=
"idx !== 0"
></div>
<div
class=
"timeline-icon"
>
<img
:src=
"typeIcon1"
alt=
""
v-if=
"item.remarks === true"
/>
<img
:src=
"typeIcon2"
alt=
""
v-else
/>
</div>
<div
class=
"timeline-line-bottom"
v-if=
"idx !== CharacterLatestDynamic.length - 1"
></div>
</div>
<div
class=
"content"
>
<div
:class=
"
{ 'content-type1': item.remarks === true, 'content-type2': item.remarks === false }">
<p
v-if=
"item.remarks === true"
class=
"content-title1"
>
{{
item
.
content
}}
</p>
<p
v-else
class=
"content-title2"
>
{{
item
.
title
}}
</p>
<p
v-if=
"item.remarks === true"
class=
"content-title-en"
>
{{
item
.
econtent
}}
</p>
</div>
<p
v-if=
"item.remarks === false"
class=
"content-contentcontent"
>
{{
item
.
content
}}
</p>
<div
class=
"content-tag"
>
<div
style=
"display: flex; flex-wrap: wrap; gap: 8px;"
>
<AreaTag
v-for=
"tag in item.industryList"
:key=
"tag"
:tag-name=
"tag.industryName"
@
click=
"handleClickTag(tag.industryName)"
/>
</div>
<div
class=
"origin"
>
来源:
{{
item
.
orgName
}}
</div>
</div>
</div>
</div>
</
template
>
</div>
<div
v-if=
"CharacterLatestDynamic.length > 0"
class=
"pagination"
>
<div
class=
"total"
>
{{ `共 ${total} 项` }}
</div>
<el-pagination
@
current-change=
"handleCurrentChange"
:page-size=
"pageSize"
:current-page=
"currentPage"
background
layout=
"prev, pager, next"
:total=
"total"
class=
"custom-pagination"
/>
</div>
</AnalysisBox>
</div>
<div
class=
"right"
>
<!-- 基本信息 -->
<AnalysisBox
title=
"基本信息"
width=
"520px"
:height=
"boxHeight"
:show-all-btn=
"false"
class=
"right-top"
v-if=
"characterBasicInfo"
>
<div
class=
"main-content"
>
<div
class=
"baseInfo"
>
<div
v-for=
"field in config.basicInfoFields"
:key=
"field.key"
class=
"baseInfo-item"
>
<div
class=
"baseInfo-item-title"
:class=
"field.titleClass || ''"
>
{{ field.label }}
</div>
<div
class=
"baseInfo-item-content"
:class=
"field.contentClass || ''"
>
<
template
v-if=
"field.type === 'text'"
>
{{
characterBasicInfo
[
field
.
key
]
}}
</
template
>
<
template
v-else-if=
"field.type === 'education'"
>
<template
v-if=
"field.format === 'school+major'"
>
<div
v-for=
"item in characterBasicInfo.educationList"
:key=
"item.school"
>
{{
item
.
school
+
item
.
major
}}
</div>
</
template
>
<
template
v-else
>
<span
class=
"education-item"
v-for=
"value in characterBasicInfo.educationList"
:key=
"value.school"
>
{{
value
.
school
+
"("
+
value
.
major
+
")"
}}
</span>
</
template
>
</template>
<
template
v-else-if=
"field.type === 'industry'"
>
<span
class=
"span"
v-for=
"item in characterBasicInfo[field.key]"
:key=
"item"
>
{{
item
.
industryName
}}
</span>
</
template
>
</div>
</div>
</div>
<div
class=
"company"
>
<div
class=
"company-title"
>
{{ config.companySectionTitle }}
</div>
<div
class=
"company-content"
>
<div
v-for=
"item in characterBasicInfo.organizationList"
:key=
"item"
class=
"company-item"
>
<img
:src=
"item.imageUrl ? item.imageUrl : DefaultIcon2"
alt=
""
/>
<div>
<div
class=
"company-cn"
>
{{ item.name }}
</div>
<div
class=
"company-name"
>
{{ item.ename }}
</div>
</div>
</div>
</div>
</div>
</div>
</AnalysisBox>
<!-- 履历 - inline 方式 -->
<
template
v-if=
"config.resumeMode === 'inline'"
>
<AnalysisBox
:title=
"config.resumeTitle"
width=
"520px"
:show-all-btn=
"false"
class=
"right-bottom auto-height-box"
>
<template
#
header-btn
>
<div
class=
"resume-tabs"
>
<button
class=
"resume-tab"
:class=
"
{ active: resumeType === 'career' }"
@click="switchResumeType('career')">职业履历
</button>
<button
class=
"resume-tab"
:class=
"
{ active: resumeType === 'education' }"
@click="switchResumeType('education')">教育履历
</button>
</div>
</
template
>
<div
class=
"content-main"
>
<
template
v-if=
"resumeType === 'career'"
>
<template
v-if=
"currentResumeList && currentResumeList.length > 0"
>
<div
v-for=
"item in currentResumeList"
:key=
"item.startTime"
class=
"content-item"
>
<img
:src=
"resumeIcon01"
alt=
""
class=
"image01"
/>
<div
class=
"content-item-time"
>
{{
item
.
startTime
.
split
(
'-'
)[
0
]
+
'-'
+
getendTime
(
item
)
}}
</div>
<div
class=
"content-item-title"
><span>
{{
item
.
orgName
}}
</span><span
style=
"margin-left: 5px;margin-right: 5px;"
>
|
</span><span>
{{
item
.
jobName
}}
</span></div>
<div
class=
"content-item-content"
>
{{
item
.
content
}}
</div>
<div
class=
"content-item-door"
v-if=
"item.door"
>
<img
:src=
"resumeIcon02"
alt=
""
/>
<span>
{{
item
.
door
}}
</span>
</div>
</div>
</
template
>
<el-empty
v-else
:image-size=
"80"
description=
"暂无职业履历"
/>
</template>
<
template
v-else
>
<template
v-if=
"currentResumeList && currentResumeList.length > 0"
>
<div
v-for=
"(item, index) in currentResumeList"
:key=
"index"
class=
"content-item"
>
<img
:src=
"resumeIcon01"
alt=
""
class=
"image01"
/>
<div
class=
"content-item-time"
>
{{
item
.
startTime
.
split
(
'-'
)[
0
]
+
'-'
+
getendTime
(
item
)
}}
</div>
<div
class=
"content-item-title"
>
{{
item
.
school
+
'('
+
item
.
country
+
')'
}}
</div>
<div
class=
"content-item-content"
>
{{
item
.
description
}}
</div>
</div>
</
template
>
<el-empty
v-else
:image-size=
"80"
description=
"暂无教育履历"
/>
</template>
</div>
</AnalysisBox>
</template>
<!-- 履历 - card 方式 -->
<
template
v-else
>
<ResumeCard
:title=
"config.resumeTitle"
:list=
"CharacterResume"
@
download=
"handleDownload"
@
collect=
"handleCollect"
/>
</
template
>
</div>
</div>
<!-- 历史提案 (国会议员) -->
<
template
v-if=
"config.historicalProposalType === 'bill'"
>
<div
v-if=
"infoActive === '历史提案'"
class=
"proposal-wrapper"
>
<div
class=
"proposal-tab-switcher"
>
<button
:class=
"['proposal-tab',
{ active: newsTab === 'history' }]" @click="newsTab = 'history'">
<span>
历史提案
</span>
<svg
v-if=
"newsTab === 'history'"
class=
"proposal-tab-arrow"
width=
"8"
height=
"8"
viewBox=
"0 0 8 8"
fill=
"currentColor"
>
<path
d=
"M4 0L8 4L4 8V0Z"
/>
</svg>
</button>
<button
:class=
"['proposal-tab',
{ active: newsTab === 'potential' }]" @click="newsTab = 'potential'">
<span>
潜在提案
</span>
<svg
v-if=
"newsTab === 'potential'"
class=
"proposal-tab-arrow"
width=
"8"
height=
"8"
viewBox=
"0 0 8 8"
fill=
"currentColor"
>
<path
d=
"M4 0L8 4L4 8V0Z"
/>
</svg>
</button>
</div>
<BillTracker
v-if=
"newsTab === 'history'"
/>
<PotentialNews
v-else
/>
</div>
</
template
>
<!-- 成果报告 (智库) -->
<
template
v-if=
"config.historicalProposalType === 'news'"
>
<NewsTracker
v-if=
"infoActive === '成果报告'"
/>
</
template
>
<!-- 人物关系 - 传递 personId 确保 graph 能获取数据 -->
<CharacterRelationships
v-if=
"infoActive === '人物关系'"
/>
<!-- 相关情况 -->
<RelevantSituation
v-if=
"config.showRelevantSituation && infoActive === '相关情况'"
/>
<!-- 弹框 -->
<el-dialog
v-model=
"dialogVisible"
width=
"761px"
class=
"viewpoint-dialog"
:modal=
"false"
:draggable=
"true"
:lock-scroll=
"false"
:show-close=
"config.rootClass === 'member-of-congress' ? false : undefined"
>
<
template
#
header
>
<div
class=
"viewpoint-header"
>
<div
class=
"viewpoint-title"
>
<span
v-if=
"config.dialogTagPrefix"
class=
"viewpoint-tag"
>
{{
config
.
dialogTagPrefix
}}{{
currentTag
}}
</span>
<span
class=
"viewpoint-label"
>
{{
config
.
dialogTagSuffix
}}
</span>
</div>
<template
v-if=
"config.rootClass === 'member-of-congress'"
>
<div
class=
"viewpoint-close"
@
click=
"dialogVisible = false"
>
<el-icon
:size=
"16"
><Close
/></el-icon>
</div>
</
template
>
</div>
</template>
<div
class=
"viewpoint-body"
>
<div
v-for=
"item in CharacterFieldView"
:key=
"item.id"
class=
"viewpoint-item"
>
<div
class=
"viewpoint-avatar"
>
<el-avatar
:size=
"48"
shape=
"circle"
:src=
"item.imageUrl ? getProxyUrl(item.imageUrl) : DefaultIcon1"
/>
</div>
<div
class=
"viewpoint-content"
>
<div
class=
"viewpoint-arrow"
></div>
<div
class=
"viewpoint-card"
>
<div
class=
"viewpoint-card-header"
>
<span
class=
"viewpoint-name"
>
{{ item.name }}
</span>
<span
class=
"viewpoint-job"
>
{{ item.jobName }}
</span>
</div>
<div
class=
"viewpoint-desc"
>
{{ item.remarks }}
</div>
</div>
</div>
</div>
<div
v-if=
"!CharacterFieldView || CharacterFieldView.length === 0"
class=
"viewpoint-empty"
>
暂无数据
</div>
</div>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
ref
,
computed
,
onMounted
,
nextTick
}
from
"vue"
;
import
{
useRoute
}
from
'vue-router'
;
import
WordCloudChart
from
"@/components/base/WordCloundChart/index.vue"
;
import
AnalysisBox
from
'@/components/base/boxBackground/analysisBox.vue'
;
import
AreaTag
from
'@/components/base/AreaTag/index.vue'
;
import
DefaultIcon1
from
'@/assets/icons/default-icon1.png'
;
import
DefaultIcon2
from
'@/assets/icons/default-icon2.png'
;
import
{
Close
}
from
'@element-plus/icons-vue'
;
import
{
ElEmpty
}
from
'element-plus'
;
import
{
getCharacterGlobalInfo
,
getCharacterBasicInfo
,
getCharacterView
,
getCharacterLatestDynamic
,
getCharacterResume
,
getCharacterFieldView
,
getCharacterFundSource
,
getCharacterReducationResume
,
getareaType
}
from
"@/api/characterPage/characterPage.js"
;
import
{
CHARACTER_CONFIG
}
from
'./config.js'
;
const
props
=
defineProps
({
type
:
{
type
:
[
Number
,
String
],
required
:
true
},
personId
:
{
type
:
String
,
default
:
''
}
});
const
route
=
useRoute
();
const
config
=
computed
(()
=>
CHARACTER_CONFIG
[
Number
(
props
.
type
)]
||
CHARACTER_CONFIG
[
1
]);
const
personIdRef
=
ref
(
props
.
personId
||
route
.
query
.
personId
||
"Y000064"
);
// 类型特定资源 - 动态导入
const
typeAssets
=
ref
({});
const
loadTypeAssets
=
async
()
=>
{
const
t
=
Number
(
props
.
type
);
if
(
t
===
1
)
{
const
assets
=
await
import
(
'../techLeader/assets/type1.png'
);
const
assets2
=
await
import
(
'../techLeader/assets/type2.png'
);
const
icon01
=
await
import
(
'../techLeader/assets/icon01.png'
);
const
icon02
=
await
import
(
'../techLeader/assets/icon02.png'
);
typeAssets
.
value
=
{
type1
:
assets
.
default
,
type2
:
assets2
.
default
,
icon01
:
icon01
.
default
,
icon02
:
icon02
.
default
};
}
else
if
(
t
===
2
)
{
const
assets
=
await
import
(
'../memberOfCongress/assets/type1.png'
);
const
assets2
=
await
import
(
'../memberOfCongress/assets/type2.png'
);
const
icon01
=
await
import
(
'../memberOfCongress/assets/icon01.png'
);
const
icon02
=
await
import
(
'../memberOfCongress/assets/icon02.png'
);
typeAssets
.
value
=
{
type1
:
assets
.
default
,
type2
:
assets2
.
default
,
icon01
:
icon01
.
default
,
icon02
:
icon02
.
default
};
}
else
{
const
assets
=
await
import
(
'../thinkTankPerson/assets/type1.png'
);
const
assets2
=
await
import
(
'../thinkTankPerson/assets/type2.png'
);
const
icon01
=
await
import
(
'../thinkTankPerson/assets/icon01.png'
);
const
icon02
=
await
import
(
'../thinkTankPerson/assets/icon02.png'
);
typeAssets
.
value
=
{
type1
:
assets
.
default
,
type2
:
assets2
.
default
,
icon01
:
icon01
.
default
,
icon02
:
icon02
.
default
};
}
};
const
typeIcon1
=
computed
(()
=>
typeAssets
.
value
.
type1
||
''
);
const
typeIcon2
=
computed
(()
=>
typeAssets
.
value
.
type2
||
''
);
const
resumeIcon01
=
computed
(()
=>
typeAssets
.
value
.
icon01
||
''
);
const
resumeIcon02
=
computed
(()
=>
typeAssets
.
value
.
icon02
||
''
);
// 子组件
import
CharacterRelationships
from
'../techLeader/components/characterRelationships/index.vue'
;
import
RelevantSituation
from
'../techLeader/components/relevantSituation/index.vue'
;
import
BillTracker
from
'../memberOfCongress/components/historicalProposal/components/BillTracker.vue'
;
import
PotentialNews
from
'../memberOfCongress/components/historicalProposal/components/PotentialNews.vue'
;
import
NewsTracker
from
'../thinkTankPerson/components/historicalProposal/components/NewsTracker.vue'
;
import
ResumeCard
from
'../thinkTankPerson/components/Resume.vue'
;
// 图片代理
const
getProxyUrl
=
(
url
)
=>
{
if
(
!
url
)
return
""
;
const
urlStr
=
String
(
url
);
if
(
!
urlStr
.
startsWith
(
'http'
)
||
urlStr
.
includes
(
'images.weserv.nl'
)
||
urlStr
.
includes
(
'localhost'
)
||
urlStr
.
includes
(
'127.0.0.1'
))
{
return
url
;
}
const
cleanUrl
=
urlStr
.
replace
(
/^https
?
:
\/\/
/i
,
''
);
return
`https://images.weserv.nl/?url=
${
encodeURIComponent
(
cleanUrl
)}
`
;
};
const
avatarUrl
=
computed
(()
=>
{
const
url
=
characterInfo
.
value
.
imageUrl
;
if
(
!
url
)
return
''
;
return
config
.
value
.
useImageProxy
?
getProxyUrl
(
url
)
:
url
;
});
// ============ 数据 ============
const
characterInfo
=
ref
({});
const
characterBasicInfo
=
ref
({});
const
characterView
=
ref
([]);
const
wordCloudKey
=
ref
(
0
);
const
CharacterLatestDynamic
=
ref
([]);
const
CharacterResume
=
ref
({});
const
CharacterFieldView
=
ref
([]);
const
CharacterFundSource
=
ref
([]);
const
CharacterEducationResume
=
ref
([]);
// ============ 状态 ============
const
infoActive
=
ref
(
"人物详情"
);
const
resumeType
=
ref
(
'career'
);
const
newsTab
=
ref
(
'history'
);
const
numActive
=
ref
(
''
);
const
yearOptions
=
ref
([]);
// 分页 - 动态
const
currentPage
=
ref
(
1
);
const
total
=
ref
(
0
);
const
pageSize
=
ref
(
7
);
const
loading
=
ref
(
false
);
const
abortController
=
ref
(
null
);
// 资金来源
const
fundCurrentPage
=
ref
(
1
);
const
fundPageSize
=
ref
(
4
);
const
fundTotal
=
ref
(
0
);
const
selectedOption
=
ref
(
"all"
);
const
yearList
=
ref
([
{
label
:
"全部"
,
value
:
"all"
},
{
label
:
"2025"
,
value
:
2025
},
{
label
:
"2024"
,
value
:
2024
},
{
label
:
"2023"
,
value
:
2023
}
]);
const
isChecked
=
ref
(
false
);
const
related
=
ref
(
'N'
);
const
dialogVisible
=
ref
(
false
);
const
currentTag
=
ref
(
null
);
const
areaList
=
ref
([]);
// ============ 计算属性 ============
const
boxHeight
=
computed
(()
=>
{
const
orgList
=
characterBasicInfo
.
value
.
organizationList
;
const
rules
=
config
.
value
.
boxHeightRules
;
if
(
orgList
===
undefined
)
return
rules
.
find
(
r
=>
r
.
condition
===
'undefined'
)?.
value
||
'600px'
;
if
(
orgList
.
length
===
0
)
return
rules
.
find
(
r
=>
r
.
condition
===
'empty'
)?.
value
||
'400px'
;
if
(
orgList
.
length
<=
2
)
return
rules
.
find
(
r
=>
r
.
condition
===
'lte2'
)?.
value
||
'500px'
;
return
rules
.
find
(
r
=>
r
.
condition
===
'default'
)?.
value
||
'600px'
;
});
const
currentResumeList
=
computed
(()
=>
{
return
resumeType
.
value
===
'career'
?
CharacterResume
.
value
:
CharacterEducationResume
.
value
;
});
// ============ 方法 ============
const
getendTime
=
(
item
)
=>
{
if
(
item
.
endTime
==
null
)
{
return
item
.
endTimeStatus
==
0
?
'至今'
:
'未知'
;
}
else
{
return
item
.
endTime
.
split
(
'-'
)[
0
];
}
};
const
switchResumeType
=
(
type
)
=>
{
resumeType
.
value
=
type
;
if
(
type
===
'education'
&&
CharacterEducationResume
.
value
.
length
===
0
)
{
getCharacterEducationResumeFn
();
}
};
// API 调用
const
getCharacterGlobalInfoFn
=
async
()
=>
{
const
params
=
{
personId
:
personIdRef
.
value
};
try
{
const
res
=
await
getCharacterGlobalInfo
(
params
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
characterInfo
.
value
=
res
.
data
;
}
}
catch
(
error
)
{
}
};
const
getCharacterBasicInfoFn
=
async
()
=>
{
const
params
=
{
personId
:
personIdRef
.
value
};
try
{
const
res
=
await
getCharacterBasicInfo
(
params
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
characterBasicInfo
.
value
=
res
.
data
;
}
}
catch
(
error
)
{
}
};
const
getCharacterViewFn
=
async
()
=>
{
const
params
=
{
personId
:
personIdRef
.
value
};
if
(
numActive
.
value
!==
config
.
value
.
yearDefault
&&
numActive
.
value
!==
'全部'
&&
numActive
.
value
!==
'全部时间'
)
{
params
.
year
=
numActive
.
value
;
}
try
{
const
res
=
await
getCharacterView
(
params
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
characterView
.
value
=
res
.
data
.
map
(
item
=>
({
name
:
item
.
option
,
value
:
item
.
count
}));
}
else
{
characterView
.
value
=
[];
}
}
catch
(
error
)
{
characterView
.
value
=
[];
}
// 强制刷新 WordCloudChart 组件
wordCloudKey
.
value
++
;
};
const
handleChangeYear
=
()
=>
{
characterView
.
value
=
[];
getCharacterViewFn
();
};
const
getCharacterFieldViewFn
=
async
(
tagname
)
=>
{
let
areaId
=
window
.
sessionStorage
.
getItem
(
"areaId"
)
||
"20"
;
if
(
config
.
value
.
fieldViewMode
===
'areaList'
&&
tagname
)
{
const
areaItem
=
areaList
.
value
.
find
(
item
=>
item
.
name
===
tagname
);
areaId
=
areaItem
?.
id
||
"20"
;
}
const
params
=
{
areaId
};
try
{
const
res
=
await
getCharacterFieldView
(
params
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
CharacterFieldView
.
value
=
res
.
data
;
}
}
catch
(
error
)
{
}
};
const
handleChange
=
()
=>
{
related
.
value
=
isChecked
.
value
?
'Y'
:
'N'
;
getCharacterLatestDynamicFn
();
};
const
handleCurrentChange
=
(
page
)
=>
{
currentPage
.
value
=
page
;
getCharacterLatestDynamicFn
();
};
const
getCharacterLatestDynamicFn
=
async
()
=>
{
if
(
abortController
.
value
)
{
abortController
.
value
.
abort
();
}
abortController
.
value
=
new
AbortController
();
loading
.
value
=
true
;
const
params
=
{
personId
:
personIdRef
.
value
,
cRelated
:
related
.
value
,
currentPage
:
currentPage
.
value
-
1
,
pageSize
:
pageSize
.
value
};
try
{
const
res
=
await
getCharacterLatestDynamic
(
params
,
abortController
.
value
.
signal
);
if
(
res
.
code
===
200
)
{
if
(
res
.
data
&&
res
.
data
.
content
)
{
CharacterLatestDynamic
.
value
=
res
.
data
.
content
.
map
(
item
=>
({
title
:
item
.
title
,
content
:
item
.
content
,
econtent
:
item
.
econtent
,
time
:
item
.
time
,
industryList
:
item
.
industryList
||
[
"人工智能"
],
orgName
:
item
.
orgName
,
remarks
:
item
.
remarks
}));
total
.
value
=
res
.
data
.
totalElements
;
}
else
{
CharacterLatestDynamic
.
value
=
[];
total
.
value
=
0
;
}
}
else
{
CharacterLatestDynamic
.
value
=
[];
total
.
value
=
0
;
}
loading
.
value
=
false
;
}
catch
(
error
)
{
if
(
error
.
name
!==
"AbortError"
)
{
console
.
error
(
error
);
loading
.
value
=
false
;
}
}
};
const
getCharacterResumeFn
=
async
()
=>
{
const
params
=
{
personId
:
personIdRef
.
value
};
try
{
const
res
=
await
getCharacterResume
(
params
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
CharacterResume
.
value
=
res
.
data
;
}
}
catch
(
error
)
{
}
};
const
getCharacterEducationResumeFn
=
async
()
=>
{
const
params
=
{
personId
:
personIdRef
.
value
};
try
{
const
res
=
await
getCharacterReducationResume
(
params
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
CharacterEducationResume
.
value
=
res
.
data
;
}
}
catch
(
error
)
{
}
};
const
getCharacterFundSourceFn
=
async
()
=>
{
const
params
=
{
personId
:
personIdRef
.
value
,
pageSize
:
4
,
currentPage
:
fundCurrentPage
.
value
-
1
,
};
if
(
selectedOption
.
value
!==
'all'
)
{
params
.
year
=
selectedOption
.
value
;
}
try
{
const
res
=
await
getCharacterFundSource
(
params
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
fundTotal
.
value
=
res
.
data
.
totalElements
;
CharacterFundSource
.
value
=
res
.
data
.
content
.
map
((
item
,
index
)
=>
({
rank
:
index
+
1
,
contributor
:
item
.
orgName
,
totalAmount
:
item
.
totalDonation
,
individualAmount
:
item
.
personalDonation
,
pacsAmount
:
item
.
pacsDonation
}));
}
}
catch
(
error
)
{
}
};
const
handleFundPageChange
=
(
page
)
=>
{
fundCurrentPage
.
value
=
page
;
getCharacterFundSourceFn
();
};
const
handleChangeYearList
=
()
=>
{
getCharacterFundSourceFn
();
};
const
handleGetAreaType
=
async
()
=>
{
try
{
const
res
=
await
getareaType
();
if
(
res
.
code
===
200
&&
res
.
data
)
{
areaList
.
value
=
res
.
data
;
}
}
catch
(
error
)
{
}
};
const
handleClickTag
=
async
(
tag
)
=>
{
currentTag
.
value
=
tag
;
dialogVisible
.
value
=
true
;
await
getCharacterFieldViewFn
(
tag
);
};
const
tableRowClassName
=
({
row
,
rowIndex
})
=>
{
if
(
rowIndex
%
2
===
0
)
return
"highlight-row"
;
return
""
;
};
const
handleDownload
=
()
=>
{
};
const
handleCollect
=
()
=>
{
};
const
buildYearOptions
=
()
=>
{
if
(
config
.
value
.
yearBuildMode
===
'dynamic'
)
{
const
currentYear
=
new
Date
().
getFullYear
();
const
years
=
[];
for
(
let
i
=
0
;
i
<
5
;
i
++
)
{
years
.
push
(
String
(
currentYear
-
i
));
}
yearOptions
.
value
=
[
config
.
value
.
yearDefault
,
...
years
];
}
else
{
yearOptions
.
value
=
config
.
value
.
yearStaticOptions
;
}
numActive
.
value
=
config
.
value
.
yearDefault
;
};
// ============ 初始化 ============
const
init
=
async
()
=>
{
await
loadTypeAssets
();
buildYearOptions
();
// 共用 API
getCharacterGlobalInfoFn
();
getCharacterBasicInfoFn
();
getCharacterLatestDynamicFn
();
getCharacterResumeFn
();
getCharacterViewFn
();
// 类型特有
if
(
config
.
value
.
useAreaTypeApi
)
{
handleGetAreaType
();
}
if
(
config
.
value
.
showFundSource
)
{
getCharacterFundSourceFn
();
}
if
(
config
.
value
.
fieldViewMode
===
'sessionStorage'
)
{
getCharacterFieldViewFn
();
}
};
onMounted
(()
=>
{
init
();
});
</
script
>
<
style
lang=
"scss"
scoped
>
*
{
margin
:
0
;
padding
:
0
;
}
:deep
(
.wrapper-main
)
{
margin-top
:
15px
;
}
:deep
(
.el-select-dropdown__item
)
{
text-align
:
center
!
important
;
justify-content
:
center
;
}
/* ============ 通用布局 ============ */
.tech-leader
,
.member-of-congress
,
.think-tank-person
{
width
:
1600px
;
margin
:
0
auto
;
padding-bottom
:
50px
;
.header
{
width
:
1600px
;
height
:
200px
;
margin
:
16px
auto
;
background-color
:
rgba
(
255
,
255
,
255
,
0
.8
);
border-radius
:
10px
;
box-shadow
:
0px
0px
20px
rgba
(
25
,
69
,
130
,
0
.1
);
padding
:
20px
;
display
:
flex
;
align-items
:
center
;
.avatar
{
width
:
160px
;
height
:
160px
;
margin-right
:
24px
;
overflow
:
hidden
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
cover
;
}
}
.info
{
flex
:
1
;
.name-cn
{
font-size
:
32px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
42px
;
color
:
rgb
(
59
,
65
,
75
);
margin-bottom
:
8px
;
}
.name-en
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
59
,
65
,
75
);
margin-bottom
:
6px
;
}
.introduction
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
59
,
65
,
75
);
margin-bottom
:
6px
;
}
.domain
{
font-size
:
14px
;
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
8px
;
p
{
display
:
inline-block
;
padding
:
1px
8px
;
border-radius
:
4px
;
margin-right
:
8px
;
border
:
1px
solid
;
}
.cl1
{
border-color
:
rgba
(
186
,
224
,
255
,
1
);
background-color
:
rgba
(
230
,
244
,
255
,
1
);
color
:
rgba
(
22
,
119
,
255
,
1
);
}
.cl2
{
border-color
:
rgba
(
217
,
247
,
190
,
1
);
background-color
:
rgba
(
246
,
255
,
237
,
1
);
color
:
rgba
(
82
,
196
,
26
,
1
);
}
.cl3
{
border-color
:
rgba
(
255
,
241
,
184
,
1
);
background-color
:
rgba
(
255
,
251
,
230
,
1
);
color
:
rgba
(
250
,
173
,
20
,
1
);
}
.cl4
{
border-color
:
rgba
(
255
,
204
,
199
,
1
);
background-color
:
rgba
(
255
,
241
,
240
,
1
);
color
:
rgba
(
255
,
77
,
79
,
1
);
}
.cl5
{
border-color
:
rgba
(
255
,
241
,
184
,
1
);
background-color
:
rgba
(
255
,
251
,
230
,
1
);
color
:
rgba
(
250
,
173
,
20
,
1
);
}
.cl6
{
border-color
:
rgba
(
255
,
204
,
199
,
1
);
background-color
:
rgba
(
255
,
241
,
240
,
1
);
color
:
rgba
(
255
,
77
,
79
,
1
);
}
}
}
}
.info-divide
{
width
:
1600px
;
height
:
64px
;
margin
:
16px
auto
;
background-color
:
rgba
(
255
,
255
,
255
,
0
.65
);
border-radius
:
10px
;
box-shadow
:
0px
0px
20px
rgba
(
25
,
69
,
130
,
0
.1
);
padding
:
5px
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
div
{
width
:
530px
;
height
:
54px
;
text-align
:
center
;
font-size
:
20px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
54px
;
color
:
rgb
(
59
,
65
,
75
);
border-radius
:
10px
;
cursor
:
pointer
;
&
:hover
{
background
:
rgba
(
231
,
243
,
255
,
1
);
}
}
.active
{
font-size
:
24px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
54px
;
color
:
rgb
(
5
,
95
,
194
);
background-color
:
rgba
(
231
,
243
,
255
,
1
);
border
:
2px
solid
rgba
(
174
,
214
,
255
,
1
);
}
}
.info-content
{
width
:
1600px
;
margin
:
16px
auto
;
display
:
flex
;
.left
{
width
:
1064px
;
margin-right
:
16px
;
.left-top
{
margin-bottom
:
16px
;
.chart-box
{
width
:
100%
;
height
:
200px
;
box-sizing
:
border-box
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
}
.left-center
{
margin-bottom
:
16px
;
}
/* ============ 最新动态 ============ */
.left-bottom
{
display
:
flex
;
flex-direction
:
column
;
:deep
(
.wrapper-header
)
{
position
:
relative
;
display
:
flex
;
align-items
:
center
;
height
:
56px
;
padding
:
0
24px
;
flex-shrink
:
0
;
}
:deep
(
.header-btn
)
{
top
:
16px
;
}
.input
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
display
:
flex
;
align-items
:
center
;
input
[
type
=
"checkbox"
]
{
width
:
14px
;
height
:
14px
;
accent-color
:
#1890ff
;
cursor
:
pointer
;
margin
:
0
;
}
}
.dynamic-main
{
padding
:
0
22px
;
.main-item
{
display
:
flex
;
flex-direction
:
row
;
gap
:
20px
;
align-items
:
flex-start
;
.time
{
flex-shrink
:
0
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-end
;
padding-top
:
18px
;
.year
{
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
color
:
rgba
(
5
,
95
,
194
,
1
);
line-height
:
24px
;
letter-spacing
:
1px
;
}
.date
{
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
color
:
rgba
(
5
,
95
,
194
,
1
);
line-height
:
24px
;
letter-spacing
:
1px
;
}
}
/* 时间轴列:上线段 + 图标 + 下线段 */
.timeline-col
{
flex-shrink
:
0
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
align-self
:
stretch
;
.timeline-line-top
{
width
:
2px
;
height
:
28px
;
background-color
:
rgba
(
234
,
236
,
238
,
1
);
flex-shrink
:
0
;
}
.timeline-icon
{
width
:
24px
;
height
:
24px
;
flex-shrink
:
0
;
img
{
width
:
24px
;
height
:
24px
;
}
}
.timeline-line-bottom
{
width
:
2px
;
flex
:
1
;
background-color
:
rgba
(
234
,
236
,
238
,
1
);
}
}
.content
{
flex
:
1
;
min-width
:
0
;
padding
:
16px
0
;
display
:
flex
;
flex-direction
:
column
;
gap
:
12px
;
/* remarks=true 涉华观点卡片 */
.content-type1
{
background-color
:
rgba
(
246
,
250
,
255
,
1
);
border-radius
:
4px
;
border
:
1px
solid
rgba
(
231
,
243
,
255
,
1
);
padding
:
12px
16px
;
display
:
flex
;
flex-direction
:
column
;
gap
:
8px
;
.content-title1
{
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
color
:
rgba
(
59
,
65
,
75
,
1
);
line-height
:
24px
;
cursor
:
pointer
;
}
.content-title-en
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
color
:
rgba
(
59
,
65
,
75
,
1
);
line-height
:
24px
;
cursor
:
pointer
;
text-align
:
justify
;
}
}
/* remarks=false 新闻 */
.content-type2
{
.content-title2
{
font-size
:
18px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
color
:
rgba
(
59
,
65
,
75
,
1
);
line-height
:
24px
;
cursor
:
pointer
;
}
}
.content-contentcontent
{
display
:
-
webkit-box
;
-webkit-box-orient
:
vertical
;
-webkit-line-clamp
:
3
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
color
:
rgba
(
95
,
101
,
108
,
1
);
line-height
:
24px
;
cursor
:
pointer
;
}
/* 标签 + 来源行 */
.content-tag
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
.origin
{
font-size
:
14px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
22px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
cursor
:
pointer
;
white-space
:
nowrap
;
flex-shrink
:
0
;
}
}
}
}
}
.pagination
{
width
:
100%
;
height
:
76px
;
margin
:
0
;
display
:
flex
;
padding
:
0
31px
0
36px
;
justify-content
:
space-between
;
align-items
:
center
;
border-top
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
position
:
relative
;
z-index
:
3
;
background
:
#fff
;
flex-shrink
:
0
;
.total
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
color
:
rgba
(
59
,
65
,
75
,
1
);
}
:deep
(
.custom-pagination
)
{
display
:
flex
;
align-items
:
center
;
}
:deep
(
.custom-pagination.el-pagination.is-background
.el-pager
li
)
{
min-width
:
32px
;
height
:
32px
;
line-height
:
32px
;
border-radius
:
6px
;
margin
:
0
6px
;
border
:
1px
solid
rgba
(
0
,
0
,
0
,
0
.15
);
background-color
:
#fff
;
color
:
rgb
(
95
,
101
,
108
);
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
}
:deep
(
.custom-pagination.el-pagination.is-background
.el-pager
li
.is-active
)
{
background-color
:
#fff
;
color
:
rgba
(
22
,
119
,
255
,
1
);
border-color
:
rgba
(
22
,
119
,
255
,
1
);
}
:deep
(
.custom-pagination.el-pagination.is-background
.el-pager
li
.is-ellipsis
)
{
border
:
none
;
background-color
:
transparent
;
color
:
rgb
(
95
,
101
,
108
);
min-width
:
16px
;
margin
:
0
6px
;
}
:deep
(
.custom-pagination.el-pagination.is-background
.btn-prev
),
:deep
(
.custom-pagination.el-pagination.is-background
.btn-next
)
{
min-width
:
32px
;
height
:
32px
;
border-radius
:
6px
;
border
:
1px
solid
rgba
(
0
,
0
,
0
,
0
.15
);
background-color
:
#fff
;
color
:
rgb
(
95
,
101
,
108
);
font-size
:
16px
;
font-family
:
"Microsoft YaHei"
;
margin
:
0
6px
;
}
:deep
(
.custom-pagination.el-pagination.is-background
.btn-prev.is-disabled
),
:deep
(
.custom-pagination.el-pagination.is-background
.btn-next.is-disabled
)
{
color
:
rgba
(
95
,
101
,
108
,
0
.45
);
border-color
:
rgb
(
235
,
238
,
242
);
background-color
:
#fff
;
}
}
}
}
.right
{
width
:
520px
;
.right-top
{
margin-bottom
:
16px
;
.main-content
{
width
:
520px
;
padding
:
0
48px
50px
34px
;
margin-top
:
16px
;
.baseInfo
{
width
:
438px
;
padding-bottom
:
12px
;
border-bottom
:
1px
solid
rgb
(
234
,
236
,
238
);
.baseInfo-item
{
display
:
flex
;
margin-bottom
:
12px
;
.baseInfo-item-title
{
flex
:
0
0
110px
;
width
:
110px
;
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
59
,
65
,
75
);
white-space
:
nowrap
;
}
.baseInfo-item-content
{
margin-left
:
14px
;
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
59
,
65
,
75
);
}
.long
{
width
:
306px
;
}
.longlong
{
width
:
306px
;
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
4px
;
.span
{
padding
:
2px
8px
;
border-radius
:
4px
;
background-color
:
rgba
(
230
,
244
,
255
,
1
);
border
:
1px
solid
rgba
(
186
,
224
,
255
,
1
);
color
:
rgba
(
22
,
119
,
255
,
1
);
font-size
:
14px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
20px
;
}
}
}
}
.company
{
width
:
438px
;
padding-top
:
19px
;
.company-title
{
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
59
,
65
,
75
);
margin-bottom
:
19px
;
}
.company-content
{
width
:
409px
;
max-height
:
114px
;
display
:
flex
;
flex-wrap
:
wrap
;
overflow-y
:
auto
;
scrollbar-width
:
none
;
-ms-overflow-style
:
none
;
.company-item
{
width
:
180px
;
height
:
49px
;
margin-bottom
:
16px
;
display
:
flex
;
align-items
:
center
;
cursor
:
pointer
;
img
{
width
:
48px
;
height
:
48px
;
margin-right
:
8px
;
}
.company-cn
{
width
:
130px
;
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
59
,
65
,
75
);
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
.company-name
{
width
:
130px
;
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
95
,
101
,
108
);
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
}
.company-item
:nth-child
(
2n-1
)
{
margin-right
:
39px
;
}
}
&
:
:-
webkit-scrollbar
{
display
:
none
;
}
}
}
}
.right-bottom
{
.content-main
{
width
:
480px
;
margin-left
:
16px
;
.content-item
{
width
:
454px
;
margin-bottom
:
16px
;
margin-left
:
26px
;
position
:
relative
;
.image01
{
width
:
14px
;
height
:
12
.13px
;
position
:
absolute
;
top
:
8px
;
left
:
-26px
;
}
.content-item-time
{
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
30px
;
color
:
rgb
(
5
,
95
,
194
);
margin-bottom
:
8px
;
}
.content-item-title
{
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
30px
;
color
:
rgb
(
59
,
65
,
75
);
margin-bottom
:
8px
;
}
.content-item-content
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
95
,
101
,
108
);
margin-bottom
:
8px
;
}
.content-item-door
{
width
:
300px
;
height
:
32px
;
display
:
flex
;
align-items
:
center
;
padding
:
4px
0
4px
11px
;
border-radius
:
4px
;
background-color
:
rgba
(
255
,
246
,
240
,
1
);
border
:
1px
solid
rgba
(
250
,
140
,
22
,
0
.4
);
img
{
width
:
20px
;
height
:
24px
;
margin-right
:
10px
;
}
span
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgba
(
255
,
149
,
77
,
1
);
}
}
}
:deep
(
.el-empty
)
{
padding-bottom
:
30px
;
}
}
}
}
}
}
/* ============ 自适应高度覆盖 ============ */
.auto-height-box
{
height
:
auto
!
important
;
:deep
(
.wrapper-main
)
{
height
:
auto
!
important
;
overflow
:
visible
!
important
;
}
}
/* ============ 科技领袖特有 ============ */
.tech-leader
{
.info-content
{
height
:
auto
;
}
}
/* ============ 国会议员特有 ============ */
.member-of-congress
{
.select
{
width
:
120px
;
}
.fund-table-main
{
padding
:
0
24px
;
}
.table-pagination
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
margin-top
:
16px
;
padding-bottom
:
16px
;
.table-pagination-total
{
font-size
:
16px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
}
}
:deep
(
.el-table
)
{
--el-table-border-color
:
rgba
(
234
,
236
,
238
,
1
);
--el-table-header-bg-color
:
transparent
;
tr
{
background-color
:
rgba
(
255
,
255
,
255
,
1
);
}
.highlight-row
{
background-color
:
rgba
(
247
,
248
,
249
,
1
)
!
important
;
}
th
.el-table__cell
{
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
}
td
.el-table__cell
{
border-bottom
:
none
;
}
}
}
/* ============ 智库特有 ============ */
.think-tank-person
{
.info-content
{
height
:
auto
;
}
}
/* ============ 弹框样式 ============ */
.viewpoint-dialog
{
border-radius
:
10px
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
}
.viewpoint-dialog.el-dialog
{
width
:
761px
!
important
;
height
:
669px
!
important
;
max-height
:
669px
!
important
;
border-radius
:
10px
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
overflow
:
hidden
;
display
:
flex
;
flex-direction
:
column
;
}
.viewpoint-dialog
.el-dialog__header
{
padding
:
0
;
margin
:
0
;
height
:
52px
;
flex-shrink
:
0
;
}
.viewpoint-dialog
.el-dialog__body
{
padding
:
0
;
flex
:
1
;
overflow
:
hidden
;
}
.viewpoint-header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
height
:
52px
;
padding
:
0
24px
;
border-bottom
:
1px
solid
rgba
(
231
,
243
,
255
,
1
);
box-sizing
:
border-box
;
}
.viewpoint-title
{
display
:
flex
;
align-items
:
center
;
}
.viewpoint-tag
{
font-size
:
18px
;
font-family
:
'Source Han Sans CN'
,
'Microsoft YaHei'
,
sans-serif
;
font-weight
:
700
;
color
:
rgba
(
206
,
79
,
81
,
1
);
line-height
:
24px
;
}
.viewpoint-label
{
font-size
:
18px
;
font-family
:
'Source Han Sans CN'
,
'Microsoft YaHei'
,
sans-serif
;
font-weight
:
700
;
color
:
rgba
(
59
,
65
,
75
,
1
);
line-height
:
24px
;
margin-left
:
2px
;
}
.viewpoint-close
{
width
:
32px
;
height
:
32px
;
cursor
:
pointer
;
}
.viewpoint-body
{
padding
:
18px
24px
24px
;
height
:
calc
(
669px
-
52px
);
max-height
:
calc
(
669px
-
52px
);
overflow-y
:
auto
;
display
:
flex
;
flex-direction
:
column
;
gap
:
12px
;
box-sizing
:
border-box
;
}
.viewpoint-item
{
display
:
flex
;
gap
:
8px
;
align-items
:
flex-start
;
}
.viewpoint-avatar
{
flex-shrink
:
0
;
padding-top
:
12px
;
}
.viewpoint-content
{
flex
:
1
;
display
:
flex
;
align-items
:
flex-start
;
}
.viewpoint-arrow
{
width
:
9px
;
height
:
72px
;
flex-shrink
:
0
;
background
:
url('../../techLeader/assets/arrow-icon.png')
no-repeat
center
/
100%
;
}
.member-of-congress
.viewpoint-arrow
{
background
:
url('../../memberOfCongress/assets/arrow-icon.png')
no-repeat
center
/
100%
;
}
.viewpoint-card
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
gap
:
2px
;
padding
:
8px
12px
;
background-color
:
rgba
(
246
,
250
,
255
,
1
);
border
:
1px
solid
rgba
(
231
,
243
,
255
,
1
);
border-radius
:
4px
;
}
.viewpoint-card-header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
}
.viewpoint-name
{
font-size
:
16px
;
font-family
:
'Source Han Sans CN'
,
'Microsoft YaHei'
,
sans-serif
;
font-weight
:
700
;
color
:
rgba
(
59
,
65
,
75
,
1
);
line-height
:
24px
;
}
.viewpoint-job
{
font-size
:
16px
;
font-family
:
'Source Han Sans CN'
,
'Microsoft YaHei'
,
sans-serif
;
font-weight
:
400
;
color
:
rgba
(
95
,
101
,
108
,
1
);
line-height
:
30px
;
}
.viewpoint-desc
{
font-size
:
16px
;
font-family
:
'Source Han Sans CN'
,
'Microsoft YaHei'
,
sans-serif
;
font-weight
:
400
;
color
:
rgba
(
59
,
65
,
75
,
1
);
line-height
:
24px
;
text-align
:
justify
;
}
.viewpoint-empty
{
text-align
:
center
;
padding
:
40px
0
;
color
:
rgba
(
170
,
173
,
177
,
1
);
font-size
:
14px
;
}
/* ============ 履历 tabs ============ */
.resume-tabs
{
display
:
flex
;
flex-direction
:
row
;
gap
:
8px
;
align-items
:
flex-start
;
}
.resume-tab
{
width
:
90px
;
height
:
28px
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
padding
:
1px
8px
;
border-radius
:
4px
;
border
:
1px
solid
rgba
(
230
,
231
,
232
,
1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
color
:
rgba
(
59
,
65
,
75
,
1
);
font-size
:
16px
;
font-family
:
'Microsoft YaHei'
,
sans-serif
;
font-weight
:
400
;
line-height
:
30px
;
cursor
:
pointer
;
box-sizing
:
border-box
;
}
.resume-tab.active
{
background
:
rgba
(
231
,
243
,
255
,
1
);
border-color
:
rgba
(
5
,
95
,
194
,
1
);
color
:
rgba
(
5
,
95
,
194
,
1
);
}
.tab-select
{
width
:
120px
;
:deep
(
.el-input__wrapper
)
{
box-shadow
:
none
;
border-radius
:
10px
;
height
:
28px
;
}
:deep
(
.el-input__wrapper
:hover
),
:deep
(
.el-input__wrapper.is-focus
)
{
box-shadow
:
none
!
important
;
}
:deep
(
.el-select__placeholder
)
{
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
22px
;
}
:deep
(
.el-select-dropdown__item
)
{
text-align
:
center
;
justify-content
:
center
;
}
:deep
(
.el-popper.is-light
)
{
border-radius
:
10px
;
}
}
/* ============ 基本信息通用样式 ============ */
.baseInfo-item
{
display
:
flex
;
align-items
:
flex-start
;
}
.baseInfo-item-title
{
flex
:
0
0
110px
;
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
59
,
65
,
75
);
white-space
:
nowrap
;
}
.baseInfo-item-content
{
flex
:
1
;
min-width
:
0
;
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
59
,
65
,
75
);
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
8px
12px
;
}
.education-item
{
white-space
:
nowrap
;
}
/* ============ 历史提案 tab ============ */
.proposal-wrapper
{
width
:
1600px
;
margin
:
16px
auto
;
position
:
relative
;
}
.proposal-tab-switcher
{
position
:
absolute
;
left
:
-124px
;
top
:
0
;
display
:
flex
;
flex-direction
:
column
;
gap
:
16px
;
align-items
:
center
;
}
.proposal-tab
{
width
:
112px
;
height
:
32px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
gap
:
4px
;
padding
:
0
16px
;
border-radius
:
16px
;
border
:
none
;
font-size
:
16px
;
font-family
:
'Microsoft YaHei'
,
sans-serif
;
font-weight
:
400
;
color
:
var
(
--
text-primary-65-color
);
background-color
:
var
(
--
bg-white-100
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
cursor
:
pointer
;
white-space
:
nowrap
;
&
.active
{
color
:
var
(
--
bg-white-100
);
background-color
:
var
(
--
color-primary-100
);
box-shadow
:
none
;
}
}
.proposal-tab-arrow
{
flex-shrink
:
0
;
}
</
style
>
<
style
lang=
"scss"
>
/* 下拉面板 teleported 到 body,需要非 scoped 样式 */
.el-select__popper
.el-select-dropdown__item
{
text-align
:
center
;
justify-content
:
center
;
}
</
style
>
src/views/characterPage/index.vue
浏览文件 @
2a5ddbf3
<
template
>
<div
class=
"character-page"
>
<img
src=
"./assets/images/background.png"
alt=
""
class=
"bg"
/>
<ModuleHeader
/>
<!-- 主要内容 -->
<div
class=
"main"
>
<!-- 科技领袖 -->
<tech-leader
v-if=
"type == 1"
/>
<!-- 国会议员 -->
<member-of-congress
v-if=
"type == 2"
/>
<!-- 智库研究人员 -->
<think-tank-person
v-if=
"type == 3"
/>
<unified-character
:type=
"type"
:person-id=
"personId"
/>
</div>
</div>
</
template
>
...
...
@@ -16,9 +12,8 @@
<
script
setup
>
import
{
ref
,
onMounted
}
from
'vue'
;
import
{
useRoute
}
from
'vue-router'
;
import
TechLeader
from
'./components/techLeader/index.vue'
;
import
MemberOfCongress
from
'./components/memberOfCongress/index.vue'
;
import
ThinkTankPerson
from
'./components/thinkTankPerson/index.vue'
;
import
UnifiedCharacter
from
'./components/unified/index.vue'
;
import
ModuleHeader
from
'@/components/base/moduleHeader/index.vue'
;
import
{
getCharacterGlobalInfo
}
from
"@/api/characterPage/characterPage.js"
;
...
...
src/views/innovationSubject/innovativeInstitutions/assets/background.png
0 → 100644
浏览文件 @
2a5ddbf3
1.2 MB
src/views/innovationSubject/innovativeInstitutions/index.vue
浏览文件 @
2a5ddbf3
...
...
@@ -77,6 +77,7 @@ import SchoolDetail from './tabs/SchoolDetail.vue'
import
ResearchStrength
from
'./tabs/ResearchStrength.vue'
import
Cooperation
from
'./tabs/Cooperation.vue'
import
OtherInfo
from
'./tabs/OtherInfo.vue'
import
bgImg
from
'./assets/background.png'
// 从路由获取 orgId
const
route
=
useRoute
()
...
...
@@ -127,16 +128,16 @@ const keyPeople = ref([
title
:
'第30任校长'
,
avatar
:
'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop&crop=face'
},
{
name
:
'迈克尔·桑德尔'
,
title
:
'政府学教授'
,
avatar
:
'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face'
},
{
name
:
'拉凯什·库拉纳'
,
title
:
'哈佛学院院长'
,
avatar
:
'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop&crop=face'
},
{
name
:
'迈克尔·桑德尔'
,
title
:
'政府学教授'
,
avatar
:
'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face'
},
{
name
:
'乔治·丘吉'
,
title
:
'哈佛医学院遗传学教授'
,
...
...
@@ -147,9 +148,9 @@ const keyPeople = ref([
// 统计数据
const
statistics
=
ref
([
{
label
:
'诺贝尔奖'
,
value
:
'161'
,
color
:
'rgba(5, 95, 194, 1)'
},
{
label
:
'图灵奖'
,
value
:
'18'
,
color
:
'rgba(
250, 173, 20
, 1)'
},
{
label
:
'图灵奖'
,
value
:
'18'
,
color
:
'rgba(
5, 95, 194
, 1)'
},
{
label
:
'菲尔兹奖'
,
value
:
'14'
,
color
:
'rgba(5, 95, 194, 1)'
},
{
label
:
'美国院士'
,
value
:
'273'
,
color
:
'rgba(
250, 173, 20
, 1)'
}
{
label
:
'美国院士'
,
value
:
'273'
,
color
:
'rgba(
5, 95, 194
, 1)'
}
])
// 历史事件
...
...
@@ -198,7 +199,7 @@ const latestDynamics = ref([
date
:
'10月10日'
,
title
:
'哈佛大学再遭电话钓鱼攻击致数据泄露'
,
content
:
'一名未授权人员通过社会工程手段入侵校友数据库,泄露联系方式、捐赠记录等信息。这是该校2025年内第二次重大数据泄露事件。'
,
tags
:
[{
name
:
'数
安治理
'
,
type
:
'tag9'
}],
tags
:
[{
name
:
'数
据泄露
'
,
type
:
'tag9'
}],
isHighlight
:
true
},
{
...
...
@@ -213,7 +214,7 @@ const latestDynamics = ref([
year
:
'2025'
,
date
:
'9月29日'
,
title
:
'常春藤盟校联合加强网络安全联盟'
,
content
:
'哈佛与普林斯顿、耶鲁、斯坦福
比亚
等校宣布成立"常春藤网络安全协作体",应对日益频繁的恶意网络攻击。'
,
content
:
'哈佛与普林斯顿、耶鲁、斯坦福等校宣布成立"常春藤网络安全协作体",应对日益频繁的恶意网络攻击。'
,
tags
:
[{
name
:
'生物科技'
,
type
:
'tag2'
}],
isHighlight
:
true
},
...
...
@@ -230,77 +231,61 @@ const latestDynamics = ref([
date
:
'9月15日'
,
title
:
'艾伦·M·加伯接任临时校长'
,
content
:
'原教务长艾伦·加伯(Alan M. Garber)出任哈佛第30任校长(临时),并完整复学术诚信与校园团结。'
,
tags
:
[{
name
:
'集成电路'
,
type
:
'tag6'
}],
isHighlight
:
true
tags
:
[{
name
:
'集成电路'
,
type
:
'tag6'
}]
},
{
year
:
'2025'
,
date
:
'9月11日'
,
title
:
'联邦法官叫停特朗普政府"禁招国际学生"令'
,
content
:
'2025年5月29日,马萨诸塞州联邦法官艾莉森·伯恩斯顿发布临时限制令,阻止国土安全部驱逐哈佛招收国际学生资质。'
,
tags
:
[{
name
:
'集成电路'
,
type
:
'tag6'
}],
isHighlight
:
true
tags
:
[{
name
:
'集成电路'
,
type
:
'tag6'
}]
},
{
year
:
'2025'
,
date
:
'
8月28
日'
,
title
:
'
哈佛启动"AI与伦理"研究中心
'
,
content
:
'
投资500万美元成立新的跨学科研究中心,旨在探索人工智能技术的伦理应用和社会影响,汇聚全球顶尖学者
。'
,
date
:
'
9月10
日'
,
title
:
'
特朗普政府要求哈佛30天内提交"改革证据"
'
,
content
:
'
美国教育部正式致函哈佛大学,要求在30天内提交针对招生公平、言论自由和反犹主义处理的整改方案与证据
。'
,
tags
:
[{
name
:
'人工智能'
,
type
:
'tag1'
}]
},
{
year
:
'2025'
,
date
:
'8月15日'
,
title
:
'哈佛医学院宣布重大癌症研究突破'
,
content
:
'研究团队开发出新型免疫疗法,在临床试验中显示出对晚期肺癌的显著疗效,成果已发表于《自然》杂志。'
,
tags
:
[{
name
:
'生物医学'
,
type
:
'tag2'
}]
},
{
year
:
'2025'
,
date
:
'7月30日'
,
title
:
'哈佛大学与MIT联合建立量子计算实验室'
,
content
:
'两校联合投资1亿美元,共同建立量子计算与信息研究实验室,推进量子技术的商业化应用。'
,
tags
:
[{
name
:
'前沿科技'
,
type
:
'tag11'
}]
date
:
'9月1日'
,
title
:
'哈佛2025届毕业典礼成政治声援现场'
,
content
:
'毕业典礼上多名学生举起声援巴勒斯坦标语,部分毕业生在演讲环节集体转身背对校方领导,表达对学校处理巴以议题方式的不满。'
,
tags
:
[{
name
:
'集成电路'
,
type
:
'tag6'
}]
},
{
year
:
'2025'
,
date
:
'
7月10
日'
,
title
:
'
2025年学年入学录取率创历史新低
'
,
content
:
'
2025年度本科生申请录取率仅为3.2%,创造了美国高等教育历史新低,共录取1,380名学生
。'
,
tags
:
[{
name
:
'
教育新闻'
,
type
:
'tag12
'
}]
date
:
'
8月25
日'
,
title
:
'
哈佛教授警告:国际博士生面临系统性驱逐风险
'
,
content
:
'
多位哈佛教授联名发表公开信,警告当前移民政策下国际博士生面临签证被撤销和驱逐出境的系统性风险,呼吁联邦政府保障学术自由
。'
,
tags
:
[{
name
:
'
能源'
,
type
:
'tag7'
},
{
name
:
'先进制造'
,
type
:
'tag10
'
}]
},
{
year
:
'2025'
,
date
:
'
6月20
日'
,
title
:
'
哈佛成立"气候变化研究全球中心"
'
,
content
:
'
新成立的中心将汇聚来自20个国家的气候科学家,共同应对全球气候变化挑战,年度预算达3000万美元
。'
,
tags
:
[{
name
:
'
气候变化'
,
type
:
'tag7
'
}]
date
:
'
8月19
日'
,
title
:
'
巴以冲突激化哈佛校园对立
'
,
content
:
'
哈佛校园内亲以色列和亲巴勒斯坦学生团体多次发生激烈对峙,校方被迫加强安保措施并设立"自由表达区"
。'
,
tags
:
[{
name
:
'
先进制造'
,
type
:
'tag10
'
}]
},
{
year
:
'2025'
,
date
:
'
6月5
日'
,
title
:
'
哈佛建筑学院获普利兹克建筑学奖
'
,
content
:
'
著名建筑师与哈佛建筑学院合作的项目获得2025年普利兹克建筑学奖,该奖项被誉为建筑领域的"诺贝尔奖"
。'
,
tags
:
[{
name
:
'
艺术建筑'
,
type
:
'tag8
'
}]
date
:
'
8月19
日'
,
title
:
'
联邦法院裁定哈佛招生不构成种族歧视
'
,
content
:
'
联邦上诉法院驳回原告上诉,维持原判认定哈佛大学在本科招生中考虑种族因素的做法不构成非法歧视
。'
,
tags
:
[{
name
:
'
先进制造'
,
type
:
'tag10
'
}]
},
{
year
:
'2025'
,
date
:
'5月15日'
,
title
:
'哈佛捐赠基金规模首次突破500亿美元'
,
content
:
'截至2024年6月30日,哈佛捐赠基金达501亿美元,创历史新高,位列全球大学捐赠基金首位。'
,
tags
:
[{
name
:
'财务报告'
,
type
:
'tag13'
}]
},
{
year
:
'2025'
,
date
:
'4月28日'
,
title
:
'哈佛法学院宣布取消LSAT考试要求'
,
content
:
'从2025年秋季开始,申请人可无需提交LSAT成绩,法学院将采用更全面的综合评估方式审核申请。'
,
tags
:
[{
name
:
'招生政策'
,
type
:
'tag14'
}]
date
:
'8月19日'
,
title
:
'哈佛捐赠基金规模达509亿美元,全球第一'
,
content
:
'截至2025财年末,哈佛大学捐赠基金规模达到509亿美元,继续稳居全球高校捐赠基金榜首,年均回报率达9.8%。'
,
tags
:
[{
name
:
'先进制造'
,
type
:
'tag10'
}]
}
])
// 分页
const
totalDynamics
=
ref
(
256
)
const
totalDynamics
=
ref
(
153
)
const
handlePageChange
=
(
page
)
=>
{
console
.
log
(
'Page changed to:'
,
page
)
...
...
@@ -316,7 +301,7 @@ const handleVisitWebsite = () => {
.university-detail
{
width
:
100%
;
height
:
100vh
;
background
:
rgba
(
247
,
248
,
249
,
1
)
;
background
:
url('/src/views/innovationSubject/innovativeInstitutions/assets/background.png')
no-repeat
center
center
;
position
:
relative
;
overflow
:
hidden
;
}
...
...
@@ -327,13 +312,12 @@ const handleVisitWebsite = () => {
position
:
absolute
;
top
:
0
;
left
:
0
;
background
:
linear-gradient
(
135deg
,
#1e5799
0%
,
#207cca
50%
,
#2989d8
100%
);
z-index
:
1
;
.bg-overlay
{
width
:
100%
;
height
:
100%
;
background
:
linear-gradient
(
to
bottom
,
rgba
(
30
,
87
,
153
,
0
.
8
)
,
rgba
(
32
,
124
,
202
,
0
.6
));
background
:
linear-gradient
(
to
bottom
,
rgba
(
30
,
87
,
153
,
0
.
5
)
,
rgba
(
32
,
124
,
202
,
0
.3
));
}
}
...
...
@@ -347,65 +331,78 @@ const handleVisitWebsite = () => {
}
.header-section
{
padding
:
80px
;
padding
:
80px
160px
;
display
:
flex
;
justify-content
:
center
;
padding-bottom
:
16px
;
.header-content
{
width
:
1600px
;
height
:
160px
;
display
:
flex
;
align-items
:
flex-start
;
gap
:
24px
;
background
:
rgba
(
255
,
255
,
255
,
0
.8
);
border
:
1px
solid
rgba
(
255
,
255
,
255
,
1
);
border-radius
:
10px
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
padding
:
16px
19px
;
position
:
relative
;
.logo
{
width
:
1
10
px
;
height
:
1
30
px
;
width
:
1
28
px
;
height
:
1
28
px
;
background
:
rgba
(
255
,
255
,
255
,
0
.9
);
border-radius
:
8
px
;
padding
:
10px
;
border-radius
:
100
px
;
overflow
:
hidden
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
flex-shrink
:
0
;
img
{
max-width
:
100%
;
max-height
:
100%
;
object-fit
:
contain
;
object-fit
:
cover
;
border-radius
:
100px
;
}
}
.info
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
gap
:
8px
;
.name-row
{
display
:
flex
;
align-items
:
baseline
;
gap
:
16px
;
margin-bottom
:
8px
;
flex-direction
:
column
;
gap
:
4px
;
.name-cn
{
font-size
:
32
px
;
font-size
:
24
px
;
font-weight
:
700
;
font-family
:
'Microsoft YaHei'
,
sans-serif
;
color
:
white
;
font-family
:
'
Source Han Sans CN'
,
'
Microsoft YaHei'
,
sans-serif
;
color
:
rgba
(
59
,
65
,
75
,
1
)
;
margin
:
0
;
}
.name-en
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
'Microsoft YaHei'
,
sans-serif
;
color
:
rgba
(
255
,
255
,
255
,
0
.9
);
font-family
:
'Source Han Sans CN'
,
'Microsoft YaHei'
,
sans-serif
;
color
:
rgba
(
59
,
65
,
75
,
1
);
line-height
:
24px
;
}
}
.description
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
'Microsoft YaHei'
,
sans-serif
;
font-family
:
'
Source Han Sans CN'
,
'
Microsoft YaHei'
,
sans-serif
;
line-height
:
24px
;
color
:
rgba
(
255
,
255
,
255
,
0
.9
);
margin-bottom
:
12px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
text-align
:
justify
;
margin
:
0
;
}
.tags
{
...
...
@@ -418,15 +415,19 @@ const handleVisitWebsite = () => {
.visit-btn
{
display
:
flex
;
align-items
:
center
;
gap
:
6
px
;
padding
:
8
px
16px
;
gap
:
8
px
;
padding
:
5
px
16px
;
background
:
rgba
(
5
,
95
,
194
,
1
);
border-radius
:
4
px
;
border-radius
:
6
px
;
color
:
white
;
font-size
:
1
4
px
;
font-size
:
1
6
px
;
font-family
:
'Microsoft YaHei'
,
sans-serif
;
cursor
:
pointer
;
transition
:
opacity
0
.2s
;
flex-shrink
:
0
;
line-height
:
22px
;
align-self
:
flex-start
;
margin-top
:
16px
;
&
:hover
{
opacity
:
0
.9
;
...
...
src/views/ruleRestriction/alliance/index.vue
浏览文件 @
2a5ddbf3
...
...
@@ -21,12 +21,11 @@
<div
class=
"flex-display content-row"
>
<div
class=
"left-col"
>
<AnalysisBox
title=
"
打压
动态"
:showAllBtn=
"false"
>
<AnalysisBox
title=
"动态"
:showAllBtn=
"false"
>
<div
class=
"news-list-wrap"
>
<div
class=
"news-scroll-area"
>
<template
v-for=
"(item, idx) in newsList"
:key=
"item.id"
>
<div
v-for=
"item in newsList"
:key=
"item.id"
class=
"news-item flex-display mouse-hover"
@
click=
"handleNewsClick(item)"
>
...
...
@@ -34,15 +33,19 @@
<span
class=
"item-thumb-text"
>
新闻资讯
</span>
</div>
<div
class=
"item-body"
>
<div
class=
"item-top flex-display"
>
<p
class=
"text-tip-1-bold text-primary-80-clor item-title"
>
{{
item
.
title
}}
</p>
<p
class=
"text-tip-2 text-primary-65-clor item-content"
>
{{
item
.
content
}}
</p>
</div>
<div
class=
"item-meta flex-display"
>
<span
class=
"text-tip-2 text-primary-50-clor"
>
{{
item
.
date
}}
</span>
<span
class=
"text-tip-2 text-primary-50-clor meta-sep"
>
·
</span>
<span
class=
"text-tip-2 text-primary-50-clor"
>
{{
item
.
source
}}
</span>
<span
class=
"text-tip-2 text-primary-65-clor"
>
{{
item
.
date
}}
</span>
<span
class=
"text-tip-2 text-primary-65-clor meta-sep"
>
·
</span>
<span
class=
"text-tip-2 text-primary-65-clor"
>
{{
item
.
source
}}
</span>
</div>
</div>
<p
class=
"text-tip-2 text-primary-65-clor item-content"
>
{{
item
.
content
}}
</p>
</div>
</div>
<div
v-if=
"idx
<
newsList
.
length
-
1
"
class=
"news-divider"
></div>
</
template
>
</div>
<div
class=
"pagination-row flex-display"
>
...
...
@@ -59,7 +62,7 @@
@
click=
"changePage(p)"
>
{{ p }}
</button>
<span
v-if=
"pagination.page < pagination.totalPages - 2"
class=
"page-ellipsis text-primary-50-clor"
>
...
</span>
<button
class=
"page-btn"
:class=
"
{ active: pagination.page === pagination.totalPages }" @click="changePage(pagination.totalPages)">
{{
pagination
.
totalPages
}}
</button>
<button
v-if=
"pagination.totalPages > 1"
class=
"page-btn"
:class=
"{ active: pagination.page === pagination.totalPages }"
@
click=
"changePage(pagination.totalPages)"
>
{{ pagination.totalPages }}
</button>
<button
class=
"page-btn"
:disabled=
"pagination.page === pagination.totalPages"
@
click=
"changePage(pagination.page + 1)"
>
>
</button>
</div>
</div>
...
...
@@ -68,7 +71,7 @@
</div>
<div
class=
"right-col"
>
<AnalysisBox
title=
"
联盟
简介"
:showAllBtn=
"false"
>
<AnalysisBox
title=
"简介"
:showAllBtn=
"false"
>
<div
class=
"intro-wrap"
>
<div
class=
"intro-row flex-display"
>
<span
class=
"text-tip-2-bold text-primary-80-clor intro-label"
>
时间:
</span>
...
...
@@ -104,7 +107,7 @@ import { ref, computed, onMounted } from 'vue'
import
{
useRoute
,
useRouter
}
from
'vue-router'
import
AnalysisBox
from
'@/components/base/boxBackground/analysisBox.vue'
import
AreaTag
from
'@/components/base/AreaTag/index.vue'
import
{
get
NewsDetail
,
getNewsList
}
from
'./mock/newsDetail
'
import
{
get
UnionIntroduction
,
getUnionDynamicList
}
from
'@/api/ruleRestriction/index.js
'
const
route
=
useRoute
()
const
router
=
useRouter
()
...
...
@@ -125,10 +128,10 @@ const newsDetail = ref({
const
newsList
=
ref
([])
const
pagination
=
ref
({
page
:
5
,
page
:
1
,
pageSize
:
10
,
total
:
153
,
totalPages
:
1
6
total
:
0
,
totalPages
:
1
})
const
visiblePages
=
computed
(()
=>
{
...
...
@@ -145,16 +148,48 @@ const visiblePages = computed(() => {
return
pages
})
const
loadNewsDetail
=
()
=>
{
newsDetail
.
value
=
getNewsDetail
(
newsId
.
value
)
const
loadNewsDetail
=
async
()
=>
{
try
{
const
res
=
await
getUnionIntroduction
(
newsId
.
value
)
if
(
res
.
code
===
200
)
{
const
data
=
res
.
data
newsDetail
.
value
=
{
title
:
data
.
unionNameZh
||
''
,
subTitle
:
data
.
unionName
||
''
,
tags
:
data
.
domains
||
[],
time
:
data
.
time
||
''
,
background
:
data
.
background
||
''
,
countries
:
(
data
.
memberCountries
||
[]).
map
(
c
=>
({
name
:
c
.
countryName
}))
}
}
}
catch
(
error
)
{
console
.
error
(
'获取联盟简介失败:'
,
error
)
}
}
const
loadNewsList
=
(
page
=
1
)
=>
{
const
data
=
getNewsList
(
page
,
pagination
.
value
.
pageSize
)
newsList
.
value
=
data
.
list
pagination
.
value
.
page
=
data
.
page
pagination
.
value
.
total
=
data
.
total
pagination
.
value
.
totalPages
=
data
.
totalPages
const
loadNewsList
=
async
(
page
=
1
)
=>
{
try
{
const
res
=
await
getUnionDynamicList
({
unionId
:
newsId
.
value
,
currentPage
:
page
,
pageSize
:
pagination
.
value
.
pageSize
})
if
(
res
.
code
===
200
)
{
const
data
=
res
.
data
newsList
.
value
=
(
data
.
content
||
[]).
map
(
item
=>
({
id
:
item
.
newsId
,
title
:
item
.
title
||
''
,
content
:
item
.
summary
||
''
,
date
:
item
.
publishedTime
||
''
,
source
:
item
.
source
||
''
}))
pagination
.
value
.
page
=
page
pagination
.
value
.
total
=
data
.
totalElements
||
0
pagination
.
value
.
totalPages
=
data
.
totalPages
||
1
}
}
catch
(
error
)
{
console
.
error
(
'获取联盟动态失败:'
,
error
)
}
}
const
changePage
=
(
page
)
=>
{
...
...
@@ -168,11 +203,14 @@ const handleNewsClick = (item) => {
onMounted
(()
=>
{
loadNewsDetail
()
loadNewsList
(
pagination
.
value
.
page
)
loadNewsList
(
1
)
})
</
script
>
<
style
lang=
"scss"
scoped
>
:deep
(
.main-container1
)
{
overflow
:
auto
;
}
.page-wrap
{
width
:
100%
;
min-height
:
100vh
;
...
...
@@ -228,7 +266,6 @@ onMounted(() => {
.left-col
{
width
:
1064px
;
height
:
1284px
;
flex-shrink
:
0
;
}
...
...
@@ -241,33 +278,32 @@ onMounted(() => {
.news-list-wrap
{
display
:
flex
;
flex-direction
:
column
;
height
:
calc
(
100%
-
48px
);
padding
:
0
20px
;
}
.news-scroll-area
{
flex
:
1
;
min-height
:
0
;
overflow-y
:
auto
;
}
.news-item
{
gap
:
16px
;
padding
:
16px
0
;
border-bottom
:
1px
solid
#eaecee
;
align-items
:
flex-start
;
gap
:
20px
;
padding
:
0
;
align-items
:
center
;
cursor
:
pointer
;
transition
:
background
0
.15s
;
}
&
:last-child
{
border-bottom
:
none
;
}
.news-divider
{
width
:
100%
;
height
:
1px
;
background
:
#f0f2f4
;
margin
:
12px
0
;
}
.item-thumb
{
width
:
100
px
;
height
:
7
0
px
;
border-radius
:
6
px
;
width
:
97
px
;
height
:
7
2
px
;
border-radius
:
4
px
;
background
:
linear-gradient
(
135deg
,
#4a7bf7
0%
,
#6b8cff
100%
);
flex-shrink
:
0
;
}
...
...
@@ -280,13 +316,24 @@ onMounted(() => {
.item-body
{
flex
:
1
;
min-width
:
0
;
display
:
flex
;
flex-direction
:
column
;
gap
:
4px
;
}
.item-top
{
align-items
:
center
;
width
:
100%
;
gap
:
0
;
}
.item-title
{
margin
:
0
0
6px
0
;
margin
:
0
;
overflow
:
hidden
;
white-space
:
nowrap
;
text-overflow
:
ellipsis
;
flex
:
1
;
min-width
:
0
;
}
.item-content
{
...
...
src/views/technologyFigures/component/PersonNewsCard.vue
浏览文件 @
2a5ddbf3
...
...
@@ -224,6 +224,19 @@ export default {
:deep
(
.el-timeline
)
{
max-width
:
688px
!important
;
padding
:
0
;
overflow
:
hidden
;
}
:deep
(
.el-timeline-item
)
{
padding-bottom
:
4px
;
}
:deep
(
.el-timeline-item
:last-child
)
{
padding-bottom
:
0
;
}
:deep
(
.el-timeline-item
:last-child
.el-timeline-item__wrapper
)
{
padding-bottom
:
0
;
}
:deep
(
.el-timeline-item__wrapper
)
{
...
...
@@ -253,4 +266,9 @@ export default {
text-align
:
justify
;
}
:deep
(
.el-timeline-item
:last-child
.el-timeline-item__tail
)
{
visibility
:
hidden
;
display
:
none
;
}
</
style
>
src/views/technologyFigures/component/PersonTable.vue
浏览文件 @
2a5ddbf3
...
...
@@ -28,9 +28,9 @@
<!-- 涉华观点次数列 -->
<div
class=
"row-col col-count"
>
<el-progress
:percentage=
"getProgress(item.
mediaQuote
Count)"
:show-text=
"false"
style=
"/* 矩形 244 */ width: 82px; height: 8px"
:status=
"getStatus(getProgress(item.
mediaQuote
Count))"
/>
<span
class=
"count-text"
>
{{
item
.
mediaQuote
Count
}}
次
</span>
<el-progress
:percentage=
"getProgress(item.
chinaRelated
Count)"
:show-text=
"false"
style=
"/* 矩形 244 */ width: 82px; height: 8px"
:status=
"getStatus(getProgress(item.
chinaRelated
Count))"
/>
<span
class=
"count-text"
>
{{
item
.
chinaRelated
Count
}}
次
</span>
</div>
<!-- 媒体引用次数列 -->
...
...
@@ -46,7 +46,6 @@
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
defineProps
,
watch
}
from
"vue"
;
import
personData
from
"../json/personData.json"
;
// 引入JSON数据
import
{
getMainCharactersView
}
from
"@/api/technologyFigures/technologyFigures"
;
import
{
useCharacterNav
}
from
"../utils/useCharacterNav"
;
const
{
handleClickToCharacter
}
=
useCharacterNav
();
...
...
@@ -99,14 +98,16 @@ const handlegetMainCharactersViewFn = async () => {
});
}
}
catch
(
error
)
{}
}
catch
(
error
)
{
console
.
error
(
"获取主要人物涉华观点统计失败:"
,
error
);
}
};
onMounted
(
async
()
=>
{
handlegetMainCharactersViewFn
();
});
const
personList
=
ref
();
const
personList
=
ref
(
[]
);
// 进度条状态
const
getStatus
=
_percent
=>
{
const
percent
=
_percent
;
...
...
@@ -120,8 +121,9 @@ const getStatus = _percent => {
};
// 计算进度条宽度(基于最大值的百分比)
const
getMaxCount
=
()
=>
{
const
counts
=
personList
.
value
.
flatMap
(
item
=>
[
item
.
chinaRelatedCount
,
item
.
mediaQuoteCount
]);
return
Math
.
max
(...
counts
);
const
counts
=
personList
.
value
.
flatMap
(
item
=>
[
item
.
chinaRelatedCount
||
0
,
item
.
mediaQuoteCount
||
0
]);
if
(
counts
.
length
===
0
)
return
1
;
return
Math
.
max
(...
counts
,
1
);
};
const
getProgress
=
count
=>
(
count
/
getMaxCount
())
*
100
;
</
script
>
...
...
src/views/technologyFigures/component/SourceLibrary.vue
浏览文件 @
2a5ddbf3
...
...
@@ -12,7 +12,7 @@
<img
:src=
"item.avatar"
alt=
""
class=
"source-library-avatar"
/>
</div>
<div
class=
"source-library-text-content"
>
<div
class=
"card-main"
:class=
"
{ 'no-title': !item.title }
">
<div
class=
"card-main"
"
>
<h3
class=
"source-library-name"
>
{{
item
.
name
}}
</h3>
<p
class=
"source-library-title"
v-if=
"item.title"
>
{{
item
.
title
}}
</p>
<div
class=
"taglist"
>
...
...
@@ -177,7 +177,11 @@ const handleClcikToCharacter = async id => {
ElMessage
.
warning
(
"找不到当前人员的类型值!"
);
return
;
}
}
catch
(
error
)
{
}
}
catch
(
error
)
{
if
(
error
.
name
!==
"AbortError"
)
{
console
.
error
(
"获取人物资源库失败:"
,
error
);
}
}
}
;
onMounted
(
async
()
=>
{
...
...
@@ -209,7 +213,7 @@ const handlePageChange = p => {
box
-
sizing
:
border
-
box
;
display
:
flex
;
border
:
1
px
solid
rgba
(
234
,
236
,
238
,
1
);
border
-
radius
:
var
(
---
10
,
10
px
)
;
border
-
radius
:
10
px
;
padding
:
20
px
18
px
;
box
-
shadow
:
0
px
0
px
20
px
0
px
rgba
(
25
,
69
,
130
,
0.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
...
...
@@ -249,9 +253,9 @@ const handlePageChange = p => {
.
source
-
library
-
avatar
{
/* 椭圆 142 */
width
:
88
px
;
height
:
88
px
;
border
-
radius
:
50
%
;
width
:
92
px
;
height
:
121
px
;
//
border-radius: 50%;
}
.
source
-
library
-
text
-
content
{
...
...
src/views/technologyFigures/component/TimelineMap.vue
浏览文件 @
2a5ddbf3
...
...
@@ -81,11 +81,6 @@
import
*
as
echarts
from
"echarts"
;
import
worldJson
from
"@/assets/json/world.json"
;
import
{
getCharacterTrends
}
from
"@/api/technologyFigures/technologyFigures"
;
import
{
ref
}
from
"vue"
;
const
CharacterTrends
=
ref
([]);
const
time
=
ref
(
""
);
const
date
=
ref
(
""
);
const
handlegetCharacterTrendsFn
=
async
()
=>
{
const
params
=
{
...
...
@@ -104,7 +99,9 @@ const handlegetCharacterTrendsFn = async () => {
};
});
}
}
catch
(
error
)
{}
}
catch
(
error
)
{
console
.
error
(
"获取人物动向失败:"
,
error
);
}
};
function
getDateDaysAgo
(
days
)
{
...
...
@@ -169,6 +166,9 @@ export default {
tickWidth
:
10
,
viewStartIndex
:
0
,
viewDays
:
120
,
CharacterTrends
:
[],
time
:
""
,
date
:
""
,
};
},
computed
:
{
...
...
src/views/technologyFigures/component/speechStance.vue
浏览文件 @
2a5ddbf3
...
...
@@ -12,7 +12,7 @@
<p
class=
"speech-stance-title"
>
{{
item
.
positionTitle
}}
</p>
</div>
<p
class=
"speech-stance-content"
:title=
"item.remarks"
>
{{
item
.
remarks
}}
</p>
<p
class=
"speech-stance-content"
:title=
"item.remarks"
>
<span
class=
"speech-stance-text"
>
{{
item
.
remarks
}}
</span>
</p>
</div>
</div>
...
...
@@ -95,11 +95,11 @@ const handleClcikToCharacter = async id => {
const
aId
=
ref
();
const
params
=
ref
({});
watch
(()
=>
props
.
fieldSelected
,
(
val
)
=>
{
aId
.
value
=
props
.
areaId
;
if
(
v
al
!==
"全部领域"
){
params
.
value
.
industryId
=
a
Id
.
value
;
watch
(()
=>
[
props
.
fieldSelected
,
props
.
areaId
]
,
(
val
)
=>
{
const
[
fieldVal
,
areaVal
]
=
val
;
aId
.
value
=
areaVal
;
if
(
fieldV
al
!==
"全部领域"
){
params
.
value
.
industryId
=
a
reaVal
;
}
else
{
params
.
value
=
{};
}
...
...
@@ -117,7 +117,9 @@ const handlegetPersonRelationFn = async () => {
if
(
res
.
code
===
200
)
{
PersonRelation
.
value
=
res
.
data
;
}
}
catch
(
error
)
{}
}
catch
(
error
)
{
console
.
error
(
"获取重要人物言论及立场失败:"
,
error
);
}
};
onMounted
(
async
()
=>
{
...
...
@@ -129,15 +131,13 @@ onMounted(async () => {
<
style
scoped
>
.speech-stance-container
{
width
:
1530px
;
/* max-width: 900px; */
margin
:
0
auto
;
margin
:
5px
35px
;
margin
:
15px
35px
;
}
.speech-stance-grid
{
display
:
grid
;
grid-template-columns
:
repeat
(
2
,
1
fr
);
gap
:
30
px
9px
;
gap
:
28
px
9px
;
}
/* 响应式:小屏变一列 */
...
...
@@ -204,8 +204,16 @@ onMounted(async () => {
line-height
:
30px
;
letter-spacing
:
0px
;
text-align
:
left
;
/* 宽度保持不变,ellipsis 移至内部 span */
}
.speech-stance-text
{
display
:
inline-block
;
max-width
:
100%
;
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
padding-right
:
24px
;
vertical-align
:
top
;
}
</
style
>
\ No newline at end of file
src/views/technologyFigures/index.vue
浏览文件 @
2a5ddbf3
...
...
@@ -81,7 +81,7 @@
<OverviewMainBox
title=
"人物新闻动态"
width=
"1064px"
height=
"460px"
@
to-detail=
"handleClcikToCharacter(curnews.personId, curnews.name)"
>
<!-- 自定义左上角图标插槽 -->
<template
#
header
I
con
>
<template
#
header
-i
con
>
<img
src=
"./assets/images/personNewIcon.svg "
alt=
""
/>
</
template
>
...
...
@@ -95,7 +95,7 @@
</div>
<div
class=
"box1-main"
>
<el-carousel
ref=
"carouselRef"
height=
"35
4
px"
:autoplay=
"true"
:interval=
"3000"
<el-carousel
ref=
"carouselRef"
height=
"35
2
px"
:autoplay=
"true"
:interval=
"3000"
arrow=
"never"
indicator-position=
"none"
@
change=
"handleCarouselChange"
>
<el-carousel-item
v-for=
"person in newsDynamics"
:key=
"person.personId"
>
<div
class=
"carousel-content"
>
...
...
@@ -104,8 +104,11 @@
<img
:src=
"person.imageUrl"
alt=
"人物头像"
/>
</div>
<!-- 竖线分隔 -->
<!-- <div class="vertical-divider"></div> -->
<!-- 事件列表 -->
<div
class=
"events"
>
<div
class=
"events"
style=
"height: 64px;"
>
<!-- 头部区域 -->
<div
class=
"header"
>
<div
class=
"info"
>
...
...
@@ -156,14 +159,15 @@
postDate=
"signalTime"
name=
"signalTitle"
riskLevel=
"signalLevel"
/>
<RiskSignalOverviewDetailDialog
v-model=
"isRiskOverviewDetailOpen"
/>
</div>
<DivideHeader
id=
"position2"
class=
"divide-header"
:titleText=
"'言论动态'"
></DivideHeader>
<DivideHeader
id=
"position2"
class=
"divide-header"
:titleText=
"'言论动态'"
v-if=
"false"
></DivideHeader>
<div
class=
"center-center"
>
<div
class=
"box3"
>
<div
class=
"box3"
v-if=
"false"
>
<div
class=
"box3-header"
>
<div
class=
"box3-header-left"
>
<div
class=
"box3-header-icon"
>
<img
src=
"./assets/images/TechnologyFigures-icon3.png"
alt=
""
/>
</div>
<!-- <div class="box3-header-title">{{ "人物动向" }}</div> -->
<div
class=
"header-title"
style=
"width: 1560px; display: flex; justify-content: space-between; margin-top: 10px"
>
...
...
@@ -235,7 +239,14 @@
</div>
</div>
</div>
<div
class=
"box5-main"
><WordCloudChart
width=
"790px"
v-if=
"WordLoading"
:data=
"CharacterOpinionWordCloud"
/></div>
<div
class=
"box5-main"
>
<WordCloudChart
v-if=
"CharacterOpinionWordCloud.length > 0"
:key=
"wordCloudKey"
width=
"790px"
:data=
"CharacterOpinionWordCloud"
/>
<el-empty
v-else
description=
"暂无数据"
/>
</div>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
><img
:src=
"tipsIcon"
alt=
""
/></div>
<div
class=
"data-origin-text"
>
科技人物观点词云,数据来源:公开新闻报道及社交媒体数据
</div>
</div>
</div>
<div
class=
"box6"
>
<div
class=
"box6-header"
style=
"width: 790px"
>
...
...
@@ -255,6 +266,10 @@
</div>
</div>
<div
class=
"box6-main"
id=
"box6Chart"
></div>
<div
class=
"data-origin-box"
style=
"margin-top: 18px;"
>
<div
class=
"data-origin-icon"
><img
:src=
"tipsIcon"
alt=
""
/></div>
<div
class=
"data-origin-text"
>
科技人物观点涉及领域变化趋势,数据来源:公开新闻报道及社交媒体数据
</div>
</div>
</div>
</div>
<div
class=
"center-footer1"
>
...
...
@@ -268,6 +283,10 @@
</div>
</div>
<div
class=
"box7-main"
id=
"box7Chart"
></div>
<div
class=
"data-origin-box"
style=
"padding-top: 3px;"
>
<div
class=
"data-origin-icon"
><img
:src=
"tipsIcon"
alt=
""
/></div>
<div
class=
"data-origin-text"
>
科技人物类型,数据来源:公开新闻报道及社交媒体数据
</div>
</div>
</div>
<div
class=
"box8"
>
<div
class=
"box8-header"
>
...
...
@@ -294,6 +313,10 @@
<div
class=
"box8-main"
>
<PersonTable
:persontypeid=
"persontypeid"
:yearSelect=
"yearSelect"
/>
</div>
<div
class=
"data-origin-box"
style=
"margin-top:14px"
>
<div
class=
"data-origin-icon"
><img
:src=
"tipsIcon"
alt=
""
/></div>
<div
class=
"data-origin-text"
>
观点统计,数据来源:公开新闻报道及社交媒体数据
</div>
</div>
</div>
</div>
</div>
...
...
@@ -343,7 +366,6 @@ import getDonutChart from "./utils/donutChart.js";
// 组件
import
TimelineMap
from
"./component/TimelineMap.vue"
;
import
PersonNewsCard
from
"./component/PersonNewsCard.vue"
;
import
SpeechStance
from
"./component/speechStance.vue"
;
import
PersonTable
from
"./component/PersonTable.vue"
;
import
SourceLibrary
from
"./component/SourceLibrary.vue"
;
...
...
@@ -448,6 +470,7 @@ const handlegetareaTypeFn = async () => {
};
const
WordLoading
=
ref
(
false
)
const
wordCloudKey
=
ref
(
0
)
// 获取科技人物观点词云
const
CharacterOpinionWordCloud
=
ref
([]);
...
...
@@ -472,7 +495,7 @@ const handlegetCharacterOpinionWordCloudFn = async () => {
}
});
WordLoading
.
value
=
true
wordCloudKey
.
value
++
}
}
catch
(
error
)
{
}
};
...
...
@@ -655,7 +678,7 @@ const handleClcikToCharacter = async (id, name) => {
personTypeName
=
arr
[
0
].
typeName
;
console
.
log
(
"personTypeName"
,
personTypeName
);
if
(
personTypeName
===
"科技企业领袖"
)
{
if
(
personTypeName
===
"科技企业领袖"
||
personTypeName
===
"政府官员"
)
{
type
=
1
;
}
else
if
(
personTypeName
===
"国会议员"
)
{
type
=
2
;
...
...
@@ -1277,7 +1300,7 @@ onMounted(async () => {
.box1-main
{
width
:
1009px
;
height
:
35
4
px
;
height
:
35
2
px
;
margin-top
:
28px
;
margin-left
:
40px
;
}
...
...
@@ -1556,7 +1579,7 @@ onMounted(async () => {
.box4-main
{
height
:
402px
;
overflow-y
:
auto
;
overflow-y
:
hidden
;
box-sizing
:
border-box
;
padding-top
:
8px
;
}
...
...
@@ -1564,15 +1587,14 @@ onMounted(async () => {
}
.center-footer
{
margin-top
:
21px
;
height
:
460px
;
margin-top
:
16px
;
display
:
flex
;
justify-content
:
center
;
gap
:
1
5
px
;
gap
:
1
6
px
;
.box5
{
width
:
792px
;
height
:
46
0px
;
height
:
50
0px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-radius
:
10px
;
...
...
@@ -1619,7 +1641,7 @@ onMounted(async () => {
.box6
{
width
:
792px
;
height
:
46
0px
;
height
:
50
0px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-radius
:
10px
;
...
...
@@ -1669,11 +1691,11 @@ onMounted(async () => {
margin-top
:
16px
;
display
:
flex
;
justify-content
:
center
;
gap
:
1
5
px
;
gap
:
1
6
px
;
.box7
{
width
:
792px
;
height
:
46
0px
;
height
:
50
0px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-radius
:
10px
;
...
...
@@ -1719,13 +1741,13 @@ onMounted(async () => {
.box7-main
{
height
:
405px
;
margin
:
0
59px
0
59
px
;
margin
:
0
24px
0
24
px
;
}
}
.box8
{
width
:
792px
;
height
:
46
0px
;
height
:
50
0px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-radius
:
10px
;
...
...
@@ -1895,13 +1917,13 @@ onMounted(async () => {
padding
:
1px
8px
1px
8px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
23
0
,
231
,
232
,
1
);
border
:
1px
solid
rgba
(
23
4
,
236
,
238
,
1
);
border-radius
:
4px
;
background
:
rgba
(
255
,
255
,
255
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
30
px
;
line-height
:
22
px
;
letter-spacing
:
0px
;
text-align
:
left
;
cursor
:
pointer
;
...
...
@@ -1923,11 +1945,11 @@ onMounted(async () => {
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
5
,
95
,
194
,
1
);
border-radius
:
4px
;
background
:
rgba
(
2
31
,
243
,
255
,
1
);
background
:
rgba
(
2
46
,
251
,
255
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
1
6
px
;
font-size
:
1
4
px
;
font-weight
:
400
;
line-height
:
30
px
;
line-height
:
22
px
;
letter-spacing
:
0px
;
text-align
:
left
;
cursor
:
pointer
;
...
...
@@ -2149,23 +2171,34 @@ onMounted(async () => {
.avatar
{
width
:
2
80
px
;
height
:
35
4
px
;
width
:
2
66
px
;
height
:
35
2
px
;
flex-shrink
:
0
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
cover
;
border-radius
:
4px
;
}
}
.vertical-divider
{
width
:
2px
;
align-self
:
center
;
height
:
54%
;
background
:
rgba
(
230
,
231
,
232
,
1
);
border-radius
:
1
.5px
;
flex-shrink
:
0
;
margin
:
0
10px
;
}
.events
{
flex
:
1
;
padding
:
0
20px
;
.header
{
padding-top
:
16px
;
padding-top
:
0
;
.info
{
display
:
flex
;
...
...
@@ -2173,7 +2206,7 @@ onMounted(async () => {
justify-content
:
space-between
;
h2
{
color
:
rgba
(
20
,
89
,
187
,
1
)
;
color
:
#055fc2
;
font-family
:
Microsoft
YaHei
;
font-size
:
24px
;
font-weight
:
700
;
...
...
@@ -2181,9 +2214,10 @@ onMounted(async () => {
}
.newtitle
{
color
:
rgba
(
102
,
102
,
102
,
1
);
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-size
:
16px
;
line-height
:
24px
;
margin-top
:
8px
;
}
}
...
...
@@ -2209,18 +2243,14 @@ onMounted(async () => {
}
.line
{
border-bottom
:
1px
solid
rgba
(
2
40
,
242
,
244
,
1
);
border-bottom
:
1px
solid
rgba
(
2
34
,
236
,
238
,
1
);
margin-top
:
16px
;
}
}
.timeline-wrapper
{
height
:
289px
;
width
:
688px
;
overflow-y
:
auto
;
overflow
:
auto
;
scrollbar-width
:
none
;
-ms-overflow-style
:
none
;
overflow
:
hidden
;
:deep
(
.el-timeline
)
{
margin-top
:
14px
;
...
...
@@ -2235,18 +2265,36 @@ onMounted(async () => {
left
:
4px
;
}
// 修复:首尾节点时间线穿点问题
:deep
(
.el-timeline-item
)
{
&
:first-child
{
.el-timeline-item__tail
{
top
:
10px
;
// 从圆点中心对齐
height
:
calc
(
100%
-
10px
);
}
}
&
:last-child
{
.el-timeline-item__tail
{
display
:
none
!
important
;
}
}
&
:nth-last-child
(
2
)
{
.el-timeline-item__tail
{
height
:
calc
(
100%
+
10px
);
// 衔接到最后一个圆点中心
}
}
}
:deep
(
.el-timeline-item__content
)
{
color
:
rgba
(
102
,
102
,
102
,
1
);
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
text-align
:
justify
;
}
}
.
timeline-wrapper
:
:-
webkit-scrollbar
{
display
:
none
;
}
.timeline-dot
{
display
:
flex
;
justify-content
:
space-between
;
...
...
@@ -2267,7 +2315,6 @@ onMounted(async () => {
.dot-date
{
margin-left
:
16px
;
margin-top
:
-6px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
...
...
@@ -2320,7 +2367,7 @@ onMounted(async () => {
.box1-main
{
width
:
1009px
;
height
:
35
4
px
;
height
:
35
2
px
;
margin-top
:
28px
;
margin-left
:
40px
;
}
...
...
@@ -2331,14 +2378,15 @@ onMounted(async () => {
}
.avatar
{
width
:
2
80
px
;
height
:
35
4
px
;
width
:
2
66
px
;
height
:
35
2
px
;
flex-shrink
:
0
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
cover
;
border-radius
:
4px
;
}
}
...
...
@@ -2355,7 +2403,7 @@ onMounted(async () => {
h2
{
margin
:
0
;
color
:
rgba
(
20
,
89
,
187
,
1
)
;
color
:
#055fc2
;
font-family
:
Microsoft
YaHei
;
font-size
:
24px
;
font-weight
:
700
;
...
...
@@ -2363,9 +2411,11 @@ onMounted(async () => {
.newtitle
{
margin-top
:
8px
;
color
:
rgba
(
102
,
102
,
102
,
1
);
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-size
:
16px
;
line-height
:
24px
;
font-weight
:
400
;
}
}
}
...
...
@@ -2390,15 +2440,14 @@ onMounted(async () => {
}
.line
{
border-bottom
:
1px
solid
rgba
(
2
40
,
242
,
244
,
1
);
border-bottom
:
1px
solid
rgba
(
2
34
,
236
,
238
,
1
);
margin-top
:
16px
;
}
}
.timeline-wrapper
{
height
:
289px
;
width
:
688px
;
overflow
-y
:
auto
;
overflow
:
hidden
;
:deep
(
.el-timeline
)
{
margin-top
:
14px
;
...
...
@@ -2413,11 +2462,34 @@ onMounted(async () => {
left
:
4px
;
}
// 修复:首尾节点时间线穿点问题
:deep
(
.el-timeline-item
)
{
&
:first-child
{
.el-timeline-item__tail
{
top
:
10px
;
// 从圆点中心对齐
height
:
calc
(
100%
-
10px
);
}
}
&
:last-child
{
.el-timeline-item__tail
{
display
:
none
!
important
;
}
}
&
:nth-last-child
(
2
)
{
.el-timeline-item__tail
{
height
:
calc
(
100%
+
10px
);
// 衔接到最后一个圆点中心
}
}
}
:deep
(
.el-timeline-item__content
)
{
color
:
rgba
(
102
,
102
,
102
,
1
);
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
text-align
:
justify
;
margin-top
:
4px
;
}
}
...
...
@@ -2491,7 +2563,7 @@ onMounted(async () => {
.box1-main
{
width
:
1009px
;
height
:
35
4
px
;
height
:
35
2
px
;
margin-top
:
28px
;
margin-left
:
40px
;
}
...
...
@@ -2502,14 +2574,15 @@ onMounted(async () => {
}
.avatar
{
width
:
2
80
px
;
height
:
35
4
px
;
width
:
2
66
px
;
height
:
35
2
px
;
flex-shrink
:
0
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
cover
;
border-radius
:
4px
;
}
}
...
...
@@ -2526,7 +2599,7 @@ onMounted(async () => {
h2
{
margin
:
0
;
color
:
rgba
(
20
,
89
,
187
,
1
)
;
color
:
#055fc2
;
font-family
:
Microsoft
YaHei
;
font-size
:
24px
;
font-weight
:
700
;
...
...
@@ -2534,9 +2607,10 @@ onMounted(async () => {
.newtitle
{
margin-top
:
8px
;
color
:
rgba
(
102
,
102
,
102
,
1
);
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-size
:
16px
;
line-height
:
24px
;
}
}
}
...
...
@@ -2547,15 +2621,14 @@ onMounted(async () => {
}
.line
{
border-bottom
:
1px
solid
rgba
(
2
40
,
242
,
244
,
1
);
border-bottom
:
1px
solid
rgba
(
2
34
,
236
,
238
,
1
);
margin-top
:
16px
;
}
}
.timeline-wrapper
{
height
:
289px
;
width
:
688px
;
overflow
-y
:
auto
;
overflow
:
hidden
;
:deep
(
.el-timeline
)
{
margin-top
:
14px
;
...
...
@@ -2563,18 +2636,41 @@ onMounted(async () => {
}
:deep
(
.el-timeline-item__wrapper
)
{
padding-left
:
40
px
;
padding-left
:
16
px
;
}
:deep
(
.el-timeline-item__tail
)
{
left
:
4px
;
}
// 修复:首尾节点时间线穿点问题
:deep
(
.el-timeline-item
)
{
&
:first-child
{
.el-timeline-item__tail
{
top
:
10px
;
// 从圆点中心对齐
height
:
calc
(
100%
-
10px
);
}
}
&
:last-child
{
.el-timeline-item__tail
{
display
:
none
!
important
;
}
}
&
:nth-last-child
(
2
)
{
.el-timeline-item__tail
{
height
:
calc
(
100%
+
10px
);
// 衔接到最后一个圆点中心
}
}
}
:deep
(
.el-timeline-item__content
)
{
color
:
rgba
(
102
,
102
,
102
,
1
);
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
text-align
:
justify
;
}
}
...
...
@@ -2609,4 +2705,31 @@ onMounted(async () => {
height
:
18px
;
}
}
.data-origin-box
{
display
:
flex
;
align-items
:
center
;
padding
:
8px
24px
;
box-sizing
:
border-box
;
.data-origin-icon
{
width
:
14px
;
height
:
14px
;
font-size
:
0
;
margin-right
:
6px
;
flex-shrink
:
0
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.data-origin-text
{
color
:
rgba
(
153
,
153
,
153
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
12px
;
line-height
:
16px
;
}
}
</
style
>
src/views/technologyFigures/utils/multiLineChart.js
浏览文件 @
2a5ddbf3
...
...
@@ -13,9 +13,9 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3, dataY4, dataY5, dataY6
},
grid
:
{
top
:
"50px"
,
right
:
"50
px"
,
right
:
"24
px"
,
bottom
:
"0px"
,
left
:
"40
px"
,
left
:
"24
px"
,
containLabel
:
true
},
legend
:
{
...
...
@@ -47,7 +47,13 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3, dataY4, dataY5, dataY6
boundaryGap
:
false
,
data
:
dataX
,
axisLabel
:
{
fontSize
:
14
// 设置X轴字体大小
fontSize
:
14
,
color
:
"rgba(59, 65, 75, 1)"
},
axisLine
:
{
lineStyle
:
{
color
:
"#E7F3FF"
}
}
}
],
...
...
@@ -63,8 +69,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3, dataY4, dataY5, dataY6
},
axisLabel
:
{
fontSize
:
14
// 设置X轴字体大小
},
}
}
],
series
:
[
...
...
src/views/technologyFigures/utils/useCharacterNav.js
浏览文件 @
2a5ddbf3
...
...
@@ -13,6 +13,7 @@ import { getPersonSummaryInfo } from "@/api/technologyFigures/technologyFigures
// 人物类型名称 -> type 映射
const
PERSON_TYPE_MAP
=
{
"科技企业领袖"
:
1
,
"政府官员"
:
1
,
"国会议员"
:
2
,
"智库研究人员"
:
3
,
};
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论