Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
8e14f2ea
提交
8e14f2ea
authored
3月 31, 2026
作者:
闫鹏
浏览文件
操作
浏览文件
下载
差异文件
合并分支 'yp-dev' 到 'pre'
Yp dev 查看合并请求
!291
上级
d072b507
506f41e6
流水线
#261
已通过 于阶段
in 6 分 10 秒
变更
17
流水线
1
隐藏空白字符变更
内嵌
并排
正在显示
17 个修改的文件
包含
1494 行增加
和
389 行删除
+1494
-389
exportControlV2.0.js
src/api/exportControlV2.0.js
+2
-2
index.js
src/api/finance/index.js
+2
-0
index.vue
src/components/base/GraphChart/index.vue
+51
-43
index.vue
src/views/exportControl/index.vue
+15
-12
charts.js
src/views/exportControl/utils/charts.js
+17
-1
index.vue
...ontrol/v2.0EntityList/components/dataStatistics/index.vue
+35
-9
index.vue
...s/sanctionsOverview/components/introductionPage/index.vue
+2
-2
index.vue
...ol/v2.0SingleSanction/components/dataStatistics/index.vue
+5
-5
RelationGraph.vue
...nction/components/deepMining/components/RelationGraph.vue
+175
-14
index.vue
...ontrol/v2.0SingleSanction/components/deepMining/index.vue
+170
-0
index.vue
...ents/impactAnalysis/components/industrialImpact/index.vue
+1
-1
index.vue
...onents/impactAnalysis/components/researchImpact/index.vue
+1
-1
index.vue
src/views/exportControl/v2.0SingleSanction/index.vue
+13
-3
index-back.vue
...xportControl/v2.0SingleSanction/originPage/index-back.vue
+271
-0
index.vue
...ews/exportControl/v2.0SingleSanction/originPage/index.vue
+216
-247
pdf.vue
...views/exportControl/v2.0SingleSanction/originPage/pdf.vue
+385
-0
index.vue
src/views/finance/index.vue
+133
-49
没有找到文件。
src/api/exportControlV2.0.js
浏览文件 @
8e14f2ea
...
@@ -292,10 +292,10 @@ export function getSingleSanctionOverviewList(data) {
...
@@ -292,10 +292,10 @@ export function getSingleSanctionOverviewList(data) {
* @param {string} params.sanRecordId - 制裁记录ID
* @param {string} params.sanRecordId - 制裁记录ID
* @header token
* @header token
*/
*/
export
function
getSingleSanctionTotalCount
(
i
d
)
{
export
function
getSingleSanctionTotalCount
(
sanTypeId
,
recordI
d
)
{
return
request
({
return
request
({
method
:
"GET"
,
method
:
"GET"
,
url
:
`/api/sanctionList/statistics/total?sanTypeId=
${
i
d
}
`
,
url
:
`/api/sanctionList/statistics/total?sanTypeId=
${
sanTypeId
}
&sanRecordId=
${
recordI
d
}
`
,
});
});
}
}
...
...
src/api/finance/index.js
0 → 100644
浏览文件 @
8e14f2ea
import
request
from
"@/api/request.js"
;
\ No newline at end of file
src/components/base/GraphChart/index.vue
浏览文件 @
8e14f2ea
<
template
>
<
template
>
<div
class=
"graph-chart-wrapper"
id=
"graph"
>
<div
class=
"graph-chart-wrapper"
id=
"graph"
></div>
</div>
</
template
>
</
template
>
<
script
setup
>
<
script
setup
>
import
{
onMounted
,
onBeforeUnmount
}
from
'vue'
;
import
{
onMounted
,
onBeforeUnmount
,
watch
}
from
"vue"
;
import
setChart
from
'@/utils/setChart'
;
import
setChart
from
"@/utils/setChart"
;
import
getGraphChart
from
'./graphChart'
;
import
getGraphChart
from
"./graphChart"
;
const
emits
=
defineEmits
([
"handleClickNode"
])
const
emits
=
defineEmits
([
"handleClickNode"
])
;
const
props
=
defineProps
({
const
props
=
defineProps
({
nodes
:
{
nodes
:
{
type
:
Array
,
type
:
Array
,
default
:
[]
default
:
[]
},
},
links
:
{
links
:
{
type
:
Array
,
type
:
Array
,
default
:
[]
default
:
[]
},
},
layoutType
:
{
layoutType
:
{
type
:
String
,
type
:
String
,
default
:
'force'
default
:
"force"
},
},
width
:
{
width
:
{
type
:
String
,
type
:
String
,
default
:
'force'
default
:
"force"
},
},
height
:
{
height
:
{
type
:
String
,
type
:
String
,
default
:
'force'
default
:
"force"
}
}
})
})
;
let
chart
=
null
let
chart
=
null
;
onMounted
(()
=>
{
onMounted
(()
=>
{
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
)
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
);
chart
=
setChart
(
graph
,
'graph'
)
chart
=
setChart
(
graph
,
"graph"
);
chart
.
on
(
"click"
,
(
event
)
=>
{
emits
(
"handleClickNode"
,
event
)
})
chart
.
on
(
"click"
,
event
=>
{
})
emits
(
"handleClickNode"
,
event
);
});
});
onBeforeUnmount
(()
=>
{
onBeforeUnmount
(()
=>
{
chart
.
off
(
"click"
)
chart
.
off
(
"click"
);
chart
.
dispose
()
chart
.
dispose
();
})
})
;
watch
(
()
=>
[
props
.
nodes
,
props
.
links
],
()
=>
{
if
(
chart
)
{
const
graph
=
getGraphChart
(
props
.
nodes
,
props
.
links
,
props
.
layoutType
);
chart
.
setOption
(
graph
,
true
);
}
},
{
deep
:
true
}
);
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.graph-chart-wrapper
{
.graph-chart-wrapper
{
width
:
100%
;
width
:
100%
;
height
:
100%
;
height
:
100%
;
// width: 800px;
// width: 800px;
// height: 500px;
// height: 500px;
}
}
</
style
>
</
style
>
\ No newline at end of file
src/views/exportControl/index.vue
浏览文件 @
8e14f2ea
...
@@ -77,7 +77,7 @@
...
@@ -77,7 +77,7 @@
<el-col
:span=
"16"
>
<el-col
:span=
"16"
>
<custom-container
titleType=
"primary"
title=
"最新出口管制政策"
:titleIcon=
"houseIcon"
height=
"450px"
>
<custom-container
titleType=
"primary"
title=
"最新出口管制政策"
:titleIcon=
"houseIcon"
height=
"450px"
>
<template
#
header-right
>
<template
#
header-right
>
<el-button
type=
"primary"
@
click=
"handleToEntityList
()
"
link
>
<el-button
type=
"primary"
@
click=
"handleToEntityList"
link
>
{{
"查看详情 >"
}}
{{
"查看详情 >"
}}
</el-button>
</el-button>
</
template
>
</
template
>
...
@@ -390,7 +390,7 @@
...
@@ -390,7 +390,7 @@
</custom-container>
</custom-container>
</el-col>
</el-col>
<el-col
:span=
"16"
>
<el-col
:span=
"16"
>
<custom-container
title=
"
实体
清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"540px"
>
<custom-container
title=
"
制裁
清单数量增长趋势"
:titleIcon=
"qushiIcon"
height=
"540px"
>
<
template
#
header-right
>
<
template
#
header-right
>
<div
style=
"display: flex; align-items: center; gap: 16px"
>
<div
style=
"display: flex; align-items: center; gap: 16px"
>
<el-checkbox
v-model=
"trendChecked"
label=
"50%规则"
size=
"large"
/>
<el-checkbox
v-model=
"trendChecked"
label=
"50%规则"
size=
"large"
/>
...
@@ -995,8 +995,6 @@ onMounted(async () => {
...
@@ -995,8 +995,6 @@ onMounted(async () => {
const
maxCountItem1
=
_
.
maxBy
(
cclList1
,
"count"
);
const
maxCountItem1
=
_
.
maxBy
(
cclList1
,
"count"
);
const
maxCountForList1
=
maxCountItem1
?
maxCountItem1
.
count
:
0
;
const
maxCountForList1
=
maxCountItem1
?
maxCountItem1
.
count
:
0
;
console
.
log
(
"shuju list"
,
list
);
console
.
log
(
"shuju total"
,
total
);
tableData1
.
value
=
_
.
map
(
list
,
item
=>
{
tableData1
.
value
=
_
.
map
(
list
,
item
=>
{
return
{
return
{
year
:
item
.
year
,
year
:
item
.
year
,
...
@@ -1053,7 +1051,7 @@ const fetchTrendData = async () => {
...
@@ -1053,7 +1051,7 @@ const fetchTrendData = async () => {
});
});
if
(
res
&&
res
[
0
]
&&
res
[
0
].
yearDomainCount
)
{
if
(
res
&&
res
[
0
]
&&
res
[
0
].
yearDomainCount
)
{
trendOption
.
value
=
processYearDomainCountData
(
res
[
0
].
yearDomainCount
);
trendOption
.
value
=
processYearDomainCountData
(
res
[
0
].
yearDomainCount
);
trendChart
.
interpret
({
type
:
"柱状图"
,
name
:
"
实体
清单数量增长趋势"
,
data
:
res
[
0
].
yearDomainCount
});
trendChart
.
interpret
({
type
:
"柱状图"
,
name
:
"
制裁
清单数量增长趋势"
,
data
:
res
[
0
].
yearDomainCount
});
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
"获取趋势图数据失败:"
,
error
);
console
.
error
(
"获取趋势图数据失败:"
,
error
);
...
@@ -1147,10 +1145,13 @@ const handleCarouselChange = index => {
...
@@ -1147,10 +1145,13 @@ const handleCarouselChange = index => {
// 跳转到V2.0单次制裁
// 跳转到V2.0单次制裁
const
handleToEntityList
=
item
=>
{
const
handleToEntityList
=
item
=>
{
console
.
log
(
"这是什么数据1 =>"
,
item
);
let
id
=
item
?.
id
;
let
id
=
item
?.
id
;
let
sanTypeId
=
item
?.
sanTypeId
||
1
;
if
(
!
id
)
{
if
(
!
id
)
{
const
currentItem
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
];
const
currentItem
=
entitiesDataInfoList
.
value
[
currentCarouselIndex
.
value
];
id
=
currentItem
?.
id
;
id
=
currentItem
?.
id
;
sanTypeId
=
currentItem
?.
sanTypeId
||
1
;
}
}
window
.
sessionStorage
.
setItem
(
window
.
sessionStorage
.
setItem
(
"curTabName"
,
"curTabName"
,
...
@@ -1159,7 +1160,8 @@ const handleToEntityList = item => {
...
@@ -1159,7 +1160,8 @@ const handleToEntityList = item => {
const
routeData
=
router
.
resolve
({
const
routeData
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
path
:
"/exportControl/singleSanction"
,
query
:
{
query
:
{
id
:
id
id
,
sanTypeId
}
}
});
});
// 打开一个新页面
// 打开一个新页面
...
@@ -1388,8 +1390,8 @@ const fetchSanctionList = async () => {
...
@@ -1388,8 +1390,8 @@ const fetchSanctionList = async () => {
const
tags
=
Array
.
isArray
(
item
.
techDomains
)
const
tags
=
Array
.
isArray
(
item
.
techDomains
)
?
item
.
techDomains
?
item
.
techDomains
:
item
.
techDomain
:
item
.
techDomain
?
[
item
.
techDomain
]
?
[
item
.
techDomain
]
:
item
.
techDomainList
||
[];
:
item
.
techDomainList
||
[];
const
fullTime
=
item
.
startTime
const
fullTime
=
item
.
startTime
?
formatAnyDateToChinese
(
item
.
startTime
)
?
formatAnyDateToChinese
(
item
.
startTime
)
...
@@ -1419,8 +1421,8 @@ const fetchSanctionList = async () => {
...
@@ -1419,8 +1421,8 @@ const fetchSanctionList = async () => {
countTag
:
item
.
cnEntityCount
countTag
:
item
.
cnEntityCount
?
`
${
item
.
cnEntityCount
}
家中国实体`
?
`
${
item
.
cnEntityCount
}
家中国实体`
:
item
.
ruleOrgCount
:
item
.
ruleOrgCount
?
`
${
item
.
ruleOrgCount
}
家关联实体`
?
`
${
item
.
ruleOrgCount
}
家关联实体`
:
item
.
countTag
||
""
:
item
.
countTag
||
""
};
};
});
});
totalAll
.
value
=
res
.
totalElements
;
totalAll
.
value
=
res
.
totalElements
;
...
@@ -2363,7 +2365,8 @@ const handleMediaClick = item => {
...
@@ -2363,7 +2365,8 @@ const handleMediaClick = item => {
overflow-y
:
auto
;
overflow-y
:
auto
;
.home-top-bg
{
.home-top-bg
{
background
:
url("./assets/images/background.png")
,
background
:
url("./assets/images/background.png")
,
linear-gradient
(
180deg
,
rgba
(
229
,
241
,
254
,
1
)
0%
,
rgba
(
246
,
251
,
255
,
0
)
30%
);
linear-gradient
(
180deg
,
rgba
(
229
,
241
,
254
,
1
)
0%
,
rgba
(
246
,
251
,
255
,
0
)
30%
);
background-size
:
100%
100%
;
background-size
:
100%
100%
;
position
:
absolute
;
position
:
absolute
;
...
@@ -3631,7 +3634,7 @@ const handleMediaClick = item => {
...
@@ -3631,7 +3634,7 @@ const handleMediaClick = item => {
width
:
100%
;
width
:
100%
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
22px
0
;
padding
:
22px
0
;
.data-origin-icon
{
.data-origin-icon
{
width
:
16px
;
width
:
16px
;
...
...
src/views/exportControl/utils/charts.js
浏览文件 @
8e14f2ea
import
*
as
echarts
from
"echarts"
;
import
*
as
echarts
from
"echarts"
;
import
chinaJson
from
"./China.json"
;
import
chinaJson
from
"./China.json"
;
import
_
from
"lodash"
;
import
_
from
"lodash"
;
import
{
name
}
from
"dayjs/locale/zh-cn"
;
//饼图
//饼图
export
function
getPieOption
(
data
,
title
)
{
export
function
getPieOption
(
data
,
title
)
{
let
option
=
{
let
option
=
{
...
@@ -1006,7 +1007,7 @@ export const getMultipleBarChart_m = object => {
...
@@ -1006,7 +1007,7 @@ export const getMultipleBarChart_m = object => {
margin
:
20
margin
:
20
},
},
axisLabel
:
{
axisLabel
:
{
formatter
:
"{value}
年
"
,
formatter
:
"{value}"
,
color
:
"rgba(95, 101, 108, 1)"
,
color
:
"rgba(95, 101, 108, 1)"
,
margin
:
20
margin
:
20
},
},
...
@@ -1022,6 +1023,21 @@ export const getMultipleBarChart_m = object => {
...
@@ -1022,6 +1023,21 @@ export const getMultipleBarChart_m = object => {
},
},
yAxis
:
{
yAxis
:
{
type
:
"value"
,
type
:
"value"
,
name
:
"数量"
,
nameLocation
:
"end"
,
nameGap
:
20
,
nameRotate
:
0
,
nameTextStyle
:
{
color
:
"#666"
,
fontFamily
:
"Microsoft YaHei"
,
fontWeight
:
400
,
fontSize
:
14
,
lineHeight
:
14
,
letterSpacing
:
0
,
align
:
"right"
,
verticalAlign
:
"bottom"
,
padding
:
[
0
,
8
,
0
,
0
]
},
splitNumber
:
5
,
splitNumber
:
5
,
alignTicks
:
false
,
alignTicks
:
false
,
axisLabel
:
{
axisLabel
:
{
...
...
src/views/exportControl/v2.0EntityList/components/dataStatistics/index.vue
浏览文件 @
8e14f2ea
...
@@ -105,7 +105,7 @@
...
@@ -105,7 +105,7 @@
</div>
</div>
</
template
>
</
template
>
<!-- <div class="echarts" ref="sanctionCountChartRef"></div> -->
<!-- <div class="echarts" ref="sanctionCountChartRef"></div> -->
<EChart
:option=
"sanctionCountChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<EChart
:option=
"sanctionCountChartOption"
autoresize
:style=
"{ height: '300px'
, padding: '0 20px'
}"
/>
<!-- <div class="bottom">
<!-- <div class="bottom">
<div class="ai">
<div class="ai">
<div class="left">
<div class="left">
...
@@ -186,7 +186,7 @@
...
@@ -186,7 +186,7 @@
</el-select>
</el-select>
</
template
>
</
template
>
<!-- <div class="echarts" ref="domainChartRef"></div> -->
<!-- <div class="echarts" ref="domainChartRef"></div> -->
<EChart
:option=
"domainChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<EChart
:option=
"domainChartOption"
autoresize
:style=
"{ height: '300px'
, padding: '0 20px'
}"
/>
<!-- <div class="bottom">
<!-- <div class="bottom">
<div class="ai">
<div class="ai">
<div class="left">
<div class="left">
...
@@ -218,7 +218,7 @@
...
@@ -218,7 +218,7 @@
</el-select>
</el-select>
</
template
>
</
template
>
<!-- <div class="echarts" ref="typeChartRef"></div> -->
<!-- <div class="echarts" ref="typeChartRef"></div> -->
<EChart
:option=
"typeChartOption"
autoresize
:style=
"{ height: '300px' }"
/>
<EChart
:option=
"typeChartOption"
autoresize
:style=
"{ height: '300px'
, padding: '0 20px'
}"
/>
<!-- <div class="bottom">
<!-- <div class="bottom">
<div class="ai">
<div class="ai">
<div class="left">
<div class="left">
...
@@ -717,8 +717,21 @@ const domainChartOption = ref({
...
@@ -717,8 +717,21 @@ const domainChartOption = ref({
width
:
1.1
width
:
1.1
}
}
},
},
labelLayout
:
{
labelLayout
:
function
(
params
)
{
hideOverlap
:
true
// hideOverlap: true
const
points
=
params
.
labelLinePoints
;
const
isLeft
=
params
.
labelRect
.
x
<
params
.
rect
.
x
+
params
.
rect
.
width
/
2
;
// 调整指示线终点到 label 垂直中心
const
labelCenterY
=
params
.
labelRect
.
y
+
params
.
labelRect
.
height
/
2
;
points
[
2
][
1
]
=
labelCenterY
;
// 调整指示线终点到 label 水平边缘
points
[
2
][
0
]
=
isLeft
?
params
.
labelRect
.
x
:
params
.
labelRect
.
x
+
params
.
labelRect
.
width
;
return
{
labelLinePoints
:
points
};
},
},
itemStyle
:
{
itemStyle
:
{
borderWidth
:
0
borderWidth
:
0
...
@@ -926,10 +939,23 @@ const typeChartOption = ref({
...
@@ -926,10 +939,23 @@ const typeChartOption = ref({
}
}
},
},
labelLayout
:
function
(
params
)
{
labelLayout
:
function
(
params
)
{
const
isLeft
=
params
.
labelRect
.
x
<
chart
.
getWidth
()
/
2
;
// const isLeft = params.labelRect.x
<
chart
.
getWidth
()
/
2
;
// const points = params.labelLinePoints;
// points[2][0] = isLeft ? params.labelRect.x : params.labelRect.x + params.labelRect.width;
// return {
// labelLinePoints: points
// };
const
points
=
params
.
labelLinePoints
;
const
points
=
params
.
labelLinePoints
;
// Update the end point.
const
isLeft
=
params
.
labelRect
.
x
<
params
.
rect
.
x
+
params
.
rect
.
width
/
2
;
// 调整指示线终点到 label 垂直中心
const
labelCenterY
=
params
.
labelRect
.
y
+
params
.
labelRect
.
height
/
2
;
points
[
2
][
1
]
=
labelCenterY
;
// 调整指示线终点到 label 水平边缘
points
[
2
][
0
]
=
isLeft
?
params
.
labelRect
.
x
:
params
.
labelRect
.
x
+
params
.
labelRect
.
width
;
points
[
2
][
0
]
=
isLeft
?
params
.
labelRect
.
x
:
params
.
labelRect
.
x
+
params
.
labelRect
.
width
;
return
{
return
{
labelLinePoints
:
points
labelLinePoints
:
points
};
};
...
@@ -1508,8 +1534,8 @@ onMounted(() => {
...
@@ -1508,8 +1534,8 @@ onMounted(() => {
width
:
100%
;
width
:
100%
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
22px
0
;
padding
:
22px
;
.data-origin-icon
{
.data-origin-icon
{
width
:
16px
;
width
:
16px
;
height
:
16px
;
height
:
16px
;
...
...
src/views/exportControl/v2.0EntityList/components/sanctionsOverview/components/introductionPage/index.vue
浏览文件 @
8e14f2ea
...
@@ -241,11 +241,11 @@ const handleClick = item => {
...
@@ -241,11 +241,11 @@ const handleClick = item => {
const
route
=
router
.
resolve
({
const
route
=
router
.
resolve
({
path
:
"/exportControl/singleSanction"
,
path
:
"/exportControl/singleSanction"
,
query
:
{
query
:
{
id
:
item
.
id
id
:
item
.
id
,
sanTypeId
:
item
.
sanTypeId
||
1
}
}
}
);
}
);
window
.
open
(
route
.
href
,
"_blank"
);
window
.
open
(
route
.
href
,
"_blank"
);
}
;
}
;
const
selectedDomain
=
ref
(
0
);
const
selectedDomain
=
ref
(
0
);
...
...
src/views/exportControl/v2.0SingleSanction/components/dataStatistics/index.vue
浏览文件 @
8e14f2ea
...
@@ -54,7 +54,7 @@
...
@@ -54,7 +54,7 @@
</div>
</div>
</div>
</div>
</div>
-->
</div>
-->
<EChart
:option=
"domainChartOption"
autoresize
:style=
"
{ height: '300px' }" />
<EChart
:option=
"domainChartOption"
autoresize
:style=
"
{ height: '300px'
, padding: '0 20px'
}" />
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
<img
:src=
"tipsIcon"
alt=
""
/>
...
@@ -104,7 +104,7 @@
...
@@ -104,7 +104,7 @@
</div>
</div>
</div>
</div>
</div>
-->
</div>
-->
<EChart
:option=
"typeChartOption"
autoresize
:style=
"
{ height: '300px' }" />
<EChart
:option=
"typeChartOption"
autoresize
:style=
"
{ height: '300px'
, padding: '0 20px'
}" />
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-box"
>
<div
class=
"data-origin-icon"
>
<div
class=
"data-origin-icon"
>
<img
:src=
"tipsIcon"
alt=
""
/>
<img
:src=
"tipsIcon"
alt=
""
/>
...
@@ -348,7 +348,7 @@ const totalCount = ref({});
...
@@ -348,7 +348,7 @@ const totalCount = ref({});
const
getTotalCount
=
async
()
=>
{
const
getTotalCount
=
async
()
=>
{
if
(
!
sanRecordId
.
value
)
return
;
if
(
!
sanRecordId
.
value
)
return
;
try
{
try
{
const
res
=
await
getSingleSanctionTotalCount
(
route
.
query
.
sanTypeId
);
const
res
=
await
getSingleSanctionTotalCount
(
route
.
query
.
sanTypeId
,
sanRecordId
.
value
);
if
(
res
.
code
===
200
)
{
if
(
res
.
code
===
200
)
{
totalCount
.
value
=
res
.
data
||
{};
totalCount
.
value
=
res
.
data
||
{};
}
}
...
@@ -1264,8 +1264,8 @@ onMounted(() => {
...
@@ -1264,8 +1264,8 @@ onMounted(() => {
width
:
100%
;
width
:
100%
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
22px
0
;
padding
:
22px
;
.data-origin-icon
{
.data-origin-icon
{
width
:
16px
;
width
:
16px
;
height
:
16px
;
height
:
16px
;
...
...
src/views/exportControl/v2.0SingleSanction/components/deepMining/components/RelationGraph.vue
浏览文件 @
8e14f2ea
...
@@ -107,22 +107,185 @@ const initGraph = (layoutType = 1) => {
...
@@ -107,22 +107,185 @@ const initGraph = (layoutType = 1) => {
});
});
};
};
// const initNormalGraph = (layoutType, width, height) => {
// const data = processGraphData(props.graphData);
// console.log("初始数据", props.graphData);
// if (!data.nodes || data.nodes.length === 0) return;
// const layout = {
// type: "none",
// center: [width / 2, height / 2],
// preventOverlap: true,
// nodeSpacing: 80,
// linkDistance: 250,
// nodeStrength: -800,
// edgeStrength: 0.1,
// collideStrength: 0.8,
// alphaDecay: 0.01,
// alphaMin: 0.001
// };
// graphInstance.value = new G6.Graph({
// container: containerRef.value,
// width,
// height,
// fitView: true,
// fitViewPadding: 100,
// fitCenter: true,
// animate: true,
// animateCfg: {
// duration: 300,
// easing: "easeLinear"
// },
// minZoom: 0.1,
// maxZoom: 10,
// modes: {
// default: [
// "drag-canvas",
// "zoom-canvas",
// "drag-node",
// {
// type: "activate-relations",
// trigger: "mouseenter",
// resetSelected: true
// }
// ]
// },
// layout,
// defaultNode: {
// type: "image",
// size: 40,
// clipCfg: {
// show: true,
// type: "circle",
// r: 20
// },
// labelCfg: {
// position: "bottom",
// offset: 10,
// style: {
// fill: "#333",
// fontSize: 11,
// fontFamily: "Microsoft YaHei",
// textAlign: "center",
// background: {
// fill: "rgba(255, 255, 255, 0.95)",
// padding: [4, 6, 4, 6],
// radius: 4
// }
// }
// }
// // 注意:节点边框样式在 processGraphData 中单独设置,不在这里设置
// },
// defaultEdge: {
// type: "quadratic",
// style: {
// stroke: "red",
// lineWidth: 3,
// opacity: 0.9,
// shadowColor: "rgba(231, 243, 255, 1)",
// shadowBlur: 4,
// endArrow: {
// path: "M 0,0 L 12,6 L 12,-6 Z",
// fill: "#5B8FF9"
// }
// },
// labelCfg: {
// autoRotate: true,
// style: {
// fill: "rgba(137, 193, 255, 1)",
// fontSize: 10,
// fontFamily: "Microsoft YaHei",
// background: {
// fill: "rgba(231, 243, 255, 1)",
// padding: [2, 4, 2, 4],
// radius: 5
// }
// }
// }
// },
// nodeStateStyles: {
// active: {
// shadowColor: "#1459BB",
// shadowBlur: 15,
// stroke: "#1459BB",
// lineWidth: 3
// },
// inactive: {
// opacity: 0.3
// }
// },
// edgeStateStyles: {
// active: {
// stroke: "#1459BB",
// lineWidth: 4
// },
// inactive: {
// opacity: 0.15
// }
// }
// });
// graphInstance.value.data(data);
// graphInstance.value.render();
// bindGraphEvents();
// };
const
initNormalGraph
=
(
layoutType
,
width
,
height
)
=>
{
const
initNormalGraph
=
(
layoutType
,
width
,
height
)
=>
{
const
data
=
processGraphData
(
props
.
graphData
);
const
data
=
processGraphData
(
props
.
graphData
);
console
.
log
(
"初始数据"
,
props
.
graphData
);
console
.
log
(
"初始数据"
,
props
.
graphData
);
if
(
!
data
.
nodes
||
data
.
nodes
.
length
===
0
)
return
;
if
(
!
data
.
nodes
||
data
.
nodes
.
length
===
0
)
return
;
// 中心节点坐标
const
centerX
=
width
/
2
;
const
centerY
=
height
/
2
;
const
upperY
=
centerY
-
240
;
// 上方节点 Y 坐标
const
lowerY
=
centerY
+
240
;
// 下方节点 Y 坐标
const
nodeSpacing
=
100
;
// 节点水平间距
// 分离中心节点和其他节点
const
centerNode
=
data
.
nodes
.
find
(
n
=>
n
.
isCenter
);
const
otherNodes
=
data
.
nodes
.
filter
(
n
=>
!
n
.
isCenter
);
const
totalNodes
=
otherNodes
.
length
;
const
upperCount
=
Math
.
ceil
(
totalNodes
/
2
);
// 向上取整,上方多一个
const
lowerCount
=
totalNodes
-
upperCount
;
// 为上方节点分配坐标
const
upperNodes
=
otherNodes
.
slice
(
0
,
upperCount
);
upperNodes
.
forEach
((
node
,
index
)
=>
{
const
totalWidth
=
(
upperCount
-
1
)
*
nodeSpacing
;
const
startX
=
centerX
-
totalWidth
/
2
;
node
.
x
=
startX
+
index
*
nodeSpacing
;
node
.
y
=
upperY
;
// 固定位置,防止力导向布局移动
node
.
fx
=
node
.
x
;
node
.
fy
=
node
.
y
;
});
// 为下方节点分配坐标
const
lowerNodes
=
otherNodes
.
slice
(
upperCount
);
lowerNodes
.
forEach
((
node
,
index
)
=>
{
const
totalWidth
=
(
lowerCount
-
1
)
*
nodeSpacing
;
const
startX
=
centerX
-
totalWidth
/
2
;
node
.
x
=
startX
+
index
*
nodeSpacing
;
node
.
y
=
lowerY
;
// 固定位置,防止力导向布局移动
node
.
fx
=
node
.
x
;
node
.
fy
=
node
.
y
;
});
// 设置中心节点坐标
if
(
centerNode
)
{
centerNode
.
x
=
centerX
;
centerNode
.
y
=
centerY
;
// 固定中心节点位置
centerNode
.
fx
=
centerX
;
centerNode
.
fy
=
centerY
;
}
const
layout
=
{
const
layout
=
{
type
:
"force"
,
type
:
"none"
,
// 使用预设坐标,不进行力导向布局
center
:
[
width
/
2
,
height
/
2
],
center
:
[
centerX
,
centerY
]
preventOverlap
:
true
,
nodeSpacing
:
80
,
linkDistance
:
250
,
nodeStrength
:
-
800
,
edgeStrength
:
0.1
,
collideStrength
:
0.8
,
alphaDecay
:
0.01
,
alphaMin
:
0.001
};
};
graphInstance
.
value
=
new
G6
.
Graph
({
graphInstance
.
value
=
new
G6
.
Graph
({
...
@@ -175,10 +338,9 @@ const initNormalGraph = (layoutType, width, height) => {
...
@@ -175,10 +338,9 @@ const initNormalGraph = (layoutType, width, height) => {
}
}
}
}
}
}
// 注意:节点边框样式在 processGraphData 中单独设置,不在这里设置
},
},
defaultEdge
:
{
defaultEdge
:
{
type
:
"
quadratic
"
,
type
:
"
line
"
,
style
:
{
style
:
{
stroke
:
"red"
,
stroke
:
"red"
,
lineWidth
:
3
,
lineWidth
:
3
,
...
@@ -230,7 +392,6 @@ const initNormalGraph = (layoutType, width, height) => {
...
@@ -230,7 +392,6 @@ const initNormalGraph = (layoutType, width, height) => {
graphInstance
.
value
.
render
();
graphInstance
.
value
.
render
();
bindGraphEvents
();
bindGraphEvents
();
};
};
const
initCircularGraph
=
(
width
,
height
)
=>
{
const
initCircularGraph
=
(
width
,
height
)
=>
{
const
data
=
processGraphData
(
props
.
graphData
);
const
data
=
processGraphData
(
props
.
graphData
);
...
@@ -307,7 +468,7 @@ const initCircularGraph = (width, height) => {
...
@@ -307,7 +468,7 @@ const initCircularGraph = (width, height) => {
}
}
},
},
defaultEdge
:
{
defaultEdge
:
{
type
:
"
quadratic
"
,
type
:
"
line
"
,
style
:
{
style
:
{
stroke
:
"#5B8FF9"
,
stroke
:
"#5B8FF9"
,
lineWidth
:
3
,
lineWidth
:
3
,
...
...
src/views/exportControl/v2.0SingleSanction/components/deepMining/index.vue
浏览文件 @
8e14f2ea
...
@@ -110,6 +110,7 @@
...
@@ -110,6 +110,7 @@
@
node-click=
"handleNodeClick"
@
node-click=
"handleNodeClick"
@
layout-change=
"handleLayoutChange"
@
layout-change=
"handleLayoutChange"
/>
/>
<!-- <GraphChart :nodes="nodes" :links="links" layoutType="none" /> -->
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -134,6 +135,7 @@ import {
...
@@ -134,6 +135,7 @@ import {
}
from
"@/api/exportControlV2.0"
;
}
from
"@/api/exportControlV2.0"
;
import
RelationGraph
from
"./components/RelationGraph.vue"
;
import
RelationGraph
from
"./components/RelationGraph.vue"
;
import
AnalysisBox
from
"@/components/base/boxBackground/analysisBox.vue"
;
import
AnalysisBox
from
"@/components/base/boxBackground/analysisBox.vue"
;
import
GraphChart
from
"@/components/base/GraphChart/index.vue"
;
const
sanRecordId
=
ref
(
""
);
const
sanRecordId
=
ref
(
""
);
const
activeTab
=
ref
([
"实体穿透分析"
]);
const
activeTab
=
ref
([
"实体穿透分析"
]);
...
@@ -157,6 +159,9 @@ const graphData = ref({ nodes: [], links: [] });
...
@@ -157,6 +159,9 @@ const graphData = ref({ nodes: [], links: [] });
const
treeData
=
ref
(
null
);
const
treeData
=
ref
(
null
);
const
selectedNode
=
ref
(
null
);
const
selectedNode
=
ref
(
null
);
const
nodes
=
ref
([]);
const
links
=
ref
([]);
const
singleSanctionEntityEquityData
=
ref
(
null
);
const
singleSanctionEntityEquityData
=
ref
(
null
);
const
singleSanctionEntitySupplyChainData
=
ref
(
null
);
const
singleSanctionEntitySupplyChainData
=
ref
(
null
);
const
singleSanctionEntityList
=
ref
([]);
const
singleSanctionEntityList
=
ref
([]);
...
@@ -204,6 +209,7 @@ const updateGraphData = () => {
...
@@ -204,6 +209,7 @@ const updateGraphData = () => {
const
data
=
const
data
=
rightActiveTab
.
value
===
"supplyChain"
?
singleSanctionEntitySupplyChainData
.
value
:
singleSanctionEntityEquityData
.
value
;
rightActiveTab
.
value
===
"supplyChain"
?
singleSanctionEntitySupplyChainData
.
value
:
singleSanctionEntityEquityData
.
value
;
console
.
log
(
"图谱数据 =>"
,
data
);
if
(
!
data
)
return
;
if
(
!
data
)
return
;
const
nodes
=
[];
const
nodes
=
[];
...
@@ -252,8 +258,172 @@ const updateGraphData = () => {
...
@@ -252,8 +258,172 @@ const updateGraphData = () => {
});
});
graphData
.
value
=
{
nodes
,
links
};
graphData
.
value
=
{
nodes
,
links
};
// nodes.value = nodes;
// links.value = links;
};
};
const
links1
=
[
{
source
:
1
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
2
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"持股"
}
},
{
source
:
3
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
4
,
target
:
7
,
lineStyle
:
{
type
:
"dashed"
,
color
:
"#d32f2f"
},
label
:
{
show
:
true
,
formatter
:
"从属"
}
},
{
source
:
5
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
6
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"持股"
}
},
{
source
:
0
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"持股"
}
},
{
source
:
8
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
9
,
target
:
7
,
lineStyle
:
{
type
:
"dashed"
,
color
:
"#d32f2f"
},
label
:
{
show
:
true
,
formatter
:
"从属"
}
},
{
source
:
10
,
target
:
7
,
lineStyle
:
{
type
:
"dashed"
,
color
:
"#d32f2f"
},
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
11
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
12
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
13
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
14
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
}
},
{
source
:
15
,
target
:
7
,
label
:
{
show
:
true
,
formatter
:
"合作"
,
color
:
"red"
,
borderColor
:
"red"
}
}
];
// const updateGraphData = () => {
// const data =
// rightActiveTab.value === "supplyChain" ? singleSanctionEntitySupplyChainData.value : singleSanctionEntityEquityData.value;
// console.log("图谱数据 =>", data);
// if (!data) return;
// const newNodes = [];
// const newLinks = [];
// // 容器尺寸(根据 .right-echarts 的高度 calc(100% - 56px) ≈ 772px)
// const containerWidth = 1000;
// const containerHeight = 700;
// // 中心节点坐标(居中)
// const centerX = containerWidth / 2;
// const centerY = containerHeight / 2;
// // 上下节点分布参数
// const upperY = centerY - 200; // 上方节点 Y 坐标
// const lowerY = centerY + 200; // 下方节点 Y 坐标
// const nodeSpacing = 100; // 节点水平间距
// // 合并所有节点列表(上游 + 下游)
// const allItems = [];
// const parentList = data.parentOrgList || [];
// const childList = data.childrenOrgList || [];
// // 添加上游节点
// parentList.forEach((item, index) => {
// allItems.push({
// ...item,
// linkType: rightActiveTab.value === "supplyChain" ? "供应商" : item.type || "持股",
// direction: "source" // 链接方向:指向中心节点
// });
// });
// // 添加下游节点
// childList.forEach((item, index) => {
// allItems.push({
// ...item,
// linkType: rightActiveTab.value === "supplyChain" ? "客户" : item.description || "投资",
// direction: "target" // 链接方向:从中心节点指出
// });
// });
// // 中心节点
// newNodes.push({
// id: 0,
// name: data.orgName || "中心节点",
// symbol: `image://${companyActive}`,
// symbolSize: 60,
// value: 10,
// isSanctioned: true,
// x: centerX,
// y: centerY
// });
// // 计算上下分配
// const totalNodes = allItems.length;
// const upperCount = Math.ceil(totalNodes / 2); // 向上取整,上方多一个
// const lowerCount = totalNodes - upperCount;
// // 上方节点(前一半)
// const upperItems = allItems.slice(0, upperCount);
// upperItems.forEach((item, index) => {
// const totalWidth = (upperCount - 1) * nodeSpacing;
// const startX = centerX - totalWidth / 2;
// const x = startX + index * nodeSpacing;
// const y = upperY;
// const nodeId = `n-${index}`;
// newNodes.push({
// id: nodeId,
// name: item.name || `节点${index}`,
// symbol: `image://${item.isSanctioned ? companyActive : company}`,
// symbolSize: 40,
// value: 5,
// isSanctioned: item.isSanctioned,
// x,
// y
// });
// // 根据 direction 决定链接方向
// if (item.direction === "source") {
// newLinks.push({
// source: nodeId,
// target: 0,
// name: item.linkType,
// label: { show: true, formatter: item.description }
// });
// } else {
// newLinks.push({
// source: 0,
// target: nodeId,
// name: item.linkType,
// label: { show: true, formatter: item.description }
// });
// }
// });
// // 下方节点(后一半)
// const lowerItems = allItems.slice(upperCount);
// lowerItems.forEach((item, index) => {
// const totalWidth = (lowerCount - 1) * nodeSpacing;
// const startX = centerX - totalWidth / 2;
// const x = startX + index * nodeSpacing;
// const y = lowerY;
// const nodeId = `n-${upperCount + index}`;
// newNodes.push({
// id: nodeId,
// name: item.name || `节点${upperCount + index}`,
// symbol: `image://${item.isSanctioned ? companyActive : company}`,
// symbolSize: 40,
// value: 5,
// isSanctioned: item.isSanctioned,
// x,
// y
// });
// // 根据 direction 决定链接方向
// if (item.direction === "source") {
// newLinks.push({
// source: nodeId,
// target: 0,
// name: item.linkType,
// label: { show: true, formatter: "{c}" }
// });
// } else {
// newLinks.push({
// source: 0,
// target: nodeId,
// name: item.linkType,
// label: { show: true, formatter: "{c}" }
// });
// }
// });
// console.log("最终节点数:", newNodes, "最终链接数:", newLinks, "上方节点:", upperCount, "下方节点:", lowerCount);
// // 更新响应式数据
// nodes.value = newNodes;
// links.value = newLinks;
// };
const
updateTreeData
=
data
=>
{
const
updateTreeData
=
data
=>
{
if
(
!
data
)
return
;
if
(
!
data
)
return
;
...
...
src/views/exportControl/v2.0SingleSanction/components/impactAnalysis/components/industrialImpact/index.vue
浏览文件 @
8e14f2ea
...
@@ -1317,7 +1317,7 @@ onMounted(async () => {
...
@@ -1317,7 +1317,7 @@ onMounted(async () => {
width
:
100%
;
width
:
100%
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
30px
0
;
padding
:
30px
0
;
.data-origin-icon
{
.data-origin-icon
{
width
:
16px
;
width
:
16px
;
...
...
src/views/exportControl/v2.0SingleSanction/components/impactAnalysis/components/researchImpact/index.vue
浏览文件 @
8e14f2ea
...
@@ -1543,7 +1543,7 @@ onBeforeUnmount(() => {
...
@@ -1543,7 +1543,7 @@ onBeforeUnmount(() => {
width
:
100%
;
width
:
100%
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
flex-start
;
padding
:
35px
0
;
padding
:
35px
0
;
.data-origin-icon
{
.data-origin-icon
{
width
:
16px
;
width
:
16px
;
...
...
src/views/exportControl/v2.0SingleSanction/index.vue
浏览文件 @
8e14f2ea
...
@@ -52,7 +52,7 @@
...
@@ -52,7 +52,7 @@
:close-on-click-modal=
"false"
:close-on-click-modal=
"false"
@
close=
"resetModal"
@
close=
"resetModal"
>
>
<div
class=
"sanction-list"
>
<div
class=
"sanction-list"
:loading=
"loading"
>
<div
<div
v-for=
"item in sanctionList"
v-for=
"item in sanctionList"
:key=
"item.id"
:key=
"item.id"
...
@@ -61,6 +61,7 @@
...
@@ -61,6 +61,7 @@
@click="selectSanction(item)"
@click="selectSanction(item)"
>
>
{{
item
.
name
}}
{{
item
.
name
}}
<div
class=
"sanction-type"
>
{{
item
.
postDate
}}
</div>
</div>
</div>
</div>
</div>
...
@@ -193,6 +194,7 @@ const handleAnalysisClick = () => {
...
@@ -193,6 +194,7 @@ const handleAnalysisClick = () => {
};
};
// ========== 新增响应式状态 ==========
// ========== 新增响应式状态 ==========
const
loading
=
ref
(
false
);
const
sanctionModalVisible
=
ref
(
false
);
const
sanctionModalVisible
=
ref
(
false
);
const
sanctionList
=
ref
([]);
const
sanctionList
=
ref
([]);
const
selectedSanctionId
=
ref
(
null
);
const
selectedSanctionId
=
ref
(
null
);
...
@@ -204,6 +206,7 @@ const totalElements = ref(0);
...
@@ -204,6 +206,7 @@ const totalElements = ref(0);
const
openSanctionModal
=
async
()
=>
{
const
openSanctionModal
=
async
()
=>
{
sanctionModalVisible
.
value
=
true
;
sanctionModalVisible
.
value
=
true
;
console
.
log
(
"制裁事件列表11:"
,
sanctionList
.
value
);
console
.
log
(
"制裁事件列表11:"
,
sanctionList
.
value
);
loading
.
value
=
true
;
await
fetchSanctionData
();
await
fetchSanctionData
();
};
};
...
@@ -211,6 +214,7 @@ const openSanctionModal = async () => {
...
@@ -211,6 +214,7 @@ const openSanctionModal = async () => {
const
fetchSanctionData
=
async
()
=>
{
const
fetchSanctionData
=
async
()
=>
{
try
{
try
{
const
res
=
await
getSanctionProcess
([
1
],
currentPage
.
value
,
10
);
const
res
=
await
getSanctionProcess
([
1
],
currentPage
.
value
,
10
);
loading
.
value
=
false
;
if
(
res
&&
!!
res
.
content
)
{
if
(
res
&&
!!
res
.
content
)
{
sanctionList
.
value
=
res
.
content
||
[];
sanctionList
.
value
=
res
.
content
||
[];
totalElements
.
value
=
res
.
totalElements
||
0
;
totalElements
.
value
=
res
.
totalElements
||
0
;
...
@@ -225,6 +229,7 @@ const fetchSanctionData = async () => {
...
@@ -225,6 +229,7 @@ const fetchSanctionData = async () => {
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
"获取制裁事件失败:"
,
error
);
console
.
error
(
"获取制裁事件失败:"
,
error
);
loading
.
value
=
false
;
sanctionList
.
value
=
[];
sanctionList
.
value
=
[];
totalElements
.
value
=
0
;
totalElements
.
value
=
0
;
}
}
...
@@ -237,7 +242,7 @@ const handlePageChange = async newPage => {
...
@@ -237,7 +242,7 @@ const handlePageChange = async newPage => {
};
};
// ========== 选择某项 ==========
// ========== 选择某项 ==========
const
selectSanction
=
item
=>
{
const
selectSanction
=
async
item
=>
{
selectedSanctionId
.
value
=
item
.
id
;
selectedSanctionId
.
value
=
item
.
id
;
router
.
replace
({
router
.
replace
({
path
:
window
.
location
.
pathname
,
path
:
window
.
location
.
pathname
,
...
@@ -247,7 +252,10 @@ const selectSanction = item => {
...
@@ -247,7 +252,10 @@ const selectSanction = item => {
}
}
});
});
sanctionModalVisible
.
value
=
false
;
sanctionModalVisible
.
value
=
false
;
window
.
location
.
reload
();
console
.
log
(
"跳转URL:"
,
window
.
location
.
href
);
// 根据最新URL参数刷新当前页面
window
.
open
(
`
${
window
.
location
.
pathname
}
?id=
${
item
.
id
}
&sanTypeId=
${
item
.
sanTypeId
}
`
,
"_self"
);
};
};
// ========== 关闭弹窗时重置 ==========
// ========== 关闭弹窗时重置 ==========
...
@@ -467,6 +475,8 @@ onMounted(() => {
...
@@ -467,6 +475,8 @@ onMounted(() => {
font-size
:
14px
;
font-size
:
14px
;
color
:
#333
;
color
:
#333
;
transition
:
background-color
0
.2s
;
transition
:
background-color
0
.2s
;
display
:
flex
;
justify-content
:
space-between
;
}
}
.sanction-item
:hover
{
.sanction-item
:hover
{
...
...
src/views/exportControl/v2.0SingleSanction/originPage/index-back.vue
0 → 100644
浏览文件 @
8e14f2ea
<
template
>
<div
class=
"entity-list"
>
<div
class=
"header"
>
<div
class=
"header-title"
>
<img
:src=
"headerTitle.img"
alt=
""
/>
<div>
<div
class=
"title"
>
{{
headerTitle
.
title
}}
<!--
<span>
{{
headerTitle
.
titleEn
}}
</span>
-->
</div>
<div
class=
"department"
>
{{
headerTitle
.
department
}}
</div>
</div>
<!--
<div
class=
"btn"
>
<img
:src=
"icon01"
alt=
""
>
切换
</div>
-->
</div>
</div>
<div
class=
"main"
>
<div
class=
"pdf-container"
>
<iframe
v-if=
"headerTitle.srcUrl"
:src=
"headerTitle.srcUrl"
width=
"100%"
height=
"100%"
frameborder=
"0"
></iframe>
<div
v-else
class=
"no-pdf"
>
暂无原文
</div>
</div>
<div
class=
"pdf-container"
>
<iframe
v-if=
"headerTitle.transUrl"
:src=
"headerTitle.transUrl"
width=
"100%"
height=
"100%"
frameborder=
"0"
></iframe>
<div
v-else
class=
"no-pdf"
>
暂无译文
</div>
</div>
</div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
}
from
"vue"
;
import
{
getSingleSanctionOverview
}
from
"@/api/exportControlV2.0.js"
;
import
title
from
"../assets/title.png"
;
import
icon01
from
"../assets/icon01.png"
;
// 单次制裁-制裁概况-基本信息
const
singleSanctionOverview
=
ref
({});
const
getSingleSanctionOverviewData
=
async
()
=>
{
if
(
!
sanRecordId
.
value
)
return
;
try
{
const
res
=
await
getSingleSanctionOverview
({
sanRecordId
:
sanRecordId
.
value
});
if
(
res
.
code
===
200
)
{
singleSanctionOverview
.
value
=
res
.
data
||
{};
// 格式化日期
let
dateStr
=
""
;
if
(
singleSanctionOverview
.
value
.
postDate
)
{
const
date
=
new
Date
(
singleSanctionOverview
.
value
.
postDate
);
if
(
!
isNaN
(
date
.
getTime
()))
{
dateStr
=
`
${
date
.
getFullYear
()}
年
${
date
.
getMonth
()
+
1
}
月
${
date
.
getDate
()}
日`
;
}
else
{
dateStr
=
singleSanctionOverview
.
value
.
postDate
;
}
}
// 更新头部信息
headerTitle
.
value
=
{
...
headerTitle
.
value
,
title
:
`
${
dateStr
}
《
${
singleSanctionOverview
.
value
.
sanTitleZh
||
singleSanctionOverview
.
value
.
sanTitle
}
》`
,
titleEn
:
singleSanctionOverview
.
value
.
sanTitle
||
""
,
department
:
singleSanctionOverview
.
value
.
fileCode
||
""
,
srcUrl
:
singleSanctionOverview
.
value
.
srcUrl
||
""
,
transUrl
:
singleSanctionOverview
.
value
.
transUrl
||
""
};
}
}
catch
(
error
)
{
console
.
error
(
"获取制裁概况失败:"
,
error
);
}
};
const
headerTitle
=
ref
({
img
:
title
});
// 获取URL参数
const
sanRecordId
=
ref
(
""
);
const
getUrlParams
=
()
=>
{
const
urlParams
=
new
URLSearchParams
(
window
.
location
.
search
);
sanRecordId
.
value
=
urlParams
.
get
(
"id"
)
||
""
;
};
onMounted
(()
=>
{
getUrlParams
();
getSingleSanctionOverviewData
();
});
</
script
>
<
style
scoped
lang=
"scss"
>
*
{
margin
:
0
;
padding
:
0
;
}
.entity-list
{
width
:
100%
;
height
:
100%
;
.header
{
width
:
100%
;
height
:
148px
;
background-color
:
#fff
;
padding-top
:
16px
;
.header-title
{
width
:
1601px
;
height
:
72px
;
background-color
:
rgba
(
246
,
250
,
255
,
1
);
margin
:
0
auto
;
border-radius
:
10px
;
border
:
2px
solid
rgba
(
174
,
214
,
255
,
1
);
display
:
flex
;
align-items
:
center
;
margin-bottom
:
12px
;
position
:
relative
;
img
{
width
:
54px
;
height
:
54px
;
margin-left
:
15px
;
margin-right
:
11px
;
}
.title
{
font-size
:
20px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
26px
;
color
:
rgb
(
59
,
65
,
75
);
span
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
95
,
101
,
108
);
margin-left
:
11px
;
}
}
.department
{
font-size
:
16px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
95
,
101
,
108
);
}
.btn
{
cursor
:
pointer
;
display
:
flex
;
align-items
:
center
;
position
:
absolute
;
right
:
16px
;
top
:
25px
;
font-size
:
18px
;
font-weight
:
700
;
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
color
:
rgb
(
5
,
95
,
194
);
img
{
width
:
20px
;
height
:
20px
;
margin-right
:
7px
;
}
}
}
.header-nav
{
width
:
1601px
;
margin
:
0
auto
;
height
:
48px
;
display
:
flex
;
align-items
:
center
;
.nav-item
{
display
:
flex
;
align-items
:
center
;
height
:
100%
;
margin-right
:
32px
;
cursor
:
pointer
;
position
:
relative
;
font-size
:
18px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
59
,
65
,
75
);
&
:last-child
{
margin-right
:
0
;
}
img
{
width
:
16px
;
height
:
16px
;
margin-right
:
4px
;
}
&
.active
{
color
:
rgb
(
5
,
95
,
194
);
font-weight
:
700
;
}
.active-line
{
position
:
absolute
;
bottom
:
0
;
left
:
0
;
width
:
100%
;
height
:
3px
;
background-color
:
#055fc2
;
border-radius
:
1
.5px
;
}
}
.original-text-btn
{
margin-left
:
auto
;
width
:
152px
;
height
:
36px
;
background
:
#ffffff
;
border-radius
:
4px
;
border
:
1px
solid
rgba
(
230
,
231
,
232
,
1
);
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
img
{
width
:
16px
;
height
:
16px
;
margin-right
:
8px
;
}
span
{
font-size
:
16px
;
font-weight
:
400
;
color
:
rgb
(
95
,
101
,
108
);
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
}
}
}
}
.main
{
width
:
1601px
;
height
:
calc
(
100%
-
148px
);
background-color
:
#f7f8f9
;
margin
:
0
auto
;
display
:
flex
;
justify-content
:
space-between
;
padding-top
:
20px
;
box-sizing
:
border-box
;
.pdf-container
{
width
:
790px
;
height
:
calc
(
100%
-
20px
);
background-color
:
#fff
;
// border: 1px solid rgba(174, 214, 255, 1);
border-radius
:
4px
;
overflow
:
hidden
;
.no-pdf
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
height
:
100%
;
color
:
#909399
;
font-size
:
16px
;
background-color
:
#fff
;
}
}
}
}
</
style
>
src/views/exportControl/v2.0SingleSanction/originPage/index.vue
浏览文件 @
8e14f2ea
<
template
>
<
template
>
<div
class=
"entity-list"
>
<div
class=
"entity-list"
>
<div
class=
"header"
>
<div
class=
"header"
>
<div
class=
"header-title"
>
<div
class=
"header-title"
>
<img
:src=
"headerTitle.img"
alt=
""
>
<img
:src=
"headerTitle.img"
alt=
""
/
>
<div>
<div>
<div
class=
"title"
>
<div
class=
"title"
>
{{
headerTitle
.
title
}}
{{
headerTitle
.
title
}}
<!--
<span>
{{
headerTitle
.
titleEn
}}
</span>
--
>
</div
>
</div
>
<div
class=
"department"
>
<div
class=
"department"
>
{{
headerTitle
.
department
}}
{{
headerTitle
.
department
}}
</div>
</div>
</div>
</div>
</div>
<!--
<div
class=
"btn"
>
</div
>
<img
:src=
"icon01"
alt=
""
>
切换
<div
class=
"main"
>
</div>
--
>
<div
class=
"main-header"
>
</div>
<div>
实体清单制裁文件
</div>
</div>
</div>
<div
class=
"main"
>
<!-- 外层滚动容器,统一控制两侧滚动 --
>
<div
class=
"pdf-container
"
>
<div
class=
"report-box"
ref=
"reportBoxRef
"
>
<iframe
v-if=
"headerTitle.srcUrl"
:src=
"headerTitle.srcUrl"
width=
"100%"
height=
"100%"
frameborder=
"0"
></iframe
>
<div
class=
"pdf-pane-wrap"
>
<div
v-else
class=
"no-pdf"
>
暂无原文
</div
>
<pdf
ref=
"leftPdfRef"
:pdfUrl=
"headerTitle.srcUrl"
class=
"pdf-pane-inner"
/
>
</div>
</div>
<div
class=
"pdf-container
"
>
<div
class=
"pdf-pane-wrap
"
>
<iframe
v-if=
"headerTitle.transUrl"
:src=
"headerTitle.transUrl"
width=
"100%"
height=
"100%"
frameborder=
"0"
></iframe
>
<pdf
ref=
"rightPdfRef"
:pdfUrl=
"headerTitle.transUrl"
class=
"pdf-pane-inner"
/
>
<div
v-else
class=
"no-pdf"
>
暂无译文
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</
template
>
</
template
>
<
script
setup
>
<
script
setup
>
import
{
ref
,
onMounted
}
from
'vue'
import
{
ref
,
onMounted
,
watch
}
from
"vue"
;
import
{
getSingleSanctionOverview
}
from
"@/api/exportControlV2.0.js"
import
{
getSingleSanctionOverview
}
from
"@/api/exportControlV2.0.js"
;
import
title
from
"../assets/title.png"
import
title
from
"../assets/title.png"
;
import
icon01
from
"../assets/icon01.png"
import
pdf
from
"./pdf.vue"
;
const
leftPdfRef
=
ref
(
null
);
const
rightPdfRef
=
ref
(
null
);
const
reportBoxRef
=
ref
(
null
);
const
headerTitle
=
ref
({
img
:
title
,
title
:
""
,
department
:
""
,
srcUrl
:
""
,
transUrl
:
""
});
const
sanRecordId
=
ref
(
""
);
const
isSyncing
=
ref
(
false
);
const
getUrlParams
=
()
=>
{
const
urlParams
=
new
URLSearchParams
(
window
.
location
.
search
);
sanRecordId
.
value
=
urlParams
.
get
(
"id"
)
||
""
;
};
// 单次制裁-制裁概况-基本信息
const
singleSanctionOverview
=
ref
({})
const
getSingleSanctionOverviewData
=
async
()
=>
{
const
getSingleSanctionOverviewData
=
async
()
=>
{
if
(
!
sanRecordId
.
value
)
return
if
(
!
sanRecordId
.
value
)
return
;
try
{
try
{
const
res
=
await
getSingleSanctionOverview
({
const
res
=
await
getSingleSanctionOverview
({
sanRecordId
:
sanRecordId
.
value
sanRecordId
:
sanRecordId
.
value
})
});
if
(
res
.
code
===
200
)
{
if
(
res
.
code
===
200
&&
res
.
data
)
{
singleSanctionOverview
.
value
=
res
.
data
||
{}
const
singleSanctionOverview
=
res
.
data
||
{};
// 格式化日期
let
dateStr
=
""
;
if
(
singleSanctionOverview
.
value
.
postDate
)
{
const
date
=
new
Date
(
singleSanctionOverview
.
value
.
postDate
);
if
(
!
isNaN
(
date
.
getTime
()))
{
dateStr
=
`
${
date
.
getFullYear
()}
年
${
date
.
getMonth
()
+
1
}
月
${
date
.
getDate
()}
日`
;
}
else
{
dateStr
=
singleSanctionOverview
.
value
.
postDate
;
}
}
// 更新头部信息
// 格式化日期
headerTitle
.
value
=
{
let
dateStr
=
""
;
...
headerTitle
.
value
,
if
(
singleSanctionOverview
.
postDate
)
{
title
:
`
${
dateStr
}
《
${
singleSanctionOverview
.
value
.
sanTitleZh
||
singleSanctionOverview
.
value
.
sanTitle
}
》`
,
const
date
=
new
Date
(
singleSanctionOverview
.
postDate
);
titleEn
:
singleSanctionOverview
.
value
.
sanTitle
||
""
,
if
(
!
isNaN
(
date
.
getTime
()))
{
department
:
singleSanctionOverview
.
value
.
fileCode
||
""
,
dateStr
=
`
${
date
.
getFullYear
()}
年
${
date
.
getMonth
()
+
1
}
月
${
date
.
getDate
()}
日`
;
srcUrl
:
singleSanctionOverview
.
value
.
srcUrl
||
""
,
}
else
{
transUrl
:
singleSanctionOverview
.
value
.
transUrl
||
""
dateStr
=
singleSanctionOverview
.
postDate
;
}
}
}
}
}
catch
(
error
)
{
console
.
error
(
"获取制裁概况失败:"
,
error
)
}
}
// 更新头部信息
headerTitle
.
value
=
{
...
headerTitle
.
value
,
title
:
`
${
dateStr
}
《
${
singleSanctionOverview
.
sanTitleZh
||
singleSanctionOverview
.
sanTitle
}
》`
,
department
:
singleSanctionOverview
.
fileCode
||
""
,
srcUrl
:
singleSanctionOverview
.
srcUrl
||
""
,
transUrl
:
singleSanctionOverview
.
transUrl
||
""
};
}
}
catch
(
error
)
{
console
.
error
(
"获取制裁概况失败:"
,
error
);
}
};
// 同步滚动处理
const
handleSyncScroll
=
()
=>
{
if
(
isSyncing
.
value
)
return
;
isSyncing
.
value
=
true
;
requestAnimationFrame
(()
=>
{
isSyncing
.
value
=
false
;
});
};
// 监听滚动事件
const
setupScrollSync
=
()
=>
{
const
reportBox
=
reportBoxRef
.
value
;
if
(
!
reportBox
)
return
;
reportBox
.
addEventListener
(
"scroll"
,
handleSyncScroll
,
{
passive
:
true
});
};
// 监听 PDF 加载完成
watch
(
()
=>
[
headerTitle
.
value
.
srcUrl
,
headerTitle
.
value
.
transUrl
],
()
=>
{
// PDF URL 变化时,等待渲染完成后设置滚动监听
setTimeout
(()
=>
{
setupScrollSync
();
},
1000
);
},
{
deep
:
true
}
);
const
headerTitle
=
ref
({
img
:
title
,
})
// 获取URL参数
const
sanRecordId
=
ref
(
""
)
const
getUrlParams
=
()
=>
{
const
urlParams
=
new
URLSearchParams
(
window
.
location
.
search
);
sanRecordId
.
value
=
urlParams
.
get
(
"id"
)
||
""
}
onMounted
(()
=>
{
onMounted
(()
=>
{
getUrlParams
()
getUrlParams
();
getSingleSanctionOverviewData
()
getSingleSanctionOverviewData
();
})
// 等待 DOM 渲染完成后设置滚动监听
setTimeout
(()
=>
{
setupScrollSync
();
},
500
);
});
</
script
>
</
script
>
<
style
scoped
lang=
"scss"
>
<
style
scoped
lang=
"scss"
>
*
{
*
{
margin
:
0
;
margin
:
0
;
padding
:
0
;
padding
:
0
;
}
}
.entity-list
{
.entity-list
{
width
:
100%
;
width
:
100%
;
height
:
100%
;
height
:
100%
;
.header
{
overflow-y
:
auto
;
width
:
100%
;
height
:
148px
;
.header
{
background-color
:
#fff
;
width
:
100%
;
padding-top
:
16px
;
height
:
148px
;
.header-title
{
background-color
:
#fff
;
width
:
1601px
;
padding-top
:
16px
;
height
:
72px
;
box-sizing
:
border-box
;
background-color
:
rgba
(
246
,
250
,
255
,
1
);
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
margin
:
0
auto
;
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
border-radius
:
10px
;
border
:
2px
solid
rgba
(
174
,
214
,
255
,
1
);
.header-title
{
display
:
flex
;
width
:
1601px
;
align-items
:
center
;
height
:
72px
;
margin-bottom
:
12px
;
background-color
:
rgba
(
246
,
250
,
255
,
1
);
position
:
relative
;
margin
:
0
auto
;
img
{
border-radius
:
10px
;
width
:
54px
;
border
:
2px
solid
rgba
(
174
,
214
,
255
,
1
);
height
:
54px
;
display
:
flex
;
margin-left
:
15px
;
align-items
:
center
;
margin-right
:
11px
;
margin-bottom
:
12px
;
}
position
:
relative
;
.title
{
font-size
:
20px
;
img
{
font-weight
:
700
;
width
:
54px
;
font-family
:
"Microsoft YaHei"
;
height
:
54px
;
line-height
:
26px
;
margin-left
:
15px
;
color
:
rgb
(
59
,
65
,
75
);
margin-right
:
11px
;
span
{
}
font-size
:
16px
;
font-weight
:
400
;
.title
{
font-family
:
"Microsoft YaHei"
;
font-size
:
20px
;
line-height
:
24px
;
font-weight
:
700
;
color
:
rgb
(
95
,
101
,
108
);
font-family
:
"Microsoft YaHei"
;
margin-left
:
11px
;
line-height
:
26px
;
}
color
:
rgb
(
59
,
65
,
75
);
}
}
.department
{
font-size
:
16px
;
.department
{
font-weight
:
400
;
font-size
:
16px
;
font-family
:
"Microsoft YaHei"
;
font-weight
:
400
;
line-height
:
24px
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
95
,
101
,
108
);
line-height
:
24px
;
}
color
:
rgb
(
95
,
101
,
108
);
.btn
{
}
cursor
:
pointer
;
}
display
:
flex
;
}
align-items
:
center
;
position
:
absolute
;
.main
{
right
:
16px
;
margin
:
0
auto
;
top
:
25px
;
background
:
rgb
(
255
,
255
,
255
);
font-size
:
18px
;
width
:
1601px
;
font-weight
:
700
;
height
:
calc
(
100vh
-
148px
);
font-family
:
"Microsoft YaHei"
;
margin-bottom
:
20px
;
line-height
:
24px
;
border
:
1px
solid
rgb
(
234
,
236
,
238
);
color
:
rgb
(
5
,
95
,
194
);
box-shadow
:
0
0
20px
0
rgba
(
25
,
69
,
130
,
0
.1
);
img
{
width
:
20px
;
height
:
20px
;
margin-right
:
7px
;
}
}
}
.header-nav
{
width
:
1601px
;
margin
:
0
auto
;
height
:
48px
;
display
:
flex
;
align-items
:
center
;
.nav-item
{
display
:
flex
;
align-items
:
center
;
height
:
100%
;
margin-right
:
32px
;
cursor
:
pointer
;
position
:
relative
;
font-size
:
18px
;
font-weight
:
400
;
font-family
:
"Microsoft YaHei"
;
color
:
rgb
(
59
,
65
,
75
);
&
:last-child
{
margin-right
:
0
;
}
img
{
.main-header
{
width
:
16px
;
height
:
64px
;
height
:
16px
;
border-bottom
:
1px
solid
rgb
(
234
,
236
,
238
);
margin-right
:
4px
;
background
:
rgb
(
255
,
255
,
255
);
}
margin
:
0
70px
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
"Source Han Sans CN"
;
font-size
:
20px
;
font-weight
:
700
;
line-height
:
26px
;
width
:
1456px
;
text-align
:
left
;
display
:
flex
;
align-items
:
center
;
}
&
.active
{
.report-box
{
color
:
rgb
(
5
,
95
,
194
);
margin-left
:
70px
;
font-weight
:
700
;
width
:
1456px
;
}
height
:
calc
(
100%
-
64px
);
display
:
flex
;
overflow-y
:
auto
;
/* 统一滚动条,控制两侧一起滚动 */
overflow-x
:
hidden
;
}
.active-line
{
.pdf-pane-wrap
{
position
:
absolute
;
flex
:
0
0
50%
;
bottom
:
0
;
max-width
:
50%
;
left
:
0
;
height
:
100%
;
width
:
100%
;
min-width
:
0
;
height
:
3px
;
}
background-color
:
#055fc2
;
border-radius
:
1
.5px
;
}
}
.original-text-btn
{
.pdf-pane-inner
{
margin-left
:
auto
;
width
:
100%
;
width
:
152px
;
height
:
100%
;
height
:
36px
;
}
background
:
#FFFFFF
;
}
border-radius
:
4px
;
border
:
1px
solid
rgba
(
230
,
231
,
232
,
1
);
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
img
{
width
:
16px
;
height
:
16px
;
margin-right
:
8px
;
}
span
{
font-size
:
16px
;
font-weight
:
400
;
color
:
rgb
(
95
,
101
,
108
);
font-family
:
"Microsoft YaHei"
;
line-height
:
24px
;
}
}
}
}
.main
{
width
:
1601px
;
height
:
calc
(
100%
-
148px
);
background-color
:
#F7F8F9
;
margin
:
0
auto
;
display
:
flex
;
justify-content
:
space-between
;
padding-top
:
20px
;
box-sizing
:
border-box
;
.pdf-container
{
width
:
790px
;
height
:
calc
(
100%
-
20px
);
background-color
:
#fff
;
// border: 1px solid rgba(174, 214, 255, 1);
border-radius
:
4px
;
overflow
:
hidden
;
.no-pdf
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
height
:
100%
;
color
:
#909399
;
font-size
:
16px
;
background-color
:
#fff
;
}
}
}
}
}
</
style
>
</
style
>
\ No newline at end of file
src/views/exportControl/v2.0SingleSanction/originPage/pdf.vue
0 → 100644
浏览文件 @
8e14f2ea
<
template
>
<div
class=
"pdf-viewer"
>
<!-- PDF 页面:canvas + textLayer 必须在同一容器内渲染 -->
<div
class=
"page-wrap"
v-for=
"page in pageCount"
:key=
"page"
>
<canvas
:ref=
"el => setCanvasRef(page, el)"
></canvas>
<div
:ref=
"el => setOverlayRef(page, el)"
class=
"textLayer"
></div>
</div>
<div
v-if=
"loading"
class=
"loading"
>
加载中...
</div>
</div>
</
template
>
<
script
>
import
{
ref
,
shallowRef
,
nextTick
,
watch
}
from
"vue"
;
import
*
as
pdfjsLib
from
"pdfjs-dist/legacy/build/pdf"
;
import
PdfWorker
from
"pdfjs-dist/legacy/build/pdf.worker.min?worker"
;
// 使用 Vite 的 ?worker 直接注入 Worker,避免线上 mjs MIME 类型问题
pdfjsLib
.
GlobalWorkerOptions
.
workerPort
=
new
PdfWorker
();
export
default
{
name
:
"PdfViewer"
,
props
:
{
pdfUrl
:
{
type
:
String
,
required
:
true
}
},
setup
(
props
)
{
const
canvasMap
=
{};
const
overlayMap
=
{};
const
pageCount
=
ref
(
0
);
const
loading
=
ref
(
true
);
const
renderedPageCount
=
ref
(
0
);
let
resolveRenderAll
=
null
;
const
waitAllPagesRendered
=
()
=>
{
if
(
pageCount
.
value
>
0
&&
renderedPageCount
.
value
>=
pageCount
.
value
)
{
return
Promise
.
resolve
();
}
return
new
Promise
(
resolve
=>
{
resolveRenderAll
=
resolve
;
});
};
// pdfjs 的 document 对象内部使用 #private 字段,用 shallowRef 保持为原始对象引用
const
pdfDocRef
=
shallowRef
(
null
);
const
searchKey
=
ref
(
""
);
const
matchList
=
ref
([]);
const
matchIdx
=
ref
(
0
);
const
pdfjsApiRef
=
shallowRef
(
pdfjsLib
);
// 保存 canvas
const
setCanvasRef
=
(
page
,
el
)
=>
{
if
(
!
el
)
return
;
canvasMap
[
page
]
=
el
;
};
// 保存 textLayer 容器(用于搜索高亮)
const
setOverlayRef
=
(
page
,
el
)
=>
{
if
(
!
el
)
return
;
overlayMap
[
page
]
=
el
;
};
// 清理 URL
const
parsePdfUrl
=
pdfUrl
=>
{
if
(
!
pdfUrl
||
typeof
pdfUrl
!==
"string"
)
return
""
;
const
[
urlPart
]
=
pdfUrl
.
split
(
"#"
);
return
urlPart
;
};
// 清空所有高亮
const
clearHighlights
=
()
=>
{
Object
.
values
(
overlayMap
).
forEach
(
layer
=>
{
if
(
!
layer
)
return
;
const
rects
=
layer
.
querySelectorAll
(
".highlight-rect"
);
rects
.
forEach
(
n
=>
n
.
remove
());
});
};
// 重置搜索状态
const
clearSearch
=
()
=>
{
searchKey
.
value
=
""
;
matchList
.
value
=
[];
matchIdx
.
value
=
0
;
clearHighlights
();
};
// 渲染单页 PDF
const
renderPage
=
async
(
pdf
,
pageNum
)
=>
{
const
pdfPage
=
await
pdf
.
getPage
(
pageNum
);
const
canvas
=
canvasMap
[
pageNum
];
const
textLayer
=
overlayMap
[
pageNum
];
if
(
!
canvas
||
!
textLayer
)
return
;
const
baseViewport
=
pdfPage
.
getViewport
({
scale
:
1
});
const
desiredWidth
=
canvas
.
clientWidth
||
726
;
const
scale
=
desiredWidth
/
baseViewport
.
width
;
const
viewport
=
pdfPage
.
getViewport
({
scale
});
const
context
=
canvas
.
getContext
(
"2d"
);
canvas
.
width
=
viewport
.
width
;
canvas
.
height
=
viewport
.
height
;
canvas
.
style
.
width
=
`
${
viewport
.
width
}
px`
;
canvas
.
style
.
height
=
`
${
viewport
.
height
}
px`
;
textLayer
.
style
.
width
=
canvas
.
width
+
"px"
;
textLayer
.
style
.
height
=
canvas
.
height
+
"px"
;
textLayer
.
innerHTML
=
""
;
textLayer
.
style
.
setProperty
(
"--scale-factor"
,
String
(
viewport
.
scale
||
1
));
await
pdfPage
.
render
({
canvasContext
:
context
,
viewport
}).
promise
;
try
{
const
textContent
=
await
pdfPage
.
getTextContent
();
let
api
=
pdfjsApiRef
.
value
||
pdfjsLib
;
let
rt
=
api
?.
renderTextLayer
;
if
(
typeof
rt
!==
"function"
)
{
try
{
const
legacy
=
await
import
(
"pdfjs-dist/legacy/build/pdf"
);
pdfjsApiRef
.
value
=
legacy
;
api
=
legacy
;
rt
=
legacy
?.
renderTextLayer
;
}
catch
(
_
)
{}
}
if
(
typeof
rt
===
"function"
)
{
await
rt
({
textContent
,
container
:
textLayer
,
viewport
,
textDivs
:
[],
enhanceTextSelection
:
false
}).
promise
;
}
}
catch
(
e
)
{
console
.
warn
(
"textLayer 渲染失败"
,
e
);
}
renderedPageCount
.
value
+=
1
;
if
(
pageCount
.
value
>
0
&&
renderedPageCount
.
value
>=
pageCount
.
value
)
{
if
(
typeof
resolveRenderAll
===
"function"
)
{
const
fn
=
resolveRenderAll
;
resolveRenderAll
=
null
;
fn
();
}
}
};
// 渲染 PDF
const
renderPdf
=
async
pdfUrl
=>
{
const
url
=
parsePdfUrl
(
pdfUrl
);
if
(
!
url
)
return
;
loading
.
value
=
true
;
pdfDocRef
.
value
=
null
;
clearHighlights
();
matchList
.
value
=
[];
searchKey
.
value
=
""
;
renderedPageCount
.
value
=
0
;
resolveRenderAll
=
null
;
try
{
const
pdf
=
await
pdfjsLib
.
getDocument
(
url
).
promise
;
pdfDocRef
.
value
=
pdf
;
pageCount
.
value
=
pdf
.
numPages
;
await
nextTick
();
for
(
let
p
=
1
;
p
<=
pdf
.
numPages
;
p
++
)
{
await
renderPage
(
pdf
,
p
);
}
}
catch
(
err
)
{
console
.
error
(
"PDF 加载失败"
,
err
);
}
finally
{
loading
.
value
=
false
;
}
};
// 搜索关键词 + 高亮
const
doSearch
=
async
()
=>
{
const
doc
=
pdfDocRef
.
value
;
const
key
=
searchKey
.
value
.
trim
();
clearHighlights
();
matchList
.
value
=
[];
matchIdx
.
value
=
0
;
if
(
!
doc
||
!
key
)
return
;
await
waitAllPagesRendered
();
for
(
let
pageNum
=
1
;
pageNum
<=
doc
.
numPages
;
pageNum
++
)
{
const
layer
=
overlayMap
[
pageNum
];
if
(
!
layer
)
continue
;
const
nodes
=
Array
.
from
(
layer
.
querySelectorAll
(
"span"
));
for
(
const
el
of
nodes
)
{
const
t
=
el
.
textContent
||
""
;
if
(
!
t
)
continue
;
let
start
=
0
;
while
(
true
)
{
const
idx
=
t
.
indexOf
(
key
,
start
);
if
(
idx
===
-
1
)
break
;
matchList
.
value
.
push
({
pageNum
,
el
,
startIdx
:
idx
,
endIdx
:
idx
+
key
.
length
});
start
=
idx
+
Math
.
max
(
1
,
key
.
length
);
}
}
}
if
(
matchList
.
value
.
length
>
0
)
jumpTo
(
0
);
};
// 跳转到第 N 个匹配项
const
jumpTo
=
idx
=>
{
if
(
idx
<
0
||
idx
>=
matchList
.
value
.
length
)
return
;
matchIdx
.
value
=
idx
;
const
m
=
matchList
.
value
[
idx
];
const
el
=
m
?.
el
;
if
(
!
el
)
return
;
clearHighlights
();
const
textNode
=
el
.
firstChild
;
if
(
textNode
&&
textNode
.
nodeType
===
Node
.
TEXT_NODE
)
{
try
{
const
range
=
document
.
createRange
();
range
.
setStart
(
textNode
,
Math
.
max
(
0
,
m
.
startIdx
??
0
));
range
.
setEnd
(
textNode
,
Math
.
max
(
0
,
m
.
endIdx
??
0
));
const
rectList
=
Array
.
from
(
range
.
getClientRects
());
const
pageWrap
=
el
.
closest
(
".page-wrap"
);
const
layer
=
overlayMap
[
m
.
pageNum
];
if
(
pageWrap
&&
layer
&&
rectList
.
length
)
{
const
pageRect
=
pageWrap
.
getBoundingClientRect
();
rectList
.
forEach
(
r
=>
{
const
mark
=
document
.
createElement
(
"div"
);
mark
.
className
=
"highlight-rect"
;
mark
.
style
.
left
=
r
.
left
-
pageRect
.
left
+
"px"
;
mark
.
style
.
top
=
r
.
top
-
pageRect
.
top
+
"px"
;
mark
.
style
.
width
=
r
.
width
+
"px"
;
mark
.
style
.
height
=
r
.
height
+
"px"
;
layer
.
appendChild
(
mark
);
});
}
range
.
detach
?.();
}
catch
(
e
)
{
// ignore
}
}
// 滚动到匹配位置
const
container
=
el
.
closest
(
".report-box"
);
if
(
container
)
{
const
TOP_OFFSET
=
72
;
const
containerRect
=
container
.
getBoundingClientRect
();
const
elRect
=
el
.
getBoundingClientRect
();
const
targetTop
=
elRect
.
top
-
containerRect
.
top
+
container
.
scrollTop
-
TOP_OFFSET
;
container
.
scrollTo
({
top
:
Math
.
max
(
0
,
targetTop
),
behavior
:
"smooth"
});
}
else
{
el
.
scrollIntoView
({
behavior
:
"smooth"
,
block
:
"center"
});
}
};
const
prevMatch
=
()
=>
jumpTo
(
matchIdx
.
value
-
1
);
const
nextMatch
=
()
=>
jumpTo
(
matchIdx
.
value
+
1
);
const
getMatchInfo
=
()
=>
{
const
total
=
matchList
.
value
.
length
;
const
current
=
total
?
matchIdx
.
value
+
1
:
0
;
return
{
current
,
total
};
};
// 外部调用方法
const
searchKeyword
=
async
keyword
=>
{
searchKey
.
value
=
keyword
;
await
doSearch
();
return
matchList
.
value
.
length
>
0
?
matchList
.
value
[
0
].
pageNum
:
0
;
};
const
goToPage
=
pageNum
=>
{
const
canvasEl
=
canvasMap
[
pageNum
];
if
(
!
canvasEl
)
return
;
const
container
=
canvasEl
.
closest
(
".report-box"
);
if
(
container
)
{
const
containerRect
=
container
.
getBoundingClientRect
();
const
canvasRect
=
canvasEl
.
getBoundingClientRect
();
const
targetTop
=
canvasRect
.
top
-
containerRect
.
top
+
container
.
scrollTop
;
container
.
scrollTo
({
top
:
Math
.
max
(
0
,
targetTop
),
behavior
:
"smooth"
});
}
else
{
canvasEl
.
scrollIntoView
({
behavior
:
"smooth"
,
block
:
"start"
});
}
};
// 获取容器元素(用于同步滚动)
const
getContainer
=
()
=>
{
const
firstCanvas
=
canvasMap
[
1
];
return
firstCanvas
?
firstCanvas
.
closest
(
".report-box"
)
:
null
;
};
watch
(
()
=>
props
.
pdfUrl
,
newVal
=>
{
if
(
newVal
)
renderPdf
(
newVal
);
},
{
immediate
:
true
}
);
return
{
pageCount
,
setCanvasRef
,
setOverlayRef
,
loading
,
searchKey
,
doSearch
,
prevMatch
,
nextMatch
,
getMatchInfo
,
matchList
,
matchIdx
,
searchKeyword
,
clearSearch
,
goToPage
,
getContainer
};
}
};
</
script
>
<
style
scoped
>
.pdf-viewer
{
position
:
relative
;
width
:
100%
;
}
.page-wrap
{
position
:
relative
;
margin-bottom
:
16px
;
width
:
100%
;
}
canvas
{
width
:
100%
;
height
:
auto
;
display
:
block
;
}
.textLayer
{
position
:
absolute
;
left
:
0
;
top
:
0
;
inset
:
0
;
overflow
:
hidden
;
pointer-events
:
none
;
z-index
:
2
;
line-height
:
1
;
}
.textLayer
:deep
(
span
)
{
position
:
absolute
;
transform-origin
:
0%
0%
;
white-space
:
pre
;
line-height
:
1
;
font-size
:
calc
(
var
(
--font-height
,
0px
)
*
var
(
--scale-factor
,
1
));
transform
:
scaleX
(
var
(
--scale-x
,
1
));
color
:
transparent
;
}
.textLayer
:deep
(
.highlight-text
)
{
background
:
#ff0
;
opacity
:
0.6
;
padding
:
0
1px
;
border-radius
:
2px
;
}
.textLayer
:deep
(
.highlight-rect
)
{
position
:
absolute
;
background
:
#ff0
;
opacity
:
0.6
;
border-radius
:
2px
;
pointer-events
:
none
;
}
.loading
{
position
:
absolute
;
top
:
50%
;
left
:
50%
;
transform
:
translate
(
-50%
,
-50%
);
font-size
:
18px
;
color
:
#333
;
}
</
style
>
src/views/finance/index.vue
浏览文件 @
8e14f2ea
...
@@ -12,8 +12,13 @@
...
@@ -12,8 +12,13 @@
<div
class=
"home-top-bg"
></div>
<div
class=
"home-top-bg"
></div>
<div
class=
"home-main-header"
>
<div
class=
"home-main-header"
>
<div
class=
"home-main-header-center"
>
<div
class=
"home-main-header-center"
>
<SearchContainer
style=
"margin-bottom: 0; height: fit-content"
v-if=
"containerRef"
placeholder=
"搜索投融资限制政策"
<SearchContainer
:containerRef=
"containerRef"
areaName=
""
/>
style=
"margin-bottom: 0; height: fit-content"
v-if=
"containerRef"
placeholder=
"搜索投融资限制政策"
:containerRef=
"containerRef"
areaName=
""
/>
<!--
<el-input
<!--
<el-input
v-model=
"searchKey"
v-model=
"searchKey"
style=
"width: 100%; height: 48px"
style=
"width: 100%; height: 48px"
...
@@ -76,12 +81,23 @@
...
@@ -76,12 +81,23 @@
<ClickableCard
text=
"资源库"
@
click=
"scrollToTop('position4')"
target=
"_blank"
/>
<ClickableCard
text=
"资源库"
@
click=
"scrollToTop('position4')"
target=
"_blank"
/>
</div>
-->
</div>
-->
<div
class=
"home-main-header-footer-info"
>
<div
class=
"home-main-header-footer-info"
>
<div
class=
"card"
v-for=
"(item, index) in infoList"
:key=
"index"
>
<
!--
<
div
class=
"card"
v-for=
"(item, index) in infoList"
:key=
"index"
>
<div
class=
"icon"
:style=
"
{ background: item.color }">
</div>
<div
class=
"icon"
:style=
"
{ background: item.color }">
</div>
<div
class=
"title"
>
{{
item
.
title
}}
</div>
<div
class=
"title"
>
{{
item
.
title
}}
</div>
<div
class=
"content"
>
{{
item
.
des
}}
</div>
<div
class=
"content"
>
{{
item
.
des
}}
</div>
<div
class=
"num"
:style=
"
{ color: item.color }">
{{
item
.
num
+
"项"
}}
</div>
<div
class=
"num"
:style=
"
{ color: item.color }">
{{
item
.
num
+
"项"
}}
</div>
</div>
</div>
-->
<InfoCard
v-for=
"(item, index) in infoList"
:key=
"item.id"
:title=
"item.nameZh"
:subtitle=
"item.nameAbbr"
:description=
"item.description"
:quantity=
"item.postCount"
unit=
"个"
:color=
"infoListColor[index]"
@
click=
"handleToEntityListNoId(item)"
/>
</div>
</div>
</div>
</div>
...
@@ -110,9 +126,17 @@
...
@@ -110,9 +126,17 @@
</div>
</div>
<div
class=
"box1-top-content-item"
>
<div
class=
"box1-top-content-item"
>
<span
class=
"box1-top-content-item-title"
>
· 涉及领域:
</span>
<span
class=
"box1-top-content-item-title"
>
· 涉及领域:
</span>
<div
class=
"box1-top-content-item-tags"
v-for=
"item in ['航空航天', '人工智能', '集成电路']"
:key=
"item"
>
<div
<el-tag
:type=
"item === '航空航天' ? 'primary' : item === '人工智能' ? 'danger' : 'info'
class=
"box1-top-content-item-tags"
"
>
{{
item
}}
</el-tag>
v-for=
"item in ['航空航天', '人工智能', '集成电路']"
:key=
"item"
>
<el-tag
:type=
"
item === '航空航天' ? 'primary' : item === '人工智能' ? 'danger' : 'info'
"
>
{{
item
}}
</el-tag
>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -170,8 +194,14 @@
...
@@ -170,8 +194,14 @@
</template>
</template>
</custom-container> -->
</custom-container> -->
<RiskSignal
:list=
"warningList"
@
item-click=
"handleToRiskSignalDetail"
@
more-click=
"handleToMoreRiskSignal"
<RiskSignal
riskLevel=
"status"
postDate=
"time"
name=
"title"
/>
:list=
"warningList"
@
item-click=
"handleToRiskSignalDetail"
@
more-click=
"handleToMoreRiskSignal"
riskLevel=
"status"
postDate=
"time"
name=
"title"
/>
</el-col>
</el-col>
</el-row>
</el-row>
<el-row
:gutter=
"20"
style=
"width: 1600px; margin: 0 auto"
>
<el-row
:gutter=
"20"
style=
"width: 1600px; margin: 0 auto"
>
...
@@ -195,11 +225,22 @@
...
@@ -195,11 +225,22 @@
<div
class=
"center-center"
>
<div
class=
"center-center"
>
<div
class=
"center-center-news"
>
<div
class=
"center-center-news"
>
<NewsList
:newsList=
"customNewsData"
@
item-click=
"handleNewsInfoClick"
@
more-click=
"handleToMoreNews"
<NewsList
from=
"from"
content=
"description"
title=
"title"
img=
"image"
/>
:newsList=
"customNewsData"
@
item-click=
"handleNewsInfoClick"
@
more-click=
"handleToMoreNews"
from=
"from"
content=
"description"
title=
"title"
img=
"image"
/>
</div>
</div>
<MessageBubble
:messageList=
"messageList"
@
person-click=
"handlePerClick"
imageUrl=
"avatar"
<MessageBubble
@
more-click=
"handleToSocialDetail"
/>
:messageList=
"messageList"
@
person-click=
"handlePerClick"
imageUrl=
"avatar"
@
more-click=
"handleToSocialDetail"
/>
<!-- <div class="boxs4">
<!-- <div class="boxs4">
<custom-container title="社交媒体" :titleIcon="dialogIcon" height="450px">
<custom-container title="社交媒体" :titleIcon="dialogIcon" height="450px">
<template #default>
<template #default>
...
@@ -239,18 +280,27 @@
...
@@ -239,18 +280,27 @@
<template
#
default=
"scope"
>
<template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<div
style=
"display: flex; align-items: center"
>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
<el-progress
:status=
"getStatus(scope.row.percent)"
/>
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"重点领域"
width=
"180"
>
<el-table-column
label=
"重点领域"
width=
"180"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center; gap: 5px"
>
<div
style=
"display: flex; align-items: center; gap: 5px"
>
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"tag === '通信网络'
<el-tag
? 'primary'
v-for=
"tag in scope.row.tags"
: TAGTYPE[Math.floor(Math.random() * 5)]
:key=
"tag"
"
>
{{
tag
}}
</el-tag>
:type=
"
tag === '通信网络'
? 'primary'
: TAGTYPE[Math.floor(Math.random() * 5)]
"
>
{{
tag
}}
</el-tag
>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
...
@@ -264,18 +314,27 @@
...
@@ -264,18 +314,27 @@
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<div
style=
"display: flex; align-items: center"
>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
<el-progress
:status=
"getStatus(scope.row.percent)"
/>
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"重点领域"
width=
"180"
>
<el-table-column
label=
"重点领域"
width=
"180"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center; gap: 5px"
>
<div
style=
"display: flex; align-items: center; gap: 5px"
>
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"tag === '通信网络'
<el-tag
? 'primary'
v-for=
"tag in scope.row.tags"
: TAGTYPE[Math.floor(Math.random() * 5)]
:key=
"tag"
"
>
{{
tag
}}
</el-tag>
:type=
"
tag === '通信网络'
? 'primary'
: TAGTYPE[Math.floor(Math.random() * 5)]
"
>
{{
tag
}}
</el-tag
>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
...
@@ -289,18 +348,27 @@
...
@@ -289,18 +348,27 @@
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center"
>
<div
style=
"display: flex; align-items: center"
>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<span
style=
"margin-right: 10px; width: 40px"
>
{{
scope
.
row
.
num
}}
次
</span>
<el-progress
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
<el-progress
:status=
"getStatus(scope.row.percent)"
/>
:percentage=
"scope.row.percent * 100"
:show-text=
"false"
:status=
"getStatus(scope.row.percent)"
/>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"重点领域"
width=
"180"
>
<el-table-column
label=
"重点领域"
width=
"180"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
style=
"display: flex; align-items: center; gap: 5px"
>
<div
style=
"display: flex; align-items: center; gap: 5px"
>
<el-tag
v-for=
"tag in scope.row.tags"
:key=
"tag"
:type=
"tag === '通信网络'
<el-tag
? 'primary'
v-for=
"tag in scope.row.tags"
: TAGTYPE[Math.floor(Math.random() * 5)]
:key=
"tag"
"
>
{{
tag
}}
</el-tag>
:type=
"
tag === '通信网络'
? 'primary'
: TAGTYPE[Math.floor(Math.random() * 5)]
"
>
{{
tag
}}
</el-tag
>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
...
@@ -357,7 +425,8 @@
...
@@ -357,7 +425,8 @@
</div>
</div>
</div>
</div>
<div
class=
"box4-footer"
>
<div
class=
"box4-footer"
>
<el-button
type=
"primary"
link
:icon=
"DownRight"
>
查看更多
<el-button
type=
"primary"
link
:icon=
"DownRight"
>
查看更多
<el-icon>
<el-icon>
<DArrowRight
/>
<DArrowRight
/>
</el-icon>
</el-icon>
...
@@ -374,8 +443,15 @@
...
@@ -374,8 +443,15 @@
</
template
>
</
template
>
<
template
#
default
>
<
template
#
default
>
<div
class=
"box5"
>
<div
class=
"box5"
>
<el-table
:data=
"paginatedData"
class=
"sanction-table"
stripe
empty-text=
"暂无数据"
height=
"700px"
<el-table
header-row-class-name=
"table-header"
row-class-name=
"table-row"
>
:data=
"paginatedData"
class=
"sanction-table"
stripe
empty-text=
"暂无数据"
height=
"700px"
header-row-class-name=
"table-header"
row-class-name=
"table-row"
>
<!--
<el-table-column
prop=
"index"
label=
"序号"
width=
"80"
align=
"center"
>
<!--
<el-table-column
prop=
"index"
label=
"序号"
width=
"80"
align=
"center"
>
<template
#
default=
"scope"
>
<template
#
default=
"scope"
>
{{
scope
.
$index
+
1
+
(
currentPage
-
1
)
*
pageSize
}}
{{
scope
.
$index
+
1
+
(
currentPage
-
1
)
*
pageSize
}}
...
@@ -384,12 +460,14 @@
...
@@ -384,12 +460,14 @@
<el-table-column
prop=
"name"
label=
"实体名称"
min-width=
"200"
>
<el-table-column
prop=
"name"
label=
"实体名称"
min-width=
"200"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
style=
"
<div
style=
"
font-weight: 700;
font-weight: 700;
font-size: 16px;
font-size: 16px;
color: rgba(59, 65, 75, 1);
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-family: Microsoft YaHei;
"
>
"
>
{{
scope
.
row
.
name
}}
{{
scope
.
row
.
name
}}
</div>
</div>
</
template
>
</
template
>
...
@@ -398,8 +476,12 @@
...
@@ -398,8 +476,12 @@
<el-table-column
prop=
"domains"
label=
"涉及领域"
min-width=
"180"
>
<el-table-column
prop=
"domains"
label=
"涉及领域"
min-width=
"180"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<div
class=
"domain-tags"
>
<div
class=
"domain-tags"
>
<el-tag
v-for=
"tag in scope.row.domains"
:key=
"tag"
<el-tag
:type=
"tag === '通信网络' ? 'primary' : 'danger'"
>
{{
tag
}}
</el-tag>
v-for=
"tag in scope.row.domains"
:key=
"tag"
:type=
"tag === '通信网络' ? 'primary' : 'danger'"
>
{{
tag
}}
</el-tag
>
</div>
</div>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
...
@@ -435,7 +517,9 @@
...
@@ -435,7 +517,9 @@
<el-table-column
prop=
"revenue"
label=
"50%规则子企业"
width=
"140"
align=
"right"
>
<el-table-column
prop=
"revenue"
label=
"50%规则子企业"
width=
"140"
align=
"right"
>
<
template
#
default=
"scope"
>
<
template
#
default=
"scope"
>
<span
:class=
"['revenue-cell', scope.row.revenue === '无营收数据' ? 'no-revenue' : '']"
>
<span
:class=
"['revenue-cell', scope.row.revenue === '无营收数据' ? 'no-revenue' : '']"
>
{{
scope
.
row
.
revenue
}}
{{
scope
.
row
.
revenue
}}
</span>
</span>
</
template
>
</
template
>
...
@@ -446,8 +530,14 @@
...
@@ -446,8 +530,14 @@
<!-- <div class="pagination-info">
<!-- <div class="pagination-info">
第{{ currentPage }}页,共{{ totalPages }}页
第{{ currentPage }}页,共{{ totalPages }}页
</div> -->
</div> -->
<el-pagination
v-model:current-page=
"currentPage"
:page-size=
"pageSize"
:total=
"total"
<el-pagination
:pager-count=
"5"
layout=
"prev, pager, next"
background
/>
v-model:current-page=
"currentPage"
:page-size=
"pageSize"
:total=
"total"
:pager-count=
"5"
layout=
"prev, pager, next"
background
/>
</div>
</div>
</div>
</div>
</template>
</template>
...
@@ -494,12 +584,6 @@ import entityIcon from "./assets/images/icon-entity.png";
...
@@ -494,12 +584,6 @@ import entityIcon from "./assets/images/icon-entity.png";
import
newsImg
from
"@/assets/images/news-img.png"
;
import
newsImg
from
"@/assets/images/news-img.png"
;
import
headerIcon1
from
"./assets/icons/header-icon1.png"
;
import
headerIcon2
from
"./assets/icons/header-icon2.png"
;
import
headerIcon3
from
"./assets/icons/header-icon3.png"
;
import
headerIcon4
from
"./assets/icons/header-icon4.png"
;
import
headerIcon5
from
"./assets/icons/header-icon5.png"
;
import
getMultiLineChart
from
"./utils/multiLineChart"
;
import
getMultiLineChart
from
"./utils/multiLineChart"
;
import
bill1
from
"./assets/images/bill1.png"
;
import
bill1
from
"./assets/images/bill1.png"
;
...
@@ -1218,7 +1302,7 @@ const handleGetHylyList = async () => {
...
@@ -1218,7 +1302,7 @@ const handleGetHylyList = async () => {
hylymc
:
"全部分类"
hylymc
:
"全部分类"
};
};
categoryList
.
value
=
[
obj
,
...
categoryList
.
value
];
categoryList
.
value
=
[
obj
,
...
categoryList
.
value
];
}
catch
(
error
)
{
}
}
catch
(
error
)
{}
};
};
const
chart1Data
=
ref
({
const
chart1Data
=
ref
({
...
@@ -1264,7 +1348,7 @@ const handleGetBillsByType = async () => {
...
@@ -1264,7 +1348,7 @@ const handleGetBillsByType = async () => {
img
:
bill1
img
:
bill1
};
};
});
});
}
catch
(
error
)
{
}
}
catch
(
error
)
{}
};
};
// 查看社交媒体详情
// 查看社交媒体详情
const
handleToSocialDetail
=
item
=>
{
const
handleToSocialDetail
=
item
=>
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论