Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
d2be76a4
提交
d2be76a4
authored
4月 24, 2026
作者:
yanpeng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
bugfix-6
上级
9688726b
显示空白字符变更
内嵌
并排
正在显示
33 个修改的文件
包含
1027 行增加
和
4392 行删除
+1027
-4392
index.js
src/api/finance/index.js
+8
-0
finance.js
src/router/modules/finance.js
+2
-1
influencePanel2.vue
...ews/exportControl/analysis/components/influencePanel2.vue
+5
-0
panel1.vue
src/views/exportControl/analysis/components/panel1.vue
+5
-0
panel2.vue
src/views/exportControl/analysis/components/panel2.vue
+5
-0
RuleSubsidiaryDialog.vue
src/views/exportControl/components/RuleSubsidiaryDialog.vue
+5
-0
index-back.vue
src/views/exportControl/index-back.vue
+0
-3864
index.vue
src/views/exportControl/index.vue
+14
-6
index.vue
...ontrol/v2.0EntityList/components/dataStatistics/index.vue
+1
-0
RuleSubsidiaryDialog.vue
...ionsOverview/components/listPage/RuleSubsidiaryDialog.vue
+5
-0
index.vue
...omponents/sanctionsOverview/components/listPage/index.vue
+5
-0
index.vue
src/views/exportControl/v2.0EntityList/index.vue
+1
-1
index.vue
...ol/v2.0SingleSanction/components/dataStatistics/index.vue
+7
-4
index.vue
...ents/impactAnalysis/components/industrialImpact/index.vue
+167
-89
index.vue
...v2.0SingleSanction/components/sanctionsOverview/index.vue
+19
-2
index.vue
src/views/exportControl/v2.0SingleSanction/index.vue
+1
-1
influencePanel2.vue
src/views/finance/analysis/components/influencePanel2.vue
+5
-0
panel1.vue
src/views/finance/analysis/components/panel1.vue
+5
-0
panel2.vue
src/views/finance/analysis/components/panel2.vue
+5
-0
overview.vue
src/views/finance/analysis/content/overview.vue
+6
-1
index.vue
...ws/finance/entityList/components/dataStatistics/index.vue
+220
-87
constrainedAssociation.vue
...mponents/deepMining/components/constrainedAssociation.vue
+7
-2
index.vue
...s/sanctionsOverview/components/introductionPage/index.vue
+20
-47
RuleSubsidiaryDialog.vue
...ionsOverview/components/listPage/RuleSubsidiaryDialog.vue
+5
-0
index.vue
...omponents/sanctionsOverview/components/listPage/index.vue
+23
-2
index.vue
...finance/entityList/components/sanctionsOverview/index.vue
+6
-7
index.vue
src/views/finance/entityList/index.vue
+1
-1
index.vue
src/views/finance/index.vue
+12
-23
index.vue
...inance/singleSanction/components/dataStatistics/index.vue
+233
-83
index.vue
...ents/impactAnalysis/components/industrialImpact/index.vue
+178
-155
index.vue
...nce/singleSanction/components/sanctionsOverview/index.vue
+35
-4
index.vue
src/views/finance/singleSanction/index.vue
+5
-3
index.vue
src/views/finance/singleSanction/originPage/index.vue
+11
-9
没有找到文件。
src/api/finance/index.js
浏览文件 @
d2be76a4
...
...
@@ -178,3 +178,11 @@ export function getVertexInfo(sanRecordId) {
export
function
getEdgeInfo
(
edgeId
)
{
return
http
.
get
(
`/api/sanctionList/invFin/getEdgeInfo?edgeId=
${
edgeId
}
`
);
}
/**
* 获取字典列表-实体类型
* url:/commonDict/entity/san-type
*/
export
function
getEntityTypeList
()
{
return
http
.
get
(
"/api/commonDict/entity/san-type"
);
}
src/router/modules/finance.js
浏览文件 @
d2be76a4
...
...
@@ -18,7 +18,8 @@ const financeRoutes = [
name
:
"sdnlistOverview"
,
component
:
()
=>
import
(
"@/views/finance/entityList/index.vue"
),
meta
:
{
title
:
"SDN制裁清单概览"
title
:
"SDN制裁清单概览"
,
dynamicTitle
:
true
}
},
// V2.0单条制裁详情
...
...
src/views/exportControl/analysis/components/influencePanel2.vue
浏览文件 @
d2be76a4
...
...
@@ -85,6 +85,7 @@
import
{
ref
,
onMounted
,
shallowReactive
,
shallowRef
,
watch
}
from
"vue"
;
import
CardCustom
from
"../../components/CardCustom.vue"
;
import
Echarts
from
"@/components/Chart/index.vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
Hint
from
"./hint.vue"
;
import
ButtonList
from
"@/components/buttonList/buttonList.vue"
;
import
Fishbone
from
"./fishbone.vue"
;
...
...
@@ -164,6 +165,10 @@ const handleEttClick = item => {
//
}
//
}
);
// window.open(route.href, "_blank");
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
gotoCompanyPages
(
item
.
id
);
}
;
// 处理点击事件
...
...
src/views/exportControl/analysis/components/panel1.vue
浏览文件 @
d2be76a4
...
...
@@ -89,6 +89,7 @@
import
{
ref
,
shallowRef
,
onMounted
,
watch
}
from
"vue"
;
import
CardCustom
from
"../../components/CardCustom.vue"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
Echarts
from
"@/components/Chart/index.vue"
;
import
{
getBarChart
,
getLineChart
}
from
"../../utils/charts"
;
import
Hint
from
"./hint.vue"
;
...
...
@@ -350,6 +351,10 @@ const handleOrgClick = item => {
// }
// });
// window.open(route.href, "_blank");
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
gotoCompanyPages
(
item
.
id
);
};
</
script
>
...
...
src/views/exportControl/analysis/components/panel2.vue
浏览文件 @
d2be76a4
...
...
@@ -68,6 +68,7 @@
import
{
ref
,
shallowRef
,
onMounted
,
watch
}
from
"vue"
;
import
CardCustom
from
"../../components/CardCustom.vue"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
Echarts
from
"@/components/Chart/index.vue"
;
import
{
getBarChart
,
getLineChart
}
from
"../../utils/charts"
;
import
_
from
"lodash"
;
...
...
@@ -313,6 +314,10 @@ const handleOrgClick = item => {
// }
// });
// window.open(route.href, "_blank");
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
gotoCompanyPages
(
item
.
id
);
};
</
script
>
...
...
src/views/exportControl/components/RuleSubsidiaryDialog.vue
浏览文件 @
d2be76a4
...
...
@@ -80,6 +80,7 @@
<
script
setup
>
import
{
ref
,
defineProps
,
defineEmits
,
computed
,
watch
}
from
"vue"
;
import
{
Close
}
from
"@element-plus/icons-vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
defaultIcon
from
"@/assets/icons/default-icon1.png"
;
import
{
useGotoCompanyPages
}
from
"@/router/modules/company"
;
const
gotoCompanyPages
=
useGotoCompanyPages
();
...
...
@@ -155,6 +156,10 @@ const getTagStyle = tag => {
// 跳转公司详情页
const
handleCompClick
=
item
=>
{
console
.
log
(
"item"
,
item
);
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
||
item
.
orgName
);
gotoCompanyPages
(
item
.
id
);
};
...
...
src/views/exportControl/index-back.vue
deleted
100644 → 0
浏览文件 @
9688726b
<
template
>
<div
class=
"home-wrapper"
>
<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=
"实体清单"
/>
<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)"
/>
</div>
</div>
<el-row
:gutter=
"16"
style=
"width: 1600px; margin: 0 auto; height: 528px; margin-top: 64px"
>
<CustomTitle
id=
"position1"
title=
"最新动态"
/>
<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
>
{{
"查看详情 >"
}}
</el-button>
</
template
>
<
template
#
default
>
<div
class=
"box1"
>
<div
class=
"box1-left-arrow"
@
click=
"handleSwithCurPolicy('left')"
>
<div
class=
"icon"
>
<img
src=
"./assets/images/box1-left.png"
alt=
""
/>
</div>
</div>
<div
class=
"box1-right-arrow"
@
click=
"handleSwithCurPolicy('right')"
>
<div
class=
"icon"
>
<img
src=
"./assets/images/box1-right.png"
alt=
""
/>
</div>
</div>
<el-carousel
ref=
"carouselRef"
height=
"370px"
:autoplay=
"false"
: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"
>
<div
class=
"box1-top-title"
>
{{
item
.
postDate
}}
——
{{
item
.
name
}}
</div>
<div
class=
"box1-top-content"
>
<div
class=
"box1-top-content-item"
>
<span
class=
"box1-top-content-item-title"
>
· 发布机构:
</span>
<span
class=
"box1-top-content-item-content"
>
{{
item
.
postOrgName
}}
</span>
</div>
<div
class=
"box1-top-content-item"
>
<span
class=
"box1-top-content-item-title"
>
· 生效日期:
</span>
<span
class=
"box1-top-content-item-content"
>
{{
item
.
postDate
}}
</span>
</div>
<div
class=
"box1-top-content-item"
>
<span
class=
"box1-top-content-item-title"
>
· 涉及领域:
</span>
<AreaTag
v-for=
"(domainItem, index) in item.domains"
:key=
"index"
:tagName=
"domainItem"
/>
</div>
</div>
</div>
<div
class=
"box1-bottom"
>
<div
class=
"box1-bottom-sanTypeId"
v-if=
"item.sanEntities?.length"
>
<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
v-else
class=
"box1-bottom-content-item-imgUndefined"
>
{{
(
ett
.
orgName
||
ett
.
orgNameZh
)?.
match
(
/
[\u
4e00-
\u
9fa5a-zA-Z0-9
]
/
)?.[
0
]
}}
</div>
<div
class=
"box1-bottom-content-item-txt"
>
{{
ett
.
orgName
||
ett
.
orgNameZh
}}
</div>
</div>
</div>
</div>
<div
class=
"box1-bottom-sanTypeId"
v-if=
"item.sanItems?.length > 0"
>
<div
class=
"box1-bottom-title"
>
· 涉及管制物项:
</div>
<div
class=
"box1-bottom-content__wx"
>
<div
class=
"box1-bottom-content__wx-item"
v-for=
"(ett, index) in item.sanItems"
:key=
"index"
@
click=
"handleWxClick(item)"
>
<div
class=
"box1-bottom-content__wx-item-id"
>
{{
ett
.
id
}}
</div>
<div
class=
"box1-bottom-content__wx-item-txt"
>
{{
ett
.
name
}}
</div>
</div>
</div>
</div>
</div>
<div
class=
"box1-absolute"
@
click=
"handleToDataLibrary(item)"
>
<div
class=
"box1-absolute-des"
>
<el-icon>
<Warning
color=
"rgba(206, 79, 81, 1)"
/>
</el-icon>
<span>
{{
item
.
sanTypeId
==
allSanTypeIds
[
0
]
?
"新增中国实体"
:
"新增物项"
}}
</span>
</div>
<div
class=
"box1-absolute-num"
>
{{
item
.
cnEntityCount
}}{{
item
.
sanTypeId
==
allSanTypeIds
[
0
]
?
"家"
:
"项"
}}
</div>
</div>
</div>
</el-carousel-item>
</el-carousel>
</div>
</
template
>
</custom-container>
</el-col>
<el-col
:span=
"8"
style=
"padding-right: 0px"
>
<RiskSignal
:list=
"warningList"
@
item-click=
"handleToRiskSignalDetail"
@
more-click=
"handleToMoreRiskSignal"
riskLevel=
"signalLevel"
postDate=
"signalTime"
name=
"signalTitle"
/>
</el-col>
</el-row>
<el-row
:gutter=
"16"
style=
"width: 1600px; margin: 0 auto; height: 50px; margin-top: 64px"
>
<CustomTitle
id=
"position2"
title=
"资讯要闻"
/>
</el-row>
<div
class=
"center-center"
>
<NewsList
:newsList=
"newsList"
@
item-click=
"handleNewsInfoClick"
@
more-click=
"handleToMoreNews"
content=
"newsContent"
/>
<MessageBubble
:messageList=
"socialMediaList"
@
person-click=
"handlePerClick"
imageUrl=
"avatar"
@
more-click=
"handleToSocialDetail"
/>
</div>
<el-row
:gutter=
"16"
style=
"width: 1600px; margin: 0 auto; height: 510px; margin-top: 64px"
>
<CustomTitle
id=
"position3"
title=
"数据总览"
/>
<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-column
prop=
"year"
label=
"年份"
width=
"200"
/>
<el-table-column
label=
"发布次数"
width=
"300"
>
<template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center; cursor: pointer"
>
<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)"
/>
</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"
>
<AreaTag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:tagName=
"tag"
/>
</div>
</
template
>
</el-table-column>
</el-table>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
数据来源:美国商务部官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
@
mouseenter=
"handleShowAiPane('entityListReleaseFreqChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.entityListReleaseFreqChart"
:aiContent=
"overviewAiContent.entityListReleaseFreqChart"
@
mouseleave=
"handleHideAiPane('entityListReleaseFreqChart')"
/>
</div>
</div>
<div
class=
"box3-content"
>
<div
class=
"box3-content-title"
>
商业管制清单发布频次统计
</div>
<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; cursor: pointer"
>
<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)"
/>
</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"
>
<AreaTag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:tagName=
"tag"
/>
</div>
</
template
>
</el-table-column>
</el-table>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
数据来源:美国商务部官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
@
mouseenter=
"handleShowAiPane('commerceControlListReleaseFreqChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.commerceControlListReleaseFreqChart"
:aiContent=
"overviewAiContent.commerceControlListReleaseFreqChart"
@
mouseleave=
"handleHideAiPane('commerceControlListReleaseFreqChart')"
/>
</div>
</div>
<div
class=
"box3-content"
style=
"display: none"
>
<div
class=
"box3-content-title"
>
关键与新兴技术清单(CETs)
</div>
<el-table
:data=
"entityListReleaseFreq"
stripe
style=
"width: 100%"
>
<el-table-column
prop=
"year"
label=
"年份"
width=
"100"
/>
<el-table-column
label=
"发布次数"
width=
"180"
>
<
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)"
/>
</div>
</
template
>
</el-table-column>
<el-table-column
label=
"重点领域"
width=
"180"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center; gap: 5px"
>
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"getTagType(tag)"
>
{{
tag
}}
</el-tag>
</div>
</
template
>
</el-table-column>
</el-table>
</div>
</div>
</template>
</custom-container>
</el-col>
</el-row>
<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"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
数据来源:美国商务部官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
@
mouseenter=
"handleShowAiPane('radarChart')"
/>
<AiPane
:aiContent=
"overviewAiContent.radarChart"
@
mouseleave=
"handleHideAiPane('radarChart')"
/>
</div>
</
template
>
</custom-container>
</el-col>
<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"
>
<el-checkbox
v-if=
"selectedEntityId != '13'"
v-model=
"trendChecked"
label=
"50%规则"
size=
"large"
/>
<el-select
v-model=
"selectedEntityId"
placeholder=
"请选择清单类型"
style=
"width: 160px"
>
<el-option
v-for=
"item in infoList"
:key=
"item.id"
:label=
"item.nameZh"
:value=
"item.id"
/>
</el-select>
</div>
</
template
>
<
template
#
default
>
<EChart
:option=
"trendOption"
autoresize
:style=
"
{ height: '420px' }"
@chart-click="handleMultiBarChartClick"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
数据来源:美国商务部官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
@
mouseenter=
"handleShowAiPane('trendChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.trendChart"
:aiContent=
"overviewAiContent.trendChart"
@
mouseleave=
"handleHideAiPane('trendChart')"
/>
</div>
</
template
>
</custom-container>
</el-col>
</el-row>
<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"
:class=
"{ active: activeResourceTab == tab.value, disabled: tab.disabled }"
@
click=
"handleResourceTabClick(tab)"
>
{{ tab.label }}
</div>
</div>
<
template
v-if=
"activeResourceTab === 'entity'"
>
<el-col
:span=
"8"
style=
"padding-left: 0"
>
<custom-container
title=
"历次制裁过程"
:titleIcon=
"listIcon"
height=
"845px"
>
<template
#
default
>
<div
class=
"box4"
>
<div
style=
"height: 90%; overflow-y: auto; padding-top: 10px"
>
<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>
<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-desc"
>
{{
item
.
desc
}}
</span>
</div>
<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>
</el-tooltip>
</div>
</div>
</div>
<div
class=
"box4-footer"
:style=
"
{ marginTop: sanctionProcessList.length > 0 ? '0px' : 'auto' }"
>
<el-button
type=
"primary"
link
@
click=
"handleGetMore"
>
查看更多
<el-icon>
<DArrowRight
/>
</el-icon>
</el-button>
</div>
</div>
</
template
>
</custom-container>
</el-col>
<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-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>
<div
v-else
class=
"box1-bottom-content-item-imgUndefined"
>
{{
(
scope
.
row
.
name
||
scope
.
row
.
enName
)?.
match
(
/
[\u
4e00-
\u
9fa5a-zA-Z0-9
]
/
)?.[
0
]
}}
</div>
<CommonPrompt
:content=
"scope.row.name"
style=
"flex: 1; overflow: hidden"
/>
</div>
</
template
>
</el-table-column>
<el-table-column
prop=
"domains"
label=
"涉及领域"
min-width=
"150"
>
<
template
#
default=
"scope"
>
<div
class=
"domain-tags"
>
<AreaTag
v-for=
"tag in scope.row.domains"
:key=
"tag"
:tagName=
"tag"
/>
</div>
<!--
<div
class=
"domain-tags"
>
<el-tag
v-for=
"tag in scope.row.domains"
:key=
"tag"
:type=
"getTagType(tag)"
>
{{
tag
}}
</el-tag>
</div>
-->
</
template
>
</el-table-column>
<el-table-column
prop=
"sanctionDate"
label=
"制裁时间"
width=
"120"
align=
"center"
>
<
template
#
default=
"scope"
>
{{
scope
.
row
.
sanctionDate
}}
</
template
>
</el-table-column>
<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=
"[
'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)"
>
{{
scope
.
row
.
ruleOrgCount
}}
家>
</div>
</div>
</
template
>
</el-table-column>
</el-table>
<div
class=
"table-footer"
>
<!-- <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"
/>
</div>
</div>
</template>
</custom-container>
</el-col>
</template>
<
template
v-if=
"activeResourceTab === 'all'"
>
<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>
-->
<div
class=
"all-content"
>
<div
class=
"left"
>
<div
class=
"title"
>
<div
class=
"box"
></div>
<div
class=
"text"
>
科技领域
</div>
</div>
<div
class=
"left-main"
>
<el-checkbox-group
v-model=
"checkedTech"
>
<div
class=
"checkbox-grid"
>
<el-checkbox
v-for=
"item in techOptions"
:key=
"item.value"
:label=
"item.value"
>
{{
item
.
label
}}
</el-checkbox>
</div>
</el-checkbox-group>
</div>
<div
class=
"title"
>
<div
class=
"box"
></div>
<div
class=
"text"
>
制裁时间
</div>
</div>
<div
class=
"left-main"
>
<el-checkbox-group
v-model=
"checkedTime"
>
<div
class=
"checkbox-grid"
>
<el-checkbox
v-for=
"item in timeOptions"
:key=
"item.value"
:label=
"item.label"
>
{{
item
.
label
}}
</el-checkbox>
</div>
</el-checkbox-group>
<div
v-if=
"timeOptions.find(i => i.value === 'custom' && i.checked)"
class=
"custom-date-picker"
>
<el-date-picker
v-model=
"customDateRange"
type=
"daterange"
range-separator=
"-"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
/>
</div>
</div>
</div>
<div
class=
"right"
>
<div
class=
"right-title"
>
<img
:src=
"icon01"
alt=
""
/>
<div>
出口管制制裁措施
</div>
</div>
<div
class=
"right-main"
>
<div
class=
"sanction-list"
v-for=
"item in sanctionList"
:key=
"item.id"
>
<div
class=
"time"
>
<div
class=
"year"
>
{{
item
.
year
}}
</div>
<div
class=
"date"
>
{{
item
.
dateStr
}}
</div>
</div>
<img
:src=
"item.orgLogoUrl || comTitle"
alt=
""
/>
<div
class=
"main"
>
<div
class=
"main-title"
@
click=
"handleTitleClick(item)"
>
{{
item
.
title
}}
</div>
<div
class=
"main-desc"
>
{{
item
.
desc
}}
</div>
<div
class=
"tag-box"
>
<div
v-for=
"tag in item.tags"
:key=
"tag"
class=
"tag-item"
>
{{
tag
}}
</div>
</div>
<div
:class=
"
{ 'count-tag': item.countTag }">
{{
item
.
countTag
}}
</div>
</div>
</div>
</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"
/>
</div>
</div>
</div>
</el-col>
</
template
>
<
template
v-if=
"activeResourceTab === 'commerce'"
>
<div
class=
"commerce-wrapper"
:style=
"
{ minHeight: '500px' }">
<listPage
/>
</div>
</
template
>
</el-row>
</div>
<RuleSubsidiaryDialog
v-model=
"dialogVisible"
:company-name=
"currentRuleCompany"
:total-count=
"currentRuleCount"
:data-list=
"currentOrgList"
/>
</div>
<el-dialog
v-model=
"mediaVisible"
title=
"社交媒体信息"
width=
"500"
:before-close=
"handleMediaClose"
>
<div
class=
"dialog-content"
>
{{ currentMedia }}
</div>
<
template
#
footer
>
<div
class=
"dialog-footer"
>
<!--
<el-button
@
click=
"mediaVisible = false"
>
Cancel
</el-button>
-->
<el-button
type=
"primary"
@
click=
"mediaVisible = false"
>
确定
</el-button>
</div>
</
template
>
</el-dialog>
<RiskSignalOverviewDetailDialog
v-model=
"isRiskOverviewDetailOpen"
:row=
"riskOverviewDetailRow"
name-field=
"signalTitle"
post-date-field=
"signalTime"
risk-level-field=
"signalLevel"
/>
</template>
<
script
setup
>
//这是一个备注
import
NewsList
from
"@/components/base/newsList/index.vue"
;
import
RiskSignal
from
"@/components/base/riskSignal/index.vue"
;
import
{
getChartAnalysis
}
from
"@/api/aiAnalysis/index"
;
import
RiskSignalOverviewDetailDialog
from
"@/components/base/RiskSignalOverviewDetailDialog/index.vue"
;
import
{
onMounted
,
ref
,
computed
,
reactive
,
shallowRef
,
watch
,
nextTick
}
from
"vue"
;
import
{
useContainerScroll
}
from
"@/hooks/useScrollShow"
;
const
homeMainRef
=
ref
(
null
);
const
{
isShow
}
=
useContainerScroll
(
homeMainRef
);
import
setChart
from
"@/utils/setChart"
;
import
listPage
from
"./v2.0CommercialControlList/components/sanctionsOverview/components/listPage/index.vue"
;
import
EChart
from
"@/components/Chart/index.vue"
;
import
tipsIcon
from
"./assets/icons/info-icon.png"
;
import
AiButton
from
"@/components/base/Ai/AiButton/index.vue"
;
import
AiPane
from
"@/components/base/Ai/AiPane/index.vue"
;
import
AreaTag
from
"@/components/base/AreaTag/index.vue"
;
import
{
useChartInterpretation
}
from
"@/views/exportControl/utils/common"
;
import
{
TAGTYPE
}
from
"@/public/constant"
;
import
{
useGotoCompanyPages
}
from
"@/router/modules/company"
;
import
{
useGotoNewsDetail
}
from
"@/router/modules/news"
;
const
gotoCompanyPages
=
useGotoCompanyPages
();
const
gotoNewsDetail
=
useGotoNewsDetail
();
const
trendChart
=
useChartInterpretation
();
const
radarChart
=
useChartInterpretation
();
const
entityListReleaseFreqChart
=
useChartInterpretation
();
const
commerceControlListReleaseFreqChart
=
useChartInterpretation
();
import
{
useRouter
}
from
"vue-router"
;
import
{
navigateToViewRiskSignal
}
from
"@/utils/riskSignalOverviewNavigate"
;
const
router
=
useRouter
();
import
CustomContainer
from
"@/components/Container/index.vue"
;
import
ClickableCard
from
"./components/link.vue"
;
import
InfoCard
from
"./components/info.vue"
;
import
CustomTitle
from
"./components/title.vue"
;
import
CommonPrompt
from
"./commonPrompt/index.vue"
;
import
RuleSubsidiaryDialog
from
"./components/RuleSubsidiaryDialog.vue"
;
import
trumpAvatar
from
"@/assets/images/icon-trump.png"
;
import
elongAvatar
from
"@/assets/images/icon-elong.png"
;
import
newsIcon
from
"@/assets/images/icon-news.png"
;
import
dialogIcon
from
"@/assets/images/icon-duihua.png"
;
import
houseIcon
from
"@/assets/images/icon-house.png"
;
import
dangerIcon
from
"./assets/images/box2-header-icon.png"
;
import
box1Image
from
"./assets/images/box1-image.png"
;
import
box3Icon
from
"./assets/images/box1-header-icon.png"
;
import
radarIcon
from
"./assets/images/icon-radar.png"
;
import
qushiIcon
from
"./assets/images/icon-qushi.png"
;
import
listIcon
from
"./assets/images/icon-list.png"
;
import
dotIcon
from
"./assets/images/info2-icon.png"
;
import
entityIcon
from
"./assets/images/icon-entity.png"
;
import
comTitle
from
"./assets/images/panel1_1.png"
;
import
getMultiLineChart
from
"./utils/multiLineChart"
;
import
icon01
from
"./assets/images/jianzhu.png"
;
import
{
getEntitiesDataCount
,
getEntitiesDataInfo
,
getIndustryCountByYear
,
getCountDomainByYear
,
getSanctionsInfoCount
,
getEntitiesList
,
getSanctionProcess
,
getSanDomainCount
,
getRiskSignal
,
getSocialMediaInfo
,
getNewsInfo
,
getExportControlList
}
from
"@/api/exportControl"
;
import
{
getMultipleBarChart_m
}
from
"./utils/charts"
;
import
{
formatAnyDateToChinese
}
from
"./utils"
;
import
_
from
"lodash"
;
const
currentRuleCompany
=
ref
(
""
);
const
currentRuleCount
=
ref
(
0
);
const
currentRuleList
=
ref
([]);
const
handleToPosi
=
id
=>
{
const
element
=
document
.
getElementById
(
id
);
if
(
element
&&
homeMainRef
.
value
)
{
// 1. 如果是从完整搜索框跳转,先强制切换状态稳定布局
if
(
!
isShow
.
value
)
{
isShow
.
value
=
true
;
}
// 2. 使用 nextTick 等待 DOM 布局(如高度切换)完成后再进行坐标计算
nextTick
(()
=>
{
const
containerRect
=
homeMainRef
.
value
.
getBoundingClientRect
();
const
elementRect
=
element
.
getBoundingClientRect
();
// 使用 getBoundingClientRect 计算元素相对于容器顶部的绝对距离,不受嵌套布局影响
const
top
=
elementRect
.
top
-
containerRect
.
top
+
homeMainRef
.
value
.
scrollTop
;
homeMainRef
.
value
.
scrollTo
({
top
:
top
,
behavior
:
"smooth"
});
});
}
};
const
isRiskOverviewDetailOpen
=
ref
(
false
);
const
riskOverviewDetailRow
=
ref
(
null
);
const
handleToRiskSignalDetail
=
item
=>
{
riskOverviewDetailRow
.
value
=
item
??
null
;
isRiskOverviewDetailOpen
.
value
=
true
;
};
const
sanctionList
=
ref
([]);
const
techOptions
=
[
{
label
:
"全部领域"
,
value
:
0
},
{
label
:
"人工智能"
,
value
:
1
},
{
label
:
"生物科技"
,
value
:
2
},
{
label
:
"新一代信息技术"
,
value
:
3
},
{
label
:
"量子科技"
,
value
:
4
},
{
label
:
"新能源"
,
value
:
5
},
{
label
:
"集成电路"
,
value
:
6
},
{
label
:
"海洋"
,
value
:
7
},
{
label
:
"先进制造"
,
value
:
8
},
{
label
:
"新材料"
,
value
:
9
},
{
label
:
"航空航天"
,
value
:
10
},
{
label
:
"深海"
,
value
:
11
},
{
label
:
"极地"
,
value
:
12
},
{
label
:
"太空"
,
value
:
13
},
{
label
:
"核"
,
value
:
14
}
];
const
customDateRange
=
ref
(
""
);
const
timeOptions
=
[
{
label
:
"全部时间"
,
value
:
"all"
,
checked
:
true
},
{
label
:
"2025年"
,
value
:
"2025"
,
checked
:
false
},
{
label
:
"2024年"
,
value
:
"2024"
,
checked
:
false
},
{
label
:
"2023年"
,
value
:
"2023"
,
checked
:
false
},
{
label
:
"2022年"
,
value
:
"2022"
,
checked
:
false
},
{
label
:
"2021年"
,
value
:
"2021"
,
checked
:
false
},
{
label
:
"自定义"
,
value
:
"custom"
,
checked
:
false
}
];
const
checkedTech
=
ref
([
0
]);
const
checkedTime
=
ref
([
"全部时间"
]);
// 跳转到单条制裁页面,单独打开一个新页面
const
handleTitleClick
=
item
=>
{
if
(
item
.
sanTypeId
==
"13"
)
{
handleWxClick
(
item
);
return
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
`
${
item
.
year
}
-
${
item
.
dateStr
}
《
${
item
.
title
}
》`
);
const
route
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
query
:
{
id
:
item
.
id
,
sanTypeId
:
item
.
sanTypeId
,
date
:
`
${
item
.
year
}
-
${
item
.
dateStr
}
`
}
});
window
.
open
(
route
.
href
,
"_blank"
);
};
const
handleCompClick
=
item
=>
{
// console.log("item", item);
if
(
!
item
.
id
)
return
;
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
);
gotoCompanyPages
(
item
.
entityId
);
// const route = router.resolve({
// name: "companyPages",
// params: {
// id: item.id,
// sanTypeId: item.sanTypeId
// }
// });
// window.open(route.href, "_blank");
};
const
tagsType
=
[
"primary"
,
"success"
,
"warning"
,
"danger"
];
const
getTagType
=
tag
=>
{
if
(
!
tag
)
return
"info"
;
const
strTag
=
String
(
tag
).
trim
();
const
tagColorMap
=
{
通信网络
:
"primary"
,
人工智能
:
"danger"
,
集成电路
:
"warning"
,
量子科技
:
"success"
,
生物技术
:
"info"
,
新一代信息技术
:
"primary"
,
新能源
:
"success"
,
航空航天
:
"primary"
,
先进制造
:
"warning"
,
海洋
:
"info"
,
新材料
:
"danger"
,
深海
:
"primary"
,
极地
:
"info"
,
核
:
"danger"
,
其他
:
"info"
};
if
(
tagColorMap
[
strTag
])
{
return
tagColorMap
[
strTag
];
}
const
hash
=
strTag
.
split
(
""
).
reduce
((
acc
,
char
)
=>
acc
+
char
.
charCodeAt
(
0
),
0
);
return
TAGTYPE
[
hash
%
TAGTYPE
.
length
];
};
//数据定义
const
entitiesDataInfoList
=
shallowRef
([]);
// 趋势图
const
trendOption
=
ref
({});
const
trendChecked
=
ref
(
false
);
const
selectedEntityId
=
ref
(
1
);
// 发布频度
const
entityListReleaseFreq
=
ref
([]);
// CCL发布频度
const
commerceControlListReleaseFreq
=
ref
([]);
// 历次制裁过程
const
sanctionProcessList
=
ref
([]);
const
sanctionPage
=
ref
(
1
);
// 制裁实体清单
const
entitiesList
=
ref
([]);
// 风险信号
const
riskSignalList
=
ref
([]);
// 社交媒体信息
const
socialMediaList
=
ref
([]);
// 新闻资讯
const
newsList
=
ref
([]);
onMounted
(
async
()
=>
{
try
{
const
[
dataCount
,
entitiesDataInfo
,
industryCountByYear
,
cclList
]
=
await
Promise
.
all
([
getEntitiesDataCount
(),
getEntitiesDataInfo
(),
getIndustryCountByYear
(
1
),
getIndustryCountByYear
(
13
)
]);
// 交换第二个和第三个元素
// [dataCount[1], dataCount[2]] = [dataCount[2], dataCount[1]];
infoList
.
value
=
dataCount
.
slice
(
0
,
2
).
map
((
item
,
idx
)
=>
{
return
{
...
item
,
unit
:
idx
==
0
?
"家"
:
"项"
};
});
allSanTypeIds
.
value
=
infoList
.
value
.
map
(
item
=>
item
.
id
);
resourceTabs
.
value
=
infoList
.
value
.
map
(
item
=>
({
label
:
item
.
nameZh
,
value
:
tabMap
[
item
.
id
],
id
:
item
.
id
,
disabled
:
false
}));
resourceTabs
.
value
.
unshift
({
label
:
"全部制裁"
,
value
:
"all"
,
id
:
""
,
disabled
:
false
});
console
.
log
(
"返回的数据结构 infoList =》"
,
resourceTabs
.
value
);
entitiesDataInfoList
.
value
=
entitiesDataInfo
||
[];
const
list
=
_
.
chain
(
industryCountByYear
).
filter
(
"year"
).
orderBy
(
"year"
,
"desc"
).
value
().
slice
(
0
,
5
);
const
cclList1
=
_
.
chain
(
cclList
).
filter
(
"year"
).
orderBy
(
"year"
,
"desc"
).
value
().
slice
(
0
,
5
);
const
total
=
_
.
sumBy
(
list
,
"count"
);
const
maxCountItem
=
_
.
maxBy
(
list
,
"count"
);
const
maxCountForList
=
maxCountItem
?
maxCountItem
.
count
:
0
;
const
maxCountItem1
=
_
.
maxBy
(
cclList1
,
"count"
);
const
maxCountForList1
=
maxCountItem1
?
maxCountItem1
.
count
:
0
;
entityListReleaseFreq
.
value
=
_
.
map
(
list
,
item
=>
{
return
{
year
:
item
.
year
,
num
:
item
.
count
,
percent
:
item
.
count
/
maxCountForList
,
tags
:
item
.
domain
};
});
entityListReleaseFreqChartData
.
value
=
entityListReleaseFreq
.
value
;
// entityListReleaseFreqChart.interpret({
// type: "柱状图",
// name: "美国商务部发布实体清单的频次",
// data: entityListReleaseFreq.value
// });
commerceControlListReleaseFreq
.
value
=
_
.
map
(
cclList1
,
item
=>
{
return
{
year
:
item
.
year
,
num
:
item
.
count
,
percent
:
item
.
count
/
maxCountForList1
,
tags
:
item
.
domain
};
});
commerceControlListReleaseFreqChartData
.
value
=
commerceControlListReleaseFreq
.
value
;
// commerceControlListReleaseFreqChart.interpret({
// type: "柱状图",
// name: "美国商务部发布商业管制清单的频次",
// data: commerceControlListReleaseFreq.value
// });
// 获取趋势图数据
await
fetchTrendData
();
await
fetchRiskSignals
(
"0103"
);
// 获取社交媒体信息
await
fetchSocialMediaInfo
();
// 获取新闻资讯
await
fetchNewsInfo
();
await
fetchEntitiesList
(
currentPage
.
value
,
pageSize
.
value
);
await
fetchSanctionProcess
(
sanctionPage
.
value
,
10
);
// 获取雷达图数据
await
fetchRadarData
(
domainChecked
.
value
);
// 获取出口管制制裁措施
await
fetchSanctionList
();
}
catch
(
err
)
{
console
.
log
(
err
);
}
});
// 查看社交媒体详情
const
handleToSocialDetail
=
item
=>
{
const
route
=
router
.
resolve
({
path
:
"/characterPage"
,
query
:
{
personId
:
item
.
id
}
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 获取趋势图数据
const
fetchTrendData
=
async
()
=>
{
try
{
const
res
=
await
getCountDomainByYear
({
isRule
:
selectedEntityId
.
value
!=
"13"
&&
trendChecked
.
value
,
startYear
:
"2020"
,
endYear
:
String
(
new
Date
().
getFullYear
()),
sanTypeId
:
selectedEntityId
.
value
});
if
(
res
&&
res
[
0
]
&&
res
[
0
].
yearDomainCount
)
{
trendOption
.
value
=
processYearDomainCountData
(
res
[
0
].
yearDomainCount
);
trendChartData
.
value
=
res
[
0
].
yearDomainCount
;
// trendChart.interpret({ type: "柱状图", name: "制裁清单数量增长趋势", data: res[0].yearDomainCount });
}
}
catch
(
error
)
{
console
.
error
(
"获取趋势图数据失败:"
,
error
);
}
};
const
requestAiPaneContent
=
async
key
=>
{
if
(
!
key
||
aiPaneLoading
.
value
[
key
]
||
aiPaneFetched
.
value
[
key
])
return
;
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
true
};
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成中..."
};
try
{
const
payload
=
buildAiChartPayload
(
key
);
const
res
=
await
getChartAnalysis
(
{
text
:
JSON
.
stringify
(
payload
)
},
{
onChunk
:
chunk
=>
{
const
current
=
overviewAiContent
.
value
[
key
];
const
base
=
current
===
"智能总结生成中..."
?
""
:
current
;
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
base
+
chunk
};
}
}
);
const
list
=
res
?.
data
;
const
first
=
Array
.
isArray
(
list
)
?
list
[
0
]
:
null
;
const
interpretation
=
first
?.
解读
||
first
?.[
"解读"
];
// 流式已渲染过内容,最终用解析出的解读覆盖(保证显示格式统一)
if
(
interpretation
)
{
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
interpretation
};
}
aiPaneFetched
.
value
=
{
...
aiPaneFetched
.
value
,
[
key
]:
true
};
}
catch
(
error
)
{
console
.
error
(
"获取图表解读失败"
,
error
);
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成失败"
};
}
finally
{
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
false
};
}
};
const
trendChartData
=
ref
([]);
const
radarChartData
=
ref
([]);
const
entityListReleaseFreqChartData
=
ref
([]);
const
commerceControlListReleaseFreqChartData
=
ref
([]);
const
aiPaneVisible
=
ref
({
trendChart
:
false
,
radarChart
:
false
,
entityListReleaseFreqChart
:
false
,
commerceControlListReleaseFreqChart
:
false
});
const
overviewAiContent
=
ref
({
trendChart
:
"智能总结生成中..."
,
radarChart
:
"智能总结生成中..."
,
entityListReleaseFreqChart
:
"智能总结生成中..."
,
commerceControlListReleaseFreqChart
:
"智能总结生成中..."
});
const
aiPaneFetched
=
ref
({
trendChart
:
false
,
radarChart
:
false
,
entityListReleaseFreqChart
:
false
,
commerceControlListReleaseFreqChart
:
false
});
const
aiPaneLoading
=
ref
({
trendChart
:
false
,
radarChart
:
false
,
entityListReleaseFreqChart
:
false
,
commerceControlListReleaseFreqChart
:
false
});
const
chartLoading
=
ref
({
trendChart
:
false
,
radarChart
:
false
,
entityListReleaseFreqChart
:
false
,
commerceControlListReleaseFreqChart
:
false
});
const
buildAiChartPayload
=
key
=>
{
if
(
key
===
"trendChart"
)
{
return
{
type
:
"柱状图"
,
name
:
"制裁清单数量增长趋势"
,
data
:
trendChartData
.
value
};
}
if
(
key
===
"radarChart"
)
{
return
{
type
:
"雷达图"
,
name
:
"实体清单领域分布情况"
,
data
:
radarChartData
.
value
};
}
if
(
key
===
"entityListReleaseFreqChart"
)
{
return
{
type
:
"柱状图"
,
name
:
"美国商务部发布实体清单的频次"
,
data
:
entityListReleaseFreqChartData
.
value
};
}
if
(
key
===
"commerceControlListReleaseFreqChart"
)
{
return
{
type
:
"柱状图"
,
name
:
"美国商务部发布商业管制清单的频次"
,
data
:
commerceControlListReleaseFreqChartData
.
value
};
}
return
{
type
:
""
,
name
:
""
,
data
:
[]
};
};
const
handleShowAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
true
};
requestAiPaneContent
(
key
);
};
const
handleHideAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
false
};
};
watch
(
()
=>
[
trendChecked
.
value
,
selectedEntityId
.
value
],
()
=>
{
fetchTrendData
();
}
);
// 新增函数:处理 yearDomainCount 数据并使用 getMultipleBarChart_m 方法生成图表配置
const
processYearDomainCountData
=
yearDomainCountData
=>
{
// 提取所有年份并排序
const
years
=
[...
new
Set
(
yearDomainCountData
.
map
(
item
=>
item
.
year
))].
sort
();
// 提取所有领域名称
const
allDomains
=
[...
new
Set
(
yearDomainCountData
.
flatMap
(
item
=>
item
.
domainCountInfo
.
map
(
domain
=>
domain
.
name
)))];
console
.
log
(
"不同领域的数据 =>"
,
allDomains
);
// 构造 getMultipleBarChart_m 所需的数据结构
const
chartData
=
{
domains
:
allDomains
,
data
:
years
.
map
(
year
=>
{
const
yearData
=
yearDomainCountData
.
find
(
item
=>
item
.
year
===
year
);
const
domainCounts
=
{};
// 初始化所有领域的计数为0
allDomains
.
forEach
(
domain
=>
{
domainCounts
[
domain
]
=
0
;
});
// 填充实际数据
if
(
yearData
&&
yearData
.
domainCountInfo
)
{
yearData
.
domainCountInfo
.
forEach
(
domain
=>
{
domainCounts
[
domain
.
name
]
=
domain
.
count
;
});
}
return
{
year
:
year
,
domainNum
:
domainCounts
};
})
};
console
.
log
(
"不同领域的数据 chartData"
,
chartData
);
// 使用 getMultipleBarChart_m 生成图表配置
return
getMultipleBarChart_m
(
chartData
);
};
const
handleEntityClick
=
item
=>
{
console
.
log
(
"item"
,
item
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
||
item
.
entityNameZh
);
gotoCompanyPages
(
item
.
id
);
};
const
handleWxClick
=
item
=>
{
const
routeData
=
router
.
resolve
({
path
:
"/exportControl/commercialControlList"
,
query
:
{
sanTypeId
:
item
.
sanTypeId
,
key
:
item
.
id
}
});
// 打开一个新页面
window
.
open
(
routeData
.
href
,
"_blank"
);
};
const
carouselRef
=
ref
(
null
);
const
currentCarouselIndex
=
ref
(
0
);
const
handleCarouselChange
=
index
=>
{
currentCarouselIndex
.
value
=
index
;
};
// 跳转到V2.0单次制裁
const
handleToEntityList
=
item
=>
{
console
.
log
(
"这是什么数据1 =>"
,
item
);
let
id
=
item
?.
id
;
let
sanTypeId
=
item
?.
sanTypeId
||
1
;
if
(
!
id
)
{
const
currentItem
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
];
id
=
currentItem
?.
id
;
sanTypeId
=
currentItem
?.
sanTypeId
||
1
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
].
postDate
+
" 《实体清单新增条目》"
);
let
date
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
].
postDate
;
const
routeData
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
query
:
{
id
,
sanTypeId
,
date
}
});
// 打开一个新页面
window
.
open
(
routeData
.
href
,
"_blank"
);
};
// 跳转到V2.0实体清单无ID
const
handleToEntityListNoId
=
item
=>
{
console
.
log
(
"这是什么数据 =>"
,
item
);
if
(
item
.
nameZh
==
"实体清单"
)
{
const
routeData
=
router
.
resolve
({
path
:
"/exportControl/entityList"
,
query
:
{
sanTypeId
:
item
.
id
}
});
// 打开一个新页面
window
.
open
(
routeData
.
href
,
"_blank"
);
}
else
if
(
item
.
nameZh
==
"商业管制清单"
)
{
const
routeData
=
router
.
resolve
({
path
:
"/exportControl/commercialControlList"
,
query
:
{
sanTypeId
:
item
.
id
}
});
// 打开一个新页面
window
.
open
(
routeData
.
href
,
"_blank"
);
}
else
{
return
;
}
};
// const billList = ref([]);
// const curBillListIndex = ref(0);
const
searchExportControlText
=
ref
(
""
);
const
infoListColor
=
ref
([
"rgba(206, 79, 81, 1)"
,
"rgba(114, 46, 209, 1)"
,
"rgba(132, 136, 142, 1)"
,
"rgba(132, 136, 142, 1)"
]);
const
infoList
=
ref
([]);
const
allSanTypeIds
=
ref
([
"1"
,
"13"
]);
// 雷达图
const
domainChecked
=
ref
(
false
);
const
radarOption
=
ref
({
title
:
{
text
:
""
},
tooltip
:
{
// trigger: "item",
confine
:
true
,
trigger
:
"axis"
,
formatter
:
function
(
params
)
{
// params 包含所有系列的数据
if
(
!
params
||
params
.
length
===
0
)
return
""
;
const
radarData
=
params
[
0
];
const
indicator
=
radarData
.
axisValue
;
// 当前角度对应的指标名
const
value
=
radarData
.
value
;
// 只显示当前角度对应的指标
return
`
${
indicator
}
:
${
value
}
`
;
}
},
legend
:
{
show
:
false
,
top
:
"0%"
,
icon
:
"circle"
,
itemWidth
:
12
,
itemHeight
:
12
,
textStyle
:
{
fontSize
:
16
,
fontWeight
:
400
,
fontFamily
:
"Microsoft YaHei"
,
color
:
"rgb(95, 101, 108)"
,
lineHeight
:
24
,
verticalAlign
:
"middle"
,
padding
:
[
2
,
0
,
0
,
0
]
},
data
:
[]
},
grid
:
{
top
:
"5%"
,
bottom
:
"5%"
},
radar
:
{
radius
:
"60%"
,
center
:
[
"50%"
,
"50%"
],
// shape: 'circle',
indicator
:
[],
axisName
:
{
formatter
:
"{value}"
,
color
:
"rgba(59, 65, 75, 1)"
,
fontSize
:
16
,
fontWeight
:
700
}
},
series
:
[
{
name
:
""
,
type
:
"radar"
,
symbol
:
"none"
,
// 隐藏节点圆圈
data
:
[]
}
]
});
// 获取雷达图数据
const
fetchRadarData
=
async
checked
=>
{
try
{
const
data
=
await
getSanDomainCount
(
checked
,
allSanTypeIds
.
value
.
join
(
","
));
if
(
data
&&
Array
.
isArray
(
data
)
&&
data
.
length
>
0
)
{
// 收集所有可能的领域名称
const
allDomains
=
new
Set
();
data
.
forEach
(
item
=>
{
if
(
item
.
domainCountInfo
)
{
item
.
domainCountInfo
.
forEach
(
domain
=>
{
allDomains
.
add
(
domain
.
name
);
});
}
});
const
domainNames
=
Array
.
from
(
allDomains
);
// 为每个制裁类型准备数据
const
radarColors
=
[
"rgba(45, 123, 248, 1)"
,
"rgba(206, 79, 81, 1)"
,
"rgba(255, 197, 61, 1)"
,
"rgba(255, 182, 193, 1)"
,
"rgba(159, 122, 234, 1)"
,
"rgba(90, 200, 220, 1)"
];
const
seriesData
=
data
.
map
((
sanItem
,
index
)
=>
{
// 创建一个映射,将领域名称映射到数量
const
domainMap
=
{};
if
(
sanItem
.
domainCountInfo
)
{
sanItem
.
domainCountInfo
.
forEach
(
domain
=>
{
domainMap
[
domain
.
name
]
=
domain
.
count
;
});
}
// 按照统一的领域顺序创建值数组
const
values
=
domainNames
.
map
(
name
=>
domainMap
[
name
]
||
0
);
// 确定颜色
const
solidColor
=
radarColors
[
index
%
radarColors
.
length
];
const
areaColor
=
solidColor
.
replace
(
"1)"
,
"0.2)"
);
return
{
value
:
values
,
name
:
sanItem
.
sanTypeName
,
itemStyle
:
{
color
:
solidColor
},
areaStyle
:
{
color
:
areaColor
}
};
});
// 更新雷达图指标
let
maxValue
=
Math
.
max
(...
seriesData
.
flatMap
(
item
=>
item
.
value
))
*
1.2
;
// 向上取整到最近的100的倍数,避免小数导致 ticks 不可读警告
maxValue
=
Math
.
ceil
(
maxValue
/
100
)
*
100
;
const
indicators
=
domainNames
.
map
(
name
=>
({
name
:
name
,
max
:
maxValue
||
100
// 防止max为0的情况
}));
// 更新雷达图配置
radarOption
.
value
.
radar
.
indicator
=
indicators
;
radarOption
.
value
.
series
[
0
].
data
=
seriesData
;
radarOption
.
value
.
legend
.
data
=
seriesData
.
map
(
item
=>
{
return
{
name
:
item
.
name
,
itemStyle
:
{
color
:
item
.
itemStyle
.
color
}
};
});
radarChartData
.
value
=
data
;
// radarChart.interpret({ type: "雷达图", name: "实体清单领域分布情况", data: data });
}
}
catch
(
error
)
{
console
.
error
(
"获取雷达图数据失败:"
,
error
);
}
};
watch
(
()
=>
domainChecked
.
value
,
()
=>
fetchRadarData
(
domainChecked
.
value
)
);
// 进度条状态
const
getStatus
=
_percent
=>
{
const
percent
=
_percent
*
100
;
if
(
percent
>=
90
)
{
return
"exception"
;
}
else
if
(
percent
>=
50
)
{
return
"warning"
;
}
else
{
return
"success"
;
}
};
// 制裁实体
const
currentPage
=
ref
(
1
);
// 默认显示第5页
const
pageSize
=
ref
(
10
);
const
total
=
ref
(
0
);
// 全部制裁分页
const
currentPageAll
=
ref
(
1
);
const
pageSizeAll
=
ref
(
10
);
const
totalAll
=
ref
(
0
);
const
fetchSanctionList
=
async
()
=>
{
try
{
const
techDomains
=
checkedTech
.
value
.
includes
(
0
)
?
null
:
checkedTech
.
value
.
map
(
String
);
let
years
=
null
;
if
(
!
checkedTime
.
value
.
includes
(
"全部时间"
))
{
years
=
checkedTime
.
value
.
map
(
t
=>
{
const
match
=
t
.
match
(
/
(\d{4})
/
);
return
match
?
parseInt
(
match
[
1
])
:
null
;
})
.
filter
(
y
=>
y
!==
null
);
if
(
years
.
length
===
0
)
years
=
null
;
const
customTime
=
timeOptions
.
value
.
find
(
item
=>
item
.
value
===
"custom"
);
if
(
customTime
&&
customTime
.
checked
&&
customDateRange
.
value
&&
customDateRange
.
value
.
length
===
2
)
{
const
start
=
new
Date
(
customDateRange
.
value
[
0
]);
const
end
=
new
Date
(
customDateRange
.
value
[
1
]);
startDate
=
`
${
start
.
getFullYear
()}
-
${
String
(
start
.
getMonth
()
+
1
).
padStart
(
2
,
"0"
)}
-
${
String
(
start
.
getDate
()
).
padStart
(
2
,
"0"
)}
`
;
endDate
=
`
${
end
.
getFullYear
()}
-
${
String
(
end
.
getMonth
()
+
1
).
padStart
(
2
,
"0"
)}
-
${
String
(
end
.
getDate
()).
padStart
(
2
,
"0"
)}
`
;
}
}
const
params
=
{
pageNum
:
currentPageAll
.
value
,
pageSize
:
pageSizeAll
.
value
,
techDomainIds
:
techDomains
,
years
:
years
,
isCn
:
false
,
// typeName: "实体清单"
sanTypeIds
:
allSanTypeIds
.
value
};
const
res
=
await
getExportControlList
(
params
);
if
(
res
&&
res
.
content
)
{
sanctionList
.
value
=
res
.
content
.
map
(
item
=>
{
const
tags
=
Array
.
isArray
(
item
.
techDomains
)
?
item
.
techDomains
:
item
.
techDomain
?
[
item
.
techDomain
]
:
item
.
techDomainList
||
[];
const
fullTime
=
item
.
startTime
?
formatAnyDateToChinese
(
item
.
startTime
)
:
item
.
postDate
||
item
.
publishDate
||
item
.
date
;
let
year
=
""
;
let
dateStr
=
fullTime
;
if
(
typeof
fullTime
===
"string"
)
{
if
(
fullTime
.
includes
(
"年"
))
{
const
parts
=
fullTime
.
split
(
"年"
);
year
=
parts
[
0
];
dateStr
=
parts
[
1
].
replace
(
/
\s
+/g
,
""
);
}
else
if
(
fullTime
.
includes
(
"-"
))
{
const
parts
=
fullTime
.
split
(
"-"
);
year
=
parts
[
0
];
dateStr
=
parts
.
slice
(
1
).
join
(
"-"
);
}
}
return
{
...
item
,
time
:
fullTime
,
year
,
dateStr
,
title
:
item
.
entityNameZh
||
item
.
entityName
||
item
.
title
||
item
.
name
,
desc
:
item
.
sanReason
||
item
.
description
||
item
.
summary
||
item
.
content
,
tags
:
tags
,
countTag
:
item
.
cnEntityCount
?
`
${
item
.
cnEntityCount
}
家中国实体`
:
item
.
ruleOrgCount
?
`
${
item
.
ruleOrgCount
}
家关联实体`
:
item
.
countTag
||
""
};
});
totalAll
.
value
=
res
.
totalElements
;
}
}
catch
(
error
)
{}
};
const
handlePageChangeAll
=
val
=>
{
currentPageAll
.
value
=
val
;
fetchSanctionList
();
handleToPosi
(
"position4"
);
};
watch
(
checkedTech
,
(
newVal
,
oldVal
)
=>
{
let
isModified
=
false
;
if
(
newVal
.
includes
(
0
))
{
if
(
!
oldVal
.
includes
(
0
))
{
checkedTech
.
value
=
[
0
];
isModified
=
true
;
}
else
if
(
newVal
.
length
>
1
)
{
checkedTech
.
value
=
newVal
.
filter
(
v
=>
v
!==
0
);
isModified
=
true
;
}
}
else
if
(
newVal
.
length
===
0
)
{
checkedTech
.
value
=
[
0
];
isModified
=
true
;
}
if
(
isModified
)
return
;
currentPageAll
.
value
=
1
;
fetchSanctionList
();
},
{
deep
:
true
}
);
watch
(
checkedTime
,
(
newVal
,
oldVal
)
=>
{
let
isModified
=
false
;
if
(
newVal
.
includes
(
"全部时间"
))
{
if
(
!
oldVal
.
includes
(
"全部时间"
))
{
checkedTime
.
value
=
[
"全部时间"
];
isModified
=
true
;
}
else
if
(
newVal
.
length
>
1
)
{
checkedTime
.
value
=
newVal
.
filter
(
v
=>
v
!==
"全部时间"
);
isModified
=
true
;
}
}
else
if
(
newVal
.
length
===
0
)
{
checkedTime
.
value
=
[
"全部时间"
];
isModified
=
true
;
}
if
(
isModified
)
return
;
currentPageAll
.
value
=
1
;
fetchSanctionList
();
},
{
deep
:
true
}
);
// 获取实体清单数据
const
fetchEntitiesList
=
async
(
page
=
1
,
size
=
10
)
=>
{
try
{
console
.
log
(
"activeResourceTabItem.value.id"
,
activeResourceTabItem
.
value
.
id
);
if
(
!
activeResourceTabItem
.
value
.
id
)
return
;
const
res
=
await
getEntitiesList
(
activeResourceTabItem
.
value
.
id
,
page
,
size
);
if
(
res
)
{
entitiesList
.
value
=
res
.
content
.
map
(
item
=>
({
...
item
,
name
:
item
.
entityNameZh
||
item
.
entityName
,
enName
:
item
.
entityName
,
domains
:
item
.
techDomains
,
sanctionDate
:
item
.
startTime
}));
total
.
value
=
res
.
totalElements
;
currentPage
.
value
=
res
.
number
+
1
;
// API返回的页码从0开始,前端从1开始
}
}
catch
(
err
)
{
console
.
error
(
err
);
}
};
const
handleGetMore
=
async
()
=>
{
sanctionPage
.
value
++
;
try
{
const
sanTypeid
=
activeResourceTabItem
.
value
.
id
?
[
activeResourceTabItem
.
value
.
id
]
:
allSanTypeIds
.
value
;
const
res
=
await
getSanctionProcess
(
sanTypeid
,
sanctionPage
.
value
,
10
);
if
(
res
&&
res
.
content
)
{
// 将新数据合并到现有列表中
const
newData
=
res
.
content
.
map
(
item
=>
({
...
item
,
title
:
item
.
name
,
desc
:
`
${
item
.
cnEntityCount
}
家中国实体`
,
content
:
item
.
summary
||
"2025年3月25日,美国商务部工业与安全局以从事有悖于美国国家安全和外交政策利益的活动为由,宣布将来自中国的54家实体新增至“实体清单”。"
}));
// 合并新数据到现有列表
sanctionProcessList
.
value
=
[...
sanctionProcessList
.
value
,
...
newData
];
}
}
catch
(
err
)
{
console
.
error
(
err
);
// 如果请求失败,回退页码
sanctionPage
.
value
--
;
}
};
// 获取历次制裁过程数据
const
fetchSanctionProcess
=
async
(
page
=
1
,
size
=
10
)
=>
{
try
{
const
res
=
await
getSanctionProcess
(
activeResourceTabItem
.
value
.
id
?
[
activeResourceTabItem
.
value
.
id
]
:
allSanTypeIds
.
value
,
page
,
size
);
if
(
res
)
{
// 暂无商业管制清单数据
sanctionProcessList
.
value
=
res
.
content
.
map
(
item
=>
({
...
item
,
title
:
item
.
name
,
desc
:
`
${
item
.
cnEntityCount
}
家中国实体`
,
content
:
item
.
summary
||
"2025年3月25日,美国商务部工业与安全局以从事有悖于美国国家安全和外交政策利益的活动为由,宣布将来自中国的54家实体新增至“实体清单”。"
}));
}
}
catch
(
err
)
{
console
.
error
(
err
);
}
};
// 分页改变时的处理函数
const
handlePageChange
=
page
=>
{
currentPage
.
value
=
page
;
fetchEntitiesList
(
page
,
pageSize
.
value
);
};
const
searchKeyword
=
ref
(
""
);
// 资源库 Tab 数据
const
resourceTabs
=
ref
([
// { label: "全部制裁", value: "all", disabled: false },
// { label: "实体清单", value: "entity", disabled: false },
// { label: "商业管制清单", value: "commerce", disabled: true }
// { label: "关键与新兴技术清单", value: "tech", disabled: true },
// { label: "军事最终用户清单", value: "military", disabled: true }
]);
const
activeResourceTab
=
ref
(
"all"
);
const
activeResourceTabItem
=
ref
({});
// 数据对应,便宜行事
const
tabMap
=
{
1
:
"entity"
,
13
:
"commerce"
};
const
handleResourceTabClick
=
tab
=>
{
// if (tab.disabled) return;
console
.
log
(
"选项点击"
,
tab
);
activeResourceTab
.
value
=
tab
.
value
;
activeResourceTabItem
.
value
=
tab
;
fetchSanctionProcess
();
console
.
log
(
"tabMap[tab.id]"
,
tabMap
[
tab
.
id
]);
if
(
tab
.
value
===
"entity"
)
{
fetchEntitiesList
();
}
};
const
strengthLabels
=
{
strong
:
"强"
,
medium
:
"中"
,
weak
:
"弱"
,
none
:
"无"
};
// 获取风险信号数据
const
fetchRiskSignals
=
async
()
=>
{
try
{
const
data
=
await
getRiskSignal
();
if
(
data
&&
Array
.
isArray
(
data
))
{
console
.
log
(
data
);
warningList
.
value
=
data
.
map
(
item
=>
({
...
item
,
title
:
item
.
signalTitle
,
time
:
item
.
signalTime
,
status
:
item
.
signalLevel
,
id
:
item
.
signalId
,
sanId
:
item
.
sanId
}));
}
}
catch
(
err
)
{
console
.
error
(
"获取风险信号数据失败:"
,
err
);
}
};
// 添加获取社交媒体信息的方法
const
fetchSocialMediaInfo
=
async
()
=>
{
try
{
const
data
=
await
getSocialMediaInfo
();
if
(
data
&&
Array
.
isArray
(
data
))
{
// console.log(data);
socialMediaList
.
value
=
data
.
map
(
item
=>
({
...
item
,
avatar
:
item
.
personImage
,
name
:
item
.
personName
,
time
:
formatTime
(
item
.
time
),
source
:
item
.
orgName
,
content
:
item
.
remarks
,
personId
:
item
.
personId
}));
}
}
catch
(
err
)
{
console
.
error
(
"获取社交媒体信息失败:"
,
err
);
}
};
// 添加获取新闻资讯的方法
const
fetchNewsInfo
=
async
()
=>
{
try
{
const
data
=
await
getNewsInfo
();
if
(
data
&&
Array
.
isArray
(
data
))
{
newsList
.
value
=
data
.
map
(
item
=>
({
...
item
,
img
:
item
.
newsImage
,
title
:
item
.
newsTitle
,
content
:
item
.
newsContent
,
from
:
item
.
newsDate
+
(
item
.
newsOrg
?
" · "
+
item
.
newsOrg
:
""
)
}));
}
}
catch
(
err
)
{
console
.
error
(
"获取新闻资讯失败:"
,
err
);
}
};
const
handlePerClick
=
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
)],
personId
:
item
.
personId
}
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 处理点击社交媒体消息的方法
// const handleInfoClick = item => {
// console.log("点击了社交媒体消息的更多信息:", item);
// // 这里可以添加打开详情页的逻辑
// ElMessageBox.alert(`${item.content}`, "信息详情", {
// confirmButtonText: "确定",
// callback: action => {
// ElMessage({
// type: "info",
// message: `action: ${action}`
// });
// }
// });
// };
// 添加格式化时间的方法
const
formatTime
=
timeStr
=>
{
// 空值兜底,避免报错
if
(
!
timeStr
)
return
"暂无时间"
;
// 核心:替换T为空格
return
timeStr
.
replace
(
"T"
,
" "
);
};
const
warningList
=
ref
([]);
const
curBillList
=
ref
([]);
const
releaseTime
=
ref
(
"近一年发布"
);
const
categoryList
=
ref
([]);
const
activeCate
=
ref
(
"全部分类"
);
const
activeHylyId
=
ref
(
""
);
// 获取领域分类
const
handleGetHylyList
=
async
()
=>
{
try
{
const
res
=
await
getHylyList
();
console
.
log
(
"行业领域列表"
);
categoryList
.
value
=
res
.
data
;
const
obj
=
{
id
:
0
,
hylyid
:
""
,
hylymc
:
"全部分类"
};
categoryList
.
value
=
[
obj
,
...
categoryList
.
value
];
}
catch
(
error
)
{}
};
const
chart1Data
=
ref
({
title
:
[
"2024-09"
,
"2024-10"
,
"2024-11"
,
"2024-12"
,
"2025-01"
,
"2025-02"
,
"2025-03"
,
"2025-04"
,
"2025-05"
,
"2025-06"
,
"2025-07"
,
"2025-08"
],
data
:
[
{
name
:
"提出法案"
,
value
:
[
145
,
52
,
84
,
99
,
71
,
96
,
128
,
144
,
140
,
168
,
188
,
172
]
},
{
name
:
"通过法案"
,
value
:
[
6
,
3
,
4
,
6
,
11
,
5
,
2
,
14
,
16
,
27
,
28
,
44
]
}
]
});
const
handleSanc
=
item
=>
{
console
.
log
(
"activeResourceTabItem.value.id"
,
activeResourceTabItem
.
value
.
id
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
`
${
item
.
postDate
}
《
${
item
.
title
}
》`
);
const
route
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
query
:
{
id
:
item
.
id
,
sanTypeId
:
activeResourceTabItem
.
value
.
id
,
date
:
item
.
postDate
}
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
navigateToViewRiskSignal
(
router
);
};
// 查看更多新闻资讯
const
handleToMoreNews
=
()
=>
{
const
route
=
router
.
resolve
(
"/newsBrief"
);
window
.
open
(
route
.
href
,
"_blank"
);
// router.push("/newsBrief")
};
const
handleNewsInfoClick
=
item
=>
{
console
.
log
(
"点击了社交媒体消息的更多信息:"
,
item
);
// 应该跳转至哪儿???
// const route = router.resolve({
// path: "/newsAnalysis",
// query: {
// newsId: item.newsId
// }
// });
// window.open(route.href, "_blank");
gotoNewsDetail
(
item
.
newsId
);
};
// 切换当前出口管制政策
const
handleSwithCurPolicy
=
name
=>
{
if
(
name
===
"left"
)
{
carouselRef
.
value
.
prev
();
}
else
{
carouselRef
.
value
.
next
();
}
};
const
handleSearch
=
()
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
`搜索-
${
searchExportControlText
.
value
}
`
);
const
curRoute
=
router
.
resolve
({
path
:
"/searchResults"
,
query
:
{
searchText
:
searchExportControlText
.
value
,
areaName
:
"实体清单"
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
// 点击实体清单发布频次统计
const
handleEntityRowClick
=
row
=>
{
console
.
log
(
"row"
,
row
);
const
params
=
{
// domains: row.tags[0],
selectedDate
:
JSON
.
stringify
([
row
.
year
+
"-01-01"
,
row
.
year
+
"-12-31"
])
};
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/dataEntityListEvent"
,
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 点击商业管制清单发布频次统计
const
handleCommercialRowClick
=
row
=>
{
console
.
log
(
"row"
,
row
);
const
params
=
{
// domains: row.tags[0],
selectedDate
:
JSON
.
stringify
([
row
.
year
+
"-01-01"
,
row
.
year
+
"-12-31"
])
};
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/dataCommerceControlListEvent"
,
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 点击实体清单领域分布情况
const
handleRadarChartClick
=
value
=>
{
// console.log('value', value);
// alert(domainChecked.value)
const
params
=
{
isHalfRule
:
domainChecked
.
value
};
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/dataEntityList"
,
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 点击制裁清单数量增长趋势
const
handleMultiBarChartClick
=
val
=>
{
const
params
=
{
isHalfRule
:
trendChecked
.
value
,
domains
:
val
.
seriesName
,
isCnEntityOnly
:
true
,
selectedDate
:
JSON
.
stringify
([
val
.
name
+
"-01-01"
,
val
.
name
+
"-12-31"
])
};
const
route
=
router
.
resolve
({
path
:
selectedEntityId
.
value
===
1
?
"/dataLibrary/dataEntityList"
:
"/dataLibrary/dataCommerceControlList"
,
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 跳转到数据资源库
const
handleToDataLibrary
=
item
=>
{
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/dataEntityList"
,
query
:
{
isCnEntityOnly
:
true
,
selectedDate
:
JSON
.
stringify
([
item
.
postDate
,
item
.
postDate
])
}
});
window
.
open
(
route
.
href
,
"_blank"
);
};
onMounted
(
async
()
=>
{
handleGetHylyList
();
let
chart1
=
getMultiLineChart
(
chart1Data
.
value
.
title
,
chart1Data
.
value
.
data
[
0
].
value
,
chart1Data
.
value
.
data
[
1
].
value
);
setChart
(
chart1
,
"chart1"
);
});
const
dialogVisible
=
ref
(
false
);
const
currentOrgList
=
ref
([]);
const
handleClose
=
()
=>
{
dialogVisible
.
value
=
false
;
};
const
handleOrgClick
=
item
=>
{
// console.log(item, item.name);
currentRuleCompany
.
value
=
item
.
name
;
currentRuleCount
.
value
=
item
.
ruleOrgCount
;
currentOrgList
.
value
=
item
.
ruleOrgList
;
dialogVisible
.
value
=
true
;
};
const
mediaVisible
=
ref
(
false
);
const
currentMedia
=
ref
(
""
);
const
handleMediaClose
=
()
=>
{
mediaVisible
.
value
=
false
;
};
const
handleMediaClick
=
item
=>
{
// console.log(item, item.name);
currentMedia
.
value
=
item
.
content
;
mediaVisible
.
value
=
true
;
};
</
script
>
<
style
lang=
"scss"
scoped
>
.list-page
{
padding-top
:
0
;
}
.home-header
{
height
:
64px
;
background
:
url("@/assets/images/nav-bg.png")
;
box-sizing
:
border-box
;
padding-left
:
160px
;
display
:
flex
;
justify-content
:
space-between
;
padding
:
0
160px
;
}
.box1
{
display
:
flex
;
flex-direction
:
column
;
gap
:
20px
;
position
:
relative
;
width
:
1036px
;
.box1-left-arrow
{
position
:
absolute
;
z-index
:
9999
;
left
:
-24px
;
top
:
135px
;
width
:
24px
!
important
;
height
:
48px
;
background
:
#e7f1ff
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
cursor
:
pointer
;
.icon
{
width
:
11px
;
height
:
18px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
.box1-right-arrow
{
position
:
absolute
;
z-index
:
9999
;
right
:
0px
;
top
:
135px
;
width
:
24px
;
height
:
48px
;
background
:
#e7f1ff
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
cursor
:
pointer
;
.icon
{
width
:
11px
;
height
:
18px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
.box1-absolute
{
position
:
absolute
;
width
:
240px
;
height
:
89px
;
top
:
12px
;
right
:
-24px
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-end
;
justify-content
:
center
;
padding-right
:
50px
;
box-sizing
:
border-box
;
background
:
linear-gradient
(
to
right
,
rgba
(
206
,
79
,
81
,
0
)
,
rgba
(
206
,
79
,
81
,
0
.3
));
cursor
:
pointer
;
&
-des
{
display
:
flex
;
gap
:
5px
;
align-items
:
center
;
font-size
:
18px
;
font-weight
:
700
;
color
:
rgba
(
206
,
79
,
81
,
1
);
}
&
-num
{
font-size
:
32px
;
font-weight
:
700
;
color
:
rgba
(
206
,
79
,
81
,
1
);
}
}
.box1-top
{
// display: flex;
// flex-direction: column;
// gap: 10px;
padding-left
:
30px
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
&
-title
{
font-size
:
20px
;
font-weight
:
700
;
color
:
$base-color
;
margin-top
:
10px
;
margin-bottom
:
15px
;
max-width
:
80%
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
&
-content
{
display
:
flex
;
flex-direction
:
column
;
gap
:
10px
;
margin-bottom
:
20px
;
&
-item
{
display
:
flex
;
gap
:
5px
;
&
-title
{
font-size
:
16px
;
font-weight
:
700
;
color
:
rgba
(
59
,
65
,
75
,
1
);
}
}
}
}
.box1-bottom
{
padding-left
:
30px
;
height
:
172px
;
padding-top
:
16px
;
box-sizing
:
border-box
;
padding-right
:
24px
;
&
-title
{
font-size
:
16px
;
font-weight
:
700
;
color
:
rgba
(
59
,
65
,
75
,
1
);
margin-bottom
:
15px
;
}
&
-content__wx
{
display
:
flex
;
flex-direction
:
column
;
gap
:
10px
;
justify-content
:
flex-start
;
padding-left
:
10px
;
height
:
156px
;
overflow
:
auto
;
&
-item
{
display
:
flex
;
align-items
:
center
;
justify-content
:
flex-start
;
gap
:
10px
;
cursor
:
pointer
;
&
-id
{
font-family
:
"Source Han Sans CN"
;
font-size
:
16px
;
font-weight
:
700
;
color
:
rgb
(
95
,
101
,
108
);
}
&
-txt
{
font-size
:
16px
;
font-weight
:
400
;
color
:
rgba
(
95
,
101
,
108
,
1
);
line-height
:
24px
;
}
}
}
&
-content
{
display
:
flex
;
gap
:
15px
;
flex-wrap
:
wrap
;
justify-content
:
space-between
;
padding-left
:
10px
;
height
:
156px
;
overflow
:
auto
;
&
-item
{
display
:
flex
;
align-items
:
center
;
justify-content
:
flex-start
;
width
:
48%
;
/* 留出2%的间距 */
// margin-bottom: 6px;
box-sizing
:
border-box
;
gap
:
10px
;
cursor
:
pointer
;
&
-img
{
width
:
24px
;
height
:
24px
;
flex-shrink
:
0
;
}
&
-imgUndefined
{
width
:
24px
;
height
:
24px
;
font-size
:
14px
;
font-weight
:
700
;
flex-shrink
:
0
;
color
:
rgba
(
5
,
95
,
194
,
1
);
background-color
:
rgb
(
236
,
245
,
255
);
line-height
:
24px
;
text-align
:
center
;
border-radius
:
12px
;
}
&
-txt
{
font-size
:
16px
;
font-weight
:
400
;
color
:
rgba
(
95
,
101
,
108
,
1
);
}
}
}
}
.box1-right
{
display
:
flex
;
flex-direction
:
column
;
gap
:
10px
;
.box1-right-title
{
font-size
:
20px
;
font-weight
:
700
;
color
:
$base-color
;
}
.box1-right-tags
{
display
:
flex
;
gap
:
10px
;
}
.box1-right-content
{
color
:
rgba
(
59
,
65
,
75
,
1
);
font-size
:
16px
;
font-weight
:
400
;
line-height
:
28px
;
}
.box1-right-footer
{
margin-top
:
auto
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
.box1-right-footer-time
{
color
:
rgba
(
95
,
101
,
108
,
1
);
font-size
:
14px
;
font-weight
:
400
;
}
}
}
}
.box2-main
{
height
:
320px
;
overflow-y
:
auto
;
.box2-main-item
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
gap
:
8px
;
box-sizing
:
border-box
;
padding-right
:
3px
;
cursor
:
pointer
;
&
:hover
{
background
:
var
(
--
color-bg-hover
);
}
.itemLeftStatus1
{
color
:
rgba
(
82
,
196
,
26
,
1
)
!
important
;
background
:
rgba
(
246
,
255
,
237
,
1
)
!
important
;
}
.itemLeftStatus2
{
color
:
rgba
(
250
,
140
,
22
,
1
)
!
important
;
background
:
rgba
(
255
,
247
,
230
,
1
)
!
important
;
}
.item-left
{
display
:
flex
;
align-items
:
center
;
width
:
40px
;
height
:
40px
;
padding
:
5px
;
border-radius
:
100%
;
background
:
rgba
(
255
,
241
,
240
);
color
:
rgba
(
245
,
34
,
45
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
12px
;
font-weight
:
400
;
line-height
:
14px
;
box-sizing
:
border-box
;
text-align
:
center
;
flex-shrink
:
0
;
}
.item-right
{
margin-left
:
13px
;
width
:
100%
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
gap
:
8px
;
height
:
47px
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
.text
{
font-family
:
Microsoft
YaHei
;
line-height
:
47px
;
width
:
260px
;
font-size
:
16px
;
font-weight
:
400
;
color
:
rgba
(
59
,
65
,
75
,
1
);
overflow
:
hidden
;
white-space
:
nowrap
;
text-overflow
:
ellipsis
;
}
.time
{
margin-left
:
10px
;
line-height
:
47px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
}
}
}
}
.box2-footer
{
position
:
absolute
;
left
:
0
;
right
:
0
;
bottom
:
20px
;
width
:
461px
;
height
:
42px
;
display
:
flex
;
flex-direction
:
row
;
justify-content
:
center
;
align-items
:
center
;
border-radius
:
6px
;
background
:
var
(
--
color-main-active
);
margin
:
0
auto
;
cursor
:
pointer
;
.icon
{
width
:
16px
;
height
:
16px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.text
{
margin-left
:
8px
;
color
:
rgba
(
255
,
255
,
255
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
22px
;
}
}
.box3
{
display
:
flex
;
justify-content
:
center
;
// align-items: flex-start;
gap
:
100px
;
flex
:
1
;
.box3-content
{
display
:
flex
;
flex-direction
:
column
;
// gap: 20px;
flex
:
1
;
position
:
relative
;
}
.box3-content-title
{
font-size
:
18px
;
font-weight
:
700
;
font-family
:
Microsoft
YaHei
;
// width: 640px;
width
:
100%
;
height
:
36px
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
background-color
:
rgba
(
247
,
248
,
249
,
1
);
color
:
$base-color
;
margin-bottom
:
15px
;
}
.box3-content
{
// flex: 1;
.el-progress--line
{
width
:
82px
;
}
}
}
.box4
{
height
:
786px
;
overflow
:
auto
;
display
:
flex
;
flex-direction
:
column
;
// justify-content: space-between;
padding-top
:
16px
;
// padding-bottom: 50px;
position
:
relative
;
.box4-item
{
display
:
flex
;
gap
:
10px
;
align-items
:
flex-start
;
padding-bottom
:
35px
;
position
:
relative
;
.box4-item-left
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
.box4-item-left-icon
{
width
:
10px
;
height
:
10px
;
}
.box4-item-left-line
{
width
:
1px
;
height
:
100%
;
position
:
absolute
;
border-left
:
1px
solid
rgba
(
10
,
87
,
166
,
0
.3
);
}
}
.box4-item-right
{
display
:
flex
;
flex-direction
:
column
;
.box4-item-right-header
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
position
:
relative
;
top
:
-7
.5px
;
padding-bottom
:
8px
;
cursor
:
pointer
;
&
-title
{
font-size
:
18px
;
color
:
$base-color
;
font-weight
:
700
;
}
&
-desc
{
font-size
:
16px
;
font-weight
:
700
;
color
:
rgba
(
59
,
65
,
75
,
1
);
}
}
.box4-item-right-content
{
font-size
:
16px
;
font-weight
:
400
;
color
:
rgba
(
95
,
101
,
108
,
1
);
overflow
:
hidden
;
display
:
-
webkit-box
;
-webkit-line-clamp
:
3
;
-webkit-box-orient
:
vertical
;
text-overflow
:
ellipsis
;
line-height
:
25px
;
}
}
}
.box4-footer
{
position
:
absolute
;
// margin-top: auto;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
bottom
:
30px
;
left
:
50%
;
margin-left
:
-30px
;
// margin-bottom: 30px;
}
}
.box5
{
height
:
115%
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
space-between
;
align-items
:
center
;
}
:deep
(
.table-header
)
{
font-size
:
16px
;
font-weight
:
700
;
color
:
rgba
(
59
,
65
,
75
,
1
);
}
:deep
(
.table-row
)
{
height
:
64px
;
}
.domain-tags
{
display
:
flex
;
gap
:
8px
;
}
.box5-header-right
{
font-size
:
16px
;
font-weight
:
700
;
color
:
$base-color
;
}
.table-footer
{
margin-top
:
20px
;
}
.home-wrapper
{
width
:
100%
;
height
:
100%
;
position
:
relative
;
overflow-y
:
hidden
;
.home-main
{
position
:
relative
;
width
:
100%
;
height
:
100%
;
overflow-y
:
auto
;
.home-top-bg
{
background
:
url("./assets/images/background.png")
,
linear-gradient
(
180deg
,
rgba
(
229
,
241
,
254
,
1
)
0%
,
rgba
(
246
,
251
,
255
,
0
)
30%
);
background-size
:
100%
100%
;
position
:
absolute
;
width
:
100%
;
height
:
100%
;
z-index
:
-100
;
top
:
-64px
;
}
.home-main-header
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
.home-main-header-center
{
margin-top
:
51px
;
width
:
960px
;
height
:
48px
;
border-radius
:
10px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
box-sizing
:
border-box
;
padding
:
1px
;
position
:
relative
;
border
:
1px
solid
transparent
;
&
:hover
{
border
:
1px
solid
var
(
--
color-main-active
);
}
.search
{
position
:
absolute
;
right
:
-1px
;
top
:
0px
;
width
:
120px
;
height
:
46px
;
border-radius
:
10px
;
background
:
var
(
--
color-main-active
);
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
cursor
:
pointer
;
.search-icon
{
width
:
18px
;
height
:
18px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.search-text
{
margin-left
:
8px
;
height
:
22px
;
color
:
#fff
;
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
22px
;
}
}
}
.home-main-header-footer
{
margin-top
:
64px
;
width
:
700px
;
height
:
64px
;
box-sizing
:
border-box
;
padding
:
0
108px
;
display
:
flex
;
justify-content
:
space-between
;
.home-main-header-footer-item
{
padding
:
0
10px
;
text-align
:
center
;
.item-top
{
height
:
22px
;
color
:
rgba
(
20
,
89
,
187
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
36px
;
font-weight
:
700
;
line-height
:
22px
;
}
.item-footer
{
margin-top
:
10px
;
height
:
30px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
30px
;
}
}
}
.home-main-header-footer-link
,
.home-main-header-footer-info
{
// width: 100%;
max-width
:
1600px
;
display
:
flex
;
justify-content
:
center
;
gap
:
16px
;
// padding: 30px 0;
}
.home-main-header-footer-info
{
margin-top
:
36px
;
}
.home-main-header-btn-box
{
width
:
688px
;
margin
:
0
auto
;
margin-top
:
39px
;
display
:
flex
;
justify-content
:
space-between
;
.btn
{
display
:
flex
;
align-items
:
center
;
gap
:
9px
;
width
:
160px
;
height
:
48px
;
border
:
1px
solid
#aed6ff
;
box-sizing
:
border-box
;
border-radius
:
24px
;
background
:
#e7f3ff
;
cursor
:
pointer
;
position
:
relative
;
&
:hover
{
background
:
#cae3fc
;
}
.btn-text
{
width
:
80px
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
400
;
line-height
:
48px
;
margin-left
:
36px
;
text-align
:
center
;
}
.btn-icon
{
position
:
absolute
;
top
:
16px
;
right
:
19px
;
width
:
6px
;
height
:
12px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
}
}
.home-main-center
{
margin-top
:
64px
;
.center-top
{
height
:
450px
;
display
:
flex
;
gap
:
20px
;
.box1
{
display
:
flex
;
gap
:
10px
;
position
:
relative
;
.box1-header
{
height
:
53px
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
display
:
flex
;
justify-content
:
space-between
;
.box1-header-left
{
display
:
flex
;
.icon
{
width
:
18px
;
height
:
18px
;
margin-top
:
19px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.title
{
height
:
22px
;
margin-left
:
18px
;
margin-top
:
16px
;
color
:
rgba
(
20
,
89
,
187
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
22px
;
}
}
.box1-header-right
{
margin-top
:
19px
;
height
:
16px
;
color
:
rgba
(
20
,
89
,
187
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
16px
;
cursor
:
pointer
;
}
}
.box1-main
{
display
:
flex
;
height
:
354px
;
margin-top
:
22px
;
.box1-main-top
{
height
:
68px
;
display
:
flex
;
justify-content
:
space-between
;
.box1-main-top-left
{
color
:
rgba
(
20
,
89
,
187
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
left
;
}
.box1-main-top-right
{
margin-left
:
20px
;
display
:
flex
;
.num
{
padding
:
1px
8px
;
height
:
24px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
145
,
202
,
255
,
1
);
border-radius
:
4px
;
background
:
rgba
(
230
,
244
,
255
,
1
);
}
.tag
{
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
135
,
232
,
222
,
1
);
border-radius
:
4px
;
background
:
rgba
(
230
,
255
,
251
,
1
);
}
}
}
}
}
.box2
{
flex
:
1
;
padding-right
:
20px
;
height
:
450px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
position
:
relative
;
.box2-header
{
height
:
54px
;
display
:
flex
;
.icon
{
width
:
24px
;
height
:
22px
;
margin-left
:
33px
;
margin-top
:
18px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.text
{
margin-left
:
22px
;
margin-top
:
16px
;
height
:
22px
;
color
:
rgba
(
20
,
89
,
187
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
22px
;
}
.num
{
width
:
24px
;
height
:
16px
;
text-align
:
center
;
color
:
rgba
(
255
,
255
,
255
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
12px
;
margin-left
:
6px
;
margin-top
:
17px
;
border
:
1px
solid
rgba
(
255
,
255
,
255
,
1
);
border-radius
:
100px
;
background
:
rgba
(
255
,
77
,
79
,
1
);
}
.more
{
margin-top
:
19px
;
margin-left
:
256px
;
color
:
rgba
(
20
,
89
,
187
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
16px
;
}
}
.box2-main
{
height
:
282px
;
overflow-y
:
auto
;
.box2-main-item
{
margin-left
:
23px
;
height
:
47px
;
width
:
464px
;
display
:
flex
;
.itemLeftStatus1
{
color
:
rgba
(
82
,
196
,
26
,
1
)
!
important
;
background
:
rgba
(
246
,
255
,
237
,
1
)
!
important
;
}
.itemLeftStatus2
{
color
:
rgba
(
250
,
140
,
22
,
1
)
!
important
;
background
:
rgba
(
255
,
247
,
230
,
1
)
!
important
;
}
.item-left
{
margin-top
:
4px
;
margin-left
:
2px
;
width
:
40px
;
height
:
40px
;
border-radius
:
20px
;
background
:
rgba
(
255
,
241
,
240
);
color
:
rgba
(
245
,
34
,
45
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
12px
;
font-weight
:
400
;
line-height
:
14px
;
box-sizing
:
border-box
;
padding
:
6px
4px
;
text-align
:
center
;
}
.item-right
{
margin-left
:
13px
;
width
:
408px
;
height
:
47px
;
border-top
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
display
:
flex
;
.text
{
width
:
348px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
47px
;
}
.time
{
margin-left
:
10px
;
line-height
:
47px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
}
}
}
}
.box2-footer
{
position
:
absolute
;
left
:
26px
;
bottom
:
20px
;
width
:
430px
;
height
:
42px
;
display
:
flex
;
flex-direction
:
row
;
justify-content
:
center
;
align-items
:
center
;
border-radius
:
6px
;
background
:
rgba
(
22
,
119
,
255
,
1
);
cursor
:
pointer
;
.icon
{
width
:
16px
;
height
:
16px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.text
{
margin-left
:
8px
;
color
:
rgba
(
255
,
255
,
255
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
22px
;
}
}
}
}
.center-footer
{
margin-top
:
21px
;
height
:
450px
;
display
:
flex
;
.box3
{
width
:
900px
;
height
:
450px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
.box3-header
{
height
:
53px
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
margin
:
0
auto
;
display
:
flex
;
justify-content
:
space-between
;
padding
:
0
20px
;
.box3-header-left
{
display
:
flex
;
.box3-header-icon
{
margin-top
:
15px
;
width
:
13px
;
height
:
13px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.box3-header-title
{
margin-top
:
16px
;
margin-left
:
22px
;
height
:
22px
;
color
:
rgba
(
20
,
89
,
187
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
22px
;
}
}
.box3-header-right
{
display
:
flex
;
justify-content
:
flex-end
;
width
:
178px
;
height
:
22px
;
.right-box
{
display
:
flex
;
margin-top
:
16px
;
width
:
89px
;
height
:
22px
;
justify-content
:
flex-end
;
.icon1
{
margin-top
:
5px
;
width
:
12px
;
height
:
12px
;
border-radius
:
6px
;
background
:
rgba
(
20
,
89
,
187
,
1
);
}
.icon2
{
margin-top
:
5px
;
width
:
12px
;
height
:
12px
;
border-radius
:
6px
;
background
:
rgba
(
250
,
140
,
22
,
1
);
}
.text
{
margin-left
:
5px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
22px
;
}
}
}
}
.box3-main
{
height
:
397px
;
}
}
.box4
{
margin-left
:
20px
;
width
:
521px
;
height
:
450px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
.box4-header
{
width
:
452px
;
margin
:
0
auto
;
height
:
53px
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
display
:
flex
;
.header-icon
{
margin-top
:
18px
;
width
:
18px
;
height
:
18px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.header-title
{
margin-top
:
16px
;
margin-left
:
26px
;
height
:
22px
;
color
:
rgba
(
20
,
89
,
187
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
22px
;
}
}
.box4-main
{
width
:
452px
;
margin
:
0
auto
;
margin-top
:
8px
;
height
:
360px
;
overflow-y
:
auto
;
.box4-main-item
{
margin-top
:
6px
;
height
:
30px
;
display
:
flex
;
.leftStatus3
{
color
:
rgba
(
255
,
197
,
61
,
1
)
!
important
;
}
.leftStatus2
{
color
:
rgba
(
255
,
169
,
64
,
1
)
!
important
;
}
.left
{
width
:
44px
;
text-align
:
left
;
font-family
:
Microsoft
YaHei
;
font-size
:
18px
;
font-weight
:
700
;
line-height
:
30px
;
color
:
rgba
(
206
,
79
,
81
,
1
);
}
.center
{
width
:
300px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
30px
;
}
.right
{
width
:
108px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
30px
;
text-align
:
right
;
}
}
}
}
}
}
.home-main-footer
{
// width: 100%;
// height: 911px;
background
:
rgba
(
248
,
249
,
250
,
1
);
.home-main-footer-header
{
margin-top
:
37px
;
margin-bottom
:
36px
;
// width: 1600px;
height
:
42px
;
// background: orange;
display
:
flex
;
justify-content
:
space-between
;
.btn-box
{
width
:
1300px
;
display
:
flex
;
justify-content
:
space-between
;
.btn
{
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
42px
;
padding
:
0
24px
;
border-radius
:
21px
;
background
:
rgba
(
20
,
89
,
187
,
0
);
cursor
:
pointer
;
&
:hover
{
background
:
rgba
(
20
,
89
,
187
,
0
.1
);
}
}
.btnActive
{
padding
:
0
24px
;
border-radius
:
21px
;
background
:
rgba
(
20
,
89
,
187
,
1
);
color
:
#fff
;
&
:hover
{
color
:
#fff
;
background
:
rgba
(
20
,
89
,
187
,
1
);
}
}
}
.select-box
{
height
:
42px
;
box-sizing
:
border-box
;
padding
:
5px
0
;
}
}
.home-main-footer-main
{
width
:
100%
;
// background: orange;
display
:
flex
;
flex-wrap
:
wrap
;
// justify-content: space-between;
// justify-content: center;
.main-item
{
width
:
240px
;
height
:
320px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
background
:
#fff
;
margin-bottom
:
24px
;
margin-right
:
25px
;
.main-item-box1
{
margin-top
:
20px
;
margin-left
:
45px
;
width
:
150px
;
height
:
200px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
img
{
width
:
100%
;
height
:
100%
;
}
}
.main-item-box2
{
margin-top
:
26px
;
text-align
:
center
;
height
:
30px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
30px
;
}
.main-item-box3
{
text-align
:
center
;
height
:
30px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
30px
;
}
}
}
}
}
}
.tableName
{
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
30px
;
letter-spacing
:
0px
;
text-align
:
justify
;
display
:
flex
;
align-items
:
center
;
gap
:
10px
;
cursor
:
pointer
;
.box1-bottom-content-item-imgUndefined
{
width
:
24px
;
height
:
24px
;
font-size
:
14px
;
font-weight
:
700
;
flex-shrink
:
0
;
color
:
rgb
(
5
,
95
,
194
);
background-color
:
rgb
(
236
,
245
,
255
);
line-height
:
24px
;
text-align
:
center
;
border-radius
:
12px
;
}
}
.num-item
{
width
:
280px
;
display
:
flex
;
.name-item
{
width
:
215px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
.dialog-title
{
text-align
:
center
;
font-size
:
24px
;
font-weight
:
700
;
font-family
:
$base-font-family
;
padding-bottom
:
10px
;
border-bottom
:
1px
solid
#eee
;
}
.dialog-ett-wrpper
{
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
10px
;
height
:
500px
;
.box1-bottom-content
{
display
:
flex
;
gap
:
15px
;
flex-wrap
:
wrap
;
justify-content
:
space-between
;
padding-left
:
10px
;
height
:
156px
;
overflow
:
auto
;
&
-item
{
display
:
flex
;
// align-items: center;
justify-content
:
flex-start
;
width
:
48%
;
/* 留出2%的间距 */
// margin-bottom: 6px;
box-sizing
:
border-box
;
gap
:
10px
;
cursor
:
pointer
;
&
-img
{
width
:
24px
;
height
:
24px
;
flex-shrink
:
0
;
}
&
-imgUndefined
{
width
:
24px
;
height
:
24px
;
font-size
:
14px
;
font-weight
:
700
;
flex-shrink
:
0
;
color
:
rgba
(
5
,
95
,
194
,
1
);
background-color
:
rgb
(
236
,
245
,
255
);
line-height
:
24px
;
text-align
:
center
;
border-radius
:
12px
;
}
&
-txt
{
font-size
:
16px
;
font-weight
:
400
;
color
:
rgba
(
95
,
101
,
108
,
1
);
}
}
}
}
:deep
(
.el-input__wrapper
)
{
box-shadow
:
none
;
// border-radius: 10px;
}
:deep
(
.el-input__wrapper
:hover
)
{
// box-shadow: none !important;
}
:deep
(
.el-input__wrapper.is-focus
)
{
// box-shadow: none !important;
}
:deep
(
.el-table
thead
)
{
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
left
;
}
:deep
(
.el-table
tr
)
{
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
letter-spacing
:
0px
;
text-align
:
justify
;
}
.resource-tabs
{
width
:
100%
;
display
:
flex
;
align-items
:
center
;
margin-top
:
6px
;
margin-bottom
:
36px
;
// padding-left: 10px;
.resource-tab-item
{
margin-right
:
12px
;
cursor
:
pointer
;
font-size
:
20px
;
color
:
rgb
(
59
,
65
,
75
);
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
padding
:
8px
24px
;
border-radius
:
21px
;
transition
:
all
0
.3s
;
&
:last-child
{
margin-right
:
0
;
}
&
.active
{
background
:
rgb
(
5
,
95
,
194
);
color
:
#ffffff
;
font-weight
:
700
;
}
&
.disabled
{
cursor
:
not
-
allowed
;
color
:
#999999
;
background
:
transparent
;
}
&
:hover:not
(
.active
)
:not
(
.disabled
)
{
color
:
#0a57a6
;
}
}
}
.all-content
{
width
:
100%
;
height
:
auto
;
padding-bottom
:
30px
;
display
:
flex
;
justify-content
:
space-between
;
// align-items: center;
gap
:
16px
;
.left
{
width
:
360px
;
height
:
auto
;
align-self
:
flex-start
;
background
:
#fff
;
border-radius
:
10px
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
.title
{
width
:
100%
;
height
:
56px
;
display
:
flex
;
align-items
:
center
;
padding
:
14px
12px
16px
0
;
.box
{
width
:
8px
;
height
:
20px
;
background-color
:
rgb
(
5
,
95
,
194
);
border-bottom-right-radius
:
4px
;
border-top-right-radius
:
4px
;
margin-right
:
14px
;
}
.text
{
font-size
:
16px
;
font-weight
:
700
;
font-family
:
"Source Han Sans CN"
;
line-height
:
24px
;
color
:
rgb
(
5
,
95
,
194
);
}
}
.left-main
{
width
:
100%
;
height
:
auto
;
padding-left
:
24px
;
.checkbox-grid
{
display
:
grid
;
grid-template-columns
:
repeat
(
2
,
1fr
);
row-gap
:
16px
;
padding-bottom
:
16px
;
}
:deep
(
.el-checkbox
)
{
margin-right
:
0
;
height
:
auto
;
}
:deep
(
.el-checkbox__label
)
{
font-size
:
16px
;
color
:
#666666
;
font-weight
:
400
;
}
}
}
.right
{
width
:
1224px
;
height
:
auto
;
background
:
#fff
;
border-radius
:
4px
;
border-radius
:
10px
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
.right-title
{
width
:
100%
;
height
:
48px
;
border-bottom
:
1px
solid
rgb
(
234
,
236
,
238
);
display
:
flex
;
align-items
:
center
;
img
{
width
:
22px
;
height
:
18px
;
margin-left
:
19px
;
}
div
{
font-size
:
20px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
26px
;
color
:
rgb
(
5
,
95
,
194
);
margin-left
:
19px
;
}
}
.right-main
{
width
:
100%
;
height
:
auto
;
padding
:
24px
35px
0
20px
;
.sanction-list
{
width
:
1169px
;
padding
:
0px
0
12px
0
;
display
:
flex
;
position
:
relative
;
&
:not
(
:last-child
)
::after
{
content
:
""
;
position
:
absolute
;
left
:
111px
;
// 80px(time width) + 16px(margin) + 15px(30px img half)
top
:
44px
;
// 14px(img margin-top) + 30px(img height)
bottom
:
-14px
;
// 延伸到下一个图标的顶部
width
:
2px
;
background-color
:
rgb
(
234
,
236
,
238
);
z-index
:
1
;
}
// justify-content: flex-start;
.time
{
width
:
80px
;
// height: 50px;
// font-size: 16px;
// font-weight: 700;
// line-height: 24px;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
5
,
95
,
194
);
margin-right
:
16px
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-end
;
.year
{
font-size
:
16px
;
font-weight
:
700
;
line-height
:
24px
;
}
.date
{
font-size
:
16px
;
font-weight
:
700
;
line-height
:
24px
;
}
}
img
{
width
:
30px
;
height
:
30px
;
border-radius
:
50%
;
margin-top
:
14px
;
margin-right
:
16px
;
}
.main
{
width
:
1027px
;
padding-top
:
14px
;
position
:
relative
;
.main-title
{
width
:
800px
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
26px
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
59
,
65
,
75
);
margin-bottom
:
11px
;
cursor
:
pointer
;
}
.main-desc
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
30px
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
95
,
101
,
108
);
margin-bottom
:
9px
;
}
.tag-box
{
display
:
flex
;
.tag-item
{
padding
:
1px
8px
;
margin-right
:
8px
;
border-radius
:
4px
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
22px
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
5
,
95
,
194
);
background-color
:
rgba
(
231
,
243
,
255
,
1
);
}
}
.count-tag
{
position
:
absolute
;
padding
:
2px
8px
;
top
:
0
;
right
:
0
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
206
,
79
,
81
);
border-radius
:
20px
;
background-color
:
rgba
(
206
,
79
,
81
,
0
.1
);
}
}
}
}
.right-footer
{
width
:
100%
;
height
:
73px
;
border-top
:
1px
solid
rgb
(
234
,
236
,
238
);
padding
:
0
31px
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
.total-count
{
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
59
,
65
,
75
);
}
}
}
}
.search-header
{
width
:
100%
;
height
:
144px
;
background
:
#fff
;
overflow
:
hidden
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.3
);
.home-main-header-center
{
margin-top
:
20px
;
margin-left
:
200px
;
width
:
800px
;
height
:
48px
;
border-radius
:
10px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
box-sizing
:
border-box
;
padding
:
1px
;
position
:
relative
;
border
:
1px
solid
transparent
;
&
:hover
{
border
:
1px
solid
var
(
--
color-main-active
);
}
.search
{
position
:
absolute
;
right
:
-1px
;
top
:
0px
;
width
:
120px
;
height
:
46px
;
border-radius
:
10px
;
background
:
var
(
--
color-main-active
);
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
cursor
:
pointer
;
.search-icon
{
width
:
18px
;
height
:
18px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.search-text
{
margin-left
:
8px
;
height
:
22px
;
color
:
#fff
;
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
22px
;
}
}
}
.home-main-header-btn-box
{
margin-top
:
20px
;
margin-left
:
200px
;
display
:
flex
;
gap
:
16px
;
.btn
{
display
:
flex
;
align-items
:
center
;
gap
:
9px
;
width
:
160px
;
height
:
48px
;
border
:
1px
solid
#aed6ff
;
box-sizing
:
border-box
;
border-radius
:
24px
;
background
:
#e7f3ff
;
cursor
:
pointer
;
position
:
relative
;
&
:hover
{
background
:
#cae3fc
;
}
.btn-text
{
width
:
80px
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
400
;
line-height
:
48px
;
margin-left
:
36px
;
text-align
:
center
;
}
.btn-icon
{
position
:
absolute
;
top
:
16px
;
right
:
19px
;
width
:
6px
;
height
:
12px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
}
}
.scroll-main
{
// height: calc(100% - 144px) !important;
}
.center-center
{
width
:
1600px
;
margin
:
0
auto
;
margin-top
:
21px
;
height
:
450px
;
display
:
flex
;
gap
:
16px
;
.center-center-news
{
flex-shrink
:
0
;
}
.boxs4
{
margin-left
:
20px
;
width
:
792px
;
height
:
450px
;
border-radius
:
10px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
25
,
69
,
130
,
0
.2
);
background
:
rgba
(
255
,
255
,
255
,
1
);
}
}
.data-origin-box
{
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
flex-start
;
padding
:
22px
0
;
.data-origin-icon
{
width
:
16px
;
height
:
16px
;
font-size
:
0px
;
margin-right
:
8px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.data-origin-text
{
font-family
:
Source
Han
Sans
CN
;
font-size
:
14px
;
color
:
var
(
--
text-primary-50-color
);
}
}
.ai-pane
{
position
:
absolute
;
right
:
0px
;
bottom
:
15px
;
z-index
:
999
;
:deep
(
.ai-pane-wrapper
)
{
display
:
none
;
}
:deep
(
.ai-button-wrapper
)
{
display
:
flex
;
}
&
:hover
{
width
:
100%
;
bottom
:
0px
;
:deep
(
.ai-pane-wrapper
)
{
display
:
block
;
}
:deep
(
.ai-button-wrapper
)
{
display
:
none
;
}
}
}
</
style
>
src/views/exportControl/index.vue
浏览文件 @
d2be76a4
...
...
@@ -688,6 +688,7 @@
import
NewsList
from
"@/components/base/newsList/index.vue"
;
import
RiskSignal
from
"@/components/base/riskSignal/index.vue"
;
import
SimplePagination
from
"@/components/SimplePagination.vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
{
getChartAnalysis
}
from
"@/api/aiAnalysis/index"
;
import
RiskSignalOverviewDetailDialog
from
"@/components/base/RiskSignalOverviewDetailDialog/index.vue"
;
import
{
onMounted
,
ref
,
computed
,
reactive
,
shallowRef
,
watch
,
nextTick
}
from
"vue"
;
...
...
@@ -702,7 +703,7 @@ import tipsIcon from "./assets/icons/info-icon.png";
import
AiButton
from
"@/components/base/Ai/AiButton/index.vue"
;
import
AiPane
from
"@/components/base/Ai/AiPane/index.vue"
;
import
AreaTag
from
"@/components/base/AreaTag/index.vue"
;
import
{
useChartInterpretation
}
from
"@/views/exportControl/utils/common"
;
//
import { useChartInterpretation } from "@/views/exportControl/utils/common";
import
{
TAGTYPE
}
from
"@/public/constant"
;
import
{
useGotoCompanyPages
}
from
"@/router/modules/company"
;
import
{
useGotoNewsDetail
}
from
"@/router/modules/news"
;
...
...
@@ -846,9 +847,12 @@ const handleTitleClick = item => {
const
handleCompClick
=
item
=>
{
// console.log("item", item);
if
(
!
item
.
id
)
return
;
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
);
gotoCompanyPages
(
item
.
entityI
d
);
gotoCompanyPages
(
item
.
i
d
);
};
const
tagsType
=
[
"primary"
,
"success"
,
"warning"
,
"danger"
];
...
...
@@ -1186,6 +1190,10 @@ const processYearDomainCountData = yearDomainCountData => {
const
handleEntityClick
=
item
=>
{
console
.
log
(
"item"
,
item
);
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
||
item
.
entityNameZh
);
gotoCompanyPages
(
item
.
id
);
};
...
...
@@ -2596,14 +2604,14 @@ const handleMediaClick = item => {
}
.box4-footer
{
//
position: absolute;
position
:
absolute
;
// margin-top: auto;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
bottom
:
3
0px
;
bottom
:
0px
;
left
:
50%
;
margin-left
:
-
3
0px
;
margin-left
:
-
4
0px
;
// margin-bottom: 30px;
}
}
...
...
src/views/exportControl/v2.0EntityList/components/dataStatistics/index.vue
浏览文件 @
d2be76a4
...
...
@@ -270,6 +270,7 @@ import {
getTechDomainCount
,
getEntityTypeCount
}
from
"@/api/exportControlV2.0"
;
import
{
getChartAnalysis
}
from
"@/api/aiAnalysis/index"
;
import
EChart
from
"@/components/Chart/index.vue"
;
import
{
useRoute
}
from
"vue-router"
;
import
{
useRouter
}
from
"vue-router"
;
...
...
src/views/exportControl/v2.0EntityList/components/sanctionsOverview/components/listPage/RuleSubsidiaryDialog.vue
浏览文件 @
d2be76a4
...
...
@@ -80,6 +80,7 @@
<
script
setup
>
import
{
ref
,
computed
,
watch
}
from
"vue"
;
import
router
from
"@/router"
;
import
{
ElMessage
}
from
"element-plus"
;
import
{
Close
}
from
"@element-plus/icons-vue"
;
import
defaultIcon
from
"@/assets/icons/default-icon1.png"
;
import
{
useGotoCompanyPages
}
from
"@/router/modules/company"
;
...
...
@@ -155,6 +156,10 @@ const getTagStyle = tag => {
// 跳转公司详情页
const
handleCompClick
=
item
=>
{
console
.
log
(
"item"
,
item
);
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
||
item
.
orgName
);
gotoCompanyPages
(
item
.
id
);
};
...
...
src/views/exportControl/v2.0EntityList/components/sanctionsOverview/components/listPage/index.vue
浏览文件 @
d2be76a4
...
...
@@ -184,6 +184,7 @@
<
script
setup
>
import
{
ref
,
computed
,
onMounted
,
watch
}
from
"vue"
;
import
{
useRouter
}
from
"vue-router"
;
import
{
ElMessage
}
from
"element-plus"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
defaultIcon
from
"../../../../../assets/icons/default-avatar.png"
;
import
RuleSubsidiaryDialog
from
"./RuleSubsidiaryDialog.vue"
;
...
...
@@ -203,6 +204,10 @@ const orderOptions = ref([
// 跳转公司详情页
const
handleCompClick
=
item
=>
{
console
.
log
(
"item"
,
item
);
if
(
!
item
.
entityId
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
entityNameZh
||
item
.
entityName
);
// const route = router.resolve({
// name: "companyPages",
...
...
src/views/exportControl/v2.0EntityList/index.vue
浏览文件 @
d2be76a4
...
...
@@ -124,7 +124,7 @@ const headerNavList = ref([
height
:
148px
;
background-color
:
#fff
;
padding-top
:
16px
;
position
:
sticky
;
//
position: sticky;
top
:
0
;
z-index
:
1000
;
box-shadow
:
0px
4px
10px
rgba
(
0
,
0
,
0
,
0
.05
);
...
...
src/views/exportControl/v2.0SingleSanction/components/dataStatistics/index.vue
浏览文件 @
d2be76a4
...
...
@@ -150,6 +150,7 @@
<div
class=
"map-wrapper"
>
<div
class=
"map-chart"
ref=
"mapChartRef"
></div>
<div
class=
"rank-list"
>
<div
class=
"rank-list-if"
v-if=
"regionDistribution.length > 0"
>
<div
class=
"rank-item"
v-for=
"(item, index) in regionDistribution"
...
...
@@ -170,6 +171,8 @@
<div
class=
"rank-value"
>
{{
item
.
count
}}
家
</div>
</div>
</div>
<el-empty
v-else
:style=
"
{ height: '90%' }" />
</div>
</div>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
...
...
@@ -215,10 +218,10 @@ import {
import
{
getChartAnalysis
}
from
"@/api/aiAnalysis/index"
;
import
{
useChartInterpretation
}
from
"@/views/exportControl/utils/common"
;
const
domainChart
=
useChartInterpretation
();
const
typeChart
=
useChartInterpretation
();
const
countryDistributionChart
=
useChartInterpretation
();
const
regionDistributionChart
=
useChartInterpretation
();
//
const domainChart = useChartInterpretation();
//
const typeChart = useChartInterpretation();
//
const countryDistributionChart = useChartInterpretation();
//
const regionDistributionChart = useChartInterpretation();
const
route
=
useRoute
();
// 单次制裁-数据统计-制裁实体地域分布情况
...
...
src/views/exportControl/v2.0SingleSanction/components/impactAnalysis/components/industrialImpact/index.vue
浏览文件 @
d2be76a4
...
...
@@ -61,12 +61,6 @@
</div>
</
template
>
<div
class=
"right-main"
v-loading=
"scaleLoading"
>
<!-- <div class="echarts" ref="chartRef"></div> -->
<!-- <div class="bottom">
<img :src="ai" class="ai-icon" alt="" />
<span class="text">列入实体清单后企业营收初期下降,后基本趋于稳定。</span>
<img :src="right" class="right-icon" alt="" />
</div> -->
<EChart
:option=
"revenueChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
...
...
@@ -75,32 +69,19 @@
<div
class=
"data-origin-text"
>
数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"revenueChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="revenueChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('revenueChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.revenueChart"
:aiContent=
"overviewAiContent.revenueChart"
@
mouseleave=
"handleHideAiPane('revenueChart')"
/>
</div>
</div>
</AnalysisBox>
</div>
<div
class=
"right-item"
>
<!-- <div class="title-com">
<div class="box"></div>
<div class="text">企业市值变化</div>
<div class="right-group">
<div class="btn">
<img src="../../../../assets/数据库按钮.png" alt="" />
<img src="../../../../assets/下载按钮.png" alt="" />
<img src="../../../../assets/收藏按钮.png" alt="" />
</div>
</div>
</div>
<div class="right-main">
<div class="echarts" ref="marketChartRef"></div>
<div class="bottom">
<img :src="ai" class="ai-icon" alt="" />
<span class="text">列入实体清单后企业营收初期下降,后基本趋于稳定。</span>
<img :src="right" class="right-icon" alt="" />
</div>
</div> -->
<AnalysisBox
title=
"企业市值变化"
>
<div
class=
"right-main"
>
<!-- <div class="echarts" ref="marketChartRef"></div>
...
...
@@ -117,38 +98,19 @@
<div
class=
"data-origin-text"
>
数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"marketChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="marketChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('marketChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.marketChart"
:aiContent=
"overviewAiContent.marketChart"
@
mouseleave=
"handleHideAiPane('marketChart')"
/>
</div>
</div>
</AnalysisBox>
</div>
<div
class=
"right-item"
>
<!-- <div class="title-com">
<div class="box"></div>
<div class="text">企业研发投入</div>
<div class="right-group">
<div class="toggle-btns">
<div class="t-btn" :class="{ active: activeRD === item }" v-for="item in rdOptions" :key="item"
@click="activeRD = item">
{{ item }}
</div>
</div>
<div class="btn">
<img src="../../../../assets/数据库按钮.png" alt="" />
<img src="../../../../assets/下载按钮.png" alt="" />
<img src="../../../../assets/收藏按钮.png" alt="" />
</div>
</div>
</div>
<div class="right-main">
<div class="echarts" ref="rdChartRef"></div>
<div class="bottom">
<img :src="ai" class="ai-icon" alt="" />
<span class="text">列入实体清单后企业研发资金投入逐渐提高。</span>
<img :src="right" class="right-icon" alt="" />
</div>
</div> -->
<AnalysisBox
title=
"企业研发投入"
>
<
template
#
header-btn
>
<div
class=
"toggle-btns"
>
...
...
@@ -178,38 +140,19 @@
<div
class=
"data-origin-text"
>
数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"rdChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="rdChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('rdChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.rdChart"
:aiContent=
"overviewAiContent.rdChart"
@
mouseleave=
"handleHideAiPane('rdChart')"
/>
</div>
</div>
</AnalysisBox>
</div>
<div
class=
"right-item"
>
<!-- <div class="title-com">
<div class="box"></div>
<div class="text">企业市场占比</div>
<div class="right-group">
<div class="toggle-btns">
<div class="t-btn" :class="{ active: activeMarketShare === item }" v-for="item in marketShareOptions"
:key="item" @click="activeMarketShare = item">
{{ item }}
</div>
</div>
<div class="btn">
<img src="../../../../assets/数据库按钮.png" alt="" />
<img src="../../../../assets/下载按钮.png" alt="" />
<img src="../../../../assets/收藏按钮.png" alt="" />
</div>
</div>
</div>
<div class="right-main">
<div class="echarts" ref="shareChartRef"></div>
<div class="bottom">
<img :src="ai" class="ai-icon" alt="" />
<span class="text">列入实体清单后企业营收初期下降,后基本趋于稳定。</span>
<img :src="right" class="right-icon" alt="" />
</div>
</div> -->
<AnalysisBox
title=
"企业市场占比"
>
<
template
#
header-btn
>
<div
class=
"toggle-btns"
>
...
...
@@ -239,8 +182,14 @@
<div
class=
"data-origin-text"
>
数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"shareChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="shareChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('shareChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.shareChart"
:aiContent=
"overviewAiContent.shareChart"
@
mouseleave=
"handleHideAiPane('shareChart')"
/>
</div>
</div>
</AnalysisBox>
...
...
@@ -269,6 +218,7 @@ import {
getSingleSanctionEntityRDInvestment
,
getSingleSanctionEntityMarketShare
}
from
"@/api/exportControlV2.0"
;
import
{
getChartAnalysis
}
from
"@/api/aiAnalysis/index"
;
import
AiButton
from
"@/components/base/Ai/AiButton/index.vue"
;
import
AiPane
from
"@/components/base/Ai/AiPane/index.vue"
;
import
EChart
from
"@/components/Chart/index.vue"
;
...
...
@@ -303,7 +253,8 @@ const getMarketShare = async () => {
nextTick
(()
=>
{
initShareChart
();
});
shareChart
.
interpret
({
type
:
"柱状图"
,
name
:
"企业市场占比"
,
data
:
sortedData
});
// shareChart.interpret({ type: "柱状图", name: "企业市场占比", data: sortedData });
shareChartData1
.
value
=
sortedData
;
}
}
}
catch
(
error
)
{
...
...
@@ -337,7 +288,8 @@ const getRDInvestment = async () => {
nextTick
(()
=>
{
initRDChart
();
});
rdChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业研发投入"
,
data
:
sortedData
});
// rdChart.interpret({ type: "折线图", name: "企业研发投入", data: sortedData });
rdChartData1
.
value
=
sortedData
;
}
}
}
catch
(
error
)
{
...
...
@@ -371,7 +323,8 @@ const getMarketValue = async () => {
nextTick
(()
=>
{
initMarketChart
();
});
marketChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业市值变化"
,
data
:
sortedData
});
// marketChart.interpret({ type: "折线图", name: "企业市值变化", data: sortedData });
marketChartData1
.
value
=
sortedData
;
}
}
}
catch
(
error
)
{
...
...
@@ -408,7 +361,8 @@ const getPersonnel = async () => {
nextTick
(()
=>
{
initRevenueChart
();
});
revenueChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业规模"
,
data
:
sortedData
});
// revenueChart.interpret({ type: "折线图", name: "企业规模", data: sortedData });
revenueChartData
.
value
=
sortedData
;
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -445,7 +399,8 @@ const getNetProfitData = async () => {
nextTick
(()
=>
{
initRevenueChart
();
});
revenueChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业规模"
,
data
:
sortedData
});
// revenueChart.interpret({ type: "折线图", name: "企业规模", data: sortedData });
revenueChartData
.
value
=
sortedData
;
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -487,7 +442,8 @@ const getRevenueData = async () => {
nextTick
(()
=>
{
initRevenueChart
();
});
revenueChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业规模"
,
data
:
sortedData
});
// revenueChart.interpret({ type: "折线图", name: "企业规模", data: sortedData });
revenueChartData
.
value
=
sortedData
;
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -923,6 +879,128 @@ const initShareChart = () => {
shareChartOption
.
value
=
option
;
};
const
requestAiPaneContent
=
async
key
=>
{
if
(
!
key
||
aiPaneLoading
.
value
[
key
]
||
aiPaneFetched
.
value
[
key
])
return
;
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
true
};
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成中..."
};
try
{
const
payload
=
buildAiChartPayload
(
key
);
const
res
=
await
getChartAnalysis
(
{
text
:
JSON
.
stringify
(
payload
)
},
{
onChunk
:
chunk
=>
{
const
current
=
overviewAiContent
.
value
[
key
];
const
base
=
current
===
"智能总结生成中..."
?
""
:
current
;
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
base
+
chunk
};
}
}
);
const
list
=
res
?.
data
;
const
first
=
Array
.
isArray
(
list
)
?
list
[
0
]
:
null
;
const
interpretation
=
first
?.
解读
||
first
?.[
"解读"
];
// 流式已渲染过内容,最终用解析出的解读覆盖(保证显示格式统一)
if
(
interpretation
)
{
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
interpretation
};
}
aiPaneFetched
.
value
=
{
...
aiPaneFetched
.
value
,
[
key
]:
true
};
}
catch
(
error
)
{
console
.
error
(
"获取图表解读失败"
,
error
);
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成失败"
};
}
finally
{
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
false
};
}
};
const
revenueChartData
=
ref
([]);
const
marketChartData1
=
ref
([]);
const
rdChartData1
=
ref
([]);
const
shareChartData1
=
ref
([]);
const
aiPaneVisible
=
ref
({
revenueChart
:
false
,
marketChart
:
false
,
rdChart
:
false
,
shareChart
:
false
});
const
overviewAiContent
=
ref
({
revenueChart
:
"智能总结生成中..."
,
marketChart
:
"智能总结生成中..."
,
rdChart
:
"智能总结生成中..."
,
shareChart
:
"智能总结生成中..."
});
const
aiPaneFetched
=
ref
({
revenueChart
:
false
,
marketChart
:
false
,
rdChart
:
false
,
shareChart
:
false
});
const
aiPaneLoading
=
ref
({
revenueChart
:
false
,
marketChart
:
false
,
rdChart
:
false
,
shareChart
:
false
});
const
chartLoading
=
ref
({
revenueChart
:
false
,
marketChart
:
false
,
rdChart
:
false
,
shareChart
:
false
});
const
buildAiChartPayload
=
key
=>
{
if
(
key
===
"revenueChart"
)
{
return
{
type
:
"折线图"
,
name
:
"企业规模"
,
data
:
revenueChartData
.
value
};
}
if
(
key
===
"marketChart"
)
{
return
{
type
:
"折线图"
,
name
:
"企业市场占比"
,
data
:
marketChartData1
.
value
};
}
if
(
key
===
"rdChart"
)
{
return
{
type
:
"折线图"
,
name
:
"企业研发投入"
,
data
:
rdChartData1
.
value
};
}
if
(
key
===
"shareChart"
)
{
return
{
type
:
"折线图"
,
name
:
"企业市场份额"
,
data
:
shareChartData1
.
value
};
}
return
{
type
:
""
,
name
:
""
,
data
:
[]
};
};
const
handleShowAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
true
};
requestAiPaneContent
(
key
);
};
const
handleHideAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
false
};
};
onMounted
(
async
()
=>
{
getUrlParams
();
// 单次制裁-影响分析-制裁企业列表-查询 (获取到默认的 selectedCompanyId 后会触发 watch 加载其他数据)
...
...
src/views/exportControl/v2.0SingleSanction/components/sanctionsOverview/index.vue
浏览文件 @
d2be76a4
...
...
@@ -80,11 +80,19 @@
<div
class=
"content"
>
{{
item
.
content
}}
</div>
</div>
</div>
<div
class=
"view-more"
v-if=
"hasMore"
@
click=
"loadMore"
>
<
!--
<
div
class=
"view-more"
v-if=
"hasMore"
@
click=
"loadMore"
>
查看更多
<el-icon
class=
"icon-more"
>
<DArrowRight
/>
</el-icon>
</div>
-->
<div
class=
"left-bottom-footer"
>
<simple-pagination
v-model:current-page=
"timelinePage"
:page-size=
"timelinePageSize"
:total=
"totalNum"
@
page-change=
"handleListPageChange"
/>
</div>
</div>
</AnalysisBox>
...
...
@@ -361,8 +369,16 @@ const getSanctionOverviewList = async () => {
// 单次制裁-制裁概况-制裁背景
const
timelinePage
=
ref
(
1
);
const
timelinePageSize
=
ref
(
5
);
const
totalNum
=
ref
(
0
);
const
hasMore
=
ref
(
true
);
const
handleListPageChange
=
pageNum
=>
{
console
.
log
(
"页面修改 =>"
,
pageNum
);
timelinePage
.
value
=
pageNum
;
getSanctionBackground
();
};
const
getSanctionBackground
=
async
(
isLoadMore
=
false
)
=>
{
try
{
const
res
=
await
getSingleSanctionBackground
({
...
...
@@ -386,6 +402,7 @@ const getSanctionBackground = async (isLoadMore = false) => {
// 判断是否还有更多数据
const
totalElements
=
res
.
data
.
totalElements
||
0
;
totalNum
.
value
=
totalElements
;
hasMore
.
value
=
timelineData
.
value
.
length
<
totalElements
;
}
}
catch
(
error
)
{
...
...
@@ -783,7 +800,7 @@ onMounted(() => {
.left-bottom
{
width
:
100%
;
height
:
521px
;
height
:
auto
;
.left-bottom-content
{
padding
:
20px
25px
0
25px
;
...
...
src/views/exportControl/v2.0SingleSanction/index.vue
浏览文件 @
d2be76a4
...
...
@@ -292,7 +292,7 @@ onMounted(() => {
height
:
148px
;
background-color
:
#fff
;
padding-top
:
16px
;
position
:
sticky
;
//
position: sticky;
top
:
0
;
z-index
:
1000
;
box-shadow
:
0px
4px
10px
rgba
(
0
,
0
,
0
,
0
.05
);
...
...
src/views/finance/analysis/components/influencePanel2.vue
浏览文件 @
d2be76a4
...
...
@@ -83,6 +83,7 @@
<
script
setup
>
import
{
ref
,
onMounted
,
shallowReactive
,
shallowRef
,
watch
}
from
"vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
CardCustom
from
"../../components/CardCustom.vue"
;
import
Echarts
from
"@/components/Chart/index.vue"
;
import
Hint
from
"./hint.vue"
;
...
...
@@ -164,6 +165,10 @@ const handleEttClick = item => {
//
}
//
}
);
// window.open(route.href, "_blank");
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
gotoCompanyPages
(
item
.
id
);
}
;
// 处理点击事件
...
...
src/views/finance/analysis/components/panel1.vue
浏览文件 @
d2be76a4
...
...
@@ -87,6 +87,7 @@
<
script
setup
>
import
{
ref
,
shallowRef
,
onMounted
,
watch
}
from
"vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
CardCustom
from
"../../components/CardCustom.vue"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
Echarts
from
"@/components/Chart/index.vue"
;
...
...
@@ -350,6 +351,10 @@ const handleOrgClick = item => {
// }
// });
// window.open(route.href, "_blank");
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
gotoCompanyPages
(
item
.
id
);
};
</
script
>
...
...
src/views/finance/analysis/components/panel2.vue
浏览文件 @
d2be76a4
...
...
@@ -66,6 +66,7 @@
<
script
setup
>
import
{
ref
,
shallowRef
,
onMounted
,
watch
}
from
"vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
CardCustom
from
"../../components/CardCustom.vue"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
Echarts
from
"@/components/Chart/index.vue"
;
...
...
@@ -313,6 +314,10 @@ const handleOrgClick = item => {
// }
// });
// window.open(route.href, "_blank");
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
gotoCompanyPages
(
item
.
id
);
};
</
script
>
...
...
src/views/finance/analysis/content/overview.vue
浏览文件 @
d2be76a4
...
...
@@ -157,7 +157,7 @@
<CardCustom
title=
"美国前序相关制裁、前序相关事件列表"
:style=
"{ width: '600px', height: '678px' }"
>
<div
class=
"panel6"
>
<div
class=
"panel6-list"
>
<div
class=
"item"
v-for=
"
(item, idx)
in panel6"
:key=
"item.title"
>
<div
class=
"item"
v-for=
"
item
in panel6"
:key=
"item.title"
>
<div
class=
"left"
>
<div
class=
"icon"
></div>
<div
class=
"line"
></div>
...
...
@@ -182,6 +182,7 @@
<
script
setup
>
import
CardCustom
from
"../../components/CardCustom.vue"
;
import
PieCharts
from
"../components/pieCharts.vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
MapCharts
from
"../components/mapCharts.vue"
;
import
ButtonList
from
"@/components/buttonList/buttonList.vue"
;
import
Hint
from
"../components/hint.vue"
;
...
...
@@ -415,6 +416,10 @@ const handleOrgClick = item => {
// }
// });
// window.open(route.href, "_blank");
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
gotoCompanyPages
(
item
.
id
);
};
...
...
src/views/finance/entityList/components/dataStatistics/index.vue
浏览文件 @
d2be76a4
...
...
@@ -104,60 +104,31 @@
</div>
</div>
</
template
>
<EChart
:option=
"sanctionCountChartOption"
autoresize
:style=
"{ height: '300px', padding: '0 20px' }"
@
chart-click=
"handleToDataLibrary4"
/>
<EChart
:option=
"sanctionCountChartOption"
autoresize
:style=
"{ height: '300px', padding: '0 20px' }"
@
chart-click=
"handleToDataLibrary4"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
进入SDN清单的中国实体数量变化趋势,数据来源:美国财政部海外资产管理办公室官网
</div>
<div
class=
"data-origin-text"
>
数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"sanctionCountChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="sanctionCountChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('sanctionCountChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.sanctionCountChart"
:aiContent=
"overviewAiContent.sanctionCountChart"
@
mouseleave=
"handleHideAiPane('sanctionCountChart')"
/>
</div>
</AnalysisBox>
</div>
<!-- <div class="main-item">
<AnalysisBox title="制裁实体各省分布情况">
<template #header-btn>
<el-select v-model="regionTime" class="time-select" placeholder="请选择" @change="getRegionCountData">
<el-option v-for="item in timeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
<div class="map-wrapper">
<div class="map-chart" ref="mapChartRef"></div>
<div class="rank-list">
<div class="rank-item" v-for="(item, index) in rankData" :key="index">
<div class="rank-index" :class="'rank-' + (index + 1)">{{ index + 1 }}</div>
<div class="rank-name">{{ item.name }}</div>
<div class="rank-bar-bg">
<div
class="rank-bar-fill"
:style="{
width: (item.value / maxRankValue) * 100 + '%',
background: getBarColor(index)
}"
></div>
</div>
<div class="rank-value">{{ item.value }}家</div>
</div>
</div>
</div>
<div class="data-origin-box">
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">进入实体清单的中国实体各省分布情况,数据来源:美国商务部官网</div>
</div>
<div class="ai-pane">
<AiButton />
<AiPane :aiContent="rankChart.interpretation" />
</div>
</AnalysisBox>
</div> -->
<div
class=
"main-item"
>
<AnalysisBox
title=
"制裁实体领域分布情况"
>
<
template
#
header-btn
>
...
...
@@ -165,19 +136,28 @@
<el-option
v-for=
"item in timeOptions"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</
template
>
<EChart
:option=
"domainChartOption"
autoresize
:style=
"{ height: '300px', padding: '0 20px' }"
@
chart-click=
"handleToDataLibrary6"
/>
<EChart
:option=
"domainChartOption"
autoresize
:style=
"{ height: '300px', padding: '0 20px' }"
@
chart-click=
"handleToDataLibrary6"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
进入SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
<div
class=
"data-origin-text"
>
数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"domainChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="domainChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('domainChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.domainChart"
:aiContent=
"overviewAiContent.domainChart"
@
mouseleave=
"handleHideAiPane('domainChart')"
/>
</div>
</AnalysisBox>
</div>
...
...
@@ -190,28 +170,44 @@
</template> -->
<
template
#
header-btn
>
<div
class=
"toggle-btns"
>
<div
class=
"t-btn"
:class=
"
{ active: activeDomainTab === 'year' }" @click="handleDomainTabChange('year')">
<div
class=
"t-btn"
:class=
"
{ active: activeDomainTab === 'year' }"
@click="handleDomainTabChange('year')"
>
按年度
</div>
<div
class=
"t-btn"
:class=
"
{ active: activeDomainTab === 'sanction' }"
@click="handleDomainTabChange('sanction')">
<div
class=
"t-btn"
:class=
"
{ active: activeDomainTab === 'sanction' }"
@click="handleDomainTabChange('sanction')"
>
按制裁
</div>
</div>
</
template
>
<EChart
:option=
"domainNumChartOption"
autoresize
:style=
"{ height: '300px', padding: '0 20px' }"
@
chart-click=
"handleToDataLibrary5"
/>
<EChart
:option=
"domainNumChartOption"
autoresize
:style=
"{ height: '300px', padding: '0 20px' }"
@
chart-click=
"handleToDataLibrary5"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
进入SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
<div
class=
"data-origin-text"
>
数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"domainNumChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="domainNumChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('domainNumChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.domainNumChart"
:aiContent=
"overviewAiContent.domainNumChart"
@
mouseleave=
"handleHideAiPane('domainNumChart')"
/>
</div>
</AnalysisBox>
</div>
...
...
@@ -223,7 +219,12 @@
</el-select>
</
template
>
<!-- <div class="echarts" ref="typeChartRef"></div> -->
<EChart
:option=
"typeChartOption"
autoresize
:style=
"{ height: '300px', padding: '0 20px' }"
@
chart-click=
"handleToDataLibrary7"
/>
<EChart
:option=
"typeChartOption"
autoresize
:style=
"{ height: '300px', padding: '0 20px' }"
@
chart-click=
"handleToDataLibrary7"
/>
<!-- <div class="bottom">
<div class="ai">
<div class="left">
...
...
@@ -239,13 +240,17 @@
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
进入SDN清单的中国实体类型分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
<div
class=
"data-origin-text"
>
数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"typeChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="typeChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('typeChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.typeChart"
:aiContent=
"overviewAiContent.typeChart"
@
mouseleave=
"handleHideAiPane('typeChart')"
/>
</div>
</AnalysisBox>
</div>
...
...
@@ -257,8 +262,6 @@
import
{
ref
,
onMounted
,
computed
}
from
"vue"
;
import
*
as
echarts
from
"echarts"
;
import
chinaJson
from
"../../../utils/China.json"
;
import
ai
from
"./assets/ai.png"
;
import
right
from
"./assets/right.png"
;
import
{
getTotalCount
,
getSanctionCountChange
,
...
...
@@ -266,6 +269,7 @@ import {
getTechDomainCount
,
getEntityTypeCount
}
from
"@/api/exportControlV2.0"
;
import
{
getChartAnalysis
}
from
"@/api/aiAnalysis/index"
;
import
{
getDomainNum
}
from
"@/api/finance"
;
import
getMultiLineChart
from
"@/views/ZMOverView/components/fourSuppress/components/addDomain/multiLineChart"
;
import
EChart
from
"@/components/Chart/index.vue"
;
...
...
@@ -281,7 +285,7 @@ const domainNumChart = useChartInterpretation();
const
typeChart
=
useChartInterpretation
();
const
rankChart
=
useChartInterpretation
();
const
router
=
useRouter
()
const
router
=
useRouter
()
;
const
route
=
useRoute
();
// 实体清单-数据统计-制裁实体类型分布情况
const
typeData
=
ref
([]);
...
...
@@ -305,7 +309,8 @@ const getTypeCountData = async () => {
value
:
item
.
count
||
item
.
value
}));
updateTypeChart
();
typeChart
.
interpret
({
type
:
"饼图"
,
name
:
"制裁实体类型分布情况"
,
data
:
data
});
// typeChart.interpret({ type: "饼图", name: "制裁实体类型分布情况", data: data });
typeChartData
.
value
=
data
;
}
}
catch
(
error
)
{
console
.
error
(
"获取实体清单-数据统计-制裁实体类型分布情况失败:"
,
error
);
...
...
@@ -333,7 +338,8 @@ const getDomainCountData = async () => {
value
:
item
.
count
||
item
.
value
}));
updateDomainChart
();
domainChart
.
interpret
({
type
:
"饼图"
,
name
:
"制裁实体领域分布情况"
,
data
:
data
});
// domainChart.interpret({ type: "饼图", name: "制裁实体领域分布情况", data: data });
domainChartData
.
value
=
data
;
}
}
catch
(
error
)
{
console
.
error
(
"获取实体清单-数据统计-制裁实体领域分布情况失败:"
,
error
);
...
...
@@ -370,7 +376,7 @@ const getRegionCountData = async () => {
}));
// Sort by value descending
rankData
.
value
.
sort
((
a
,
b
)
=>
b
.
value
-
a
.
value
);
rankChart
.
interpret
({
type
:
"柱状图"
,
name
:
"制裁实体各省分布情况"
,
data
:
data
});
//
rankChart.interpret({ type: "柱状图", name: "制裁实体各省分布情况", data: data });
updateMapChart
();
}
}
catch
(
error
)
{
...
...
@@ -530,7 +536,8 @@ const getDomainNumData = async () => {
domainNumChartOption
.
value
=
getMultiLineChart
(
processedData
);
console
.
log
(
"获取实体清单-数据统计-processedData:"
,
processedData
);
console
.
log
(
"获取实体清单-数据统计-domainNumChartOption:"
,
res
);
domainNumChart
.
interpret
({
type
:
"折线图"
,
name
:
"制裁实体领域数量变化情况"
,
data
:
res
});
// domainNumChart.interpret({ type: "折线图", name: "制裁实体领域数量变化情况", data: res });
domainNumChartData
.
value
=
res
;
}
}
catch
(
error
)
{
console
.
error
(
"获取实体清单-数据统计-制裁实体领域数量变化趋势失败:"
,
error
);
...
...
@@ -549,7 +556,8 @@ const getSanctionCountChangeData = async () => {
const
res
=
await
getSanctionCountChange
(
param
);
sanctionCountChange
.
value
=
res
.
data
||
[];
updateSanctionCountChart
();
sanctionCountChart
.
interpret
({
type
:
"饼图"
,
name
:
"制裁实体数量变化情况"
,
data
:
res
.
data
});
// sanctionCountChart.interpret({ type: "饼图", name: "制裁实体数量变化情况", data: res.data });
sanctionCountChartData
.
value
=
res
.
data
;
}
catch
(
error
)
{
console
.
error
(
"获取实体清单-数据统计-制裁实体数量变化情况失败:"
,
error
);
}
...
...
@@ -1275,7 +1283,7 @@ const handleToDataLibrary = () => {
}
});
window
.
open
(
route
.
href
,
"_blank"
);
}
}
;
const
handleToDataLibrary1
=
()
=>
{
const
route
=
router
.
resolve
({
...
...
@@ -1286,19 +1294,19 @@ const handleToDataLibrary1 = () => {
}
});
window
.
open
(
route
.
href
,
"_blank"
);
}
}
;
const
handleToDataLibrary2
=
()
=>
{
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/sDNList"
,
query
:
{
selectedDate
:
JSON
.
stringify
([
currentYear
+
'01-01'
,
currentYear
+
'12-31'
])
selectedDate
:
JSON
.
stringify
([
currentYear
+
"01-01"
,
currentYear
+
"12-31"
])
}
});
window
.
open
(
route
.
href
,
"_blank"
);
}
}
;
const
handleToDataLibrary3
=
(
time
)
=>
{
const
handleToDataLibrary3
=
time
=>
{
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/sDNList"
,
query
:
{
...
...
@@ -1306,8 +1314,7 @@ const handleToDataLibrary3 = (time) => {
}
});
window
.
open
(
route
.
href
,
"_blank"
);
}
};
// 点击制裁实体数量变化情况
const
handleToDataLibrary4
=
val
=>
{
...
...
@@ -1321,20 +1328,19 @@ const handleToDataLibrary4 = val => {
};
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/sDNList"
,
query
:
params
,
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
};
// 制裁实体各省分布情况
const
handleToDataLibrary5
=
item
=>
{
console
.
log
(
'item'
,
item
);
console
.
log
(
"item"
,
item
);
const
params
=
{
domains
:
item
.
seriesName
,
isCnEntityOnly
:
true
,
selectedDate
:
JSON
.
stringify
([
item
.
name
+
"-01-01"
,
item
.
name
+
"-12-31"
])
selectedDate
:
JSON
.
stringify
([
item
.
name
+
"-01-01"
,
item
.
name
+
"-12-31"
])
};
const
route
=
router
.
resolve
({
path
:
"/dataLibrary/sDNList"
,
...
...
@@ -1372,13 +1378,140 @@ const handleToDataLibrary7 = val => {
query
:
params
});
window
.
open
(
route
.
href
,
"_blank"
);
}
};
const
requestAiPaneContent
=
async
key
=>
{
if
(
!
key
||
aiPaneLoading
.
value
[
key
]
||
aiPaneFetched
.
value
[
key
])
return
;
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
true
};
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成中..."
};
try
{
const
payload
=
buildAiChartPayload
(
key
);
const
res
=
await
getChartAnalysis
(
{
text
:
JSON
.
stringify
(
payload
)
},
{
onChunk
:
chunk
=>
{
const
current
=
overviewAiContent
.
value
[
key
];
const
base
=
current
===
"智能总结生成中..."
?
""
:
current
;
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
base
+
chunk
};
}
}
);
const
list
=
res
?.
data
;
const
first
=
Array
.
isArray
(
list
)
?
list
[
0
]
:
null
;
const
interpretation
=
first
?.
解读
||
first
?.[
"解读"
];
// 流式已渲染过内容,最终用解析出的解读覆盖(保证显示格式统一)
if
(
interpretation
)
{
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
interpretation
};
}
aiPaneFetched
.
value
=
{
...
aiPaneFetched
.
value
,
[
key
]:
true
};
}
catch
(
error
)
{
console
.
error
(
"获取图表解读失败"
,
error
);
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成失败"
};
}
finally
{
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
false
};
}
};
// const sanctionCountChart = useChartInterpretation();
// const domainChart = useChartInterpretation();
// const domainNumChart = useChartInterpretation();
// const typeChart = useChartInterpretation();
const
sanctionCountChartData
=
ref
([]);
const
domainChartData
=
ref
([]);
const
domainNumChartData
=
ref
([]);
const
typeChartData
=
ref
([]);
const
aiPaneVisible
=
ref
({
sanctionCountChart
:
false
,
domainChart
:
false
,
domainNumChart
:
false
,
typeChart
:
false
});
const
overviewAiContent
=
ref
({
sanctionCountChart
:
"智能总结生成中..."
,
domainChart
:
"智能总结生成中..."
,
domainNumChart
:
"智能总结生成中..."
,
typeChart
:
"智能总结生成中..."
});
const
aiPaneFetched
=
ref
({
sanctionCountChart
:
false
,
domainChart
:
false
,
domainNumChart
:
false
,
typeChart
:
false
});
const
aiPaneLoading
=
ref
({
sanctionCountChart
:
false
,
domainChart
:
false
,
domainNumChart
:
false
,
typeChart
:
false
});
const
chartLoading
=
ref
({
sanctionCountChart
:
false
,
domainChart
:
false
,
domainNumChart
:
false
,
typeChart
:
false
});
const
buildAiChartPayload
=
key
=>
{
if
(
key
===
"sanctionCountChart"
)
{
return
{
type
:
"饼图"
,
name
:
"制裁实体数量变化情况"
,
data
:
sanctionCountChartData
.
value
};
}
if
(
key
===
"domainChart"
)
{
return
{
type
:
"饼图"
,
name
:
"制裁实体领域分布情况"
,
data
:
domainChartData
.
value
};
}
if
(
key
===
"domainNumChart"
)
{
return
{
type
:
"折线图"
,
name
:
"制裁实体领域数量变化情况"
,
data
:
domainNumChartData
.
value
};
}
if
(
key
===
"typeChart"
)
{
return
{
type
:
"饼图"
,
name
:
"制裁实体类型分布情况"
,
data
:
typeChartData
.
value
};
}
return
{
type
:
""
,
name
:
""
,
data
:
[]
};
};
const
handleShowAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
true
};
requestAiPaneContent
(
key
);
};
const
handleHideAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
false
};
};
onMounted
(()
=>
{
sanTypeId
.
value
=
route
.
query
.
sanTypeId
||
""
;
console
.
log
(
"数据统计页面接收到的 sanTypeId:"
,
sanTypeId
.
value
);
// initSanctionCountChart();
initMapChart
();
//
initMapChart();
initDomainChart
();
initTypeChart
();
// 获取实体清单-数据统计-总量统计
...
...
@@ -1386,7 +1519,7 @@ onMounted(() => {
// 获取实体清单-数据统计-制裁实体数量变化情况
getSanctionCountChangeData
();
// 获取实体清单-数据统计-制裁实体地域分布情况
getRegionCountData
();
//
getRegionCountData();
// 获取实体清单-数据统计-制裁实体领域分布情况
getDomainCountData
();
// 获取实体清单-数据统计-制裁实体类型分布情况
...
...
src/views/finance/entityList/components/deepMining/components/constrainedAssociation.vue
浏览文件 @
d2be76a4
...
...
@@ -114,7 +114,7 @@
</div>
</div>
</div>
<div
class=
"content-item"
>
<div
class=
"content-item
content-item-table
"
>
<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"
>
...
...
@@ -1040,10 +1040,11 @@ onMounted(() => {
top
:
20px
;
right
:
20px
;
}
.content-item
{
display
:
flex
;
justify-content
:
flex-start
;
align-items
:
flex-start
;
align-items
:
center
;
gap
:
8px
;
.item-label
{
min-width
:
75px
;
...
...
@@ -1109,5 +1110,9 @@ onMounted(() => {
}
}
}
.content-item-table
{
align-items
:
flex-start
;
}
}
</
style
>
src/views/finance/entityList/components/sanctionsOverview/components/introductionPage/index.vue
浏览文件 @
d2be76a4
...
...
@@ -29,50 +29,7 @@
</AnalysisBox>
</div>
<div
class=
"left-bottom"
>
<!--
<div
class=
"title"
>
<div
class=
"box"
></div>
<div
class=
"text"
>
实体清单更新历史
</div>
<div
class=
"filters"
>
<el-select
v-model=
"selectedDomain"
placeholder=
"Select"
style=
"width: 150px; height: 32px; margin-right: 16px"
>
<el-option
v-for=
"item in domainOptions"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
<el-checkbox
v-model=
"onlyChina"
>
只看涉华动态
</el-checkbox>
</div>
<div
class=
"btn"
>
<img
src=
"../../../../assets/下载按钮.png"
alt=
""
/>
<img
src=
"../../../../assets/收藏按钮.png"
alt=
""
/>
</div>
</div>
<div
class=
"left-bottom-main"
>
<div
class=
"sanction-list"
v-for=
"item in sanctionList"
:key=
"item.id"
>
<div
class=
"time"
>
<div
class=
"year"
>
{{
item
.
year
}}
</div>
<div
class=
"date"
>
{{
item
.
date
}}
</div>
</div>
<img
:src=
"item.icon || title"
alt=
""
/>
<div
class=
"main"
>
<div
class=
"main-title"
@
click=
"handleClick(item)"
>
{{
item
.
name
}}
</div>
<el-tooltip
effect=
"dark"
:content=
"item.summary"
popper-class=
"common-prompt-popper"
placement=
"top"
:show-after=
"500"
>
<div
class=
"main-desc"
>
{{
item
.
summary
}}
</div>
</el-tooltip>
<div
class=
"tag-box"
>
<div
v-for=
"tag in item.techDomainList"
:key=
"tag"
class=
"tag-item"
>
{{
tag
}}
</div>
</div>
<div
:class=
"
{ 'count-tag': item.cnEntityCount }">
{{
item
.
cnEntityCount
?
`${item.cnEntityCount
}
家中国实体`
:
""
}}
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
div
class
=
"left-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"
/>
<
/div> --
>
<
AnalysisBox
title
=
"实体清单更新历史"
:
showAllBtn
=
"false"
>
<AnalysisBox
:title=
"route.query.sanTypeId == 3 ? 'CMC清单更新历史' : 'SDN清单更新历史'"
:showAllBtn=
"false"
>
<template
#
header-btn
>
<div
class=
"filters"
>
<el-select
...
...
@@ -532,7 +489,12 @@ onMounted(() => {
.left-bottom
{
width
:
100%
;
min-height
:
1000px
;
.filters
{
margin-left
:
auto
;
display
:
flex
;
align-items
:
center
;
margin-right
:
20px
;
}
.title
{
border-bottom
:
1px
solid
rgb
(
234
,
236
,
238
);
...
...
@@ -557,7 +519,17 @@ onMounted(() => {
width
:
1169px
;
padding
:
0px
0
12px
0
;
display
:
flex
;
position
:
relative
;
&
:not
(
:last-child
)
::after
{
content
:
""
;
position
:
absolute
;
left
:
130px
;
top
:
44px
;
bottom
:
-14px
;
width
:
2px
;
background-color
:
rgb
(
234
,
236
,
238
);
z-index
:
1
;
}
// justify-content: flex-start;
.time
{
width
:
100px
;
...
...
@@ -697,6 +669,7 @@ onMounted(() => {
display
:
flex
;
margin-bottom
:
20px
;
padding
:
16px
;
align-items
:
center
;
img
{
width
:
64px
;
...
...
@@ -724,7 +697,7 @@ onMounted(() => {
.right-main-key-person
{
width
:
100%
;
padding
-
bottom
:
20
px
;
//
padding-bottom: 20px;
border-bottom
:
1px
solid
rgb
(
234
,
236
,
238
);
margin-bottom
:
18px
;
...
...
src/views/finance/entityList/components/sanctionsOverview/components/listPage/RuleSubsidiaryDialog.vue
浏览文件 @
d2be76a4
...
...
@@ -79,6 +79,7 @@
<
script
setup
>
import
{
ref
,
computed
,
watch
}
from
"vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
router
from
"@/router"
;
import
{
Close
}
from
"@element-plus/icons-vue"
;
import
defaultIcon
from
"@/assets/icons/default-icon1.png"
;
...
...
@@ -156,6 +157,10 @@ const getTagStyle = tag => {
const
handleCompClick
=
item
=>
{
console
.
log
(
"item"
,
item
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
||
item
.
orgName
);
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
gotoCompanyPages
(
item
.
id
);
};
</
script
>
...
...
src/views/finance/entityList/components/sanctionsOverview/components/listPage/index.vue
浏览文件 @
d2be76a4
...
...
@@ -63,7 +63,7 @@
</div>
</div>
<div
class=
"right"
>
<AnalysisBox
title=
"
实体清单
"
:showAllBtn=
"false"
>
<AnalysisBox
title=
"
SDN清单列表
"
:showAllBtn=
"false"
>
<template
#
header-btn
>
<div
class=
"stats"
>
<div
class=
"dot"
></div>
...
...
@@ -178,12 +178,14 @@
<
script
setup
>
import
{
ref
,
computed
,
onMounted
,
watch
}
from
"vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
{
useRouter
}
from
"vue-router"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
TimeSortSelectBox
from
"@/components/base/TimeSortSelectBox/index.vue"
;
import
defaultIcon
from
"../../../../../assets/icons/default-avatar.png"
;
import
RuleSubsidiaryDialog
from
"./RuleSubsidiaryDialog.vue"
;
import
{
getExportControlList
,
get50PercentEntityCount
}
from
"@/api/exportControlV2.0.js"
;
import
{
getEntityTypeList
}
from
"@/api/finance/index.js"
;
import
CommonPrompt
from
"@/views/exportControl/commonPrompt/index.vue"
;
import
{
useGotoCompanyPages
}
from
"@/router/modules/company"
;
const
gotoCompanyPages
=
useGotoCompanyPages
();
...
...
@@ -205,7 +207,10 @@ const handleCompClick = item => {
// }
// });
// window.open(route.href, "_blank");
if
(
!
item
.
entityId
)
return
;
if
(
!
item
.
entityId
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
gotoCompanyPages
(
item
.
entityId
);
};
...
...
@@ -470,6 +475,22 @@ watch(searchKeyword, () => {
const
sanTypeId
=
ref
(
""
);
onMounted
(()
=>
{
sanTypeId
.
value
=
router
.
currentRoute
.
value
.
query
.
sanTypeId
||
"1"
;
console
.
log
(
"sanTypeId.value"
,
sanTypeId
.
value
);
if
(
sanTypeId
.
value
==
"3"
)
{
getEntityTypeList
().
then
(
res
=>
{
console
.
log
(
"实体类型列表"
,
res
);
if
(
res
.
length
>
0
)
{
entityTypes
.
value
=
[
{
label
:
"全部类型"
,
value
:
"all"
,
checked
:
true
},
...
res
.
map
(
item
=>
({
label
:
item
.
name
,
value
:
item
.
id
,
checked
:
false
}))
];
}
});
}
getExportControlListApi
();
});
...
...
src/views/finance/entityList/components/sanctionsOverview/index.vue
浏览文件 @
d2be76a4
...
...
@@ -14,10 +14,10 @@
</div>
<div
class=
"content-box"
>
<introductionPage
v-show=
"activeIndex ==
1
"
v-show=
"activeIndex ==
0
"
@
update-entity-info=
"data => $emit('update-entity-info', data)"
></introductionPage>
<listPage
v-show=
"activeIndex ==
0
"
></listPage>
<listPage
v-show=
"activeIndex ==
1
"
></listPage>
</div>
</div>
</
template
>
...
...
@@ -26,10 +26,13 @@
import
{
ref
,
defineEmits
}
from
"vue"
;
import
introductionPage
from
"./components/introductionPage/index.vue"
;
import
listPage
from
"./components/listPage/index.vue"
;
import
{
useRoute
}
from
"vue-router"
;
const
route
=
useRoute
();
console
.
log
(
"路由参数"
,
route
.
query
.
sanTypeId
);
const
emit
=
defineEmits
([
"update-entity-info"
]);
const
activeTab
=
ref
(
[
"SDN清单列表"
,
"SDN清单简介
"
]);
const
activeTab
=
ref
(
route
.
query
.
sanTypeId
==
3
?
[
"CMC清单简介"
,
"CMC清单列表"
]
:
[
"SDN清单简介"
,
"SDN清单列表
"
]);
const
activeIndex
=
ref
(
0
);
const
handleClickTab
=
index
=>
{
...
...
@@ -39,10 +42,6 @@ const handleClickTab = index => {
</
script
>
<
style
scoped
lang=
"scss"
>
*
{
margin
:
0
;
padding
:
0
;
}
.sanctions-overview
{
width
:
1601px
;
margin
:
0
auto
;
...
...
src/views/finance/entityList/index.vue
浏览文件 @
d2be76a4
...
...
@@ -124,7 +124,7 @@ const headerNavList = ref([
height
:
148px
;
background-color
:
#fff
;
padding-top
:
16px
;
position
:
sticky
;
//
position: sticky;
top
:
0
;
z-index
:
1000
;
box-shadow
:
0px
4px
10px
rgba
(
0
,
0
,
0
,
0
.05
);
...
...
src/views/finance/index.vue
浏览文件 @
d2be76a4
...
...
@@ -76,13 +76,7 @@
</div>
<div
class=
"box1-top-content-item"
>
<span
class=
"box1-top-content-item-title"
>
· 涉及领域:
</span>
<!--
<div
class=
"box1-top-content-item-tags"
v-for=
"(domainItem, index) in item.domains"
:key=
"index"
>
<el-tag
:type=
"getTagType(domainItem)"
>
{{
domainItem
}}
</el-tag>
</div>
-->
<AreaTag
v-for=
"(domainItem, index) in item.domains"
:key=
"index"
...
...
@@ -150,21 +144,7 @@
<el-row
:gutter=
"16"
style=
"width: 1600px; margin: 0 auto; height: 50px; margin-top: 64px"
>
<CustomTitle
id=
"position2"
title=
"资讯要闻"
/>
</el-row>
<!-- <el-col :span="12">
<custom-container title="新闻资讯" :titleIcon="newsIcon" height="450px">
<template #header-right>
<el-button type="primary" link @click="handleToMoreNews">
{{ "更多 +" }}
</el-button>
</template>
<template #default>
<div class="news-list">
<NewsList :list-data="newsList" @item-click="item => handleNewsInfoClick(item)" />
</div>
</template>
</custom-container>
</el-col> -->
<div
class=
"center-center"
>
<NewsList
:newsList=
"newsList"
...
...
@@ -756,6 +736,7 @@
import
NewsList
from
"@/components/base/newsList/index.vue"
;
import
RiskSignal
from
"@/components/base/riskSignal/index.vue"
;
import
RiskSignalOverviewDetailDialog
from
"@/components/base/RiskSignalOverviewDetailDialog/index.vue"
;
import
{
ElMessage
}
from
"element-plus"
;
import
{
onMounted
,
ref
,
computed
,
reactive
,
shallowRef
,
watch
,
nextTick
}
from
"vue"
;
import
{
useContainerScroll
}
from
"@/hooks/useScrollShow"
;
import
{
getChartAnalysis
}
from
"@/api/aiAnalysis/index"
;
...
...
@@ -930,7 +911,10 @@ const handleTitleClick = item => {
const
handleCompClick
=
item
=>
{
// console.log("item", item);
if
(
!
item
.
entityId
)
return
;
if
(
!
item
.
entityId
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
);
gotoCompanyPages
(
item
.
entityId
);
// const route = router.resolve({
...
...
@@ -1071,7 +1055,10 @@ const processYearDomainCountData = yearDomainCountData => {
const
handleEntityClick
=
item
=>
{
console
.
log
(
"item"
,
item
);
if
(
!
item
.
id
)
return
;
if
(
!
item
.
id
)
{
ElMessage
.
warning
(
"暂无对应数据"
);
return
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
orgName
||
item
.
orgNameZh
);
gotoCompanyPages
(
item
.
id
);
// const route = router.resolve({
...
...
@@ -1139,6 +1126,8 @@ const handleToEntityList = item => {
// 跳转到V2.0实体清单无ID
const
handleToEntityListNoId
=
item
=>
{
console
.
log
(
"item"
,
item
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
id
==
2
?
"SDN制裁清单概览"
:
"CMC清单概览"
);
const
routeData
=
router
.
resolve
({
path
:
"/finance/sdnlistoverview"
,
query
:
{
...
...
src/views/finance/singleSanction/components/dataStatistics/index.vue
浏览文件 @
d2be76a4
...
...
@@ -54,18 +54,27 @@
</div>
</div>
</div>
-->
<EChart
:option=
"domainChartOption"
autoresize
:style=
"
{ height: '300px', padding: '0 20px' }" @chart-click="handleToDataLibrary3" />
<EChart
:option=
"domainChartOption"
autoresize
:style=
"
{ height: '300px', padding: '0 20px' }"
@chart-click="handleToDataLibrary3"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
进入本次SDN清单的中国实体领域分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
<div
class=
"data-origin-text"
>
数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"domainChart.interpretation"
/>
<!--
<AiButton
/>
<AiPane
:aiContent=
"domainChart.interpretation"
/>
-->
<AiButton
@
mouseenter=
"handleShowAiPane('domainChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.domainChart"
:aiContent=
"overviewAiContent.domainChart"
@
mouseleave=
"handleHideAiPane('domainChart')"
/>
</div>
</AnalysisBox>
</div>
...
...
@@ -106,32 +115,49 @@
</div>
</div>
</div>
-->
<EChart
:option=
"typeChartOption"
autoresize
:style=
"
{ height: '300px', padding: '0 20px' }" @chart-click="handleToDataLibrary4" />
<EChart
:option=
"typeChartOption"
autoresize
:style=
"
{ height: '300px', padding: '0 20px' }"
@chart-click="handleToDataLibrary4"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
进入本次SDN清单的中国实体类型分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
<div
class=
"data-origin-text"
>
数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"typeChart.interpretation"
/>
<!--
<AiButton
/>
<AiPane
:aiContent=
"typeChart.interpretation"
/>
-->
<AiButton
@
mouseenter=
"handleShowAiPane('typeChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.typeChart"
:aiContent=
"overviewAiContent.typeChart"
@
mouseleave=
"handleHideAiPane('typeChart')"
/>
</div>
</AnalysisBox>
</div>
<div
class=
"main-item"
>
<AnalysisBox
title=
"制裁实体国家地区分布情况"
>
<div
class=
"country-list"
>
<div
class=
"list-item"
v-for=
"(item, index) in countryDistribution"
:key=
"index"
@
click=
"handleToDataLibrary5(item)"
>
<div
class=
"list-item"
v-for=
"(item, index) in countryDistribution"
:key=
"index"
@
click=
"handleToDataLibrary5(item)"
>
<img
:src=
"flag"
alt=
""
class=
"flag"
/>
<div
class=
"country-name"
>
{{
item
.
name
}}
</div>
<div
class=
"progress-bar-container"
>
<div
class=
"progress-bar"
:style=
"
{
<div
class=
"progress-bar"
:style=
"
{
width: item.width,
background: item.gradient
}">
</div>
}"
>
</div>
</div>
<div
class=
"count"
:class=
"
{ highlight: index === 0 }">
{{
item
.
count
}}
家
</div>
</div>
...
...
@@ -151,13 +177,17 @@
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
进入本次SDN清单的实体国家地区分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
<div
class=
"data-origin-text"
>
数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"countryDistributionChart.interpretation"
/>
<!--
<AiButton
/>
<AiPane
:aiContent=
"countryDistributionChart.interpretation"
/>
-->
<AiButton
@
mouseenter=
"handleShowAiPane('countryDistributionChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.countryDistributionChart"
:aiContent=
"overviewAiContent.countryDistributionChart"
@
mouseleave=
"handleHideAiPane('countryDistributionChart')"
/>
</div>
</AnalysisBox>
</div>
...
...
@@ -166,41 +196,45 @@
<div
class=
"map-wrapper"
>
<div
class=
"map-chart"
ref=
"mapChartRef"
></div>
<div
class=
"rank-list"
>
<div
class=
"rank-item"
v-for=
"(item, index) in regionDistribution"
:key=
"index"
@
click=
"handleToDataLibrary6(item)"
>
<div
class=
"rank-list-if"
v-if=
"regionDistribution.length > 0"
>
<div
class=
"rank-item"
v-for=
"(item, index) in regionDistribution"
:key=
"index"
@
click=
"handleToDataLibrary6(item)"
>
<div
class=
"rank-index"
:class=
"'rank-' + (index + 1)"
>
{{
index
+
1
}}
</div>
<div
class=
"rank-name"
>
{{
item
.
name
}}
</div>
<div
class=
"rank-bar-bg"
>
<div
class=
"rank-bar-fill"
:style=
"
{
<div
class=
"rank-bar-fill"
:style=
"
{
width: (maxRegionCount > 0 ? (item.count / maxRegionCount) * 100 : 0) + '%',
background: getBarColor(index)
}">
</div>
}"
>
</div>
</div>
<div
class=
"rank-value"
>
{{
item
.
count
}}
家
</div>
</div>
</div>
</div>
<!--
<div
class=
"bottom"
>
<div
class=
"ai"
>
<div
class=
"left"
>
<img
:src=
"ai"
alt=
""
class=
"icon1"
/>
<div
class=
"text"
>
我国被制裁实体多分布于沿海经济活跃省份。
</div>
</div>
<div
class=
"right"
>
<img
:src=
"right"
alt=
""
class=
"icon2"
/>
<el-empty
v-else
:style=
"
{ height: '90%' }" />
</div>
</div>
</div>
-->
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
</div>
<div
class=
"data-origin-text"
>
进入本次SDN清单的中国实体各省分布情况,数据来源:美国财政部海外资产管理办公室官网
</div>
<div
class=
"data-origin-text"
>
数据来源:美国财政部海外资产管理办公室官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"regionDistributionChart.interpretation"
/>
<!--
<AiButton
/>
<AiPane
:aiContent=
"regionDistributionChart.interpretation"
/>
-->
<AiButton
@
mouseenter=
"handleShowAiPane('regionDistributionChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.regionDistributionChart"
:aiContent=
"overviewAiContent.regionDistributionChart"
@
mouseleave=
"handleHideAiPane('regionDistributionChart')"
/>
</div>
</AnalysisBox>
</div>
...
...
@@ -227,13 +261,13 @@ import {
getSingleSanctionEntityCountryCount
,
getSingleSanctionEntityRegionCount
}
from
"@/api/exportControlV2.0"
;
import
{
getChartAnalysis
}
from
"@/api/aiAnalysis/index"
;
import
{
useChartInterpretation
}
from
"@/views/exportControl/utils/common"
;
const
sanctionCountChart
=
useChartInterpretation
();
const
domainChart
=
useChartInterpretation
();
const
typeChart
=
useChartInterpretation
();
const
countryDistributionChart
=
useChartInterpretation
();
const
regionDistributionChart
=
useChartInterpretation
();
// const domainChart = useChartInterpretation();
// const typeChart = useChartInterpretation();
// const countryDistributionChart = useChartInterpretation();
// const regionDistributionChart = useChartInterpretation();
const
route
=
useRoute
();
// 单次制裁-数据统计-制裁实体地域分布情况
...
...
@@ -252,8 +286,9 @@ const getRegionData = async () => {
if
(
res
.
code
===
200
)
{
regionDistribution
.
value
=
res
.
data
||
[];
maxRegionCount
.
value
=
Math
.
max
(...
regionDistribution
.
value
.
map
(
item
=>
item
.
count
),
0
);
regionDistributionChartData
.
value
=
res
.
data
||
[];
initMapChart
();
regionDistributionChart
.
interpret
({
type
:
"柱状图"
,
name
:
"进入本次实体清单的中国实体各省分布情况"
,
data
:
res
.
data
});
//
regionDistributionChart.interpret({ type: "柱状图", name: "进入本次实体清单的中国实体各省分布情况", data: res.data });
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -293,11 +328,12 @@ const getCountryCount = async () => {
gradient
};
});
countryDistributionChart
.
interpret
({
type
:
"柱状图"
,
name
:
"进入本次实体清单的实体国家地区分布情况"
,
data
:
res
.
data
});
countryDistributionChartData
.
value
=
res
.
data
||
[];
// countryDistributionChart.interpret({
// type: "柱状图",
// name: "进入本次实体清单的实体国家地区分布情况",
// data: res.data
// });
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -318,7 +354,7 @@ const getEntityTypeCount = async () => {
const
res
=
await
getSingleSanctionEntityTypeCount
(
params
);
if
(
res
.
code
===
200
)
{
entityTypeCount
.
value
=
res
.
data
||
[];
typeChart
.
interpret
({
type
:
"饼图"
,
name
:
"进入本次实体清单的中国实体类型分布情况"
,
data
:
entityTypeCount
.
value
});
//
typeChart.interpret({ type: "饼图", name: "进入本次实体清单的中国实体类型分布情况", data: entityTypeCount.value });
initTypeChart
();
}
}
catch
(
error
)
{
...
...
@@ -341,7 +377,7 @@ const getDomainCount = async () => {
if
(
res
.
code
===
200
)
{
domainCount
.
value
=
res
.
data
||
[];
initDomainChart
();
domainChart
.
interpret
({
type
:
"饼图"
,
name
:
"进入本次实体清单的中国实体领域分布情况"
,
data
:
domainCount
.
value
});
//
domainChart.interpret({ type: "饼图", name: "进入本次实体清单的中国实体领域分布情况", data: domainCount.value });
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -391,14 +427,6 @@ for (let i = 2025; i >= 2000; i--) {
timeOptions
.
push
({
label
:
`
${
i
}
年`
,
value
:
`
${
i
}
`
});
}
// const countryDistribution = [
// { name: "中国", count: 24, width: "80%", gradient: "linear-gradient(90deg, rgba(205, 66, 70, 0) 0%, rgba(205, 66, 70, 1) 100%)" },
// { name: "沙特阿拉伯", count: 2, width: "60%", gradient: "linear-gradient(90deg, rgba(255, 172, 77, 0) 0%, rgba(255, 172, 77, 1) 100%)" },
// { name: "伊朗", count: 2, width: "60%", gradient: "linear-gradient(90deg, rgba(255, 172, 77, 0) 0%, rgba(255, 172, 77, 1) 100%)" },
// { name: "俄罗斯", count: 2, width: "55%", gradient: "linear-gradient(90deg, rgba(255, 172, 77, 0) 0%, rgba(255, 172, 77, 1) 100%)" },
// { name: "中国香港", count: 1, width: "40%", gradient: "linear-gradient(90deg, rgba(5, 95, 194, 0) 0%, rgba(5, 95, 194, 1) 100%)" }
// ];
const
mapChartRef
=
ref
(
null
);
const
domainChartRef
=
ref
(
null
);
const
typeChartRef
=
ref
(
null
);
...
...
@@ -826,7 +854,7 @@ const sanTypeId = ref("");
// 跳转到数据资源库
const
handleToDataLibrary
=
()
=>
{
const
dateStr
=
route
.
query
.
date
?
route
.
query
.
date
:
''
const
dateStr
=
route
.
query
.
date
?
route
.
query
.
date
:
""
;
const
curRoute
=
router
.
resolve
({
path
:
"/dataLibrary/sDNList"
,
query
:
{
...
...
@@ -835,10 +863,10 @@ const handleToDataLibrary = () => {
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
}
;
const
handleToDataLibrary1
=
()
=>
{
const
dateStr
=
route
.
query
.
date
?
route
.
query
.
date
:
''
const
dateStr
=
route
.
query
.
date
?
route
.
query
.
date
:
""
;
const
curRoute
=
router
.
resolve
({
path
:
"/dataLibrary/sDNList"
,
query
:
{
...
...
@@ -848,78 +876,200 @@ const handleToDataLibrary1 = () => {
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
}
;
const
handleToDataLibrary2
=
()
=>
{
const
dateStr
=
route
.
query
.
date
?
route
.
query
.
date
:
''
const
dateStr
=
route
.
query
.
date
?
route
.
query
.
date
:
""
;
const
curRoute
=
router
.
resolve
({
path
:
"/dataLibrary/sDNList"
,
query
:
{
selectedDate
:
JSON
.
stringify
([
dateStr
,
dateStr
]),
isCnEntityOnly
:
true
,
isCnEntityOnly
:
true
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
}
;
// 制裁实体领域分布情况
const
handleToDataLibrary3
=
(
val
)
=>
{
const
handleToDataLibrary3
=
val
=>
{
// console.log('val', val);
const
params
=
{
domains
:
val
.
name
,
isCnEntityOnly
:
true
,
selectedDate
:
JSON
.
stringify
([
route
.
query
.
date
,
route
.
query
.
date
])
}
}
;
const
curRoute
=
router
.
resolve
({
path
:
'/dataLibrary/sDNList'
,
path
:
"/dataLibrary/sDNList"
,
query
:
params
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
}
;
// 制裁实体类型分布情况
const
handleToDataLibrary4
=
(
val
)
=>
{
const
handleToDataLibrary4
=
val
=>
{
// console.log('val', val);
const
params
=
{
selectedEntityType
:
val
.
name
,
isCnEntityOnly
:
true
,
selectedDate
:
JSON
.
stringify
([
route
.
query
.
date
,
route
.
query
.
date
])
}
}
;
const
curRoute
=
router
.
resolve
({
path
:
'/dataLibrary/sDNList'
,
path
:
"/dataLibrary/sDNList"
,
query
:
params
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
}
;
// 制裁实体国家地区分布情况
const
handleToDataLibrary5
=
(
item
)
=>
{
const
handleToDataLibrary5
=
item
=>
{
const
params
=
{
selectedCountryId
:
item
.
id
,
isCnEntityOnly
:
true
,
selectedDate
:
JSON
.
stringify
([
route
.
query
.
date
,
route
.
query
.
date
])
}
}
;
const
curRoute
=
router
.
resolve
({
path
:
'/dataLibrary/sDNList'
,
path
:
"/dataLibrary/sDNList"
,
query
:
params
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
}
;
// 制裁实体各省分布情况
const
handleToDataLibrary6
=
(
item
)
=>
{
console
.
log
(
'item'
,
item
);
const
handleToDataLibrary6
=
item
=>
{
console
.
log
(
"item"
,
item
);
const
params
=
{
selectedProvince
:
item
.
name
,
isCnEntityOnly
:
true
,
selectedDate
:
JSON
.
stringify
([
route
.
query
.
date
,
route
.
query
.
date
])
}
}
;
const
curRoute
=
router
.
resolve
({
path
:
'/dataLibrary/sDNList'
,
path
:
"/dataLibrary/sDNList"
,
query
:
params
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
}
};
const
requestAiPaneContent
=
async
key
=>
{
if
(
!
key
||
aiPaneLoading
.
value
[
key
]
||
aiPaneFetched
.
value
[
key
])
return
;
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
true
};
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成中..."
};
try
{
const
payload
=
buildAiChartPayload
(
key
);
const
res
=
await
getChartAnalysis
(
{
text
:
JSON
.
stringify
(
payload
)
},
{
onChunk
:
chunk
=>
{
const
current
=
overviewAiContent
.
value
[
key
];
const
base
=
current
===
"智能总结生成中..."
?
""
:
current
;
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
base
+
chunk
};
}
}
);
const
list
=
res
?.
data
;
const
first
=
Array
.
isArray
(
list
)
?
list
[
0
]
:
null
;
const
interpretation
=
first
?.
解读
||
first
?.[
"解读"
];
// 流式已渲染过内容,最终用解析出的解读覆盖(保证显示格式统一)
if
(
interpretation
)
{
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
interpretation
};
}
aiPaneFetched
.
value
=
{
...
aiPaneFetched
.
value
,
[
key
]:
true
};
}
catch
(
error
)
{
console
.
error
(
"获取图表解读失败"
,
error
);
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成失败"
};
}
finally
{
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
false
};
}
};
const
domainChartData
=
ref
([]);
const
typeChartData
=
ref
([]);
const
countryDistributionChartData
=
ref
([]);
const
regionDistributionChartData
=
ref
([]);
const
aiPaneVisible
=
ref
({
domainChart
:
false
,
typeChart
:
false
,
countryDistributionChart
:
false
,
regionDistributionChart
:
false
});
const
overviewAiContent
=
ref
({
domainChart
:
"智能总结生成中..."
,
typeChart
:
"智能总结生成中..."
,
countryDistributionChart
:
"智能总结生成中..."
,
regionDistributionChart
:
"智能总结生成中..."
});
const
aiPaneFetched
=
ref
({
domainChart
:
false
,
typeChart
:
false
,
countryDistributionChart
:
false
,
regionDistributionChart
:
false
});
const
aiPaneLoading
=
ref
({
domainChart
:
false
,
typeChart
:
false
,
countryDistributionChart
:
false
,
regionDistributionChart
:
false
});
const
chartLoading
=
ref
({
domainChart
:
false
,
typeChart
:
false
,
countryDistributionChart
:
false
,
regionDistributionChart
:
false
});
const
buildAiChartPayload
=
key
=>
{
if
(
key
===
"domainChart"
)
{
return
{
type
:
"饼图"
,
name
:
"进入本次实体清单的中国实体领域分布情况"
,
data
:
domainCount
.
value
};
}
if
(
key
===
"typeChart"
)
{
return
{
type
:
"饼图"
,
name
:
"进入本次实体清单的中国实体类型分布情况"
,
data
:
entityTypeCount
.
value
};
}
if
(
key
===
"countryDistributionChart"
)
{
return
{
type
:
"柱状图"
,
name
:
"进入本次实体清单的实体国家地区分布情况"
,
data
:
countryDistributionChartData
.
value
};
}
if
(
key
===
"regionDistributionChart"
)
{
return
{
type
:
"柱状图"
,
name
:
"进入本次实体清单的中国实体各省分布情况"
,
data
:
regionDistributionChartData
.
value
};
}
return
{
type
:
""
,
name
:
""
,
data
:
[]
};
};
const
handleShowAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
true
};
requestAiPaneContent
(
key
);
};
const
handleHideAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
false
};
};
onMounted
(()
=>
{
// 获取路由参数id
...
...
src/views/finance/singleSanction/components/impactAnalysis/components/industrialImpact/index.vue
浏览文件 @
d2be76a4
...
...
@@ -2,51 +2,6 @@
<div
class=
"industrial-impact"
>
<div
class=
"main"
>
<div
class=
"left"
>
<!--
<div
class=
"title-com"
>
<div
class=
"box"
></div>
<div
class=
"text"
>
制裁企业列表
</div>
<div
class=
"right-group"
>
<div
class=
"btn"
>
<img
src=
"../../../../assets/数据库按钮.png"
alt=
""
/>
<img
src=
"../../../../assets/下载按钮.png"
alt=
""
/>
<img
src=
"../../../../assets/收藏按钮.png"
alt=
""
/>
</div>
</div>
</div>
<div
class=
"left-main"
>
<div
class=
"top-bar"
>
<el-select
v-model=
"searchDomain"
placeholder=
"全部领域"
class=
"domain-select"
>
<el-option
label=
"全部领域"
value=
""
/>
<el-option
label=
"人工智能"
value=
"1"
/>
<el-option
label=
"生物科技"
value=
"2"
/>
<el-option
label=
"新一代信息技术"
value=
"3"
/>
<el-option
label=
"量子科技"
value=
"4"
/>
<el-option
label=
"新能源"
value=
"5"
/>
<el-option
label=
"集成电路"
value=
"6"
/>
<el-option
label=
"海洋"
value=
"7"
/>
<el-option
label=
"先进制造"
value=
"8"
/>
<el-option
label=
"新材料"
value=
"9"
/>
<el-option
label=
"航空航天"
value=
"10"
/>
<el-option
label=
"深海"
value=
"11"
/>
<el-option
label=
"极地"
value=
"12"
/>
<el-option
label=
"太空"
value=
"13"
/>
<el-option
label=
"核"
value=
"14"
/>
</el-select>
<el-input
v-model=
"searchKeyword"
class=
"search-input"
placeholder=
"搜索实体"
:suffix-icon=
"Search"
/>
</div>
<div
class=
"company-list-container"
>
<div
class=
"list-header"
>
企业名称
</div>
<div
class=
"company-list"
>
<div
class=
"company-item"
:class=
"
{ active: selectedCompanyId === item.id }" v-for="item in entityList"
:key="item.id" @click="selectedCompanyId = item.id">
<div
class=
"icon-wrapper"
>
<img
:src=
"defaultTitle"
alt=
""
/>
</div>
<div
class=
"company-name"
>
{{
item
.
name
}}
</div>
</div>
</div>
</div>
</div>
-->
<AnalysisBox
title=
"制裁企业列表"
>
<div
class=
"left-main"
>
<div
class=
"top-bar"
>
...
...
@@ -91,31 +46,6 @@
</div>
<div
class=
"right"
>
<div
class=
"right-item"
>
<!--
<div
class=
"title-com"
>
<div
class=
"box"
></div>
<div
class=
"text"
>
企业规模
</div>
<div
class=
"right-group"
>
<div
class=
"toggle-btns"
>
<div
class=
"t-btn"
:class=
"
{ active: activeScale === item }" v-for="item in scaleOptions" :key="item"
@click="handleScaleClick(item)">
{{
item
}}
</div>
</div>
<div
class=
"btn"
>
<img
src=
"../../../../assets/数据库按钮.png"
alt=
""
/>
<img
src=
"../../../../assets/下载按钮.png"
alt=
""
/>
<img
src=
"../../../../assets/收藏按钮.png"
alt=
""
/>
</div>
</div>
</div>
<div
class=
"right-main"
>
<div
class=
"echarts"
ref=
"chartRef"
></div>
<div
class=
"bottom"
>
<img
:src=
"ai"
class=
"ai-icon"
alt=
""
/>
<span
class=
"text"
>
列入实体清单后企业营收初期下降,后基本趋于稳定。
</span>
<img
:src=
"right"
class=
"right-icon"
alt=
""
/>
</div>
</div>
-->
<AnalysisBox
title=
"企业规模"
>
<template
#
header-btn
>
<div
class=
"toggle-btns"
>
...
...
@@ -145,32 +75,19 @@
<div
class=
"data-origin-text"
>
企业规模情况,数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"revenueChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="revenueChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('revenueChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.revenueChart"
:aiContent=
"overviewAiContent.revenueChart"
@
mouseleave=
"handleHideAiPane('revenueChart')"
/>
</div>
</div>
</AnalysisBox>
</div>
<div
class=
"right-item"
>
<!-- <div class="title-com">
<div class="box"></div>
<div class="text">企业市值变化</div>
<div class="right-group">
<div class="btn">
<img src="../../../../assets/数据库按钮.png" alt="" />
<img src="../../../../assets/下载按钮.png" alt="" />
<img src="../../../../assets/收藏按钮.png" alt="" />
</div>
</div>
</div>
<div class="right-main">
<div class="echarts" ref="marketChartRef"></div>
<div class="bottom">
<img :src="ai" class="ai-icon" alt="" />
<span class="text">列入实体清单后企业营收初期下降,后基本趋于稳定。</span>
<img :src="right" class="right-icon" alt="" />
</div>
</div> -->
<AnalysisBox
title=
"企业市值变化"
>
<div
class=
"right-main"
>
<!-- <div class="echarts" ref="marketChartRef"></div>
...
...
@@ -187,38 +104,19 @@
<div
class=
"data-origin-text"
>
企业市值变化情况,数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"marketChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="marketChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('marketChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.marketChart"
:aiContent=
"overviewAiContent.marketChart"
@
mouseleave=
"handleHideAiPane('marketChart')"
/>
</div>
</div>
</AnalysisBox>
</div>
<div
class=
"right-item"
>
<!-- <div class="title-com">
<div class="box"></div>
<div class="text">企业研发投入</div>
<div class="right-group">
<div class="toggle-btns">
<div class="t-btn" :class="{ active: activeRD === item }" v-for="item in rdOptions" :key="item"
@click="activeRD = item">
{{ item }}
</div>
</div>
<div class="btn">
<img src="../../../../assets/数据库按钮.png" alt="" />
<img src="../../../../assets/下载按钮.png" alt="" />
<img src="../../../../assets/收藏按钮.png" alt="" />
</div>
</div>
</div>
<div class="right-main">
<div class="echarts" ref="rdChartRef"></div>
<div class="bottom">
<img :src="ai" class="ai-icon" alt="" />
<span class="text">列入实体清单后企业研发资金投入逐渐提高。</span>
<img :src="right" class="right-icon" alt="" />
</div>
</div> -->
<AnalysisBox
title=
"企业研发投入"
>
<
template
#
header-btn
>
<div
class=
"toggle-btns"
>
...
...
@@ -248,38 +146,19 @@
<div
class=
"data-origin-text"
>
企业研发投入情况,数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"rdChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="rdChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('rdChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.rdChart"
:aiContent=
"overviewAiContent.rdChart"
@
mouseleave=
"handleHideAiPane('rdChart')"
/>
</div>
</div>
</AnalysisBox>
</div>
<div
class=
"right-item"
>
<!-- <div class="title-com">
<div class="box"></div>
<div class="text">企业市场占比</div>
<div class="right-group">
<div class="toggle-btns">
<div class="t-btn" :class="{ active: activeMarketShare === item }" v-for="item in marketShareOptions"
:key="item" @click="activeMarketShare = item">
{{ item }}
</div>
</div>
<div class="btn">
<img src="../../../../assets/数据库按钮.png" alt="" />
<img src="../../../../assets/下载按钮.png" alt="" />
<img src="../../../../assets/收藏按钮.png" alt="" />
</div>
</div>
</div>
<div class="right-main">
<div class="echarts" ref="shareChartRef"></div>
<div class="bottom">
<img :src="ai" class="ai-icon" alt="" />
<span class="text">列入实体清单后企业营收初期下降,后基本趋于稳定。</span>
<img :src="right" class="right-icon" alt="" />
</div>
</div> -->
<AnalysisBox
title=
"企业市场占比"
>
<
template
#
header-btn
>
<div
class=
"toggle-btns"
>
...
...
@@ -309,8 +188,14 @@
<div
class=
"data-origin-text"
>
企业市场占比情况,数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"shareChart.interpretation"
/>
<!-- <AiButton />
<AiPane :aiContent="shareChart.interpretation" /> -->
<AiButton
@
mouseenter=
"handleShowAiPane('shareChart')"
/>
<AiPane
v-if=
"aiPaneVisible?.shareChart"
:aiContent=
"overviewAiContent.shareChart"
@
mouseleave=
"handleHideAiPane('shareChart')"
/>
</div>
</div>
</AnalysisBox>
...
...
@@ -326,8 +211,6 @@ import { debounce } from "lodash";
import
*
as
echarts
from
"echarts"
;
import
{
Search
}
from
"@element-plus/icons-vue"
;
import
defaultTitle
from
"../../../../assets/default-icon2.png"
;
import
ai
from
"../../assets/ai.png"
;
import
right
from
"../../assets/right.png"
;
import
tipsIcon
from
"../../../../../assets/icons/info-icon.png"
;
import
{
...
...
@@ -339,6 +222,7 @@ import {
getSingleSanctionEntityRDInvestment
,
getSingleSanctionEntityMarketShare
}
from
"@/api/exportControlV2.0"
;
import
{
getChartAnalysis
}
from
"@/api/aiAnalysis/index"
;
import
AiButton
from
"@/components/base/Ai/AiButton/index.vue"
;
import
AiPane
from
"@/components/base/Ai/AiPane/index.vue"
;
import
EChart
from
"@/components/Chart/index.vue"
;
...
...
@@ -373,7 +257,8 @@ const getMarketShare = async () => {
nextTick
(()
=>
{
initShareChart
();
});
shareChart
.
interpret
({
type
:
"柱状图"
,
name
:
"企业市场占比"
,
data
:
sortedData
});
// shareChart.interpret({ type: "柱状图", name: "企业市场占比", data: sortedData });
shareChartData1
.
value
=
sortedData
;
}
}
}
catch
(
error
)
{
...
...
@@ -407,7 +292,8 @@ const getRDInvestment = async () => {
nextTick
(()
=>
{
initRDChart
();
});
rdChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业研发投入"
,
data
:
sortedData
});
// rdChart.interpret({ type: "折线图", name: "企业研发投入", data: sortedData });
rdChartData1
.
value
=
sortedData
;
}
}
}
catch
(
error
)
{
...
...
@@ -441,7 +327,8 @@ const getMarketValue = async () => {
nextTick
(()
=>
{
initMarketChart
();
});
marketChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业市值变化"
,
data
:
sortedData
});
// marketChart.interpret({ type: "折线图", name: "企业市值变化", data: sortedData });
marketChartData1
.
value
=
sortedData
;
}
}
}
catch
(
error
)
{
...
...
@@ -474,7 +361,8 @@ const getPersonnel = async () => {
nextTick
(()
=>
{
initRevenueChart
();
});
revenueChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业规模"
,
data
:
sortedData
});
// revenueChart.interpret({ type: "折线图", name: "企业规模", data: sortedData });
revenueChartData
.
value
=
sortedData
;
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -506,7 +394,8 @@ const getNetProfitData = async () => {
nextTick
(()
=>
{
initRevenueChart
();
});
revenueChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业规模"
,
data
:
sortedData
});
// revenueChart.interpret({ type: "折线图", name: "企业规模", data: sortedData });
revenueChartData
.
value
=
sortedData
;
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -543,7 +432,8 @@ const getRevenueData = async () => {
nextTick
(()
=>
{
initRevenueChart
();
});
revenueChart
.
interpret
({
type
:
"折线图"
,
name
:
"企业规模"
,
data
:
sortedData
});
// revenueChart.interpret({ type: "折线图", name: "企业规模", data: sortedData });
revenueChartData
.
value
=
sortedData
;
}
}
catch
(
error
)
{
console
.
log
(
error
);
...
...
@@ -700,6 +590,12 @@ const getBaseOption = data => {
yAxis
:
{
type
:
"value"
,
min
:
0
,
name
:
"数量"
,
nameTextStyle
:
{
padding
:
[
-
10
,
0
,
0
,
-
30
],
// [上, 右, 下, 左],负数向左移,正数向右移
align
:
"left"
,
// 可选: 'left', 'center', 'right'
verticalAlign
:
"top"
// 可选: 'top', 'middle', 'bottom'
},
splitNumber
:
5
,
axisLabel
:
{
color
:
"#606266"
,
...
...
@@ -933,6 +829,11 @@ const initShareChart = () => {
option
.
xAxis
.
axisLabel
.
interval
=
"auto"
;
// 自动计算间隔,避免标签重叠导致柱子变细
option
.
yAxis
.
name
=
"百分比"
;
option
.
yAxis
.
nameTextStyle
=
{
padding
:
[
-
10
,
0
,
0
,
-
45
],
// [上, 右, 下, 左],负数向左移,正数向右移
align
:
"left"
,
// 可选: 'left', 'center', 'right'
verticalAlign
:
"top"
// 可选: 'top', 'middle', 'bottom'
};
// 动态计算 Y 轴最大值,避免数据太小时展示不明显
const
maxVal
=
Math
.
max
(...
data
.
values
);
const
maxY
=
maxVal
===
0
?
100
:
maxVal
*
1.5
;
...
...
@@ -977,6 +878,128 @@ const initShareChart = () => {
shareChartOption
.
value
=
option
;
};
const
requestAiPaneContent
=
async
key
=>
{
if
(
!
key
||
aiPaneLoading
.
value
[
key
]
||
aiPaneFetched
.
value
[
key
])
return
;
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
true
};
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成中..."
};
try
{
const
payload
=
buildAiChartPayload
(
key
);
const
res
=
await
getChartAnalysis
(
{
text
:
JSON
.
stringify
(
payload
)
},
{
onChunk
:
chunk
=>
{
const
current
=
overviewAiContent
.
value
[
key
];
const
base
=
current
===
"智能总结生成中..."
?
""
:
current
;
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
base
+
chunk
};
}
}
);
const
list
=
res
?.
data
;
const
first
=
Array
.
isArray
(
list
)
?
list
[
0
]
:
null
;
const
interpretation
=
first
?.
解读
||
first
?.[
"解读"
];
// 流式已渲染过内容,最终用解析出的解读覆盖(保证显示格式统一)
if
(
interpretation
)
{
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
interpretation
};
}
aiPaneFetched
.
value
=
{
...
aiPaneFetched
.
value
,
[
key
]:
true
};
}
catch
(
error
)
{
console
.
error
(
"获取图表解读失败"
,
error
);
overviewAiContent
.
value
=
{
...
overviewAiContent
.
value
,
[
key
]:
"智能总结生成失败"
};
}
finally
{
aiPaneLoading
.
value
=
{
...
aiPaneLoading
.
value
,
[
key
]:
false
};
}
};
const
revenueChartData
=
ref
([]);
const
marketChartData1
=
ref
([]);
const
rdChartData1
=
ref
([]);
const
shareChartData1
=
ref
([]);
const
aiPaneVisible
=
ref
({
revenueChart
:
false
,
marketChart
:
false
,
rdChart
:
false
,
shareChart
:
false
});
const
overviewAiContent
=
ref
({
revenueChart
:
"智能总结生成中..."
,
marketChart
:
"智能总结生成中..."
,
rdChart
:
"智能总结生成中..."
,
shareChart
:
"智能总结生成中..."
});
const
aiPaneFetched
=
ref
({
revenueChart
:
false
,
marketChart
:
false
,
rdChart
:
false
,
shareChart
:
false
});
const
aiPaneLoading
=
ref
({
revenueChart
:
false
,
marketChart
:
false
,
rdChart
:
false
,
shareChart
:
false
});
const
chartLoading
=
ref
({
revenueChart
:
false
,
marketChart
:
false
,
rdChart
:
false
,
shareChart
:
false
});
const
buildAiChartPayload
=
key
=>
{
if
(
key
===
"revenueChart"
)
{
return
{
type
:
"折线图"
,
name
:
"企业规模"
,
data
:
revenueChartData
.
value
};
}
if
(
key
===
"marketChart"
)
{
return
{
type
:
"折线图"
,
name
:
"企业市场占比"
,
data
:
marketChartData1
.
value
};
}
if
(
key
===
"rdChart"
)
{
return
{
type
:
"折线图"
,
name
:
"企业研发投入"
,
data
:
rdChartData1
.
value
};
}
if
(
key
===
"shareChart"
)
{
return
{
type
:
"折线图"
,
name
:
"企业市场份额"
,
data
:
shareChartData1
.
value
};
}
return
{
type
:
""
,
name
:
""
,
data
:
[]
};
};
const
handleShowAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
true
};
requestAiPaneContent
(
key
);
};
const
handleHideAiPane
=
key
=>
{
aiPaneVisible
.
value
=
{
...
aiPaneVisible
.
value
,
[
key
]:
false
};
};
onMounted
(
async
()
=>
{
getUrlParams
();
// 单次制裁-影响分析-制裁企业列表-查询 (获取到默认的 selectedCompanyId 后会触发 watch 加载其他数据)
...
...
src/views/finance/singleSanction/components/sanctionsOverview/index.vue
浏览文件 @
d2be76a4
...
...
@@ -37,7 +37,12 @@
<div
class=
"left-top-content"
>
<div
class=
"content-title"
>
新闻链接:
</div>
<div
class=
"distribution-list"
>
<div
class=
"list-item news-item"
v-for=
"item in newsList"
:key=
"item.newsId"
>
<div
class=
"list-item news-item"
v-for=
"item in newsList"
:key=
"item.newsId"
@
click=
"handleNewsClick(item.newsId)"
>
<div
class=
"item-title"
>
{{
item
.
newsTitle
}}
</div>
<img
:src=
"openIcon"
class=
"flag"
/>
</div>
...
...
@@ -81,11 +86,19 @@
<div
class=
"content"
>
{{
item
.
content
}}
</div>
</div>
</div>
<div
class=
"view-more"
v-if=
"hasMore"
@
click=
"loadMore"
>
<
!--
<
div
class=
"view-more"
v-if=
"hasMore"
@
click=
"loadMore"
>
查看更多
<el-icon
class=
"icon-more"
>
<DArrowRight
/>
</el-icon>
</div>
-->
<div
class=
"left-bottom-footer"
>
<simple-pagination
v-model:current-page=
"timelinePage"
:page-size=
"timelinePageSize"
:total=
"totalNum"
@
page-change=
"handleListPageChange"
/>
</div>
</div>
</AnalysisBox>
...
...
@@ -165,7 +178,7 @@
<template
#
default=
"scope"
>
<div
class=
"name-cell"
>
<!--
<div
class=
"dot"
></div>
-->
<img
:src=
"defaultTitle"
class=
"company-icon"
/>
<img
:src=
"default
Org
Title"
class=
"company-icon"
/>
<span
class=
"company-name"
@
click=
"handleCompClick(scope.row)"
>
{{
scope
.
row
.
name
}}
</span>
...
...
@@ -274,8 +287,10 @@ import { useRouter } from "vue-router";
import
{
ElMessage
}
from
"element-plus"
;
import
AreaTag
from
"@/components/base/AreaTag/index.vue"
;
import
{
debounce
}
from
"lodash"
;
import
title
from
"../../assets/title.png"
;
import
defaultTitle
from
"../../assets/default-icon1.png"
;
import
defaultOrgTitle
from
"../../../assets/images/icon-entity.png"
;
import
flag
from
"../../assets/default-icon2.png"
;
import
openIcon
from
"../../../assets/icons/icon-open.png"
;
import
{
...
...
@@ -289,6 +304,8 @@ import { getReasonAndSan } from "@/api/finance";
import
{
useRoute
}
from
"vue-router"
;
import
{
useGotoCompanyPages
}
from
"@/router/modules/company"
;
import
{
useGotoNewsDetail
}
from
"@/router/modules/news"
;
const
gotoNewsDetail
=
useGotoNewsDetail
();
const
gotoCompanyPages
=
useGotoCompanyPages
();
const
route
=
useRoute
();
...
...
@@ -387,8 +404,16 @@ const getSanctionOverviewList = async () => {
// 单次制裁-制裁概况-制裁背景
const
timelinePage
=
ref
(
1
);
const
timelinePageSize
=
ref
(
5
);
const
totalNum
=
ref
(
0
);
const
hasMore
=
ref
(
true
);
const
handleListPageChange
=
pageNum
=>
{
console
.
log
(
"页面修改 =>"
,
pageNum
);
timelinePage
.
value
=
pageNum
;
getSanctionBackground
();
};
const
getSanctionBackground
=
async
(
isLoadMore
=
false
)
=>
{
try
{
const
res
=
await
getSingleSanctionBackground
({
...
...
@@ -412,6 +437,7 @@ const getSanctionBackground = async (isLoadMore = false) => {
// 判断是否还有更多数据
const
totalElements
=
res
.
data
.
totalElements
||
0
;
totalNum
.
value
=
totalElements
||
0
;
hasMore
.
value
=
timelineData
.
value
.
length
<
totalElements
;
}
}
catch
(
error
)
{
...
...
@@ -501,6 +527,10 @@ const handleClick = () => {
window
.
open
(
route
.
href
,
"_blank"
);
};
const
handleNewsClick
=
id
=>
{
gotoNewsDetail
(
id
);
};
// 计算属性处理数据
const
formattedData
=
computed
(()
=>
{
const
info
=
props
.
data
||
{};
...
...
@@ -886,7 +916,7 @@ onMounted(() => {
.left-bottom
{
width
:
100%
;
height
:
521px
;
height
:
auto
;
.left-bottom-content
{
padding
:
20px
25px
0
25px
;
...
...
@@ -1139,6 +1169,7 @@ onMounted(() => {
.domain-box
{
display
:
flex
;
justify-content
:
center
;
gap
:
8px
;
}
...
...
src/views/finance/singleSanction/index.vue
浏览文件 @
d2be76a4
...
...
@@ -2,14 +2,14 @@
<div
class=
"entity-list"
>
<div
class=
"header"
>
<div
class=
"header-title"
>
<img
:src=
"headerTitle.
img
"
alt=
""
/>
<img
:src=
"headerTitle.
postOrgLogoUrl
"
alt=
""
/>
<div>
<div
class=
"title"
>
{{
headerTitle
.
title
}}
<!--
<span>
{{
headerTitle
.
titleEn
}}
</span>
-->
</div>
<div
class=
"department"
>
{{
headerTitle
.
department
}}
{{
headerTitle
.
postOrgName
+
" · "
+
"特别指定国民清单(SDN)"
}}
</div>
</div>
<div
class=
"btn"
@
click=
"openSanctionModal"
><img
:src=
"icon01"
alt=
""
/>
切换
</div>
...
...
@@ -144,10 +144,12 @@ const getSingleSanctionOverviewData = async () => {
// 更新头部信息
headerTitle
.
value
=
{
...
headerTitle
.
value
,
...
singleSanctionOverview
.
value
,
title
:
`
${
dateStr
}
《
${
singleSanctionOverview
.
value
.
sanTitleZh
||
singleSanctionOverview
.
value
.
sanTitle
}
》`
,
titleEn
:
singleSanctionOverview
.
value
.
sanTitle
||
""
,
department
:
singleSanctionOverview
.
value
.
fileCode
||
""
};
console
.
log
(
"headerTitle.value"
,
headerTitle
.
value
);
}
}
catch
(
error
)
{
console
.
error
(
"获取制裁概况失败:"
,
error
);
...
...
@@ -284,7 +286,7 @@ onMounted(() => {
height
:
148px
;
background-color
:
#fff
;
padding-top
:
16px
;
position
:
sticky
;
//
position: sticky;
top
:
0
;
z-index
:
1000
;
box-shadow
:
0px
4px
10px
rgba
(
0
,
0
,
0
,
0
.05
);
...
...
src/views/finance/singleSanction/originPage/index.vue
浏览文件 @
d2be76a4
...
...
@@ -3,7 +3,7 @@
<div
class=
"header"
>
<div
class=
"header-top"
>
<div
class=
"header-top-left"
>
<img
:src=
"headerTitle.
img
"
alt=
""
/>
<img
:src=
"headerTitle.
postOrgLogoUrl
"
alt=
""
/>
<div>
<div
class=
"title"
>
{{
headerTitle
.
title
}}
</div>
<div
class=
"en-title"
>
...
...
@@ -22,7 +22,7 @@
</div>
<div
class=
"main"
>
<div
class=
"main-header"
>
<div>
实体
清单制裁文件
</div>
<div>
SDN
清单制裁文件
</div>
<div
class=
"btn-box"
>
<div
class=
"translate"
>
<div
class=
"search-input-wrap"
v-if=
"showSearchInput"
>
...
...
@@ -78,7 +78,7 @@
</div>
</div>
</div>
<div
class=
"report-box"
>
<div
class=
"report-box"
v-if=
"!reportUrlWithPage || !reportUrlEnWithPage"
>
<div
class=
"pdf-pane-wrap"
:class=
"
{ 'is-full': !valueSwitch }" v-if="reportUrlWithPage">
<pdf
:key=
"`right-pdf-$
{valueSwitch ? 'split' : 'full'}`"
...
...
@@ -91,6 +91,7 @@
<pdf
ref=
"leftPdfRef"
:pdfUrl=
"reportUrlEnWithPage"
class=
"pdf-pane-inner"
/>
</div>
</div>
<el-empty
v-else
/>
</div>
</div>
</
template
>
...
...
@@ -366,8 +367,8 @@ const switchTab = name => {
};
onMounted
(
async
()
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
"实体清单原文"
);
handleGetThinkTankReportSummary
();
handleGetThinkTankReportcontentUrl
();
//
handleGetThinkTankReportSummary();
//
handleGetThinkTankReportcontentUrl();
console
.
log
(
"原文展示"
);
getUrlParams
();
getSingleSanctionOverviewData
();
...
...
@@ -376,19 +377,20 @@ onMounted(async () => {
<
style
lang=
"scss"
scoped
>
.wrap
{
overflow-y
:
hidden
;
overflow-y
:
auto
;
height
:
100vh
;
display
:
flex
;
flex-direction
:
column
;
.header
{
width
:
100%
;
min-height
:
88px
;
height
:
88px
;
box-sizing
:
border-box
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
position
:
sticky
;
//
position: sticky;
top
:
0
;
z-index
:
99999
;
overflow
:
hidden
;
...
...
@@ -404,7 +406,7 @@ onMounted(async () => {
display
:
flex
;
img
{
width
:
4
4px
;
width
:
5
4px
;
height
:
54px
;
}
...
...
@@ -751,7 +753,7 @@ onMounted(async () => {
.report-box
{
margin-left
:
70px
;
width
:
1456px
;
height
:
881px
;
//
height: 881px;
display
:
flex
;
overflow-y
:
auto
;
/* 右侧统一滚动条,控制两侧原文+译文一起滚动 */
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论