Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
846d853c
提交
846d853c
authored
3月 26, 2026
作者:
yanpeng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
图表AI解读
上级
3f645e0f
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
10 个修改的文件
包含
365 行增加
和
164 行删除
+365
-164
analysisBox.vue
src/components/base/boxBackground/analysisBox.vue
+154
-157
index.vue
src/views/exportControl/index.vue
+2
-2
index.vue
...ontrol/v2.0EntityList/components/dataStatistics/index.vue
+0
-0
index.vue
src/views/exportControl/v2.0EntityList/index.vue
+1
-1
index.vue
...ol/v2.0SingleSanction/components/dataStatistics/index.vue
+0
-0
RelationGraph.vue
...nction/components/deepMining/components/RelationGraph.vue
+64
-2
index.vue
...ents/impactAnalysis/components/industrialImpact/index.vue
+0
-0
index.vue
...onents/impactAnalysis/components/researchImpact/index.vue
+0
-0
index.vue
src/views/exportControl/v2.0SingleSanction/index.vue
+144
-2
mock.json
src/views/exportControl/v2.0SingleSanction/mock.json
+0
-0
没有找到文件。
src/components/base/boxBackground/analysisBox.vue
浏览文件 @
846d853c
<
template
>
<div
class=
"analysis-box-wrapper"
:style=
"
{ width: width ? width : '100%', height: height ? height : '100%' }">
<div
class=
"wrapper-header"
>
<div
class=
"header-icon"
></div>
<div
class=
"header-title"
>
<div
v-if=
"title"
>
{{
title
}}
</div>
<slot
v-else
name=
"custom-title"
></slot>
</div>
<div
class=
"header-btn"
v-if=
"!showAllBtn"
>
<slot
name=
"header-btn"
></slot>
</div>
<div
class=
"header-btn1"
v-else
>
<slot
name=
"header-btn"
></slot>
</div>
<div
class=
"header-right"
>
<div
class=
"header-right-btn"
@
click=
"handleSave"
v-if=
"showAllBtn"
>
<img
src=
"@/assets/icons/box-header-icon1.png"
alt=
""
>
</div>
<div
class=
"header-right-btn"
@
click=
"handleDownload"
>
<img
src=
"@/assets/icons/box-header-icon2.png"
alt=
""
>
</div>
<div
class=
"header-right-btn"
@
click=
"handleCollect"
>
<img
src=
"@/assets/icons/box-header-icon3.png"
alt=
""
>
</div>
</div>
</div>
<div
class=
"wrapper-main"
>
<slot></slot>
</div>
</div>
<div
class=
"analysis-box-wrapper"
:style=
"
{ width: width ? width : '100%', height: height ? height : '100%' }">
<div
class=
"wrapper-header"
>
<div
class=
"header-icon"
></div>
<div
class=
"header-title"
>
<div
v-if=
"title"
>
{{
title
}}
</div>
<slot
v-else
name=
"custom-title"
></slot>
</div>
<div
class=
"header-btn"
v-if=
"!showAllBtn"
>
<slot
name=
"header-btn"
></slot>
</div>
<div
class=
"header-btn1"
v-else
>
<slot
name=
"header-btn"
></slot>
</div>
<div
class=
"header-right"
>
<div
class=
"header-right-btn"
@
click=
"handleSave"
v-if=
"showAllBtn"
>
<img
src=
"@/assets/icons/box-header-icon1.png"
alt=
""
/
>
</div>
<div
class=
"header-right-btn"
@
click=
"handleDownload"
>
<img
src=
"@/assets/icons/box-header-icon2.png"
alt=
""
/
>
</div>
<div
class=
"header-right-btn"
@
click=
"handleCollect"
>
<img
src=
"@/assets/icons/box-header-icon3.png"
alt=
""
/
>
</div>
</div>
</div>
<div
class=
"wrapper-main"
>
<slot></slot>
</div>
</div>
</
template
>
<
script
setup
>
import
{
ElMessage
}
from
'element-plus'
import
{
ref
,
computed
}
from
'vue'
import
{
ElMessage
}
from
"element-plus"
;
import
{
ref
,
computed
}
from
"vue"
;
const
props
=
defineProps
({
title
:
{
type
:
String
,
default
:
''
},
width
:
{
type
:
String
,
default
:
''
},
height
:
{
type
:
String
,
default
:
''
},
showAllBtn
:
{
type
:
Boolean
,
default
:
true
},
// 当业务功能尚未实现时,点击右上角图标仅弹出统一提示
devTip
:
{
type
:
Boolean
,
default
:
false
}
})
title
:
{
type
:
String
,
default
:
""
},
width
:
{
type
:
String
,
default
:
""
},
height
:
{
type
:
String
,
default
:
""
},
showAllBtn
:
{
type
:
Boolean
,
default
:
true
},
// 当业务功能尚未实现时,点击右上角图标仅弹出统一提示
devTip
:
{
type
:
Boolean
,
default
:
false
}
})
;
const
handleSave
=
()
=>
{
if
(
props
.
devTip
)
{
ElMessage
.
warning
(
'当前功能正在开发中,敬请期待!'
)
return
}
ElMessage
.
success
(
'保存当前内容'
)
// emit('save')
}
if
(
props
.
devTip
)
{
ElMessage
.
warning
(
"当前功能正在开发中,敬请期待!"
);
return
;
}
ElMessage
.
success
(
"保存当前内容"
);
// emit('save')
}
;
const
handleDownload
=
()
=>
{
if
(
props
.
devTip
)
{
ElMessage
.
warning
(
'当前功能正在开发中,敬请期待!'
)
return
}
ElMessage
.
success
(
'下载当前内容'
)
// emit('download')
}
if
(
props
.
devTip
)
{
ElMessage
.
warning
(
"当前功能正在开发中,敬请期待!"
);
return
;
}
ElMessage
.
success
(
"下载当前内容"
);
// emit('download')
};
const
handleCollect
=
()
=>
{
if
(
props
.
devTip
)
{
ElMessage
.
warning
(
'当前功能正在开发中,敬请期待!'
)
return
}
ElMessage
.
success
(
'收藏当前内容'
)
// emit('collect')
}
const
emit
=
defineEmits
([
'save'
,
'download'
,
'collect'
])
if
(
props
.
devTip
)
{
ElMessage
.
warning
(
"当前功能正在开发中,敬请期待!"
);
return
;
}
ElMessage
.
success
(
"收藏当前内容"
);
// emit('collect')
};
const
emit
=
defineEmits
([
"save"
,
"download"
,
"collect"
]);
</
script
>
<
style
lang=
"scss"
scoped
>
.analysis-box-wrapper
{
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-radius
:
10px
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
.wrapper-header
{
height
:
45px
;
display
:
flex
;
padding-right
:
14px
;
align-items
:
center
;
box-sizing
:
border-box
;
.header-icon
{
width
:
8px
;
height
:
20px
;
background
:
var
(
--
color-main-active
);
border-radius
:
0
4px
4px
0
;
margin-right
:
14px
;
}
.header-title
{
flex
:
auto
;
width
:
20px
;
// color: var(--color-main-active);
// font-family: Source Han Sans CN;
// font-size: 20px;
// font-weight: 700;
// line-height: 26px;
// letter-spacing: 0px;
height
:
100%
;
&
>
div
{
height
:
100%
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
line-height
:
45px
;
font-weight
:
700
;
}
}
.header-btn
{
// display: flex;
// justify-content: flex-end;
// gap: 8px;
margin-right
:
10px
;
}
// .header-btn1 {
// position: absolute;
// top: 14px;
// right: 116px;
// }
.header-right
{
height
:
28px
;
display
:
flex
;
justify-content
:
flex-end
;
gap
:
4px
;
.header-right-btn
{
width
:
28px
;
height
:
28px
;
cursor
:
pointer
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
}
.wrapper-main
{
height
:
calc
(
100%
-
45px
);
overflow
:
hidden
;
// overflow-y: auto;
padding
:
5px
auto
;
}
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-radius
:
10px
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
position
:
relative
;
.wrapper-header
{
height
:
45px
;
display
:
flex
;
padding-right
:
14px
;
align-items
:
center
;
box-sizing
:
border-box
;
.header-icon
{
width
:
8px
;
height
:
20px
;
background
:
var
(
--
color-main-active
);
border-radius
:
0
4px
4px
0
;
margin-right
:
14px
;
}
.header-title
{
flex
:
auto
;
width
:
20px
;
// color: var(--color-main-active);
// font-family: Source Han Sans CN;
// font-size: 20px;
// font-weight: 700;
// line-height: 26px;
// letter-spacing: 0px;
height
:
100%
;
&
>
div
{
height
:
100%
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
line-height
:
45px
;
font-weight
:
700
;
}
}
.header-btn
{
// display: flex;
// justify-content: flex-end;
// gap: 8px;
margin-right
:
10px
;
}
// .header-btn1 {
// position: absolute;
// top: 14px;
// right: 116px;
// }
.header-right
{
height
:
28px
;
display
:
flex
;
justify-content
:
flex-end
;
gap
:
4px
;
.header-right-btn
{
width
:
28px
;
height
:
28px
;
cursor
:
pointer
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
}
.wrapper-main
{
height
:
calc
(
100%
-
45px
);
overflow
:
hidden
;
// overflow-y: auto;
padding
:
5px
auto
;
}
}
</
style
>
src/views/exportControl/index.vue
浏览文件 @
846d853c
...
...
@@ -416,7 +416,7 @@
</el-col>
</el-row>
<el-row
:gutter=
"20"
style=
"width: 1600px; margin: 0 auto; margin-top: 39px"
>
<el-row
:gutter=
"20"
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
...
...
@@ -3603,7 +3603,7 @@ const handleMediaClick = item => {
}
.scroll-main
{
height
:
calc
(
100%
-
144px
)
!
important
;
//
height: calc(100% - 144px) !important;
}
.center-center
{
...
...
src/views/exportControl/v2.0EntityList/components/dataStatistics/index.vue
浏览文件 @
846d853c
差异被折叠。
点击展开。
src/views/exportControl/v2.0EntityList/index.vue
浏览文件 @
846d853c
...
...
@@ -12,7 +12,7 @@
{{
headerTitle
.
department
}}
</div>
</div>
<
div
class=
"btn"
><img
:src=
"icon01"
alt=
""
/>
切换
</div
>
<
!--
<div
class=
"btn"
><img
:src=
"icon01"
alt=
""
/>
切换
</div>
--
>
</div>
<div
class=
"header-nav"
>
<div
...
...
src/views/exportControl/v2.0SingleSanction/components/dataStatistics/index.vue
浏览文件 @
846d853c
差异被折叠。
点击展开。
src/views/exportControl/v2.0SingleSanction/components/deepMining/components/RelationGraph.vue
浏览文件 @
846d853c
...
...
@@ -23,7 +23,7 @@
</div>
</div>
<div
ref=
"containerRef"
class=
"graph-container"
></div>
<!--
<GraphChart
v-if=
"currentLayoutType === 1"
:nodes=
"graphNodes"
:links=
"graphLinks"
/>
-->
<div
v-if=
"selectedNode"
class=
"node-popup"
>
<div
class=
"popup-header"
>
<img
:src=
"selectedNode.image || defaultIcon"
alt=
""
class=
"popup-icon"
/>
...
...
@@ -55,6 +55,8 @@ import echartsIcon02 from "../assets/echartsIcon02.png";
import
echartsIcon03
from
"../assets/echartsIcon03.png"
;
import
defaultIcon
from
"../assets/echartsIcon03.png"
;
// import GraphChart from "@/components/base/GraphChart/index.vue";
import
GraphChart
from
"@/views/companyPages2/component/SupplyChain/GraphChart.vue"
;
import
{
getSingleSanctionEntityInfo
}
from
"@/api/exportControlV2.0"
;
const
props
=
defineProps
({
...
...
@@ -107,7 +109,7 @@ const initGraph = (layoutType = 1) => {
const
initNormalGraph
=
(
layoutType
,
width
,
height
)
=>
{
const
data
=
processGraphData
(
props
.
graphData
);
console
.
log
(
"初始数据"
,
props
.
graphData
);
if
(
!
data
.
nodes
||
data
.
nodes
.
length
===
0
)
return
;
const
layout
=
{
...
...
@@ -653,6 +655,56 @@ const bindGraphEvents = () => {
});
};
// 将传入的 graphData 转换为 GraphChart.vue 需要的格式
// GraphChart.vue 需要节点有 x, y 坐标,所以我们需要一个简单的布局算法
const
graphNodes
=
ref
([]);
const
graphLinks
=
ref
([]);
const
applyStarLayout
=
(
rawNodes
,
rawLinks
)
=>
{
if
(
!
rawNodes
?.
length
)
return
{
nodes
:
[],
links
:
[]
};
const
centerX
=
0
;
const
centerY
=
0
;
const
radius
=
200
;
// 环绕半径
const
nodes
=
rawNodes
.
map
((
node
,
index
)
=>
{
let
x
,
y
;
if
(
index
===
0
)
{
// 中心节点
x
=
centerX
;
y
=
centerY
;
}
else
{
// 其他节点均匀分布在圆周上
const
angle
=
(
2
*
Math
.
PI
*
(
index
-
1
))
/
(
rawNodes
.
length
-
1
);
x
=
centerX
+
radius
*
Math
.
cos
(
angle
);
y
=
centerY
+
radius
*
Math
.
sin
(
angle
);
}
return
{
id
:
String
(
node
.
id
??
index
),
name
:
node
.
name
||
""
,
type
:
node
.
isSanctioned
?
"sanctioned"
:
"normal"
,
// 用于区分样式(如果需要)
symbolSize
:
node
.
symbolSize
||
(
index
===
0
?
60
:
40
),
symbol
:
`image://
${
node
.
image
||
defaultIcon
}
`
,
isSanctioned
:
node
.
isSanctioned
,
image
:
node
.
image
||
defaultIcon
,
x
:
x
,
y
:
y
,
...
node
// 透传其他字段
};
});
const
links
=
(
rawLinks
||
[]).
map
(
link
=>
({
source
:
String
(
link
.
source
),
target
:
String
(
link
.
target
),
type
:
link
.
name
||
"relation"
,
// GraphChart.vue 使用 type 字段
label
:
{
show
:
true
,
formatter
:
link
.
name
||
""
}
}));
return
{
nodes
,
links
};
};
const
handleClickControlBtn
=
btn
=>
{
currentLayoutType
.
value
=
btn
;
emit
(
"layoutChange"
,
btn
);
...
...
@@ -675,6 +727,16 @@ const handleResize = () => {
}
};
watch
(
()
=>
props
.
graphData
,
newVal
=>
{
const
{
nodes
,
links
}
=
applyStarLayout
(
newVal
.
nodes
,
newVal
.
links
);
graphNodes
.
value
=
JSON
.
parse
(
JSON
.
stringify
(
nodes
));
graphLinks
.
value
=
JSON
.
parse
(
JSON
.
stringify
(
links
));
},
{
deep
:
true
,
immediate
:
true
}
);
watch
(
()
=>
props
.
graphData
,
()
=>
{
...
...
src/views/exportControl/v2.0SingleSanction/components/impactAnalysis/components/industrialImpact/index.vue
浏览文件 @
846d853c
差异被折叠。
点击展开。
src/views/exportControl/v2.0SingleSanction/components/impactAnalysis/components/researchImpact/index.vue
浏览文件 @
846d853c
差异被折叠。
点击展开。
src/views/exportControl/v2.0SingleSanction/index.vue
浏览文件 @
846d853c
...
...
@@ -12,7 +12,7 @@
{{
headerTitle
.
department
}}
</div>
</div>
<div
class=
"btn"
><img
:src=
"icon01"
alt=
""
/>
切换
</div>
<div
class=
"btn"
@
click=
"openSanctionModal"
><img
:src=
"icon01"
alt=
""
/>
切换
</div>
</div>
<div
class=
"header-nav"
>
<div
...
...
@@ -44,12 +44,46 @@
<deep-mining
v-if=
"activeIndex === 2"
></deep-mining>
<impact-analysis
v-if=
"activeIndex === 3"
></impact-analysis>
</div>
<el-dialog
v-model=
"sanctionModalVisible"
title=
"制裁事件列表"
width=
"600px"
:close-on-click-modal=
"false"
@
close=
"resetModal"
>
<div
class=
"sanction-list"
>
<div
v-for=
"item in sanctionList"
:key=
"item.id"
class=
"sanction-item"
:class=
"
{ active: selectedSanctionId === item.id }"
@click="selectSanction(item)"
>
{{
item
.
name
}}
</div>
</div>
<template
#
footer
>
<div
class=
"pagination-footer"
>
<el-pagination
v-model:current-page=
"currentPage"
v-model:page-size=
"pageSize"
:total=
"totalElements"
:page-sizes=
"[10]"
layout=
"total, prev, pager, next"
background
@
current-change=
"handlePageChange"
/>
</div>
</
template
>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
ref
,
onMounted
}
from
"vue"
;
import
{
ElDialog
,
ElPagination
}
from
"element-plus"
;
import
sanctionsOverview
from
"./components/sanctionsOverview/index.vue"
;
import
dataStatistics
from
"./components/dataStatistics/index.vue"
;
import
deepMining
from
"./components/deepMining/index.vue"
;
...
...
@@ -67,6 +101,7 @@ import icon3 from "../assets/icons/icon3.png";
import
icon3Active
from
"../assets/icons/icon3_active.png"
;
import
{
getSingleSanctionOverview
}
from
"@/api/exportControlV2.0.js"
;
import
{
getSanctionProcess
}
from
"@/api/exportControl"
;
import
router
from
"@/router"
;
// 处理点击实体清单原文按钮
...
...
@@ -157,6 +192,77 @@ const handleAnalysisClick = () => {
});
};
// ========== 新增响应式状态 ==========
const
sanctionModalVisible
=
ref
(
false
);
const
sanctionList
=
ref
([]);
const
selectedSanctionId
=
ref
(
null
);
const
currentPage
=
ref
(
1
);
const
pageSize
=
ref
(
10
);
const
totalElements
=
ref
(
0
);
// ========== 打开弹窗并加载第一页 ==========
const
openSanctionModal
=
async
()
=>
{
sanctionModalVisible
.
value
=
true
;
console
.
log
(
"制裁事件列表11:"
,
sanctionList
.
value
);
await
fetchSanctionData
();
};
// ========== 获取制裁数据 ==========
const
fetchSanctionData
=
async
()
=>
{
try
{
const
res
=
await
getSanctionProcess
([
1
],
currentPage
.
value
,
10
);
if
(
res
&&
!!
res
.
content
)
{
sanctionList
.
value
=
res
.
content
||
[];
totalElements
.
value
=
res
.
totalElements
||
0
;
// 如果当前选中的不在新数据中,清空选中
if
(
selectedSanctionId
.
value
&&
!
sanctionList
.
value
.
some
(
item
=>
item
.
id
===
selectedSanctionId
.
value
))
{
selectedSanctionId
.
value
=
null
;
}
console
.
log
(
"制裁事件列表:"
,
sanctionList
.
value
);
}
else
{
sanctionList
.
value
=
[];
totalElements
.
value
=
0
;
}
}
catch
(
error
)
{
console
.
error
(
"获取制裁事件失败:"
,
error
);
sanctionList
.
value
=
[];
totalElements
.
value
=
0
;
}
};
// ========== 翻页处理 ==========
const
handlePageChange
=
async
newPage
=>
{
currentPage
.
value
=
newPage
;
await
fetchSanctionData
();
};
// ========== 选择某项 ==========
const
selectSanction
=
item
=>
{
selectedSanctionId
.
value
=
item
.
id
;
// 可在此处触发其他逻辑,如查看详情
// 替换当前路由参数,并重新加载数据
router
.
replace
({
path
:
window
.
location
.
pathname
,
query
:
{
id
:
item
.
id
,
sanTypeId
:
item
.
sanTypeId
}
});
// 3. 立即重新加载数据(关键!)
getSingleSanctionOverviewData
();
// 4. 可选:关闭弹窗
sanctionModalVisible
.
value
=
false
;
};
// ========== 关闭弹窗时重置 ==========
const
resetModal
=
()
=>
{
sanctionList
.
value
=
[];
selectedSanctionId
.
value
=
null
;
currentPage
.
value
=
1
;
totalElements
.
value
=
0
;
};
onMounted
(()
=>
{
getUrlParams
();
getSingleSanctionOverviewData
();
...
...
@@ -350,4 +456,40 @@ onMounted(() => {
background-color
:
#f7f8f9
;
}
}
.sanction-list
{
max-height
:
400px
;
overflow-y
:
auto
;
padding
:
0
10px
;
}
.sanction-item
{
padding
:
7px
;
margin
:
6px
0
;
border-radius
:
4px
;
cursor
:
pointer
;
font-size
:
14px
;
color
:
#333
;
transition
:
background-color
0
.2s
;
}
.sanction-item
:hover
{
background-color
:
#f5f7fa
;
}
.sanction-item.active
{
background-color
:
#e6f0ff
;
color
:
#1890ff
;
font-weight
:
bold
;
}
.pagination-footer
{
display
:
flex
;
justify-content
:
center
;
margin-top
:
12px
;
}
:deep
(
.el-pagination.is-background
.el-pager
li
:not
(
.is-disabled
)
.is-active
)
{
background-color
:
#0e78f1
;
}
</
style
>
src/views/exportControl/v2.0SingleSanction/mock.json
0 → 100644
浏览文件 @
846d853c
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论