Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
f8cfb724
提交
f8cfb724
authored
3月 23, 2026
作者:
张伊明
浏览文件
操作
浏览文件
下载
差异文件
合并分支 'zy-dev' 到 'master'
Zy dev 查看合并请求
!190
上级
a99df1de
1ad256dd
隐藏空白字符变更
内嵌
并排
正在显示
16 个修改的文件
包含
1237 行增加
和
2874 行删除
+1237
-2874
config.js
public/js/config.js
+2
-2
App.vue
src/App.vue
+1
-1
home.js
src/api/decree/home.js
+32
-10
influence.js
src/api/decree/influence.js
+33
-0
introduction.js
src/api/decree/introduction.js
+17
-0
index.vue
src/components/base/DecreeOriginal/index.vue
+2
-3
index.vue
src/components/base/GraphChart/index.vue
+10
-3
index.vue
src/views/decree/decreeHome/index.vue
+428
-985
index.vue
src/views/decree/decreeLayout/deepdig/index.vue
+58
-146
ChartChain.vue
src/views/decree/decreeLayout/influence/com/ChartChain.vue
+150
-374
fishbone.vue
src/views/decree/decreeLayout/influence/fishbone.vue
+0
-736
index.vue
src/views/decree/decreeLayout/influence/index.vue
+181
-296
index.vue
src/views/decree/decreeLayout/overview/index.vue
+1
-1
index.vue
...views/decree/decreeLayout/overview/introduction/index.vue
+316
-312
index.vue
src/views/decree/decreeOriginal/index.vue
+4
-2
vite.config.js
vite.config.js
+2
-3
没有找到文件。
public/js/config.js
浏览文件 @
f8cfb724
const
baseUrl
=
`http://8.140.26.4:9085/`
\ No newline at end of file
const
baseUrl
=
`http://8.140.26.4:9085`
\ No newline at end of file
src/App.vue
浏览文件 @
f8cfb724
...
...
@@ -251,7 +251,7 @@ body {
/* 可点击文本 鼠标悬浮样式 */
#app
.text-click-hover
:hover
{
text-decoration
:
underline
;
color
:
rgb
(
5
,
95
,
194
);
color
:
var
(
--color-primary-100
);
cursor
:
pointer
;
}
/* #endregion 公共样式类名 */
...
...
src/api/decree/home.js
浏览文件 @
f8cfb724
...
...
@@ -5,6 +5,7 @@ export function getDepartmentList(params) {
return
request
({
method
:
'GET'
,
url
:
`/api/administrativeDict/department`
,
params
})
}
...
...
@@ -27,34 +28,36 @@ export function getDecreeRiskSignal(params) {
// 行政令发布频度
export
function
getDecreeYearOrder
(
params
)
{
return
request
({
method
:
'
GE
T'
,
url
:
`/api/administrativeOrderOverview/yearOrder
/
${
params
.
year
}
`
,
params
method
:
'
POS
T'
,
url
:
`/api/administrativeOrderOverview/yearOrder`
,
data
:
params
})
}
// 政令涉及领域
export
function
getDecreeArea
(
params
)
{
return
request
({
method
:
'
GE
T'
,
url
:
`/api/administrativeOrderOverview/industry
/
${
params
.
year
}
`
,
params
method
:
'
POS
T'
,
url
:
`/api/administrativeOrderOverview/industry`
,
data
:
params
})
}
// 关键行政令
export
function
getKeyDecree
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/administrativeOrderOverview/action?pageSize=
${
params
.
pageSize
}
&pageNum=
${
params
.
pageNum
}
`
,
method
:
'POST'
,
url
:
`/api/administrativeOrderOverview/action`
,
data
:
params
})
}
// 政令重点条款
export
function
getDecreeKeyInstruction
()
{
export
function
getDecreeKeyInstruction
(
params
)
{
return
request
({
method
:
'
GE
T'
,
method
:
'
POS
T'
,
url
:
`/api/administrativeOrderOverview/instruction`
,
data
:
params
})
}
...
...
@@ -85,4 +88,22 @@ export function getDecreeTypeList() {
method
:
'GET'
,
url
:
`/api/administrativeDict/type`
,
})
}
// 关键机构
export
function
getKeyOrganization
()
{
return
request
({
method
:
'GET'
,
url
:
`/api/commonFeature/keyOrganization`
,
})
}
// AI智能总结
export
function
getChartInterpretation
(
params
)
{
return
request
({
method
:
'POST'
,
url
:
`/aiAnalysis/chart_interpretation`
,
headers
:
{
"X-API-Key"
:
"aircasKEY19491001"
},
data
:
params
})
}
\ No newline at end of file
src/api/decree/influence.js
浏览文件 @
f8cfb724
...
...
@@ -20,6 +20,39 @@ export function getDecreehylyList() {
})
}
// 获取受影响实体列表
export
function
getDecreeEntities
(
params
)
{
return
request
({
method
:
'POST'
,
url
:
`/api/administrativeOrderInfo/relatedEntities`
,
data
:
params
})
}
// 获取实体产业链列表
export
function
getDecreeRelatedChain
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/administrativeOrderInfo/relatedChain/
${
params
.
id
}
`
,
})
}
// 获取产业链节点列表
export
function
getDecreeChainNodes
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/administrativeOrderInfo/relatedChainNodes/
${
params
.
id
}
`
,
})
}
// 获取实体关系节点列表
export
function
getDecreeRelatedEntitie
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/administrativeOrderInfo/listRelatedEntitie/
${
params
.
id
}
`
,
})
}
// 根据政行业领域ID获取公司列表
/**
* @param {cRelated, id}
...
...
src/api/decree/introduction.js
浏览文件 @
f8cfb724
...
...
@@ -77,4 +77,20 @@ export function getDecreeReport(params) {
method
:
'GET'
,
url
:
`/api/administrativeOrderInfo/contentUrl/
${
params
.
id
}
`
,
})
}
// 政令关键词云
export
function
getKeyWordUp
()
{
return
request
({
method
:
'GET'
,
url
:
`/api/element/getKeyWordUp/2025-01-01`
,
})
}
// 报告内容摘要
export
function
getOverview
(
params
)
{
return
request
({
method
:
'GET'
,
url
:
`/api/administrativeOrderInfo/overview/
${
params
.
id
}
`
,
})
}
\ No newline at end of file
src/components/base/DecreeOriginal/index.vue
浏览文件 @
f8cfb724
...
...
@@ -326,9 +326,8 @@ watch(isTranslate, () => {
.report-main
{
flex
:
auto
;
min-height
:
0
;
box-sizing
:
border-box
;
padding-top
:
10px
;
height
:
20px
;
padding
:
10px
0
;
:deep
(
.el-scrollbar
)
{
height
:
100%
;
...
...
src/components/base/GraphChart/index.vue
浏览文件 @
f8cfb724
...
...
@@ -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
浏览文件 @
f8cfb724
...
...
@@ -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,43 +29,25 @@
<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>
<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
class=
"date-box"
v-if=
"govInsList.length"
>
<div
class=
"date-icon"
>
<img
:src=
"tipsTcon"
alt=
""
>
</div>
</div>
-->
<div
class=
"date-text"
>
近期美国各联邦政府机构发布涉华政令数量汇总
</div>
<TimeTabPane
@
time-click=
"handleGetDepartmentList"
/>
</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=
"
organization-
item"
v-for=
"(item, index) in govInsList.slice(0, 7)"
:key=
"index"
@
click=
"handleToInstitution(item)"
>
<div
class=
"item-left"
>
<img
:src=
"item.orgImage || DefaultIcon2"
alt=
""
/>
</div>
<div
class=
"item-right one-line-ellipsis"
>
{{
item
.
orgName
}}
</div>
<div
class=
"item-
num
"
>
{{
item
.
total
}}
项
</div>
<div
class=
"item-
total
"
>
{{
item
.
total
}}
项
</div>
<el-icon
color=
"var(--color-primary-100)"
><ArrowRightBold
/></el-icon>
<div
class=
"item-dot"
v-if=
"item.totalRecent"
>
+
{{
item
.
totalRecent
}}
</div>
</div>
<div
class=
"item"
>
<div
class=
"item-
num item-
more"
>
查看全部机构 (
{{
govInsList
.
length
+
1
}}
家)
</div>
<div
class=
"
organization-
item"
>
<div
class=
"item-more"
>
查看全部机构 (
{{
govInsList
.
length
+
1
}}
家)
</div>
<el-icon
color=
"var(--color-primary-100)"
><ArrowRightBold
/></el-icon>
</div>
</div>
...
...
@@ -198,38 +172,74 @@
<div
class=
"center-footer"
>
<div
class=
"box5"
>
<div
class=
"box5-header"
>
<div
class=
"box5-header-left"
>
<div
class=
"box5-header-icon"
>
<img
src=
"./assets/images/box3-header-icon.png"
alt=
""
/>
</div>
<div
class=
"box5-header-title"
>
{{
"行政令发布频度"
}}
</div>
<div
class=
"box5-header-icon"
>
<img
src=
"./assets/images/box3-header-icon.png"
alt=
""
/>
</div>
<div
class=
"box5-header-title"
>
{{
"数量变化趋势"
}}
</div>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleBox5"
v-model=
"box5Params.proposeName"
:empty-values=
"[null, undefined]"
style=
"width:150px"
>
<el-option
label=
"全部政府部门"
value=
""
/>
<el-option
v-for=
"item in keyOrganizationList"
:key=
"item.orgId"
:label=
"item.orgName"
:value=
"item.orgId"
/>
</el-select>
</div>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleBox5"
v-model=
"box5Params.domainId"
:empty-values=
"[null, undefined]"
style=
"width:120px"
>
<el-option
label=
"全部领域"
value=
""
/>
<el-option
v-for=
"item in areaList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
</div>
<div
class=
"box5-selectbox"
>
<el-select
@
change=
"handleBox5YearChange"
v-model=
"box5SelectedYear"
placeholder=
"选择时间"
style=
"width: 120px"
>
<el-option
v-for=
"item in box5YearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleBox5"
v-model=
"box5Params.year"
placeholder=
"选择时间"
style=
"width:120px"
>
<el-option
v-for=
"item in yearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
</div>
<div
class=
"box5-main"
>
<div
class=
"box5-chart"
id=
"chart1"
></div>
</div>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsTcon"
alt=
""
>
</div>
<div
class=
"data-origin-text"
>
科技政令数量变化趋势,数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"summarize1"
/>
</div>
</div>
<div
class=
"box6"
>
<div
class=
"box6-header"
>
<div
class=
"header-icon"
>
<div
class=
"box5"
>
<div
class=
"box5-header"
>
<div
class=
"box5-header-icon"
>
<img
src=
"./assets/images/box4-header-icon.png"
alt=
""
/>
</div>
<div
class=
"
header-title"
>
{{
"政令科技领域
"
}}
</div>
<div
class=
"box6-selectbox
"
>
<el-select
@
change=
"handleBox6YearChange"
v-model=
"box6
SelectedYear"
placeholder=
"选择时间"
style=
"width: 120px"
>
<el-option
v-for=
"item in
box6YearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value
"
/>
<div
class=
"
box5-header-title"
>
{{
"领域分布情况
"
}}
</div>
<div
style=
"margin-right: 20px;
"
>
<el-select
@
change=
"handleBox6YearChange"
v-model=
"box6
Params.proposeName"
:empty-values=
"[null, undefined]"
style=
"width:150px"
>
<el-option
label=
"全部政府部门"
value=
""
/
>
<el-option
v-for=
"item in
keyOrganizationList"
:key=
"item.orgId"
:label=
"item.orgName"
:value=
"item.orgId
"
/>
</el-select>
</div>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleBox6YearChange"
v-model=
"box6Params.year"
placeholder=
"选择时间"
style=
"width: 120px"
>
<el-option
v-for=
"item in yearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
</div>
<div
class=
"box5-main"
>
<div
class=
"box5-chart"
id=
"chart2"
></div>
</div>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsTcon"
alt=
""
>
</div>
<div
class=
"data-origin-text"
>
科技政领领域分布情况,数据来源:美国各行政机构官网
</div>
</div>
<div
class=
"ai-pane"
>
<AiButton
/>
<AiPane
:aiContent=
"summarize2"
/>
</div>
<div
class=
"box6-main"
id=
"chart2"
></div>
</div>
</div>
<div
class=
"center-footer1"
>
...
...
@@ -238,7 +248,24 @@
<div
class=
"header-icon"
>
<img
src=
"./assets/images/box5-header-icon.png"
alt=
""
/>
</div>
<div
class=
"header-title"
>
{{
"关键行政令"
}}
</div>
<div
class=
"header-title"
>
{{
"关键科技政令"
}}
</div>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleGetKeyDecree"
v-model=
"box7Params.proposeName"
:empty-values=
"[null, undefined]"
style=
"width:150px"
>
<el-option
label=
"全部政府部门"
value=
""
/>
<el-option
v-for=
"item in keyOrganizationList"
:key=
"item.orgId"
:label=
"item.orgName"
:value=
"item.orgId"
/>
</el-select>
</div>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleGetKeyDecree"
v-model=
"box7Params.domainId"
:empty-values=
"[null, undefined]"
style=
"width:120px"
>
<el-option
label=
"全部领域"
value=
""
/>
<el-option
v-for=
"item in areaList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
</div>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleGetKeyDecree"
v-model=
"box7Params.year"
placeholder=
"选择时间"
style=
"width:120px"
>
<el-option
v-for=
"item in yearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
</div>
<div
class=
"box7-main"
>
<div
class=
"box7-list"
>
...
...
@@ -248,14 +275,20 @@
</div>
<div
class=
"info"
>
<div
class=
"info-header"
>
<div
class=
"title"
>
{{
item
.
title
}}
</div>
<div
class=
"title
one-line-ellipsis
"
>
{{
item
.
title
}}
</div>
<div
class=
"time"
>
{{
item
.
time
}}
</div>
</div>
<div
class=
"info-content
"
>
{{
item
.
content
?
item
.
content
:
"暂无数据"
}}
</div>
<div
class=
"info-content
one-line-ellipsis"
>
{{
item
.
content
||
"暂无数据"
}}
</div>
</div>
</div>
</div>
<SimplePagination
v-model:current-page=
"keyDecreeInfo.page"
:page-size=
"keyDecreeInfo.size"
:total=
"keyDecreeInfo.total"
@
page-change=
"handleGetKeyDecree"
/>
</div>
<SimplePagination
v-model:current-page=
"keyDecreeInfo.page"
:page-size=
"keyDecreeInfo.size"
:total=
"keyDecreeInfo.total"
@
page-change=
"handleGetKeyDecree"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsTcon"
alt=
""
>
</div>
<div
class=
"data-origin-text"
>
关键科技政领列表,数据来源:美国各行政机构官网
</div>
</div>
</div>
<div
class=
"box8"
>
...
...
@@ -263,10 +296,33 @@
<div
class=
"header-icon"
>
<img
src=
"./assets/images/box5-header-icon.png"
alt=
""
/>
</div>
<div
class=
"header-title"
>
{{
"政令重点条款"
}}
</div>
<div
class=
"header-title"
>
{{
"关键条款词云"
}}
</div>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleGetDecreeKeyInstruction"
v-model=
"box8Params.proposeName"
:empty-values=
"[null, undefined]"
style=
"width:150px"
>
<el-option
label=
"全部政府部门"
value=
""
/>
<el-option
v-for=
"item in keyOrganizationList"
:key=
"item.orgId"
:label=
"item.orgName"
:value=
"item.orgId"
/>
</el-select>
</div>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleGetDecreeKeyInstruction"
v-model=
"box8Params.domainId"
:empty-values=
"[null, undefined]"
style=
"width:120px"
>
<el-option
label=
"全部领域"
value=
""
/>
<el-option
v-for=
"item in areaList"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
</div>
<div
style=
"margin-right: 20px;"
>
<el-select
@
change=
"handleGetDecreeKeyInstruction"
v-model=
"box8Params.year"
placeholder=
"选择时间"
style=
"width:120px"
>
<el-option
v-for=
"item in yearList"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</div>
</div>
<div
class=
"box8-content"
>
<WordCloudChart
v-if=
"wordCloudData?.length"
:data=
"wordCloudData"
width=
"100%"
height=
"100%"
/>
</div>
<div
class=
"box8-content"
v-if=
"wordCloudData?.length"
>
<WordCloudChart
:data=
"wordCloudData"
width=
"100%"
height=
"100%"
/>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsTcon"
alt=
""
>
</div>
<div
class=
"data-origin-text"
>
科技政领重点条款词云,数据来源:美国各行政机构官网
</div>
</div>
</div>
</div>
...
...
@@ -319,6 +375,10 @@
</div>
<div
class=
"select-main"
>
<div
class=
"checkbox-group"
>
<el-checkbox
v-model=
"activeAreaList"
label=
"all"
style=
"width: 100px"
class=
"filter-checkbox"
@
change=
"checked => handleAreaChange('all', checked)"
>
{{ "全部领域" }}
</el-checkbox>
<el-checkbox
v-for=
"area in areaList"
:key=
"area.id"
v-model=
"activeAreaList"
:label=
"area.id"
style=
"width: 100px"
class=
"filter-checkbox"
@
change=
"checked => handleAreaChange(area.id, checked)"
>
{{ area.name }}
...
...
@@ -396,6 +456,9 @@ 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
AiButton
from
'@/components/base/Ai/AiButton/index.vue'
;
import
AiPane
from
'@/components/base/Ai/AiPane/index.vue'
;
import
{
getDepartmentList
,
getLatestDecree
,
...
...
@@ -406,7 +469,8 @@ import {
getDecreeKeyInstruction
,
getDecreeOrderList
,
getDecreehylyList
,
getDecreeTypeList
getDecreeTypeList
,
getKeyOrganization
,
}
from
"@/api/decree/home"
;
import
{
getPersonSummaryInfo
}
from
"@/api/common/index"
;
import
{
getNews
,
getSocialMedia
}
from
"@/api/general/index"
;
...
...
@@ -418,21 +482,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,13 +496,17 @@ const handleCurrentChange = page => {
handleGetDecreeOrderList
();
};
//
页面 header
//
机构列表
const
govInsList
=
ref
([]);
const
checkedGovIns
=
ref
([]);
const
handleGetDepartmentList
=
async
(
event
)
=>
{
let
day
=
7
if
(
event
?.
time
===
'近一周'
)
day
=
7
if
(
event
?.
time
===
'近一月'
)
day
=
30
if
(
event
?.
time
===
'近一年'
)
day
=
365
const
handleGetDepartmentList
=
async
()
=>
{
try
{
const
res
=
await
getDepartmentList
();
const
res
=
await
getDepartmentList
(
{
day
}
);
console
.
log
(
"机构列表"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
govInsList
.
value
=
res
.
data
;
...
...
@@ -459,7 +515,17 @@ const handleGetDepartmentList = async () => {
console
.
error
(
"获取机构列表error"
,
error
);
}
};
handleGetDepartmentList
();
// 跳转行政机构主页
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 +552,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
();
...
...
@@ -722,46 +778,37 @@ const handleClickPerson = async item => {
}
catch
(
error
)
{
}
};
// 获取最近年份列表
const
currentYear
=
new
Date
().
getFullYear
();
const
getYearList
=
(
count
=
6
)
=>
{
const
yearOptions
=
[];
for
(
let
i
=
0
;
i
<
count
;
i
++
)
{
const
year
=
currentYear
-
i
;
yearOptions
.
push
({
label
:
year
.
toString
(),
value
:
year
.
toString
()
});
}
return
yearOptions
;
};
const
yearList
=
getYearList
();
// 行政令发布频度
const
chart1Data
=
ref
({
dataX
:
[],
dataY
:
[]
});
const
box5YearList
=
ref
([
{
label
:
"2026"
,
value
:
"2026"
},
{
label
:
"2025"
,
value
:
"2025"
},
{
label
:
"2024"
,
value
:
"2024"
},
{
label
:
"2023"
,
value
:
"2023"
},
{
label
:
"2022"
,
value
:
"2022"
},
{
label
:
"2021"
,
value
:
"2021"
}
]);
const
box5SelectedYear
=
ref
(
"2026"
);
const
box5Params
=
reactive
({
year
:
yearList
[
0
].
value
,
domainId
:
''
,
proposeName
:
''
,
})
const
summarize1
=
ref
()
const
handleGetDecreeYearOrder
=
async
()
=>
{
const
params
=
{
year
:
box5SelectedYear
.
value
};
try
{
const
res
=
await
getDecreeYearOrder
(
params
);
let
{
year
,
domainId
,
proposeName
}
=
box5Params
;
const
res
=
await
getDecreeYearOrder
({
year
,
domainId
:
domainId
||
undefined
,
orgId
:
proposeName
||
undefined
});
console
.
log
(
"行政令发布频度"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
chart1Data
.
value
.
dataX
=
res
.
data
.
map
(
item
=>
{
...
...
@@ -770,19 +817,52 @@ const handleGetDecreeYearOrder = async () => {
chart1Data
.
value
.
dataY
=
res
.
data
.
map
(
item
=>
{
return
item
.
count
;
});
summarize1
.
value
=
await
onChartInterpretation
({
type
:
"柱状图"
,
name
:
"数量变化趋势"
,
data
:
res
.
data
})
}
}
catch
(
error
)
{
console
.
error
(
"行政令发布频度error"
,
error
);
}
};
const
handleBox5YearChange
=
val
=>
{
handleBox5
();
};
// AI智能总结
const
onChartInterpretation
=
async
(
text
)
=>
{
const
response
=
await
fetch
(
'/aiAnalysis/chart_interpretation'
,
{
method
:
'POST'
,
headers
:
{
"X-API-Key"
:
"aircasKEY19491001"
,
'Content-Type'
:
'application/json'
,
},
body
:
JSON
.
stringify
({
text
})
// 把参数转为JSON字符串
});
const
reader
=
response
.
body
.
getReader
();
const
decoder
=
new
TextDecoder
();
let
buffer
=
''
;
let
summarize
=
''
;
while
(
true
)
{
const
{
done
,
value
}
=
await
reader
.
read
();
if
(
done
)
break
;
buffer
+=
decoder
.
decode
(
value
,
{
stream
:
true
});
const
lines
=
buffer
.
split
(
'
\
n'
);
buffer
=
lines
.
pop
()
||
''
;
for
(
const
line
of
lines
)
{
if
(
line
.
startsWith
(
'data: '
))
{
const
content
=
line
.
substring
(
6
);
const
textMatch
=
content
.
match
(
/"解读":
\s
*"
([^
"
]
*
)
"/
);
if
(
textMatch
&&
textMatch
[
1
])
summarize
=
textMatch
[
1
];
}
}
}
return
summarize
}
const
handleBox5
=
async
()
=>
{
await
handleGetDecreeYearOrder
();
let
chart1
=
getBarChart
(
chart1Data
.
value
.
dataX
,
chart1Data
.
value
.
dataY
);
chart1
.
yAxis
.
name
=
"数量"
;
chart1
.
yAxis
.
nameTextStyle
=
{
align
:
'right'
}
setChart
(
chart1
,
"chart1"
);
};
...
...
@@ -799,40 +879,18 @@ const chart2Data = ref([
]);
// const colorList = ["#69B1FF", "#FFC069", "#87E8DE", "#85A5FF", "#FF7875", "#B37FEB", "#4096FF"];
const
box6YearList
=
ref
([
{
label
:
"2026"
,
value
:
"2026"
},
{
label
:
"2025"
,
value
:
"2025"
},
{
label
:
"2024"
,
value
:
"2024"
},
{
label
:
"2023"
,
value
:
"2023"
},
{
label
:
"2022"
,
value
:
"2022"
},
{
label
:
"2021"
,
value
:
"2021"
}
]);
const
box6SelectedYear
=
ref
(
"2026"
);
const
box6Params
=
reactive
({
year
:
yearList
[
0
].
value
,
proposeName
:
''
,
});
const
summarize2
=
ref
()
const
handleGetDecreeArea
=
async
()
=>
{
const
params
=
{
year
:
box6SelectedYear
.
value
};
try
{
const
res
=
await
getDecreeArea
(
params
);
let
{
year
,
proposeName
}
=
box6Params
;
const
res
=
await
getDecreeArea
({
year
,
orgId
:
proposeName
||
undefined
});
console
.
log
(
"政令科技领域"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
chart2Data
.
value
=
res
.
data
.
map
(
item
=>
{
...
...
@@ -841,6 +899,7 @@ const handleGetDecreeArea = async () => {
value
:
item
.
count
};
});
summarize2
.
value
=
await
onChartInterpretation
({
type
:
"环形图"
,
name
:
"领域分布情况"
,
data
:
res
.
data
})
}
}
catch
(
error
)
{
console
.
error
(
"政令科技领域error"
,
error
);
...
...
@@ -861,12 +920,23 @@ const keyDecreeList = ref([]);
const
keyDecreeInfo
=
reactive
({
total
:
0
,
page
:
1
,
size
:
3
,
size
:
4
,
})
const
box7Params
=
reactive
({
year
:
yearList
[
0
].
value
,
domainId
:
''
,
proposeName
:
''
,
})
const
handleGetKeyDecree
=
async
()
=>
{
try
{
const
res
=
await
getKeyDecree
({
pageSize
:
keyDecreeInfo
.
size
,
pageNum
:
keyDecreeInfo
.
page
-
1
});
let
{
year
,
domainId
,
proposeName
}
=
box7Params
;
const
res
=
await
getKeyDecree
({
pageSize
:
keyDecreeInfo
.
size
,
pageNum
:
keyDecreeInfo
.
page
-
1
,
year
,
domainId
:
domainId
||
undefined
,
orgId
:
proposeName
||
undefined
});
console
.
log
(
"关键行政令"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
?.
total
)
{
keyDecreeInfo
.
total
=
res
.
data
.
total
||
0
;
...
...
@@ -882,13 +952,21 @@ const handleGetKeyDecree = async () => {
}
catch
(
error
)
{
}
};
handleGetKeyDecree
();
// 政令重点条款
const
wordCloudData
=
ref
([]);
const
box8Params
=
reactive
({
year
:
yearList
[
0
].
value
,
domainId
:
''
,
proposeName
:
''
,
})
const
handleGetDecreeKeyInstruction
=
async
()
=>
{
try
{
const
res
=
await
getDecreeKeyInstruction
();
let
{
year
,
domainId
,
proposeName
}
=
box8Params
;
const
res
=
await
getDecreeKeyInstruction
({
year
,
domainId
:
domainId
||
undefined
,
orgId
:
proposeName
||
undefined
});
console
.
log
(
"政令重点条款"
,
res
);
wordCloudData
.
value
=
res
.
data
.
map
(
item
=>
({
name
:
item
.
clause
,
value
:
item
.
count
}));
}
catch
(
error
)
{
...
...
@@ -952,7 +1030,7 @@ const handleChangeCheckedDecreeType = () => {
};
const
pubTime
=
ref
([
{
id
:
"all"
,
name
:
"全
选
时间"
},
{
id
:
"all"
,
name
:
"全
部
时间"
},
{
id
:
"2026"
,
name
:
"2026年"
},
{
id
:
"2025"
,
name
:
"2025年"
},
{
id
:
"2024"
,
name
:
"2024年"
},
...
...
@@ -984,7 +1062,7 @@ const handlePubTimeChange = (id, checked) => {
};
const
handleAreaChange
=
(
id
,
checked
)
=>
{
const
allIds
=
areaList
.
value
.
filter
(
item
=>
item
.
id
!==
"all"
).
map
(
item
=>
item
.
id
);
const
allIds
=
areaList
.
value
.
map
(
item
=>
item
.
id
);
if
(
id
===
"all"
)
{
activeAreaList
.
value
=
checked
?
[
"all"
,
...
allIds
]
:
[];
...
...
@@ -1013,18 +1091,9 @@ const handleGetAreaList = async () => {
const
res
=
await
getDecreehylyList
();
console
.
log
(
"行业领域列表"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
areaList
.
value
=
[
{
name
:
"全部领域"
,
id
:
"all"
},
...
res
.
data
.
map
(
item
=>
{
return
{
name
:
item
.
name
,
id
:
item
.
id
};
})
];
areaList
.
value
=
res
.
data
;
// 设置默认全选
activeAreaList
.
value
=
[
"all"
,
...
res
.
data
.
map
(
item
=>
item
.
id
)];
console
.
log
(
"areaList"
,
areaList
.
value
);
// 获取列表后重新查询
handleGetDecreeOrderList
();
}
...
...
@@ -1037,11 +1106,9 @@ const decreeList = ref([]);
// 修改请求方法,处理全选时不传参数的情况
const
handleGetDecreeOrderList
=
async
()
=>
{
const
p0
=
checkedGovIns
.
value
.
join
(
","
);
// 处理科技领域:如果包含 all 或全选,则 researchTypeIds 为空(不传)
let
p1
=
""
;
const
allAreaIds
=
areaList
.
value
.
filter
(
item
=>
item
.
id
!==
"all"
).
map
(
item
=>
item
.
id
);
const
allAreaIds
=
areaList
.
value
.
map
(
item
=>
item
.
id
);
const
selectedAreaIds
=
activeAreaList
.
value
.
filter
(
id
=>
id
!==
"all"
);
if
(
!
activeAreaList
.
value
.
includes
(
"all"
)
&&
selectedAreaIds
.
length
>
0
&&
selectedAreaIds
.
length
<
allAreaIds
.
length
)
{
...
...
@@ -1062,11 +1129,9 @@ const handleGetDecreeOrderList = async () => {
p2
=
selectedPubTimeIds
.
join
(
","
);
}
// 其他情况(包含all、长度为0、全部选中)p2保持为空,即不传years
console
.
log
(
activePubTime
.
value
,
"activePubTime.value"
);
const
params
=
{
currentPage
:
currentPage
.
value
,
pageSize
:
pageSize
.
value
,
proposeName
:
p0
,
researchTypeIds
:
p1
,
// 全选时不传(为空)
sortFun
:
isSort
.
value
,
isCN
:
isChina
.
value
?
1
:
0
,
...
...
@@ -1130,12 +1195,27 @@ const handleSearch = () => {
window
.
open
(
curRoute
.
href
,
"_blank"
);
};
// 关键机构
const
keyOrganizationList
=
ref
([]);
const
onKeyOrganization
=
async
()
=>
{
try
{
const
res
=
await
getKeyOrganization
();
console
.
log
(
"关键机构"
,
res
);
if
(
res
.
code
===
200
)
{
keyOrganizationList
.
value
=
res
.
data
.
map
(
item
=>
({
orgName
:
item
.
orgName
,
orgId
:
item
.
id
}));
}
}
catch
(
error
)
{
}
}
onMounted
(
async
()
=>
{
onKeyOrganization
();
handleGetDepartmentList
();
handleGetNews
();
handleGetDecreeTypeList
();
handleGetAreaList
();
handleGetDecreeOrderList
();
handleBox1
();
// 最新科技政令
handleGetKeyDecree
();
handleBox5
();
handleBox6
();
handleGetDecreeKeyInstruction
();
...
...
@@ -1147,132 +1227,57 @@ onMounted(async () => {
box-shadow
:
none
;
}
.home-wrapper
{
width
:
100%
;
height
:
100%
;
position
:
relative
;
overflow-y
:
hidden
;
.search-header
{
.ai-pane
{
position
:
absolute
;
right
:
0px
;
bottom
:
15px
;
z-index
:
2
;
:deep
(
.ai-pane-wrapper
)
{
display
:
none
;
}
:deep
(
.ai-button-wrapper
)
{
display
:
flex
;
}
&
:hover
{
width
:
100%
;
// height: 144px;
background
:
#fff
;
overflow
:
hidden
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
.search-header-container
{
width
:
1600px
;
margin
:
0
auto
;
padding
:
16px
0px
16px
0px
;
bottom
:
0px
;
:deep
(
.ai-pane-wrapper
)
{
display
:
block
;
}
.home-main-header-center
{
// margin-top: 20px;
// margin-left: 200px;
width
:
800px
;
height
:
48px
;
border-radius
:
10px
;
// box-shadow: 0px 0px 15px 0px rgba(22, 119, 255, 0.1);
border
:
1px
solid
var
(
--
color-primary-35
);
background
:
rgba
(
255
,
255
,
255
,
1
);
box-sizing
:
border-box
;
padding
:
1px
;
position
:
relative
;
&
:hover
{
border
:
1px
solid
var
(
--
color-main-active
);
}
.search
{
position
:
absolute
;
right
:
-1px
;
top
:
0px
;
width
:
120px
;
height
:
46px
;
border-radius
:
10px
;
background
:
var
(
--
color-main-active
);
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
cursor
:
pointer
;
.search-icon
{
width
:
18px
;
height
:
18px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.search-text
{
margin-left
:
8px
;
height
:
22px
;
color
:
#fff
;
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
22px
;
}
}
:deep
(
.ai-button-wrapper
)
{
display
:
none
;
}
}
}
.home-main-header-btn-box
{
margin-top
:
16px
;
// margin-left: 200px;
display
:
flex
;
gap
:
16px
;
.btn
{
display
:
flex
;
align-items
:
center
;
gap
:
9px
;
width
:
140px
;
height
:
36px
;
border
:
1px
solid
#aed6ff
;
box-sizing
:
border-box
;
border-radius
:
24px
;
background
:
#e7f3ff
;
cursor
:
pointer
;
position
:
relative
;
&
:hover
{
background
:
#cae3fc
;
}
.btn-text
{
width
:
80px
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
400
;
line-height
:
48px
;
margin-left
:
24px
;
text-align
:
center
;
}
.btn-icon
{
position
:
absolute
;
top
:
10px
;
right
:
19px
;
width
:
6px
;
height
:
12px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
.data-origin-box
{
width
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
padding
:
16px
0
;
.data-origin-icon
{
width
:
16px
;
height
:
16px
;
font-size
:
0px
;
margin-right
:
8px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.scrollHomeMain
{
width
:
100%
;
height
:
calc
(
100%
-
144px
);
overflow-y
:
auto
;
.data-origin-text
{
font-family
:
Source
Han
Sans
CN
;
font-size
:
14px
;
color
:
var
(
--
text-primary-50-color
);
}
}
.home-wrapper
{
width
:
100%
;
height
:
100%
;
position
:
relative
;
overflow-y
:
hidden
;
.home-main
{
position
:
relative
;
...
...
@@ -1389,14 +1394,41 @@ 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
;
gap
:
16px
;
font-family
:
Microsoft
YaHei
;
.item
{
.
organization-
item
{
width
:
20%
;
flex
:
auto
;
height
:
80px
;
...
...
@@ -1410,9 +1442,8 @@ onMounted(async () => {
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
transition
:
transform
0
.3s
ease
,
box-shadow
0
.3s
ease
;
transition
:
transform
0
.3s
ease
,
box-shadow
0
.3s
ease
;
position
:
relative
;
&
:hover
{
transform
:
translateY
(
-3px
);
...
...
@@ -1433,25 +1464,43 @@ onMounted(async () => {
width
:
20px
;
flex
:
auto
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
20px
;
margin
:
0
16px
;
}
.item-num
{
white-space
:
nowrap
;
font-family
:
Microsoft
YaHei
;
.item-total
{
font-size
:
20px
;
margin-right
:
2px
;
white-space
:
nowrap
;
font-weight
:
700
;
line-height
:
20px
;
margin-right
:
2px
;
color
:
var
(
--
color-primary-100
);
}
.item-more
{
font-size
:
16px
;
margin-right
:
12px
;
white-space
:
nowrap
;
font-weight
:
700
;
line-height
:
16px
;
color
:
var
(
--
color-primary-100
);
}
.item-dot
{
position
:
absolute
;
right
:
-13px
;
top
:
-10px
;
padding
:
0
8px
;
height
:
26px
;
background-color
:
#FF4D4F
;
color
:
white
;
font-size
:
16px
;
line-height
:
26px
;
font-family
:
Source
Han
Sans
CN
;
border-radius
:
14px
;
letter-spacing
:
1px
;
}
}
}
...
...
@@ -2084,693 +2133,100 @@ onMounted(async () => {
padding-bottom
:
8px
;
padding-left
:
24px
;
padding-top
:
5px
;
// .box4-main-item {
// margin-top: 16px;
// display: flex;
// margin-left: 21px;
// .left {
// margin-top: 5px;
// width: 36px;
// height: 36px;
// border-radius: 18px;
// overflow: hidden;
// cursor: pointer;
// img {
// width: 100%;
// height: 100%;
// }
// }
// .right {
// margin-left: 10px;
// width: 690px;
// border-radius: 4px;
// box-sizing: border-box;
// border: 1px solid rgba(231, 243, 255, 1);
// background: rgba(246, 250, 255, 1);
// padding: 10px 15px;
// .right-top {
// display: flex;
// justify-content: space-between;
// .name {
// height: 24px;
// color: rgba(59, 65, 75, 1);
// font-family: Microsoft YaHei;
// font-size: 16px;
// font-weight: 700;
// line-height: 24px;
// }
// .time {
// height: 30px;
// color: rgba(95, 101, 108, 1);
// font-family: Microsoft YaHei;
// font-size: 16px;
// font-weight: 400;
// line-height: 30px;
// }
// }
// .content {
// color: rgba(59, 65, 75, 1);
// font-family: Microsoft YaHei;
// font-size: 16px;
// font-weight: 400;
// line-height: 24px;
// }
// }
// }
}
}
}
.center-center1
{
margin
:
0
auto
;
margin-top
:
24px
;
height
:
100px
;
.divide3
{
width
:
1600px
;
border-radius
:
50px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
60
,
87
,
126
,
0
.2
);
background
:
rgba
(
255
,
255
,
255
,
1
);
margin
:
0
auto
;
margin-top
:
68px
;
margin-bottom
:
36px
;
}
.center-footer
{
margin-top
:
21px
;
height
:
460px
;
display
:
flex
;
justify-content
:
space-between
;
box-sizing
:
border-box
;
padding
:
4px
5px
;
gap
:
16px
;
justify-content
:
center
;
.center1-item
{
width
:
351px
;
height
:
92px
;
border-radius
:
48px
;
.box5
{
width
:
792px
;
height
:
100%
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
border-radius
:
10px
;
position
:
relative
;
display
:
flex
;
cursor
:
pointer
;
&
:hover
{
background
:
rgba
(
231
,
243
,
255
,
1
);
}
flex-direction
:
column
;
.left
{
margin-top
:
15px
;
margin-left
:
39px
;
width
:
60px
;
height
:
60px
;
.box5-header
{
width
:
100%
;
height
:
48px
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
display
:
flex
;
align-items
:
center
;
img
{
width
:
100%
;
height
:
100%
;
.box5-header-icon
{
margin-left
:
24px
;
width
:
17px
;
height
:
17px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
.right
{
margin-left
:
8px
;
.name
{
height
:
31px
;
margin-top
:
16px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
.box5-header-title
{
width
:
20px
;
flex
:
auto
;
margin-left
:
19px
;
height
:
26px
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
font-size
:
2
4
px
;
font-size
:
2
0
px
;
font-weight
:
700
;
line-height
:
31px
;
}
.nameActive
{
color
:
var
(
--
color-main-active
);
}
.time
{
margin-top
:
1px
;
height
:
30px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
30px
;
}
.timeActive
{
color
:
var
(
--
color-main-active
);
}
}
}
.center1ItemActive
{
background
:
rgba
(
231
,
243
,
255
,
1
);
}
}
.center-center2
{
margin
:
0
auto
;
margin-top
:
24px
;
width
:
1600px
;
height
:
960px
;
border-radius
:
4px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
60
,
87
,
126
,
0
.2
);
background
:
rgba
(
255
,
255
,
255
,
1
);
.center2-header
{
display
:
flex
;
justify-content
:
space-between
;
.center2-header-left
{
margin-left
:
62px
;
display
:
flex
;
.left
{
width
:
140px
;
height
:
175px
;
border-radius
:
0px
0px
70px
70px
;
background
:
rgba
(
231
,
243
,
255
,
1
);
overflow
:
hidden
;
.icon
{
width
:
128px
;
height
:
128px
;
border-radius
:
75px
;
margin-top
:
41px
;
margin-left
:
6px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
.right
{
margin-left
:
29px
;
.right-item1
{
margin-top
:
41px
;
height
:
31px
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
font-size
:
24px
;
font-weight
:
700
;
line-height
:
32px
;
}
.right-item2
{
display
:
flex
;
margin-top
:
7px
;
.icon
{
width
:
24px
;
height
:
24px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.text
{
margin-left
:
8px
;
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
18px
;
font-weight
:
400
;
line-height
:
24px
;
}
}
.right-item3
{
margin-top
:
10px
;
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
18px
;
font-weight
:
400
;
line-height
:
24px
;
}
.right-item4
{
margin-top
:
8px
;
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
18px
;
font-weight
:
400
;
line-height
:
24px
;
}
}
}
.center2-header-right
{
margin-right
:
59px
;
margin-top
:
47px
;
.top
{
display
:
flex
;
.top-box
{
width
:
180px
;
height
:
72px
;
margin-left
:
50px
;
.item1
{
height
:
26px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
26px
;
text-align
:
right
;
}
.item2
{
margin-top
:
4px
;
font-family
:
Microsoft
YaHei
;
font-weight
:
700
;
display
:
flex
;
justify-content
:
flex-end
;
.item2-3
{
height
:
42px
;
color
:
var
(
--
color-main-active
);
font-size
:
32px
;
line-height
:
42px
;
}
.item2-2
{
height
:
24px
;
margin-top
:
9px
;
margin-left
:
5px
;
margin-right
:
5px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
18px
;
font-weight
:
700
;
line-height
:
24px
;
}
.item2-1
{
height
:
42px
;
color
:
rgba
(
206
,
79
,
81
,
1
);
font-size
:
32px
;
line-height
:
42px
;
}
}
}
}
.bottom
{
height
:
22px
;
margin-top
:
29px
;
display
:
flex
;
justify-content
:
flex-end
;
.icon
{
margin-top
:
4px
;
width
:
14px
;
height
:
14px
;
margin-right
:
8px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.text
{
height
:
22px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
24px
;
}
}
}
}
.center2-mid
{
width
:
1479px
;
height
:
189px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-radius
:
4px
;
margin
:
40px
auto
0
;
}
.center2-footer
{
display
:
flex
;
.center2-footer-left
{
width
:
732px
;
margin-left
:
58px
;
margin-top
:
21px
;
.header
{
display
:
flex
;
height
:
48px
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
.icon
{
margin-top
:
15px
;
margin-left
:
20px
;
width
:
20px
;
height
:
20px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.text
{
margin-left
:
20px
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
48px
;
}
}
.main
{
width
:
732px
;
height
:
470px
;
overflow-y
:
auto
;
overflow-x
:
hidden
;
display
:
flex
;
flex-wrap
:
wrap
;
box-sizing
:
border-box
;
padding-top
:
9px
;
.item
{
width
:
50%
;
height
:
80px
;
display
:
flex
;
margin-top
:
8px
;
.item-left
{
width
:
60px
;
height
:
60px
;
margin-top
:
10px
;
margin-left
:
16px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.item-right
{
margin-left
:
13px
;
.item-right-box1
{
margin-top
:
15px
;
height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
18px
;
font-weight
:
700
;
line-height
:
24px
;
}
.item-right-box2
{
margin-top
:
1px
;
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
}
}
}
}
}
.center2-footer-right
{
margin-left
:
21px
;
margin-top
:
16px
;
width
:
730px
;
.header
{
height
:
54px
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
display
:
flex
;
.icon
{
width
:
24px
;
height
:
24px
;
margin-left
:
16px
;
margin-top
:
16px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.tab-box
{
margin-left
:
20px
;
width
:
500px
;
display
:
flex
;
.tab
{
height
:
54px
;
margin-right
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
400
;
line-height
:
54px
;
padding
:
0
2px
;
box-sizing
:
border-box
;
}
.tabActive
{
font-weight
:
700
;
color
:
var
(
--
color-main-active
);
border-bottom
:
3px
solid
var
(
--
color-main-active
);
}
}
.right
{
width
:
80px
;
margin-left
:
90px
;
display
:
flex
;
justify-content
:
space-between
;
.btn
{
width
:
28px
;
height
:
28px
;
margin-top
:
13px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
}
.main
{
height
:
475px
;
margin-top
:
5px
;
overflow-y
:
hidden
;
.main-item
{
display
:
flex
;
margin-top
:
20px
;
.id
{
margin-top
:
3px
;
margin-left
:
2px
;
width
:
36px
;
height
:
36px
;
border-radius
:
18px
;
background
:
#e7f3ff
;
line-height
:
36px
;
text-align
:
center
;
color
:
var
(
--
color-main-active
);
}
.info
{
margin-left
:
13px
;
width
:
672px
;
.info-header
{
display
:
flex
;
justify-content
:
space-between
;
height
:
24px
;
.title
{
height
:
24px
;
margin-top
:
1px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
18px
;
font-weight
:
700
;
line-height
:
24px
;
}
.tag
{
height
:
24px
;
line-height
:
24px
;
border-radius
:
4px
;
padding
:
0
8px
;
background
:
rgba
(
255
,
251
,
230
,
1
);
color
:
rgba
(
250
,
173
,
20
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
}
}
}
}
}
}
}
}
.divide3
{
width
:
1600px
;
margin
:
0
auto
;
margin-top
:
68px
;
margin-bottom
:
36px
;
}
.center-footer
{
margin-top
:
21px
;
height
:
452px
;
display
:
flex
;
justify-content
:
center
;
.box5
{
width
:
792px
;
height
:
452px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
border-radius
:
10px
;
.box5-header
{
height
:
48px
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
margin
:
0
auto
;
display
:
flex
;
justify-content
:
space-between
;
.box5-header-left
{
display
:
flex
;
.box5-header-icon
{
margin-top
:
17px
;
margin-left
:
24px
;
width
:
17px
;
height
:
17px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.box5-header-title
{
margin-top
:
11px
;
margin-left
:
19px
;
height
:
26px
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
26px
;
}
}
.box5-selectbox
{
margin-right
:
20px
;
margin-top
:
8px
;
line-height
:
26px
;
}
}
.box5-main
{
height
:
397px
;
flex
:
auto
;
height
:
20px
;
.box5-chart
{
height
:
397px
;
}
}
}
.box6
{
margin-left
:
16px
;
width
:
792px
;
height
:
452px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
22
,
119
,
255
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
border-radius
:
10px
;
.box6-header
{
margin
:
0
auto
;
height
:
53px
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
display
:
flex
;
position
:
relative
;
.header-icon
{
margin-top
:
16px
;
margin-left
:
22px
;
width
:
20px
;
height
:
20px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.header-title
{
margin-top
:
11px
;
margin-left
:
18px
;
height
:
26px
;
color
:
rgba
(
20
,
89
,
187
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
26px
;
}
.box6-selectbox
{
position
:
absolute
;
right
:
20px
;
top
:
8px
;
height
:
100%
;
}
}
.box6-main
{
margin-top
:
8px
;
height
:
390px
;
}
}
}
.center-footer1
{
margin-top
:
21px
;
height
:
4
5
0px
;
height
:
4
6
0px
;
display
:
flex
;
justify-content
:
center
;
.box7
{
width
:
792px
;
height
:
450px
;
height
:
100%
;
border-radius
:
10px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
60
,
87
,
126
,
0
.2
);
background
:
rgba
(
255
,
255
,
255
,
1
);
display
:
flex
;
flex-direction
:
column
;
.box7-header
{
width
:
792px
;
height
:
48px
;
display
:
flex
;
align-items
:
center
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
.header-icon
{
width
:
22px
;
height
:
20px
;
margin-left
:
25px
;
margin-top
:
15px
;
img
{
width
:
100%
;
height
:
100%
;
...
...
@@ -2778,8 +2234,9 @@ onMounted(async () => {
}
.header-title
{
width
:
20px
;
flex
:
auto
;
height
:
26px
;
margin-top
:
11px
;
margin-left
:
13px
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
...
...
@@ -2790,27 +2247,23 @@ onMounted(async () => {
}
.box7-main
{
margin-top
:
1
0px
;
height
:
2
0px
;
flex
:
auto
;
.box7-list
{
height
:
310px
;
padding
:
10px
24px
0
;
.box7-item
{
width
:
730px
;
margin-top
:
16px
;
margin-left
:
25px
;
display
:
flex
;
padding
:
10px
0
;
cursor
:
pointer
;
&
:hover
{
background
:
var
(
--
color-bg-hover
);
}
.icon
{
margin-top
:
6
px
;
margin-top
:
8
px
;
width
:
24px
;
height
:
22px
;
font-size
:
0px
;
img
{
width
:
100%
;
height
:
100%
;
...
...
@@ -2819,8 +2272,8 @@ onMounted(async () => {
.info
{
margin-left
:
13px
;
width
:
100%
;
width
:
20px
;
flex
:
auto
;
.info-header
{
height
:
24px
;
display
:
flex
;
...
...
@@ -2835,9 +2288,6 @@ onMounted(async () => {
font-size
:
18px
;
font-weight
:
700
;
line-height
:
24px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.time
{
...
...
@@ -2855,30 +2305,27 @@ onMounted(async () => {
}
.info-content
{
min-height
:
24px
;
max-height
:
48px
;
height
:
24px
;
margin-top
:
6px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
display
:
-
webkit-box
;
-webkit-line-clamp
:
2
;
-webkit-box-orient
:
vertical
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
}
}
}
}
:deep
(
.simple-pagination
)
{
padding
:
0
;
}
}
.box8
{
margin-left
:
16px
;
width
:
792px
;
height
:
450px
;
height
:
100%
;
border-radius
:
10px
;
box-shadow
:
0px
0px
15px
0px
rgba
(
60
,
87
,
126
,
0
.2
);
background
:
rgba
(
255
,
255
,
255
,
1
);
...
...
@@ -2889,14 +2336,13 @@ onMounted(async () => {
width
:
100%
;
height
:
48px
;
display
:
flex
;
align-items
:
center
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
.header-icon
{
width
:
22px
;
height
:
20px
;
margin-left
:
25px
;
margin-top
:
15px
;
img
{
width
:
100%
;
height
:
100%
;
...
...
@@ -2904,8 +2350,9 @@ onMounted(async () => {
}
.header-title
{
width
:
20px
;
flex
:
auto
;
height
:
26px
;
margin-top
:
11px
;
margin-left
:
13px
;
color
:
var
(
--
color-main-active
);
font-family
:
Microsoft
YaHei
;
...
...
@@ -2920,10 +2367,6 @@ onMounted(async () => {
height
:
20px
;
flex
:
auto
;
}
.box8-main
{
height
:
401px
;
}
}
}
}
...
...
src/views/decree/decreeLayout/deepdig/index.vue
浏览文件 @
f8cfb724
...
...
@@ -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
浏览文件 @
f8cfb724
<
template
>
<div
class=
"view-box"
>
<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' }">
<el-empty
v-if=
"!listData?.length"
style=
"padding: 60px 0;"
description=
"暂无数据"
:image-size=
"100"
/>
<div
v-if=
"listData.length"
class=
"main-content-main"
@
wheel
.
prevent=
"handleWheel"
@
mousedown=
"handleMouseDown"
@
mouseup=
"handleMouseUp"
@
mouseleave=
"handleMouseUp"
@
mousemove=
"handleMouseMove"
>
<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
,
'
green-theme
'
:
index
>
= 2
&&
index
<
4
,
'
purple-theme
'
:
index
>
= 4
}" :style="{ left: index * 200 + 220 + 'px' }">
{{
item
.
text
}}
<div
class=
"main-line"
:style=
"
{ width: listData.length * 200 + 300 + 'px' }">
<div
v-for=
"(item, index) in listData"
:key=
"item.id"
class=
"main-line-text"
:class=
"getThemeClass(item.level)"
:style=
"
{ left: index * 200 + 220 + 'px' }">
{{
item
.
name
}}
</div>
</div>
<!-- 奇数索引的数据组放在上方 -->
<div
v-for=
"(causeGroup, groupIndex) in onFilterData(1)"
:key=
"groupIndex"
class=
"top-bone"
:style=
"
{ left: groupIndex * 400 + 510 + 'px', height: (causeGroup.c
auses
?.length) * 22 + 100 + 'px' }">
class=
"top-bone"
:style=
"
{ left: groupIndex * 400 + 510 + 'px', height: (causeGroup.c
hildren
?.length) * 22 + 100 + 'px' }">
<div
class=
"left-bone"
>
<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
class=
"bone-item-box bone-item-end bone-item-top"
v-for=
"item in getLeftItems(causeGroup.children)"
:key=
"item.id"
>
<div
:class=
"['bone-item-word',
{'bone-item-back':item.back}]">
<div
class=
"bone-item-icon"
>
<img
:src=
"item.image || defaultIcon2"
alt=
""
/>
</div>
<div
class=
"bone-item-text one-line-ellipsis"
:style=
"
{color: item.isEntity==1? '#ce4f51' : '#3b414b'}" :title="item.companyName">
{{
item
.
companyName
}}
</div>
</div>
<div
class=
"bone-item-line"
></div>
</div>
</div>
<div
class=
"right-bone"
>
<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
class=
"bone-item-box bone-item-start bone-item-top"
v-for=
"item in getRightItems(causeGroup.children)"
:key=
"item.id"
>
<div
class=
"bone-item-line"
></div>
<div
:class=
"['bone-item-word',
{'bone-item-back':item.back}]">
<div
class=
"bone-item-icon"
>
<img
:src=
"item.image || defaultIcon2"
alt=
""
/>
</div>
<div
class=
"bone-item-text one-line-ellipsis"
:style=
"
{color: item.isEntity==1? '#ce4f51' : '#3b414b'}" :title="item.companyName">
{{
item
.
companyName
}}
</div>
</div>
</div>
</div>
</div>
<!-- 偶数索引的数据组放在下方 -->
<div
v-for=
"(causeGroup, groupIndex) in onFilterData(0)"
:key=
"groupIndex"
class=
"bottom-bone"
:style=
"
{ left: groupIndex * 400 + 310 + 'px', height: (causeGroup.c
auses
?.length) * 22 + 100 + 'px' }">
class=
"bottom-bone"
:style=
"
{ left: groupIndex * 400 + 310 + 'px', height: (causeGroup.c
hildren
?.length) * 22 + 100 + 'px' }">
<div
class=
"left-bone"
>
<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
class=
"bone-item-box bone-item-end bone-item-down"
v-for=
"item in getRightItems(causeGroup.children)"
:key=
"item.id"
>
<div
:class=
"['bone-item-word',
{'bone-item-back':item.back}]">
<div
class=
"bone-item-icon"
>
<img
:src=
"item.image || defaultIcon2"
alt=
""
/>
</div>
<div
class=
"bone-item-text one-line-ellipsis"
:style=
"
{color: item.isEntity==1? '#ce4f51' : '#3b414b'}" :title="item.companyName">
{{
item
.
companyName
}}
</div>
</div>
<div
class=
"bone-item-line"
></div>
</div>
</div>
<div
class=
"right-bone"
>
<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>
<div
class=
"bone-item-box bone-item-start bone-item-down"
v-for=
"item in getLeftItems(causeGroup.children)"
:key=
"item.id"
>
<div
class=
"bone-item-line"
></div>
<div
:class=
"['bone-item-word',
{'bone-item-back':item.back}]">
<div
class=
"bone-item-icon"
>
<img
:src=
"item.image || defaultIcon2"
alt=
""
/>
</div>
<div
class=
"bone-item-text one-line-ellipsis"
:style=
"
{color: item.isEntity==1? '#ce4f51' : '#3b414b'}" :title="item.companyName">
{{
item
.
companyName
}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
v-if=
"
dataList
.length"
class=
"main-content-footer"
>
<div
class=
"footer-item footer-item1
"
>
<div
v-if=
"
listData
.length"
class=
"main-content-footer"
>
<div
v-for=
"(item, index) in props.baseData"
:key=
"index"
class=
"footer-item
"
>
<div
class=
"footer-item-bottom"
>
<div
class=
"icon"
>
<img
:src=
"noticeIcon"
alt=
""
/>
</div>
<div
class=
"text"
>
{{
`中国企业${cnEntityOnChainData.upstreamInternalCount ||
0
}
家(${formatRate(cnEntityOnChainData.upstreamInternalRate)
}
%),受制裁${cnEntityOnChainData.upstreamEntityCount
|| 0
}
家(${formatRate(cnEntityOnChainData.upstreamEntityRate)
}
%)`
`中国企业${item.isChinaCount
}
家(${formatRate(item, 'isChinaCount')
}
%),受制裁${item.sanCount
}
家(${formatRate(item, 'sanCount')
}
%)`
}}
<
/div
>
<
/div
>
<
div
class
=
"footer-item-top"
>
{{
"上游"
}}
<
/div
>
<
/div
>
<
div
class
=
"footer-item footer-item2"
>
<
div
class
=
"footer-item-bottom"
>
<
div
class
=
"icon"
>
<
img
:
src
=
"noticeIcon"
alt
=
""
/>
<
/div
>
<
div
class
=
"text"
>
{{
`中国企业${cnEntityOnChainData.midstreamInternalCount ||
0
}
家(${formatRate(cnEntityOnChainData.midstreamInternalRate)
}
%),受制裁${cnEntityOnChainData.midstreamEntityCount
|| 0
}
家(${formatRate(cnEntityOnChainData.midstreamEntityRate)
}
%)`
}}
<
/div
>
<
/div
>
<
div
class
=
"footer-item-top"
>
{{
"中游"
}}
<
/div
>
<
/div
>
<
div
class
=
"footer-item footer-item3"
>
<
div
class
=
"footer-item-bottom"
>
<
div
class
=
"icon"
>
<
img
:
src
=
"noticeIcon"
alt
=
""
/>
<
/div
>
<
div
class
=
"text"
>
{{
`中国企业${cnEntityOnChainData.downstreamInternalCount ||
0
}
家(${formatRate(cnEntityOnChainData.downstreamInternalRate)
}
%),受制裁${cnEntityOnChainData.downstreamEntityCount
|| 0
}
家(${formatRate(cnEntityOnChainData.downstreamEntityRate)
}
%)`
}}
<
/div
>
<
/div
>
<
div
class
=
"footer-item-top"
>
{{
"下游"
}}
<
/div
>
<
div
class
=
"footer-item-top"
:
class
=
"getThemeClass(item.name)"
>
{{
item
.
name
}}
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
/template
>
<
script
setup
name
=
"ChartChain"
>
import
{
ref
,
onMounted
}
from
"vue"
;
import
{
ref
}
from
"vue"
;
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
props
=
defineProps
({
baseData
:
{
type
:
Object
,
default
:
()
=>
([])
}
,
listData
:
{
type
:
Array
,
default
:
()
=>
([])
}
}
);
const
getThemeClass
=
(
name
)
=>
{
if
(
name
==
"上游"
)
return
"blue-theme"
;
if
(
name
==
"中游"
)
return
"green-theme"
;
if
(
name
==
"下游"
)
return
"purple-theme"
;
}
// #region 缩放功能处理
const
scale
=
ref
(
1
)
const
minScale
=
0.1
const
maxScale
=
10
...
...
@@ -128,7 +122,9 @@ const handleWheel = (e) => {
scale
.
value
=
Math
.
max
(
scale
.
value
-
0.1
,
minScale
)
}
}
// 移动功能处理
// #endregion 缩放功能处理
// #region 移动功能处理
const
translateX
=
ref
(
0
)
// X轴位移
const
translateY
=
ref
(
0
)
// Y轴位移
let
isDragging
=
false
...
...
@@ -149,40 +145,11 @@ const handleMouseDown = (e) => {
const
handleMouseUp
=
()
=>
{
isDragging
=
false
}
// #endregion 移动功能处理
// 实体清单-深度挖掘-产业链中国企业实体信息查询
const
cnEntityOnChainData
=
ref
({
}
);
const
getCnEntityOnChainData
=
async
()
=>
{
const
currentSanction
=
sanctionList
.
value
.
find
(
item
=>
item
.
id
===
currentSanctionId
.
value
);
const
date
=
currentSanction
?
currentSanction
.
date
:
''
;
// 确保 date 格式正确
const
formattedDate
=
date
&&
date
.
includes
(
'年'
)
?
date
.
replace
(
'年'
,
'-'
).
replace
(
'月'
,
'-'
).
replace
(
'日'
,
''
)
:
date
;
const
params
=
{
date
:
formattedDate
}
;
if
(
selectedIndustryId
.
value
)
{
params
.
chainId
=
selectedIndustryId
.
value
;
}
try
{
const
res
=
await
getDeepMiningIndustryEntity
(
params
);
console
.
log
(
"企业信息"
,
res
)
if
(
res
.
code
===
200
&&
res
.
data
)
{
cnEntityOnChainData
.
value
=
res
.
data
;
}
else
{
cnEntityOnChainData
.
value
=
{
}
;
}
}
catch
(
error
)
{
console
.
error
(
"获取产业链中国企业实体信息失败:"
,
error
);
cnEntityOnChainData
.
value
=
{
}
;
}
}
// 产业链鱼骨数据
const
dataList
=
ref
([]);
// 奇数索引的数据组放在上方, 偶数索引的数据组放在下方
const
onFilterData
=
(
num
)
=>
{
return
dataList
.
value
.
filter
((
_
,
index
)
=>
index
%
2
===
num
);
return
props
.
listData
.
filter
((
_
,
index
)
=>
index
%
2
===
num
);
}
;
// 获取左侧显示的项目(前半部分)
const
getLeftItems
=
items
=>
{
...
...
@@ -194,122 +161,11 @@ const getRightItems = items => {
const
midpoint
=
Math
.
ceil
(
items
.
length
/
2
);
return
items
.
slice
(
midpoint
);
}
;
const
getFishboneData
=
async
()
=>
{
const
currentSanction
=
sanctionList
.
value
.
find
(
item
=>
item
.
id
===
currentSanctionId
.
value
);
const
date
=
currentSanction
?
currentSanction
.
date
:
''
;
// 确保 date 格式正确
const
formattedDate
=
date
&&
date
.
includes
(
'年'
)
?
date
.
replace
(
'年'
,
'-'
).
replace
(
'月'
,
'-'
).
replace
(
'日'
,
''
)
:
date
;
const
params
=
{
date
:
formattedDate
}
;
if
(
selectedIndustryId
.
value
)
{
params
.
chainId
=
selectedIndustryId
.
value
;
}
try
{
const
res
=
await
getDeepMiningIndustryFishbone
(
params
);
console
.
log
(
"获取产业链数据:"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
?.
causes
?.
length
)
{
dataList
.
value
=
res
.
data
.
causes
;
}
else
{
dataList
.
value
=
[];
}
}
catch
(
error
)
{
console
.
error
(
"获取产业链鱼骨图数据失败:"
,
error
);
dataList
.
value
=
[];
}
}
// 实体清单-深度挖掘-产业链列表信息
const
selectedIndustryId
=
ref
(
null
);
const
getIndustryList
=
async
()
=>
{
try
{
const
res
=
await
getDeepMiningIndustry
();
if
(
res
.
code
===
200
&&
res
.
data
&&
res
.
data
.
length
>
0
)
{
selectedIndustryId
.
value
=
res
.
data
[
0
].
id
;
getFishboneData
();
getCnEntityOnChainData
();
}
else
{
selectedIndustryId
.
value
=
null
;
}
}
catch
(
error
)
{
console
.
error
(
"获取产业链列表数据失败:"
,
error
);
selectedIndustryId
.
value
=
null
;
}
}
// 获取选择制裁
const
loading
=
ref
(
false
);
const
currentPage
=
ref
(
1
);
const
pageSize
=
ref
(
10000
);
const
getDeepMiningSelectData
=
async
()
=>
{
loading
.
value
=
true
;
const
params
=
{
startDate
:
dateRange
.
value
&&
dateRange
.
value
[
0
]
?
dateRange
.
value
[
0
]
:
''
,
endDate
:
dateRange
.
value
&&
dateRange
.
value
[
1
]
?
dateRange
.
value
[
1
]
:
''
,
typeName
:
"实体清单"
,
isCn
:
false
,
pageNum
:
currentPage
.
value
,
pageSize
:
pageSize
.
value
}
;
try
{
const
res
=
await
getDeepMiningSelect
(
params
);
if
(
res
.
code
===
200
&&
res
.
data
&&
res
.
data
.
content
)
{
sanctionList
.
value
=
res
.
data
.
content
.
map
(
item
=>
({
id
:
item
.
id
,
date
:
item
.
postDate
,
title
:
item
.
name
,
count
:
item
.
cnEntityCount
,
unit
:
'家中国实体'
,
// 接口未返回单位,暂时固定
summary
:
item
.
summary
,
// 保留额外信息备用
techDomainList
:
item
.
techDomainList
// 保留额外信息备用
}
));
// 默认选中第一条
if
(
sanctionList
.
value
.
length
>
0
)
{
currentSanctionId
.
value
=
sanctionList
.
value
[
0
].
id
;
// getFishboneData(); // 这里不需要调用,因为getIndustryList会调用
}
}
else
{
sanctionList
.
value
=
[];
}
}
catch
(
error
)
{
console
.
error
(
"获取选择制裁数据失败:"
,
error
);
sanctionList
.
value
=
[];
}
finally
{
loading
.
value
=
false
;
}
}
const
dateRange
=
ref
([
"2025-01-01"
,
"2025-12-31"
]);
const
sanctionList
=
ref
([
{
id
:
1
,
date
:
"2025年2月8日"
,
title
:
"实体清单更新"
,
count
:
2
,
unit
:
"家中国实体"
}
,
{
id
:
2
,
date
:
"2025年4月10日"
,
title
:
"实体清单更新"
,
count
:
5
,
unit
:
"家中国实体"
}
,
{
id
:
3
,
date
:
"2025年6月29日"
,
title
:
"实体清单更新"
,
count
:
6
,
unit
:
"家中国实体"
}
,
{
id
:
4
,
date
:
"2025年8月12日"
,
title
:
"实体清单更新"
,
count
:
24
,
unit
:
"家中国实体"
}
,
{
id
:
5
,
date
:
"2025年8月19日"
,
title
:
"实体清单更新"
,
count
:
11
,
unit
:
"家中国实体"
}
,
{
id
:
6
,
date
:
"2025年9月12日"
,
title
:
"实体清单更新"
,
count
:
3
,
unit
:
"家中国实体"
}
,
{
id
:
7
,
date
:
"2025年9月26日"
,
title
:
"实体清单更新"
,
count
:
6
,
unit
:
"家中国实体"
}
,
{
id
:
8
,
date
:
"2025年10月12日"
,
title
:
"实体清单更新"
,
count
:
18
,
unit
:
"家中国实体"
}
]);
const
currentSanctionId
=
ref
(
5
);
// 格式化比率
const
formatRate
=
(
rate
,
ratio
=
false
)
=>
{
if
(
!
rate
)
return
'0.00'
;
return
(
rate
*
100
).
toFixed
(
2
);
const
formatRate
=
(
item
,
key
)
=>
{
if
(
!
item
[
key
]
||
!
item
.
total
)
return
"0.00"
return
(
item
[
key
]
*
100
/
item
.
total
).
toFixed
(
2
)
}
;
onMounted
(()
=>
{
// 获取选择制裁
getDeepMiningSelectData
();
// 获取产业链信息
getIndustryList
();
}
);
<
/script
>
<
style
scoped
lang
=
"scss"
>
...
...
@@ -327,14 +183,6 @@ onMounted(() => {
align
-
items
:
center
;
justify
-
content
:
center
;
overflow
:
hidden
;
.
main
-
mask
{
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
100
%
;
height
:
100
%
;
z
-
index
:
3
;
}
.
fishbone
-
container
{
position
:
relative
;
...
...
@@ -344,52 +192,25 @@ onMounted(() => {
background
:
rgb
(
230
,
231
,
232
);
display
:
flex
;
justify
-
content
:
space
-
between
;
align
-
items
:
center
;
// 添加中间的文字块
.
main
-
line
-
text
{
top
:
-
16
px
;
position
:
absolute
;
// top: -14px;
font
-
size
:
16
px
;
color
:
#
055
FC2
;
font
-
weight
:
bold
;
background
-
color
:
#
f7f8f9
;
padding
:
0
10
px
;
z
-
index
:
2
;
// 箭头背景
height
:
32
px
;
line
-
height
:
32
px
;
width
:
160
px
;
text
-
align
:
center
;
background
:
rgba
(
231
,
243
,
255
,
1
);
clip
-
path
:
polygon
(
0
%
0
%
,
90
%
0
%
,
100
%
50
%
,
90
%
100
%
,
0
%
100
%
,
10
%
50
%
);
&
.
blue
-
theme
{
background
:
rgba
(
231
,
243
,
255
,
1
);
color
:
rgba
(
22
,
119
,
255
,
1
);
}
&
.
green
-
theme
{
background
:
rgba
(
225
,
255
,
251
,
1
);
color
:
rgba
(
19
,
168
,
168
,
1
);
}
&
.
purple
-
theme
{
background
:
rgba
(
246
,
235
,
255
,
1
);
color
:
rgba
(
146
,
84
,
222
,
1
);
}
}
}
}
.
company
-
icon
{
width
:
16
px
;
height
:
16
px
;
margin
:
0
4
px
;
object
-
fit
:
contain
;
}
.
top
-
bone
{
position
:
absolute
;
bottom
:
0
px
;
...
...
@@ -409,31 +230,6 @@ onMounted(() => {
display
:
flex
;
flex
-
direction
:
column
;
justify
-
content
:
flex
-
end
;
.
left
-
bone
-
item
{
transform
:
skew
(
-
30
deg
);
height
:
40
px
;
margin
:
4
px
0
;
display
:
flex
;
justify
-
content
:
flex
-
end
;
align
-
items
:
center
;
.
text
{
margin
-
left
:
4
px
;
height
:
25
px
;
line
-
height
:
25
px
;
overflow
:
hidden
;
text
-
overflow
:
ellipsis
;
white
-
space
:
nowrap
;
}
.
line
{
margin
-
left
:
7
px
;
width
:
40
px
;
height
:
2
px
;
background
:
rgb
(
230
,
231
,
232
);
}
}
}
.
right
-
bone
{
...
...
@@ -446,32 +242,6 @@ onMounted(() => {
display
:
flex
;
flex
-
direction
:
column
;
justify
-
content
:
flex
-
end
;
.
right
-
bone
-
item
{
transform
:
skew
(
-
30
deg
);
height
:
40
px
;
margin
:
4
px
0
;
display
:
flex
;
justify
-
content
:
flex
-
start
;
align
-
items
:
center
;
.
line
{
margin
-
right
:
7
px
;
width
:
30
px
;
height
:
2
px
;
background
:
rgb
(
230
,
231
,
232
);
}
.
text
{
max
-
width
:
100
px
;
margin
-
right
:
4
px
;
height
:
25
px
;
line
-
height
:
25
px
;
overflow
:
hidden
;
text
-
overflow
:
ellipsis
;
white
-
space
:
nowrap
;
}
}
}
}
...
...
@@ -494,32 +264,6 @@ onMounted(() => {
display
:
flex
;
flex
-
direction
:
column
;
justify
-
content
:
flex
-
start
;
.
left
-
bone
-
item
{
transform
:
skew
(
30
deg
);
height
:
40
px
;
margin
:
4
px
0
;
display
:
flex
;
justify
-
content
:
flex
-
end
;
align
-
items
:
center
;
.
text
{
margin
-
left
:
4
px
;
height
:
25
px
;
max
-
width
:
130
px
;
line
-
height
:
25
px
;
overflow
:
hidden
;
text
-
overflow
:
ellipsis
;
white
-
space
:
nowrap
;
}
.
line
{
margin
-
left
:
7
px
;
width
:
40
px
;
height
:
2
px
;
background
:
rgb
(
230
,
231
,
232
);
}
}
}
.
right
-
bone
{
...
...
@@ -532,34 +276,71 @@ onMounted(() => {
display
:
flex
;
flex
-
direction
:
column
;
justify
-
content
:
flex
-
start
;
}
}
.
right
-
bone
-
item
{
transform
:
skew
(
30
deg
);
height
:
40
px
;
margin
:
4
px
0
;
display
:
flex
;
justify
-
content
:
flex
-
start
;
align
-
items
:
center
;
.
line
{
margin
-
right
:
7
px
;
width
:
30
px
;
height
:
2
px
;
background
:
rgb
(
230
,
231
,
232
);
.
bone
-
item
-
box
{
transform
:
skew
(
30
deg
);
height
:
40
px
;
margin
:
4
px
0
;
display
:
flex
;
align
-
items
:
center
;
.
bone
-
item
-
line
{
width
:
30
px
;
height
:
2
px
;
background
:
rgb
(
230
,
231
,
232
);
}
.
bone
-
item
-
word
{
display
:
flex
;
align
-
items
:
center
;
height
:
30
px
;
display
:
flex
;
align
-
items
:
center
;
gap
:
8
px
;
padding
:
0
8
px
;
.
bone
-
item
-
icon
{
width
:
16
px
;
height
:
16
px
;
font
-
size
:
0
px
;
position
:
relative
;
&
::
after
{
content
:
""
;
position
:
absolute
;
top
:
0
px
;
left
:
0
px
;
width
:
100
%
;
height
:
100
%
;
}
.
text
{
max
-
width
:
100
px
;
margin
-
right
:
4
px
;
height
:
25
px
;
line
-
height
:
25
px
;
overflow
:
hidden
;
text
-
overflow
:
ellipsis
;
white
-
space
:
nowrap
;
img
{
width
:
100
%
;
height
:
100
%
;
object
-
fit
:
contain
;
}
}
.
bone
-
item
-
text
{
max
-
width
:
100
px
;
line
-
height
:
14
px
;
font
-
size
:
14
px
;
}
}
}
.
bone
-
item
-
back
{
background
-
color
:
#
FFF1F0
;
border
:
1
px
solid
var
(
--
color
-
red
-
100
);
border
-
radius
:
4
px
;
}
.
bone
-
item
-
start
{
justify
-
content
:
flex
-
start
;
}
.
bone
-
item
-
end
{
justify
-
content
:
flex
-
end
;
}
.
bone
-
item
-
top
{
transform
:
skew
(
-
30
deg
);
}
.
bone
-
item
-
down
{
transform
:
skew
(
30
deg
);
}
}
.
main
-
content
-
footer
{
...
...
@@ -609,25 +390,19 @@ onMounted(() => {
}
}
}
}
.
footer
-
item1
{
color
:
rgba
(
22
,
119
,
255
,
1
);
.
footer
-
item
-
top
{
background
:
rgba
(
231
,
243
,
255
,
1
);
}
}
.
footer
-
item2
{
color
:
rgba
(
19
,
168
,
168
,
1
);
.
footer
-
item
-
top
{
background
:
rgba
(
225
,
255
,
251
,
1
);
}
}
.
footer
-
item3
{
color
:
rgba
(
146
,
84
,
222
,
1
);
.
footer
-
item
-
top
{
background
:
rgba
(
246
,
235
,
255
,
1
);
}
}
.
blue
-
theme
{
background
:
rgba
(
231
,
243
,
255
,
1
);
color
:
rgba
(
22
,
119
,
255
,
1
);
}
.
green
-
theme
{
background
:
rgba
(
225
,
255
,
251
,
1
);
color
:
rgba
(
19
,
168
,
168
,
1
);
}
.
purple
-
theme
{
background
:
rgba
(
246
,
235
,
255
,
1
);
color
:
rgba
(
146
,
84
,
222
,
1
);
}
}
<
/style>
\ No newline at end of file
src/views/decree/decreeLayout/influence/fishbone.vue
deleted
100644 → 0
浏览文件 @
a99df1de
<
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
浏览文件 @
f8cfb724
...
...
@@ -5,25 +5,25 @@
<div
class=
"box1-main"
>
<div
class=
"data-filter"
>
<div
class=
"filter-select"
>
<el-select
v-model=
"
curAreaId"
:empty-values=
"[null, undefined]"
style=
"width:
100%"
>
<el-select
v-model=
"
areaInfo.id"
:empty-values=
"[null, undefined]"
@
change=
"onDecreeEntities()"
style=
"width:
100%"
>
<el-option
label=
"全部领域"
value=
""
/>
<el-option
v-for=
"item in area
L
ist"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
<el-option
v-for=
"item in area
Info.l
ist"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
/>
</el-select>
</div>
<div
class=
"filter-input"
>
<el-input
v-model=
"
commandWord"
@
keyup
.
enter=
"handleSearch"
style=
"width: 100%; height: 100%;
"
:suffix-icon=
"Search"
placeholder=
"搜索实体"
/>
<el-input
v-model=
"
entityInfo.keyword"
@
keyup
.
enter=
"onDecreeEntities()
"
:suffix-icon=
"Search"
placeholder=
"搜索实体"
/>
</div>
</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=
"!
entityInfo.list?.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)">
<div
class=
"list-item"
v-for=
"item in
entityInfo.list"
:key=
"item.id"
:class=
"
{ 'item-active': entityInfo.id==item.id }" @click="headerChartData
(item)">
<div
class=
"item-icon"
>
<img
:src=
"defaultIcon2"
alt=
""
class=
"item-img"
/>
</div>
<div
class=
"item-name one-line-ellipsis"
>
{{
item
.
n
ame
}}
</div>
<div
class=
"item-name one-line-ellipsis"
>
{{
item
.
companyN
ame
}}
</div>
<div
class=
"item-icon item-icon-tag"
>
<img
:src=
"noticeIcon"
alt=
""
class=
"item-img"
/>
</div>
...
...
@@ -33,16 +33,16 @@
</el-scrollbar>
</div>
<div
class=
"pagination-info"
>
<div
class=
"pagination-left"
>
{{
`共 ${
companyTotalNum
}
家企业`
}}
<
/div
>
<div
class=
"pagination-left"
>
{{
`共 ${
entityInfo.total
}
家企业`
}}
<
/div
>
<
div
class
=
"pagination-right"
>
<
el
-
pagination
@
current
-
change
=
"
handleCurrentChange
"
:
pageSize
=
"pageSize"
:
current
-
page
=
"
currentPage
"
@
current
-
change
=
"
onDecreeEntities
"
:
pageSize
=
"
entityInfo.
pageSize"
:
current
-
page
=
"
entityInfo.pageNum
"
background
layout
=
"prev, pager, next"
size
=
"small"
:
total
=
"
companyTotalNum
"
:
total
=
"
entityInfo.total
"
/>
<
/div
>
<
/div
>
...
...
@@ -68,9 +68,8 @@
<
/div
>
<
/div
>
<
div
class
=
"title-right"
v
-
if
=
"contentType==1"
>
<
el
-
select
v
-
model
=
"curAreaId"
:
empty
-
values
=
"[null, undefined]"
style
=
"width: 100%"
>
<
el
-
option
label
=
"全部领域"
value
=
""
/>
<
el
-
option
v
-
for
=
"item in areaList"
:
key
=
"item.id"
:
label
=
"item.name"
:
value
=
"item.id"
/>
<
el
-
select
v
-
model
=
"industryChain.id"
style
=
"width: 100%"
@
change
=
"onDecreeChainNodes"
>
<
el
-
option
v
-
for
=
"item in industryChain.list"
:
key
=
"item.id"
:
label
=
"item.name"
:
value
=
"item.id"
/>
<
/el-select
>
<
/div
>
<
/div
>
...
...
@@ -78,10 +77,10 @@
<
div
class
=
"box2-main"
>
<
AiTips
:
tips
=
"tips"
/>
<
div
class
=
"graph-box"
v
-
if
=
"contentType==1"
>
<
ChartChain
/>
<
ChartChain
:
listData
=
"fishbone.list"
:
baseData
=
"fishbone.base"
/>
<
/div
>
<
div
class
=
"graph-box"
v
-
if
=
"contentType==2"
>
<
GraphChart
:
nodes
=
"
testData.nodes"
:
links
=
"testData
.links"
layoutType
=
"force"
/>
<
div
class
=
"graph-box"
v
-
if
=
"contentType==2
&& graphInfo.nodes.length
"
>
<
GraphChart
:
nodes
=
"
graphInfo.nodes"
:
links
=
"graphInfo
.links"
layoutType
=
"force"
/>
<
/div
>
<
/div
>
<
/AnalysisBox
>
...
...
@@ -90,13 +89,16 @@
<
/template
>
<
script
setup
>
import
{
ref
,
onMounted
}
from
"vue"
;
import
setChart
from
"@/utils/setChart
"
;
import
{
ref
,
onMounted
,
reactive
}
from
"vue"
;
import
{
useRoute
}
from
"vue-router
"
;
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
,
getDecreeEntities
,
getDecreeRelatedChain
,
getDecreeChainNodes
,
getDecreeRelatedEntitie
}
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,319 +109,197 @@ 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
}
`
}
,
],
const
route
=
useRoute
();
// 关系数据
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
tips
=
"这项政令标志着中美AI竞争进入一个新阶段,其核心特征是 “精准封锁”与“体系输出”相结合。它短期内无疑会给中国AI产业链带来压力,但长期看,这场竞争更可能是一场围绕技术路线、生态系统和治理规则的持久战。"
// 受影响实体
const
companyList
=
ref
([]);
const
activeEntityId
=
ref
(
1
);
const
currentPage
=
ref
(
1
);
const
pageSize
=
ref
(
10
);
const
handleToCompanyDetail
=
(
item
)
=>
{
activeEntityId
.
value
=
item
.
id
;
}
;
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
:
4
,
name
:
"深圳市"
,
status
:
"上市"
}
,
{
id
:
5
,
name
:
"成都市"
,
status
:
"上市"
}
,
{
id
:
7
,
name
:
"天津市"
,
status
:
"上市"
}
,
{
id
:
9
,
name
:
"武汉市"
,
status
:
"上市"
}
,
{
id
:
10
,
name
:
"西安市"
,
status
:
"上市"
}
,
]);
const
handleGetCompanyListByArea
=
async
()
=>
{
const
params
=
{
id
:
curAreaId
.
value
}
;
// 行业领域
const
areaInfo
=
reactive
({
list
:
[],
id
:
""
,
}
)
const
handleGetHylyList
=
async
()
=>
{
try
{
const
res
=
await
getDecreeCompany
(
params
);
console
.
log
(
"行业领域公司列表"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
companyList
.
value
=
res
.
data
.
map
(
item
=>
{
return
{
name
:
item
.
name
,
id
:
item
.
id
,
status
:
item
.
marketChange
}
;
}
);
companyTotalNum
.
value
=
companyList
.
value
.
length
;
if
(
res
.
data
?.
length
)
handleToCompanyDetail
(
res
.
data
[
0
])
}
else
{
companyList
.
value
=
[];
companyTotalNum
.
value
=
0
;
const
res
=
await
getDecreehylyList
();
console
.
log
(
"行业领域:"
,
res
);
if
(
res
.
code
===
200
)
{
areaInfo
.
list
=
res
.
data
||
[];
}
}
catch
(
error
)
{
companyList
.
value
=
[];
companyTotalNum
.
value
=
0
;
areaInfo
.
list
=
[];
}
}
;
// 指令搜索
const
commandWord
=
ref
(
""
);
const
handleSearch
=
()
=>
{
}
;
// 行业领域
const
curAreaId
=
ref
(
""
);
const
areaList
=
ref
([]);
const
handleGetHylyList
=
async
()
=>
{
// 受影响实体
const
entityInfo
=
reactive
({
keyword
:
""
,
pageSize
:
10
,
pageNum
:
1
,
total
:
0
,
list
:
[],
id
:
''
,
node
:
{
id
:
''
,
companyName
:
''
}
,
}
)
const
onDecreeEntities
=
async
(
page
=
1
)
=>
{
entityInfo
.
pageNum
=
page
;
try
{
const
res
=
await
getDecreehylyList
();
console
.
log
(
"行业领域列表"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
areaList
.
value
=
res
.
data
;
handleGetChainId
();
let
params
=
{
id
:
route
.
query
.
id
,
pageSize
:
entityInfo
.
pageSize
,
pageNum
:
entityInfo
.
pageNum
-
1
,
keyword
:
entityInfo
.
keyword
,
domainId
:
areaInfo
.
id
||
undefined
}
const
res
=
await
getDecreeEntities
(
params
);
console
.
log
(
"受影响实体:"
,
res
);
if
(
res
.
code
===
200
)
{
entityInfo
.
list
=
res
.
data
.
companyInfos
;
entityInfo
.
total
=
res
.
data
.
total
;
if
(
entityInfo
.
total
&&
entityInfo
.
list
.
every
(
item
=>
item
.
id
!=
entityInfo
.
id
))
{
headerChartData
(
entityInfo
.
list
[
0
])
}
}
}
catch
(
error
)
{
}
}
catch
(
error
)
{
console
.
log
(
"获取受影响实体失败"
,
error
);
}
}
;
// 产业链/实体关系
const
contentType
=
ref
(
1
);
const
headerContentType
=
(
type
)
=>
{
contentType
.
value
=
type
;
headerChartData
(
entityInfo
.
node
)
}
;
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
headerChartData
=
(
row
)
=>
{
entityInfo
.
id
=
row
.
id
;
entityInfo
.
node
=
row
;
industryChain
.
id
=
""
;
fishbone
.
list
=
[]
fishbone
.
base
=
[]
graphInfo
.
nodes
=
[];
graphInfo
.
links
=
[];
switch
(
contentType
.
value
)
{
case
1
:
onDecreeRelatedChain
(
row
.
id
)
break
;
case
2
:
onDecreeRelatedEntitie
(
row
.
id
)
break
;
}
}
;
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
()
=>
{
// 产业链
const
industryChain
=
reactive
({
list
:
[],
id
:
""
,
}
)
const
onDecreeRelatedChain
=
async
(
id
)
=>
{
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
}
))
}
;
const
res
=
await
getDecreeRelatedChain
({
id
}
);
console
.
log
(
"产业链:"
,
res
);
if
(
res
.
code
===
200
)
{
industryChain
.
list
=
res
.
data
;
if
(
industryChain
.
list
.
length
)
onDecreeChainNodes
(
industryChain
.
list
[
0
].
id
)
}
}
catch
(
error
)
{
console
.
log
(
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
}
;
// 产业链鱼骨图
const
fishbone
=
reactive
({
list
:
[],
base
:
[],
}
)
const
onDecreeChainNodes
=
async
(
id
)
=>
{
industryChain
.
id
=
id
;
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
;
const
res
=
await
getDecreeChainNodes
({
id
}
);
console
.
log
(
"产业链鱼骨图:"
,
res
);
if
(
res
.
code
===
200
)
{
let
obj
=
res
.
data
.
chains
.
reduce
((
result
,
item
)
=>
{
result
[
'chain-'
+
item
.
id
]
=
{...
item
,
children
:
[]
}
;
return
result
;
}
,
{
}
);
res
.
data
.
children
.
forEach
(
item
=>
{
if
(
item
.
companyId
==
entityInfo
.
id
)
{
obj
[
'chain-'
+
item
.
chainId
].
children
.
push
({
...
item
,
back
:
true
}
)
}
else
if
(
obj
[
'chain-'
+
item
.
chainId
]?.
children
?.
length
<
10
)
{
obj
[
'chain-'
+
item
.
chainId
].
children
.
push
(
item
)
}
}
)
fishbone
.
list
=
Object
.
values
(
obj
);
console
.
log
(
"fishbone.list:"
,
fishbone
.
list
);
fishbone
.
base
=
res
.
data
.
levelInfos
.
map
((
item
,
index
)
=>
{
return
{...
item
,
name
:
[
'上游'
,
'中游'
,
'下游'
][
index
]
}
}
);
}
else
{
chart1Data
.
value
.
title
=
[];
chart1Data
.
value
.
value
=
[];
}
}
catch
(
error
)
{
chart1Data
.
value
.
title
=
[];
chart1Data
.
value
.
value
=
[];
console
.
log
(
"获取产业链鱼骨图失败"
,
error
);
}
}
;
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
// 实体关系
const
graphInfo
=
reactive
({
nodes
:
[],
links
:
[],
}
);
// 根据chainId获取chainInfo
const
handleGetChainInfoByChainId
=
async
()
=>
{
const
onDecreeRelatedEntitie
=
async
(
id
)
=>
{
try
{
const
res
=
await
getCnEntityOnChain
(
chainId
.
value
);
console
.
log
(
"chainInfo"
,
res
);
if
(
res
)
{
chainInfo
.
value
=
res
;
const
res
=
await
getDecreeRelatedEntitie
({
id
}
);
console
.
log
(
"实体关系:"
,
res
);
if
(
res
.
code
===
200
)
{
graphInfo
.
links
=
res
.
data
.
map
(
onFormatLink
)
graphInfo
.
nodes
=
res
.
data
.
map
(
onFormatNode
)
graphInfo
.
nodes
.
unshift
(
onFormatNode
(
entityInfo
.
node
))
}
}
catch
(
error
)
{
console
.
log
(
"
chainInfo error
"
,
error
);
console
.
log
(
"
获取实体关系失败
"
,
error
);
}
}
;
}
const
onFormatLink
=
(
item
,
index
)
=>
{
return
{
id
:
`link-${index+1
}
`
,
source
:
item
.
id
+
''
,
target
:
entityInfo
.
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
==
entityInfo
.
id
;
return
{
id
:
item
.
id
+
''
,
name
:
onWordWrap
(
item
.
companyName
,
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
;
}
onMounted
(()
=>
{
// handleGetCompanyListByArea();
handleGetChart1Data
();
onDecreeEntities
();
handleGetHylyList
();
handelBox1
();
getSingleSanctionEntitySupplyChainRequest
()
}
);
<
/script
>
...
...
@@ -458,6 +338,11 @@ onMounted(() => {
box
-
shadow
:
0
0
0
1
px
var
(
--
el
-
border
-
color
)
inset
;
box
-
sizing
:
border
-
box
;
height
:
32
px
;
:
deep
(.
el
-
input
)
{
height
:
100
%
;
width
:
100
%
;
}
}
}
...
...
src/views/decree/decreeLayout/overview/index.vue
浏览文件 @
f8cfb724
...
...
@@ -79,7 +79,7 @@ onMounted(() => {
.left
{
position
:
absolute
;
left
:
-160px
;
top
:
0
px
;
top
:
25
px
;
width
:
160px
;
padding
:
0px
16px
;
}
...
...
src/views/decree/decreeLayout/overview/introduction/index.vue
浏览文件 @
f8cfb724
...
...
@@ -4,7 +4,7 @@
<WarnningPane
:warnningLevel=
"riskInfo.riskLevel"
:warnningContent=
"riskInfo.content"
/>
</div>
<div
class=
"introduction-wrap"
>
<div
class=
"left"
>
<div
class=
"
page-
left"
>
<div
class=
"box1"
>
<AnalysisBox
title=
"基本信息"
:showAllBtn=
"false"
>
<div
class=
"box1-main"
>
...
...
@@ -23,14 +23,10 @@
</div>
<div
class=
"item"
>
<div
class=
"item-left"
>
{{
"英文全称:"
}}
</div>
<div
class=
"item-right text"
v-if=
"basicInfo.eName?.length
<
60
"
>
{{
basicInfo
.
eName
}}
</div>
<div
class=
"item-right text"
v-if=
"basicInfo.eName?.length
<
60
"
>
{{
basicInfo
.
eName
}}
</div>
<el-popover
v-else
effect=
"dark"
:width=
"500"
:content=
"basicInfo.eName"
placement=
"top-start"
>
<template
#
reference
>
<div
class=
"item-right text"
>
{{
basicInfo
.
eName
}}
</div>
<div
class=
"item-right text"
>
{{
basicInfo
.
eName
}}
</div>
</
template
>
</el-popover>
</div>
...
...
@@ -66,7 +62,19 @@
</div>
</AnalysisBox>
</div>
<div
class=
"box2"
>
<div>
<AnalysisBox
title=
"报告内容摘要"
:showAllBtn=
"false"
>
<el-empty
v-if=
"false"
style=
"margin: 20px 0;"
description=
"暂无数据"
:image-size=
"100"
/>
<div
class=
"box5-main"
>
<AiSummary>
<
template
#
summary-content
>
<div
class=
"box5-text"
>
{{
box1Data
}}
</div>
</
template
>
</AiSummary>
</div>
</AnalysisBox>
</div>
<div>
<AnalysisBox
title=
"相关事件"
:showAllBtn=
"false"
>
<div
class=
"box2-main"
>
<el-empty
v-if=
"!relatedData.length"
description=
"暂无数据"
:image-size=
"100"
/>
...
...
@@ -80,18 +88,21 @@
<span
class=
"meta"
>
{{ item.sjsj }} · {{ item.source }}
</span>
</div>
<div
class=
"content"
>
{{ item.sjnr }}
</div>
<!-- <el-popover effect="dark" :width="1000" :content="item.content" placement="top-start">
<template #reference>
<div class="content">{{ item.content }}</div>
</template>
</el-popover> -->
</div>
</div>
</div>
</AnalysisBox>
</div>
</div>
<div
class=
"right"
>
<div
class=
"page-right"
>
<div
class=
"box4"
>
<AnalysisBox
title=
"政令关键词云"
:showAllBtn=
"false"
>
<div
class=
"box4-main"
>
<el-empty
v-if=
"!wordCloudData.length"
description=
"暂无数据"
:image-size=
"100"
/>
<WordCloudChart
v-if=
"wordCloudData.length"
:data=
"wordCloudData"
width=
"100%"
height=
"100%"
/>
</div>
</AnalysisBox>
</div>
<div
class=
"box3"
>
<AnalysisBox
title=
"发布机构"
:showAllBtn=
"false"
>
<div
class=
"box3-top"
>
...
...
@@ -151,12 +162,16 @@ import { ref, onMounted } from "vue";
import
{
useRoute
}
from
"vue-router"
;
import
router
from
"@/router"
;
import
WarnningPane
from
'@/components/base/WarningPane/index.vue'
import
WordCloudChart
from
"@/components/base/WordCloundChart/index.vue"
import
{
getDecreeBasicInfo
,
getDecreeRiskSignal
,
getDecreeIssueOrganization
getDecreeIssueOrganization
,
getKeyWordUp
,
getOverview
,
}
from
"@/api/decree/introduction"
;
import
{
getDecreeRelatedEvent
}
from
"@/api/decree/background"
;
import
AiSummary
from
'@/components/base/Ai/AiSummary/index.vue'
import
DefaultIcon1
from
"@/assets/icons/default-icon1.png"
;
import
DefaultIcon2
from
"@/assets/icons/default-icon2.png"
;
...
...
@@ -216,6 +231,30 @@ const handleGetBasicInfo = async () => {
};
handleGetBasicInfo
();
// 政令关键词云
const
wordCloudData
=
ref
([])
const
onKeyWordUp
=
async
()
=>
{
try
{
const
res
=
await
getKeyWordUp
();
console
.
log
(
"政令关键词云"
,
res
);
wordCloudData
.
value
=
res
.
data
.
slice
(
0
,
10
).
map
(
item
=>
({
name
:
item
.
name
,
value
:
item
.
count
}));
}
catch
(
error
)
{
console
.
error
(
"获取政令关键词云数据失败"
,
error
);
}
};
// 报告内容摘要
const
box1Data
=
ref
(
''
);
const
onOverview
=
async
()
=>
{
try
{
const
res
=
await
getOverview
({
id
:
decreeId
.
value
});
console
.
log
(
"报告内容摘要"
,
res
);
box1Data
.
value
=
res
.
data
;
}
catch
(
error
)
{
console
.
error
(
"获取报告内容摘要数据失败"
,
error
);
}
};
// 相关事件
const
relatedData
=
ref
([]);
const
handleGetRelateEvents
=
async
()
=>
{
...
...
@@ -304,6 +343,8 @@ const handleClickUser = item => {
};
onMounted
(()
=>
{
onOverview
()
onKeyWordUp
()
onRiskSignalData
()
handleGetRelateEvents
();
handleGetOrgnization
();
...
...
@@ -322,15 +363,15 @@ onMounted(() => {
width
:
100%
;
display
:
flex
;
.left
{
.
page-
left
{
display
:
flex
;
flex-direction
:
column
;
flex
:
auto
;
margin-right
:
16px
;
gap
:
16px
;
.box1
{
height
:
414px
;
.box1-main
{
display
:
flex
;
padding
:
0
24px
;
...
...
@@ -427,161 +468,183 @@ onMounted(() => {
}
}
.box2
{
margin-top
:
16px
;
height
:
420px
;
.box2-main
{
margin-top
:
3px
;
margin-left
:
31px
;
height
:
100%
;
width
:
1004px
;
overflow
:
hidden
;
overflow-y
:
auto
;
.box2-item
{
display
:
flex
;
height
:
60px
;
width
:
100%
;
margin-bottom
:
2px
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
margin-top
:
10px
;
.item-left
{
width
:
64px
;
height
:
48px
;
border-radius
:
2px
;
.box5-main
{
padding
:
0px
22px
22px
;
.box5-text
{
padding-bottom
:
20px
;
font-family
:
"Source Han Sans CN"
;
font-weight
:
400
;
font-size
:
16px
;
line-height
:
30px
;
min-height
:
300px
;
}
}
img
{
width
:
100%
;
height
:
100%
;
}
.box2-main
{
padding
:
0
22px
;
.box2-item
{
display
:
flex
;
height
:
60px
;
width
:
100%
;
margin-bottom
:
2px
;
border-bottom
:
1px
solid
rgba
(
240
,
242
,
244
,
1
);
margin-top
:
10px
;
.item-left
{
width
:
64px
;
height
:
48px
;
border-radius
:
2px
;
font-size
:
0px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.item-center
{
flex
:
auto
;
width
:
20px
;
margin-left
:
14px
;
.item-center
{
flex
:
auto
;
width
:
20px
;
margin-left
:
14px
;
.bubble-header
{
display
:
flex
;
align-items
:
center
;
cursor
:
pointer
;
.name
{
flex
:
auto
;
width
:
20px
;
color
:
rgb
(
59
,
65
,
75
);
font-family
:
"Source Han Sans CN"
;
font-size
:
16px
;
font-weight
:
700
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
&
:hover
{
text-decoration
:
underline
;
color
:
var
(
--
color-main-active
);
}
}
.bubble-header
{
display
:
flex
;
align-items
:
center
;
cursor
:
pointer
;
.meta
{
margin-left
:
10px
;
color
:
rgb
(
95
,
101
,
108
);
font-family
:
"Source Han Sans CN"
;
font-size
:
16px
;
font-weight
:
400
;
letter-spacing
:
0px
;
white-space
:
nowrap
;
.name
{
flex
:
auto
;
width
:
20px
;
color
:
rgb
(
59
,
65
,
75
);
font-family
:
"Source Han Sans CN"
;
font-size
:
16px
;
font-weight
:
700
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
&
:hover
{
text-decoration
:
underline
;
color
:
var
(
--
color-main-active
);
}
}
.content
{
width
:
100%
;
height
:
30px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
.meta
{
margin-left
:
10px
;
color
:
rgb
(
95
,
101
,
108
);
font-family
:
"Source Han Sans CN"
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
30px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
letter-spacing
:
0px
;
white-space
:
nowrap
;
}
}
}
}
.box2-footer
{
margin
:
20px
22px
;
display
:
fle
x
;
justify-content
:
space-between
;
.box2-footer-left
{
height
:
20px
;
color
:
rgba
(
132
,
136
,
142
,
1
)
;
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
20px
;
.content
{
width
:
100%
;
height
:
30p
x
;
color
:
rgba
(
59
,
65
,
75
,
1
)
;
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
30px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
.box2-footer
{
margin
:
20px
22px
;
display
:
flex
;
justify-content
:
space-between
;
.box2-footer-left
{
height
:
20px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
20px
;
}
}
}
.right
{
.page-right
{
display
:
flex
;
flex-direction
:
column
;
width
:
520px
;
flex
:
none
;
gap
:
16px
;
.box3
{
width
:
520px
;
height
:
100%
;
.box3-top
{
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
.box3-top-top
{
width
:
473px
;
height
:
88px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-radius
:
4px
;
background
:
rgba
(
247
,
248
,
249
,
1
);
display
:
flex
;
align-items
:
center
;
margin
:
0
auto
;
position
:
relative
;
cursor
:
pointer
;
.more
{
position
:
absolute
;
right
:
17px
;
top
:
17px
;
display
:
flex
;
gap
:
3px
;
.box4
{
height
:
414px
;
.box4-main
{
height
:
100%
;
}
}
.text
{
height
:
16px
;
color
:
rgba
(
5
,
95
,
194
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
16px
;
}
.box3-top
{
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
padding
:
0
22px
;
.icon
{
width
:
16px
;
height
:
16px
;
.box3-top-top
{
height
:
88px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
border-radius
:
4px
;
background
:
rgba
(
247
,
248
,
249
,
1
);
display
:
flex
;
align-items
:
center
;
margin
:
0
auto
;
position
:
relative
;
padding
:
0
16px
;
cursor
:
pointer
;
.left
{
width
:
64px
;
height
:
64px
;
font-size
:
0px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
img
{
width
:
100%
;
height
:
100%
;
}
}
.right
{
width
:
20px
;
flex
:
auto
;
margin-left
:
15px
;
.name
{
height
:
26px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
26px
;
}
.ename
{
margin-top
:
6px
;
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
}
}
}
.box3-top-bottom
{
height
:
193px
;
margin
:
0
auto
;
.left
{
width
:
64px
;
height
:
64px
;
margin-left
:
17px
;
.box3-top-bottom-header
{
height
:
40px
;
display
:
flex
;
padding-top
:
14px
;
box-sizing
:
border-box
;
gap
:
12px
;
.icon
{
margin-top
:
5px
;
width
:
14px
;
height
:
14px
;
img
{
width
:
100%
;
...
...
@@ -589,47 +652,41 @@ onMounted(() => {
}
}
.right
{
width
:
370px
;
margin-left
:
15px
;
.name
{
height
:
26px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
26px
;
}
.ename
{
margin-top
:
6px
;
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
}
.text
{
width
:
100px
;
height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Bold
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
24px
;
letter-spacing
:
1px
;
text-align
:
left
;
}
}
.box3-top-bottom
{
width
:
473px
;
height
:
193px
;
margin
:
0
auto
;
.box3-top-bottom-main
{
margin-top
:
2px
;
height
:
130px
;
overflow
:
hidden
;
overflow-y
:
auto
;
display
:
flex
;
flex-wrap
:
wrap
;
justify-content
:
space-between
;
.box3-top-bottom-header
{
height
:
40px
;
.box3-top-bottom-item
{
margin-top
:
12px
;
height
:
48px
;
width
:
200px
;
display
:
flex
;
padding-top
:
14px
;
box-sizing
:
border-box
;
gap
:
12px
;
justify-content
:
flex-start
;
.icon
{
margin-top
:
5px
;
width
:
14px
;
height
:
14px
;
.box3-top-bottom-item-left
{
width
:
48px
;
height
:
48px
;
border-radius
:
24px
;
overflow
:
hidden
;
img
{
width
:
100%
;
...
...
@@ -637,155 +694,102 @@ onMounted(() => {
}
}
.text
{
width
:
100px
;
height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Bold
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
24px
;
letter-spacing
:
1px
;
text-align
:
left
;
}
}
.box3-top-bottom-main
{
margin-top
:
2px
;
height
:
130px
;
overflow
:
hidden
;
overflow-y
:
auto
;
display
:
flex
;
flex-wrap
:
wrap
;
justify-content
:
space-between
;
.box3-top-bottom-item-right
{
margin-left
:
8px
;
width
:
144px
;
.box3-top-bottom-item
{
margin-top
:
12px
;
height
:
48px
;
width
:
200px
;
display
:
flex
;
justify-content
:
flex-start
;
.box3-top-bottom-item-left
{
width
:
48px
;
height
:
48px
;
border-radius
:
24px
;
overflow
:
hidden
;
img
{
width
:
100%
;
height
:
100%
;
}
.name
{
width
:
144px
;
height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Bold
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
24px
;
letter-spacing
:
0px
;
text-align
:
left
;
}
.
box3-top-bottom-item-right
{
margin-
left
:
8
px
;
.
position
{
margin-
top
:
1
px
;
width
:
144px
;
.name
{
width
:
144px
;
height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Bold
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
24px
;
letter-spacing
:
0px
;
text-align
:
left
;
}
.position
{
margin-top
:
1px
;
width
:
144px
;
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Regular
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
letter-spacing
:
0px
;
text-align
:
left
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Regular
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
24px
;
letter-spacing
:
0px
;
text-align
:
left
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
}
}
.box3-bottom
{
padding-right
:
22px
;
.box3-bottom-header
{
height
:
59px
;
display
:
flex
;
.box3-bottom
{
.box3-bottom-header
{
height
:
59px
;
display
:
flex
;
.header-icon
{
margin-left
:
22px
;
margin-top
:
27px
;
width
:
16px
;
height
:
16px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.header-icon
{
margin-left
:
22px
;
margin-top
:
27px
;
width
:
16px
;
height
:
16px
;
.header-title
{
margin-left
:
12px
;
margin-top
:
23px
;
height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
24px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.box3-bottom-main
{
width
:
510px
;
height
:
440px
;
overflow
:
hidden
;
overflow-y
:
auto
;
.header-title
{
margin-left
:
12px
;
margin-top
:
23px
;
height
:
24px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
700
;
line-height
:
24px
;
}
}
:deep
(
.el-timeline
)
{
padding
:
8px
0px
0px
25px
!
important
;
}
.box3-bottom-main
{
:deep
(
.el-timeline
)
{
padding
:
8px
0px
0px
25px
!
important
;
}
:deep
(
.el-timeline-item__node
)
{
border
:
4px
solid
var
(
--
color-main-active
)
!
important
;
background-color
:
#fff
;
}
:deep
(
.el-timeline-item__node
)
{
border
:
4px
solid
var
(
--
color-main-active
)
!
important
;
background-color
:
#fff
;
}
:deep
(
.el-timeline-item
)
{
padding-bottom
:
12px
!
important
;
}
:deep
(
.el-timeline-item
)
{
padding-bottom
:
12px
!
important
;
}
:deep
(
.el-timeline-item__timestamp
)
{
color
:
var
(
--
color-main-active
)
!
important
;
font-family
:
Microsoft
YaHei
!
important
;
font-size
:
16px
!
important
;
font-weight
:
600
!
important
;
padding-top
:
0px
!
important
;
}
:deep
(
.el-timeline-item__timestamp
)
{
color
:
var
(
--
color-main-active
)
!
important
;
font-family
:
Microsoft
YaHei
!
important
;
font-size
:
16px
!
important
;
font-weight
:
600
!
important
;
padding-top
:
0px
!
important
;
}
.timeline-content
{
color
:
var
(
--
text-primary-65-color
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
26px
;
display
:
-
webkit-box
;
-webkit-box-orient
:
vertical
;
-webkit-line-clamp
:
3
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
.timeline-content
{
color
:
var
(
--
text-primary-65-color
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
26px
;
}
}
}
...
...
src/views/decree/decreeOriginal/index.vue
浏览文件 @
f8cfb724
...
...
@@ -41,10 +41,11 @@ import { getDecreeReport } from "@/api/decree/introduction";
import
BaseDecreeOriginal
from
"@/components/base/DecreeOriginal/index.vue"
;
const
route
=
useRoute
();
let
pdfUrl
=
""
;
const
handleDownload
=
async
()
=>
{
if
(
summaryInfo
.
value
?.
u
rl
)
{
if
(
pdfU
rl
)
{
try
{
const
response
=
await
fetch
(
summaryInfo
.
value
.
u
rl
,
{
const
response
=
await
fetch
(
pdfU
rl
,
{
method
:
'GET'
,
headers
:
{
'Content-Type'
:
'application/pdf'
},
});
...
...
@@ -103,6 +104,7 @@ const handleGetReport = async () => {
const
res
=
await
getDecreeReport
({
id
:
route
.
query
.
id
});
console
.
log
(
"报告原文"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
pdfUrl
=
res
.
data
.
pdfUrl
;
const
originData
=
[];
let
num
=
Math
.
max
(
res
.
data
.
content
.
length
,
res
.
data
.
contentEn
.
length
)
for
(
let
i
=
0
;
i
<
num
;
i
++
)
{
...
...
vite.config.js
浏览文件 @
f8cfb724
...
...
@@ -47,16 +47,15 @@ export default defineConfig({
port
:
3000
,
open
:
true
,
proxy
:
{
'/reportData'
:
{
target
:
'http://8.140.26.4:10022/'
,
changeOrigin
:
true
,
rewrite
:
(
path
)
=>
path
.
replace
(
/^
\/
reportData/
,
''
)
},
'/api'
:
{
target
:
'http://8.140.26.4:9085/'
,
// target: 'http://192.168.0.6:28080/',
// target: 'http://192.168.0.4:28080/',
// target: 'http://172.20.10.3:28080/',
changeOrigin
:
true
,
rewrite
:
(
path
)
=>
path
.
replace
(
/^
\/
api/
,
''
)
},
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论