Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
7bc0a1ee
提交
7bc0a1ee
authored
3月 18, 2026
作者:
张烨
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix:政令模块细节优化
上级
3042de15
隐藏空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
184 行增加
和
1185 行删除
+184
-1185
index.vue
src/components/base/GraphChart/index.vue
+10
-3
index.vue
src/views/decree/decreeHome/index.vue
+51
-60
index.vue
src/views/decree/decreeLayout/deepdig/index.vue
+58
-146
ChartChain.vue
src/views/decree/decreeLayout/influence/com/ChartChain.vue
+1
-1
fishbone.vue
src/views/decree/decreeLayout/influence/fishbone.vue
+0
-736
index.vue
src/views/decree/decreeLayout/influence/index.vue
+64
-239
没有找到文件。
src/components/base/GraphChart/index.vue
浏览文件 @
7bc0a1ee
...
...
@@ -5,10 +5,11 @@
</
template
>
<
script
setup
>
import
{
onMounted
,
nextTick
}
from
'vue'
;
import
{
onMounted
,
onBeforeUnmount
}
from
'vue'
;
import
setChart
from
'@/utils/setChart'
;
import
getGraphChart
from
'./graphChart'
;
const
emits
=
defineEmits
([
"handleClickNode"
])
const
props
=
defineProps
({
nodes
:
{
type
:
Array
,
...
...
@@ -27,16 +28,22 @@ const props = defineProps({
default
:
'force'
},
height
:
{
type
:
String
,
type
:
String
,
default
:
'force'
}
})
let
chart
=
null
onMounted
(()
=>
{
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
)
setChart
(
graph
,
'graph'
)
chart
=
setChart
(
graph
,
'graph'
)
chart
.
on
(
"click"
,
(
event
)
=>
{
emits
(
"handleClickNode"
,
event
)
})
})
onBeforeUnmount
(()
=>
{
chart
.
off
(
"click"
)
chart
.
dispose
()
})
</
script
>
...
...
src/views/decree/decreeHome/index.vue
浏览文件 @
7bc0a1ee
...
...
@@ -6,14 +6,6 @@
<div
class=
"home-main-header-center"
>
<SearchContainer
style=
"margin-bottom: 0; margin-top: 48px; height: fit-content"
v-if=
"containerRef"
placeholder=
"搜索政令"
:containerRef=
"containerRef"
areaName=
"政令"
/>
<!--
<el-input
v-model=
"searchDecreeText"
@
keyup
.
enter=
"handleSearch"
style=
"width: 838px; height: 100%"
placeholder=
"搜索政令"
/>
<div
class=
"search"
>
<div
class=
"search-icon"
>
<img
src=
"./assets/images/search-icon.png"
alt=
""
/>
</div>
<div
class=
"search-text"
@
click=
"handleSearch"
>
搜索
</div>
</div>
-->
</div>
<!--
<div
class=
"home-main-header-footer"
v-show=
"!isShow"
>
<div
class=
"home-main-header-footer-item"
>
...
...
@@ -37,32 +29,13 @@
<div
class=
"item-footer"
>
分析报告
</div>
</div>
</div>
-->
<!--
<div
class=
"home-main-header-btn-box"
v-show=
"!isShow"
>
<div
class=
"btn"
@
click=
"handleToPosi('position1')"
>
<div
class=
"btn-text"
>
{{
"最新动态"
}}
</div>
<div
class=
"btn-icon"
>
<img
src=
"@/assets/icons/arrow-right-icon.png"
alt=
""
/>
</div>
</div>
<div
class=
"btn"
@
click=
"handleToPosi('position2')"
>
<div
class=
"btn-text"
>
{{
"资讯要闻"
}}
</div>
<div
class=
"btn-icon"
>
<img
src=
"@/assets/icons/arrow-right-icon.png"
alt=
""
/>
</div>
</div>
<div
class=
"btn"
@
click=
"handleToPosi('position3')"
>
<div
class=
"btn-text"
>
{{
"数据总览"
}}
</div>
<div
class=
"btn-icon"
>
<img
src=
"@/assets/icons/arrow-right-icon.png"
alt=
""
/>
</div>
<div
class=
"date-box"
v-if=
"govInsList.length"
>
<div
class=
"date-icon"
>
<img
:src=
"tipsTcon"
alt=
""
>
</div>
<div
class=
"btn"
@
click=
"handleToPosi('position4')"
>
<div
class=
"btn-text"
>
{{
"资源库"
}}
</div>
<div
class=
"btn-icon"
>
<img
src=
"@/assets/icons/arrow-right-icon.png"
alt=
""
/>
</div>
</div>
</div>
-->
<div
class=
"date-text"
>
近期美国各联邦政府机构发布涉华政令数量汇总
</div>
<TimeTabPane
@
time-click=
"handleTimeClick"
/>
</div>
<div
class=
"home-main-header-item-box"
v-if=
"govInsList.length"
>
<div
class=
"item"
v-for=
"(item, index) in govInsList.slice(0, 7)"
:key=
"index"
@
click=
"handleToInstitution(item)"
>
<div
class=
"item-left"
>
...
...
@@ -396,6 +369,7 @@ import { onMounted, ref, watch, nextTick, reactive } from "vue";
import
router
from
"@/router"
;
import
WordCloudChart
from
"@/components/base/WordCloundChart/index.vue"
import
SimplePagination
from
"@/components/SimplePagination.vue"
;
import
TimeTabPane
from
'@/components/base/TimeTabPane/index.vue'
import
{
getDepartmentList
,
getLatestDecree
,
...
...
@@ -418,21 +392,9 @@ import getPieChart from "./utils/piechart";
import
setChart
from
"@/utils/setChart"
;
import
DefaultIcon2
from
"@/assets/icons/default-icon2.png"
;
import
tipsTcon
from
"./assets/images/tips-icon.png"
;
import
{
ElMessage
}
from
"element-plus"
;
// 跳转行政机构主页
const
handleToInstitution
=
item
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
orgName
);
const
curRoute
=
router
.
resolve
({
path
:
"/institution"
,
query
:
{
id
:
item
.
orgId
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
const
containerRef
=
ref
(
null
);
const
{
isShow
}
=
useContainerScroll
(
containerRef
);
const
currentPage
=
ref
(
1
);
...
...
@@ -444,10 +406,9 @@ const handleCurrentChange = page => {
handleGetDecreeOrderList
();
};
//
页面 header
//
机构列表
const
govInsList
=
ref
([]);
const
checkedGovIns
=
ref
([]);
const
handleGetDepartmentList
=
async
()
=>
{
try
{
const
res
=
await
getDepartmentList
();
...
...
@@ -459,7 +420,20 @@ const handleGetDepartmentList = async () => {
console
.
error
(
"获取机构列表error"
,
error
);
}
};
handleGetDepartmentList
();
const
handleTimeClick
=
(
time
)
=>
{
console
.
log
(
"time"
,
time
);
}
// 跳转行政机构主页
const
handleToInstitution
=
item
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
item
.
orgName
);
const
curRoute
=
router
.
resolve
({
path
:
"/institution"
,
query
:
{
id
:
item
.
orgId
}
});
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
// 查看更多风险信号
const
handleToMoreRiskSignal
=
()
=>
{
...
...
@@ -486,16 +460,6 @@ const box1DataList = ref([
}
]);
// const curBox1Data = ref({
// id: 89,
// name: "",
// postDate: "",
// describe: null,
// imageUrl: null,
// officialUrl: null,
// industryList: null
// });
const
handleGetLatestDecree
=
async
()
=>
{
try
{
const
res
=
await
getLatestDecree
();
...
...
@@ -1131,6 +1095,7 @@ const handleSearch = () => {
};
onMounted
(
async
()
=>
{
handleGetDepartmentList
();
handleGetNews
();
handleGetDecreeTypeList
();
handleGetAreaList
();
...
...
@@ -1389,8 +1354,34 @@ onMounted(async () => {
}
}
.date-box
{
display
:
flex
;
align-items
:
center
;
width
:
1600px
;
margin-top
:
48px
;
.date-icon
{
width
:
16px
;
height
:
16px
;
font-size
:
0px
;
margin-right
:
6px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.date-text
{
width
:
20px
;
flex
:
auto
;
font-size
:
18px
;
line-height
:
18px
;
font-family
:
Source
Han
Sans
CN
;
color
:
var
(
--
text-primary-80-color
);
}
}
.home-main-header-item-box
{
margin
:
48
px
0
64px
;
margin
:
20
px
0
64px
;
width
:
1600px
;
display
:
flex
;
flex-wrap
:
wrap
;
...
...
src/views/decree/decreeLayout/deepdig/index.vue
浏览文件 @
7bc0a1ee
...
...
@@ -3,7 +3,7 @@
<div
class=
"box1"
>
<AnalysisBox
title=
"相关政令"
:showAllBtn=
"false"
>
<div
class=
"box1-main"
>
<el-empty
v-if=
"!siderList?.length"
style=
"padding
-top: 40%
;"
description=
"暂无数据"
:image-size=
"100"
/>
<el-empty
v-if=
"!siderList?.length"
style=
"padding
: 60px 0
;"
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,9 +18,9 @@
</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
>
<el-empty
v-if=
"!siderList?.length"
style=
"padding
: 60px 0
;"
description=
"暂无数据"
:image-size=
"100"
/>
<div
class=
"box2-main"
v-if=
"graphData.nodes?.length"
>
<
GraphChart
:nodes=
"graphData.nodes"
:links=
"graphData.links"
layoutType=
"force"
@
handleClickNode=
"handleClickNode"
/
>
</div>
</AnalysisBox>
</div>
...
...
@@ -48,12 +48,13 @@
</template>
<
script
setup
>
import
{
ref
,
onMounted
,
onBeforeUnmount
}
from
"vue"
;
import
{
ref
,
onMounted
,
onBeforeUnmount
,
reactive
}
from
"vue"
;
import
{
useRoute
}
from
"vue-router"
;
import
router
from
"@/router"
;
import
*
as
G6
from
'@antv/g6'
;
import
{
getDecreeRelatedOrder
}
from
"@/api/decree/deepdig"
;
import
{
getDecreeSummary
}
from
"@/api/decree/introduction"
;
import
GraphChart
from
"@/components/base/GraphChart/index.vue"
;
import
icon1628
from
"./assets/icons/icon1628.png"
;
import
icon1629
from
"./assets/icons/icon1629.png"
;
...
...
@@ -64,7 +65,7 @@ const route = useRoute();
const
dialogVisible
=
ref
(
false
);
// 基本信息
const
mainInfo
=
ref
({});
const
mainInfo
=
ref
({
label
:
""
,
time
:
""
,
id
:
""
});
const
nodeInfo
=
ref
({});
const
onDecreeSummaryData
=
async
()
=>
{
try
{
...
...
@@ -74,10 +75,9 @@ const onDecreeSummaryData = async () => {
mainInfo
.
value
.
label
=
res
.
data
.
name
;
mainInfo
.
value
.
time
=
res
.
data
.
postDate
;
mainInfo
.
value
.
id
=
route
.
query
.
id
;
mainInfo
.
value
.
isCenter
=
true
}
}
catch
(
error
)
{
mainInfo
.
value
=
{};
mainInfo
.
value
=
{
label
:
""
,
time
:
""
,
id
:
""
};
console
.
log
(
"获取基本信息数据失败:"
,
error
);
}
};
...
...
@@ -109,8 +109,53 @@ const handleGetRelateOrder = async () => {
};
// 政令关系挖掘
const
containerRef
=
ref
();
let
graphInstance
=
null
;
const
graphData
=
reactive
({
nodes
:
[],
links
:
[],
})
// 节点点击处理
const
handleClickNode
=
({
data
})
=>
{
if
(
data
.
target
)
{
let
node
=
siderList
.
value
.
find
(
item
=>
item
.
id
==
data
.
target
)
if
(
node
)
handleClickSider
(
node
)
}
else
{
let
node
=
siderList
.
value
.
find
(
item
=>
item
.
id
==
data
.
id
)
if
(
node
)
handleClickDecree
(
node
)
}
}
const
initGraphChart
=
()
=>
{
Promise
.
all
([
onDecreeSummaryData
(),
handleGetRelateOrder
()]).
then
(()
=>
{
if
(
mainInfo
.
value
.
id
&&
siderList
.
value
.
length
)
{
graphData
.
links
=
siderList
.
value
.
map
(
onFormatLink
)
graphData
.
nodes
=
siderList
.
value
.
map
(
onFormatNode
)
graphData
.
nodes
.
unshift
(
onFormatNode
(
mainInfo
.
value
))
}
})
}
const
onFormatLink
=
(
item
,
index
)
=>
{
return
{
id
:
`link-
${
index
+
1
}
`
,
source
:
route
.
query
.
id
,
target
:
item
.
id
+
''
,
label
:
{
show
:
true
,
color
:
"#055fc2"
,
backgroundColor
:
"#eef7ff"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
item
.
relation
},
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
,
opacity
:
1
}
}
}
const
onFormatNode
=
(
item
)
=>
{
let
leader
=
item
.
id
==
mainInfo
.
value
.
id
;
return
{
id
:
item
.
id
+
''
,
name
:
onWordWrap
(
item
.
label
,
8
),
label
:
{
show
:
true
,
color
:
leader
?
"#055fc2"
:
"#3b414b"
,
fontSize
:
leader
?
16
:
14
,
fontWeight
:
leader
?
700
:
400
,
fontFamily
:
'Source Han Sans CN'
,
},
symbolSize
:
leader
?
60
:
40
,
symbol
:
`image://
${
leader
?
icon1628
:
icon1629
}
`
}
}
// 文本插入换行符
const
onWordWrap
=
(
word
,
num
)
=>
{
const
list
=
word
.
split
(
''
);
...
...
@@ -123,132 +168,6 @@ const onWordWrap = (word, num) => {
}
return
label
;
}
const
onFormatNode
=
(
item
)
=>
{
let
isCenter
=
item
.
isCenter
||
false
return
{
id
:
item
.
id
+
''
,
label
:
onWordWrap
(
item
.
label
,
15
),
isCenter
,
img
:
isCenter
?
icon1628
:
icon1629
,
clipCfg
:
{
r
:
isCenter
?
40
:
30
},
labelCfg
:
{
style
:
{
fill
:
isCenter
?
"#1459BB"
:
"#333333"
,
fontSize
:
isCenter
?
13
:
13
,
fontWeight
:
isCenter
?
"bold"
:
"normal"
}
}
}
}
const
onFormatEdge
=
(
item
,
index
)
=>
{
return
{
id
:
`edge-
${
index
+
1
}
`
,
target
:
item
.
id
+
''
,
source
:
route
.
query
.
id
,
// label: ["", "相似", "继承", "冲突"][1],
label
:
item
.
relation
,
style
:
{
stroke
:
[
""
,
"#B9DCFF"
,
"#87E8DE"
,
"#FFCCC7"
][
1
],
},
labelCfg
:
{
style
:
{
fill
:
[
""
,
"#055FC2"
,
"#13A8A8"
,
"#CE4F51"
][
1
],
background
:
{
fill
:
[
""
,
"#E7F3FF"
,
"#E6FFFB"
,
"#FFE0E0"
][
1
],
}
}
}
}
}
const
initChart
=
()
=>
{
let
edgeList
=
siderList
.
value
.
map
(
onFormatEdge
)
let
nodeList
=
siderList
.
value
.
map
(
onFormatNode
)
nodeList
.
unshift
(
onFormatNode
(
mainInfo
.
value
))
console
.
log
(
nodeList
)
const
width
=
containerRef
.
value
.
offsetWidth
||
800
const
height
=
containerRef
.
value
.
offsetHeight
||
600
const
centerX
=
width
/
2
const
centerY
=
height
/
2
const
radius
=
Math
.
min
(
width
,
height
)
/
2
-
120
const
otherNodes
=
nodeList
.
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
=
nodeList
.
find
(
n
=>
n
.
isCenter
)
if
(
centerNode
)
{
centerNode
.
x
=
centerX
centerNode
.
y
=
centerY
centerNode
.
fx
=
centerX
centerNode
.
fy
=
centerY
}
graphInstance
=
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'
]
},
defaultNode
:
{
type
:
'image'
,
size
:
50
,
style
:
{
cursor
:
"pointer"
},
clipCfg
:
{
show
:
true
,
type
:
'circle'
},
labelCfg
:
{
position
:
"bottom"
,
offset
:
12
,
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
:
"line"
,
style
:
{
lineWidth
:
1
,
endArrow
:
true
},
labelCfg
:
{
autoRotate
:
true
,
style
:
{
cursor
:
"pointer"
,
fontSize
:
12
,
fontFamily
:
'Microsoft YaHei'
,
background
:
{
padding
:
[
4
,
4
,
4
,
4
]
}
}
}
}
})
// 节点点击处理
graphInstance
.
on
(
'node:click'
,
(
evt
)
=>
{
let
node
=
siderList
.
value
.
find
(
item
=>
item
.
id
==
evt
.
item
.
_cfg
.
model
.
id
)
if
(
node
)
handleClickDecree
(
node
)
});
graphInstance
.
on
(
'edge:click'
,
(
evt
)
=>
{
let
node
=
siderList
.
value
.
find
(
item
=>
item
.
id
==
evt
.
item
.
_cfg
.
model
.
target
)
if
(
node
)
handleClickSider
(
node
)
});
graphInstance
.
data
({
nodes
:
nodeList
,
edges
:
edgeList
})
graphInstance
.
render
()
}
const
handleClickDecree
=
decree
=>
{
window
.
sessionStorage
.
setItem
(
"curTabName"
,
decree
.
name
);
...
...
@@ -293,9 +212,9 @@ const onRelationChart = () => {
},
labelCfg
:
{
style
:
{
fill
:
[
""
,
"#055
FC
2"
,
"#13A8A8"
,
"#CE4F51"
][
1
],
fill
:
[
""
,
"#055
fc
2"
,
"#13A8A8"
,
"#CE4F51"
][
1
],
background
:
{
fill
:
[
""
,
"#
E7F3FF
"
,
"#E6FFFB"
,
"#FFE0E0"
][
1
],
fill
:
[
""
,
"#
eef7ff
"
,
"#E6FFFB"
,
"#FFE0E0"
][
1
],
}
}
}
...
...
@@ -363,13 +282,10 @@ const onRelationChart = () => {
}
onMounted
(()
=>
{
Promise
.
all
([
onDecreeSummaryData
(),
handleGetRelateOrder
()]).
then
(()
=>
{
if
(
mainInfo
.
value
.
id
&&
siderList
.
value
.
length
)
initChart
()
})
initGraphChart
()
});
onBeforeUnmount
(()
=>
{
graphInstance
?.
destroy
()
graph
?.
destroy
()
})
</
script
>
...
...
@@ -462,10 +378,6 @@ onBeforeUnmount(() => {
.box2-main
{
height
:
100%
;
padding
:
10px
;
.graph-container
{
width
:
100%
;
height
:
600px
;
}
}
}
}
...
...
src/views/decree/decreeLayout/influence/com/ChartChain.vue
浏览文件 @
7bc0a1ee
<
template
>
<div
class=
"view-box"
>
<el-empty
v-if=
"!dataList?.length"
style=
"padding
-top: 15%
;"
description=
"暂无数据"
:image-size=
"100"
/>
<el-empty
v-if=
"!dataList?.length"
style=
"padding
: 60px 0
;"
description=
"暂无数据"
:image-size=
"100"
/>
<div
v-if=
"dataList.length"
class=
"main-content-main"
>
<div
class=
"main-mask"
@
wheel
.
prevent=
"handleWheel"
...
...
src/views/decree/decreeLayout/influence/fishbone.vue
deleted
100644 → 0
浏览文件 @
3042de15
<
template
>
<div
class=
"fishbone-wrapper"
>
<div
class=
"fishbone-scroll-container"
ref=
"scrollContainerRef"
>
<div
class=
"fishbone"
ref=
"fishboneRef"
v-if=
"fishboneData.length > 0"
>
<div
class=
"main-line"
:style=
"
{ width: (fishboneData.length / 2) * 340 - 200 + 'px' }">
</div>
<!-- 奇数索引的数据组放在上方 -->
<div
v-for=
"(causeGroup, groupIndex) in getOddGroups(fishboneData)"
:key=
"'top-' + groupIndex"
:class=
"getTopBoneClass(groupIndex)"
:style=
"
{ left: groupIndex * 300 + 400 + 'px' }"
>
<div
class=
"left-bone"
>
<div
class=
"left-bone-item"
v-for=
"(item, index) in getLeftItems(causeGroup.causes)"
:key=
"'left-' + index"
>
<div
class=
"text"
>
{{
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=
"line"
></div>
<div
class=
"text"
>
{{
item
.
name
}}
</div>
</div>
</div>
</div>
<!-- 偶数索引的数据组放在下方 -->
<div
v-for=
"(causeGroup, groupIndex) in getEvenGroups(fishboneData)"
:key=
"'bottom-' + groupIndex"
:class=
"getBottomBoneClass(groupIndex)"
:style=
"
{ left: groupIndex * 300 + 200 + 'px' }"
>
<div
class=
"left-bone"
>
<div
class=
"left-bone-item"
v-for=
"(item, index) in getLeftItems(causeGroup.causes)"
:key=
"'left-bottom-' + index"
>
<div
class=
"text"
>
{{
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=
"line"
></div>
<div
class=
"text"
>
{{
item
.
name
}}
</div>
</div>
</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
class=
"scroll-indicators"
v-if=
"showScrollIndicator"
>
<div
class=
"scroll-btn left"
:class=
"
{ disabled: !canScrollLeft }" @click="scrollLeft">‹
</div>
<div
class=
"scroll-btn right"
:class=
"
{ disabled: !canScrollRight }" @click="scrollRight">›
</div>
</div>
-->
</div>
</
template
>
<
script
setup
>
import
{
getChainFishbone
}
from
"@/api/exportControl"
;
import
{
onMounted
,
ref
,
nextTick
,
watch
}
from
"vue"
;
// 这儿需要接收父组件传递来的产业链ID
const
props
=
defineProps
({
chainId
:
{
type
:
Number
,
default
:
1
}
});
// const chainId = ref(1);
const
fishboneData
=
ref
([]);
const
scrollContainerRef
=
ref
(
null
);
const
fishboneRef
=
ref
(
null
);
const
showScrollIndicator
=
ref
(
false
);
const
canScrollLeft
=
ref
(
false
);
const
canScrollRight
=
ref
(
true
);
// 获取奇数索引的数据组(放在上方)
const
getOddGroups
=
data
=>
{
console
.
log
(
"getOddGroups:"
,
data
.
filter
((
_
,
index
)
=>
index
%
2
===
1
)
);
return
data
.
filter
((
_
,
index
)
=>
index
%
2
===
1
);
};
// 获取偶数索引的数据组(放在下方)
const
getEvenGroups
=
data
=>
{
console
.
log
(
"getEvenGroups:"
,
data
.
filter
((
_
,
index
)
=>
index
%
2
===
0
)
);
return
data
.
filter
((
_
,
index
)
=>
index
%
2
===
0
);
};
// 获取上方鱼骨图位置类名
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
getLeftItems
=
items
=>
{
const
midpoint
=
Math
.
ceil
(
items
.
length
/
2
);
return
items
.
slice
(
0
,
midpoint
);
};
// 获取右侧显示的项目(后半部分)
const
getRightItems
=
items
=>
{
const
midpoint
=
Math
.
ceil
(
items
.
length
/
2
);
return
items
.
slice
(
midpoint
);
};
// 检查滚动状态
const
updateScrollState
=
()
=>
{
if
(
!
scrollContainerRef
.
value
)
return
;
const
container
=
scrollContainerRef
.
value
;
canScrollLeft
.
value
=
container
.
scrollLeft
>
0
;
canScrollRight
.
value
=
container
.
scrollLeft
<
container
.
scrollWidth
-
container
.
clientWidth
;
};
// 滚动处理
const
scrollLeft
=
()
=>
{
if
(
scrollContainerRef
.
value
)
{
scrollContainerRef
.
value
.
scrollBy
({
left
:
-
200
,
behavior
:
"smooth"
});
}
};
const
scrollRight
=
()
=>
{
if
(
scrollContainerRef
.
value
)
{
scrollContainerRef
.
value
.
scrollBy
({
left
:
200
,
behavior
:
"smooth"
});
}
};
// 处理滚动事件
const
handleScroll
=
()
=>
{
updateScrollState
();
};
onMounted
(
async
()
=>
{
// try {
// const chainFishboneData = await getChainFishbone(props.chainId);
// fishboneData.value = chainFishboneData?.causes ?? [];
// // 等待DOM更新后检查是否需要滚动
// nextTick(() => {
// if (scrollContainerRef.value && fishboneRef.value) {
// showScrollIndicator.value = fishboneRef.value.scrollWidth > scrollContainerRef.value.clientWidth;
// updateScrollState();
// }
// });
// console.log("鱼骨图数据:", fishboneData.value);
// } catch (error) {
// console.log(error);
// }
});
// 监听props中的chainId变化
watch
(
()
=>
props
.
chainId
,
async
()
=>
{
try
{
const
chainFishboneData
=
await
getChainFishbone
(
props
.
chainId
);
fishboneData
.
value
=
chainFishboneData
?.
causes
??
[];
}
catch
(
error
)
{
console
.
log
(
error
);
}
}
);
</
script
>
<
style
lang=
"scss"
scoped
>
.fishbone-wrapper
{
position
:
relative
;
width
:
100%
;
height
:
100%
;
}
.fishbone-scroll-container
{
display
:
flex
;
align-items
:
center
;
width
:
100%
;
height
:
100%
;
overflow-x
:
auto
;
overflow-y
:
hidden
;
scrollbar-width
:
thin
;
scrollbar-color
:
rgba
(
144
,
202
,
249
,
0
.5
)
transparent
;
&
:
:-
webkit-scrollbar
{
height
:
6px
;
}
&
:
:-
webkit-scrollbar-track
{
background
:
transparent
;
}
&
:
:-
webkit-scrollbar-thumb
{
background-color
:
rgba
(
144
,
202
,
249
,
0
.5
);
border-radius
:
3px
;
}
}
/* ... 原有的样式保持不变 ... */
.fishbone
{
position
:
relative
;
width
:
fit-content
;
height
:
100%
;
margin-top
:
40px
;
min-width
:
100%
;
padding-left
:
275px
;
.main-line
{
margin-top
:
280px
;
width
:
1888px
;
height
:
3px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
}
.top-bone
{
position
:
absolute
;
top
:
20px
;
right
:
200px
;
width
:
3px
;
height
:
260px
;
background
:
#90caf9
;
transform
:
skew
(
30deg
);
z-index
:
1
;
.left-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
left
:
-150px
;
width
:
150px
;
height
:
260px
;
.left-bone-item
{
transform
:
skew
(
-30deg
);
height
:
35px
;
margin-bottom
:
5px
;
margin-top
:
15px
;
display
:
flex
;
justify-content
:
flex-end
;
.text
{
margin-left
:
4px
;
height
:
70px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.line
{
margin-left
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
}
}
.right-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
right
:
-150px
;
width
:
150px
;
height
:
260px
;
.right-bone-item
{
transform
:
skew
(
-30deg
);
height
:
35px
;
margin-bottom
:
15px
;
margin-top
:
5px
;
display
:
flex
;
justify-content
:
flex-start
;
.line
{
margin-right
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
.text
{
width
:
100px
;
margin-right
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
.top-bone1
{
position
:
absolute
;
top
:
20px
;
right
:
500px
;
width
:
3px
;
height
:
260px
;
background
:
#90caf9
;
transform
:
skew
(
30deg
);
z-index
:
1
;
.left-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
left
:
-150px
;
width
:
150px
;
height
:
260px
;
.left-bone-item
{
transform
:
skew
(
-30deg
);
height
:
35px
;
margin-bottom
:
5px
;
margin-top
:
15px
;
display
:
flex
;
justify-content
:
flex-end
;
.text
{
width
:
100px
;
margin-left
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.line
{
margin-left
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
}
}
.right-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
right
:
-150px
;
width
:
150px
;
height
:
260px
;
.right-bone-item
{
transform
:
skew
(
-30deg
);
height
:
35px
;
margin-bottom
:
15px
;
margin-top
:
5px
;
display
:
flex
;
justify-content
:
flex-start
;
.line
{
margin-right
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
.text
{
width
:
100px
;
margin-right
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
.top-bone2
{
position
:
absolute
;
top
:
20px
;
right
:
800px
;
width
:
3px
;
height
:
260px
;
background
:
#90caf9
;
transform
:
skew
(
30deg
);
z-index
:
1
;
.left-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
left
:
-150px
;
width
:
150px
;
height
:
260px
;
.left-bone-item
{
transform
:
skew
(
-30deg
);
height
:
35px
;
margin-bottom
:
5px
;
margin-top
:
15px
;
display
:
flex
;
justify-content
:
flex-end
;
.text
{
width
:
100px
;
margin-left
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.line
{
margin-left
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
}
}
.right-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
right
:
-150px
;
width
:
150px
;
height
:
260px
;
.right-bone-item
{
transform
:
skew
(
-30deg
);
height
:
35px
;
margin-bottom
:
15px
;
margin-top
:
5px
;
display
:
flex
;
justify-content
:
flex-start
;
.line
{
margin-right
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
.text
{
width
:
100px
;
margin-right
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
.bottom-bone
{
position
:
absolute
;
top
:
280px
;
right
:
360px
;
width
:
3px
;
height
:
260px
;
background
:
#90caf9
;
transform
:
skew
(
-30deg
);
z-index
:
1
;
.left-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
left
:
-150px
;
width
:
150px
;
height
:
260px
;
.left-bone-item
{
transform
:
skew
(
30deg
);
height
:
35px
;
margin-bottom
:
5px
;
margin-top
:
15px
;
display
:
flex
;
justify-content
:
flex-end
;
.text
{
width
:
100px
;
margin-left
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.line
{
margin-left
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
}
}
.right-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
right
:
-150px
;
width
:
150px
;
height
:
260px
;
.right-bone-item
{
transform
:
skew
(
30deg
);
height
:
35px
;
margin-bottom
:
15px
;
margin-top
:
5px
;
display
:
flex
;
justify-content
:
flex-start
;
.line
{
margin-right
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
.text
{
width
:
100px
;
margin-right
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
.bottom-bone1
{
position
:
absolute
;
top
:
280px
;
right
:
660px
;
width
:
3px
;
height
:
260px
;
background
:
#90caf9
;
transform
:
skew
(
-30deg
);
z-index
:
1
;
.left-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
left
:
-150px
;
width
:
150px
;
height
:
260px
;
.left-bone-item
{
transform
:
skew
(
30deg
);
height
:
35px
;
margin-bottom
:
5px
;
margin-top
:
15px
;
display
:
flex
;
justify-content
:
flex-end
;
.text
{
width
:
100px
;
margin-left
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.line
{
margin-left
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
}
}
.right-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
right
:
-150px
;
width
:
150px
;
height
:
260px
;
.right-bone-item
{
transform
:
skew
(
30deg
);
height
:
35px
;
margin-bottom
:
15px
;
margin-top
:
5px
;
display
:
flex
;
justify-content
:
flex-start
;
.line
{
margin-right
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
.text
{
width
:
100px
;
margin-right
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
.bottom-bone2
{
position
:
absolute
;
top
:
280px
;
right
:
960px
;
width
:
3px
;
height
:
260px
;
background
:
#90caf9
;
transform
:
skew
(
-30deg
);
z-index
:
1
;
.left-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
left
:
-150px
;
width
:
150px
;
height
:
260px
;
.left-bone-item
{
transform
:
skew
(
30deg
);
height
:
35px
;
margin-bottom
:
5px
;
margin-top
:
15px
;
display
:
flex
;
justify-content
:
flex-end
;
.text
{
width
:
100px
;
margin-left
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.line
{
margin-left
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
}
}
.right-bone
{
color
:
#777
;
position
:
absolute
;
top
:
0
;
right
:
-150px
;
width
:
150px
;
height
:
260px
;
.right-bone-item
{
transform
:
skew
(
30deg
);
height
:
35px
;
margin-bottom
:
15px
;
margin-top
:
5px
;
display
:
flex
;
justify-content
:
flex-start
;
.line
{
margin-right
:
7px
;
margin-top
:
16px
;
width
:
30px
;
height
:
2px
;
background
:
rgba
(
174
,
208
,
255
,
1
);
}
.text
{
width
:
100px
;
margin-right
:
4px
;
height
:
35px
;
line-height
:
35px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
.scroll-indicators
{
position
:
absolute
;
top
:
50%
;
left
:
0
;
right
:
0
;
transform
:
translateY
(
-50%
);
display
:
flex
;
justify-content
:
space-between
;
pointer-events
:
none
;
padding
:
0
10px
;
z-index
:
10
;
}
.scroll-btn
{
width
:
30px
;
height
:
30px
;
border-radius
:
50%
;
background
:
rgba
(
255
,
255
,
255
,
0
.8
);
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
font-size
:
20px
;
font-weight
:
bold
;
color
:
#90caf9
;
cursor
:
pointer
;
pointer-events
:
auto
;
box-shadow
:
0
1px
4px
rgba
(
0
,
0
,
0
,
0
.2
);
transition
:
all
0
.2s
ease
;
&
:hover:not
(
.disabled
)
{
background
:
#90caf9
;
color
:
white
;
transform
:
scale
(
1
.1
);
}
&
.disabled
{
color
:
#c0c4cc
;
cursor
:
not
-
allowed
;
background
:
rgba
(
255
,
255
,
255
,
0
.5
);
}
}
</
style
>
src/views/decree/decreeLayout/influence/index.vue
浏览文件 @
7bc0a1ee
...
...
@@ -16,7 +16,7 @@
</div>
<div
class=
"data-title"
>
实体名称
</div>
<div
style=
"height: 20px; flex: auto;"
>
<el-empty
v-if=
"!showCompanyList?.length"
style=
"padding
-top: 35%
;"
description=
"暂无数据"
:image-size=
"100"
/>
<el-empty
v-if=
"!showCompanyList?.length"
style=
"padding
: 60px 0
;"
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)">
...
...
@@ -81,7 +81,7 @@
<
ChartChain
/>
<
/div
>
<
div
class
=
"graph-box"
v
-
if
=
"contentType==2"
>
<
GraphChart
:
nodes
=
"
testData.nodes"
:
links
=
"test
Data.links"
layoutType
=
"force"
/>
<
GraphChart
:
nodes
=
"
graphData.nodes"
:
links
=
"graph
Data.links"
layoutType
=
"force"
/>
<
/div
>
<
/div
>
<
/AnalysisBox
>
...
...
@@ -90,13 +90,9 @@
<
/template
>
<
script
setup
>
import
{
ref
,
onMounted
}
from
"vue"
;
import
setChart
from
"@/utils/setChart"
;
import
{
ref
,
onMounted
,
reactive
}
from
"vue"
;
import
{
Search
}
from
'@element-plus/icons-vue'
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
{
getDecreehylyList
,
getDecreeCompany
}
from
"@/api/decree/influence"
;
import
ChartChain
from
"./com/ChartChain.vue"
;
import
AiTips
from
"./com/AiTips.vue"
;
import
GraphChart
from
"@/components/base/GraphChart/index.vue"
;
...
...
@@ -107,68 +103,65 @@ import icon423 from "./assets/images/icon423.png";
import
icon1620
from
"./assets/images/icon1620.png"
;
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
:
[
{
source
:
1
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'持股'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
source
:
2
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'持股'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
source
:
3
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'合作'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
source
:
4
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'从属'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
source
:
5
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'合作'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
source
:
6
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'持股'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
source
:
7
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'合作'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
}
,
{
source
:
8
,
target
:
0
,
label
:
{
show
:
true
,
color
:
"#055FC2"
,
backgroundColor
:
"#E7F3FF"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
'合作'
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
}
const
graphData
=
reactive
({
leader
:
{
id
:
0
,
name
:
"泰丰先行"
}
,
list
:
[
{
id
:
1
,
name
:
"国轩高科"
,
formatter
:
'持股'
}
,
{
id
:
2
,
name
:
"智方纳米"
,
formatter
:
'持股'
}
,
{
id
:
3
,
name
:
"香百科技"
,
formatter
:
'合作'
}
,
{
id
:
4
,
name
:
"格林滨"
,
formatter
:
'从属'
}
,
{
id
:
5
,
name
:
"江西紫宸"
,
formatter
:
'合作'
}
,
{
id
:
6
,
name
:
"紫江企业"
,
formatter
:
'持股'
}
,
{
id
:
7
,
name
:
"大而美法案"
,
formatter
:
'合作'
}
,
{
id
:
8
,
name
:
"比亚迪"
,
formatter
:
'合作'
}
,
],
nodes
:
[],
links
:
[],
}
);
const
initGraphChart
=
()
=>
{
graphData
.
links
=
graphData
.
list
.
map
(
onFormatLink
)
graphData
.
nodes
=
graphData
.
list
.
map
(
onFormatNode
)
graphData
.
nodes
.
unshift
(
onFormatNode
(
graphData
.
leader
))
}
const
onFormatLink
=
(
item
,
index
)
=>
{
return
{
id
:
`link-${index+1
}
`
,
source
:
item
.
id
+
''
,
target
:
'0'
,
label
:
{
show
:
true
,
color
:
"#055fc2"
,
backgroundColor
:
"#eef7ff"
,
borderWidth
:
0
,
offset
:
[
0
,
15
],
formatter
:
item
.
formatter
}
,
lineStyle
:
{
color
:
'#B9DCFF'
,
type
:
"solid"
,
opacity
:
1
}
}
}
const
onFormatNode
=
(
item
)
=>
{
let
leader
=
item
.
id
==
'0'
;
return
{
id
:
item
.
id
+
''
,
name
:
onWordWrap
(
item
.
name
,
7
),
label
:
{
show
:
true
,
color
:
"#3b414b"
,
fontSize
:
leader
?
18
:
14
,
fontWeight
:
leader
?
700
:
400
,
fontFamily
:
'Source Han Sans CN'
,
}
,
],
}
;
symbolSize
:
40
,
symbol
:
`image://${company
}
`
}
}
// 文本插入换行符
const
onWordWrap
=
(
word
,
num
)
=>
{
const
list
=
word
.
split
(
''
);
let
label
=
""
;
for
(
let
i
=
0
;
i
<
list
.
length
;
i
++
)
{
if
(
i
%
num
===
0
&&
i
!==
0
)
{
label
+=
"
\
n"
;
}
label
+=
list
[
i
];
}
return
label
;
}
// 受影响实体
const
companyList
=
ref
([]);
...
...
@@ -181,15 +174,10 @@ const handleToCompanyDetail = (item) => {
const
handleCurrentChange
=
page
=>
{
currentPage
.
value
=
page
;
}
;
// const showCompanyList = computed(() =>
{
// const startIndex = (currentPage.value - 1) * pageSize.value;
// const endIndex = startIndex + pageSize.value;
// return companyList.value.slice(startIndex, endIndex);
//
}
);
const
showCompanyList
=
ref
([
{
id
:
1
,
name
:
"北京市"
,
status
:
"上市"
}
,
{
id
:
2
,
name
:
"上海市"
,
status
:
"上市"
}
,
{
id
:
3
,
name
:
"广州市
广州市广州市广州市广州市广州市广州市广州市
"
,
status
:
"上市"
}
,
{
id
:
3
,
name
:
"广州市"
,
status
:
"上市"
}
,
{
id
:
4
,
name
:
"深圳市"
,
status
:
"上市"
}
,
{
id
:
5
,
name
:
"成都市"
,
status
:
"上市"
}
,
{
id
:
7
,
name
:
"天津市"
,
status
:
"上市"
}
,
...
...
@@ -238,9 +226,10 @@ const handleGetHylyList = async () => {
console
.
log
(
"行业领域列表"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
areaList
.
value
=
res
.
data
;
handleGetChainId
();
}
}
catch
(
error
)
{
}
}
catch
(
error
)
{
areaList
.
value
=
[];
}
}
;
// 产业链/实体关系
...
...
@@ -248,178 +237,14 @@ const contentType = ref(1);
const
headerContentType
=
(
type
)
=>
{
contentType
.
value
=
type
;
}
;
const
chainId
=
ref
(
0
);
const
handleGetChainId
=
async
()
=>
{
try
{
const
res
=
await
getChainInfoByDomainId
(
curAreaId
.
value
);
console
.
log
(
"获取chainId"
,
res
);
if
(
res
&&
res
.
length
)
{
chainId
.
value
=
res
[
0
].
id
;
// handleGetChainInfoByChainId();
}
}
catch
(
error
)
{
console
.
error
(
"chainId error"
,
error
);
}
}
;
const
handleNodeClick
=
(
node
)
=>
{
}
;
const
handleLayoutChange
=
(
type
)
=>
{
}
;
const
treeData
=
ref
(
null
);
const
graphData
=
ref
({
nodes
:
[],
links
:
[]
}
);
const
singleSanctionEntitySupplyChainData
=
ref
(
null
);
const
updateGraphData
=
()
=>
{
const
data
=
singleSanctionEntitySupplyChainData
.
value
;
if
(
!
data
)
return
;
const
nodes
=
[];
const
links
=
[];
nodes
.
push
({
id
:
"0"
,
name
:
data
.
orgName
,
image
:
companyActive
,
symbolSize
:
60
,
isSanctioned
:
true
}
);
const
parentList
=
data
.
parentOrgList
||
[];
parentList
.
forEach
((
item
,
index
)
=>
{
nodes
.
push
({
id
:
`p-${item.id || index
}
`
,
name
:
item
.
name
,
image
:
item
.
isSanctioned
?
companyActive
:
company
,
symbolSize
:
40
,
isSanctioned
:
item
.
isSanctioned
}
);
links
.
push
({
source
:
`p-${item.id || index
}
`
,
target
:
"0"
,
name
:
"供应商"
}
);
}
);
const
childList
=
data
.
childrenOrgList
||
[];
childList
.
forEach
((
item
,
index
)
=>
{
nodes
.
push
({
id
:
`c-${item.id || index
}
`
,
name
:
item
.
name
,
image
:
item
.
isSanctioned
?
companyActive
:
company
,
symbolSize
:
40
,
isSanctioned
:
item
.
isSanctioned
}
);
links
.
push
({
source
:
"0"
,
target
:
`c-${item.id || index
}
`
,
name
:
"客户"
}
);
}
);
graphData
.
value
=
{
nodes
,
links
}
;
}
;
const
getSingleSanctionEntitySupplyChainRequest
=
async
()
=>
{
try
{
const
res
=
await
getSingleSanctionEntitySupplyChain
({
orgId
:
"91370102723265504D"
}
);
console
.
log
(
"data1"
,
res
)
if
(
res
.
code
===
200
&&
res
.
data
)
{
singleSanctionEntitySupplyChainData
.
value
=
res
.
data
;
updateGraphData
();
treeData
.
value
=
{
id
:
res
.
data
.
orgId
,
name
:
res
.
data
.
orgName
,
image
:
companyActive
,
symbolSize
:
50
,
children
:
(
res
.
data
.
parentOrgList
||
[]).
map
((
item
,
index
)
=>
({
id
:
item
.
id
||
`p-${index
}
`
,
name
:
item
.
name
,
image
:
item
.
isSanctioned
?
companyActive
:
company
,
symbolSize
:
30
}
))
}
;
}
}
catch
(
error
)
{
console
.
log
(
error
);
}
}
;
// 企业影响分析
const
companyTotalNum
=
ref
(
0
);
// 企业数量
const
chart1Data
=
ref
({
// title: ["集成电路", "新能源", "人工智能", "先进制造", "量子科技"],
// value: [109, 95, 79, 25, 11]
}
);
const
handleGetChart1Data
=
async
()
=>
{
const
params
=
{
id
:
147
}
;
try
{
const
res
=
await
getDecreeIndustry
(
params
);
console
.
log
(
"企业影响分析"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
chart1Data
.
value
.
title
=
res
.
data
.
map
(
item
=>
{
return
item
.
hylyName
;
}
);
chart1Data
.
value
.
value
=
res
.
data
.
map
(
item
=>
{
return
item
.
companyNum
;
}
);
}
else
{
chart1Data
.
value
.
title
=
[];
chart1Data
.
value
.
value
=
[];
}
}
catch
(
error
)
{
chart1Data
.
value
.
title
=
[];
chart1Data
.
value
.
value
=
[];
}
}
;
const
handelBox1
=
async
()
=>
{
await
handleGetChart1Data
();
let
chart1
=
getBarChart
(
chart1Data
.
value
.
title
,
chart1Data
.
value
.
value
);
setChart
(
chart1
,
"chart1"
);
}
;
const
chainInfo
=
ref
({
upstreamInternalCount
:
0
,
upstreamInternalRate
:
0
,
upstreamEntityCount
:
0
,
upstreamEntityRate
:
0
,
midstreamInternalCount
:
0
,
midstreamInternalRate
:
0
,
midstreamEntityCount
:
0
,
midstreamEntityRate
:
0
,
downstreamInternalCount
:
0
,
downstreamInternalRate
:
0
,
downstreamEntityCount
:
0
,
downstreamEntityRate
:
0
}
);
// 根据chainId获取chainInfo
const
handleGetChainInfoByChainId
=
async
()
=>
{
try
{
const
res
=
await
getCnEntityOnChain
(
chainId
.
value
);
console
.
log
(
"chainInfo"
,
res
);
if
(
res
)
{
chainInfo
.
value
=
res
;
}
}
catch
(
error
)
{
console
.
log
(
"chainInfo error"
,
error
);
}
}
;
onMounted
(()
=>
{
// handleGetCompanyListByArea();
handleGetChart1Data
();
initGraphChart
()
handleGetHylyList
();
handelBox1
();
getSingleSanctionEntitySupplyChainRequest
()
}
);
<
/script
>
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论