Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
8e14f2ea
提交
8e14f2ea
authored
3月 31, 2026
作者:
闫鹏
浏览文件
操作
浏览文件
下载
差异文件
合并分支 'yp-dev' 到 'pre'
Yp dev 查看合并请求
!291
上级
d072b507
506f41e6
流水线
#261
已通过 于阶段
in 6 分 10 秒
变更
17
流水线
1
全部展开
显示空白字符变更
内嵌
并排
正在显示
17 个修改的文件
包含
734 行增加
和
66 行删除
+734
-66
exportControlV2.0.js
src/api/exportControlV2.0.js
+2
-2
index.js
src/api/finance/index.js
+2
-0
index.vue
src/components/base/GraphChart/index.vue
+29
-20
index.vue
src/views/exportControl/index.vue
+11
-8
charts.js
src/views/exportControl/utils/charts.js
+17
-1
index.vue
...ontrol/v2.0EntityList/components/dataStatistics/index.vue
+35
-9
index.vue
...s/sanctionsOverview/components/introductionPage/index.vue
+2
-2
index.vue
...ol/v2.0SingleSanction/components/dataStatistics/index.vue
+5
-5
RelationGraph.vue
...nction/components/deepMining/components/RelationGraph.vue
+175
-14
index.vue
...ontrol/v2.0SingleSanction/components/deepMining/index.vue
+170
-0
index.vue
...ents/impactAnalysis/components/industrialImpact/index.vue
+1
-1
index.vue
...onents/impactAnalysis/components/researchImpact/index.vue
+1
-1
index.vue
src/views/exportControl/v2.0SingleSanction/index.vue
+13
-3
index-back.vue
...xportControl/v2.0SingleSanction/originPage/index-back.vue
+271
-0
index.vue
...ews/exportControl/v2.0SingleSanction/originPage/index.vue
+0
-0
pdf.vue
...views/exportControl/v2.0SingleSanction/originPage/pdf.vue
+0
-0
index.vue
src/views/finance/index.vue
+0
-0
没有找到文件。
src/api/exportControlV2.0.js
浏览文件 @
8e14f2ea
...
...
@@ -292,10 +292,10 @@ export function getSingleSanctionOverviewList(data) {
* @param {string} params.sanRecordId - 制裁记录ID
* @header token
*/
export
function
getSingleSanctionTotalCount
(
i
d
)
{
export
function
getSingleSanctionTotalCount
(
sanTypeId
,
recordI
d
)
{
return
request
({
method
:
"GET"
,
url
:
`/api/sanctionList/statistics/total?sanTypeId=
${
i
d
}
`
,
url
:
`/api/sanctionList/statistics/total?sanTypeId=
${
sanTypeId
}
&sanRecordId=
${
recordI
d
}
`
,
});
}
...
...
src/api/finance/index.js
0 → 100644
浏览文件 @
8e14f2ea
import
request
from
"@/api/request.js"
;
\ No newline at end of file
src/components/base/GraphChart/index.vue
浏览文件 @
8e14f2ea
<
template
>
<div
class=
"graph-chart-wrapper"
id=
"graph"
>
</div>
<div
class=
"graph-chart-wrapper"
id=
"graph"
></div>
</
template
>
<
script
setup
>
import
{
onMounted
,
onBeforeUnmount
}
from
'vue'
;
import
setChart
from
'@/utils/setChart'
;
import
getGraphChart
from
'./graphChart'
;
import
{
onMounted
,
onBeforeUnmount
,
watch
}
from
"vue"
;
import
setChart
from
"@/utils/setChart"
;
import
getGraphChart
from
"./graphChart"
;
const
emits
=
defineEmits
([
"handleClickNode"
])
const
emits
=
defineEmits
([
"handleClickNode"
])
;
const
props
=
defineProps
({
nodes
:
{
type
:
Array
,
...
...
@@ -21,33 +19,44 @@ const props = defineProps({
},
layoutType
:
{
type
:
String
,
default
:
'force'
default
:
"force"
},
width
:
{
type
:
String
,
default
:
'force'
default
:
"force"
},
height
:
{
type
:
String
,
default
:
'force'
default
:
"force"
}
})
})
;
let
chart
=
null
let
chart
=
null
;
onMounted
(()
=>
{
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
)
chart
=
setChart
(
graph
,
'graph'
)
chart
.
on
(
"click"
,
(
event
)
=>
{
emits
(
"handleClickNode"
,
event
)
})
})
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
);
chart
=
setChart
(
graph
,
"graph"
);
chart
.
on
(
"click"
,
event
=>
{
emits
(
"handleClickNode"
,
event
);
});
});
onBeforeUnmount
(()
=>
{
chart
.
off
(
"click"
)
chart
.
dispose
()
})
chart
.
off
(
"click"
);
chart
.
dispose
();
})
;
watch
(
()
=>
[
props
.
nodes
,
props
.
links
],
()
=>
{
if
(
chart
)
{
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
);
chart
.
setOption
(
graph
,
true
);
}
},
{
deep
:
true
}
);
</
script
>
<
style
lang=
"scss"
scoped
>
.graph-chart-wrapper
{
width
:
100%
;
...
...
src/views/exportControl/index.vue
浏览文件 @
8e14f2ea
...
...
@@ -77,7 +77,7 @@
<el-col
:span=
"16"
>
<custom-container
titleType=
"primary"
title=
"最新出口管制政策"
:titleIcon=
"houseIcon"
height=
"450px"
>
<template
#
header-right
>
<el-button
type=
"primary"
@
click=
"handleToEntityList
()
"
link
>
<el-button
type=
"primary"
@
click=
"handleToEntityList"
link
>
{{
"查看详情 >"
}}
</el-button>
</
template
>
...
...
@@ -390,7 +390,7 @@
</custom-container>
</el-col>
<el-col
:span=
"16"
>
<custom-container
title=
"
实体
清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"540px"
>
<custom-container
title=
"
制裁
清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"540px"
>
<
template
#
header-right
>
<div
style=
"display: flex; align-items: center; gap: 16px"
>
<el-checkbox
v-model=
"trendChecked"
label=
"50%规则"
size=
"large"
/>
...
...
@@ -995,8 +995,6 @@ onMounted(async () => {
const
maxCountItem1
=
_
.
maxBy
(
cclList1
,
"count"
);
const
maxCountForList1
=
maxCountItem1
?
maxCountItem1
.
count
:
0
;
console
.
log
(
"shuju list"
,
list
);
console
.
log
(
"shuju total"
,
total
);
tableData1
.
value
=
_
.
map
(
list
,
item
=>
{
return
{
year
:
item
.
year
,
...
...
@@ -1053,7 +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
});
trendChart
.
interpret
({
type
:
"柱状图"
,
name
:
"
制裁
清单数量增长趋势"
,
data
:
res
[
0
].
yearDomainCount
});
}
}
catch
(
error
)
{
console
.
error
(
"获取趋势图数据失败:"
,
error
);
...
...
@@ -1147,10 +1145,13 @@ const handleCarouselChange = index => {
// 跳转到V2.0单次制裁
const
handleToEntityList
=
item
=>
{
console
.
log
(
"这是什么数据1 =>"
,
item
);
let
id
=
item
?.
id
;
let
sanTypeId
=
item
?.
sanTypeId
||
1
;
if
(
!
id
)
{
const
currentItem
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
];
id
=
currentItem
?.
id
;
sanTypeId
=
currentItem
?.
sanTypeId
||
1
;
}
window
.
sessionStorage
.
setItem
(
"curTabName"
,
...
...
@@ -1159,7 +1160,8 @@ const handleToEntityList = item => {
const
routeData
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
query
:
{
id
:
id
id
,
sanTypeId
}
});
// 打开一个新页面
...
...
@@ -2363,7 +2365,8 @@ const handleMediaClick = item => {
overflow-y
:
auto
;
.home-top-bg
{
background
:
url("./assets/images/background.png")
,
background
:
url("./assets/images/background.png")
,
linear-gradient
(
180deg
,
rgba
(
229
,
241
,
254
,
1
)
0%
,
rgba
(
246
,
251
,
255
,
0
)
30%
);
background-size
:
100%
100%
;
position
:
absolute
;
...
...
@@ -3631,7 +3634,7 @@ const handleMediaClick = item => {
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
22px
0
;
.data-origin-icon
{
width
:
16px
;
...
...
src/views/exportControl/utils/charts.js
浏览文件 @
8e14f2ea
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
=
{
...
...
@@ -1006,7 +1007,7 @@ export const getMultipleBarChart_m = object => {
margin
:
20
},
axisLabel
:
{
formatter
:
"{value}
年
"
,
formatter
:
"{value}"
,
color
:
"rgba(95, 101, 108, 1)"
,
margin
:
20
},
...
...
@@ -1022,6 +1023,21 @@ export const getMultipleBarChart_m = object => {
},
yAxis
:
{
type
:
"value"
,
name
:
"数量"
,
nameLocation
:
"end"
,
nameGap
:
20
,
nameRotate
:
0
,
nameTextStyle
:
{
color
:
"#666"
,
fontFamily
:
"Microsoft YaHei"
,
fontWeight
:
400
,
fontSize
:
14
,
lineHeight
:
14
,
letterSpacing
:
0
,
align
:
"right"
,
verticalAlign
:
"bottom"
,
padding
:
[
0
,
8
,
0
,
0
]
},
splitNumber
:
5
,
alignTicks
:
false
,
axisLabel
:
{
...
...
src/views/exportControl/v2.0EntityList/components/dataStatistics/index.vue
浏览文件 @
8e14f2ea
...
...
@@ -105,7 +105,7 @@
</div>
</
template
>
<!-- <div class="echarts" ref="sanctionCountChartRef"></div> -->
<EChart
:option=
"sanctionCountChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<EChart
:option=
"sanctionCountChartOption"
autoresize
:style=
"{ height: '300px'
, padding: '0 20px'
}"
/>
<!-- <div class="bottom">
<div class="ai">
<div class="left">
...
...
@@ -186,7 +186,7 @@
</el-select>
</
template
>
<!-- <div class="echarts" ref="domainChartRef"></div> -->
<EChart
:option=
"domainChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<EChart
:option=
"domainChartOption"
autoresize
:style=
"{ height: '300px'
, padding: '0 20px'
}"
/>
<!-- <div class="bottom">
<div class="ai">
<div class="left">
...
...
@@ -218,7 +218,7 @@
</el-select>
</
template
>
<!-- <div class="echarts" ref="typeChartRef"></div> -->
<EChart
:option=
"typeChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<EChart
:option=
"typeChartOption"
autoresize
:style=
"{ height: '300px'
, padding: '0 20px'
}"
/>
<!-- <div class="bottom">
<div class="ai">
<div class="left">
...
...
@@ -717,8 +717,21 @@ const domainChartOption = ref({
width
:
1.1
}
},
labelLayout
:
{
hideOverlap
:
true
labelLayout
:
function
(
params
)
{
// hideOverlap: true
const
points
=
params
.
labelLinePoints
;
const
isLeft
=
params
.
labelRect
.
x
<
params
.
rect
.
x
+
params
.
rect
.
width
/
2
;
// 调整指示线终点到 label 垂直中心
const
labelCenterY
=
params
.
labelRect
.
y
+
params
.
labelRect
.
height
/
2
;
points
[
2
][
1
]
=
labelCenterY
;
// 调整指示线终点到 label 水平边缘
points
[
2
][
0
]
=
isLeft
?
params
.
labelRect
.
x
:
params
.
labelRect
.
x
+
params
.
labelRect
.
width
;
return
{
labelLinePoints
:
points
};
},
itemStyle
:
{
borderWidth
:
0
...
...
@@ -926,10 +939,23 @@ const typeChartOption = ref({
}
},
labelLayout
:
function
(
params
)
{
const
isLeft
=
params
.
labelRect
.
x
<
chart
.
getWidth
()
/
2
;
// const isLeft = params.labelRect.x
<
chart
.
getWidth
()
/
2
;
// const points = params.labelLinePoints;
// points[2][0] = isLeft ? params.labelRect.x : params.labelRect.x + params.labelRect.width;
// return {
// labelLinePoints: points
// };
const
points
=
params
.
labelLinePoints
;
// Update the end point.
const
isLeft
=
params
.
labelRect
.
x
<
params
.
rect
.
x
+
params
.
rect
.
width
/
2
;
// 调整指示线终点到 label 垂直中心
const
labelCenterY
=
params
.
labelRect
.
y
+
params
.
labelRect
.
height
/
2
;
points
[
2
][
1
]
=
labelCenterY
;
// 调整指示线终点到 label 水平边缘
points
[
2
][
0
]
=
isLeft
?
params
.
labelRect
.
x
:
params
.
labelRect
.
x
+
params
.
labelRect
.
width
;
return
{
labelLinePoints
:
points
};
...
...
@@ -1508,8 +1534,8 @@ onMounted(() => {
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
padding
:
22px
0
;
justify-content
:
flex-start
;
padding
:
22px
;
.data-origin-icon
{
width
:
16px
;
height
:
16px
;
...
...
src/views/exportControl/v2.0EntityList/components/sanctionsOverview/components/introductionPage/index.vue
浏览文件 @
8e14f2ea
...
...
@@ -241,11 +241,11 @@ const handleClick = item => {
const
route
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
query
:
{
id
:
item
.
id
id
:
item
.
id
,
sanTypeId
:
item
.
sanTypeId
||
1
}
}
);
window
.
open
(
route
.
href
,
"_blank"
);
}
;
const
selectedDomain
=
ref
(
0
);
...
...
src/views/exportControl/v2.0SingleSanction/components/dataStatistics/index.vue
浏览文件 @
8e14f2ea
...
...
@@ -54,7 +54,7 @@
</div>
</div>
</div>
-->
<EChart
:option=
"domainChartOption"
autoresize
:style=
"
{ height: '300px' }" />
<EChart
:option=
"domainChartOption"
autoresize
:style=
"
{ height: '300px'
, padding: '0 20px'
}" />
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
...
...
@@ -104,7 +104,7 @@
</div>
</div>
</div>
-->
<EChart
:option=
"typeChartOption"
autoresize
:style=
"
{ height: '300px' }" />
<EChart
:option=
"typeChartOption"
autoresize
:style=
"
{ height: '300px'
, padding: '0 20px'
}" />
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
...
...
@@ -348,7 +348,7 @@ const totalCount = ref({});
const
getTotalCount
=
async
()
=>
{
if
(
!
sanRecordId
.
value
)
return
;
try
{
const
res
=
await
getSingleSanctionTotalCount
(
route
.
query
.
sanTypeId
);
const
res
=
await
getSingleSanctionTotalCount
(
route
.
query
.
sanTypeId
,
sanRecordId
.
value
);
if
(
res
.
code
===
200
)
{
totalCount
.
value
=
res
.
data
||
{};
}
...
...
@@ -1264,8 +1264,8 @@ onMounted(() => {
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
padding
:
22px
0
;
justify-content
:
flex-start
;
padding
:
22px
;
.data-origin-icon
{
width
:
16px
;
height
:
16px
;
...
...
src/views/exportControl/v2.0SingleSanction/components/deepMining/components/RelationGraph.vue
浏览文件 @
8e14f2ea
...
...
@@ -107,22 +107,185 @@ 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 = {
// type: "none",
// center: [width / 2, height / 2],
// preventOverlap: true,
// nodeSpacing: 80,
// linkDistance: 250,
// nodeStrength: -800,
// edgeStrength: 0.1,
// collideStrength: 0.8,
// alphaDecay: 0.01,
// alphaMin: 0.001
// };
// graphInstance.value = new G6.Graph({
// container: containerRef.value,
// width,
// height,
// fitView: true,
// fitViewPadding: 100,
// fitCenter: true,
// animate: true,
// animateCfg: {
// duration: 300,
// easing: "easeLinear"
// },
// minZoom: 0.1,
// maxZoom: 10,
// modes: {
// default: [
// "drag-canvas",
// "zoom-canvas",
// "drag-node",
// {
// type: "activate-relations",
// trigger: "mouseenter",
// resetSelected: true
// }
// ]
// },
// layout,
// defaultNode: {
// type: "image",
// size: 40,
// clipCfg: {
// show: true,
// type: "circle",
// r: 20
// },
// labelCfg: {
// position: "bottom",
// offset: 10,
// style: {
// fill: "#333",
// fontSize: 11,
// fontFamily: "Microsoft YaHei",
// textAlign: "center",
// background: {
// fill: "rgba(255, 255, 255, 0.95)",
// padding: [4, 6, 4, 6],
// radius: 4
// }
// }
// }
// // 注意:节点边框样式在 processGraphData 中单独设置,不在这里设置
// },
// defaultEdge: {
// type: "quadratic",
// style: {
// stroke: "red",
// lineWidth: 3,
// opacity: 0.9,
// shadowColor: "rgba(231, 243, 255, 1)",
// shadowBlur: 4,
// endArrow: {
// path: "M 0,0 L 12,6 L 12,-6 Z",
// fill: "#5B8FF9"
// }
// },
// labelCfg: {
// autoRotate: true,
// style: {
// fill: "rgba(137, 193, 255, 1)",
// fontSize: 10,
// fontFamily: "Microsoft YaHei",
// background: {
// fill: "rgba(231, 243, 255, 1)",
// padding: [2, 4, 2, 4],
// radius: 5
// }
// }
// }
// },
// nodeStateStyles: {
// active: {
// shadowColor: "#1459BB",
// shadowBlur: 15,
// stroke: "#1459BB",
// lineWidth: 3
// },
// inactive: {
// opacity: 0.3
// }
// },
// edgeStateStyles: {
// active: {
// stroke: "#1459BB",
// lineWidth: 4
// },
// inactive: {
// opacity: 0.15
// }
// }
// });
// graphInstance.value.data(data);
// graphInstance.value.render();
// bindGraphEvents();
// };
const
initNormalGraph
=
(
layoutType
,
width
,
height
)
=>
{
const
data
=
processGraphData
(
props
.
graphData
);
console
.
log
(
"初始数据"
,
props
.
graphData
);
if
(
!
data
.
nodes
||
data
.
nodes
.
length
===
0
)
return
;
// 中心节点坐标
const
centerX
=
width
/
2
;
const
centerY
=
height
/
2
;
const
upperY
=
centerY
-
240
;
// 上方节点 Y 坐标
const
lowerY
=
centerY
+
240
;
// 下方节点 Y 坐标
const
nodeSpacing
=
100
;
// 节点水平间距
// 分离中心节点和其他节点
const
centerNode
=
data
.
nodes
.
find
(
n
=>
n
.
isCenter
);
const
otherNodes
=
data
.
nodes
.
filter
(
n
=>
!
n
.
isCenter
);
const
totalNodes
=
otherNodes
.
length
;
const
upperCount
=
Math
.
ceil
(
totalNodes
/
2
);
// 向上取整,上方多一个
const
lowerCount
=
totalNodes
-
upperCount
;
// 为上方节点分配坐标
const
upperNodes
=
otherNodes
.
slice
(
0
,
upperCount
);
upperNodes
.
forEach
((
node
,
index
)
=>
{
const
totalWidth
=
(
upperCount
-
1
)
*
nodeSpacing
;
const
startX
=
centerX
-
totalWidth
/
2
;
node
.
x
=
startX
+
index
*
nodeSpacing
;
node
.
y
=
upperY
;
// 固定位置,防止力导向布局移动
node
.
fx
=
node
.
x
;
node
.
fy
=
node
.
y
;
});
// 为下方节点分配坐标
const
lowerNodes
=
otherNodes
.
slice
(
upperCount
);
lowerNodes
.
forEach
((
node
,
index
)
=>
{
const
totalWidth
=
(
lowerCount
-
1
)
*
nodeSpacing
;
const
startX
=
centerX
-
totalWidth
/
2
;
node
.
x
=
startX
+
index
*
nodeSpacing
;
node
.
y
=
lowerY
;
// 固定位置,防止力导向布局移动
node
.
fx
=
node
.
x
;
node
.
fy
=
node
.
y
;
});
// 设置中心节点坐标
if
(
centerNode
)
{
centerNode
.
x
=
centerX
;
centerNode
.
y
=
centerY
;
// 固定中心节点位置
centerNode
.
fx
=
centerX
;
centerNode
.
fy
=
centerY
;
}
const
layout
=
{
type
:
"force"
,
center
:
[
width
/
2
,
height
/
2
],
preventOverlap
:
true
,
nodeSpacing
:
80
,
linkDistance
:
250
,
nodeStrength
:
-
800
,
edgeStrength
:
0.1
,
collideStrength
:
0.8
,
alphaDecay
:
0.01
,
alphaMin
:
0.001
type
:
"none"
,
// 使用预设坐标,不进行力导向布局
center
:
[
centerX
,
centerY
]
};
graphInstance
.
value
=
new
G6
.
Graph
({
...
...
@@ -175,10 +338,9 @@ const initNormalGraph = (layoutType, width, height) => {
}
}
}
// 注意:节点边框样式在 processGraphData 中单独设置,不在这里设置
},
defaultEdge
:
{
type
:
"
quadratic
"
,
type
:
"
line
"
,
style
:
{
stroke
:
"red"
,
lineWidth
:
3
,
...
...
@@ -230,7 +392,6 @@ const initNormalGraph = (layoutType, width, height) => {
graphInstance
.
value
.
render
();
bindGraphEvents
();
};
const
initCircularGraph
=
(
width
,
height
)
=>
{
const
data
=
processGraphData
(
props
.
graphData
);
...
...
@@ -307,7 +468,7 @@ const initCircularGraph = (width, height) => {
}
},
defaultEdge
:
{
type
:
"
quadratic
"
,
type
:
"
line
"
,
style
:
{
stroke
:
"#5B8FF9"
,
lineWidth
:
3
,
...
...
src/views/exportControl/v2.0SingleSanction/components/deepMining/index.vue
浏览文件 @
8e14f2ea
...
...
@@ -110,6 +110,7 @@
@
node-click=
"handleNodeClick"
@
layout-change=
"handleLayoutChange"
/>
<!-- <GraphChart :nodes="nodes" :links="links" layoutType="none" /> -->
</div>
</div>
</div>
...
...
@@ -134,6 +135,7 @@ import {
}
from
"@/api/exportControlV2.0"
;
import
RelationGraph
from
"./components/RelationGraph.vue"
;
import
AnalysisBox
from
"@/components/base/boxBackground/analysisBox.vue"
;
import
GraphChart
from
"@/components/base/GraphChart/index.vue"
;
const
sanRecordId
=
ref
(
""
);
const
activeTab
=
ref
([
"实体穿透分析"
]);
...
...
@@ -157,6 +159,9 @@ const graphData = ref({ nodes: [], links: [] });
const
treeData
=
ref
(
null
);
const
selectedNode
=
ref
(
null
);
const
nodes
=
ref
([]);
const
links
=
ref
([]);
const
singleSanctionEntityEquityData
=
ref
(
null
);
const
singleSanctionEntitySupplyChainData
=
ref
(
null
);
const
singleSanctionEntityList
=
ref
([]);
...
...
@@ -204,6 +209,7 @@ const updateGraphData = () => {
const
data
=
rightActiveTab
.
value
===
"supplyChain"
?
singleSanctionEntitySupplyChainData
.
value
:
singleSanctionEntityEquityData
.
value
;
console
.
log
(
"图谱数据 =>"
,
data
);
if
(
!
data
)
return
;
const
nodes
=
[];
...
...
@@ -252,8 +258,172 @@ const updateGraphData = () => {
});
graphData
.
value
=
{
nodes
,
links
};
// nodes.value = nodes;
// links.value = links;
};
const
links1
=
[
{
source
:
1
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
2
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"持股"
}
},
{
source
:
3
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
4
,
target
:
7
,
lineStyle
:
{
type
:
"dashed"
,
color
:
"#d32f2f"
},
label
:
{
show
:
true
,
formatter
:
"从属"
}
},
{
source
:
5
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
6
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"持股"
}
},
{
source
:
0
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"持股"
}
},
{
source
:
8
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
9
,
target
:
7
,
lineStyle
:
{
type
:
"dashed"
,
color
:
"#d32f2f"
},
label
:
{
show
:
true
,
formatter
:
"从属"
}
},
{
source
:
10
,
target
:
7
,
lineStyle
:
{
type
:
"dashed"
,
color
:
"#d32f2f"
},
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
11
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
12
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
13
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
14
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
15
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
,
color
:
"red"
,
borderColor
:
"red"
}
}
];
// const updateGraphData = () => {
// const data =
// rightActiveTab.value === "supplyChain" ? singleSanctionEntitySupplyChainData.value : singleSanctionEntityEquityData.value;
// console.log("图谱数据 =>", data);
// if (!data) return;
// const newNodes = [];
// const newLinks = [];
// // 容器尺寸(根据 .right-echarts 的高度 calc(100% - 56px) ≈ 772px)
// const containerWidth = 1000;
// const containerHeight = 700;
// // 中心节点坐标(居中)
// const centerX = containerWidth / 2;
// const centerY = containerHeight / 2;
// // 上下节点分布参数
// const upperY = centerY - 200; // 上方节点 Y 坐标
// const lowerY = centerY + 200; // 下方节点 Y 坐标
// const nodeSpacing = 100; // 节点水平间距
// // 合并所有节点列表(上游 + 下游)
// const allItems = [];
// const parentList = data.parentOrgList || [];
// const childList = data.childrenOrgList || [];
// // 添加上游节点
// parentList.forEach((item, index) => {
// allItems.push({
// ...item,
// linkType: rightActiveTab.value === "supplyChain" ? "供应商" : item.type || "持股",
// direction: "source" // 链接方向:指向中心节点
// });
// });
// // 添加下游节点
// childList.forEach((item, index) => {
// allItems.push({
// ...item,
// linkType: rightActiveTab.value === "supplyChain" ? "客户" : item.description || "投资",
// direction: "target" // 链接方向:从中心节点指出
// });
// });
// // 中心节点
// newNodes.push({
// id: 0,
// name: data.orgName || "中心节点",
// symbol: `image://${companyActive}`,
// symbolSize: 60,
// value: 10,
// isSanctioned: true,
// x: centerX,
// y: centerY
// });
// // 计算上下分配
// const totalNodes = allItems.length;
// const upperCount = Math.ceil(totalNodes / 2); // 向上取整,上方多一个
// const lowerCount = totalNodes - upperCount;
// // 上方节点(前一半)
// const upperItems = allItems.slice(0, upperCount);
// upperItems.forEach((item, index) => {
// const totalWidth = (upperCount - 1) * nodeSpacing;
// const startX = centerX - totalWidth / 2;
// const x = startX + index * nodeSpacing;
// const y = upperY;
// const nodeId = `n-${index}`;
// newNodes.push({
// id: nodeId,
// name: item.name || `节点${index}`,
// symbol: `image://${item.isSanctioned ? companyActive : company}`,
// symbolSize: 40,
// value: 5,
// isSanctioned: item.isSanctioned,
// x,
// y
// });
// // 根据 direction 决定链接方向
// if (item.direction === "source") {
// newLinks.push({
// source: nodeId,
// target: 0,
// name: item.linkType,
// label: { show: true, formatter: item.description }
// });
// } else {
// newLinks.push({
// source: 0,
// target: nodeId,
// name: item.linkType,
// label: { show: true, formatter: item.description }
// });
// }
// });
// // 下方节点(后一半)
// const lowerItems = allItems.slice(upperCount);
// lowerItems.forEach((item, index) => {
// const totalWidth = (lowerCount - 1) * nodeSpacing;
// const startX = centerX - totalWidth / 2;
// const x = startX + index * nodeSpacing;
// const y = lowerY;
// const nodeId = `n-${upperCount + index}`;
// newNodes.push({
// id: nodeId,
// name: item.name || `节点${upperCount + index}`,
// symbol: `image://${item.isSanctioned ? companyActive : company}`,
// symbolSize: 40,
// value: 5,
// isSanctioned: item.isSanctioned,
// x,
// y
// });
// // 根据 direction 决定链接方向
// if (item.direction === "source") {
// newLinks.push({
// source: nodeId,
// target: 0,
// name: item.linkType,
// label: { show: true, formatter: "{c}" }
// });
// } else {
// newLinks.push({
// source: 0,
// target: nodeId,
// name: item.linkType,
// label: { show: true, formatter: "{c}" }
// });
// }
// });
// console.log("最终节点数:", newNodes, "最终链接数:", newLinks, "上方节点:", upperCount, "下方节点:", lowerCount);
// // 更新响应式数据
// nodes.value = newNodes;
// links.value = newLinks;
// };
const
updateTreeData
=
data
=>
{
if
(
!
data
)
return
;
...
...
src/views/exportControl/v2.0SingleSanction/components/impactAnalysis/components/industrialImpact/index.vue
浏览文件 @
8e14f2ea
...
...
@@ -1317,7 +1317,7 @@ onMounted(async () => {
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
30px
0
;
.data-origin-icon
{
width
:
16px
;
...
...
src/views/exportControl/v2.0SingleSanction/components/impactAnalysis/components/researchImpact/index.vue
浏览文件 @
8e14f2ea
...
...
@@ -1543,7 +1543,7 @@ onBeforeUnmount(() => {
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
35px
0
;
.data-origin-icon
{
width
:
16px
;
...
...
src/views/exportControl/v2.0SingleSanction/index.vue
浏览文件 @
8e14f2ea
...
...
@@ -52,7 +52,7 @@
:close-on-click-modal=
"false"
@
close=
"resetModal"
>
<div
class=
"sanction-list"
>
<div
class=
"sanction-list"
:loading=
"loading"
>
<div
v-for=
"item in sanctionList"
:key=
"item.id"
...
...
@@ -61,6 +61,7 @@
@click="selectSanction(item)"
>
{{
item
.
name
}}
<div
class=
"sanction-type"
>
{{
item
.
postDate
}}
</div>
</div>
</div>
...
...
@@ -193,6 +194,7 @@ const handleAnalysisClick = () => {
};
// ========== 新增响应式状态 ==========
const
loading
=
ref
(
false
);
const
sanctionModalVisible
=
ref
(
false
);
const
sanctionList
=
ref
([]);
const
selectedSanctionId
=
ref
(
null
);
...
...
@@ -204,6 +206,7 @@ const totalElements = ref(0);
const
openSanctionModal
=
async
()
=>
{
sanctionModalVisible
.
value
=
true
;
console
.
log
(
"制裁事件列表11:"
,
sanctionList
.
value
);
loading
.
value
=
true
;
await
fetchSanctionData
();
};
...
...
@@ -211,6 +214,7 @@ const openSanctionModal = async () => {
const
fetchSanctionData
=
async
()
=>
{
try
{
const
res
=
await
getSanctionProcess
([
1
],
currentPage
.
value
,
10
);
loading
.
value
=
false
;
if
(
res
&&
!!
res
.
content
)
{
sanctionList
.
value
=
res
.
content
||
[];
totalElements
.
value
=
res
.
totalElements
||
0
;
...
...
@@ -225,6 +229,7 @@ const fetchSanctionData = async () => {
}
}
catch
(
error
)
{
console
.
error
(
"获取制裁事件失败:"
,
error
);
loading
.
value
=
false
;
sanctionList
.
value
=
[];
totalElements
.
value
=
0
;
}
...
...
@@ -237,7 +242,7 @@ const handlePageChange = async newPage => {
};
// ========== 选择某项 ==========
const
selectSanction
=
item
=>
{
const
selectSanction
=
async
item
=>
{
selectedSanctionId
.
value
=
item
.
id
;
router
.
replace
({
path
:
window
.
location
.
pathname
,
...
...
@@ -247,7 +252,10 @@ const selectSanction = item => {
}
});
sanctionModalVisible
.
value
=
false
;
window
.
location
.
reload
();
console
.
log
(
"跳转URL:"
,
window
.
location
.
href
);
// 根据最新URL参数刷新当前页面
window
.
open
(
`
${
window
.
location
.
pathname
}
?id=
${
item
.
id
}
&sanTypeId=
${
item
.
sanTypeId
}
`
,
"_self"
);
};
// ========== 关闭弹窗时重置 ==========
...
...
@@ -467,6 +475,8 @@ onMounted(() => {
font-size
:
14px
;
color
:
#333
;
transition
:
background-color
0
.2s
;
display
:
flex
;
justify-content
:
space-between
;
}
.sanction-item
:hover
{
...
...
src/views/exportControl/v2.0SingleSanction/originPage/index-back.vue
0 → 100644
浏览文件 @
8e14f2ea
<
template
>
<div
class=
"entity-list"
>
<div
class=
"header"
>
<div
class=
"header-title"
>
<img
:src=
"headerTitle.img"
alt=
""
/>
<div>
<div
class=
"title"
>
{{
headerTitle
.
title
}}
<!--
<span>
{{
headerTitle
.
titleEn
}}
</span>
-->
</div>
<div
class=
"department"
>
{{
headerTitle
.
department
}}
</div>
</div>
<!--
<div
class=
"btn"
>
<img
:src=
"icon01"
alt=
""
>
切换
</div>
-->
</div>
</div>
<div
class=
"main"
>
<div
class=
"pdf-container"
>
<iframe
v-if=
"headerTitle.srcUrl"
:src=
"headerTitle.srcUrl"
width=
"100%"
height=
"100%"
frameborder=
"0"
></iframe>
<div
v-else
class=
"no-pdf"
>
暂无原文
</div>
</div>
<div
class=
"pdf-container"
>
<iframe
v-if=
"headerTitle.transUrl"
:src=
"headerTitle.transUrl"
width=
"100%"
height=
"100%"
frameborder=
"0"
></iframe>
<div
v-else
class=
"no-pdf"
>
暂无译文
</div>
</div>
</div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
}
from
"vue"
;
import
{
getSingleSanctionOverview
}
from
"@/api/exportControlV2.0.js"
;
import
title
from
"../assets/title.png"
;
import
icon01
from
"../assets/icon01.png"
;
// 单次制裁-制裁概况-基本信息
const
singleSanctionOverview
=
ref
({});
const
getSingleSanctionOverviewData
=
async
()
=>
{
if
(
!
sanRecordId
.
value
)
return
;
try
{
const
res
=
await
getSingleSanctionOverview
({
sanRecordId
:
sanRecordId
.
value
});
if
(
res
.
code
===
200
)
{
singleSanctionOverview
.
value
=
res
.
data
||
{};
// 格式化日期
let
dateStr
=
""
;
if
(
singleSanctionOverview
.
value
.
postDate
)
{
const
date
=
new
Date
(
singleSanctionOverview
.
value
.
postDate
);
if
(
!
isNaN
(
date
.
getTime
()))
{
dateStr
=
`
${
date
.
getFullYear
()}
年
${
date
.
getMonth
()
+
1
}
月
${
date
.
getDate
()}
日`
;
}
else
{
dateStr
=
singleSanctionOverview
.
value
.
postDate
;
}
}
// 更新头部信息
headerTitle
.
value
=
{
...
headerTitle
.
value
,
title
:
`
${
dateStr
}
《
${
singleSanctionOverview
.
value
.
sanTitleZh
||
singleSanctionOverview
.
value
.
sanTitle
}
》`
,
titleEn
:
singleSanctionOverview
.
value
.
sanTitle
||
""
,
department
:
singleSanctionOverview
.
value
.
fileCode
||
""
,
srcUrl
:
singleSanctionOverview
.
value
.
srcUrl
||
""
,
transUrl
:
singleSanctionOverview
.
value
.
transUrl
||
""
};
}
}
catch
(
error
)
{
console
.
error
(
"获取制裁概况失败:"
,
error
);
}
};
const
headerTitle
=
ref
({
img
:
title
});
// 获取URL参数
const
sanRecordId
=
ref
(
""
);
const
getUrlParams
=
()
=>
{
const
urlParams
=
new
URLSearchParams
(
window
.
location
.
search
);
sanRecordId
.
value
=
urlParams
.
get
(
"id"
)
||
""
;
};
onMounted
(()
=>
{
getUrlParams
();
getSingleSanctionOverviewData
();
});
</
script
>
<
style
scoped
lang=
"scss"
>
*
{
margin
:
0
;
padding
:
0
;
}
.entity-list
{
width
:
100%
;
height
:
100%
;
.header
{
width
:
100%
;
height
:
148px
;
background-color
:
#fff
;
padding-top
:
16px
;
.header-title
{
width
:
1601px
;
height
:
72px
;
background-color
:
rgba
(
246
,
250
,
255
,
1
);
margin
:
0
auto
;
border-radius
:
10px
;
border
:
2px
solid
rgba
(
174
,
214
,
255
,
1
);
display
:
flex
;
align-items
:
center
;
margin-bottom
:
12px
;
position
:
relative
;
img
{
width
:
54px
;
height
:
54px
;
margin-left
:
15px
;
margin-right
:
11px
;
}
.title
{
font-size
:
20px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
26px
;
color
:
rgb
(
59
,
65
,
75
);
span
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
95
,
101
,
108
);
margin-left
:
11px
;
}
}
.department
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
95
,
101
,
108
);
}
.btn
{
cursor
:
pointer
;
display
:
flex
;
align-items
:
center
;
position
:
absolute
;
right
:
16px
;
top
:
25px
;
font-size
:
18px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
5
,
95
,
194
);
img
{
width
:
20px
;
height
:
20px
;
margin-right
:
7px
;
}
}
}
.header-nav
{
width
:
1601px
;
margin
:
0
auto
;
height
:
48px
;
display
:
flex
;
align-items
:
center
;
.nav-item
{
display
:
flex
;
align-items
:
center
;
height
:
100%
;
margin-right
:
32px
;
cursor
:
pointer
;
position
:
relative
;
font-size
:
18px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
59
,
65
,
75
);
&
:last-child
{
margin-right
:
0
;
}
img
{
width
:
16px
;
height
:
16px
;
margin-right
:
4px
;
}
&
.active
{
color
:
rgb
(
5
,
95
,
194
);
font-weight
:
700
;
}
.active-line
{
position
:
absolute
;
bottom
:
0
;
left
:
0
;
width
:
100%
;
height
:
3px
;
background-color
:
#055fc2
;
border-radius
:
1
.5px
;
}
}
.original-text-btn
{
margin-left
:
auto
;
width
:
152px
;
height
:
36px
;
background
:
#ffffff
;
border-radius
:
4px
;
border
:
1px
solid
rgba
(
230
,
231
,
232
,
1
);
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
img
{
width
:
16px
;
height
:
16px
;
margin-right
:
8px
;
}
span
{
font-size
:
16px
;
font-weight
:
400
;
color
:
rgb
(
95
,
101
,
108
);
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
}
}
}
}
.main
{
width
:
1601px
;
height
:
calc
(
100%
-
148px
);
background-color
:
#f7f8f9
;
margin
:
0
auto
;
display
:
flex
;
justify-content
:
space-between
;
padding-top
:
20px
;
box-sizing
:
border-box
;
.pdf-container
{
width
:
790px
;
height
:
calc
(
100%
-
20px
);
background-color
:
#fff
;
// border: 1px solid rgba(174, 214, 255, 1);
border-radius
:
4px
;
overflow
:
hidden
;
.no-pdf
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
height
:
100%
;
color
:
#909399
;
font-size
:
16px
;
background-color
:
#fff
;
}
}
}
}
</
style
>
src/views/exportControl/v2.0SingleSanction/originPage/index.vue
浏览文件 @
8e14f2ea
差异被折叠。
点击展开。
src/views/exportControl/v2.0SingleSanction/originPage/pdf.vue
0 → 100644
浏览文件 @
8e14f2ea
差异被折叠。
点击展开。
src/views/finance/index.vue
浏览文件 @
8e14f2ea
差异被折叠。
点击展开。
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论