Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
26ccefc7
提交
26ccefc7
authored
3月 16, 2026
作者:
张烨
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix:政令-受影响实体板块-鱼骨图增加缩放和移动的功能
上级
123be9b5
显示空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
232 行增加
和
1086 行删除
+232
-1086
index.vue
src/views/decree/decreeLayout/deepdig/index.vue
+2
-1
index.vue
src/views/decree/decreeLayout/index.vue
+6
-6
ChartRelation.vue
src/views/decree/decreeLayout/influence/ChartRelation.vue
+0
-697
AiTips.vue
src/views/decree/decreeLayout/influence/com/AiTips.vue
+62
-0
ChartChain.vue
src/views/decree/decreeLayout/influence/com/ChartChain.vue
+106
-204
index.vue
src/views/decree/decreeLayout/influence/index.vue
+56
-178
没有找到文件。
src/views/decree/decreeLayout/deepdig/index.vue
浏览文件 @
26ccefc7
...
...
@@ -3,7 +3,7 @@
<div
class=
"box1"
>
<AnalysisBox
title=
"相关政令"
:showAllBtn=
"false"
>
<div
class=
"box1-main"
>
<el-empty
v-if=
"
siderList.length===0"
style=
"padding-top: 30%
"
description=
"暂无数据"
:image-size=
"100"
/>
<el-empty
v-if=
"
!siderList?.length"
style=
"padding-top: 40%;
"
description=
"暂无数据"
:image-size=
"100"
/>
<el-scrollbar
height=
"100%"
always
>
<div
class=
"left-item"
:class=
"
{ 'item-active': false }" v-for="(item, index) in siderList" :key="index" @click="handleClickDecree(item)">
<div
class=
"item-head"
>
...
...
@@ -18,6 +18,7 @@
</div>
<div
class=
"box2"
>
<AnalysisBox
title=
"政令关系挖掘"
:showAllBtn=
"false"
>
<el-empty
v-if=
"!siderList?.length"
style=
"padding-top: 20%;"
description=
"暂无数据"
:image-size=
"100"
/>
<div
class=
"box2-main"
>
<div
ref=
"containerRef"
class=
"graph-container"
></div>
</div>
...
...
src/views/decree/decreeLayout/index.vue
浏览文件 @
26ccefc7
...
...
@@ -203,12 +203,12 @@ const mainHeaderBtnList = ref([
name
:
"深度挖掘"
,
path
:
"/decreeLayout/deepDig"
},
//
{
//
icon: icon3,
//
activeIcon: icon3Active,
//
name: "影响分析",
//
path: "/decreeLayout/influence"
//
},
{
icon
:
icon3
,
activeIcon
:
icon3Active
,
name
:
"影响分析"
,
path
:
"/decreeLayout/influence"
},
]);
const
activeTitle
=
ref
(
"政令概况"
);
...
...
src/views/decree/decreeLayout/influence/ChartRelation.vue
deleted
100644 → 0
浏览文件 @
123be9b5
<
template
>
<div
class=
"relation-graph-wrapper"
>
<div
class=
"graph-controls"
>
<!-- 这项政令标志着中美AI竞争进入一个新阶段,其核心特征是 “精准封锁”与“体系输出”相结合。它短期内无疑会给中国AI产业链带来压力,但长期看,这场竞争更可能是一场围绕技术路线、生态系统和治理规则的持久战。 -->
<div
v-for=
"item in controlBtns"
:key=
"item.type"
:class=
"['control-btn',
{ 'control-btn-active': currentLayoutType === item.type }]" @click="handleClickControlBtn(item.type)">
<img
:src=
"item.icon"
alt=
""
/>
</div>
</div>
<div
ref=
"containerRef"
class=
"graph-container"
></div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
onUnmounted
,
watch
,
nextTick
}
from
'vue'
import
G6
from
'@antv/g6'
import
{
Close
}
from
'@element-plus/icons-vue'
import
echartsIcon01
from
'./assets/images/echartsicon01.png'
import
echartsIcon02
from
'./assets/images/echartsicon02.png'
import
echartsIcon03
from
'./assets/images/echartsicon03.png'
const
props
=
defineProps
({
graphData
:
{
type
:
Object
,
default
:
()
=>
({
nodes
:
[],
links
:
[]
})
},
treeData
:
{
type
:
Object
,
default
:
()
=>
null
},
controlActive
:
{
type
:
Number
,
default
:
1
}
})
const
emit
=
defineEmits
([
'nodeClick'
,
'layoutChange'
])
const
containerRef
=
ref
(
null
)
const
graphInstance
=
ref
(
null
)
const
currentLayoutType
=
ref
(
1
)
const
controlBtns
=
[
{
type
:
1
,
icon
:
echartsIcon01
,
name
:
'力导向布局'
},
{
type
:
2
,
icon
:
echartsIcon02
,
name
:
'树布局'
},
{
type
:
3
,
icon
:
echartsIcon03
,
name
:
'环状布局'
}
]
const
initGraph
=
(
layoutType
=
1
)
=>
{
if
(
!
containerRef
.
value
)
return
destroyGraph
()
nextTick
(()
=>
{
const
width
=
containerRef
.
value
.
offsetWidth
||
800
const
height
=
containerRef
.
value
.
offsetHeight
||
600
switch
(
layoutType
)
{
case
1
:
initNormalGraph
(
layoutType
,
width
,
height
)
break
case
2
:
initTreeGraph
(
width
,
height
)
break
case
3
:
initCircularGraph
(
width
,
height
)
break
}
})
}
const
initNormalGraph
=
(
layoutType
,
width
,
height
)
=>
{
const
data
=
processGraphData
(
props
.
graphData
)
if
(
!
data
.
nodes
||
data
.
nodes
.
length
===
0
)
return
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
}
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
}
}
}
},
defaultEdge
:
{
type
:
'quadratic'
,
style
:
{
stroke
:
'#5B8FF9'
,
lineWidth
:
3
,
opacity
:
0.9
,
endArrow
:
{
path
:
'M 0,0 L 12,6 L 12,-6 Z'
,
fill
:
'#5B8FF9'
}
},
labelCfg
:
{
autoRotate
:
true
,
style
:
{
fill
:
'#333'
,
fontSize
:
10
,
fontFamily
:
'Microsoft YaHei'
,
background
:
{
fill
:
'#fff'
,
padding
:
[
2
,
4
,
2
,
4
],
radius
:
2
}
}
}
},
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
initCircularGraph
=
(
width
,
height
)
=>
{
const
data
=
processGraphData
(
props
.
graphData
)
if
(
!
data
.
nodes
||
data
.
nodes
.
length
===
0
)
return
const
centerX
=
width
/
2
const
centerY
=
height
/
2
const
radius
=
Math
.
min
(
width
,
height
)
/
2
-
120
const
otherNodes
=
data
.
nodes
.
filter
(
n
=>
!
n
.
isCenter
)
const
nodeCount
=
otherNodes
.
length
otherNodes
.
forEach
((
node
,
index
)
=>
{
const
angle
=
(
2
*
Math
.
PI
*
index
)
/
nodeCount
-
Math
.
PI
/
2
node
.
x
=
centerX
+
radius
*
Math
.
cos
(
angle
)
node
.
y
=
centerY
+
radius
*
Math
.
sin
(
angle
)
})
const
centerNode
=
data
.
nodes
.
find
(
n
=>
n
.
isCenter
)
if
(
centerNode
)
{
centerNode
.
x
=
centerX
centerNode
.
y
=
centerY
centerNode
.
fx
=
centerX
centerNode
.
fy
=
centerY
}
graphInstance
.
value
=
new
G6
.
Graph
({
container
:
containerRef
.
value
,
width
,
height
,
fitView
:
false
,
fitCenter
:
false
,
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
}
]
},
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
}
}
}
},
defaultEdge
:
{
type
:
'quadratic'
,
style
:
{
stroke
:
'#5B8FF9'
,
lineWidth
:
3
,
opacity
:
0.9
,
endArrow
:
{
path
:
'M 0,0 L 12,6 L 12,-6 Z'
,
fill
:
'#5B8FF9'
}
},
labelCfg
:
{
autoRotate
:
true
,
style
:
{
fill
:
'#333'
,
fontSize
:
10
,
fontFamily
:
'Microsoft YaHei'
,
background
:
{
fill
:
'#fff'
,
padding
:
[
2
,
4
,
2
,
4
],
radius
:
2
}
}
}
},
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
initTreeGraph
=
(
width
,
height
)
=>
{
const
treeDataSource
=
convertGraphToTree
(
props
.
graphData
)
if
(
!
treeDataSource
)
return
graphInstance
.
value
=
new
G6
.
TreeGraph
({
container
:
containerRef
.
value
,
width
,
height
,
fitView
:
true
,
fitViewPadding
:
80
,
animate
:
true
,
animateCfg
:
{
duration
:
300
,
easing
:
'easeLinear'
},
minZoom
:
0.1
,
maxZoom
:
10
,
modes
:
{
default
:
[
'drag-canvas'
,
'zoom-canvas'
,
'drag-node'
,
{
type
:
'collapse-expand'
,
onChange
:
function
onChange
(
item
,
collapsed
)
{
const
data
=
item
.
getModel
()
data
.
collapsed
=
collapsed
return
true
}
}
]
},
layout
:
{
type
:
'compactBox'
,
direction
:
'LR'
,
getId
:
function
getId
(
d
)
{
return
d
.
id
},
getHeight
:
function
getHeight
()
{
return
16
},
getWidth
:
function
getWidth
()
{
return
16
},
getVGap
:
function
getVGap
()
{
return
30
},
getHGap
:
function
getHGap
()
{
return
120
}
},
defaultNode
:
{
type
:
'image'
,
size
:
40
,
clipCfg
:
{
show
:
true
,
type
:
'circle'
,
r
:
20
},
labelCfg
:
{
position
:
'right'
,
offset
:
10
,
style
:
{
fill
:
'#333'
,
fontSize
:
11
,
fontFamily
:
'Microsoft YaHei'
,
background
:
{
fill
:
'rgba(255, 255, 255, 0.95)'
,
padding
:
[
4
,
6
,
4
,
6
],
radius
:
4
}
}
}
},
defaultEdge
:
{
type
:
'cubic-horizontal'
,
style
:
{
stroke
:
'#5B8FF9'
,
lineWidth
:
3
}
},
nodeStateStyles
:
{
active
:
{
shadowColor
:
'#1459BB'
,
shadowBlur
:
15
,
stroke
:
'#1459BB'
,
lineWidth
:
3
}
}
})
graphInstance
.
value
.
data
(
treeDataSource
)
graphInstance
.
value
.
render
()
graphInstance
.
value
.
fitView
()
bindGraphEvents
()
}
const
convertGraphToTree
=
(
graphData
)
=>
{
if
(
!
graphData
||
!
graphData
.
nodes
||
graphData
.
nodes
.
length
===
0
)
{
return
null
}
const
nodes
=
graphData
.
nodes
const
links
=
graphData
.
links
||
graphData
.
edges
||
[]
const
centerNode
=
nodes
[
0
]
const
centerId
=
String
(
centerNode
.
id
||
'0'
)
const
childIdSet
=
new
Set
()
const
childrenNodes
=
[]
links
.
forEach
((
link
)
=>
{
const
source
=
String
(
link
.
source
)
const
target
=
String
(
link
.
target
)
if
(
source
===
centerId
&&
!
childIdSet
.
has
(
target
))
{
const
node
=
nodes
.
find
(
n
=>
String
(
n
.
id
)
===
target
)
if
(
node
)
{
childIdSet
.
add
(
target
)
childrenNodes
.
push
({
id
:
target
,
label
:
node
.
name
||
''
,
img
:
node
.
image
||
echartsIcon03
,
size
:
node
.
symbolSize
||
40
,
name
:
node
.
name
,
image
:
node
.
image
,
isSanctioned
:
node
.
isSanctioned
})
}
}
else
if
(
target
===
centerId
&&
!
childIdSet
.
has
(
source
))
{
const
node
=
nodes
.
find
(
n
=>
String
(
n
.
id
)
===
source
)
if
(
node
)
{
childIdSet
.
add
(
source
)
childrenNodes
.
push
({
id
:
source
,
label
:
node
.
name
||
''
,
img
:
node
.
image
||
echartsIcon03
,
size
:
node
.
symbolSize
||
40
,
name
:
node
.
name
,
image
:
node
.
image
,
isSanctioned
:
node
.
isSanctioned
})
}
}
})
if
(
childrenNodes
.
length
===
0
)
{
nodes
.
slice
(
1
).
forEach
((
node
)
=>
{
const
nodeId
=
String
(
node
.
id
)
if
(
!
childIdSet
.
has
(
nodeId
))
{
childIdSet
.
add
(
nodeId
)
childrenNodes
.
push
({
id
:
nodeId
,
label
:
node
.
name
||
''
,
img
:
node
.
image
||
echartsIcon03
,
size
:
node
.
symbolSize
||
40
,
name
:
node
.
name
,
image
:
node
.
image
,
isSanctioned
:
node
.
isSanctioned
})
}
})
}
return
{
id
:
centerId
,
label
:
centerNode
.
name
||
''
,
img
:
centerNode
.
image
||
echartsIcon03
,
size
:
centerNode
.
symbolSize
||
60
,
name
:
centerNode
.
name
,
image
:
centerNode
.
image
,
isSanctioned
:
centerNode
.
isSanctioned
,
children
:
childrenNodes
}
}
const
processGraphData
=
(
rawData
)
=>
{
if
(
!
rawData
||
!
rawData
.
nodes
||
rawData
.
nodes
.
length
===
0
)
{
return
{
nodes
:
[],
edges
:
[]
}
}
const
nodeMap
=
new
Map
()
const
nodes
=
[]
rawData
.
nodes
.
forEach
((
node
,
index
)
=>
{
const
nodeId
=
String
(
node
.
id
||
index
)
if
(
nodeMap
.
has
(
nodeId
))
{
return
}
nodeMap
.
set
(
nodeId
,
true
)
const
isCenter
=
index
===
0
const
size
=
node
.
symbolSize
||
(
isCenter
?
60
:
40
)
nodes
.
push
({
id
:
nodeId
,
label
:
node
.
name
||
''
,
img
:
node
.
image
||
echartsIcon03
,
size
,
isCenter
,
clipCfg
:
{
show
:
true
,
type
:
'circle'
,
r
:
size
/
2
},
style
:
{
cursor
:
'pointer'
},
labelCfg
:
{
position
:
'bottom'
,
offset
:
12
,
style
:
{
fill
:
isCenter
?
'#1459BB'
:
'#333'
,
fontSize
:
isCenter
?
13
:
11
,
fontWeight
:
isCenter
?
'bold'
:
'normal'
,
fontFamily
:
'Microsoft YaHei'
,
textAlign
:
'center'
}
},
...
node
,
id
:
nodeId
})
})
const
edgeMap
=
new
Map
()
const
edges
=
[]
const
rawEdges
=
rawData
.
links
||
rawData
.
edges
||
[]
rawEdges
.
forEach
((
edge
,
index
)
=>
{
const
source
=
String
(
edge
.
source
)
const
target
=
String
(
edge
.
target
)
const
edgeKey
=
`
${
source
}
-
${
target
}
`
if
(
edgeMap
.
has
(
edgeKey
))
{
return
}
if
(
!
nodeMap
.
has
(
source
)
||
!
nodeMap
.
has
(
target
))
{
return
}
edgeMap
.
set
(
edgeKey
,
true
)
edges
.
push
({
id
:
`edge-
${
index
}
`
,
source
,
target
,
label
:
edge
.
name
||
''
})
})
return
{
nodes
,
edges
}
}
const
bindGraphEvents
=
()
=>
{
if
(
!
graphInstance
.
value
)
return
graphInstance
.
value
.
on
(
'node:click'
,
(
evt
)
=>
{
const
node
=
evt
.
item
const
model
=
node
.
getModel
()
emit
(
'nodeClick'
,
model
)
})
graphInstance
.
value
.
on
(
'canvas:click'
,
()
=>
{
})
}
const
handleClickControlBtn
=
(
btn
)
=>
{
currentLayoutType
.
value
=
btn
emit
(
'layoutChange'
,
btn
)
initGraph
(
btn
)
}
const
destroyGraph
=
()
=>
{
if
(
graphInstance
.
value
)
{
graphInstance
.
value
.
destroy
()
graphInstance
.
value
=
null
}
}
const
handleResize
=
()
=>
{
if
(
graphInstance
.
value
&&
containerRef
.
value
)
{
const
width
=
containerRef
.
value
.
offsetWidth
const
height
=
containerRef
.
value
.
offsetHeight
graphInstance
.
value
.
changeSize
(
width
,
height
)
graphInstance
.
value
.
fitView
()
}
}
watch
(
()
=>
props
.
graphData
,
()
=>
{
initGraph
(
currentLayoutType
.
value
)
}
)
watch
(
()
=>
props
.
treeData
,
()
=>
{
if
(
currentLayoutType
.
value
===
2
)
{
initGraph
(
2
)
}
}
)
watch
(
()
=>
props
.
controlActive
,
(
newVal
)
=>
{
if
(
newVal
!==
currentLayoutType
.
value
)
{
handleClickControlBtn
(
newVal
)
}
}
)
onMounted
(()
=>
{
initGraph
(
1
)
window
.
addEventListener
(
'resize'
,
handleResize
)
})
onUnmounted
(()
=>
{
window
.
removeEventListener
(
'resize'
,
handleResize
)
destroyGraph
()
})
defineExpose
({
refresh
:
()
=>
initGraph
(
currentLayoutType
.
value
),
changeLayout
:
(
type
)
=>
handleClickControlBtn
(
type
),
getGraph
:
()
=>
graphInstance
.
value
})
</
script
>
<
style
lang=
"scss"
scoped
>
.relation-graph-wrapper
{
position
:
relative
;
width
:
100%
;
height
:
100%
;
}
.graph-container
{
width
:
100%
;
height
:
100%
;
}
.graph-controls
{
position
:
absolute
;
top
:
16px
;
right
:
16px
;
display
:
flex
;
gap
:
8px
;
z-index
:
10
;
.control-btn
{
width
:
32px
;
height
:
32px
;
border-radius
:
4px
;
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
img
{
width
:
16px
;
height
:
16px
;
}
&
:hover
{
border-color
:
rgba
(
5
,
95
,
194
,
0
.5
);
}
}
.control-btn-active
{
border-color
:
rgba
(
5
,
95
,
194
,
1
);
background
:
rgba
(
231
,
243
,
255
,
1
);
}
}
</
style
>
\ No newline at end of file
src/views/decree/decreeLayout/influence/com/AiTips.vue
0 → 100644
浏览文件 @
26ccefc7
<
template
>
<div
class=
"view-box"
>
<div
class=
"icon-left"
>
<img
src=
"../../assets/icons/ai.png"
alt=
""
>
</div>
<div
class=
"tips-content"
>
{{
props
.
tips
}}
</div>
<div
class=
"icon-right"
>
<img
src=
"../../assets/icons/right.png"
alt=
""
>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
name=
"AiTips"
>
const
props
=
defineProps
({
tips
:
{
type
:
String
,
default
:
''
}
});
</
script
>
<
style
scoped
lang=
"scss"
>
.view-box
{
width
:
100%
;
display
:
flex
;
align-items
:
center
;
padding
:
7px
12px
;
border
:
1px
solid
rgba
(
231
,
243
,
255
,
1
);
border-radius
:
4px
;
background
:
rgba
(
246
,
250
,
255
,
1
);
.icon-left
{
width
:
20px
;
height
:
20px
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
contain
;
}
}
.tips-content
{
color
:
rgb
(
5
,
95
,
194
);
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
margin-left
:
13px
;
flex
:
1
;
}
.icon-right
{
width
:
24px
;
height
:
24px
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
contain
;
}
}
}
</
style
>
\ No newline at end of file
src/views/decree/decreeLayout/influence/ChartChain.vue
→
src/views/decree/decreeLayout/influence/
com/
ChartChain.vue
浏览文件 @
26ccefc7
<
template
>
<div
class=
"view-box"
>
<div
class=
"right-main"
>
<div
class=
"right-main-content"
>
<div
class=
"hintWrap"
>
<div
class=
"icon1"
></div>
<div
class=
"title"
>
这项政令标志着中美AI竞争进入一个新阶段,其核心特征是 “精准封锁”与“体系输出”相结合。它短期内无疑会给中国AI产业链带来压力,但长期看,这场竞争更可能是一场围绕技术路线、生态系统和治理规则的持久战。
</div>
<div
class=
"icon2Wrap"
>
<div
class=
"icon2"
></div>
</div>
</div>
<div
class=
"right-main-content-main"
>
<div
class=
"fishbone-wrapper"
>
<div
class=
"fishbone-scroll-container"
ref=
"scrollContainerRef"
>
<div
class=
"fishbone"
v-if=
"dataList.length > 0"
>
<div
class=
"main-line"
:style=
"
{ width: dataList.length * 200 + 300 + 'px' }">
<el-empty
v-if=
"!dataList?.length"
style=
"padding-top: 15%;"
description=
"暂无数据"
:image-size=
"100"
/>
<div
v-if=
"dataList.length"
class=
"main-content-main"
>
<div
class=
"main-mask"
@
wheel
.
prevent=
"handleWheel"
@
mousedown=
"handleMouseDown"
@
mouseup=
"handleMouseUp"
@
mouseleave=
"handleMouseUp"
@
mousemove=
"handleMouseMove"
></div>
<div
class=
"fishbone-container"
:style=
"
{ transform: `translate(${translateX}px, ${translateY}px) scale(${scale})`, transformOrigin: 'center center' }">
<!-- 主轴上的标签 -->
<div
class=
"main-line"
:style=
"
{ width: dataList.length * 200 + 300 + 'px' }">
<div
class=
"main-line-text"
v-for=
"(item, index) in dataList"
:key=
"'label-' + index"
:class=
"
{
'blue-theme': index
<
2
,
...
...
@@ -27,36 +22,35 @@
</div>
</div>
<!-- 奇数索引的数据组放在上方 -->
<div
v-for=
"(causeGroup, groupIndex) in onFilterData(1)"
:key=
"'top-' +
groupIndex"
:class=
"getTopBoneClass(groupIndex)"
:style=
"
{ left: groupIndex * 400 + 42
0 + 'px' }">
<div
v-for=
"(causeGroup, groupIndex) in onFilterData(1)"
:key=
"
groupIndex"
class=
"top-bone"
:style=
"
{ left: groupIndex * 400 + 510 + 'px', height: (causeGroup.causes?.length) * 22 + 10
0 + 'px' }">
<div
class=
"left-bone"
>
<div
class=
"left-bone-item"
v-for=
"(item, index) in getLeftItems(causeGroup.causes)"
:key=
"'left-' + index
"
>
<div
class=
"left-bone-item"
v-for=
"item in getLeftItems(causeGroup.causes)"
:key=
"item.id
"
>
<img
:src=
"defaultIcon2 || item.picture"
alt=
""
class=
"company-icon"
/>
<div
class=
"text"
:title=
"item.name"
>
{{
item
.
name
}}
</div>
<div
class=
"line"
></div>
</div>
</div>
<div
class=
"right-bone"
>
<div
class=
"right-bone-item"
v-for=
"(item, index) in getRightItems(causeGroup.causes)"
:key=
"'right-' + index
"
>
<div
class=
"right-bone-item"
v-for=
"item in getRightItems(causeGroup.causes)"
:key=
"item.id
"
>
<div
class=
"line"
></div>
<img
:src=
"defaultIcon2 || item.picture"
alt=
""
class=
"company-icon"
/>
<div
class=
"text"
:title=
"item.name"
>
{{
item
.
name
}}
</div>
</div>
</div>
</div>
<!-- 偶数索引的数据组放在下方 -->
<div
v-for=
"(causeGroup, groupIndex) in onFilterData(0)"
:key=
"'bottom-' +
groupIndex"
:class=
"getBottomBoneClass(groupIndex)"
:style=
"
{ left: groupIndex * 400 + 22
0 + 'px' }">
<div
v-for=
"(causeGroup, groupIndex) in onFilterData(0)"
:key=
"
groupIndex"
class=
"bottom-bone"
:style=
"
{ left: groupIndex * 400 + 310 + 'px', height: (causeGroup.causes?.length) * 22 + 10
0 + 'px' }">
<div
class=
"left-bone"
>
<div
class=
"left-bone-item"
v-for=
"(item, index) in getLeftItems(causeGroup.causes)"
:key=
"'left-bottom-' + index
"
>
<div
class=
"left-bone-item"
v-for=
"item in getRightItems(causeGroup.causes)"
:key=
"item.id
"
>
<img
:src=
"defaultIcon2 || item.picture"
alt=
""
class=
"company-icon"
/>
<div
class=
"text"
:title=
"item.name"
>
{{
item
.
name
}}
</div>
<div
class=
"line"
></div>
</div>
</div>
<div
class=
"right-bone"
>
<div
class=
"right-bone-item"
v-for=
"(item, index) in getRightItems(causeGroup.causes)"
:key=
"'right-bottom-' + index
"
>
<div
class=
"right-bone-item"
v-for=
"item in getLeftItems(causeGroup.causes)"
:key=
"item.id
"
>
<div
class=
"line"
></div>
<img
:src=
"defaultIcon2 || item.picture"
alt=
""
class=
"company-icon"
/>
<div
class=
"text"
:title=
"item.name"
>
{{
item
.
name
}}
</div>
...
...
@@ -64,14 +58,8 @@
</div>
</div>
</div>
<div
v-else
style=
"display: flex; justify-content: center; align-items: center; height: 200px; width: 100%"
>
<el-empty
description=
"暂无相关数据"
/>
</div>
</div>
</div>
</div>
<div
class=
"right-main-content-footer"
>
<div
v-if=
"dataList.length"
class=
"main-content-footer"
>
<div
class=
"footer-item footer-item1"
>
<div
class=
"footer-item-bottom"
>
<div
class=
"icon"
>
...
...
@@ -119,8 +107,6 @@
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/template
>
<
script
setup
name
=
"ChartChain"
>
...
...
@@ -129,6 +115,41 @@ import defaultIcon2 from "@/assets/icons/default-icon2.png";
import
noticeIcon
from
"./assets/images/notice-icon.png"
;
import
{
getDeepMiningSelect
,
getDeepMiningIndustry
,
getDeepMiningIndustryFishbone
,
getDeepMiningIndustryEntity
}
from
"@/api/exportControlV2.0"
;
// 缩放功能处理
const
scale
=
ref
(
1
)
const
minScale
=
0.1
const
maxScale
=
10
const
handleWheel
=
(
e
)
=>
{
if
(
e
.
deltaY
<
0
)
{
// 放大:不超过最大值
scale
.
value
=
Math
.
min
(
scale
.
value
+
0.1
,
maxScale
)
}
else
{
// 缩小:不低于最小值
scale
.
value
=
Math
.
max
(
scale
.
value
-
0.1
,
minScale
)
}
}
// 移动功能处理
const
translateX
=
ref
(
0
)
// X轴位移
const
translateY
=
ref
(
0
)
// Y轴位移
let
isDragging
=
false
let
startX
=
0
let
startY
=
0
const
handleMouseMove
=
(
e
)
=>
{
if
(
!
isDragging
)
return
translateX
.
value
=
e
.
clientX
-
startX
translateY
.
value
=
e
.
clientY
-
startY
}
const
handleMouseDown
=
(
e
)
=>
{
// 排除右键/中键,只响应左键(e.button=0为左键)
if
(
e
.
button
!==
0
)
return
isDragging
=
true
startX
=
e
.
clientX
-
translateX
.
value
startY
=
e
.
clientY
-
translateY
.
value
}
const
handleMouseUp
=
()
=>
{
isDragging
=
false
}
// 实体清单-深度挖掘-产业链中国企业实体信息查询
const
cnEntityOnChainData
=
ref
({
}
);
const
getCnEntityOnChainData
=
async
()
=>
{
...
...
@@ -173,16 +194,6 @@ const getRightItems = items => {
const
midpoint
=
Math
.
ceil
(
items
.
length
/
2
);
return
items
.
slice
(
midpoint
);
}
;
// 获取上方鱼骨图位置类名
const
getTopBoneClass
=
index
=>
{
const
positions
=
[
"top-bone"
,
"top-bone1"
,
"top-bone2"
];
return
positions
[
index
%
3
]
||
"top-bone"
;
}
;
// 获取下方鱼骨图位置类名
const
getBottomBoneClass
=
index
=>
{
const
positions
=
[
"bottom-bone"
,
"bottom-bone1"
,
"bottom-bone2"
];
return
positions
[
index
%
3
]
||
"bottom-bone"
;
}
;
const
getFishboneData
=
async
()
=>
{
const
currentSanction
=
sanctionList
.
value
.
find
(
item
=>
item
.
id
===
currentSanctionId
.
value
);
const
date
=
currentSanction
?
currentSanction
.
date
:
''
;
...
...
@@ -305,126 +316,35 @@ onMounted(() => {
.
view
-
box
{
width
:
100
%
;
height
:
100
%
;
}
.
right
-
main
{
height
:
100
%
;
padding
:
11
px
16
px
20
px
;
.
right
-
main
-
content
{
height
:
100
%
;
display
:
flex
;
flex
-
direction
:
column
;
.
hintWrap
{
display
:
flex
;
align
-
items
:
center
;
padding
:
7
px
12
px
;
border
:
1
px
solid
rgba
(
231
,
243
,
255
,
1
);
border
-
radius
:
4
px
;
background
:
rgba
(
246
,
250
,
255
,
1
);
margin
-
bottom
:
9
px
;
.
icon1
{
width
:
19
px
;
.
main
-
content
-
main
{
position
:
relative
;
height
:
20
px
;
background
-
image
:
url
(
"../assets/icons/ai.png"
);
background
-
size
:
100
%
100
%
;
flex
-
shrink
:
0
;
}
.
title
{
color
:
rgb
(
5
,
95
,
194
);
font
-
size
:
16
px
;
font
-
weight
:
400
;
line
-
height
:
24
px
;
margin
-
left
:
13
px
;
flex
:
1
;
}
.
icon2Wrap
{
width
:
24
px
;
height
:
24
px
;
background
-
color
:
rgba
(
231
,
243
,
255
,
1
);
flex
:
auto
;
display
:
flex
;
justify
-
content
:
center
;
align
-
items
:
center
;
border
-
radius
:
12
px
;
margin
-
left
:
20
px
;
flex
-
shrink
:
0
;
.
icon2
{
width
:
24
px
;
height
:
24
px
;
background
-
image
:
url
(
"../assets/icons/right.png"
);
background
-
size
:
100
%
100
%
;
}
}
}
.
right
-
main
-
content
-
main
{
flex
:
1
;
position
:
relative
;
justify
-
content
:
center
;
overflow
:
hidden
;
.
fishbone
-
wrapper
{
position
:
relative
;
width
:
100
%
;
height
:
100
%
;
}
.
fishbone
-
scroll
-
container
{
display
:
flex
;
align
-
items
:
center
;
.
main
-
mask
{
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
100
%
;
height
:
100
%
;
overflow
-
x
:
auto
;
overflow
-
y
:
auto
;
scrollbar
-
width
:
thin
;
scrollbar
-
color
:
rgba
(
144
,
202
,
249
,
0.5
)
transparent
;
&
::
-
webkit
-
scrollbar
{
height
:
6
px
;
z
-
index
:
3
;
}
&
::
-
webkit
-
scrollbar
-
track
{
background
:
transparent
;
}
&
::
-
webkit
-
scrollbar
-
thumb
{
background
-
color
:
rgba
(
144
,
202
,
249
,
0.5
);
border
-
radius
:
3
px
;
}
}
.
fishbone
{
.
fishbone
-
container
{
position
:
relative
;
width
:
fit
-
content
;
height
:
100
%
;
margin
-
top
:
40
px
;
min
-
width
:
100
%
;
padding
-
left
:
275
px
;
margin
-
left
:
40
px
;
.
main
-
line
{
margin
-
top
:
280
px
;
width
:
1888
px
;
height
:
3
px
;
background
:
rgb
(
230
,
231
,
232
);
display
:
flex
;
justify
-
content
:
space
-
between
;
align
-
items
:
center
;
padding
:
0
100
px
;
// 虚线
&
::
after
{
content
:
''
;
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
100
%
;
height
:
100
%
;
}
// 添加中间的文字块
.
main
-
line
-
text
{
...
...
@@ -472,28 +392,28 @@ onMounted(() => {
.
top
-
bone
{
position
:
absolute
;
top
:
20
px
;
right
:
200
px
;
bottom
:
0
px
;
width
:
3
px
;
height
:
260
px
;
background
:
rgb
(
230
,
231
,
232
);
transform
-
origin
:
bottom
center
;
transform
:
skew
(
30
deg
);
z
-
index
:
1
;
.
left
-
bone
{
color
:
#
777
;
position
:
absolute
;
top
:
0
;
left
:
-
150
px
;
width
:
150
px
;
height
:
50
px
;
top
:
-
20
px
;
right
:
0
;
width
:
180
px
;
height
:
100
%
;
display
:
flex
;
flex
-
direction
:
column
;
justify
-
content
:
flex
-
end
;
// overflow: hidden;
.
left
-
bone
-
item
{
transform
:
skew
(
-
30
deg
);
height
:
45
px
;
margin
-
bottom
:
2
px
;
margin
-
top
:
2
px
;
height
:
40
px
;
margin
:
4
px
0
;
display
:
flex
;
justify
-
content
:
flex
-
end
;
align
-
items
:
center
;
...
...
@@ -519,17 +439,18 @@ onMounted(() => {
.
right
-
bone
{
color
:
#
777
;
position
:
absolute
;
top
:
0
;
right
:
-
150
px
;
width
:
150
px
;
height
:
210
px
;
overflow
:
hidden
;
top
:
-
44
px
;
left
:
0
;
width
:
180
px
;
height
:
100
%
;
display
:
flex
;
flex
-
direction
:
column
;
justify
-
content
:
flex
-
end
;
.
right
-
bone
-
item
{
transform
:
skew
(
-
30
deg
);
height
:
39
px
;
margin
-
bottom
:
2
px
;
margin
-
top
:
2
px
;
height
:
40
px
;
margin
:
4
px
0
;
display
:
flex
;
justify
-
content
:
flex
-
start
;
align
-
items
:
center
;
...
...
@@ -554,39 +475,30 @@ onMounted(() => {
}
}
.
top
-
bone1
{
@
extend
.
top
-
bone
;
right
:
500
px
;
}
.
top
-
bone2
{
@
extend
.
top
-
bone
;
right
:
800
px
;
}
.
bottom
-
bone
{
position
:
absolute
;
top
:
280
px
;
right
:
360
px
;
top
:
0
px
;
width
:
3
px
;
height
:
260
px
;
background
:
rgb
(
230
,
231
,
232
);
transform
-
origin
:
top
center
;
transform
:
skew
(
-
30
deg
);
z
-
index
:
1
;
.
left
-
bone
{
color
:
#
777
;
position
:
absolute
;
top
:
50
px
;
left
:
-
150
px
;
width
:
150
px
;
height
:
260
px
;
bottom
:
-
44
px
;
right
:
0
;
width
:
180
px
;
height
:
100
%
;
display
:
flex
;
flex
-
direction
:
column
;
justify
-
content
:
flex
-
start
;
.
left
-
bone
-
item
{
transform
:
skew
(
30
deg
);
height
:
39
px
;
margin
-
bottom
:
2
px
;
margin
-
top
:
2
px
;
height
:
40
px
;
margin
:
4
px
0
;
display
:
flex
;
justify
-
content
:
flex
-
end
;
align
-
items
:
center
;
...
...
@@ -613,16 +525,18 @@ onMounted(() => {
.
right
-
bone
{
color
:
#
777
;
position
:
absolute
;
top
:
50
px
;
right
:
-
150
px
;
width
:
150
px
;
height
:
260
px
;
bottom
:
-
20
px
;
left
:
0
;
width
:
180
px
;
height
:
100
%
;
display
:
flex
;
flex
-
direction
:
column
;
justify
-
content
:
flex
-
start
;
.
right
-
bone
-
item
{
transform
:
skew
(
30
deg
);
height
:
35
px
;
margin
-
bottom
:
2
px
;
margin
-
top
:
2
px
;
height
:
40
px
;
margin
:
4
px
0
;
display
:
flex
;
justify
-
content
:
flex
-
start
;
align
-
items
:
center
;
...
...
@@ -646,19 +560,9 @@ onMounted(() => {
}
}
}
.
bottom
-
bone1
{
@
extend
.
bottom
-
bone
;
right
:
660
px
;
}
.
bottom
-
bone2
{
@
extend
.
bottom
-
bone
;
right
:
960
px
;
}
}
.
right
-
main
-
content
-
footer
{
.
main
-
content
-
footer
{
margin
-
top
:
16
px
;
display
:
flex
;
justify
-
content
:
space
-
between
;
...
...
@@ -725,6 +629,5 @@ onMounted(() => {
}
}
}
}
}
<
/style>
\ No newline at end of file
src/views/decree/decreeLayout/influence/index.vue
浏览文件 @
26ccefc7
...
...
@@ -16,7 +16,7 @@
</div>
<div
class=
"data-title"
>
实体名称
</div>
<div
style=
"height: 20px; flex: auto;"
>
<el-empty
v-if=
"
showCompanyList.length === 0"
style=
"padding-top: 30%
"
description=
"暂无数据"
:image-size=
"100"
/>
<el-empty
v-if=
"
!showCompanyList?.length"
style=
"padding-top: 35%;
"
description=
"暂无数据"
:image-size=
"100"
/>
<el-scrollbar
height=
"100%"
always
>
<div
class=
"list-data"
>
<div
class=
"list-item"
v-for=
"item in showCompanyList"
:key=
"item.id"
:class=
"
{ 'item-active': activeEntityId === item.id }" @click="handleToCompanyDetail(item)">
...
...
@@ -75,19 +75,15 @@
<
/div
>
<
/div
>
<
/template
>
<
div
class
=
"box2-main"
v
-
if
=
"contentType==1"
>
<
div
class
=
"box2-main"
>
<
AiTips
:
tips
=
"tips"
/>
<
div
class
=
"graph-box"
v
-
if
=
"contentType==1"
>
<
ChartChain
/>
<
/div
>
<
div
class
=
"box2-main"
v
-
if
=
"contentType==2"
>
<!--
<
ChartRelation
:
graph
-
data
=
"graphData"
:
tree
-
data
=
"treeData"
:
control
-
active
=
"1"
@
node
-
click
=
"handleNodeClick"
@
layout
-
change
=
"handleLayoutChange"
/>
-->
<
div
class
=
"graph-box"
v
-
if
=
"contentType==2"
>
<
GraphChart
:
nodes
=
"testData.nodes"
:
links
=
"testData.links"
layoutType
=
"force"
/>
<
/div
>
<
/div
>
<
/AnalysisBox
>
<
/div
>
<
/div
>
...
...
@@ -101,9 +97,9 @@ import getBarChart from "./utils/barChart";
import
{
getDecreeIndustry
,
getDecreehylyList
,
getDecreeCompany
}
from
"@/api/decree/influence"
;
import
{
getCnEntityOnChain
,
getChainInfoByDomainId
}
from
"@/api/exportControl"
;
import
{
getSingleSanctionEntitySupplyChain
}
from
"@/api/exportControlV2.0"
;
import
ChartChain
from
"./ChartChain.vue"
;
import
ChartChain
from
"./com/ChartChain.vue"
;
import
AiTips
from
"./com/AiTips.vue"
;
import
GraphChart
from
"@/components/base/GraphChart/index.vue"
;
import
ChartRelation
from
"./ChartRelation.vue"
;
import
defaultIcon2
from
"@/assets/icons/default-icon2.png"
;
import
noticeIcon
from
"./assets/images/notice-icon.png"
;
import
icon422
from
"./assets/images/icon422.png"
;
...
...
@@ -113,191 +109,65 @@ import icon1621 from "./assets/images/icon1621.png";
import
company
from
"./assets/images/company.png"
;
import
companyActive
from
"./assets/images/company-active.png"
;
const
tips
=
"这项政令标志着中美AI竞争进入一个新阶段,其核心特征是 “精准封锁”与“体系输出”相结合。它短期内无疑会给中国AI产业链带来压力,但长期看,这场竞争更可能是一场围绕技术路线、生态系统和治理规则的持久战。"
// 关系图数据
const
testData
=
{
// 节点数据
nodes
:
[
{
id
:
0
,
name
:
"泰丰先行"
,
symbolSize
:
60
,
symbol
:
`image://${company
}
`
,
x
:
0
,
y
:
0
}
,
{
id
:
1
,
name
:
"国轩高科"
,
symbolSize
:
40
,
symbol
:
`image://${company
}
`
}
,
{
id
:
2
,
name
:
"智方纳米"
,
symbolSize
:
40
,
symbol
:
`image://${company
}
`
}
,
{
id
:
3
,
name
:
"香百科技"
,
symbolSize
:
40
,
symbol
:
`image://${company
}
`
}
,
{
id
:
4
,
name
:
"格林滨"
,
symbolSize
:
40
,
symbol
:
`image://${company
}
`
}
,
{
id
:
5
,
name
:
"江西紫宸"
,
symbolSize
:
40
,
symbol
:
`image://${company
}
`
}
,
{
id
:
6
,
name
:
"紫江企业"
,
symbolSize
:
40
,
symbol
:
`image://${company
}
`
}
,
{
id
:
7
,
name
:
"大而美法案"
,
symbolSize
:
40
,
symbol
:
`image://${company
}
`
}
,
{
id
:
8
,
name
:
"比亚迪"
,
symbolSize
:
40
,
symbol
:
`image://${company
}
`
}
,
],
// 关系数据
links
:
[
{
id
:
0
,
name
:
"泰丰先行"
,
// category: 0,
symbolSize
:
30
,
value
:
8
,
symbol
:
`image://${company
}
`
,
x
:
50
,
y
:
10
}
,
{
id
:
1
,
name
:
"国轩高科"
,
// category: 0,
symbolSize
:
30
,
value
:
9
,
symbol
:
`image://${company
}
`
,
x
:
150
,
y
:
10
}
,
{
id
:
2
,
name
:
"智方纳米"
,
// category: 2,
symbolSize
:
30
,
value
:
7
,
symbol
:
`image://${company
}
`
,
x
:
250
,
y
:
10
}
,
{
id
:
3
,
name
:
"香百科技"
,
// category: 1,
symbolSize
:
30
,
value
:
6
,
symbol
:
`image://${company
}
`
,
x
:
350
,
y
:
10
}
,
{
id
:
4
,
name
:
"格林滨"
,
// category: 2,
symbolSize
:
30
,
value
:
6
,
symbol
:
`image://${company
}
`
,
x
:
450
,
y
:
10
}
,
{
id
:
5
,
name
:
"江西紫宸"
,
// category: 2,
symbolSize
:
30
,
value
:
7
,
symbol
:
`image://${company
}
`
,
x
:
550
,
y
:
10
}
,
{
id
:
6
,
name
:
"紫江企业"
,
// category: 4,
symbolSize
:
30
,
value
:
6
,
symbol
:
`image://${company
}
`
,
x
:
650
,
y
:
10
}
,
{
id
:
7
,
name
:
"大而美法案"
,
// category: 4,
symbolSize
:
50
,
value
:
5
,
symbol
:
`image://${company
}
`
,
x
:
300
,
y
:
200
}
,
{
id
:
8
,
name
:
"比亚迪"
,
// category: 0,
symbolSize
:
30
,
value
:
10
,
symbol
:
`image://${company
}
`
,
x
:
50
,
y
:
400
source
:
1
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'持股'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
id
:
9
,
name
:
"铜陵有色"
,
// category: 3,
symbolSize
:
30
,
value
:
8
,
symbol
:
`image://${company
}
`
,
x
:
150
,
y
:
400
source
:
2
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'持股'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
id
:
10
,
name
:
"长盛精密"
,
// category: 1,
symbolSize
:
30
,
value
:
7
,
symbol
:
`image://${company
}
`
,
x
:
250
,
y
:
400
source
:
3
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'合作'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
id
:
11
,
name
:
"天合光能"
,
// category: 0,
symbolSize
:
30
,
value
:
8
,
symbol
:
`image://${company
}
`
,
x
:
350
,
y
:
400
source
:
4
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'从属'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
id
:
12
,
name
:
"昆仑化学"
,
// category: 2,
symbolSize
:
30
,
value
:
6
,
symbol
:
`image://${company
}
`
,
x
:
250
,
y
:
400
source
:
5
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'合作'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
id
:
13
,
name
:
"嘉源科技"
,
// category: 1,
symbolSize
:
30
,
value
:
6
,
symbol
:
`image://${company
}
`
,
x
:
450
,
y
:
400
source
:
6
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'持股'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
id
:
14
,
name
:
"华阳集团"
,
// category: 4,
symbolSize
:
30
,
value
:
7
,
symbol
:
`image://${company
}
`
,
x
:
550
,
y
:
400
source
:
7
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'合作'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
id
:
15
,
name
:
"海辰智能"
,
// category: 1,
symbolSize
:
30
,
value
:
7
,
symbol
:
`image://${company
}
`
,
x
:
650
,
y
:
400
source
:
8
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'合作'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
],
// 关系数据
links
:
[
{
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'
}
}
,
],
}
;
// 受影响实体
...
...
@@ -374,7 +244,7 @@ const handleGetHylyList = async () => {
}
;
// 产业链/实体关系
const
contentType
=
ref
(
2
);
const
contentType
=
ref
(
1
);
const
headerContentType
=
(
type
)
=>
{
contentType
.
value
=
type
;
}
;
...
...
@@ -693,7 +563,7 @@ onMounted(() => {
align
-
items
:
flex
-
end
;
width
:
100
%
;
height
:
100
%
;
padding
:
0
16
px
;
padding
:
0
20
px
;
.
title
-
left
{
display
:
flex
;
border
:
1
px
solid
rgb
(
5
,
95
,
194
);
...
...
@@ -734,6 +604,14 @@ onMounted(() => {
.
box2
-
main
{
width
:
100
%
;
height
:
100
%
;
display
:
flex
;
flex
-
direction
:
column
;
padding
:
16
px
20
px
;
.
graph
-
box
{
height
:
20
px
;
flex
:
auto
;
margin
-
top
:
16
px
;
}
}
}
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论