Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
f18fbd9e
提交
f18fbd9e
authored
4月 11, 2026
作者:
yanpeng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
style
上级
5c38f268
显示空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
1109 行增加
和
237 行删除
+1109
-237
index.js
src/api/finance/index.js
+8
-0
title.vue
src/views/exportControl/components/title.vue
+1
-1
index.vue
src/views/exportControl/index.vue
+217
-96
title.vue
src/views/finance/components/title.vue
+1
-1
back.vue
...ance/entityList/components/deepMining/components/back.vue
+442
-40
constrainedAssociation.vue
...mponents/deepMining/components/constrainedAssociation.vue
+386
-25
mock.json
...nce/entityList/components/deepMining/components/mock.json
+31
-57
index.vue
src/views/finance/index.vue
+23
-17
没有找到文件。
src/api/finance/index.js
浏览文件 @
f18fbd9e
...
...
@@ -160,3 +160,11 @@ export function getRecordRelation(sanRecordIds) {
export
function
getVertexInfo
(
sanRecordId
)
{
return
http
.
get
(
`/api/sanctionList/invFin/getVertexInfo?sanRecordId=
${
sanRecordId
}
`
);
}
/**
* 查询投融资限制关联-图谱-关系详情
* url:/sanctionList/invFin/getEdgeInfo
*/
export
function
getEdgeInfo
(
edgeId
)
{
return
http
.
get
(
`/api/sanctionList/invFin/getEdgeInfo?edgeId=
${
edgeId
}
`
);
}
src/views/exportControl/components/title.vue
浏览文件 @
f18fbd9e
...
...
@@ -22,7 +22,7 @@ defineProps({
align-items
:
center
;
width
:
100%
;
margin-bottom
:
36px
;
padding
:
0
15
px
;
padding
:
0px
;
}
.color-block
{
...
...
src/views/exportControl/index.vue
浏览文件 @
f18fbd9e
...
...
@@ -3,18 +3,31 @@
<div
class=
"home-main"
ref=
"homeMainRef"
>
<div
class=
"home-top-bg"
></div>
<div
class=
"home-main-header"
>
<SearchContainer
style=
"margin-bottom: 0; margin-top: 48px; height: fit-content"
v-if=
"homeMainRef"
placeholder=
"搜索出口管制"
:containerRef=
"homeMainRef"
areaName=
"实体清单"
/>
<SearchContainer
style=
"margin-bottom: 0; margin-top: 48px; height: fit-content"
v-if=
"homeMainRef"
placeholder=
"搜索出口管制"
:containerRef=
"homeMainRef"
areaName=
"实体清单"
/>
<div
class=
"home-main-header-footer-info"
>
<InfoCard
v-for=
"(item, index) in infoList"
:key=
"item.id"
:title=
"item.nameZh"
:subtitle=
"item.nameAbbr"
:description=
"item.description"
:quantity=
"item.postCount"
:unit=
"item.unit"
:color=
"infoListColor[index]"
@
click=
"handleToEntityListNoId(item)"
/>
<InfoCard
v-for=
"(item, index) in infoList"
:key=
"item.id"
:title=
"item.nameZh"
:subtitle=
"item.nameAbbr"
:description=
"item.description"
:quantity=
"item.postCount"
:unit=
"item.unit"
:color=
"infoListColor[index]"
@
click=
"handleToEntityListNoId(item)"
/>
</div>
</div>
<el-row
:gutter=
"1
5
"
style=
"width: 1600px; margin: 0 auto; height: 528px; margin-top: 64px"
>
<el-row
:gutter=
"1
6
"
style=
"width: 1600px; margin: 0 auto; height: 528px; margin-top: 64px"
>
<CustomTitle
id=
"position1"
title=
"最新动态"
/>
<el-col
:span=
"16"
>
<el-col
:span=
"16"
style=
"padding-left: 0px"
>
<custom-container
titleType=
"primary"
title=
"最新出口管制政策"
:titleIcon=
"houseIcon"
height=
"450px"
>
<template
#
header-right
>
<el-button
type=
"primary"
@
click=
"handleToEntityList"
link
>
...
...
@@ -34,8 +47,15 @@
<img
src=
"./assets/images/box1-right.png"
alt=
""
/>
</div>
</div>
<el-carousel
ref=
"carouselRef"
height=
"370px"
:autoplay=
"true"
:interval=
"3000"
arrow=
"never"
indicator-position=
"none"
@
change=
"handleCarouselChange"
>
<el-carousel
ref=
"carouselRef"
height=
"370px"
:autoplay=
"true"
:interval=
"3000"
arrow=
"never"
indicator-position=
"none"
@
change=
"handleCarouselChange"
>
<el-carousel-item
v-for=
"(item, index) in entitiesDataInfoList"
:key=
"item.id + index"
>
<div>
<div
class=
"box1-top"
>
...
...
@@ -60,17 +80,29 @@
>
<el-tag
:type=
"getTagType(domainItem)"
>
{{
domainItem
}}
</el-tag>
</div>
-->
<AreaTag
v-for=
"(domainItem, index) in item.domains"
:key=
"index"
:tagName=
"domainItem"
/>
<AreaTag
v-for=
"(domainItem, index) in item.domains"
:key=
"index"
:tagName=
"domainItem"
/>
</div>
</div>
</div>
<div
class=
"box1-bottom"
>
<div
class=
"box1-bottom-title"
>
· 涉及主要实体:
</div>
<div
class=
"box1-bottom-content"
>
<div
class=
"box1-bottom-content-item"
v-for=
"(ett, index) in item.sanEntities"
:key=
"index"
@
click=
"handleEntityClick(ett)"
>
<el-image
v-if=
"ett.img"
class=
"box1-bottom-content-item-img"
:src=
"ett.img"
alt=
""
></el-image>
<div
class=
"box1-bottom-content-item"
v-for=
"(ett, index) in item.sanEntities"
:key=
"index"
@
click=
"handleEntityClick(ett)"
>
<el-image
v-if=
"ett.img"
class=
"box1-bottom-content-item-img"
:src=
"ett.img"
alt=
""
></el-image>
<div
v-else
class=
"box1-bottom-content-item-imgUndefined"
>
{{
(
ett
.
orgName
||
ett
.
orgNameZh
)?.
match
(
...
...
@@ -100,7 +132,7 @@
</
template
>
</custom-container>
</el-col>
<el-col
:span=
"8"
>
<el-col
:span=
"8"
style=
"padding-right: 0px"
>
<!-- <custom-container
titleType="danger"
title="风险信号"
...
...
@@ -143,12 +175,18 @@
</div>
</template>
</custom-container> -->
<RiskSignal
:list=
"warningList"
@
item-click=
"handleToRiskSignalDetail"
@
more-click=
"handleToMoreRiskSignal"
riskLevel=
"signalLevel"
postDate=
"signalTime"
name=
"signalTitle"
/>
<RiskSignal
:list=
"warningList"
@
item-click=
"handleToRiskSignalDetail"
@
more-click=
"handleToMoreRiskSignal"
riskLevel=
"signalLevel"
postDate=
"signalTime"
name=
"signalTitle"
/>
</el-col>
</el-row>
<el-row
:gutter=
"1
5
"
style=
"width: 1600px; margin: 0 auto; height: 50px; margin-top: 64px"
>
<el-row
:gutter=
"1
6
"
style=
"width: 1600px; margin: 0 auto; height: 50px; margin-top: 64px"
>
<CustomTitle
id=
"position2"
title=
"资讯要闻"
/>
</el-row>
<!-- <el-col :span="12">
...
...
@@ -167,11 +205,19 @@
</custom-container>
</el-col> -->
<div
class=
"center-center"
>
<NewsList
:newsList=
"newsList"
@
item-click=
"handleNewsInfoClick"
@
more-click=
"handleToMoreNews"
content=
"newsContent"
/>
<NewsList
:newsList=
"newsList"
@
item-click=
"handleNewsInfoClick"
@
more-click=
"handleToMoreNews"
content=
"newsContent"
/>
<MessageBubble
:messageList=
"socialMediaList"
@
person-click=
"handlePerClick"
imageUrl=
"avatar"
@
more-click=
"handleToSocialDetail"
/>
<MessageBubble
:messageList=
"socialMediaList"
@
person-click=
"handlePerClick"
imageUrl=
"avatar"
@
more-click=
"handleToSocialDetail"
/>
<!-- <custom-container title="社交媒体" :titleIcon="dialogIcon" height="450px">
<template #default>
<div class="dialog-list">
...
...
@@ -183,28 +229,38 @@
</custom-container> -->
</div>
<el-row
:gutter=
"
20
"
style=
"width: 1600px; margin: 0 auto; height: 510px; margin-top: 64px"
>
<el-row
:gutter=
"
16
"
style=
"width: 1600px; margin: 0 auto; height: 510px; margin-top: 64px"
>
<CustomTitle
id=
"position3"
title=
"数据总览"
/>
<el-col
:span=
"24"
>
<el-col
:span=
"24"
style=
"padding: 0"
>
<custom-container
title=
"发布频次统计"
:titleIcon=
"box3Icon"
height=
"420px"
>
<
template
#
default
>
<div
class=
"box3"
>
<div
class=
"box3-content"
>
<div
class=
"box3-content-title"
>
实体清单发布频次统计
</div>
<el-table
:data=
"entityListReleaseFreq"
stripe
style=
"width: 100%"
@
row-click=
"handleEntityRowClick"
>
<el-table
:data=
"entityListReleaseFreq"
stripe
style=
"width: 100%"
@
row-click=
"handleEntityRowClick"
>
<el-table-column
prop=
"year"
label=
"年份"
width=
"200"
/>
<el-table-column
label=
"发布次数"
width=
"300"
>
<template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
</div>
</
template
>
</el-table-column>
<el-table-column
label=
"重点领域"
width=
"220"
align=
"center"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; justify-content: center; align-items: center; gap: 5px"
>
<div
style=
"display: flex; justify-content: center; align-items: center; gap: 5px"
>
<AreaTag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:tagName=
"tag"
/>
<!--
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"getTagType(tag)"
>
{{
tag
...
...
@@ -226,21 +282,30 @@
</div>
<div
class=
"box3-content"
>
<div
class=
"box3-content-title"
>
商业管制清单发布频次统计
</div>
<el-table
:data=
"commerceControlListReleaseFreq"
stripe
style=
"width: 100%"
@
row-click=
"handleCommercialRowClick"
>
<el-table
:data=
"commerceControlListReleaseFreq"
stripe
style=
"width: 100%"
@
row-click=
"handleCommercialRowClick"
>
<el-table-column
prop=
"year"
label=
"年份"
width=
"200"
/>
<el-table-column
label=
"发布次数"
width=
"300"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
</div>
</
template
>
</el-table-column>
<el-table-column
label=
"重点领域"
width=
"220"
align=
"center"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; justify-content: center; align-items: center; gap: 5px"
>
<div
style=
"display: flex; justify-content: center; align-items: center; gap: 5px"
>
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"getTagType(tag)"
>
{{
tag
}}
</el-tag>
...
...
@@ -269,8 +334,11 @@
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
</div>
</
template
>
</el-table-column>
...
...
@@ -291,15 +359,19 @@
</el-col>
</el-row>
<el-row
:gutter=
"
20
"
style=
"width: 1600px; margin: 0 auto; height: 540px; margin-top: 16px"
>
<el-col
:span=
"8"
>
<el-row
:gutter=
"
16
"
style=
"width: 1600px; margin: 0 auto; height: 540px; margin-top: 16px"
>
<el-col
:span=
"8"
style=
"padding-left: 0"
>
<custom-container
title=
"实体清单领域分布情况"
:titleIcon=
"radarIcon"
height=
"540px"
>
<
template
#
header-right
>
<el-checkbox
v-model=
"domainChecked"
label=
"50%规则"
size=
"large"
/>
</
template
>
<
template
#
default
>
<EChart
:option=
"radarOption"
autoresize
:style=
"
{ height: '420px' }"
@chart-click="handleRadarChartClick" />
<EChart
:option=
"radarOption"
autoresize
:style=
"
{ height: '420px' }"
@chart-click="handleRadarChartClick"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
...
...
@@ -313,7 +385,7 @@
</
template
>
</custom-container>
</el-col>
<el-col
:span=
"16"
>
<el-col
:span=
"16"
style=
"padding-right: 0"
>
<custom-container
title=
"制裁清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"540px"
>
<
template
#
header-right
>
<div
style=
"display: flex; align-items: center; gap: 16px"
>
...
...
@@ -324,8 +396,12 @@
</div>
</
template
>
<
template
#
default
>
<EChart
:option=
"trendOption"
autoresize
:style=
"
{ height: '420px' }"
@chart-click="handleMultiBarChartClick" />
<EChart
:option=
"trendOption"
autoresize
:style=
"
{ height: '420px' }"
@chart-click="handleMultiBarChartClick"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
...
...
@@ -341,17 +417,21 @@
</el-col>
</el-row>
<el-row
:gutter=
"
20
"
style=
"width: 1600px; margin: 0 auto; margin-top: 39px; padding-bottom: 60px"
>
<el-row
:gutter=
"
16
"
style=
"width: 1600px; margin: 0 auto; margin-top: 39px; padding-bottom: 60px"
>
<CustomTitle
id=
"position4"
title=
"资源库"
style=
"margin-top: 0px"
/>
<div
class=
"resource-tabs"
>
<div
v-for=
"tab in resourceTabs"
:key=
"tab.value"
class=
"resource-tab-item"
<div
v-for=
"tab in resourceTabs"
:key=
"tab.value"
class=
"resource-tab-item"
:class=
"{ active: activeResourceTab == tab.value, disabled: tab.disabled }"
@
click=
"handleResourceTabClick(tab)"
>
@
click=
"handleResourceTabClick(tab)"
>
{{ tab.label }}
</div>
</div>
<
template
v-if=
"activeResourceTab === 'entity'"
>
<el-col
:span=
"8"
>
<el-col
:span=
"8"
style=
"padding-left: 0"
>
<custom-container
title=
"历次制裁过程"
:titleIcon=
"listIcon"
height=
"845px"
>
<template
#
default
>
<div
class=
"box4"
>
...
...
@@ -359,15 +439,25 @@
<div
class=
"box4-item"
v-for=
"(item, idx) in sanctionProcessList"
:key=
"item.title"
>
<div
class=
"box4-item-left"
>
<el-image
:src=
"dotIcon"
alt=
"图片"
class=
"box4-item-left-icon"
/>
<div
class=
"box4-item-left-line"
v-if=
"idx + 1 != sanctionProcessList.length"
></div>
<div
class=
"box4-item-left-line"
v-if=
"idx + 1 != sanctionProcessList.length"
></div>
</div>
<div
class=
"box4-item-right"
>
<div
class=
"box4-item-right-header"
@
click=
"handleSanc(item)"
>
<span
class=
"box4-item-right-header-title"
>
{{
item
.
postDate
}}
—
{{
item
.
title
}}
</span>
<span
class=
"box4-item-right-header-title"
>
{{
item
.
postDate
}}
—
{{
item
.
title
}}
</span
>
<span
class=
"box4-item-right-header-desc"
>
{{
item
.
desc
}}
</span>
</div>
<el-tooltip
effect=
"dark"
:content=
"item.content"
popper-class=
"common-prompt-popper"
placement=
"top"
:show-after=
"500"
>
<el-tooltip
effect=
"dark"
:content=
"item.content"
popper-class=
"common-prompt-popper"
placement=
"top"
:show-after=
"500"
>
<div
class=
"box4-item-right-content"
>
{{
item
.
content
}}
</div>
...
...
@@ -375,8 +465,12 @@
</div>
</div>
</div>
<div
class=
"box4-footer"
:style=
"
{ marginTop: sanctionProcessList.length > 0 ? '0px' : 'auto' }">
<el-button
type=
"primary"
link
@
click=
"handleGetMore"
>
查看更多
<div
class=
"box4-footer"
:style=
"
{ marginTop: sanctionProcessList.length > 0 ? '0px' : 'auto' }"
>
<el-button
type=
"primary"
link
@
click=
"handleGetMore"
>
查看更多
<el-icon>
<DArrowRight
/>
</el-icon>
...
...
@@ -386,20 +480,31 @@
</
template
>
</custom-container>
</el-col>
<el-col
:span=
"16"
>
<el-col
:span=
"16"
style=
"padding-right: 0"
>
<custom-container
title=
"制裁实体清单"
:titleIcon=
"entityIcon"
height=
"845px"
>
<
template
#
header-right
>
<div
class=
"box5-header-right"
>
共
{{
total
}}
家实体
</div>
</
template
>
<
template
#
default
>
<div
class=
"box5"
>
<el-table
:data=
"entitiesList"
class=
"sanction-table"
stripe
empty-text=
"暂无数据"
height=
"700px"
header-row-class-name=
"table-header"
row-class-name=
"table-row"
>
<el-table
:data=
"entitiesList"
class=
"sanction-table"
stripe
empty-text=
"暂无数据"
height=
"700px"
header-row-class-name=
"table-header"
row-class-name=
"table-row"
>
<el-table-column
prop=
"name"
label=
"实体名称"
min-width=
"200"
>
<template
#
default=
"scope"
>
<div
class=
"tableName"
@
click=
"handleCompClick(scope.row)"
>
<el-image
v-if=
"scope.row.img"
class=
"box1-bottom-content-item-img"
:src=
"scope.row.img"
alt=
""
></el-image>
<el-image
v-if=
"scope.row.img"
class=
"box1-bottom-content-item-img"
:src=
"scope.row.img"
alt=
""
></el-image>
<div
v-else
class=
"box1-bottom-content-item-imgUndefined"
>
{{
(
scope
.
row
.
name
||
scope
.
row
.
enName
)?.
match
(
...
...
@@ -453,13 +558,19 @@
<el-table-column
prop=
"revenue"
label=
"50%规则子企业"
width=
"280"
align=
"right"
>
<
template
#
default=
"scope"
>
<div
class=
"num-item"
v-if=
"scope.row.ruleOrgCount > 0"
>
<div
class=
"name-item"
:class=
"[
<div
class=
"name-item"
:class=
"[
'revenue-cell',
scope.row.revenue === '无营收数据' ? 'no-revenue' : ''
]"
>
]"
>
{{
scope
.
row
.
ruleOrgList
[
0
].
orgName
}}
...等
</div>
<div
style=
"width: 50px; color: #409eff; cursor: pointer"
@
click=
"handleOrgClick(scope.row)"
>
<div
style=
"width: 50px; color: #409eff; cursor: pointer"
@
click=
"handleOrgClick(scope.row)"
>
{{
scope
.
row
.
ruleOrgCount
}}
家>
</div>
</div>
...
...
@@ -471,8 +582,15 @@
<!-- <div class="pagination-info">
第{{ currentPage }}页,共{{ totalPages }}页
</div> -->
<el-pagination
v-model:current-page=
"currentPage"
:page-size=
"pageSize"
:total=
"total"
:pager-count=
"5"
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChange"
/>
<el-pagination
v-model:current-page=
"currentPage"
:page-size=
"pageSize"
:total=
"total"
:pager-count=
"5"
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChange"
/>
</div>
</div>
</template>
...
...
@@ -480,7 +598,7 @@
</el-col>
</template>
<
template
v-if=
"activeResourceTab === 'all'"
>
<el-col
:span=
"24"
>
<el-col
:span=
"24"
style=
"padding: 0"
>
<!--
<div
style=
"min-height: 500px; display: flex; justify-content: center; align-items: center; background: #fff; border-radius: 4px;"
>
暂无内容
</div>
-->
...
...
@@ -538,8 +656,14 @@
</div>
<div
class=
"right-footer"
>
<div
class=
"total-count"
>
共
{{
totalAll
}}
项
</div>
<el-pagination
v-model:current-page=
"currentPageAll"
:page-size=
"pageSizeAll"
:total=
"totalAll"
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChangeAll"
/>
<el-pagination
v-model:current-page=
"currentPageAll"
:page-size=
"pageSizeAll"
:total=
"totalAll"
layout=
"prev, pager, next"
background
@
current-change=
"handlePageChangeAll"
/>
</div>
</div>
</div>
...
...
@@ -1026,7 +1150,7 @@ const handleToEntityList = item => {
"curTabName"
,
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
].
postDate
+
" 《实体清单新增条目》"
);
let
date
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
].
postDate
let
date
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
].
postDate
;
const
routeData
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
query
:
{
...
...
@@ -1082,10 +1206,10 @@ const radarOption = ref({
tooltip
:
{
// trigger: "item",
confine
:
true
,
trigger
:
'axis'
,
trigger
:
"axis"
,
formatter
:
function
(
params
)
{
// params 包含所有系列的数据
if
(
!
params
||
params
.
length
===
0
)
return
''
;
if
(
!
params
||
params
.
length
===
0
)
return
""
;
const
radarData
=
params
[
0
];
const
indicator
=
radarData
.
axisValue
;
// 当前角度对应的指标名
...
...
@@ -1310,7 +1434,7 @@ const fetchSanctionList = async () => {
});
totalAll
.
value
=
res
.
totalElements
;
}
}
catch
(
error
)
{
}
}
catch
(
error
)
{}
};
const
handlePageChangeAll
=
val
=>
{
...
...
@@ -1604,7 +1728,7 @@ const handleGetHylyList = async () => {
hylymc
:
"全部分类"
};
categoryList
.
value
=
[
obj
,
...
categoryList
.
value
];
}
catch
(
error
)
{
}
}
catch
(
error
)
{}
};
const
chart1Data
=
ref
({
...
...
@@ -1696,62 +1820,60 @@ const handleSearch = () => {
};
// 点击实体清单发布频次统计
const
handleEntityRowClick
=
(
row
)
=>
{
console
.
log
(
'row'
,
row
);
const
handleEntityRowClick
=
row
=>
{
console
.
log
(
"row"
,
row
);
const
params
=
{
domains
:
row
.
tags
[
0
],
selectedDate
:
JSON
.
stringify
([
row
.
year
+
'-01-01'
,
row
.
year
+
'-12-31'
])
}
selectedDate
:
JSON
.
stringify
([
row
.
year
+
"-01-01"
,
row
.
year
+
"-12-31"
])
};
const
route
=
router
.
resolve
({
path
:
'/dataLibrary/dataEntityListEvent'
,
path
:
"/dataLibrary/dataEntityListEvent"
,
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
}
}
;
// 点击商业管制清单发布频次统计
const
handleCommercialRowClick
=
(
row
)
=>
{
console
.
log
(
'row'
,
row
);
const
handleCommercialRowClick
=
row
=>
{
console
.
log
(
"row"
,
row
);
const
params
=
{
domains
:
row
.
tags
[
0
],
selectedDate
:
JSON
.
stringify
([
row
.
year
+
'-01-01'
,
row
.
year
+
'-12-31'
])
}
selectedDate
:
JSON
.
stringify
([
row
.
year
+
"-01-01"
,
row
.
year
+
"-12-31"
])
}
;
const
route
=
router
.
resolve
({
path
:
'/dataLibrary/dataCommerceControlListEvent'
,
path
:
"/dataLibrary/dataCommerceControlListEvent"
,
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
}
}
;
// 点击实体清单领域分布情况
const
handleRadarChartClick
=
(
value
)
=>
{
const
handleRadarChartClick
=
value
=>
{
// console.log('value', value);
// alert(domainChecked.value)
const
params
=
{
isHalfRule
:
domainChecked
.
value
}
}
;
const
route
=
router
.
resolve
({
path
:
'/dataLibrary/dataEntityList'
,
path
:
"/dataLibrary/dataEntityList"
,
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
}
}
;
// 点击制裁清单数量增长趋势
const
handleMultiBarChartClick
=
(
val
)
=>
{
const
handleMultiBarChartClick
=
val
=>
{
// console.log('value', val);
const
params
=
{
domains
:
val
.
seriesName
,
selectedDate
:
JSON
.
stringify
([
val
.
name
+
'-01-01'
,
val
.
name
+
'-12-31'
])
}
selectedDate
:
JSON
.
stringify
([
val
.
name
+
"-01-01"
,
val
.
name
+
"-12-31"
])
};
const
route
=
router
.
resolve
({
path
:
'/dataLibrary/dataEntityListEvent'
,
path
:
"/dataLibrary/dataEntityListEvent"
,
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
}
}
;
onMounted
(
async
()
=>
{
handleGetHylyList
();
...
...
@@ -2162,7 +2284,6 @@ const handleMediaClick = item => {
}
.box3-content
{
// flex: 1;
.el-progress--line
{
width
:
82px
;
...
...
@@ -3169,7 +3290,7 @@ const handleMediaClick = item => {
align-items
:
center
;
margin-top
:
6px
;
margin-bottom
:
36px
;
padding-left
:
10px
;
//
padding-left: 10px;
.resource-tab-item
{
margin-right
:
12px
;
...
...
@@ -3556,7 +3677,7 @@ const handleMediaClick = item => {
margin-top
:
21px
;
height
:
450px
;
display
:
flex
;
gap
:
20
px
;
gap
:
16
px
;
.center-center-news
{
flex-shrink
:
0
;
...
...
src/views/finance/components/title.vue
浏览文件 @
f18fbd9e
...
...
@@ -22,7 +22,7 @@ defineProps({
align-items
:
center
;
width
:
100%
;
margin-bottom
:
36px
;
padding
:
0
15px
;
padding
:
0
;
}
.color-block
{
...
...
src/views/finance/entityList/components/deepMining/components/back.vue
浏览文件 @
f18fbd9e
...
...
@@ -27,7 +27,9 @@
<div
class=
"list-item"
v-for=
"item in sanctionList"
:key=
"item.id"
@
click=
"handleSanctionSelect(item.id)"
>
<el-checkbox
v-model=
"item.checked"
@
change=
"val => handleCheckOneChange(val, item)"
@
click
.
stop
>
<div
class=
"item-label"
>
<div
class=
"item-left"
>
{{
item
.
date
}}
-
{{
"SDN清单更新"
}}
</div>
<div
class=
"item-left"
>
{{
dayjs
(
item
.
date
).
format
(
"YYYY年MM月DD日"
)
}}
-
{{
"SDN清单更新"
}}
</div>
<div
class=
"item-right"
>
{{
item
.
count
}}{{
item
.
unit
}}
</div>
</div>
</el-checkbox>
...
...
@@ -51,50 +53,170 @@
</el-empty>
</div>
<div
class=
"relation-content"
v-else
>
<!--
修改点:
绑定转换后的 graphNodes 和 graphLinks -->
<GraphChart
:nodes=
"graphNodes"
:links=
"graphLinks"
/>
<!-- 绑定转换后的 graphNodes 和 graphLinks -->
<GraphChart
:nodes=
"graphNodes"
:links=
"graphLinks"
@
handleClickNode=
"handleClickNode"
/>
</div>
</div>
</AnalysisBox>
</div>
<el-dialog
v-model=
"nodeVisible"
:title=
"curNode?.data?.name || '制裁历程'"
width=
"960"
>
<div
class=
"dialog-content"
>
<div
class=
"info-btn"
>
<el-button
type=
"primary"
:style=
"{ borderRadius: '8px', paddingTop: '10px' }"
@
click=
"handleInfoClick"
>
查看详情 >
</el-button>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
制裁标题:
</div>
<div
class=
"item-desc item-label"
>
{{ vertexInfo.name }}
</div>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
制裁领域:
</div>
<div
class=
"item-desc"
>
<AreaTag
v-for=
"item in vertexInfo.domainList"
:key=
"item"
:tagName=
"item"
/>
</div>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
依托文件:
</div>
<div
class=
"item-desc"
>
<div
class=
"item-file"
v-for=
"item in vertexInfo.relyFileList"
:key=
"item.id"
>
<div
class=
"item-file-name"
>
{{ item.name }}
</div>
<img
:src=
"openIcon"
alt=
"文件"
class=
"item-file-icon"
/>
</div>
</div>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
依托制裁:
</div>
<div
class=
"item-desc"
>
<div
class=
"item-file"
v-for=
"item in vertexInfo.relySanList"
:key=
"item.id"
>
<div
class=
"item-file-name"
>
{{ item.title }}
</div>
<img
:src=
"openIcon"
alt=
"文件"
class=
"item-file-icon"
/>
</div>
</div>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
制裁原因:
</div>
<div
class=
"item-desc-table"
>
<div
class=
"item-file"
v-for=
"item in vertexInfo.sanReasonList"
:key=
"item"
>
<div
class=
"dot"
></div>
<div
class=
"item-file-name"
>
{{ item }}
</div>
</div>
</div>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
制裁对象:
</div>
<div
class=
"item-desc item-desc-table"
>
<span
class=
"item-table-desc"
v-if=
"vertexInfo.addObjectList?.length || vertexInfo.delObjectList?.length"
>
{{ formatChangeSummary(vertexInfo.addObjectList, vertexInfo.delObjectList) }}
</span>
<el-table
:data=
"vertexInfo.sanList"
stripe
>
<el-table-column
property=
"entityNameZh"
label=
"制裁对象"
width=
"350"
/>
<el-table-column
property=
"domainNames"
label=
"所属领域"
width=
"400"
>
<
template
#
default=
"scope"
>
<AreaTag
v-for=
"item in scope.row.domainNames"
:key=
"item"
:tagName=
"item"
/>
</
template
>
</el-table-column>
</el-table>
</div>
</div>
</div>
</el-dialog>
<el-dialog
:title=
"curLink.data?.relationType + '关系' || '关联关系'"
v-model=
"relationVisible"
width=
"960"
>
<div
class=
"dialog-content"
>
<div
class=
"hintWrap"
>
<div
class=
"icon1"
></div>
<div
class=
"title"
>
{{ tipsInfo }}
</div>
<div
class=
"icon2Wrap"
>
<div
class=
"icon2"
></div>
</div>
</div>
<RelationChart
:is-vertical-chart=
"true"
:graph-data=
"graphData"
/>
</div>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
ref
,
onMounted
,
nextTick
,
onUnmounted
,
computed
}
from
"vue"
;
import
defaultTitle
from
"../../../assets/default-icon2.png"
;
import
{
ref
,
onMounted
,
computed
}
from
"vue"
;
import
GraphChart
from
"@/components/base/GraphChart/index.vue"
;
import
RelationChart
from
"@/components/base/RelationChart/index.vue"
;
import
emptyImg
from
"../assets/empty.png"
;
import
markIcon
from
"../assets/icon-mark.png"
;
import
{
getSanRecord
,
getRecordRelation
}
from
"@/api/finance"
;
import
{
useRoute
}
from
"vue-router"
;
import
markIcon
from
"../assets/icon-mark.png"
;
// 引入图标
import
openIcon
from
"../../../../assets/icons/icon-open.png"
;
import
{
getSanRecord
,
getRecordRelation
,
getVertexInfo
,
getEdgeInfo
}
from
"@/api/finance"
;
import
{
useRoute
,
useRouter
}
from
"vue-router"
;
import
dayjs
from
"dayjs"
;
const
route
=
useRoute
();
const
router
=
useRouter
();
// 定义颜色映射
const
colors
=
{
// 相似
similarity
:
{
fontColor
:
"rgba(5, 95, 194)"
,
color
:
"rgb(231, 243, 255)"
color
:
"rgb(231, 243, 255)"
,
// 连线颜色 & 标签背景
lineColor
:
"rgba(5, 95, 194)"
// 专门用于连线的颜色,如果需要和背景色区分
},
// 继承
inheritance
:
{
fontColor
:
"rgba(19, 168, 168)"
,
color
:
"rgba(230, 255, 251, 1)"
color
:
"rgba(230, 255, 251, 1)"
,
lineColor
:
"rgba(19, 168, 168)"
},
// 冲突
conflict
:
{
fontColor
:
"rgb(206, 79, 81)"
,
color
:
"rgba(5, 95, 194)"
color
:
"rgba(255, 241, 240, 1)"
,
// 修正:冲突背景通常偏红/浅红,这里沿用你提供的蓝色背景可能不太符合直觉,但我保留你的配置或微调
lineColor
:
"rgb(206, 79, 81)"
}
};
const
handleInfoClick
=
()
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
`
${
curNode
.
value
.
data
.
originDate
}
-《
${
curNode
.
value
.
data
.
originName
}
》`
);
const
routeData
=
router
.
resolve
({
path
:
"/finance/singleSanction"
,
query
:
{
id
:
curNode
.
value
.
data
.
id
,
sanTypeId
:
sanTypeId
.
value
}
});
// 打开新页面
window
.
open
(
routeData
.
href
,
"_blank"
);
};
// 辅助函数:获取关系类型对应的颜色配置
const
getRelationStyle
=
relationType
=>
{
switch
(
relationType
)
{
case
"相似"
:
return
colors
.
similarity
;
case
"继承"
:
return
colors
.
inheritance
;
case
"冲突"
:
return
colors
.
conflict
;
default
:
return
{
fontColor
:
"#666"
,
color
:
"#f0f2f5"
,
lineColor
:
"#AED6FF"
};
}
};
// ... 其他原有变量保持不变 ...
const
selectedSanctionIds
=
ref
([]);
const
isAllSelected
=
computed
({
get
()
{
return
sanctionList
.
value
.
length
>
0
&&
sanctionList
.
value
.
every
(
item
=>
item
.
checked
);
},
set
(
val
)
{}
}
});
const
handleCheckAllChange
=
val
=>
{
...
...
@@ -123,27 +245,46 @@ const indeterminate = computed(() => {
const
recordRelation
=
ref
({
noRelationVertices
:
[],
relationVoList
:
[]
});
// 【
新增】计算属性:处理图表
数据
// 【
修改】处理图表节点
数据
const
graphNodes
=
computed
(()
=>
{
const
nodesMap
=
new
Map
();
// 1. 处理无关联节点 (noRelationVertices)
// 定义统一的标签样式
const
labelStyle
=
{
show
:
true
,
position
:
"bottom"
,
// 标签位置,可根据需要调整为 'top', 'left', 'right', 'inside' 等
fontSize
:
14
,
fontWeight
:
400
,
fontFamily
:
"Source Han Sans CN"
,
lineHeight
:
22
,
color
:
"#333"
// 默认字体颜色,可根据需要调整
// 如果标签背景需要透明或特定颜色,可以添加 backgroundColor
// backgroundColor: 'rgba(255, 255, 255, 0.8)',
// padding: [2, 4]
};
// 1. 处理无关联节点
if
(
recordRelation
.
value
.
noRelationVertices
)
{
recordRelation
.
value
.
noRelationVertices
.
forEach
(
node
=>
{
if
(
!
nodesMap
.
has
(
node
.
id
))
{
nodesMap
.
set
(
node
.
id
,
{
id
:
node
.
id
,
name
:
node
.
name
,
// 可以根据需要添加 category 或其他样式属性
// name: node.name,
originDate
:
node
.
date
,
originName
:
node
.
name
,
name
:
dayjs
(
node
.
date
).
format
(
"YYYY年MM月DD日"
)
+
" "
+
"SDN清单更新"
,
symbol
:
`image://
${
markIcon
}
`
,
// 设置自定义图标
symbolSize
:
[
50
,
50
],
// 根据图标实际大小调整
itemStyle
:
{
color
:
"#91cc75"
// 例如:无关联节点用绿色区分
}
color
:
"#91cc75"
},
label
:
{
...
labelStyle
}
// 应用标签样式
});
}
});
}
// 2. 处理关联节点
(relationVoList 中的 fromVertex 和 toVertex)
// 2. 处理关联节点
if
(
recordRelation
.
value
.
relationVoList
)
{
recordRelation
.
value
.
relationVoList
.
forEach
(
rel
=>
{
const
from
=
rel
.
fromVertex
;
...
...
@@ -152,20 +293,30 @@ const graphNodes = computed(() => {
if
(
from
&&
!
nodesMap
.
has
(
from
.
id
))
{
nodesMap
.
set
(
from
.
id
,
{
id
:
from
.
id
,
name
:
from
.
name
,
// name: from.name,
originDate
:
from
.
date
,
originName
:
from
.
name
,
name
:
dayjs
(
from
.
date
).
format
(
"YYYY年MM月DD日"
)
+
" "
+
"SDN清单更新"
,
symbol
:
`image://
${
markIcon
}
`
,
// 设置自定义图标
symbolSize
:
[
50
,
50
],
itemStyle
:
{
color
:
"#5470c6"
// 例如:有关联节点用蓝色
}
color
:
"#5470c6"
},
label
:
{
...
labelStyle
}
// 应用标签样式
});
}
if
(
to
&&
!
nodesMap
.
has
(
to
.
id
))
{
nodesMap
.
set
(
to
.
id
,
{
id
:
to
.
id
,
name
:
to
.
name
,
// name: to.name,
name
:
dayjs
(
to
.
date
).
format
(
"YYYY年MM月DD日"
)
+
" "
+
"SDN清单更新"
,
symbol
:
`image://
${
markIcon
}
`
,
// 设置自定义图标
symbolSize
:
[
50
,
50
],
itemStyle
:
{
color
:
"#5470c6"
}
},
label
:
{
...
labelStyle
}
// 应用标签样式
});
}
});
...
...
@@ -174,17 +325,38 @@ const graphNodes = computed(() => {
return
Array
.
from
(
nodesMap
.
values
());
});
// 【修改】处理图表连线数据
const
graphLinks
=
computed
(()
=>
{
if
(
!
recordRelation
.
value
.
relationVoList
)
return
[];
return
recordRelation
.
value
.
relationVoList
.
map
(
rel
=>
{
const
relationType
=
rel
.
edgeInfo
?
rel
.
edgeInfo
.
value
:
""
;
const
style
=
getRelationStyle
(
relationType
);
return
{
source
:
rel
.
fromVertex
.
id
,
target
:
rel
.
toVertex
.
id
,
// 将
edgeInfo 挂载到 data 上,以便在 formatter 中访问
// 将
样式信息挂载到 label 或 data 上,供 formatter 和 lineStyle 使用
label
:
{
formatter
:
rel
.
edgeInfo
?
rel
.
edgeInfo
.
value
:
""
}
formatter
:
relationType
,
show
:
true
,
color
:
style
.
fontColor
,
// 字体颜色
backgroundColor
:
style
.
color
,
// 标签背景色
borderColor
:
style
.
color
,
// 标签边框色
padding
:
[
4
,
8
],
borderRadius
:
4
,
fontSize
:
12
},
lineStyle
:
{
color
:
style
.
lineColor
,
// 连线颜色
width
:
1
,
type
:
"solid"
// curveness: 0.1 // 稍微有点弧度可能更好看
},
// 额外存储原始数据,以备后用
relationType
:
relationType
,
edgeInfo
:
rel
.
edgeInfo
,
originInfo
:
rel
};
});
});
...
...
@@ -211,9 +383,119 @@ const fetchRecordRelation = async () => {
recordRelation
.
value
=
{
noRelationVertices
:
[],
relationVoList
:
[]
};
}
};
const
vertexInfo
=
ref
({});
const
curNode
=
ref
({});
const
curLink
=
ref
({});
const
nodeVisible
=
ref
(
false
);
const
relationVisible
=
ref
(
false
);
const
tipsInfo
=
ref
(
""
);
const
graphData
=
ref
({});
const
getTipsInfo
=
(
relationType
,
reason
)
=>
{
switch
(
relationType
)
{
case
"继承"
:
return
`
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
fromVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新依托于
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
toVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新,两次制裁存在继承关系。`
;
case
"冲突"
:
return
`
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
toVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新中制裁的实体在
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
fromVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新中被移除,存在冲突关系。`
;
default
:
return
`
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
fromVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新与
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
toVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新存在相同
${
reason
}
,属于相似关系。`
;
}
};
const
handleClickNode
=
node
=>
{
console
.
log
(
"节点点击"
,
node
);
if
(
node
.
dataType
==
"node"
)
{
nodeVisible
.
value
=
true
;
curNode
.
value
=
node
;
getVertexInfo
(
node
.
data
.
id
).
then
(
res
=>
{
console
.
log
(
"getVertexInfo"
,
res
);
if
(
!!
res
)
{
vertexInfo
.
value
=
res
;
nodeVisible
.
value
=
true
;
}
else
{
vertexInfo
.
value
=
{};
}
});
}
else
{
relationVisible
.
value
=
true
;
curLink
.
value
=
node
;
const
relationType
=
node
.
data
.
relationType
;
// 继承 - 2025年10月1日-SDN清单更新依托于2024年2月08日-SDN清单更新,两次制裁存在继承关系。
// 冲突 - 2025年2月19日-SDN清单更新中制裁的实体在2024年2月08日-SDN清单更新中被移除,属于冲突关系。
// 相似 - 2025年2月19日-SDN清单更新与2024年2月08日-SDN清单更新存在相同制裁原因,属于相似关系。
// 相似 - 2025年2月19日-SDN清单更新与2024年2月08日-SDN清单更新存在同领域制裁实体,属于相似关系。
// 相似 - 2025年2月19日-SDN清单更新与2024年2月08日-SDN清单更新存在相同依托文件,属于相似关系。
getEdgeInfo
(
node
.
data
.
edgeInfo
.
key
).
then
(
res
=>
{
if
(
!!
res
)
{
// recordRelation.value = res;
console
.
log
(
"制裁之间的关系 =>"
,
res
);
let
reason
=
""
;
if
(
relationType
==
"相似"
)
{
reason
=
res
[
0
].
edgeReasonList
[
0
].
reason
;
}
tipsInfo
.
value
=
getTipsInfo
(
relationType
,
reason
);
}
else
{
// recordRelation.value = { noRelationVertices: [], relationVoList: [] };
}
});
}
};
// 【新增/修改】格式化变动 summary 的函数
const
formatChangeSummary
=
(
addList
,
delList
)
=>
{
const
parts
=
[];
// 处理新增列表
if
(
addList
&&
addList
.
length
>
0
)
{
// 将每个对象转换为 "value个实体" 或 "value名个人" 的形式
const
addItems
=
addList
.
map
(
item
=>
{
let
unit
=
"个"
;
let
noun
=
"实体"
;
if
(
item
.
key
===
"人物"
)
{
unit
=
"名"
;
noun
=
"个人"
;
}
else
if
(
item
.
key
===
"机构"
)
{
// 默认机构对应实体,也可以根据需求调整
unit
=
"个"
;
noun
=
"实体"
;
}
return
`
${
item
.
value
}${
unit
}${
noun
}
`
;
});
// 拼接:新增 + item1 + , + item2 ...
parts
.
push
(
`新增
${
addItems
.
join
(
","
)}
`
);
}
// 处理移除列表
if
(
delList
&&
delList
.
length
>
0
)
{
// 将每个对象转换为 "value个实体" 或 "value名个人" 的形式
const
delItems
=
delList
.
map
(
item
=>
{
let
unit
=
"个"
;
let
noun
=
"实体"
;
if
(
item
.
key
===
"人物"
)
{
unit
=
"名"
;
noun
=
"个人"
;
}
else
if
(
item
.
key
===
"机构"
)
{
unit
=
"个"
;
noun
=
"实体"
;
}
return
`
${
item
.
value
}${
unit
}${
noun
}
`
;
});
// 拼接:移除 + item1 + , + item2 ...
// 注意:题目要求“删除”,但之前代码用的是“移除”,这里统一使用“移除”或“删除”。
// 根据题目描述“展示样本为:新增12个实体,3名个人,移除1个实体”,这里使用“移除”更贴切上下文,
// 如果必须用“删除”,请将下面的 '移除' 改为 '删除'。
parts
.
push
(
`移除
${
delItems
.
join
(
","
)}
`
);
}
return
parts
.
length
>
0
?
parts
.
join
(
","
)
:
"无变动"
;
};
const
loading
=
ref
(
false
);
const
currentPage
=
ref
(
1
);
const
sanctionList
=
ref
([]);
const
currentSanctionId
=
ref
(
5
);
const
dateRange
=
ref
([
"2025-01-01"
,
"2025-12-31"
]);
const
sanTypeId
=
ref
(
""
);
const
fetchSanRecord
=
async
()
=>
{
loading
.
value
=
true
;
...
...
@@ -225,15 +507,13 @@ const fetchSanRecord = async () => {
try
{
const
res
=
await
getSanRecord
(
params
);
if
(
res
&&
res
.
length
>
0
)
{
sanctionList
.
value
=
res
.
map
(
item
=>
({
sanctionList
.
value
=
res
.
map
(
item
=>
({
id
:
item
.
sanRecordId
,
date
:
item
.
sanRecordDate
,
title
:
item
.
sanRecordName
,
count
:
item
.
cnEntitiesNum
,
unit
:
"家中国实体"
}))
.
reverse
();
}));
if
(
sanctionList
.
value
.
length
>
0
)
{
currentSanctionId
.
value
=
sanctionList
.
value
[
0
].
id
;
...
...
@@ -257,11 +537,6 @@ const handleSanctionSelect = id => {
currentSanctionId
.
value
=
id
;
};
const
dateRange
=
ref
([
"2025-01-01"
,
"2025-12-31"
]);
const
sanctionList
=
ref
([]);
const
currentSanctionId
=
ref
(
5
);
const
sanTypeId
=
ref
(
""
);
onMounted
(()
=>
{
sanTypeId
.
value
=
route
.
query
.
sanTypeId
||
""
;
fetchSanRecord
();
...
...
@@ -338,7 +613,6 @@ onMounted(() => {
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
width
:
100%
;
}
.item-left
{
...
...
@@ -423,7 +697,135 @@ onMounted(() => {
}
}
.main-association
{
padding-top
:
12px
!
important
;
justify-content
:
flex-start
!
important
;
gap
:
16px
;
}
.dialog-content
{
position
:
relative
;
padding
:
20px
;
display
:
flex
;
flex-direction
:
column
;
gap
:
16px
;
border-top
:
1px
solid
rgb
(
238
,
238
,
238
);
.hintWrap
{
display
:
flex
;
align-items
:
center
;
padding
:
7px
12px
;
border
:
1px
solid
rgba
(
231
,
243
,
255
,
1
);
border-radius
:
4px
;
background
:
rgba
(
246
,
250
,
255
,
1
);
margin-bottom
:
9px
;
.icon1
{
width
:
19px
;
height
:
20px
;
background-image
:
url("../assets/ai.png")
;
background-size
:
100%
100%
;
flex-shrink
:
0
;
}
.title
{
color
:
rgb
(
5
,
95
,
194
);
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
margin-left
:
13px
;
flex
:
1
;
}
.icon2Wrap
{
width
:
24px
;
height
:
24px
;
background-color
:
rgba
(
231
,
243
,
255
,
1
);
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
border-radius
:
12px
;
margin-left
:
20px
;
flex-shrink
:
0
;
.icon2
{
width
:
24px
;
height
:
24px
;
background-image
:
url("../assets/right.png")
;
background-size
:
100%
100%
;
}
}
}
.info-btn
{
position
:
absolute
;
top
:
20px
;
right
:
20px
;
}
.content-item
{
display
:
flex
;
justify-content
:
flex-start
;
align-items
:
flex-start
;
gap
:
8px
;
.item-label
{
min-width
:
75px
;
font-size
:
14px
;
font-weight
:
700
;
font-family
:
Source
Han
Sans
CN
;
color
:
rgba
(
59
,
65
,
75
,
1
);
line-height
:
24px
;
}
.item-desc-table
{
display
:
flex
;
flex-direction
:
column
;
padding-top
:
3px
;
.dot
{
width
:
4px
;
height
:
4px
;
border-radius
:
50%
;
background-color
:
rgb
(
59
,
65
,
75
);
}
.item-file
{
display
:
flex
;
justify-content
:
flex-start
;
align-items
:
center
;
gap
:
8px
;
// background: rgb(231, 243, 255);
// border-radius: 20px;
// border: 1px solid rgb(231, 243, 255);
padding
:
4px
0px
;
font-family
:
Source
Han
Sans
CN
;
font-size
:
16px
;
font-weight
:
400
;
}
}
.item-desc
{
font-size
:
14px
;
font-family
:
Source
Han
Sans
CN
;
margin-top
:
1px
;
display
:
flex
;
gap
:
15px
;
.item-file
{
display
:
flex
;
justify-content
:
flex-start
;
align-items
:
center
;
gap
:
8px
;
background
:
rgb
(
231
,
243
,
255
);
border-radius
:
20px
;
border
:
1px
solid
rgb
(
231
,
243
,
255
);
padding
:
5px
15px
;
cursor
:
pointer
;
.item-file-name
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
Source
Han
Sans
CN
;
color
:
rgb
(
5
,
95
,
194
);
line-height
:
24px
;
}
.item-file-icon
{
width
:
16px
;
height
:
16px
;
margin-top
:
1px
;
}
}
}
}
}
</
style
>
src/views/finance/entityList/components/deepMining/components/constrainedAssociation.vue
浏览文件 @
f18fbd9e
...
...
@@ -59,8 +59,13 @@
</div>
</AnalysisBox>
</div>
<el-dialog
v-model=
"
visible"
:title=
"curNode.name
"
width=
"960"
>
<el-dialog
v-model=
"
nodeVisible"
:title=
"curNode?.data?.name || '制裁历程'
"
width=
"960"
>
<div
class=
"dialog-content"
>
<div
class=
"info-btn"
>
<el-button
type=
"primary"
:style=
"{ borderRadius: '8px', paddingTop: '10px' }"
@
click=
"handleInfoClick"
>
查看详情 >
</el-button>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
制裁标题:
</div>
<div
class=
"item-desc item-label"
>
...
...
@@ -76,24 +81,37 @@
<div
class=
"content-item"
>
<div
class=
"item-label"
>
依托文件:
</div>
<div
class=
"item-desc"
>
<div
class=
"item-file"
v-for=
"item in vertexInfo.relyFileList"
:key=
"item.id"
>
{{ item.name }}
</div>
<div
class=
"item-file"
v-for=
"item in vertexInfo.relyFileList"
:key=
"item.id"
>
<div
class=
"item-file-name"
>
{{ item.name }}
</div>
<img
:src=
"openIcon"
alt=
"文件"
class=
"item-file-icon"
/>
</div>
</div>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
依托制裁:
</div>
<div
class=
"item-desc"
>
<div
class=
"item-file"
v-for=
"item in vertexInfo.relySanList"
:key=
"item.id"
>
{{ item.title }}
</div>
<div
class=
"item-file"
v-for=
"item in vertexInfo.relySanList"
:key=
"item.id"
>
<div
class=
"item-file-name"
>
{{ item.title }}
</div>
<img
:src=
"openIcon"
alt=
"文件"
class=
"item-file-icon"
/>
</div>
</div>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
制裁原因:
</div>
<div
class=
"item-desc"
>
<div
class=
"item-file"
v-for=
"item in vertexInfo.sanReasonList"
:key=
"item"
>
{{ item }}
</div>
<div
class=
"item-desc-table"
>
<div
class=
"item-file"
v-for=
"item in vertexInfo.sanReasonList"
:key=
"item"
>
<div
class=
"dot"
></div>
<div
class=
"item-file-name"
>
{{ item }}
</div>
</div>
</div>
</div>
<div
class=
"content-item"
>
<div
class=
"item-label"
>
制裁对象:
</div>
<div
class=
"item-desc"
>
<div
class=
"item-desc
item-desc-table
"
>
<span
class=
"item-table-desc"
v-if=
"vertexInfo.addObjectList?.length || vertexInfo.delObjectList?.length"
>
{{ formatChangeSummary(vertexInfo.addObjectList, vertexInfo.delObjectList) }}
</span>
...
...
@@ -109,19 +127,54 @@
</div>
</div>
</el-dialog>
<el-dialog
:title=
"curLink.data?.relationType + '关系' || '关联关系'"
v-model=
"relationVisible"
width=
"960"
>
<div
class=
"dialog-content"
>
<div
class=
"hintWrap"
>
<div
class=
"icon1"
></div>
<div
class=
"title"
>
{{ tipsInfo }}
</div>
<div
class=
"icon2Wrap"
>
<div
class=
"icon2"
></div>
</div>
</div>
<!-- <div class="relation-content">
<RelationChart :is-vertical-chart="true" :graph-data="graphData" />
</div> -->
<div
class=
"relation-charts-container"
>
<div
v-for=
"(graphData, index) in graphDataList"
:key=
"index"
class=
"single-relation-chart-wrapper"
>
<!-- 可选:显示当前小图的标题,例如制裁名称 -->
<div
class=
"chart-title"
v-if=
"graphData.originalItem?.vertex?.name"
>
{{ graphData.originalItem.vertex.name }}
</div>
<div
class=
"relation-content-item"
>
<RelationChart
:is-vertical-chart=
"true"
:graph-data=
"graphData"
/>
</div>
</div>
<!-- 空状态提示 -->
<div
v-if=
"graphDataList.length === 0"
class=
"empty-chart-tip"
>
暂无关联详情数据
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
ref
,
onMounted
,
computed
}
from
"vue"
;
import
GraphChart
from
"@/components/base/GraphChart/index.vue"
;
import
RelationChart
from
"@/components/base/RelationChart/index.vue"
;
import
emptyImg
from
"../assets/empty.png"
;
import
markIcon
from
"../assets/icon-mark.png"
;
// 引入图标
import
{
getSanRecord
,
getRecordRelation
,
getVertexInfo
}
from
"@/api/finance"
;
import
{
useRoute
}
from
"vue-router"
;
import
openIcon
from
"../../../../assets/icons/icon-open.png"
;
import
{
getSanRecord
,
getRecordRelation
,
getVertexInfo
,
getEdgeInfo
}
from
"@/api/finance"
;
import
{
useRoute
,
useRouter
}
from
"vue-router"
;
import
dayjs
from
"dayjs"
;
const
route
=
useRoute
();
const
router
=
useRouter
();
// 定义颜色映射
const
colors
=
{
...
...
@@ -145,6 +198,19 @@ const colors = {
}
};
const
handleInfoClick
=
()
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
`
${
curNode
.
value
.
data
.
originDate
}
-《
${
curNode
.
value
.
data
.
originName
}
》`
);
const
routeData
=
router
.
resolve
({
path
:
"/finance/singleSanction"
,
query
:
{
id
:
curNode
.
value
.
data
.
id
,
sanTypeId
:
sanTypeId
.
value
}
});
// 打开新页面
window
.
open
(
routeData
.
href
,
"_blank"
);
};
// 辅助函数:获取关系类型对应的颜色配置
const
getRelationStyle
=
relationType
=>
{
switch
(
relationType
)
{
...
...
@@ -200,6 +266,20 @@ const recordRelation = ref({ noRelationVertices: [], relationVoList: [] });
const
graphNodes
=
computed
(()
=>
{
const
nodesMap
=
new
Map
();
// 定义统一的标签样式
const
labelStyle
=
{
show
:
true
,
position
:
"bottom"
,
// 标签位置,可根据需要调整为 'top', 'left', 'right', 'inside' 等
fontSize
:
14
,
fontWeight
:
400
,
fontFamily
:
"Source Han Sans CN"
,
lineHeight
:
22
,
color
:
"#333"
// 默认字体颜色,可根据需要调整
// 如果标签背景需要透明或特定颜色,可以添加 backgroundColor
// backgroundColor: 'rgba(255, 255, 255, 0.8)',
// padding: [2, 4]
};
// 1. 处理无关联节点
if
(
recordRelation
.
value
.
noRelationVertices
)
{
recordRelation
.
value
.
noRelationVertices
.
forEach
(
node
=>
{
...
...
@@ -207,12 +287,15 @@ const graphNodes = computed(() => {
nodesMap
.
set
(
node
.
id
,
{
id
:
node
.
id
,
// name: node.name,
originDate
:
node
.
date
,
originName
:
node
.
name
,
name
:
dayjs
(
node
.
date
).
format
(
"YYYY年MM月DD日"
)
+
" "
+
"SDN清单更新"
,
symbol
:
`image://
${
markIcon
}
`
,
// 设置自定义图标
symbolSize
:
[
50
,
50
],
// 根据图标实际大小调整
itemStyle
:
{
color
:
"#91cc75"
}
},
label
:
{
...
labelStyle
}
// 应用标签样式
});
}
});
...
...
@@ -228,12 +311,15 @@ const graphNodes = computed(() => {
nodesMap
.
set
(
from
.
id
,
{
id
:
from
.
id
,
// name: from.name,
originDate
:
from
.
date
,
originName
:
from
.
name
,
name
:
dayjs
(
from
.
date
).
format
(
"YYYY年MM月DD日"
)
+
" "
+
"SDN清单更新"
,
symbol
:
`image://
${
markIcon
}
`
,
// 设置自定义图标
symbolSize
:
[
50
,
50
],
itemStyle
:
{
color
:
"#5470c6"
}
},
label
:
{
...
labelStyle
}
// 应用标签样式
});
}
...
...
@@ -246,7 +332,8 @@ const graphNodes = computed(() => {
symbolSize
:
[
50
,
50
],
itemStyle
:
{
color
:
"#5470c6"
}
},
label
:
{
...
labelStyle
}
// 应用标签样式
});
}
});
...
...
@@ -279,11 +366,14 @@ const graphLinks = computed(() => {
},
lineStyle
:
{
color
:
style
.
lineColor
,
// 连线颜色
width
:
2
width
:
1
,
type
:
"solid"
// curveness: 0.1 // 稍微有点弧度可能更好看
},
// 额外存储原始数据,以备后用
relationType
:
relationType
relationType
:
relationType
,
edgeInfo
:
rel
.
edgeInfo
,
originInfo
:
rel
};
});
});
...
...
@@ -312,19 +402,136 @@ const fetchRecordRelation = async () => {
};
const
vertexInfo
=
ref
({});
const
curNode
=
ref
({});
const
visible
=
ref
(
false
);
const
curLink
=
ref
({});
const
nodeVisible
=
ref
(
false
);
const
relationVisible
=
ref
(
false
);
const
tipsInfo
=
ref
(
""
);
const
graphDataList
=
ref
([]);
const
getTipsInfo
=
(
relationType
,
reason
)
=>
{
switch
(
relationType
)
{
case
"继承"
:
return
`
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
fromVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新依托于
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
toVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新,两次制裁存在继承关系。`
;
case
"冲突"
:
return
`
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
toVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新中制裁的实体在
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
fromVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新中被移除,存在冲突关系。`
;
default
:
return
`
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
fromVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新与
${
dayjs
(
curLink
.
value
.
data
.
originInfo
.
toVertex
.
date
).
format
(
"YYYY年MM月DD日"
)}
-SDN清单更新存在相同
${
reason
}
,属于相似关系。`
;
}
};
// 在 constrainedAssociation.vue 的 script setup 中
const
handleClickNode
=
node
=>
{
console
.
log
(
"节点点击"
,
node
);
curNode
.
value
=
node
.
data
;
if
(
node
.
dataType
==
"node"
)
{
nodeVisible
.
value
=
true
;
curNode
.
value
=
node
;
getVertexInfo
(
node
.
data
.
id
).
then
(
res
=>
{
console
.
log
(
"getVertexInfo"
,
res
);
if
(
!!
res
)
{
vertexInfo
.
value
=
res
;
v
isible
.
value
=
true
;
nodeV
isible
.
value
=
true
;
}
else
{
vertexInfo
.
value
=
{};
}
});
}
else
{
relationVisible
.
value
=
true
;
curLink
.
value
=
node
;
const
relationType
=
node
.
data
.
relationType
;
// 获取边详情数据
getEdgeInfo
(
node
.
data
.
edgeInfo
.
key
)
.
then
(
res
=>
{
if
(
!!
res
&&
Array
.
isArray
(
res
))
{
console
.
log
(
"制裁之间的关系 =>"
,
res
);
// 【核心修改】遍历 res,为每一项生成独立的图表数据
const
list
=
[];
res
.
forEach
((
item
,
index
)
=>
{
const
vertex
=
item
.
vertex
;
if
(
!
vertex
||
!
vertex
.
id
)
return
;
const
nodes
=
[];
const
lines
=
[];
const
nodeMap
=
new
Map
();
// 辅助函数:添加节点
const
addNode
=
(
id
,
text
,
type
=
"vertex"
)
=>
{
if
(
nodeMap
.
has
(
id
))
return
;
const
newNode
=
{
id
:
id
,
text
:
text
,
// 样式:顶点用主题色,细节用白色
color
:
type
===
"vertex"
?
"var(--color-primary-50)"
:
"#ffffff"
,
fontColor
:
type
===
"vertex"
?
"var(--text-primary-90-color)"
:
"#333333"
,
customFontSize
:
type
===
"vertex"
?
"14px"
:
"12px"
};
nodes
.
push
(
newNode
);
nodeMap
.
set
(
id
,
newNode
);
};
// 辅助函数:添加连线
const
addLine
=
(
fromId
,
toId
,
relationText
)
=>
{
lines
.
push
({
from
:
fromId
,
to
:
toId
,
text
:
relationText
,
color
:
"var(--color-primary-50)"
,
fontColor
:
"#666"
});
};
// 1. 添加出发点 (Vertex)
addNode
(
vertex
.
id
,
vertex
.
name
,
"vertex"
);
// 2. 处理 edgeReasonList -> reasonDetail
if
(
item
.
edgeReasonList
&&
item
.
edgeReasonList
.
length
>
0
)
{
item
.
edgeReasonList
.
forEach
(
reasonItem
=>
{
const
relationName
=
reasonItem
.
reason
;
// 例如: "依托文件"
if
(
reasonItem
.
reasonDetail
&&
reasonItem
.
reasonDetail
.
length
>
0
)
{
reasonItem
.
reasonDetail
.
forEach
(
detailItem
=>
{
// 使用 detailItem.name 作为唯一 ID
// 注意:在这个独立的小图中,ID 只要不重复即可。
// 如果不同项之间有相同的 detailItem.name,它们在不同图中是隔离的,所以没问题。
const
detailId
=
detailItem
.
name
;
addNode
(
detailId
,
detailItem
.
name
,
"detail"
);
addLine
(
vertex
.
id
,
detailId
,
relationName
);
});
}
});
}
// 只有当有连线时才加入列表,或者即使只有顶点也加入(视需求而定)
if
(
nodes
.
length
>
0
)
{
list
.
push
({
rootId
:
vertex
.
id
,
nodes
:
nodes
,
lines
:
lines
,
// 可以保留原始数据用于调试或额外展示
originalItem
:
item
});
}
});
graphDataList
.
value
=
list
;
// 处理提示文案 (取第一个或根据业务逻辑组合)
let
reason
=
""
;
if
(
relationType
==
"相似"
&&
res
[
0
]?.
edgeReasonList
?.[
0
]?.
reason
)
{
reason
=
res
[
0
].
edgeReasonList
[
0
].
reason
;
}
tipsInfo
.
value
=
getTipsInfo
(
relationType
,
reason
);
}
else
{
graphDataList
.
value
=
[];
}
})
.
catch
(
err
=>
{
console
.
error
(
"获取边信息失败"
,
err
);
graphDataList
.
value
=
[];
});
}
};
// 【新增/修改】格式化变动 summary 的函数
...
...
@@ -394,15 +601,13 @@ const fetchSanRecord = async () => {
try
{
const
res
=
await
getSanRecord
(
params
);
if
(
res
&&
res
.
length
>
0
)
{
sanctionList
.
value
=
res
.
map
(
item
=>
({
sanctionList
.
value
=
res
.
map
(
item
=>
({
id
:
item
.
sanRecordId
,
date
:
item
.
sanRecordDate
,
title
:
item
.
sanRecordName
,
count
:
item
.
cnEntitiesNum
,
unit
:
"家中国实体"
}))
.
reverse
();
}));
if
(
sanctionList
.
value
.
length
>
0
)
{
currentSanctionId
.
value
=
sanctionList
.
value
[
0
].
id
;
...
...
@@ -502,7 +707,6 @@ onMounted(() => {
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
width
:
100%
;
}
.item-left
{
...
...
@@ -592,27 +796,184 @@ onMounted(() => {
gap
:
16px
;
}
.dialog-content
{
position
:
relative
;
padding
:
20px
;
display
:
flex
;
flex-direction
:
column
;
gap
:
8
px
;
gap
:
16
px
;
border-top
:
1px
solid
rgb
(
238
,
238
,
238
);
// 【新增】关系图容器样式
.relation-charts-container
{
display
:
flex
;
flex-direction
:
column
;
gap
:
20px
;
max-height
:
60vh
;
// 限制最大高度,超出滚动
overflow-y
:
auto
;
padding-right
:
10px
;
// 给滚动条留空间
// 自定义滚动条样式
&
:
:-
webkit-scrollbar
{
width
:
6px
;
}
&
:
:-
webkit-scrollbar-thumb
{
background
:
#ccc
;
border-radius
:
3px
;
}
}
.single-relation-chart-wrapper
{
border
:
1px
solid
#eee
;
border-radius
:
8px
;
padding
:
10px
;
background-color
:
#fafafa
;
.chart-title
{
font-size
:
14px
;
font-weight
:
bold
;
color
:
#333
;
margin-bottom
:
10px
;
padding-left
:
5px
;
border-left
:
3px
solid
var
(
--
color-primary-50
);
}
.relation-content-item
{
height
:
200px
;
// 每个小图的高度,可根据需要调整
width
:
100%
;
// 确保 RelationChart 内部能正确填充
:deep
(
.relation-graph
)
{
width
:
100%
;
height
:
100%
;
}
}
}
.empty-chart-tip
{
text-align
:
center
;
color
:
#999
;
padding
:
20px
;
}
.hintWrap
{
display
:
flex
;
align-items
:
center
;
padding
:
7px
12px
;
border
:
1px
solid
rgba
(
231
,
243
,
255
,
1
);
border-radius
:
4px
;
background
:
rgba
(
246
,
250
,
255
,
1
);
margin-bottom
:
9px
;
.icon1
{
width
:
19px
;
height
:
20px
;
background-image
:
url("../assets/ai.png")
;
background-size
:
100%
100%
;
flex-shrink
:
0
;
}
.title
{
color
:
rgb
(
5
,
95
,
194
);
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
margin-left
:
13px
;
flex
:
1
;
}
.icon2Wrap
{
width
:
24px
;
height
:
24px
;
background-color
:
rgba
(
231
,
243
,
255
,
1
);
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
border-radius
:
12px
;
margin-left
:
20px
;
flex-shrink
:
0
;
.icon2
{
width
:
24px
;
height
:
24px
;
background-image
:
url("../assets/right.png")
;
background-size
:
100%
100%
;
}
}
}
.relation-content
{
height
:
400px
;
width
:
100%
;
}
.info-btn
{
position
:
absolute
;
top
:
20px
;
right
:
20px
;
}
.content-item
{
display
:
flex
;
justify-content
:
flex-start
;
align-items
:
center
;
align-items
:
flex-start
;
gap
:
8px
;
.item-label
{
font-size
:
146x
;
min-width
:
75px
;
font-size
:
14px
;
font-weight
:
700
;
font-family
:
Source
Han
Sans
CN
;
color
:
rgba
(
59
,
65
,
75
,
1
);
line-height
:
24px
;
}
.item-desc-table
{
display
:
flex
;
flex-direction
:
column
;
padding-top
:
3px
;
.dot
{
width
:
4px
;
height
:
4px
;
border-radius
:
50%
;
background-color
:
rgb
(
59
,
65
,
75
);
}
.item-file
{
display
:
flex
;
justify-content
:
flex-start
;
align-items
:
center
;
gap
:
8px
;
// background: rgb(231, 243, 255);
// border-radius: 20px;
// border: 1px solid rgb(231, 243, 255);
padding
:
4px
0px
;
font-family
:
Source
Han
Sans
CN
;
font-size
:
16px
;
font-weight
:
400
;
}
}
.item-desc
{
font-size
:
14px
;
font-family
:
Source
Han
Sans
CN
;
margin-top
:
3px
;
margin-top
:
1px
;
display
:
flex
;
gap
:
15px
;
.item-file
{
display
:
flex
;
justify-content
:
flex-start
;
align-items
:
center
;
gap
:
8px
;
background
:
rgb
(
231
,
243
,
255
);
border-radius
:
20px
;
border
:
1px
solid
rgb
(
231
,
243
,
255
);
padding
:
5px
15px
;
cursor
:
pointer
;
.item-file-name
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
Source
Han
Sans
CN
;
color
:
rgb
(
5
,
95
,
194
);
line-height
:
24px
;
}
.item-file-icon
{
width
:
16px
;
height
:
16px
;
margin-top
:
1px
;
}
}
}
}
}
...
...
src/views/finance/entityList/components/deepMining/components/mock.json
浏览文件 @
f18fbd9e
{
"
id"
:
214
0
,
"
name"
:
"美国以伊朗石油非法贸易为由实施制裁,多家中国企业被列入制裁名单
"
,
"
domainList"
:
[
"海洋"
],
"relyFileList"
:
[
{
"id"
:
null
,
"name"
:
"第13382号行政命令"
"
code"
:
20
0
,
"
message"
:
"操作成功
"
,
"
success"
:
true
,
"data"
:
[
{
"vertex"
:
{
"id"
:
"2145"
,
"name"
:
"OFAC将38个实体及4名个人列入SDN清单,涉及中国关联主体"
,
"highlight"
:
true
},
"edgeReasonList"
:
[
{
"id"
:
null
,
"name"
:
"第14530号行政命令"
}
],
"relySanList"
:
[
"reason"
:
"依托文件"
,
"reasonDetail"
:
[
{
"sanTypeId"
:
2
,
"id"
:
2145
,
"title"
:
"OFAC将38个实体及4名个人列入SDN清单,涉及中国关联主体"
,
"postDate"
:
"2025-10-14"
}
],
"sanReasonList"
:
[
"参与了从伊朗购买、收购、销售、运输或营销石油化工产品"
,
"参与了与采购、获取、销售、运输或销售伊朗石油及石油制品相关的重大交易"
],
"addObjectList"
:
[
"name"
:
"第13382号行政命令"
,
"highlight"
:
false
},
{
"key"
:
"机构
"
,
"value"
:
3
"name"
:
"第13388号行政命令
"
,
"highlight"
:
true
}
],
"delObjectList"
:
[
{
"key"
:
"人物"
,
"value"
:
1
]
}
],
"sanList"
:
[
{
"entityId"
:
"91310115MA1HBB8PXH"
,
"entityName"
:
"SHANGHAI QIZHANG SHIP MANAGEMENT CO., LTD."
,
"entityNameZh"
:
"上海启章船舶管理有限公司"
,
"entityTypeId"
:
2
,
"entityTypeName"
:
"机构"
,
"domainNames"
:
[
"海洋"
]
},
{
"entityId"
:
"71180883"
,
"entityName"
:
"ALL WIN SHIPPING MANAGEMENT LIMITED"
,
"entityNameZh"
:
"誠安船舶管理有限公司"
,
"entityTypeId"
:
2
,
"entityTypeName"
:
"机构"
,
"domainNames"
:
[
"海洋"
]
"vertex"
:
{
"id"
:
"2146"
,
"name"
:
"OFAC将15个中国实体及3名中国籍个人列入SDN清单"
,
"highlight"
:
true
},
"edgeReasonList"
:
[
{
"reason"
:
"依托文件"
,
"reasonDetail"
:
[
{
"entityId"
:
"91370211MAEBUA7E2Q"
,
"entityName"
:
"QINGDAO OCEAN KIMO SHIP MANAGEMENT CO LTD"
,
"entityNameZh"
:
"青岛明洋凯茂船舶管理有限公司"
,
"entityTypeId"
:
2
,
"entityTypeName"
:
"机构"
,
"domainNames"
:
[
"海洋"
"name"
:
"第13388号行政命令"
,
"highlight"
:
true
}
]
}
]
}
]
...
...
src/views/finance/index.vue
浏览文件 @
f18fbd9e
...
...
@@ -25,9 +25,9 @@
</div>
</div>
<el-row
:gutter=
"1
5
"
style=
"width: 1600px; margin: 0 auto; height: 528px; margin-top: 64px"
>
<el-row
:gutter=
"1
6
"
style=
"width: 1600px; margin: 0 auto; height: 528px; margin-top: 64px"
>
<CustomTitle
id=
"position1"
title=
"最新动态"
/>
<el-col
:span=
"16"
>
<el-col
:span=
"16"
style=
"padding: 0"
>
<custom-container
titleType=
"primary"
title=
"最新出口管制政策"
:titleIcon=
"houseIcon"
height=
"450px"
>
<template
#
header-right
>
<el-button
type=
"primary"
@
click=
"handleToEntityList"
link
>
...
...
@@ -132,7 +132,7 @@
</
template
>
</custom-container>
</el-col>
<el-col
:span=
"8"
>
<el-col
:span=
"8"
style=
"padding: 0"
>
<RiskSignal
:list=
"warningList"
@
item-click=
"handleToRiskSignalDetail"
...
...
@@ -144,7 +144,7 @@
</el-col>
</el-row>
<el-row
:gutter=
"1
5
"
style=
"width: 1600px; margin: 0 auto; height: 50px; margin-top: 64px"
>
<el-row
:gutter=
"1
6
"
style=
"width: 1600px; margin: 0 auto; height: 50px; margin-top: 64px"
>
<CustomTitle
id=
"position2"
title=
"资讯要闻"
/>
</el-row>
<!-- <el-col :span="12">
...
...
@@ -187,9 +187,9 @@
</custom-container> -->
</div>
<el-row
:gutter=
"
20
"
style=
"width: 1600px; margin: 0 auto; height: 510px; margin-top: 64px"
>
<el-row
:gutter=
"
16
"
style=
"width: 1600px; margin: 0 auto; height: 510px; margin-top: 64px"
>
<CustomTitle
id=
"position3"
title=
"数据总览"
/>
<el-col
:span=
"24"
>
<el-col
:span=
"24"
style=
"padding: 0"
>
<custom-container
title=
"发布频次统计"
:titleIcon=
"box3Icon"
height=
"420px"
>
<
template
#
default
>
<div
class=
"box3"
>
...
...
@@ -235,7 +235,11 @@
</div>
<div
class=
"box3-content"
>
<div
class=
"box3-content-title"
>
中国军事工业复合体企业清单(CMIC)更新频度
</div>
<el-table
:data=
"commerceControlListReleaseFreq"
stripe
style=
"width: 100%"
>
<el-table
:data=
"commerceControlListReleaseFreq"
stripe
style=
"width: 100%; margin-bottom: auto"
>
<el-table-column
prop=
"year"
label=
"年份"
width=
"200"
/>
<el-table-column
label=
"发布次数"
width=
"300"
>
<
template
#
default=
"scope"
>
...
...
@@ -307,8 +311,8 @@
</el-col>
</el-row>
<el-row
:gutter=
"
20
"
style=
"width: 1600px; margin: 0 auto; height: 540px; margin-top: 16px"
>
<el-col
:span=
"8"
>
<el-row
:gutter=
"
16
"
style=
"width: 1600px; margin: 0 auto; height: 540px; margin-top: 16px"
>
<el-col
:span=
"8"
style=
"padding-left: 0"
>
<custom-container
title=
"制裁领域分布"
:titleIcon=
"radarIcon"
height=
"540px"
>
<
template
#
header-right
>
<el-checkbox
v-model=
"domainChecked"
label=
"50%规则"
size=
"large"
/>
...
...
@@ -328,7 +332,7 @@
</
template
>
</custom-container>
</el-col>
<el-col
:span=
"16"
>
<el-col
:span=
"16"
style=
"padding-right: 0"
>
<custom-container
title=
"制裁清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"540px"
>
<
template
#
header-right
>
<div
style=
"display: flex; align-items: center; gap: 16px"
>
...
...
@@ -355,7 +359,7 @@
</el-col>
</el-row>
<el-row
:gutter=
"
20
"
style=
"width: 1600px; margin: 0 auto; margin-top: 39px; padding-bottom: 60px"
>
<el-row
:gutter=
"
16
"
style=
"width: 1600px; margin: 0 auto; margin-top: 39px; padding-bottom: 60px"
>
<CustomTitle
id=
"position4"
title=
"资源库"
style=
"margin-top: 0px"
/>
<div
class=
"resource-tabs"
>
<div
...
...
@@ -369,7 +373,7 @@
</div>
</div>
<
template
v-if=
"activeResourceTab === 'entity'"
>
<el-col
:span=
"8"
>
<el-col
:span=
"8"
style=
"padding: 0"
>
<custom-container
title=
"历次制裁过程"
:titleIcon=
"listIcon"
height=
"845px"
>
<template
#
default
>
<div
class=
"box4"
>
...
...
@@ -418,7 +422,7 @@
</
template
>
</custom-container>
</el-col>
<el-col
:span=
"16"
>
<el-col
:span=
"16"
style=
"padding: 0"
>
<custom-container
title=
"制裁实体清单"
:titleIcon=
"entityIcon"
height=
"845px"
>
<
template
#
header-right
>
<div
class=
"box5-header-right"
>
共
{{
total
}}
家实体
</div>
...
...
@@ -542,7 +546,7 @@
</el-col>
</template>
<
template
v-if=
"activeResourceTab === 'all'"
>
<el-col
:span=
"24"
>
<el-col
:span=
"24"
style=
"padding: 0"
>
<!--
<div
style=
"min-height: 500px; display: flex; justify-content: center; align-items: center; background: #fff; border-radius: 4px;"
>
暂无内容
</div>
-->
...
...
@@ -781,7 +785,8 @@ const handleToRiskSignalDetail = item => {
const
routeData
=
router
.
resolve
({
path
:
"/finance/singleSanction"
,
query
:
{
id
:
item
.
sanId
id
:
item
.
sanId
,
sanTypeId
:
item
.
sanTypeId
}
});
// 打开新页面
...
...
@@ -1514,6 +1519,7 @@ const fetchSocialMediaInfo = async () => {
if
(
data
&&
Array
.
isArray
(
data
))
{
// console.log(data);
socialMediaList
.
value
=
data
.
map
(
item
=>
({
...
item
,
avatar
:
item
.
personImage
,
name
:
item
.
personName
,
time
:
formatTime
(
item
.
time
),
...
...
@@ -1546,12 +1552,12 @@ const fetchNewsInfo = async () => {
};
const
handlePerClick
=
item
=>
{
//
console.log("点击了社交媒体消息:", item);
console
.
log
(
"点击了社交媒体消息:"
,
item
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
);
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
type
:
item
.
personType
||
[
1
,
2
,
3
][
Math
.
floor
(
Math
.
random
()
*
3
)]
,
type
:
item
.
personType
,
personId
:
item
.
personId
}
});
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论