Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
1
合并请求
1
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
9e986979
提交
9e986979
authored
4月 14, 2026
作者:
付康
浏览文件
操作
浏览文件
下载
差异文件
合并分支 'zz-dev' 到 'pre'
feat:智库和风险列表加入加载状态,同时修改智库数量变化趋势图表调用 查看合并请求
!339
上级
d26a1cfc
71f8359b
流水线
#450
已通过 于阶段
in 3 分 26 秒
变更
8
流水线
1
显示空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
259 行增加
和
177 行删除
+259
-177
request.js
src/api/request.js
+1
-1
index.js
src/api/riskSignal/index.js
+6
-14
overview.js
src/api/thinkTank/overview.js
+19
-0
index.vue
src/views/thinkTank/ReportDetail/policyTracking/index.vue
+7
-1
index.vue
src/views/thinkTank/ReportDetail/reportAnalysis/index.vue
+1
-0
index.vue
src/views/thinkTank/ThinkTankDetail/PolicyTracking/index.vue
+6
-1
index.vue
src/views/thinkTank/index.vue
+19
-4
index.vue
src/views/viewRiskSignal/index.vue
+200
-156
没有找到文件。
src/api/request.js
浏览文件 @
9e986979
...
...
@@ -113,7 +113,7 @@ service.interceptors.response.use(
}
// 特殊处理:风险信号管理页面接口偶发 500,不弹出提示
// 覆盖接口:/api/riskSignal/
getCountInfo | /api/riskSignal/getDailyCount
| /api/riskSignal/pageQuery
// 覆盖接口:/api/riskSignal/
baseInfo
| /api/riskSignal/pageQuery
try
{
const
errUrl
=
String
(
error
?.
config
?.
url
||
''
)
if
(
error
?.
response
?.
status
===
500
&&
errUrl
.
includes
(
'/api/riskSignal/'
))
{
...
...
src/api/riskSignal/index.js
浏览文件 @
9e986979
import
request
from
"@/api/request.js"
;
/
/ 基本统计信息
export
function
get
Count
Info
()
{
/
** 风险信号管理页:统计 + 日历热力数据(原 getCountInfo + getDailyCount) */
export
function
get
RiskSignalBase
Info
()
{
return
request
({
method
:
'GET'
,
url
:
`/api/riskSignal/getCountInfo`
,
})
}
// 每日统计信息
export
function
getDailyCount
()
{
return
request
({
method
:
'GET'
,
url
:
`/api/riskSignal/getDailyCount`
,
})
method
:
"GET"
,
url
:
`/api/riskSignal/baseInfo`
});
}
// 按条件分页查询风险信号信息
export
function
getPageQuery
(
data
)
{
return
request
({
method
:
'POST'
,
url
:
`/api/riskSignal/
pageQuery
`
,
url
:
`/api/riskSignal/
PageLimit
`
,
data
:
data
})
}
src/api/thinkTank/overview.js
浏览文件 @
9e986979
...
...
@@ -53,6 +53,25 @@ export function getThinkTankPolicyIndustryChange(params) {
});
}
/**
* 智库概览-数量变化趋势(按领域统计)
* GET /thinkTankReport/domainStats
* @param {{ startDate: string, endDate: string }} params
*/
export
function
getThinkTankReportDomainStats
(
params
)
{
return
request
({
method
:
"GET"
,
url
:
`/api/thinkTankReport/domainStats`
,
params
:
{
startDate
:
params
.
startDate
,
endDate
:
params
.
endDate
},
// 与 policyIndustryChange 一致:无数据年份可能返回 400/500,避免走全局错误提示
validateStatus
:
(
status
)
=>
(
status
>=
200
&&
status
<
300
)
||
status
===
400
||
status
===
500
});
}
// 政策建议领域分布
export
function
getThinkTankPolicyIndustry
(
params
)
{
return
request
({
...
...
src/views/thinkTank/ReportDetail/policyTracking/index.vue
浏览文件 @
9e986979
...
...
@@ -21,7 +21,7 @@
<span
class=
"tag-text"
>
{{
tag
}}
(
{{
tagCountMap
[
tag
]
||
0
}}
项)
</span>
</span>
</div>
<div
class=
"item-box"
>
<div
class=
"item-box"
v-loading=
"loading"
>
<div
class=
"item"
v-for=
"(item, index) in filteredOpinions"
:key=
"item.id || index"
:class=
"
{ 'item-active': index === activeItemIndex }" @click="
() => {
...
...
@@ -138,6 +138,7 @@ import {
import
{
useRouter
}
from
"vue-router"
;
import
DefaultNewsImg
from
'@/assets/images/default-icon-news.png'
const
router
=
useRouter
();
const
loading
=
ref
(
false
);
const
searchOpinions
=
ref
(
""
);
// 政策建议相关情况(当前页/当前筛选展示的数据)
const
box1Data
=
ref
([]);
...
...
@@ -277,6 +278,7 @@ const updateTagsFromAllData = () => {
const
handleGetThinkTankReportPolicyAction
=
async
()
=>
{
try
{
loading
.
value
=
true
;
const
params
=
{
reportId
:
router
.
currentRoute
.
_value
.
params
.
id
,
// 这里请求全量数据,前端自行分页
...
...
@@ -312,6 +314,8 @@ const handleGetThinkTankReportPolicyAction = async () => {
box1Data
.
value
=
[];
allTags
.
value
=
[];
tagCountMap
.
value
=
{};
}
finally
{
loading
.
value
=
false
;
}
};
// 按当前标签与页码从全量数据中截取一页
...
...
@@ -765,6 +769,7 @@ onMounted(async () => {
width
:
20px
;
height
:
20px
;
margin-left
:
auto
;
cursor
:
pointer
;
img
{
width
:
100%
;
...
...
@@ -815,6 +820,7 @@ onMounted(async () => {
width
:
20px
;
height
:
20px
;
margin-left
:
auto
;
cursor
:
pointer
;
img
{
width
:
100%
;
...
...
src/views/thinkTank/ReportDetail/reportAnalysis/index.vue
浏览文件 @
9e986979
...
...
@@ -1284,6 +1284,7 @@ onMounted(() => {
height
:
24px
;
margin-top
:
12px
;
margin-left
:
18px
;
cursor
:
pointer
;
}
...
...
src/views/thinkTank/ThinkTankDetail/PolicyTracking/index.vue
浏览文件 @
9e986979
...
...
@@ -226,7 +226,7 @@
</div>
</div>
</div>
<div
class=
"right"
>
<div
class=
"right"
v-loading=
"loading"
>
<div
class=
"right-main"
>
<div
class=
"right-main-item"
v-for=
"item in policyList"
:key=
"item.id"
>
<div
class=
"item-left"
>
...
...
@@ -308,6 +308,8 @@ import { useRouter } from "vue-router";
const
router
=
useRouter
();
const
loading
=
ref
(
false
);
/** 与 AreaTag 一致的领域色(取 tag 的文字色) */
const
AREA_TAG_COLOR_BY_NAME
=
{
"人工智能"
:
"rgba(245, 34, 45, 1)"
,
// tag1
...
...
@@ -1247,6 +1249,7 @@ const handleCurrentChange = page => {
const
handleGetThinkPolicy
=
async
()
=>
{
try
{
loading
.
value
=
true
;
const
thinkTankId
=
router
.
currentRoute
.
_value
.
params
.
id
;
const
domainIds
=
selectedAreaList
.
value
.
filter
((
id
)
=>
id
!=
null
&&
id
!==
""
&&
id
!==
POLICY_FILTER_ALL_AREA
)
...
...
@@ -1292,6 +1295,8 @@ const handleGetThinkPolicy = async () => {
console
.
error
(
"获取智库政策error"
,
error
);
policyList
.
value
=
[];
total
.
value
=
0
;
}
finally
{
loading
.
value
=
false
;
}
};
...
...
src/views/thinkTank/index.vue
浏览文件 @
9e986979
...
...
@@ -456,7 +456,7 @@ import ThinkTankPolicyAdviceOverview from "./components/ThinkTankPolicyAdviceOve
import
{
getThinkTankList
,
getThinkTankRiskSignal
,
getThinkTank
PolicyIndustryChange
,
getThinkTank
ReportDomainStats
,
getThinkTankPolicyIndustry
,
getThinkTankDonation
,
getAllThinkTankList
,
...
...
@@ -1003,10 +1003,25 @@ const changeBox5Data = year => {
// 政策建议趋势分布
const
handleGetThinkTankPolicyIndustryChange
=
async
range
=>
{
try
{
const
res
=
await
getThinkTank
PolicyIndustryChange
(
range
);
console
.
log
(
"
政策建议趋势分布
"
,
res
);
const
res
=
await
getThinkTank
ReportDomainStats
(
range
);
console
.
log
(
"
智库报告数量变化趋势(domainStats)
"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
const
originalData
=
res
.
data
;
const
rawList
=
Array
.
isArray
(
res
.
data
)
?
res
.
data
:
[];
// domainStats:季度维度 + areaList;旧逻辑使用 industryList,这里做字段归一(不改图表样式/结构)
const
originalData
=
rawList
.
map
((
item
)
=>
{
const
industryList
=
Array
.
isArray
(
item
?.
industryList
)
?
item
.
industryList
:
Array
.
isArray
(
item
?.
areaList
)
?
item
.
areaList
:
[];
return
{
...
item
,
year
:
item
?.
year
,
industryList
};
})
.
filter
((
item
)
=>
Array
.
isArray
(
item
.
industryList
)
&&
item
.
industryList
.
length
>
0
);
// 提取年份
const
years
=
originalData
.
map
(
item
=>
item
.
year
);
// 提取所有行业名称
...
...
src/views/viewRiskSignal/index.vue
浏览文件 @
9e986979
...
...
@@ -150,7 +150,7 @@
</div>
</div>
</div>
<div
class=
"right"
>
<div
class=
"right"
v-loading=
"loading"
>
<div
class=
"right-header"
>
<div
class=
"header-left"
>
<div
class=
"btn-left"
:class=
"
{ btnleftactive: activeProcessStatusId === item.id }"
...
...
@@ -187,18 +187,17 @@
<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=
"risktitle"
v-html=
"highlightRiskText(val.title)"
/
>
<div
class=
"risktype"
:class=
"'risktype--' + getRiskListItemLevelKey(val.risktype)"
>
<div
class=
"icon"
:class=
"'icon--' + getRiskListItemLevelKey(val.risktype)"
/>
<div
class=
"text"
>
{{ getRiskListItemLevelLabel(val.risktype) }}
</div>
</div>
</div>
<div
class=
"box-source"
>
<img
class=
"source-pic"
:src=
"DefaultIcon2"
alt=
""
/>
<div
class=
"source-text"
>
{{ val.origin }}
</div>
<div
class=
"source-text"
>
{{ val.time }}
</div>
<img
class=
"source-pic"
:src=
"val.pic || DefaultIcon2"
alt=
""
/>
<div
class=
"source-text"
>
{{ formatRiskSourceLine(val) }}
</div>
</div>
<div
class=
"desc-box"
>
{{ val.dsc }}
</div
>
<div
class=
"desc-box"
v-html=
"highlightRiskText(val.dsc)"
/
>
<div
class=
"tag-box"
v-if=
"val.tag.length"
>
<AreaTag
v-for=
"(tag, index) in val.tag"
:key=
"index"
:tagName=
"tag"
>
{{ tag }}
</AreaTag>
</div>
...
...
@@ -206,7 +205,7 @@
</div>
<div
class=
"right-footer"
>
<div
class=
"footer-left"
>
{{ `共 ${
totalNum} 项
调查` }}
{{ `共 ${
formatRiskStatCount(totalNum)}
调查` }}
</div>
<div
class=
"footer-right"
>
<el-pagination
@
current-change=
"handleCurrentChange"
:pageSize=
"pageSize"
:current-page=
"currentPage"
...
...
@@ -241,7 +240,7 @@
<div
class=
"risk-signal-detail-dialog_relation"
>
<div
class=
"relation"
>
<div
class=
"logo"
><img
src=
"./assets/images/logo.png"
alt=
""
/></div>
<div
class=
"name-text"
>
{{ "总统行政令
——
" }}
</div>
<div
class=
"name-text"
>
{{ "总统行政令" }}
</div>
<div
class=
"content-text"
>
{{ "关于调整进口木材、锯材及其衍生产品进入美国的相关修正案" }}
</div>
</div>
<div
class=
"right-arrow"
><img
src=
"./assets/images/right-arrow.png"
alt=
""
/></div>
...
...
@@ -260,7 +259,7 @@
import
{
computed
,
nextTick
,
onMounted
,
reactive
,
ref
,
watch
}
from
"vue"
;
import
{
useRoute
,
useRouter
}
from
"vue-router"
;
import
{
OPEN_FIRST_RISK_DETAIL_QUERY_KEY
}
from
"@/utils/riskSignalOverviewNavigate"
;
import
{
get
CountInfo
,
getDailyCount
,
getPageQuery
}
from
"@/api/riskSignal/index"
;
import
{
get
RiskSignalBaseInfo
,
getPageQuery
}
from
"@/api/riskSignal/index"
;
import
{
getHylyList
}
from
"@/api/thinkTank/overview"
;
import
setChart
from
"@/utils/setChart"
;
...
...
@@ -410,79 +409,7 @@ const handleClickBtn = item => {
handleGetPageQuery
();
};
const
riskList
=
ref
([
{
rowKey
:
"risk-demo-1"
,
title
:
"扩大实体清单制裁范围,对中企子公司实施同等管制"
,
origin
:
"美国商务部"
,
fileType
:
"实体清单"
,
time
:
"2025年11月10日 16:14"
,
dsc
:
"任何被列入美国出口管制“实体清单”或“军事最终用户清单”的企业,如果其直接或间接持有另一家公司 50%或以上的股权,那么这家被控股的公司也将自动受到与清单上母公司同等的出口管制限制"
,
tag
:
[
"生物科技"
,
"人工智能"
],
risktype
:
"特别重大风险"
,
pic
:
"src/views/riskSignal/assets/images/origin1.png"
},
{
rowKey
:
"risk-demo-2"
,
title
:
"大而美法案通过国会众议院投票,将提交至总统签署"
,
origin
:
"美国国会 · 科技法案"
,
time
:
"2025年11月10日 16:14"
,
dsc
:
""
,
tag
:
[
"能源"
,
"人工智能"
],
risktype
:
"重大风险"
,
pic
:
"src/views/riskSignal/assets/images/origin2.png"
,
textcolor
:
"rgba(255, 149, 77, 1)"
,
bgcolor
:
"rgba(255, 149, 77, 0.1)"
},
{
rowKey
:
"risk-demo-3"
,
title
:
"兰德公司发布智库报告《中美经济竞争:复杂经济和地缘政治关系中的收益和风险》"
,
origin
:
"兰德公司 · 科技智库"
,
time
:
"2025年11月10日 16:14"
,
dsc
:
"包括经济竞争在内的美中竞争自2017年以来一直在定义美国外交政策。这两个经济体是世界上第一和第二大国家经济体,并且深深交织在一起。改变关系,无论多么必要,可能是昂贵的。因此,美国面临着一项挑战,确保其经济在耦合的战略竞争条件下满足国家的需求。"
,
tag
:
[
"生物科技"
,
"人工智能"
,
"集成电路"
],
risktype
:
"一般风险"
,
pic
:
"src/views/riskSignal/assets/images/origin3.png"
,
textcolor
:
"rgba(5, 95, 194, 1)"
,
bgcolor
:
"rgba(5, 95, 194, 0.1)"
},
{
rowKey
:
"risk-demo-4"
,
title
:
"美国白宫发布总统政令《关于进一步延长TikTok执法宽限期的行政令》"
,
origin
:
"美国白宫 · 总统政令"
,
time
:
"2025年11月10日 16:14"
,
dsc
:
"再次推迟(第四次)对TikTok禁令的执法,新的宽限期截止日为2025年12月16日。在宽限期内及对于宽限期前的行为,司法部不得强制执行《保护美国人免受外国对手控制应用程序法》或因此处罚相关实体(如TikTok及其分发平台)。"
,
tag
:
[
"人工智能"
],
risktype
:
"一般风险"
,
pic
:
"src/views/riskSignal/assets/images/origin2.png"
,
textcolor
:
"rgba(5, 95, 194, 1)"
,
bgcolor
:
"rgba(5, 95, 194, 0.1)"
},
{
rowKey
:
"risk-demo-5"
,
title
:
"美国财政部更新《特别指定国民清单》"
,
origin
:
"美国财政部 · 特别指定国民清单"
,
time
:
"2025年11月10日 16:14"
,
dsc
:
""
,
tag
:
[
"生物科技"
],
risktype
:
"特别重大风险"
,
pic
:
"src/views/riskSignal/assets/images/origin4.png"
,
textcolor
:
"rgba(206, 79, 81, 1)"
,
bgcolor
:
"rgba(206, 79, 81, 0.1)"
},
{
rowKey
:
"risk-demo-6"
,
title
:
"美国FDA针对两家中国第三方检测机构的数据完整性问题采取行动"
,
origin
:
"美国食品药品监督管理局 · 规则限制"
,
time
:
"2025年11月10日 16:14"
,
dsc
:
"FDA因发现数据伪造或无效问题,向两家中国第三方检测公司(天津中联科技检测有限公司和苏州大学卫生与环境技术研究所)正式发出“一般信函”。"
,
tag
:
[
"生物科技"
,
"人工智能"
],
risktype
:
"特别重大风险"
,
pic
:
"src/views/riskSignal/assets/images/origin5.png"
,
textcolor
:
"rgba(206, 79, 81, 1)"
,
bgcolor
:
"rgba(206, 79, 81, 0.1)"
}
]);
const
riskList
=
ref
([]);
const
isRiskDetailVisible
=
ref
(
false
);
const
riskDetailItem
=
reactive
({
...
...
@@ -572,32 +499,49 @@ const basicInfo = ref({
pendingCount
:
0
,
yearAdded
:
0
});
const
handleGetCountInfo
=
async
()
=>
{
try
{
const
res
=
await
getCountInfo
();
console
.
log
(
"基本统计信息"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
basicInfo
.
value
=
res
.
data
;
/** 风险统计:按数量级压缩展示(保留两位小数) */
const
formatRiskStatCount
=
(
raw
)
=>
{
const
n
=
Math
.
floor
(
Number
(
raw
)
||
0
);
if
(
n
>=
1000000
)
{
return
`
${(
n
/
1000000
).
toFixed
(
2
)}
百万项`
;
}
if
(
n
>=
100000
)
{
return
`
${(
n
/
100000
).
toFixed
(
2
)}
十万项`
;
}
if
(
n
>=
10000
)
{
return
`
${(
n
/
10000
).
toFixed
(
2
)}
万项`
;
}
}
catch
(
error
)
{
}
return
`
${
n
}
项`
;
};
/
/ 每日统计信息
const
handleGet
DailyCount
=
async
()
=>
{
/
** 合并 baseInfo:顶部统计 + 热力图 dateList(eventTime / total) */
const
handleGet
RiskSignalBaseInfo
=
async
()
=>
{
try
{
const
res
=
await
getDailyCount
();
console
.
log
(
"每日统计信息"
,
res
);
const
res
=
await
getRiskSignalBaseInfo
();
if
(
res
.
code
===
200
&&
res
.
data
)
{
calendarData
.
value
=
res
.
data
.
map
(
item
=>
{
return
[
item
.
day
,
item
.
count
];
const
d
=
res
.
data
;
basicInfo
.
value
=
{
yearAdded
:
Number
(
d
.
yearAdded
)
||
0
,
monthAdded
:
Number
(
d
.
monthAdded
)
||
0
,
dealCount
:
Number
(
d
.
dealCount
)
||
0
,
pendingCount
:
Number
(
d
.
pendingCount
)
||
0
};
const
list
=
Array
.
isArray
(
d
.
dateList
)
?
d
.
dateList
:
[];
calendarData
.
value
=
list
.
map
((
item
)
=>
{
const
day
=
item
.
eventTime
??
item
.
day
??
""
;
const
count
=
item
.
total
??
item
.
count
??
0
;
return
[
day
,
Number
(
count
)
||
0
];
});
}
}
catch
(
error
)
{
}
}
catch
(
error
)
{
console
.
error
(
"风险信号 baseInfo"
,
error
);
}
};
const
handleCleandarChart
=
async
()
=>
{
await
handleGet
DailyCount
();
le
t
chartCalendar
=
getCalendarHeatChart
(
calendarData
.
value
);
await
handleGet
RiskSignalBaseInfo
();
cons
t
chartCalendar
=
getCalendarHeatChart
(
calendarData
.
value
);
setChart
(
chartCalendar
,
"chartCalendar"
);
};
...
...
@@ -626,8 +570,40 @@ const handleSearch = async () => {
handleGetPageQuery
();
};
const
loading
=
ref
(
false
);
const
escapeHtml
=
(
text
)
=>
{
return
String
(
text
??
""
)
.
replace
(
/&/g
,
"&"
)
.
replace
(
/</g
,
"<"
)
.
replace
(
/>/g
,
">"
)
.
replace
(
/"/g
,
"""
)
.
replace
(
/'/g
,
"'"
);
};
const
escapeRegExp
=
(
text
)
=>
{
return
String
(
text
??
""
).
replace
(
/
[
.*+?^${}()|[
\]\\]
/g
,
"
\\
$&"
);
};
const
highlightRiskText
=
(
text
)
=>
{
const
safeText
=
escapeHtml
(
text
);
const
keyword
=
(
kewword
.
value
||
""
).
trim
();
if
(
!
keyword
)
return
safeText
;
const
pattern
=
new
RegExp
(
`(
${
escapeRegExp
(
keyword
)}
)`
,
"gi"
);
return
safeText
.
replace
(
pattern
,
`<span class="risk-keyword-highlight">$1</span>`
);
};
const
formatRiskSourceLine
=
(
row
)
=>
{
const
origin
=
String
(
row
?.
origin
??
""
).
trim
();
const
typeName
=
String
(
row
?.
typeName
??
""
).
trim
();
const
time
=
String
(
row
?.
time
??
""
).
trim
();
const
left
=
typeName
?
`
${
origin
}
·
${
typeName
}
`
:
origin
;
if
(
left
&&
time
)
return
`
${
left
}
${
time
}
`
;
return
left
||
time
;
};
// 风险信号总数
const
totalNum
=
ref
(
6
);
const
totalNum
=
ref
(
0
);
const
currentPage
=
ref
(
1
);
const
pageSize
=
ref
(
10
);
// 处理页码改变事件
...
...
@@ -636,91 +612,142 @@ const handleCurrentChange = page => {
handleGetPageQuery
();
};
// 按条件分页查询风险信号信息
/** PageLimit 列表项:领域标签(优先 domainNames,兼容 domainName / domains) */
const
parseRiskSignalTagList
=
(
item
)
=>
{
const
names
=
item
?.
domainNames
;
if
(
names
!=
null
&&
String
(
names
).
trim
()
!==
""
)
{
return
String
(
names
)
.
split
(
/
[
,,、;;|
]
+/
)
.
map
((
s
)
=>
s
.
trim
())
.
filter
(
Boolean
);
}
const
dn
=
item
?.
domainName
;
if
(
dn
!=
null
&&
String
(
dn
).
trim
()
!==
""
)
{
return
[
String
(
dn
).
trim
()];
}
const
raw
=
item
?.
domains
;
if
(
Array
.
isArray
(
raw
))
{
return
raw
.
map
((
d
)
=>
(
typeof
d
===
"string"
?
d
:
d
?.
name
)).
filter
(
Boolean
);
}
if
(
typeof
raw
===
"string"
&&
raw
.
trim
())
{
return
raw
.
split
(
/
[
,,
]
/
).
map
((
s
)
=>
s
.
trim
()).
filter
(
Boolean
);
}
return
[];
};
/** 发布时间:YYYY-MM-DD HH:mm:ss →「2026年1月26日 00:00」;仅日期则「2026年1月26日」 */
const
formatRiskPublishDisplay
=
(
raw
)
=>
{
if
(
raw
==
null
||
raw
===
""
)
{
return
""
;
}
const
s
=
String
(
raw
).
trim
();
const
dt
=
s
.
match
(
/^
(\d{4})
-
(\d{1,2})
-
(\d{1,2})\s
+
(\d{1,2})
:
(\d{2})(?:
:
(\d{2}))?
/
);
if
(
dt
)
{
const
h
=
String
(
Number
(
dt
[
4
])).
padStart
(
2
,
"0"
);
const
mi
=
String
(
Number
(
dt
[
5
])).
padStart
(
2
,
"0"
);
return
`
${
Number
(
dt
[
1
])}
年
${
Number
(
dt
[
2
])}
月
${
Number
(
dt
[
3
])}
日
${
h
}
:
${
mi
}
`
;
}
const
m
=
s
.
match
(
/^
(\d{4})
-
(\d{1,2})
-
(\d{1,2})(?:
$|
[
T
\s])
/
);
if
(
m
)
{
return
`
${
Number
(
m
[
1
])}
年
${
Number
(
m
[
2
])}
月
${
Number
(
m
[
3
])}
日`
;
}
return
s
;
};
// 按条件分页查询风险信号信息(POST /api/riskSignal/PageLimit)
const
handleGetPageQuery
=
async
()
=>
{
const
stripAll
=
(
list
,
allLabel
)
=>
(
Array
.
isArray
(
list
)
?
list
.
filter
((
x
)
=>
x
!==
allLabel
)
:
[]);
// 选中「全部xxx」时,传空数组表示不按该条件过滤(与之前未勾选时语义一致)
const
riskTypes
=
stripAll
(
selectedRiskTypeModel
.
value
,
RISK_FILTER_ALL_TYPE
);
const
srcCountryList
=
stripAll
(
selectedRiskSourceModel
.
value
,
RISK_FILTER_ALL_SOURCE
);
const
riskLevels
=
stripAll
(
selectedRiskDegreeModel
.
value
,
RISK_FILTER_ALL_LEVEL
);
const
techDomainIds
=
stripAll
(
selectedAreaModel
.
value
,
RISK_FILTER_ALL_AREA
);
stripAll
(
selectedAreaModel
.
value
,
RISK_FILTER_ALL_AREA
);
const
timeFilters
=
stripAll
(
selectedTimeModel
.
value
,
Time_FILTER_ALL_SOURCE
);
const
pad2
=
(
n
)
=>
String
(
n
).
padStart
(
2
,
"0"
);
const
formatYmd
=
(
d
)
=>
`
${
d
.
getFullYear
()}
-
${
pad2
(
d
.
getMonth
()
+
1
)}
-
${
pad2
(
d
.
getDate
())}
`
;
const
buildStartDateFromTimeFilter
=
()
=>
{
if
(
!
timeFilters
.
length
)
return
""
;
// 单选时间窗:取第一个即可(normalizeExclusiveAllOption 已保证互斥)
const
id
=
timeFilters
[
0
];
const
now
=
new
Date
();
const
start
=
new
Date
(
now
);
if
(
id
===
TIME_FILTER_1M
)
start
.
setMonth
(
start
.
getMonth
()
-
1
);
else
if
(
id
===
TIME_FILTER_3M
)
start
.
setMonth
(
start
.
getMonth
()
-
3
);
else
if
(
id
===
TIME_FILTER_6M
)
start
.
setMonth
(
start
.
getMonth
()
-
6
);
else
if
(
id
===
TIME_FILTER_1Y
)
start
.
setFullYear
(
start
.
getFullYear
()
-
1
);
else
return
""
;
return
formatYmd
(
start
);
// 发布时间筛选统一传 day(后端:全部时间=900000,近一年=365,其它同理)
const
getDayFromTimeFilter
=
()
=>
{
// 选中「全部时间」或未选具体时间 → 走全量
if
(
!
timeFilters
.
length
)
return
900000
;
const
getDaysById
=
(
id
)
=>
{
if
(
id
===
TIME_FILTER_1M
)
return
30
;
if
(
id
===
TIME_FILTER_3M
)
return
90
;
if
(
id
===
TIME_FILTER_6M
)
return
180
;
if
(
id
===
TIME_FILTER_1Y
)
return
365
;
return
null
;
};
// 多选:以最大时间窗为准(如 近一月 + 近一年 => 365)
const
days
=
(
timeFilters
||
[])
.
map
((
id
)
=>
getDaysById
(
id
))
.
filter
((
x
)
=>
typeof
x
===
"number"
&&
!
Number
.
isNaN
(
x
));
return
days
.
length
?
Math
.
max
(...
days
)
:
900000
;
};
const
startDate
=
buildStartDateFromTimeFilter
();
const
endDate
=
timeFilters
.
length
?
formatYmd
(
new
Date
())
:
""
;
const
day
=
getDayFromTimeFilter
();
let
params
;
if
(
activeProcessStatusId
.
value
===
-
1
)
{
params
=
{
riskTypes
,
srcCountryList
,
countryId
:
srcCountryList
,
directionId
:
[],
riskLevels
,
techDomainIds
,
startDate
,
endDate
,
keywords
:
kewword
.
value
,
pageNum
:
currentPage
.
value
,
pageSize
:
pageSize
.
value
,
sortField
:
"time"
,
sortOrder
:
sortModel
.
value
===
true
?
"asc"
:
"desc"
day
,
keyWord
:
kewword
.
value
,
pageNum
:
currentPage
.
value
-
1
,
pageSize
:
pageSize
.
value
};
}
else
{
params
=
{
riskTypes
,
srcCountryList
,
countryId
:
srcCountryList
,
directionId
:
[],
riskLevels
,
techDomainIds
,
dealStatus
:
activeProcessStatusId
.
value
,
startDate
,
endDate
,
keywords
:
kewword
.
value
,
pageNum
:
1
,
pageSize
:
10
,
sortField
:
"time"
,
sortOrder
:
sortModel
.
value
===
true
?
"asc"
:
"desc"
day
,
keyWord
:
kewword
.
value
,
pageNum
:
currentPage
.
value
-
1
,
pageSize
:
pageSize
.
value
};
}
try
{
loading
.
value
=
true
;
const
res
=
await
getPageQuery
(
params
);
console
.
log
(
"按条件查询"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
totalNum
.
value
=
res
.
data
.
totalElements
;
riskList
.
value
=
res
.
data
.
content
.
map
((
item
,
i
)
=>
{
const
d
=
res
.
data
;
const
content
=
Array
.
isArray
(
d
.
content
)
?
d
.
content
:
[];
totalNum
.
value
=
Number
(
d
.
totalElements
??
d
.
total
??
content
.
length
)
||
0
;
riskList
.
value
=
content
.
map
((
item
,
i
)
=>
{
const
stableId
=
item
.
id
??
item
.
riskId
??
item
.
riskSignalId
;
const
title
=
item
.
title
??
item
.
titleZh
??
""
;
const
publishRaw
=
item
.
publishDate
??
item
.
time
??
""
;
return
{
rowKey
:
stableId
!=
null
?
String
(
stableId
)
:
`p
${
currentPage
.
value
}
-i
${
i
}
-
${
String
(
item
.
time
??
""
)}
-
$
{
String
(
item
.
titleZh
??
""
)}
`,
title
: item.titleZh
,
origin: item.
srcOrgId
,
fileType: "暂无数据
",
time:
item.time
,
dsc: item.contentZh,
tag:
[]
,
risktype: item.
level
,
pic: ""
:
`p
${
currentPage
.
value
}
-i
${
i
}
-
${
String
(
publishRaw
)}
-
${
String
(
title
)}
`
,
title
,
origin
:
item
.
orgName
!=
null
&&
String
(
item
.
orgName
).
trim
()
!==
""
?
String
(
item
.
orgName
).
trim
()
:
""
,
typeName
:
item
.
typeName
??
item
.
type
??
item
.
modle
??
item
.
module
??
"
"
,
time
:
formatRiskPublishDisplay
(
publishRaw
)
||
String
(
publishRaw
||
""
)
,
dsc
:
item
.
contentZh
??
item
.
summary
??
item
.
description
??
""
,
tag
:
parseRiskSignalTagList
(
item
)
,
risktype
:
item
.
riskLevel
??
item
.
level
??
""
,
pic
:
item
.
orgLogo
||
""
};
});
}
else
{
riskList
.
value
=
[];
totalNum
.
value
=
0
;
}
}
catch
(
error
)
{
console
.
error
(
"按条件查询error"
,
error
);
riskList
.
value
=
[];
totalNum
.
value
=
0
;
}
finally
{
loading
.
value
=
false
;
}
};
...
...
@@ -736,12 +763,11 @@ watch(
);
onMounted
(
async
()
=>
{
handleGetCountInfo();
handleCleandarChart
();
await
handleGetHylyList();
await
handleGetPageQuery();
await
nextTick();
await
consumeOpenFirstDetailFromQuery();
handleGetHylyList
();
handleGetPageQuery
();
nextTick
();
consumeOpenFirstDetailFromQuery
();
});
</
script
>
...
...
@@ -764,7 +790,7 @@ onMounted(async () => {
background-size
:
100%
100%
;
.home-main-center
{
margin-top
:
34
px
;
margin-top
:
16
px
;
.center-center
{
margin
:
0
auto
;
...
...
@@ -902,7 +928,7 @@ onMounted(async () => {
.home-main-footer-main
{
width
:
1600px
;
margin
:
30
px
auto
;
margin
:
16
px
auto
;
/* 意思:上30px / 左右auto / 下300px */
box-sizing
:
border-box
;
// padding: 20px;
...
...
@@ -910,7 +936,7 @@ onMounted(async () => {
.left
{
width
:
388px
;
margin-bottom
:
24px
;
border-radius
:
10px
;
padding-bottom
:
24px
;
box-sizing
:
border-box
;
...
...
@@ -985,7 +1011,8 @@ onMounted(async () => {
margin-left
:
16px
;
margin-bottom
:
24px
;
width
:
1196px
;
height
:
1821px
;
position
:
relative
;
border-radius
:
10px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
60
,
87
,
126
,
0
.2
);
background
:
rgba
(
255
,
255
,
255
,
1
);
...
...
@@ -1074,9 +1101,10 @@ onMounted(async () => {
.right-main
{
width
:
1196px
;
min-height
:
1667px
;
padding-left
:
18px
;
padding-top
:
6px
;
min-height
:
520px
;
.itemlist
{
padding-left
:
25px
;
...
...
@@ -1094,10 +1122,20 @@ onMounted(async () => {
justify-content
:
space-between
;
.risktitle
{
max-width
:
857px
;
font-size
:
18px
;
font-weight
:
700
;
line-height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
flex
:
0
1
auto
;
:deep
(
.risk-keyword-highlight
)
{
background
:
rgba
(
255
,
204
,
0
,
0
.35
);
color
:
inherit
;
}
}
.risktype
{
...
...
@@ -1111,6 +1149,7 @@ onMounted(async () => {
justify-content
:
center
;
align-items
:
center
;
gap
:
6px
;
flex
:
0
0
auto
;
.icon
{
width
:
4px
;
...
...
@@ -1193,6 +1232,11 @@ onMounted(async () => {
line-height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
text-align
:
justify
;
:deep
(
.risk-keyword-highlight
)
{
background
:
rgba
(
255
,
204
,
0
,
0
.35
);
color
:
inherit
;
}
}
.tag-box
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论