Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
351ae3b2
提交
351ae3b2
authored
3月 25, 2026
作者:
yanpeng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
exportControl 修改
上级
bb9c644a
全部展开
显示空白字符变更
内嵌
并排
正在显示
10 个修改的文件
包含
216 行增加
和
42 行删除
+216
-42
index.js
src/api/zmOverview/risk/index.js
+27
-28
index.vue
src/views/ZMOverView/components/gameProfile/index.vue
+30
-2
index.vue
src/views/ZMOverView/index.vue
+1
-1
index.vue
src/views/decree/decreeHome/index.vue
+0
-0
index.vue
src/views/exportControl/index.vue
+82
-7
charts.js
src/views/exportControl/utils/charts.js
+7
-0
common.js
src/views/exportControl/utils/common.js
+63
-0
index.vue
...omponents/sanctionsOverview/components/listPage/index.vue
+0
-0
index.vue
...v2.0SingleSanction/components/sanctionsOverview/index.vue
+6
-4
index.vue
src/views/thinkTank/index.vue
+0
-0
没有找到文件。
src/api/zmOverview/risk/index.js
浏览文件 @
351ae3b2
...
...
@@ -3,66 +3,65 @@ import request from "@/api/request.js";
// 中美博弈概览V2:最新风险动态统计
export
function
getLatestRiskUpdates
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/rivalryIndexV2/LatestRiskUpdates`
,
params
:
params
})
});
}
// 中美博弈概览V2:最新风险信号
export
function
getLatestRisks
()
{
return
request
({
method
:
'GET'
,
url
:
`/api/rivalryIndexV2/LatestRisks`
,
})
method
:
"GET"
,
url
:
`/api/rivalryIndexV2/LatestRisks`
});
}
// 中美博弈概览V2:美对华制裁措施数量趋势
export
function
geDomainContainmentTrend
(
params
)
{
return
request
({
method
:
'GET'
,
method
:
"GET"
,
url
:
`/api/rivalryIndexV2/DomainContainmentTrend`
,
params
:
params
})
});
}
// 中美博弈概况:获取榜单字典
export
function
getChartDict
()
{
return
request
({
method
:
'GET'
,
url
:
`/api/union/summary/chartDict`
,
})
method
:
"GET"
,
url
:
`/api/union/summary/chartDict`
});
}
// 根据字典信息,获取年份信息
export
function
getYearDict
(
id
)
{
return
request
({
method
:
"GET"
,
url
:
`/api/union/summary/chartYear/
${
id
}
`
});
}
// 中美博弈概况:中美科技实力对比
export
function
getCompare
(
id
)
{
export
function
getCompare
(
id
,
year
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/union/summary/compare/
${
id
}
`
,
})
method
:
"GET"
,
url
:
`/api/union/summary/compare/
${
id
}
/
${
year
}
`
});
}
// 中美博弈分析
export
function
getTechnologyGameAnalysis
()
{
return
request
({
method
:
'GET'
,
url
:
`/api/rivalryIndexV2/TechnologyGameAnalysis`
,
})
method
:
"GET"
,
url
:
`/api/rivalryIndexV2/TechnologyGameAnalysis`
});
}
//中美博弈概览V7:美国政府部门对华制裁最新动态
export
function
getGovernmentSanctionsDynamics
()
{
return
request
({
method
:
'GET'
,
url
:
`/api/rivalryIndex/governmentSanctionsDynamics`
,
})
method
:
"GET"
,
url
:
`/api/rivalryIndex/governmentSanctionsDynamics`
});
}
src/views/ZMOverView/components/gameProfile/index.vue
浏览文件 @
351ae3b2
...
...
@@ -18,6 +18,15 @@
>
<el-option
:value=
"value.id"
:label=
"value.name"
v-for=
"(value, index) in originList"
:key=
"index"
/>
</el-select>
<el-select
class=
"select-item"
size=
"default"
style=
"margin-left: 15px; width: 200px; height: 32px"
v-model=
"year"
@
change=
"handleGetCompare()"
>
<el-option
:value=
"value"
:label=
"value"
v-for=
"(value, index) in yearList"
:key=
"index"
/>
</el-select>
</div>
</div>
<div
style=
"display: flex; height: 650px; width: 100%; padding-top: 12px"
>
...
...
@@ -237,7 +246,7 @@ import Echarts from "@/components/Chart/index.vue";
import
mockData
from
"./mock.json"
;
import
radarChart
from
"./radarChart3.js"
;
import
{
getCompare
,
getChartDict
,
getTechnologyGameAnalysis
}
from
"@/api/zmOverview/risk/index.js"
;
import
{
getCompare
,
getChartDict
,
get
YearDict
,
get
TechnologyGameAnalysis
}
from
"@/api/zmOverview/risk/index.js"
;
import
icon1
from
"./icon/btn-icon-0.png"
;
import
icon2
from
"./icon/btn-icon-1.png"
;
import
icon3
from
"./icon/btn-icon-2.png"
;
...
...
@@ -351,10 +360,27 @@ const handleGetChartDict = async () => {
console
.
error
(
"获取数据来源error"
,
error
);
}
};
const
yearList
=
ref
([]);
const
year
=
ref
(
""
);
//年份
const
handleGetYearDict
=
async
()
=>
{
try
{
const
res
=
await
getYearDict
(
origin
.
value
);
console
.
log
(
"年份"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
yearList
.
value
=
res
.
data
;
year
.
value
=
res
.
data
[
0
];
}
}
catch
(
error
)
{
console
.
error
(
"获取年份error"
,
error
);
}
};
//中美科技实力对比
const
handleGetCompare
=
async
()
=>
{
try
{
const
res
=
await
getCompare
(
origin
.
value
);
const
res
=
await
getCompare
(
origin
.
value
,
year
.
value
);
console
.
log
(
"中美科技实力对比"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
tableData
.
value
=
res
.
data
[
0
].
children
;
...
...
@@ -392,6 +418,7 @@ const handlegetTechnologyGameAnalysis = async () => {
};
onMounted
(
async
()
=>
{
await
handleGetChartDict
();
await
handleGetYearDict
();
await
handleGetCompare
();
await
handlegetTechnologyGameAnalysis
();
// const dom = document.getElementById("char");
...
...
@@ -566,6 +593,7 @@ const lineOption = ref({
},
yAxis
:
{
type
:
"value"
,
min
:
77
,
// name: "指数",
nameLocation
:
"top"
,
nameGap
:
35
,
...
...
src/views/ZMOverView/index.vue
浏览文件 @
351ae3b2
...
...
@@ -37,7 +37,7 @@
<fourSuppress></fourSuppress>
<!-- 中美博弈概况 -->
<commonTitle
id=
"zm-overview"
title=
"中美博弈概况"
style=
"margin-top: 64px; margin-bottom: 36px"
></commonTitle>
<gameProfile
></gameProfile
>
<gameProfile
/
>
<div
class=
"bottom-info"
>
<div
class=
"info-item"
>
<div
class=
"info-item-left"
>
...
...
src/views/decree/decreeHome/index.vue
浏览文件 @
351ae3b2
差异被折叠。
点击展开。
src/views/exportControl/index.vue
浏览文件 @
351ae3b2
...
...
@@ -368,19 +368,29 @@
</el-col>
</el-row>
<el-row
:gutter=
"20"
style=
"width: 1600px; margin: 0 auto; height: 5
05
px; margin-top: 16px"
>
<el-row
:gutter=
"20"
style=
"width: 1600px; margin: 0 auto; height: 5
40
px; margin-top: 16px"
>
<el-col
:span=
"8"
>
<custom-container
title=
"实体领域分布"
:titleIcon=
"radarIcon"
height=
"
48
0px"
>
<custom-container
title=
"实体领域分布"
:titleIcon=
"radarIcon"
height=
"
52
0px"
>
<
template
#
header-right
>
<el-checkbox
v-model=
"domainChecked"
label=
"50%规则"
size=
"large"
/>
</
template
>
<
template
#
default
>
<EChart
:option=
"radarOption"
autoresize
:style=
"
{ height: '460px' }" />
<EChart
:option=
"radarOption"
autoresize
:style=
"
{ height: '400px' }" />
<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=
"radarChart.interpretation"
/>
</div>
</
template
>
</custom-container>
</el-col>
<el-col
:span=
"16"
>
<custom-container
title=
"实体清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"
48
0px"
>
<custom-container
title=
"实体清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"
52
0px"
>
<
template
#
header-right
>
<div
style=
"display: flex; align-items: center; gap: 16px"
>
<el-checkbox
v-model=
"trendChecked"
label=
"50%规则"
size=
"large"
/>
...
...
@@ -391,6 +401,16 @@
</
template
>
<
template
#
default
>
<EChart
:option=
"trendOption"
autoresize
:style=
"
{ height: '400px' }" />
<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=
"trendChart.interpretation"
/>
</div>
</
template
>
</custom-container>
</el-col>
...
...
@@ -703,7 +723,7 @@
<
script
setup
>
//这是一个备注
import
NewsList
from
"@/components/base/newsList/index.vue"
;
import
RiskSignal
from
"@/components/base/
R
iskSignal/index.vue"
;
import
RiskSignal
from
"@/components/base/
r
iskSignal/index.vue"
;
import
{
onMounted
,
ref
,
computed
,
reactive
,
shallowRef
,
watch
,
nextTick
}
from
"vue"
;
import
{
useContainerScroll
}
from
"@/hooks/useScrollShow"
;
const
homeMainRef
=
ref
(
null
);
...
...
@@ -712,9 +732,10 @@ import * as echarts from "echarts";
import
setChart
from
"@/utils/setChart"
;
import
{
ElMessage
,
ElMessageBox
}
from
"element-plus"
;
import
{
DArrowRight
,
Warning
,
Search
}
from
"@element-plus/icons-vue"
;
import
{
DArrowRight
,
Warning
,
Search
,
TrendCharts
}
from
"@element-plus/icons-vue"
;
import
EChart
from
"@/components/Chart/index.vue"
;
import
{
TAGTYPE
}
from
"@/public/constant"
;
import
{
useChartInterpretation
}
from
"@/views/exportControl/utils/common"
;
import
{
useGotoCompanyPages
}
from
"@/router/modules/company"
;
import
{
useGotoNewsDetail
}
from
"@/router/modules/news"
;
const
gotoCompanyPages
=
useGotoCompanyPages
();
...
...
@@ -726,6 +747,8 @@ const router = useRouter();
import
CustomContainer
from
"@/components/Container/index.vue"
;
import
ClickableCard
from
"./components/link.vue"
;
import
AiButton
from
"@/components/base/Ai/AiButton/index.vue"
;
import
AiPane
from
"@/components/base/Ai/AiPane/index.vue"
;
import
InfoCard
from
"./components/info.vue"
;
import
CustomTitle
from
"./components/title.vue"
;
import
CommonPrompt
from
"./commonPrompt/index.vue"
;
...
...
@@ -746,6 +769,7 @@ 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
tipsIcon
from
"./assets/icons/info-icon.png"
;
import
{
getEntitiesDataCount
,
getEntitiesDataInfo
,
...
...
@@ -1015,6 +1039,7 @@ const handleToSocialDetail = item => {
});
window
.
open
(
route
.
href
,
"_blank"
);
};
const
trendChart
=
useChartInterpretation
();
// 获取趋势图数据
const
fetchTrendData
=
async
()
=>
{
try
{
...
...
@@ -1026,6 +1051,7 @@ const fetchTrendData = async () => {
});
if
(
res
&&
res
[
0
]
&&
res
[
0
].
yearDomainCount
)
{
trendOption
.
value
=
processYearDomainCountData
(
res
[
0
].
yearDomainCount
);
trendChart
.
interpret
({
type
:
"柱状图"
,
name
:
"实体清单数量增长趋势"
,
data
:
res
[
0
].
yearDomainCount
});
}
}
catch
(
error
)
{
console
.
error
(
"获取趋势图数据失败:"
,
error
);
...
...
@@ -1205,7 +1231,7 @@ const radarOption = ref({
},
radar
:
{
radius
:
"60%"
,
center
:
[
"5
0%"
,
"50
%"
],
center
:
[
"5
2%"
,
"45
%"
],
// shape: 'circle',
indicator
:
[],
axisName
:
{
...
...
@@ -1225,11 +1251,14 @@ const radarOption = ref({
]
});
const
radarChart
=
useChartInterpretation
();
// 获取雷达图数据
const
fetchRadarData
=
async
checked
=>
{
try
{
const
data
=
await
getSanDomainCount
(
checked
,
"export"
);
console
.
log
(
"雷达数据data"
,
data
);
if
(
data
&&
Array
.
isArray
(
data
)
&&
data
.
length
>
0
)
{
radarChart
.
interpret
({
type
:
"雷达图"
,
name
:
"实体领域分布"
,
data
:
data
});
// 收集所有可能的领域名称
const
allDomains
=
new
Set
();
data
.
forEach
(
item
=>
{
...
...
@@ -3597,4 +3626,50 @@ const handleMediaClick = item => {
background
:
rgba
(
255
,
255
,
255
,
1
);
}
}
.data-origin-box
{
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
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
:
2
;
: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/utils/charts.js
浏览文件 @
351ae3b2
import
*
as
echarts
from
"echarts"
;
import
chinaJson
from
"./China.json"
;
import
_
from
"lodash"
;
import
{
name
}
from
"dayjs/locale/zh-cn"
;
//饼图
export
function
getPieOption
(
data
,
title
)
{
let
option
=
{
...
...
@@ -1022,6 +1023,12 @@ export const getMultipleBarChart_m = object => {
},
yAxis
:
{
type
:
"value"
,
name
:
"数量"
,
nameLocation
:
"end"
,
nameGap
:
5
,
nameTextStyle
:
{
padding
:
[
0
,
40
,
10
,
0
]
// [上, 右, 下, 左] —— 减少右侧 padding 相当于左移
},
splitNumber
:
5
,
alignTicks
:
false
,
axisLabel
:
{
...
...
src/views/exportControl/utils/common.js
0 → 100644
浏览文件 @
351ae3b2
import
{
ref
}
from
"vue"
;
export
const
useChartInterpretation
=
()
=>
{
const
loading
=
ref
(
false
);
const
interpretation
=
ref
(
""
);
const
error
=
ref
(
null
);
const
interpret
=
async
text
=>
{
loading
.
value
=
true
;
error
.
value
=
null
;
interpretation
.
value
=
""
;
try
{
const
response
=
await
fetch
(
"/aiAnalysis/chart_interpretation"
,
{
method
:
"POST"
,
headers
:
{
"X-API-Key"
:
"aircasKEY19491001"
,
"Content-Type"
:
"application/json"
},
body
:
JSON
.
stringify
({
text
})
});
if
(
!
response
.
ok
)
{
throw
new
Error
(
`HTTP error! status:
${
response
.
status
}
`
);
}
const
reader
=
response
.
body
.
getReader
();
const
decoder
=
new
TextDecoder
();
let
buffer
=
""
;
while
(
true
)
{
const
{
done
,
value
}
=
await
reader
.
read
();
if
(
done
)
break
;
buffer
+=
decoder
.
decode
(
value
,
{
stream
:
true
});
const
lines
=
buffer
.
split
(
"
\
n"
);
buffer
=
lines
.
pop
()
||
""
;
for
(
const
line
of
lines
)
{
if
(
line
.
startsWith
(
"data: "
))
{
const
content
=
line
.
substring
(
6
);
const
textMatch
=
content
.
match
(
/"解读":
\s
*"
([^
"
]
*
)
"/
);
if
(
textMatch
&&
textMatch
[
1
])
{
interpretation
.
value
=
textMatch
[
1
];
}
}
}
}
}
catch
(
err
)
{
error
.
value
=
err
.
message
||
"AI 解读失败"
;
console
.
error
(
"AI Chart Interpretation Error:"
,
err
);
}
finally
{
loading
.
value
=
false
;
}
};
return
{
loading
,
interpretation
,
error
,
interpret
};
};
src/views/exportControl/v2.0CommercialControlList/components/sanctionsOverview/components/listPage/index.vue
浏览文件 @
351ae3b2
差异被折叠。
点击展开。
src/views/exportControl/v2.0SingleSanction/components/sanctionsOverview/index.vue
浏览文件 @
351ae3b2
...
...
@@ -31,7 +31,7 @@
<div
class=
"info-row"
>
<div
class=
"label"
>
发布人:
</div>
<div
class=
"value link"
>
<img
:src=
"
defaultTitle
"
alt=
""
class=
"icon avatar"
/>
<img
:src=
"
formattedData.avartarUrl
"
alt=
""
class=
"icon avatar"
/>
<span
@
click=
"handleClick"
>
{{
formattedData
.
postPersonName
}}
>
</span>
</div>
</div>
...
...
@@ -46,7 +46,7 @@
<div
class=
"content-title"
>
制裁实体分布:
</div>
<div
class=
"distribution-list"
>
<div
class=
"list-item"
v-for=
"(item, index) in entityDistribution"
:key=
"index"
>
<img
:src=
"flag"
alt=
""
class=
"flag"
/>
<img
:src=
"
item.imageUrl ||
flag"
alt=
""
class=
"flag"
/>
<div
class=
"country-name"
>
{{
item
.
name
}}
</div>
<div
class=
"progress-bar-container"
>
<div
...
...
@@ -152,6 +152,7 @@
</div>
<div
class=
"right-content"
>
<div
class=
"sanction-group-list"
>
<el-empty
v-if=
"sanctionList.length === 0"
description=
"暂无制裁清单数据"
/>
<div
class=
"sanction-group"
v-for=
"(group, index) in sanctionList"
:key=
"index"
>
<el-table
:data=
"group.entities"
style=
"width: 100%"
>
<el-table-column
label=
"实体名称"
min-width=
"280"
>
...
...
@@ -302,7 +303,7 @@ const getSanctionOverviewList = async () => {
removeCount
.
value
=
data
.
removeCount
||
0
;
removeRuleCount
.
value
=
data
.
removeRuleCount
||
0
;
const
list
=
data
.
san
List
||
[];
const
list
=
searchType
.
value
==
"add"
?
data
.
sanList
:
data
.
remove
List
||
[];
sanctionList
.
value
=
list
.
map
(
item
=>
({
reason
:
item
.
sanReason
,
entities
:
(
item
.
orgList
||
[]).
map
(
org
=>
({
...
...
@@ -448,7 +449,8 @@ const formattedData = computed(() => {
fileCode
:
info
.
fileCode
?
`
${
info
.
fileCode
}
`
:
""
,
administrativeOrderId
:
info
.
administrativeOrderId
?
`No.
${
info
.
administrativeOrderId
}
`
:
""
,
postPersonName
:
info
.
postPersonName
,
domains
:
info
.
domainNames
domains
:
info
.
domainNames
,
avartarUrl
:
info
.
postPersonAvatarUrl
};
});
...
...
src/views/thinkTank/index.vue
浏览文件 @
351ae3b2
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论