Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
risk-monitor
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蔡建
risk-monitor
Commits
c49eaec3
提交
c49eaec3
authored
3月 17, 2026
作者:
张伊明
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat 抽取政令原文组件形成公共组件
上级
0b438adc
隐藏空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
539 行增加
和
434 行删除
+539
-434
download.png
src/components/base/DecreeOriginal/assets/icons/download.png
+0
-0
search.png
src/components/base/DecreeOriginal/assets/icons/search.png
+0
-0
index.vue
src/components/base/DecreeOriginal/index.vue
+531
-0
index.vue
src/views/decree/decreeOriginal/index.vue
+8
-434
没有找到文件。
src/components/base/DecreeOriginal/assets/icons/download.png
0 → 100644
浏览文件 @
c49eaec3
350 Bytes
src/components/base/DecreeOriginal/assets/icons/search.png
0 → 100644
浏览文件 @
c49eaec3
399 Bytes
src/components/base/DecreeOriginal/index.vue
0 → 100644
浏览文件 @
c49eaec3
<
template
>
<div
class=
"layout-container"
>
<div
class=
"layout-main"
>
<div
class=
"header-main"
>
<div
class=
"layout-main-header"
>
<div
class=
"icon"
>
<img
:src=
"summaryInfo?.imageUrl"
alt=
""
/>
</div>
<div
class=
"info"
>
<div
class=
"info-box1 one-line-ellipsis"
>
{{
summaryInfo
?.
name
||
"--"
}}
</div>
<div
class=
"info-box2"
>
<div
class=
"info-box2-item"
>
{{
summaryInfo
?.
postDate
||
"--"
}}
</div>
|
<div
class=
"info-box2-item"
>
{{
summaryInfo
?.
orgName
||
"--"
}}
</div>
|
<div
class=
"info-box2-item one-line-ellipsis"
>
{{
summaryInfo
?.
ename
||
"--"
}}
</div>
</div>
</div>
<div
class=
"layout-main-header-right-box"
>
<div
class=
"right-box-top"
>
<div
class=
"time"
>
{{
summaryInfo
?.
postDate
||
"--"
}}
</div>
<div
class=
"name"
>
{{
summaryInfo
?.
orgName
||
"--"
}}
</div>
</div>
</div>
</div>
</div>
<div
class=
"layout-main-center"
>
<div
class=
"report-header"
>
<div
class=
"report-title"
>
政令原文
</div>
<el-switch
v-model=
"isHighlight"
/>
<div
class=
"switch-label switch-label-left"
>
高亮实体
</div>
<el-switch
v-model=
"isTranslate"
/>
<div
class=
"switch-label"
>
原文显示
</div>
<div
class=
"btn"
@
click=
"emits('download')"
>
<div
class=
"icon icon-gap-4"
>
<img
:src=
"defaultDownloadIcon"
alt=
""
/>
</div>
<div
class=
"text"
>
下载
</div>
</div>
<div
class=
"btn"
@
click=
"handleFindWord('open')"
>
<div
class=
"icon icon-gap-6"
>
<img
:src=
"defaultSearchIcon"
alt=
""
/>
</div>
<div
class=
"text"
>
查找
</div>
</div>
<div
class=
"find-word-box"
v-if=
"findWordBox"
>
<div
class=
"find-word-input"
>
<el-input
v-model=
"findWordTxt"
placeholder=
"查找原文内容"
@
input=
"handleUpdateWord"
/>
</div>
<div
class=
"find-word-limit"
>
{{
findWordNum
}}
/
{{
findWordMax
}}
</div>
<div
class=
"find-word-icon"
@
click=
"handleFindWord('last')"
>
<el-icon><ArrowUp
/></el-icon>
</div>
<div
class=
"find-word-icon"
@
click=
"handleFindWord('next')"
>
<el-icon><ArrowDown
/></el-icon>
</div>
<div
class=
"find-word-icon"
@
click=
"handleFindWord('close')"
>
<el-icon><Close
/></el-icon>
</div>
</div>
</div>
<div
class=
"report-main"
>
<div
v-if=
"!displayReportData.length"
class=
"noContent"
>
{{
"暂无数据"
}}
</div>
<el-scrollbar
height=
"100%"
v-else
>
<div
v-for=
"item in displayReportData"
:key=
"item.num"
:class=
"['content-row',
{ 'high-light': isHighlight }]"
>
<div
:class=
"['content-cn',
{ 'translate-cn': !isTranslate }]" v-html="item.content">
</div>
<div
class=
"content-en"
v-html=
"item.contentEn"
v-if=
"isTranslate"
></div>
</div>
</el-scrollbar>
</div>
</div>
</div>
</div>
</
template
>
<
script
setup
>
import
defaultDownloadIcon
from
"./assets/icons/download.png"
;
import
defaultSearchIcon
from
"./assets/icons/search.png"
;
import
{
nextTick
,
ref
,
watch
}
from
"vue"
;
import
{
debounce
}
from
"lodash"
;
// 该组件为公共展示组件:网络请求/下载等业务由父组件处理;查找、高亮、显示切换等通用交互在组件内部封装。
// 图标资源固定使用组件内置文件,保证组件资源自包含。
/**
* 父组件需传入的数据结构说明
*
* @prop {Object} summaryInfo - 顶部摘要信息(用于展示 + 下载)
* @prop {string} summaryInfo.imageUrl - 左上角图标/封面 URL
* @prop {string} summaryInfo.name - 标题
* @prop {string} summaryInfo.postDate - 发布时间(展示在头部与右侧信息)
* @prop {string} summaryInfo.orgName - 发布机构(展示在头部与右侧信息)
* @prop {string} summaryInfo.ename - 英文名/别名(头部展示)
* @prop {string} [summaryInfo.url] - 原文 PDF 下载地址(父组件下载逻辑使用;组件点击“下载”仅触发事件)
*
* @prop {Array<Object>} reportData - 正文分段数组(用于原文渲染/查找高亮)
* @prop {number|string} reportData[].num - 段落序号/唯一标识(用于列表 key)
* @prop {string} reportData[].content - 中文段落 HTML 字符串(组件内使用 v-html 渲染)
* @prop {string} reportData[].contentEn - 英文段落 HTML 字符串(组件内使用 v-html 渲染;关闭“原文显示”时不展示)
*/
const
props
=
defineProps
({
summaryInfo
:
{
type
:
Object
,
default
:
()
=>
({})
},
reportData
:
{
type
:
Array
,
default
:
()
=>
[]
},
});
const
emits
=
defineEmits
([
"download"
]);
const
isHighlight
=
ref
(
false
);
const
isTranslate
=
ref
(
true
);
const
findWordTxt
=
ref
(
""
);
const
findWordBox
=
ref
(
false
);
const
findWordNum
=
ref
(
0
);
const
findWordMax
=
ref
(
0
);
const
originReportData
=
ref
([]);
const
displayReportData
=
ref
([]);
function
escapeRegExp
(
text
)
{
return
text
.
replace
(
/
[
.*+?^${}()|[
\]\\]
/g
,
"
\\
$&"
);
}
function
applyHighlightToText
(
text
,
searchTerm
)
{
if
(
!
text
||
!
searchTerm
)
{
return
{
html
:
text
||
""
,
count
:
0
};
}
const
escapedTerm
=
escapeRegExp
(
searchTerm
);
let
count
=
0
;
const
html
=
String
(
text
).
replace
(
new
RegExp
(
escapedTerm
,
"g"
),
(
match
)
=>
{
count
+=
1
;
return
`<span class="highlight">
${
match
}
</span>`
;
});
return
{
html
,
count
};
}
function
setDisplayFromOrigin
()
{
displayReportData
.
value
=
originReportData
.
value
.
map
((
item
)
=>
({
...
item
,
content
:
item
.
content
||
""
,
contentEn
:
item
.
contentEn
||
""
,
}));
}
function
updateActiveHighlight
()
{
const
spans
=
document
.
querySelectorAll
(
"span.highlight"
);
spans
.
forEach
((
span
,
index
)
=>
{
if
(
index
+
1
===
findWordNum
.
value
)
{
span
.
scrollIntoView
({});
span
.
style
.
backgroundColor
=
"#ff9632"
;
}
else
{
span
.
style
.
backgroundColor
=
"#ffff00"
;
}
});
}
const
doUpdateWord
=
()
=>
{
findWordNum
.
value
=
0
;
findWordMax
.
value
=
0
;
const
term
=
findWordTxt
.
value
?.
trim
();
if
(
!
term
)
{
setDisplayFromOrigin
();
return
;
}
displayReportData
.
value
=
originReportData
.
value
.
map
((
item
)
=>
{
const
cn
=
applyHighlightToText
(
item
.
content
,
term
);
const
en
=
isTranslate
.
value
?
applyHighlightToText
(
item
.
contentEn
,
term
)
:
{
html
:
item
.
contentEn
,
count
:
0
};
findWordMax
.
value
+=
cn
.
count
+
en
.
count
;
return
{
...
item
,
content
:
cn
.
html
,
contentEn
:
en
.
html
,
};
});
if
(
findWordMax
.
value
>
0
)
{
nextTick
(()
=>
{
findWordNum
.
value
=
1
;
updateActiveHighlight
();
});
}
};
const
handleUpdateWord
=
debounce
(()
=>
{
doUpdateWord
();
},
300
);
function
handleFindWord
(
event
)
{
switch
(
event
)
{
case
"open"
:
findWordBox
.
value
=
true
;
break
;
case
"last"
:
if
(
findWordMax
.
value
>
1
)
{
findWordNum
.
value
=
findWordNum
.
value
===
1
?
findWordMax
.
value
:
findWordNum
.
value
-
1
;
updateActiveHighlight
();
}
break
;
case
"next"
:
if
(
findWordMax
.
value
>
1
)
{
findWordNum
.
value
=
findWordNum
.
value
===
findWordMax
.
value
?
1
:
findWordNum
.
value
+
1
;
updateActiveHighlight
();
}
break
;
case
"close"
:
findWordBox
.
value
=
false
;
findWordTxt
.
value
=
""
;
doUpdateWord
();
break
;
}
}
watch
(
()
=>
props
.
reportData
,
(
val
)
=>
{
originReportData
.
value
=
(
val
||
[]).
map
((
item
)
=>
({
content
:
item
?.
content
||
""
,
contentEn
:
item
?.
contentEn
||
""
,
num
:
item
?.
num
,
}));
setDisplayFromOrigin
();
doUpdateWord
();
},
{
deep
:
true
,
immediate
:
true
},
);
watch
(
isTranslate
,
()
=>
{
doUpdateWord
();
});
</
script
>
<
style
lang=
"scss"
scoped
>
.high-light
{
:deep
(
span
.highlight
)
{
background-color
:
#ffff00
;
}
}
.layout-container
{
width
:
100%
;
height
:
100%
;
background-color
:
#f7f8f9
;
.layout-main
{
height
:
100%
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
.header-main
{
padding
:
17px
0
;
width
:
100%
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
}
.layout-main-header
{
width
:
1600px
;
display
:
flex
;
align-items
:
center
;
margin
:
0
auto
;
.icon
{
width
:
64px
;
height
:
40px
;
overflow
:
hidden
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.info
{
margin-left
:
10px
;
margin-right
:
40px
;
width
:
20px
;
flex
:
auto
;
.info-box1
{
width
:
100%
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
600
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
left
;
margin-top
:
5px
;
}
.info-box2
{
margin-top
:
5px
;
height
:
22px
;
line-height
:
22px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
left
;
display
:
flex
;
.info-box2-item
{
white-space
:
nowrap
;
padding
:
0
10px
;
}
.info-box2-item
:first-child
{
padding-left
:
0px
;
}
}
}
.layout-main-header-right-box
{
.right-box-top
{
white-space
:
nowrap
;
.time
{
height
:
24px
;
line-height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
right
;
}
.name
{
height
:
24px
;
line-height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
right
;
}
}
}
}
.layout-main-center
{
width
:
1600px
;
background-color
:
white
;
padding
:
0
60px
;
height
:
20px
;
flex
:
auto
;
display
:
flex
;
flex-direction
:
column
;
.report-header
{
height
:
80px
;
display
:
flex
;
align-items
:
center
;
border-bottom
:
solid
1px
rgba
(
234
,
236
,
238
,
1
);
margin
:
0
20px
10px
;
position
:
relative
;
.find-word-box
{
position
:
absolute
;
top
:
-50px
;
right
:
0px
;
width
:
430px
;
height
:
60px
;
border
:
1px
solid
rgba
(
230
,
231
,
232
,
1
);
background-color
:
white
;
border-radius
:
6px
;
display
:
flex
;
align-items
:
center
;
.find-word-input
{
width
:
20px
;
flex
:
auto
;
}
.find-word-limit
{
border-right
:
solid
1px
rgba
(
230
,
231
,
232
,
1
);
color
:
#5f656c
;
padding-right
:
16px
;
}
.find-word-icon
{
padding
:
10px
12px
;
margin
:
0
2px
;
cursor
:
pointer
;
}
}
.report-title
{
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
line-height
:
20px
;
font-weight
:
700
;
width
:
20px
;
flex
:
auto
;
}
.btn
{
margin-left
:
10px
;
width
:
88px
;
height
:
32px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
230
,
231
,
232
,
1
);
border-radius
:
6px
;
background
:
rgba
(
255
,
255
,
255
,
1
);
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
cursor
:
pointer
;
.text
{
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Regular
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
24px
;
letter-spacing
:
0px
;
text-align
:
left
;
}
.icon
{
width
:
16px
;
height
:
16px
;
font-size
:
0px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.icon-gap-4
{
margin-right
:
4px
;
}
.icon-gap-6
{
margin-right
:
6px
;
}
}
}
.report-main
{
height
:
20px
;
flex
:
auto
;
box-sizing
:
border-box
;
padding-top
:
10px
;
&
:
:-
webkit-scrollbar
{
display
:
none
;
}
&
:
:-
webkit-scrollbar-thumb
{
background
:
#c1c1c1
;
border-radius
:
4px
;
}
&
:
:-
webkit-scrollbar-track
{
background
:
#f1f1f1
;
}
.noContent
{
height
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Regular
;
font-size
:
20px
;
font-weight
:
400
;
}
.content-row
{
display
:
flex
;
width
:
100%
;
padding
:
0
20px
;
min-height
:
100px
;
gap
:
80px
;
&
:last-child
{
border-bottom
:
none
;
}
.content-en
,
.content-cn
{
width
:
50%
;
flex
:
auto
;
padding-bottom
:
40px
;
box-sizing
:
border-box
;
font-size
:
16px
;
line-height
:
1
.8
;
color
:
#3b414b
;
font-family
:
Microsoft
YaHei
;
text-align
:
justify
;
white-space
:
pre-wrap
;
}
.translate-cn
{
padding-bottom
:
10px
;
}
}
}
}
}
}
.switch-label
{
margin-left
:
6px
;
}
.switch-label-left
{
margin-right
:
10px
;
}
:deep
(
.el-scrollbar__bar.is-vertical
)
{
right
:
0px
;
width
:
4px
;
background
:
transparent
;
border-radius
:
2px
;
&
>
div
{
background
:
#c5c7c9
;
opacity
:
1
;
}
&
>
div
:hover
{
background
:
#505357
;
}
}
</
style
>
src/views/decree/decreeOriginal/index.vue
浏览文件 @
c49eaec3
<
template
>
<div
class=
"layout-container"
>
<!-- 导航菜单 -->
<div
class=
"layout-main"
>
<div
class=
"header-main"
>
<div
class=
"layout-main-header"
>
<div
class=
"icon"
>
<img
:src=
"summaryInfo.imageUrl"
alt=
""
/>
</div>
<div
class=
"info"
>
<div
class=
"info-box1 one-line-ellipsis"
>
{{
summaryInfo
.
name
||
"--"
}}
</div>
<div
class=
"info-box2"
>
<div
class=
"info-box2-item"
>
{{
summaryInfo
.
postDate
||
"--"
}}
</div>
|
<div
class=
"info-box2-item"
>
{{
summaryInfo
.
orgName
||
"--"
}}
</div>
|
<div
class=
"info-box2-item one-line-ellipsis"
>
{{
summaryInfo
.
ename
||
"--"
}}
</div>
</div>
</div>
<div
class=
"layout-main-header-right-box"
>
<div
class=
"right-box-top"
>
<div
class=
"time"
>
{{
summaryInfo
.
postDate
||
"--"
}}
</div>
<div
class=
"name"
>
{{
summaryInfo
.
orgName
||
"--"
}}
</div>
</div>
</div>
</div>
</div>
<div
class=
"layout-main-center"
>
<div
class=
"report-header"
>
<div
class=
"report-title"
>
政令原文
</div>
<el-switch
v-model=
"isHighlight"
/>
<div
style=
"margin-left: 6px; margin-right: 10px;"
>
高亮实体
</div>
<el-switch
v-model=
"isTranslate"
/>
<div
style=
"margin-left: 6px;"
>
原文显示
</div>
<div
class=
"btn"
@
click=
"handleDownload"
>
<div
class=
"icon"
style=
"margin-right: 4px;"
>
<img
:src=
"download"
alt=
""
>
</div>
<div
class=
"text"
>
下载
</div>
</div>
<div
class=
"btn"
@
click=
"handleFindWord('open')"
>
<div
class=
"icon"
style=
"margin-right: 6px;"
>
<img
:src=
"search"
alt=
""
>
</div>
<div
class=
"text"
>
查找
</div>
</div>
<div
class=
"find-word-box"
v-if=
"findWordBox"
>
<div
class=
"find-word-input"
>
<el-input
v-model=
"findWordTxt"
placeholder=
"查找原文内容"
@
input=
"handleUpdateWord()"
/>
</div>
<div
class=
"find-word-limit"
>
{{
findWordNum
}}
/
{{
findWordMax
}}
</div>
<div
class=
"find-word-icon"
@
click=
"handleFindWord('last')"
>
<el-icon><ArrowUp
/></el-icon>
</div>
<div
class=
"find-word-icon"
@
click=
"handleFindWord('next')"
>
<el-icon><ArrowDown
/></el-icon>
</div>
<div
class=
"find-word-icon"
@
click=
"handleFindWord('close')"
>
<el-icon><Close
/></el-icon>
</div>
</div>
</div>
<div
class=
"report-main"
>
<div
v-if=
"!reportData.length"
class=
"noContent"
>
{{
"暂无数据"
}}
</div>
<el-scrollbar
height=
"100%"
v-else
>
<div
v-for=
"(item, index) in reportData"
:key=
"index"
:class=
"['content-row',
{'high-light':isHighlight}]">
<!-- 右侧:中文 -->
<div
:class=
"['content-cn',
{'translate-cn':!isTranslate}]" v-html="item.content">
</div>
<!-- 左侧:英文 -->
<div
class=
"content-en"
v-html=
"item.contentEn"
v-if=
"isTranslate"
></div>
</div>
</el-scrollbar>
</div>
</div>
</div>
</div>
<BaseDecreeOriginal
:summary-info=
"summaryInfo"
:report-data=
"reportData"
@
download=
"handleDownload"
/>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
nextTick
}
from
"vue"
;
import
{
ref
,
onMounted
}
from
"vue"
;
import
{
useRoute
}
from
"vue-router"
;
import
{
ElMessage
}
from
"element-plus"
;
import
{
debounce
}
from
"lodash"
;
import
{
getDecreeSummary
}
from
"@/api/decree/introduction"
;
import
{
getDecreeReport
}
from
"@/api/decree/introduction"
;
import
download
from
"./assets/icons/download.png"
;
import
search
from
"./assets/icons/search.png"
;
import
BaseDecreeOriginal
from
"@/components/base/DecreeOriginal/index.vue"
;
const
route
=
useRoute
();
// 政令原文操作
const
isHighlight
=
ref
(
false
);
const
isTranslate
=
ref
(
true
);
const
findWordTxt
=
ref
(
""
)
const
findWordBox
=
ref
(
false
);
const
findWordNum
=
ref
(
0
);
const
findWordMax
=
ref
(
0
);
const
handleDownload
=
async
()
=>
{
if
(
summaryInfo
.
value
?.
url
)
{
try
{
...
...
@@ -134,76 +54,6 @@ const handleDownload = async () => {
ElMessage
.
warning
(
"暂无下载链接!"
);
}
}
const
handleHighlight
=
()
=>
{
let
spans
=
document
.
querySelectorAll
(
`span.highlight`
);
spans
.
forEach
((
span
,
index
)
=>
{
if
(
index
+
1
===
findWordNum
.
value
)
{
// 平滑滚动 behavior: 'smooth'
span
.
scrollIntoView
({})
span
.
style
.
backgroundColor
=
"#ff9632"
;
}
else
{
span
.
style
.
backgroundColor
=
"#ffff00"
;
}
})
}
const
handleFindWord
=
(
event
)
=>
{
switch
(
event
)
{
case
"open"
:
findWordBox
.
value
=
true
;
break
;
case
"last"
:
if
(
findWordMax
.
value
>
1
)
{
findWordNum
.
value
=
findWordNum
.
value
==
1
?
findWordMax
.
value
:
findWordNum
.
value
-
1
;
handleHighlight
()
}
break
;
case
"next"
:
if
(
findWordMax
.
value
>
1
)
{
findWordNum
.
value
=
findWordNum
.
value
==
findWordMax
.
value
?
1
:
findWordNum
.
value
+
1
;
handleHighlight
()
}
break
;
case
"close"
:
findWordBox
.
value
=
false
;
findWordTxt
.
value
=
""
;
handleUpdateWord
()
break
;
}
}
const
handleUpdateWord
=
debounce
(()
=>
{
console
.
log
(
"更新查找词"
,
findWordTxt
.
value
);
findWordNum
.
value
=
0
;
findWordMax
.
value
=
0
;
if
(
findWordTxt
.
value
)
{
originData
.
forEach
((
item
,
index
)
=>
{
if
(
item
.
content
)
{
reportData
.
value
[
index
].
content
=
highlightText
(
item
.
content
,
findWordTxt
.
value
);
}
if
(
isTranslate
.
value
&&
item
.
contentEn
)
{
reportData
.
value
[
index
].
contentEn
=
highlightText
(
item
.
contentEn
,
findWordTxt
.
value
);
}
});
if
(
findWordMax
.
value
>
0
)
{
nextTick
(()
=>
{
findWordNum
.
value
=
findWordNum
.
value
==
findWordMax
.
value
?
1
:
findWordNum
.
value
+
1
;
handleHighlight
()
})
}
}
else
{
originData
.
forEach
((
item
,
index
)
=>
{
reportData
.
value
[
index
].
content
=
item
.
content
;
reportData
.
value
[
index
].
contentEn
=
item
.
contentEn
;
});
}
},
300
)
const
highlightText
=
(
text
,
searchTerm
)
=>
{
const
escapedTerm
=
searchTerm
.
replace
(
/
[
.*+?^${}()|[
\]\\]
/g
,
'
\\
$&'
);
return
text
.
replace
(
new
RegExp
(
escapedTerm
,
'g'
),
(
match
)
=>
{
findWordMax
.
value
++
;
return
`<span class="highlight">
${
match
}
</span>`
;
});
}
// 获取全局信息
const
summaryInfo
=
ref
({});
...
...
@@ -222,13 +72,12 @@ const handleGetSummary = async () => {
// 获取报告原文 - 修改为获取分段数组
const
reportData
=
ref
([]);
let
originData
=
[];
const
handleGetReport
=
async
()
=>
{
try
{
const
res
=
await
getDecreeReport
({
id
:
route
.
query
.
id
});
console
.
log
(
"报告原文"
,
res
);
if
(
res
.
code
===
200
&&
res
.
data
)
{
originData
=
[];
const
originData
=
[];
let
num
=
Math
.
max
(
res
.
data
.
content
.
length
,
res
.
data
.
contentEn
.
length
)
for
(
let
i
=
0
;
i
<
num
;
i
++
)
{
let
obj
=
{
...
...
@@ -250,278 +99,4 @@ onMounted(() => {
</
script
>
<
style
lang=
"scss"
scoped
>
.high-light
{
:deep
(
span
.highlight
)
{
// color: #055FC2;
background-color
:
#ffff00
;
}
}
.layout-container
{
width
:
100%
;
height
:
100%
;
background-color
:
#F7F8F9
;
.layout-main
{
height
:
100%
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
.header-main
{
padding
:
17px
0
;
width
:
100%
;
border-bottom
:
1px
solid
rgba
(
234
,
236
,
238
,
1
);
box-shadow
:
0px
0px
20px
0px
rgba
(
25
,
69
,
130
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
1
);
}
.layout-main-header
{
width
:
1600px
;
display
:
flex
;
align-items
:
center
;
margin
:
0
auto
;
.icon
{
width
:
64px
;
height
:
40px
;
overflow
:
hidden
;
img
{
width
:
100%
;
height
:
100%
;
}
}
.info
{
margin-left
:
10px
;
margin-right
:
40px
;
width
:
20px
;
flex
:
auto
;
.info-box1
{
width
:
100%
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
font-weight
:
600
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
left
;
margin-top
:
5px
;
}
.info-box2
{
margin-top
:
5px
;
height
:
22px
;
line-height
:
22px
;
color
:
rgba
(
132
,
136
,
142
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
left
;
display
:
flex
;
.info-box2-item
{
white-space
:
nowrap
;
padding
:
0
10px
;
}
.info-box2-item
:first-child
{
padding-left
:
0px
;
}
}
}
.layout-main-header-right-box
{
.right-box-top
{
white-space
:
nowrap
;
.time
{
height
:
24px
;
line-height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
right
;
}
.name
{
height
:
24px
;
line-height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
16px
;
font-weight
:
400
;
line-height
:
22px
;
letter-spacing
:
0px
;
text-align
:
right
;
}
}
}
}
.layout-main-center
{
width
:
1600px
;
background-color
:
white
;
padding
:
0
60px
;
height
:
20px
;
flex
:
auto
;
display
:
flex
;
flex-direction
:
column
;
.report-header
{
height
:
80px
;
display
:
flex
;
align-items
:
center
;
border-bottom
:
solid
1px
rgba
(
234
,
236
,
238
,
1
);
margin
:
0
20px
10px
;
position
:
relative
;
.find-word-box
{
position
:
absolute
;
top
:
-50px
;
right
:
0px
;
width
:
430px
;
height
:
60px
;
border
:
1px
solid
rgba
(
230
,
231
,
232
,
1
);
background-color
:
white
;
border-radius
:
6px
;
display
:
flex
;
align-items
:
center
;
.find-word-input
{
width
:
20px
;
flex
:
auto
;
}
.find-word-limit
{
border-right
:
solid
1px
rgba
(
230
,
231
,
232
,
1
);
color
:
#5F656C
;
padding-right
:
16px
;
}
.find-word-icon
{
padding
:
10px
12px
;
margin
:
0
2px
;
cursor
:
pointer
;
}
}
.report-title
{
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-size
:
20px
;
line-height
:
20px
;
font-weight
:
700
;
width
:
20px
;
flex
:
auto
;
}
.btn
{
margin-left
:
10px
;
width
:
88px
;
height
:
32px
;
box-sizing
:
border-box
;
border
:
1px
solid
rgba
(
230
,
231
,
232
,
1
);
border-radius
:
6px
;
background
:
rgba
(
255
,
255
,
255
,
1
);
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
cursor
:
pointer
;
.text
{
height
:
24px
;
color
:
rgba
(
95
,
101
,
108
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Regular
;
font-size
:
14px
;
font-weight
:
400
;
line-height
:
24px
;
letter-spacing
:
0px
;
text-align
:
left
;
}
.icon
{
width
:
16px
;
height
:
16px
;
font-size
:
0px
;
img
{
width
:
100%
;
height
:
100%
;
}
}
}
}
.report-main
{
height
:
20px
;
flex
:
auto
;
box-sizing
:
border-box
;
padding-top
:
10px
;
// 滚动条样式
&
:
:-
webkit-scrollbar
{
display
:
none
;
}
&
:
:-
webkit-scrollbar-thumb
{
background
:
#c1c1c1
;
border-radius
:
4px
;
}
&
:
:-
webkit-scrollbar-track
{
background
:
#f1f1f1
;
}
.noContent
{
height
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
color
:
rgba
(
59
,
65
,
75
,
1
);
font-family
:
Microsoft
YaHei
;
font-style
:
Regular
;
font-size
:
20px
;
font-weight
:
400
;
}
.content-row
{
display
:
flex
;
width
:
100%
;
padding
:
0
20px
;
min-height
:
100px
;
gap
:
80px
;
&
:last-child
{
border-bottom
:
none
;
}
.content-en
,
.content-cn
{
width
:
50%
;
flex
:
auto
;
padding-bottom
:
40px
;
box-sizing
:
border-box
;
font-size
:
16px
;
line-height
:
1
.8
;
color
:
#3B414B
;
font-family
:
Microsoft
YaHei
;
text-align
:
justify
;
white-space
:
pre-wrap
;
// 保留换行格式
}
.translate-cn
{
padding-bottom
:
10px
;
}
}
}
}
}
}
// 修改element-plus滚动条样式
:deep
(
.el-scrollbar__bar.is-vertical
)
{
right
:
0px
;
width
:
4px
;
background
:
transparent
;
border-radius
:
2px
;
&
>
div
{
background
:
#c5c7c9
;
opacity
:
1
;
}
&
>
div
:hover
{
background
:
#505357
;
}
}
</
style
>
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论