Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
4e9a1efd
提交
4e9a1efd
authored
4月 10, 2026
作者:
张伊明
浏览文件
操作
浏览文件
下载
差异文件
合并分支 'zz-dev' 到 'pre'
feat:风险信号页面dialog开发,智库点击风险信号列表dialog开发,智库报告页面搜索功能修改搜索bug 查看合并请求
!330
上级
42feb66d
e8ae5570
流水线
#413
已通过 于阶段
in 1 分 34 秒
变更
19
流水线
2
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
19 个修改的文件
包含
724 行增加
和
156 行删除
+724
-156
riskSignalOverviewNavigate.js
src/utils/riskSignalOverviewNavigate.js
+26
-0
index.vue
src/views/ZMGame/component/riskToday/index.vue
+6
-8
index.vue
src/views/ZMOverView/components/newRisk/index.vue
+15
-8
index.vue
src/views/bill/billHome/index.vue
+7
-4
index.vue
src/views/coopRestriction/components/dataNew/index.vue
+7
-3
index.vue
src/views/decree/decreeHome/index.vue
+7
-4
index.vue
src/views/exportControl/index.vue
+5
-14
index.vue
src/views/finance/index.vue
+5
-14
index.vue
src/views/gjOverView/index.vue
+7
-3
index.vue
src/views/innovationSubject/index.vue
+9
-5
index.vue
...views/marketAccessRestrictions/marketAccessHome/index.vue
+7
-3
index.vue
src/views/overView/index.vue
+7
-3
index.vue
src/views/ruleRestriction/components/dataNew/index.vue
+8
-4
index.vue
src/views/scientificFunding/components/dataNew/index.vue
+8
-4
index.vue
src/views/technologyFigures/index.vue
+8
-5
index.vue
src/views/thinkTank/index.vue
+184
-6
pdf.vue
src/views/thinkTank/reportOriginal/pdf.vue
+0
-0
index.vue
src/views/viewRiskSignal/index.vue
+182
-4
cleandarHeat.js
src/views/viewRiskSignal/utils/cleandarHeat.js
+226
-64
没有找到文件。
src/utils/riskSignalOverviewNavigate.js
0 → 100644
浏览文件 @
4e9a1efd
/** 从各概览页跳转风险信号管理页,并自动打开列表第一条详情的 el-dialog */
export
const
OPEN_FIRST_RISK_DETAIL_QUERY_KEY
=
"openFirstDetail"
;
/**
* 概览页 -> 风险信号管理页(新页面打开,不弹窗)
* @param {import('vue-router').Router} router
*/
export
const
navigateToViewRiskSignal
=
(
router
)
=>
{
const
route
=
router
.
resolve
({
path
:
"/viewRiskSignal"
});
window
.
open
(
route
.
href
,
"_blank"
);
};
/**
* 概览页 -> 风险信号管理页(新页面打开,并自动打开第一条详情弹窗)
* @param {import('vue-router').Router} router
*/
export
const
navigateToViewRiskSignalOpenFirstDetail
=
(
router
)
=>
{
const
route
=
router
.
resolve
({
path
:
"/viewRiskSignal"
,
query
:
{
[
OPEN_FIRST_RISK_DETAIL_QUERY_KEY
]:
"1"
}
});
window
.
open
(
route
.
href
,
"_blank"
);
};
src/views/ZMGame/component/riskToday/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -47,8 +47,8 @@
<div
class=
"risk-signals-item"
v-for=
"(item, index) in warningList"
:key=
"index"
@
click=
"handle
ClickToDetailO(item)
"
:key=
"i
tem.signalId || item.billId || i
ndex"
@
click=
"handle
RiskSignalItemToManage
"
:class=
"
{ highlighted: item.eventType === highlightedEventType }"
>
<div
...
...
@@ -123,6 +123,8 @@ import { color } from "echarts";
import
{
onMounted
,
ref
,
computed
}
from
"vue"
;
import
WaveBall
from
"./WaveBall.vue"
;
import
{
getBillRiskSignal
}
from
"@/api/bill/billHome"
;
import
router
from
"@/router"
;
import
{
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
const
sectionTab
=
[
{
textColor
:
"rgba(9, 88, 217, 1)"
,
...
...
@@ -289,12 +291,8 @@ const handleSwithCurNews = name => {
}
};
// 查看详情 传递参数
const
handleClickToDetailO
=
item
=>
{
window
.
sessionStorage
.
setItem
(
"billId"
,
item
.
billId
);
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
name
||
item
.
signalTitle
);
const
route
=
router
.
resolve
(
"/billLayout?billId="
+
item
.
billId
);
window
.
open
(
route
.
href
,
"_blank"
);
const
handleRiskSignalItemToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
const
highlightedEventType
=
ref
(
""
);
...
...
src/views/ZMOverView/components/newRisk/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -43,9 +43,15 @@
<div
style=
"display: flex"
>
<!-- 风险信号列表 -->
<div
class=
"risk-signals"
ref=
"riskSignalsRef"
>
<div
class=
"risk-signals-item"
v-for=
"(item, index) in warningList"
:key=
"index"
@
mouseenter=
"onMouseEnter(item, index)"
@
mouseleave=
"onMouseLeave"
:class=
"['risk-signals-item',
{ 'risk-signals-item-hightLight': riskSignalActiveIndex === index }]">
<div
class=
"risk-signals-item"
v-for=
"(item, index) in warningList"
:key=
"item.signalId != null ? String(item.signalId) : 'risk-' + index"
@
mouseenter=
"onMouseEnter(item, index)"
@
mouseleave=
"onMouseLeave"
@
click
.
stop=
"handleRiskSignalRowToManage"
:class=
"['risk-signals-item',
{ 'risk-signals-item-hightLight': riskSignalActiveIndex === index }]"
>
<div
class=
"item-left"
:class=
"
{
'item-status-1': item.signalLevel === '特别重大',
'item-status-2': item.signalLevel === '重大风险',
...
...
@@ -128,6 +134,7 @@ import { onMounted, ref, onUnmounted, computed } from "vue";
import
WaveBall
from
"./WaveBall.vue"
;
import
{
getLatestRiskUpdates
,
getLatestRisks
}
from
"@/api/zmOverview/risk/index.js"
;
import
router
from
"@/router/index"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
icon1
from
"./icon/title-1.svg"
;
import
icon2
from
"./icon/title-2.svg"
;
import
icon3
from
"./icon/title-3.svg"
;
...
...
@@ -645,12 +652,12 @@ const filteredHotNewsList = computed(() => {
return
hotNewsList
.
value
.
filter
(
newsItem
=>
newsItem
.
signalId
===
currentHoveredSignalId
.
value
);
});
const
handleRiskSignalRowToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
const
handleToRiskManage
=
()
=>
{
// 这里的路由路径请根据实际情况修改
// router.push('/riskSignalManage');
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
console
.
log
(
"跳转到风险信号管理"
);
navigateToViewRiskSignal
(
router
);
};
const
highlightedEventType
=
ref
(
""
);
...
...
src/views/bill/billHome/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -106,7 +106,7 @@
</el-carousel>
</div>
</OverviewMainBox>
<RiskSignal
:list=
"warningList"
@
more-click=
"handleToMoreRiskSignal"
@
item-click=
"handle
ClickToDetailO
"
<RiskSignal
:list=
"warningList"
@
more-click=
"handleToMoreRiskSignal"
@
item-click=
"handle
RiskSignalItemToManage
"
riskLevel=
"signalLevel"
postDate=
"signalTime"
name=
"signalTitle"
/>
</div>
...
...
@@ -247,6 +247,7 @@ import RiskSignal from "@/components/base/riskSignal/index.vue";
import
SummaryCardsPanel
from
"@/components/base/SummaryCardsPanel/index.vue"
;
import
{
onMounted
,
ref
,
onUnmounted
,
nextTick
,
watch
,
computed
}
from
"vue"
;
import
router
from
"@/router/index"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
setChart
from
"@/utils/setChart"
;
import
{
getBillIndustry
,
...
...
@@ -465,11 +466,13 @@ const handleClickToDetailO = item => {
// router.push("/billLayout?billId=" + item.billId)
};
const
handleRiskSignalItemToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
// router.push("/viewRiskSignal")
navigateToViewRiskSignal
(
router
);
};
// 查看更多新闻资讯(新闻主页)
...
...
src/views/coopRestriction/components/dataNew/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -112,7 +112,7 @@
</div>
-->
<RiskSignal
:list=
"riskSignals"
@
more-click=
"handleToMoreRiskSignal"
postDate=
"time"
name=
"content"
riskLevel=
"title"
@
item-click=
"handle
ClickToDetail
"
/>
riskLevel=
"title"
@
item-click=
"handle
RiskSignalItemToManage
"
/>
</div>
</
template
>
...
...
@@ -120,6 +120,7 @@
import
RiskSignal
from
"@/components/base/riskSignal/index.vue"
;
import
{
ref
,
onMounted
,
computed
}
from
"vue"
;
import
router
from
"@/router"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
{
getCoopRestrictionTrends
,
getCoopRestrictionSignals
}
from
"@/api/coopRestriction/coopRestriction.js"
;
import
defaultImg
from
"./assets/usImg.png"
;
import
CommonPrompt
from
"../../commonPrompt/index.vue"
;
...
...
@@ -210,10 +211,13 @@ const handleToRiskDetail = (item) => {
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
const
handleRiskSignalItemToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
navigateToViewRiskSignal
(
router
);
};
onMounted
(()
=>
{
...
...
src/views/decree/decreeHome/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -102,7 +102,7 @@
</el-carousel-item>
</el-carousel>
</OverviewMainBox>
<RiskSignal
:list=
"warningList"
@
item-click=
"
onNavigateToDetail
"
@
more-click=
"handleToMoreRiskSignal"
<RiskSignal
:list=
"warningList"
@
item-click=
"
handleRiskSignalItemToManage
"
@
more-click=
"handleToMoreRiskSignal"
riskLevel=
"signalLevel"
postDate=
"signalTime"
name=
"signalTitle"
>
</RiskSignal>
</div>
...
...
@@ -409,6 +409,7 @@
<
script
setup
>
import
{
onMounted
,
ref
,
watch
,
nextTick
,
reactive
,
computed
}
from
"vue"
;
import
router
from
"@/router"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
WordCloudChart
from
"@/components/base/WordCloundChart/index.vue"
import
SimplePagination
from
"@/components/SimplePagination.vue"
;
import
SummaryCardsPanel
from
"@/components/base/SummaryCardsPanel/index.vue"
;
...
...
@@ -490,10 +491,12 @@ const onNavigateTo = () => {
}
// 查看更多风险信号
const
handleRiskSignalItemToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
// router.push("/viewRiskSignal")
navigateToViewRiskSignal
(
router
);
};
// 查看更多新闻资讯
...
...
src/views/exportControl/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -602,6 +602,7 @@ const entityListReleaseFreqChart = useChartInterpretation();
const
commerceControlListReleaseFreqChart
=
useChartInterpretation
();
import
{
useRouter
}
from
"vue-router"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
const
router
=
useRouter
();
...
...
@@ -673,17 +674,9 @@ const handleToPosi = id => {
}
};
// 跳转到单项制裁页面
const
handleToRiskSignalDetail
=
item
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
title
);
const
routeData
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
query
:
{
id
:
item
.
sanId
}
});
// 打开新页面
window
.
open
(
routeData
.
href
,
"_blank"
);
// 风险信号:进入管理页并自动打开列表第一条详情
const
handleToRiskSignalDetail
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
const
sanctionList
=
ref
([]);
...
...
@@ -1649,9 +1642,7 @@ const handleSanc = item => {
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
// router.push("/viewRiskSignal")
navigateToViewRiskSignal
(
router
);
};
// 查看更多新闻资讯
...
...
src/views/finance/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -693,6 +693,7 @@ const entityListReleaseFreqChart = useChartInterpretation();
const
commerceControlListReleaseFreqChart
=
useChartInterpretation
();
import
{
useRouter
}
from
"vue-router"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
const
router
=
useRouter
();
...
...
@@ -775,17 +776,9 @@ const handleToPosi = id => {
}
};
// 跳转到单项制裁页面
const
handleToRiskSignalDetail
=
item
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
title
);
const
routeData
=
router
.
resolve
({
path
:
"/finance/singleSanction"
,
query
:
{
id
:
item
.
sanId
}
});
// 打开新页面
window
.
open
(
routeData
.
href
,
"_blank"
);
// 风险信号:进入管理页并自动打开列表第一条详情
const
handleToRiskSignalDetail
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
const
sanctionList
=
ref
([]);
...
...
@@ -1649,9 +1642,7 @@ const handleSanc = item => {
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
// router.push("/viewRiskSignal")
navigateToViewRiskSignal
(
router
);
};
// 查看更多新闻资讯
...
...
src/views/gjOverView/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -75,7 +75,7 @@
</div>
<div
class=
"item-header-divider"
/>
<div
class=
"warning-wrap"
>
<div
v-for=
"(item, index) in warningList"
:key=
"index"
class=
"waring-item"
>
<div
v-for=
"(item, index) in warningList"
:key=
"index"
class=
"waring-item"
@
click=
"handleRiskSignalItemClick"
>
<div
class=
"waring-row"
>
<div
class=
"waring-status"
:style=
"
{
color: item.status === 0 ? '#CE4F51' : item.status === 1 ? '#FA8C16' : '#52C41A',
...
...
@@ -120,6 +120,7 @@
<
script
setup
>
import
{
ref
}
from
'vue'
;
import
router
from
'@/router'
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
'@/utils/riskSignalOverviewNavigate'
;
import
MeansAnalysis
from
'./component/MeansAnalysis.vue'
;
import
ResourceAnalysis
from
'./component/ResourceAnalysis.vue'
import
AdvantagesAnalysis
from
'./component/AdvantagesAnalysis.vue'
...
...
@@ -220,10 +221,13 @@ const warningList = ref([
{
title
:
'首次提出“限制外国敏感实体获取补偿'
,
time
:
'一天前'
,
status
:
0
},
]);
const
handleRiskSignalItemClick
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
navigateToViewRiskSignal
(
router
);
};
</
script
>
...
...
src/views/innovationSubject/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -145,8 +145,8 @@
<div
class=
"text"
>
{{
"查看更多"
}}
</div>
</div>
</div>
-->
<RiskSignal
:list=
"warningList"
@
more-click=
"handleToMoreRiskSignal"
riskLevel=
"signalLevel
"
postDate=
"signalTime"
name=
"signalTitle"
/>
<RiskSignal
:list=
"warningList"
@
more-click=
"handleToMoreRiskSignal"
@
item-click=
"handleRiskSignalItemToManage
"
riskLevel=
"signalLevel"
postDate=
"signalTime"
name=
"signalTitle"
/>
</div>
<DivideHeader
id=
"position2"
class=
"divide2"
:titleText=
"'资讯要闻'"
></DivideHeader>
<div
class=
"center-center"
>
...
...
@@ -348,7 +348,8 @@ import RiskSignal from "@/components/base/riskSignal/index.vue";
import
NewsList
from
"@/components/base/newsList/index.vue"
;
import
{
onMounted
,
ref
,
computed
}
from
"vue"
;
import
*
as
echarts
from
"echarts"
;
import
router
from
"@/router"
;
import
router
from
"@/router"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
DivideHeader
from
"@/components/DivideHeader.vue"
;
import
{
useContainerScroll
}
from
"@/hooks/useScrollShow"
;
import
getPieChart
from
"./utils/piechart"
;
...
...
@@ -514,10 +515,13 @@ const handleClickToDetail = university => {
// window.open(route.href, "_blank");
};
const
handleRiskSignalItemToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
navigateToViewRiskSignal
(
router
);
};
// 查看更多新闻资讯
...
...
src/views/marketAccessRestrictions/marketAccessHome/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -58,7 +58,7 @@
<
div
class
=
"box1-right"
@
click
=
"handleSwithCurSurvey('right')"
>
<
RightBtn
/>
<
/div
>
<
/overviewMainBox
>
<
/div
>
<
RiskSignal
:
list
=
"box2Data"
@
more
-
click
=
"handleToMoreRiskSignal"
@
item
-
click
=
"
onNavigateToDetail
"
postDate
=
"signalTime"
name
=
"signalTitle"
riskLevel
=
"signalLevel"
/>
<
RiskSignal
:
list
=
"box2Data"
@
more
-
click
=
"handleToMoreRiskSignal"
@
item
-
click
=
"
handleRiskSignalItemToManage
"
postDate
=
"signalTime"
name
=
"signalTitle"
riskLevel
=
"signalLevel"
/>
<
/div
>
<
DivideHeader
id
=
"position2"
class
=
"divide-header"
:
titleText
=
"'资讯要闻'"
><
/DivideHeader
>
...
...
@@ -278,6 +278,7 @@ import CarouselItem232 from '@/views/marketAccessRestrictions/marketAccessHome/c
import
setChart
from
"@/utils/setChart"
;
import
router
from
"@/router"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
getMultiLineChart
from
"./utils/multiLineChart"
;
import
getPieChart
from
"./utils/piechart"
;
...
...
@@ -928,10 +929,13 @@ const handleFetchSurveyList = async () => {
}
catch
(
error
)
{
}
}
;
const
handleRiskSignalItemToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
}
;
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
navigateToViewRiskSignal
(
router
);
}
;
// 查看更多新闻资讯
...
...
src/views/overView/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -112,7 +112,7 @@
</div>
<div
class=
"item-header-divider"
></div>
<div
style=
"padding: 30px 23px; height: 400px"
>
<div
class=
"waring-item"
v-for=
"(item, index) in warningList"
:key=
"index"
>
<div
class=
"waring-item"
v-for=
"(item, index) in warningList"
:key=
"index"
@
click=
"handleRiskSignalItemClick"
>
<div
style=
"display: flex; height: 47px"
>
<div
class=
"waring-status"
...
...
@@ -204,6 +204,7 @@ import Thematicanalysis from "./component/Thematicanalysis.vue";
import
ResourceSupport
from
"./component/ResourceSupport.vue"
;
import
strengthComparison
from
"./component/strengthComparison.vue"
;
import
router
from
"@/router"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
const
searchText
=
ref
(
""
);
const
handleSearch
=
()
=>
{
...
...
@@ -223,10 +224,13 @@ const handleToSearch = () => {
window
.
open
(
route
.
href
,
"_blank"
);
};
const
handleRiskSignalItemClick
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
navigateToViewRiskSignal
(
router
);
};
// 查看更多新闻资讯
...
...
src/views/ruleRestriction/components/dataNew/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -69,8 +69,8 @@
查看更多
</div>
</div>
-->
<RiskSignal
:list=
"list"
@
more-click=
"handleToMoreRiskSignal"
riskLevel=
"signalLevel"
postDate=
"signalTim
e"
name=
"signalTitle"
/>
<RiskSignal
:list=
"list"
@
more-click=
"handleToMoreRiskSignal"
@
item-click=
"handleRiskSignalItemToManag
e"
riskLevel=
"signalLevel"
postDate=
"signalTime"
name=
"signalTitle"
/>
</div>
</
template
>
...
...
@@ -78,6 +78,7 @@
import
RiskSignal
from
"@/components/base/riskSignal/index.vue"
;
import
{
ref
,
onBeforeMount
,
computed
}
from
"vue"
;
import
router
from
"@/router"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
{
getLatestUpdates
,
getRiskSignal
}
from
'@/api/ruleRestriction/index.js'
const
list
=
ref
([
...
...
@@ -194,10 +195,13 @@ const handleToRiskDetail = (item) => {
// window.open(curRoute.href, "_blank");
// };
const
handleRiskSignalItemToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
// 查看更多动态
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
navigateToViewRiskSignal
(
router
);
};
onBeforeMount
(
async
()
=>
{
...
...
src/views/scientificFunding/components/dataNew/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -90,8 +90,8 @@
查看更多
</div>
</div>
-->
<RiskSignal
:list=
"list"
@
more-click=
"handleToMoreRiskSignal"
postDate=
"signalTime"
name=
"signalTitl
e"
riskLevel=
"signalLevel"
/>
<RiskSignal
:list=
"list"
@
more-click=
"handleToMoreRiskSignal"
@
item-click=
"handleRiskSignalItemToManag
e"
postDate=
"signalTime"
name=
"signalTitle"
riskLevel=
"signalLevel"
/>
</div>
</
template
>
...
...
@@ -102,6 +102,7 @@ import {
getNewProject
,
getRiskSignal
}
from
"@/api/scientificFunding/overview"
;
import
router
from
"@/router"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
const
list
=
ref
([
...
...
@@ -124,10 +125,13 @@ const formatDate = (dateStr) => {
const
[
y
,
m
,
d
]
=
dateStr
.
split
(
'-'
);
return
`
${
y
}
年
${
m
}
月
${
d
}
日`
;
};
const
handleRiskSignalItemToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
navigateToViewRiskSignal
(
router
);
};
const
box1Data
=
ref
([])
const
carouselRef
=
ref
(
null
);
...
...
src/views/technologyFigures/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -152,8 +152,8 @@
</div>
</OverviewMainBox>
<RiskSignal
:list=
"warningList"
@
more-click=
"handleToMoreRiskSignal"
postDate=
"signalTim
e"
name=
"signalTitle"
riskLevel=
"signalLevel"
/>
<RiskSignal
:list=
"warningList"
@
more-click=
"handleToMoreRiskSignal"
@
item-click=
"handleRiskSignalItemToManag
e"
postDate=
"signalTime"
name=
"signalTitle"
riskLevel=
"signalLevel"
/>
</div>
<DivideHeader
id=
"position2"
class=
"divide-header"
:titleText=
"'言论动态'"
></DivideHeader>
<div
class=
"center-center"
>
...
...
@@ -346,10 +346,10 @@ import SpeechStance from "./component/speechStance.vue";
import
PersonTable
from
"./component/PersonTable.vue"
;
import
SourceLibrary
from
"./component/SourceLibrary.vue"
;
import
{
useContainerScroll
}
from
"@/hooks/useScrollShow"
;
import
{
navigateToViewRiskSignal
,
navigateToViewRiskSignalOpenFirstDetail
}
from
"@/utils/riskSignalOverviewNavigate"
;
const
router
=
useRouter
();
const
containerRef
=
ref
(
null
);
const
{
isShow
}
=
useContainerScroll
(
containerRef
);
...
...
@@ -802,10 +802,13 @@ const handleClickCate = cate => {
typeId
.
value
=
cate
.
typeId
;
};
const
handleRiskSignalItemToManage
=
()
=>
{
navigateToViewRiskSignalOpenFirstDetail
(
router
);
};
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
navigateToViewRiskSignal
(
router
);
};
// === 图表数据 ===
...
...
src/views/thinkTank/index.vue
浏览文件 @
4e9a1efd
<
template
>
<div
class=
"home-wrapper"
>
<div
class=
"home-main"
ref=
"containerRef"
>
<div
class=
"home-main"
ref=
"containerRef"
:class=
"
{ 'is-risk-detail-open': isRiskDetailVisible }"
>
<div
class=
"home-top-bg"
></div>
<div
class=
"home-main-header"
>
<!--
<div
class=
"home-main-header-top"
>
...
...
@@ -209,7 +209,29 @@
</el-carousel>
</OverviewMainBox>
<RiskSignal
:list=
"warningList"
@
more-click=
"handleToMoreRiskSignal"
postDate=
"time"
name=
"title"
@
item-click=
"handleClickToDetail"
/>
@
item-click=
"handleRiskSignalItemToManage"
/>
<el-dialog
v-model=
"isRiskDetailVisible"
class=
"risk-signal-detail-dialog"
modal-class=
"risk-signal-detail-modal"
width=
"1280px"
align-center
:z-index=
"20000"
:show-close=
"true"
destroy-on-close
@
closed=
"handleCloseRiskDetail"
>
<
template
#
header
>
<span
class=
"risk-signal-detail-dialog__title"
>
{{
riskDetailItem
.
title
}}
</span>
</
template
>
<div
v-if=
"riskDetailItem.title"
class=
"risk-signal-detail-dialog__body"
>
<div
class=
"risk-signal-detail-dialog__meta"
>
<span>
{{ riskDetailItem.origin }}
</span>
<span>
{{ riskDetailItem.time }}
</span>
<span
class=
"risk-signal-detail-dialog__level"
>
{{ riskDetailItem.risktype }}
</span>
</div>
<div
class=
"risk-signal-detail-dialog__desc"
>
{{ riskDetailItem.dsc }}
</div>
<div
v-if=
"riskDetailItem.tag.length"
class=
"risk-signal-detail-dialog__tags"
>
<AreaTag
v-for=
"(tag, index) in riskDetailItem.tag"
:key=
"'risk-detail-tag-' + index + '-' + tag"
:tagName=
"tag"
>
{{ tag }}
</AreaTag>
</div>
</div>
</el-dialog>
</div>
<DivideHeader
id=
"position2"
class=
"divide-header"
:titleText=
"'资讯要闻'"
></DivideHeader>
<div
class=
"center-center"
>
...
...
@@ -442,6 +464,7 @@ import MessageBubble from "@/components/base/messageBubble/index.vue"
import
{
onBeforeUnmount
,
onMounted
,
ref
,
computed
,
reactive
,
nextTick
}
from
"vue"
;
import
scrollToTop
from
"@/utils/scrollToTop"
;
import
router
from
"@/router"
;
import
{
navigateToViewRiskSignal
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
DivideHeader
from
"@/components/DivideHeader.vue"
;
import
setChart
from
"@/utils/setChart"
;
import
HomeMainFooterMain
from
"./components/HomeMainFooterMain.vue"
;
...
...
@@ -511,6 +534,52 @@ import { useRouter } from 'vue-router';
import
{
useGotoNewsDetail
}
from
'@/router/modules/news'
;
const
gotoNewsDetail
=
useGotoNewsDetail
()
const
containerRef
=
ref
(
null
);
const
isRiskDetailVisible
=
ref
(
false
);
const
riskDetailItem
=
reactive
({
title
:
""
,
origin
:
""
,
time
:
""
,
risktype
:
""
,
dsc
:
""
,
tag
:
[]
});
const
HARD_CODED_RISK_DETAIL_MAP
=
{
"关于对中华人民共和国合成阿片类药物供应链..."
:
{
origin
:
"智库概览 · 风险信号"
,
time
:
"一天前"
,
risktype
:
"特别重大"
,
dsc
:
"这里先写死详情内容:该风险信号涉及合成阿片类药物供应链相关议题,可能对相关实体合规、供应链与对外合作产生影响。后续接入后端后将替换为真实详情。"
,
tag
:
[
"生物科技"
,
"供应链"
,
"合规风险"
]
},
"关于调整钢铁进口的公告"
:
{
origin
:
"智库概览 · 风险信号"
,
time
:
"一天前"
,
risktype
:
"重大风险"
,
dsc
:
"这里先写死详情内容:钢铁进口政策调整可能影响相关行业成本结构与贸易路径,需关注后续执行细则与范围变化。"
,
tag
:
[
"材料"
,
"贸易政策"
,
"成本影响"
]
},
"关于修订对中华人民共和国低价值进口商品适..."
:
{
origin
:
"智库概览 · 风险信号"
,
time
:
"一天前"
,
risktype
:
"一般风险"
,
dsc
:
"这里先写死详情内容:低价值进口商品规则修订可能带来申报、税费与物流环节的流程变化,建议提前梳理影响链路。"
,
tag
:
[
"跨境电商"
,
"关务"
,
"流程变化"
]
}
};
const
handleCloseRiskDetail
=
()
=>
{
isRiskDetailVisible
.
value
=
false
;
riskDetailItem
.
title
=
""
;
riskDetailItem
.
origin
=
""
;
riskDetailItem
.
time
=
""
;
riskDetailItem
.
risktype
=
""
;
riskDetailItem
.
dsc
=
""
;
riskDetailItem
.
tag
=
[];
};
const
statCountInfo
=
ref
([]);
const
pageSize
=
ref
(
15
)
const
totalAllItem
=
ref
(
0
)
...
...
@@ -2119,11 +2188,28 @@ const handleClick = tank => {
// router.push({ name: "ThinkTankDetail", params: { id: tank.id, name: tank.name } })
};
// 查看更多风险信号
// 风险信号 item:当前页弹窗(先写死内容,后续接后端)
const
handleRiskSignalItemToManage
=
(
item
)
=>
{
const
title
=
item
?.
title
||
""
;
const
time
=
item
?.
time
||
""
;
const
risktype
=
item
?.
status
||
""
;
const
hardCoded
=
HARD_CODED_RISK_DETAIL_MAP
[
title
]
||
{};
riskDetailItem
.
title
=
title
;
riskDetailItem
.
origin
=
hardCoded
.
origin
||
"智库概览 · 风险信号"
;
riskDetailItem
.
time
=
hardCoded
.
time
||
time
||
"—"
;
riskDetailItem
.
risktype
=
hardCoded
.
risktype
||
risktype
||
"一般风险"
;
riskDetailItem
.
dsc
=
hardCoded
.
dsc
||
"这里先写死详情内容:后续接入后端后将替换为真实详情。"
;
riskDetailItem
.
tag
=
hardCoded
.
tag
||
[
"暂无标签"
];
isRiskDetailVisible
.
value
=
true
;
};
const
handleToMoreRiskSignal
=
()
=>
{
const
route
=
router
.
resolve
(
"/viewRiskSignal"
);
window
.
open
(
route
.
href
,
"_blank"
);
// router.push("/viewRiskSignal")
navigateToViewRiskSignal
(
router
);
};
// 查看更多新闻资讯
...
...
@@ -4590,3 +4676,95 @@ onBeforeUnmount(() => {
}
}
</
style
>
<
style
lang=
"scss"
>
/* el-dialog 默认 teleport 到 body,壳子样式需非 scoped */
/* 遮罩层内水平垂直居中(勿对 .el-dialog 写 margin:0 !important,会顶到左上角) */
.risk-signal-detail-modal.el-overlay
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
z-index
:
20000
!
important
;
}
.risk-signal-detail-modal
.el-overlay-dialog
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
.risk-signal-detail-dialog.el-dialog
{
width
:
1280px
!
important
;
max-width
:
calc
(
100vw
-
32px
);
height
:
750px
;
max-height
:
calc
(
100vh
-
32px
);
border-radius
:
10px
;
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
box-sizing
:
border-box
;
}
.risk-signal-detail-dialog
.el-dialog__header
{
flex-shrink
:
0
;
padding
:
16px
20px
8px
;
margin
:
0
;
}
.risk-signal-detail-dialog
.el-dialog__body
{
flex
:
1
;
min-height
:
0
;
overflow
:
auto
;
padding
:
12px
20px
20px
;
box-sizing
:
border-box
;
}
.risk-signal-detail-dialog__title
{
font-size
:
18px
;
font-weight
:
700
;
line-height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
}
.risk-signal-detail-dialog__body
{
display
:
flex
;
flex-direction
:
column
;
gap
:
12px
;
}
.risk-signal-detail-dialog__meta
{
display
:
flex
;
flex-wrap
:
wrap
;
align-items
:
center
;
gap
:
12px
;
font-size
:
14px
;
line-height
:
22px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
}
.risk-signal-detail-dialog__level
{
color
:
rgba
(
5
,
95
,
194
,
1
);
}
.risk-signal-detail-dialog__desc
{
font-size
:
16px
;
line-height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
text-align
:
justify
;
}
.risk-signal-detail-dialog__tags
{
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
8px
;
}
/* 弹窗打开时,禁用轮播左右切换按钮,避免穿透点击 */
.home-main.is-risk-detail-open
{
.box1-left
,
.box1-right
{
pointer-events
:
none
;
}
}
</
style
>
src/views/thinkTank/reportOriginal/pdf.vue
浏览文件 @
4e9a1efd
差异被折叠。
点击展开。
src/views/viewRiskSignal/index.vue
浏览文件 @
4e9a1efd
...
...
@@ -190,7 +190,8 @@
</div>
<div
class=
"right-main"
>
<div
class=
"itemlist"
v-for=
"(val, idx) in riskList"
:key=
"idx"
>
<div
class=
"itemlist itemlist--clickable"
v-for=
"(val, idx) in riskList"
:key=
"val.rowKey"
@
click=
"handleOpenRiskDetail(val)"
>
<div
class=
"box-title"
>
<div
class=
"risktitle"
>
{{ val.title }}
</div>
<div
class=
"risktype"
:class=
"{
...
...
@@ -233,11 +234,33 @@
</div>
</div>
</div>
<el-dialog
v-model=
"isRiskDetailVisible"
class=
"risk-signal-detail-dialog"
modal-class=
"risk-signal-detail-modal"
width=
"1280px"
align-center
:show-close=
"true"
destroy-on-close
@
closed=
"handleCloseRiskDetail"
>
<
template
#
header
>
<span
class=
"risk-signal-detail-dialog__title"
>
{{
riskDetailItem
.
title
}}
</span>
</
template
>
<div
v-if=
"riskDetailItem.title"
class=
"risk-signal-detail-dialog__body"
>
<div
class=
"risk-signal-detail-dialog__meta"
>
<span>
{{ riskDetailItem.origin }}
</span>
<span>
{{ riskDetailItem.time }}
</span>
<span
class=
"risk-signal-detail-dialog__level"
>
{{ riskDetailItem.risktype }}
</span>
</div>
<div
class=
"risk-signal-detail-dialog__desc"
>
{{ riskDetailItem.dsc }}
</div>
<div
v-if=
"riskDetailItem.tag.length"
class=
"risk-signal-detail-dialog__tags"
>
<AreaTag
v-for=
"(tag, index) in riskDetailItem.tag"
:key=
"'risk-detail-tag-' + index + '-' + tag"
:tagName=
"tag"
>
{{ tag }}
</AreaTag>
</div>
</div>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
onMounted
,
ref
}
from
"vue"
;
import
{
nextTick
,
onMounted
,
reactive
,
ref
,
watch
}
from
"vue"
;
import
{
useRoute
,
useRouter
}
from
"vue-router"
;
import
{
OPEN_FIRST_RISK_DETAIL_QUERY_KEY
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
{
getCountInfo
,
getDailyCount
,
getPageQuery
}
from
"@/api/riskSignal/index"
;
import
{
getHylyList
}
from
"@/api/thinkTank/overview"
;
import
setChart
from
"@/utils/setChart"
;
...
...
@@ -390,6 +413,7 @@ const handleClickBtn = item => {
const
riskList
=
ref
([
{
rowKey
:
"risk-demo-1"
,
title
:
"扩大实体清单制裁范围,对中企子公司实施同等管制"
,
origin
:
"美国商务部"
,
fileType
:
"实体清单"
,
...
...
@@ -400,6 +424,7 @@ const riskList = ref([
pic
:
"src/views/riskSignal/assets/images/origin1.png"
},
{
rowKey
:
"risk-demo-2"
,
title
:
"大而美法案通过国会众议院投票,将提交至总统签署"
,
origin
:
"美国国会 · 科技法案"
,
time
:
"2025年11月10日 16:14"
,
...
...
@@ -411,6 +436,7 @@ const riskList = ref([
bgcolor
:
"rgba(255, 149, 77, 0.1)"
},
{
rowKey
:
"risk-demo-3"
,
title
:
"兰德公司发布智库报告《中美经济竞争:复杂经济和地缘政治关系中的收益和风险》"
,
origin
:
"兰德公司 · 科技智库"
,
time
:
"2025年11月10日 16:14"
,
...
...
@@ -422,6 +448,7 @@ const riskList = ref([
bgcolor
:
"rgba(5, 95, 194, 0.1)"
},
{
rowKey
:
"risk-demo-4"
,
title
:
"美国白宫发布总统政令《关于进一步延长TikTok执法宽限期的行政令》"
,
origin
:
"美国白宫 · 总统政令"
,
time
:
"2025年11月10日 16:14"
,
...
...
@@ -433,6 +460,7 @@ const riskList = ref([
bgcolor
:
"rgba(5, 95, 194, 0.1)"
},
{
rowKey
:
"risk-demo-5"
,
title
:
"美国财政部更新《特别指定国民清单》"
,
origin
:
"美国财政部 · 特别指定国民清单"
,
time
:
"2025年11月10日 16:14"
,
...
...
@@ -444,6 +472,7 @@ const riskList = ref([
bgcolor
:
"rgba(206, 79, 81, 0.1)"
},
{
rowKey
:
"risk-demo-6"
,
title
:
"美国FDA针对两家中国第三方检测机构的数据完整性问题采取行动"
,
origin
:
"美国食品药品监督管理局 · 规则限制"
,
time
:
"2025年11月10日 16:14"
,
...
...
@@ -456,6 +485,50 @@ const riskList = ref([
}
]);
const
isRiskDetailVisible
=
ref
(
false
);
const
riskDetailItem
=
reactive
({
title
:
""
,
origin
:
""
,
time
:
""
,
dsc
:
""
,
tag
:
[],
risktype
:
""
});
const
assignRiskDetail
=
(
val
)
=>
{
riskDetailItem
.
title
=
val
.
title
??
""
;
riskDetailItem
.
origin
=
val
.
origin
??
""
;
riskDetailItem
.
time
=
val
.
time
??
""
;
riskDetailItem
.
dsc
=
val
.
dsc
??
""
;
riskDetailItem
.
tag
=
Array
.
isArray
(
val
.
tag
)
?
[...
val
.
tag
]
:
[];
riskDetailItem
.
risktype
=
val
.
risktype
??
""
;
};
const
handleOpenRiskDetail
=
(
val
)
=>
{
assignRiskDetail
(
val
);
isRiskDetailVisible
.
value
=
true
;
};
const
handleCloseRiskDetail
=
()
=>
{
assignRiskDetail
({
tag
:
[]
});
};
const
route
=
useRoute
();
const
router
=
useRouter
();
const
consumeOpenFirstDetailFromQuery
=
async
()
=>
{
if
(
route
.
query
[
OPEN_FIRST_RISK_DETAIL_QUERY_KEY
]
!==
"1"
)
{
return
;
}
if
(
!
riskList
.
value
.
length
)
{
return
;
}
handleOpenRiskDetail
(
riskList
.
value
[
0
]);
const
nextQuery
=
{
...
route
.
query
};
delete
nextQuery
[
OPEN_FIRST_RISK_DETAIL_QUERY_KEY
];
await
router
.
replace
({
path
:
route
.
path
,
query
:
nextQuery
});
};
const
calendarData
=
ref
([
]);
...
...
@@ -596,8 +669,13 @@ const handleGetPageQuery = async () => {
console
.
log
(
"按条件查询"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
totalNum
.
value
=
res
.
data
.
totalElements
;
riskList
.
value
=
res
.
data
.
content
.
map
(
item
=>
{
riskList
.
value
=
res
.
data
.
content
.
map
((
item
,
i
)
=>
{
const
stableId
=
item
.
id
??
item
.
riskId
??
item
.
riskSignalId
;
return
{
rowKey
:
stableId
!=
null
?
String
(
stableId
)
:
`p
${
currentPage
.
value
}
-i
${
i
}
-
${
String
(
item
.
time
??
""
)}
-
$
{
String
(
item
.
titleZh
??
""
)}
`,
title: item.titleZh,
origin: item.srcOrgId,
fileType: "暂无数据",
...
...
@@ -614,11 +692,24 @@ const handleGetPageQuery = async () => {
}
};
watch(
() => route.query[OPEN_FIRST_RISK_DETAIL_QUERY_KEY],
async (v) => {
if (v !== "1") {
return;
}
await nextTick();
await consumeOpenFirstDetailFromQuery();
}
);
onMounted(async () => {
handleGetCountInfo();
handleCleandarChart();
await handleGetHylyList();
handleGetPageQuery
();
await handleGetPageQuery();
await nextTick();
await consumeOpenFirstDetailFromQuery();
});
</
script
>
...
...
@@ -1063,6 +1154,10 @@ onMounted(async () => {
}
&
.itemlist--clickable
{
cursor
:
pointer
;
}
}
}
...
...
@@ -1093,4 +1188,86 @@ onMounted(async () => {
}
/* 复选框尺寸由 .checkbox-group 内统一控制,避免重复覆盖 */
.risk-signal-detail-dialog__title
{
font-size
:
18px
;
font-weight
:
700
;
line-height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
}
.risk-signal-detail-dialog__body
{
display
:
flex
;
flex-direction
:
column
;
gap
:
12px
;
}
.risk-signal-detail-dialog__meta
{
display
:
flex
;
flex-wrap
:
wrap
;
align-items
:
center
;
gap
:
12px
;
font-size
:
14px
;
line-height
:
22px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
}
.risk-signal-detail-dialog__level
{
color
:
rgba
(
5
,
95
,
194
,
1
);
}
.risk-signal-detail-dialog__desc
{
font-size
:
16px
;
line-height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
text-align
:
justify
;
}
.risk-signal-detail-dialog__tags
{
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
8px
;
}
</
style
>
<
style
lang=
"scss"
>
/* el-dialog 默认 teleport 到 body,壳子样式需非 scoped */
/* 遮罩层内水平垂直居中(勿对 .el-dialog 写 margin:0 !important,会顶到左上角) */
.risk-signal-detail-modal.el-overlay
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
.risk-signal-detail-modal
.el-overlay-dialog
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
}
.risk-signal-detail-dialog.el-dialog
{
width
:
1280px
!
important
;
max-width
:
calc
(
100vw
-
32px
);
height
:
750px
;
max-height
:
calc
(
100vh
-
32px
);
border-radius
:
10px
;
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
box-sizing
:
border-box
;
}
.risk-signal-detail-dialog
.el-dialog__header
{
flex-shrink
:
0
;
padding
:
16px
20px
8px
;
margin
:
0
;
}
.risk-signal-detail-dialog
.el-dialog__body
{
flex
:
1
;
min-height
:
0
;
overflow
:
auto
;
padding
:
12px
20px
20px
;
box-sizing
:
border-box
;
}
</
style
>
\ No newline at end of file
src/views/viewRiskSignal/utils/cleandarHeat.js
浏览文件 @
4e9a1efd
import
dayjs
from
"dayjs"
;
const
RISK_CALENDAR_MONTH_TOTAL
=
12
;
const
RISK_HEAT_CELL_INNER
=
16
;
const
RISK_HEAT_CELL_GAP
=
2
;
const
RISK_HEAT_CELL_STRIDE
=
RISK_HEAT_CELL_INNER
+
RISK_HEAT_CELL_GAP
;
const
RISK_HEAT_CELL_BORDER
=
RISK_HEAT_CELL_GAP
/
2
;
const
getCalendarHeatChart
=
(
data
)
=>
{
const
option
=
{
title
:
{
top
:
30
,
left
:
'center'
,
text
:
`日历热力图`
,
show
:
false
},
tooltip
:
{
position
:
'top'
,
formatter
:
function
(
params
)
{
const
date
=
new
Date
(
params
.
data
[
0
]);
return
`
${
date
.
getFullYear
()}
-
${(
date
.
getMonth
()
+
1
).
toString
().
padStart
(
2
,
'0'
)}
-
${
date
.
getDate
().
toString
().
padStart
(
2
,
'0'
)}
<br/>数值:
${
params
.
data
[
1
]}
`
;
}
},
visualMap
:
{
show
:
false
,
min
:
0
,
max
:
20
,
calculable
:
true
,
orient
:
'horizontal'
,
left
:
'center'
,
top
:
65
,
inRange
:
{
color
:
[
'rgb(231, 243, 255)'
,
'rgb(137, 193, 255)'
,
'rgb(5, 95, 194)'
]
},
textStyle
:
{
color
:
'rgba(95, 101, 108, 1)'
}
},
calendar
:
{
top
:
24
,
left
:
30
,
right
:
30
,
cellSize
:
[
'auto'
,
20
],
range
:
'2026'
,
splitLine
:
{
show
:
false
},
itemStyle
:
{
borderWidth
:
0.5
,
borderColor
:
'#ccc'
},
yearLabel
:
{
show
:
true
},
monthLabel
:
{
nameMap
:
'cn'
},
dayLabel
:
{
nameMap
:
[
'日'
,
'一'
,
'二'
,
'三'
,
'四'
,
'五'
,
'六'
],
show
:
false
,
}
},
series
:
{
type
:
'heatmap'
,
coordinateSystem
:
'calendar'
,
data
:
data
}
};
return
option
}
export
default
getCalendarHeatChart
\ No newline at end of file
const
RISK_HEAT_CELL_SEPARATOR_COLOR
=
"rgb(255, 255, 255)"
;
const
RISK_HEAT_EMPTY_FILL
=
"rgb(247, 248, 249)"
;
/** 每行 5 列;日期按「左→右、上→下」排布(不再用 6 列×6 行) */
const
COLS_PER_MONTH
=
5
;
/**
* 行数 = ceil(天数/5);月初补 (行数*5-天数) 个空位,使最后一行尽量排满。
* 常见:28–30 天为 5×6 内;31 天需 7 行(5×6=30 格装不下 31 天)。
* @param {number} daysInMonth
*/
const
getMonthGridLayout
=
(
daysInMonth
)
=>
{
const
rows
=
Math
.
ceil
(
daysInMonth
/
COLS_PER_MONTH
);
const
paddingSlots
=
rows
*
COLS_PER_MONTH
-
daysInMonth
;
return
{
rows
,
paddingSlots
};
};
const
HEAT_RGB_STOPS
=
[
[
231
,
243
,
255
],
[
137
,
193
,
255
],
[
5
,
95
,
194
]
];
const
lerpChannel
=
(
a
,
b
,
t
)
=>
Math
.
round
(
a
+
(
b
-
a
)
*
t
);
/** v<=0 用空色;v>0 按三段渐变 */
const
getHeatColor
=
(
v
,
maxV
)
=>
{
const
n
=
Number
(
v
);
if
(
!
Number
.
isFinite
(
n
)
||
n
<=
0
)
{
return
RISK_HEAT_EMPTY_FILL
;
}
const
ratio
=
Math
.
min
(
n
/
maxV
,
1
);
const
[
c0
,
c1
,
c2
]
=
HEAT_RGB_STOPS
;
if
(
ratio
<=
0.5
)
{
const
t
=
ratio
/
0.5
;
return
`rgb(
${
lerpChannel
(
c0
[
0
],
c1
[
0
],
t
)}
,
${
lerpChannel
(
c0
[
1
],
c1
[
1
],
t
)}
,
${
lerpChannel
(
c0
[
2
],
c1
[
2
],
t
)}
)`
;
}
const
t
=
(
ratio
-
0.5
)
/
0.5
;
return
`rgb(
${
lerpChannel
(
c1
[
0
],
c2
[
0
],
t
)}
,
${
lerpChannel
(
c1
[
1
],
c2
[
1
],
t
)}
,
${
lerpChannel
(
c1
[
2
],
c2
[
2
],
t
)}
)`
;
};
const
getCalendarHeatChart
=
(
rawData
)
=>
{
const
now
=
dayjs
();
const
monthLabels
=
[];
for
(
let
offset
=
RISK_CALENDAR_MONTH_TOTAL
-
1
;
offset
>=
0
;
offset
-=
1
)
{
monthLabels
.
push
(
now
.
subtract
(
offset
,
"month"
).
format
(
"YYYY-MM"
));
}
const
startBound
=
dayjs
(
`
${
monthLabels
[
0
]}
-01`
).
startOf
(
"month"
);
const
endBound
=
now
.
endOf
(
"month"
);
const
countMap
=
new
Map
();
let
maxVal
=
0
;
for
(
const
row
of
rawData
||
[])
{
if
(
!
row
||
row
.
length
<
2
)
continue
;
const
d
=
dayjs
(
row
[
0
]);
if
(
!
d
.
isValid
())
continue
;
if
(
d
.
isBefore
(
startBound
,
"day"
)
||
d
.
isAfter
(
endBound
,
"day"
))
continue
;
const
key
=
d
.
format
(
"YYYY-MM-DD"
);
const
c
=
Number
(
row
[
1
])
||
0
;
countMap
.
set
(
key
,
c
);
if
(
c
>
maxVal
)
maxVal
=
c
;
}
const
visualMax
=
Math
.
max
(
1
,
maxVal
);
const
monthWidthPx
=
COLS_PER_MONTH
*
RISK_HEAT_CELL_STRIDE
;
const
monthLayouts
=
monthLabels
.
map
((
ym
)
=>
{
const
daysInMonth
=
dayjs
(
`
${
ym
}
-01`
).
daysInMonth
();
return
{
ym
,
daysInMonth
,
...
getMonthGridLayout
(
daysInMonth
)
};
});
/** 12 个月紧挨排列;月与月之间不额外加空隙,仅靠两侧 1px 描边形成固定 2px */
const
CONTENT_MARGIN_LEFT_PX
=
22
;
const
CONTENT_MARGIN_TOP_PX
=
15
;
/** 月份文字在上,格子在其下(12px 字号约一行高) */
const
MONTH_LABEL_TOP_PX
=
CONTENT_MARGIN_TOP_PX
;
const
GRID_TOP_PX
=
CONTENT_MARGIN_TOP_PX
+
18
;
const
monthTitleGraphics
=
monthLayouts
.
map
((
layout
,
idx
)
=>
{
const
monthNum
=
dayjs
(
`
${
layout
.
ym
}
-01`
).
month
()
+
1
;
return
{
type
:
"text"
,
id
:
`risk-heat-month-
${
idx
}
`
,
left
:
CONTENT_MARGIN_LEFT_PX
+
idx
*
monthWidthPx
,
top
:
MONTH_LABEL_TOP_PX
,
z
:
10
,
silent
:
true
,
style
:
{
text
:
`
${
monthNum
}
月`
,
fill
:
"rgb(59, 65, 75)"
,
fontSize
:
12
,
fontWeight
:
500
,
fontFamily
:
"Source Han Sans CN, PingFang SC, Microsoft YaHei, sans-serif"
}
};
});
const
grids
=
monthLayouts
.
map
((
layout
,
idx
)
=>
({
left
:
CONTENT_MARGIN_LEFT_PX
+
idx
*
monthWidthPx
,
top
:
GRID_TOP_PX
,
width
:
monthWidthPx
,
height
:
layout
.
rows
*
RISK_HEAT_CELL_STRIDE
,
containLabel
:
false
}));
const
xAxes
=
monthLabels
.
map
((
_
,
idx
)
=>
({
type
:
"value"
,
gridIndex
:
idx
,
min
:
0
,
max
:
COLS_PER_MONTH
,
axisLine
:
{
show
:
false
},
axisTick
:
{
show
:
false
},
axisLabel
:
{
show
:
false
},
splitLine
:
{
show
:
false
}
}));
const
yAxes
=
monthLayouts
.
map
((
layout
,
idx
)
=>
({
type
:
"value"
,
gridIndex
:
idx
,
min
:
0
,
max
:
layout
.
rows
,
axisLine
:
{
show
:
false
},
axisTick
:
{
show
:
false
},
axisLabel
:
{
show
:
false
},
splitLine
:
{
show
:
false
}
}));
const
series
=
monthLayouts
.
map
((
layout
,
idx
)
=>
{
const
{
ym
,
daysInMonth
,
rows
,
paddingSlots
}
=
layout
;
const
m
=
dayjs
(
`
${
ym
}
-01`
);
const
data
=
[];
const
totalSlots
=
rows
*
COLS_PER_MONTH
;
for
(
let
slot
=
0
;
slot
<
totalSlots
;
slot
+=
1
)
{
const
col
=
slot
%
COLS_PER_MONTH
;
const
row
=
Math
.
floor
(
slot
/
COLS_PER_MONTH
);
if
(
slot
<
paddingSlots
)
{
data
.
push
([
col
,
row
,
""
,
null
,
1
]);
continue
;
}
const
day
=
slot
-
paddingSlots
+
1
;
const
dateStr
=
m
.
date
(
day
).
format
(
"YYYY-MM-DD"
);
const
v
=
countMap
.
get
(
dateStr
)
??
0
;
data
.
push
([
col
,
row
,
dateStr
,
v
,
0
]);
}
return
{
type
:
"custom"
,
name
:
ym
,
xAxisIndex
:
idx
,
yAxisIndex
:
idx
,
data
,
renderItem
(
params
,
api
)
{
const
col
=
api
.
value
(
0
);
const
row
=
api
.
value
(
1
);
const
dateStr
=
api
.
value
(
2
);
const
v
=
api
.
value
(
3
);
const
isPadding
=
api
.
value
(
4
)
===
1
;
/**
* 不能用 api.coord([0,0]) 当「顶部」:默认 value 轴 y=0 在网格下方,
* 会导致整块热力画在偏下位置并从 canvas 底部被裁切。
* 用当前 grid 的 coordSys 像素框,按列/行直接铺格,保证第 0 行贴 grid 顶。
*/
const
coordSys
=
params
.
coordSys
;
if
(
!
coordSys
||
typeof
coordSys
.
x
!==
"number"
||
typeof
coordSys
.
y
!==
"number"
)
{
return
null
;
}
const
xPx
=
coordSys
.
x
+
col
*
RISK_HEAT_CELL_STRIDE
;
const
yPx
=
coordSys
.
y
+
row
*
RISK_HEAT_CELL_STRIDE
;
return
{
type
:
"rect"
,
shape
:
{
x
:
xPx
,
y
:
yPx
,
width
:
RISK_HEAT_CELL_STRIDE
,
height
:
RISK_HEAT_CELL_STRIDE
},
style
:
api
.
style
({
fill
:
isPadding
?
RISK_HEAT_EMPTY_FILL
:
getHeatColor
(
v
,
visualMax
),
stroke
:
RISK_HEAT_CELL_SEPARATOR_COLOR
,
lineWidth
:
RISK_HEAT_CELL_BORDER
}),
silent
:
isPadding
};
},
encode
:
{
tooltip
:
[
2
,
3
]
},
tooltip
:
{
formatter
(
p
)
{
const
dateStr
=
p
.
data
?.[
2
]
||
""
;
if
(
!
dateStr
)
{
return
""
;
}
const
v
=
p
.
data
?.[
3
]
??
0
;
return
`
${
dateStr
}
<br/>数值:
${
v
}
`
;
}
}
};
});
return
{
tooltip
:
{
trigger
:
"item"
,
position
:
"top"
},
graphic
:
monthTitleGraphics
,
grid
:
grids
,
xAxis
:
xAxes
,
yAxis
:
yAxes
,
series
};
};
export
default
getCalendarHeatChart
;
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论