Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
sts网站
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
liyang
sts网站
Commits
b86b7619
Commit
b86b7619
authored
Apr 16, 2026
by
liyang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:新增若干修改项
parent
57104fe8
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
945 additions
and
1035 deletions
+945
-1035
index.vue
admin-ui/src/views/sdgsat1/case/index.vue
+167
-92
progress.js
portal-ui/src/api/portal/progress.js
+10
-0
PortalFooter.vue
portal-ui/src/components/PortalFooter.vue
+0
-1
PortalNav.vue
portal-ui/src/components/PortalNav.vue
+0
-1
BannerCarousel.vue
portal-ui/src/components/portal/BannerCarousel.vue
+16
-1
index.js
portal-ui/src/router/index.js
+6
-6
Achievement.vue
portal-ui/src/views/portal/Achievement.vue
+246
-4
AchievementDetail.vue
portal-ui/src/views/portal/AchievementDetail.vue
+32
-7
Application.vue
portal-ui/src/views/portal/Application.vue
+0
-765
ProgressDetail.vue
portal-ui/src/views/portal/ProgressDetail.vue
+254
-0
SDGSAT1.vue
portal-ui/src/views/portal/SDGSAT1.vue
+3
-2
SDGSAT1CaseDetail.vue
portal-ui/src/views/portal/SDGSAT1CaseDetail.vue
+199
-156
PortalProgressController.java
...ruoyi/web/controller/portal/PortalProgressController.java
+12
-0
No files found.
admin-ui/src/views/sdgsat1/case/index.vue
View file @
b86b7619
<
template
>
<
template
>
<div
class=
"app-container"
>
<div
class=
"app-container"
>
<el-form
:model=
"queryParams"
ref=
"queryForm"
size=
"small"
:inline=
"true"
v-show=
"showSearch"
label-width=
"80px"
>
<el-form
:model=
"queryParams"
ref=
"queryForm"
size=
"small"
:inline=
"true"
v-show=
"showSearch"
label-width=
"80px"
>
<el-form-item
label=
"案例名称"
prop=
"title"
>
<el-form-item
label=
"案例名称"
prop=
"title"
>
<el-input
<el-input
v-model=
"queryParams.title"
v-model=
"queryParams.title"
...
@@ -37,8 +44,16 @@
...
@@ -37,8 +44,16 @@
></el-date-picker>
></el-date-picker>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item>
<el-button
type=
"primary"
icon=
"el-icon-search"
size=
"mini"
@
click=
"handleQuery"
>
搜索
</el-button>
<el-button
<el-button
icon=
"el-icon-refresh"
size=
"mini"
@
click=
"resetQuery"
>
重置
</el-button>
type=
"primary"
icon=
"el-icon-search"
size=
"mini"
@
click=
"handleQuery"
>
搜索
</el-button
>
<el-button
icon=
"el-icon-refresh"
size=
"mini"
@
click=
"resetQuery"
>
重置
</el-button
>
</el-form-item>
</el-form-item>
</el-form>
</el-form>
...
@@ -51,7 +66,8 @@
...
@@ -51,7 +66,8 @@
size=
"mini"
size=
"mini"
@
click=
"handleAdd"
@
click=
"handleAdd"
v-hasPermi=
"['sdgsat1:case:add']"
v-hasPermi=
"['sdgsat1:case:add']"
>
新增
</el-button>
>
新增
</el-button
>
</el-col>
</el-col>
<el-col
:span=
"1.5"
>
<el-col
:span=
"1.5"
>
<el-button
<el-button
...
@@ -62,7 +78,8 @@
...
@@ -62,7 +78,8 @@
:disabled=
"single"
:disabled=
"single"
@
click=
"handleUpdate"
@
click=
"handleUpdate"
v-hasPermi=
"['sdgsat1:case:edit']"
v-hasPermi=
"['sdgsat1:case:edit']"
>
修改
</el-button>
>
修改
</el-button
>
</el-col>
</el-col>
<el-col
:span=
"1.5"
>
<el-col
:span=
"1.5"
>
<el-button
<el-button
...
@@ -73,15 +90,28 @@
...
@@ -73,15 +90,28 @@
:disabled=
"multiple"
:disabled=
"multiple"
@
click=
"handleDelete"
@
click=
"handleDelete"
v-hasPermi=
"['sdgsat1:case:remove']"
v-hasPermi=
"['sdgsat1:case:remove']"
>
删除
</el-button>
>
删除
</el-button
>
</el-col>
</el-col>
<right-toolbar
:showSearch
.
sync=
"showSearch"
@
queryTable=
"getList"
></right-toolbar>
<right-toolbar
:showSearch
.
sync=
"showSearch"
@
queryTable=
"getList"
></right-toolbar>
</el-row>
</el-row>
<el-table
v-loading=
"loading"
:data=
"caseList"
@
selection-change=
"handleSelectionChange"
>
<el-table
v-loading=
"loading"
:data=
"caseList"
@
selection-change=
"handleSelectionChange"
>
<el-table-column
type=
"selection"
width=
"55"
align=
"center"
/>
<el-table-column
type=
"selection"
width=
"55"
align=
"center"
/>
<el-table-column
label=
"序号"
align=
"center"
prop=
"id"
width=
"80"
/>
<el-table-column
label=
"序号"
align=
"center"
prop=
"id"
width=
"80"
/>
<el-table-column
label=
"封面"
align=
"center"
prop=
"coverImage"
width=
"100"
>
<el-table-column
label=
"封面"
align=
"center"
prop=
"coverImage"
width=
"100"
>
<template
slot-scope=
"scope"
>
<template
slot-scope=
"scope"
>
<el-image
<el-image
v-if=
"scope.row.coverImage"
v-if=
"scope.row.coverImage"
...
@@ -107,22 +137,42 @@
...
@@ -107,22 +137,42 @@
:show-overflow-tooltip=
"true"
:show-overflow-tooltip=
"true"
min-width=
"200"
min-width=
"200"
/>
/>
<el-table-column
label=
"应用领域"
align=
"center"
prop=
"applicationField"
width=
"120"
/>
<el-table-column
label=
"应用领域"
align=
"center"
prop=
"applicationField"
width=
"120"
/>
<el-table-column
label=
"状态"
align=
"center"
prop=
"status"
width=
"80"
>
<el-table-column
label=
"状态"
align=
"center"
prop=
"status"
width=
"80"
>
<
template
slot-scope=
"scope"
>
<
template
slot-scope=
"scope"
>
<el-tag
:type=
"scope.row.status === '0' ? 'success' : 'danger'"
>
<el-tag
:type=
"scope.row.status === '0' ? 'success' : 'danger'"
>
{{
scope
.
row
.
status
===
'0'
?
'正常'
:
'停用'
}}
{{
scope
.
row
.
status
===
"0"
?
"正常"
:
"停用"
}}
</el-tag>
</el-tag>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
label=
"排序"
align=
"center"
prop=
"sort"
width=
"80"
/>
<el-table-column
label=
"排序"
align=
"center"
prop=
"sort"
width=
"80"
/>
<el-table-column
label=
"发布人"
align=
"center"
prop=
"createBy"
width=
"100"
/>
<el-table-column
<el-table-column
label=
"发布时间"
align=
"center"
prop=
"createTime"
width=
"120"
>
label=
"发布人"
align=
"center"
prop=
"createBy"
width=
"100"
/>
<el-table-column
label=
"发布时间"
align=
"center"
prop=
"createTime"
width=
"120"
>
<
template
slot-scope=
"scope"
>
<
template
slot-scope=
"scope"
>
<span>
{{
parseTime
(
scope
.
row
.
createTime
,
'{y
}
-{m
}
-{d
}
'
)
}}
<
/span
>
<span>
{{
parseTime
(
scope
.
row
.
createTime
,
"{y
}
-{m
}
-{d
}
"
)
}}
<
/span
>
<
/template
>
<
/template
>
<
/el-table-column
>
<
/el-table-column
>
<
el
-
table
-
column
label
=
"操作"
align
=
"center"
class
-
name
=
"small-padding fixed-width"
width
=
"180"
>
<
el
-
table
-
column
label
=
"操作"
align
=
"center"
class
-
name
=
"small-padding fixed-width"
width
=
"180"
>
<
template
slot
-
scope
=
"scope"
>
<
template
slot
-
scope
=
"scope"
>
<
el
-
button
<
el
-
button
size
=
"mini"
size
=
"mini"
...
@@ -130,20 +180,22 @@
...
@@ -130,20 +180,22 @@
icon
=
"el-icon-edit"
icon
=
"el-icon-edit"
@
click
=
"handleUpdate(scope.row)"
@
click
=
"handleUpdate(scope.row)"
v
-
hasPermi
=
"['sdgsat1:case:edit']"
v
-
hasPermi
=
"['sdgsat1:case:edit']"
>
修改
<
/el-button
>
>
修改
<
/el-butto
n
>
<
el
-
button
<
el
-
button
size
=
"mini"
size
=
"mini"
type
=
"text"
type
=
"text"
icon
=
"el-icon-delete"
icon
=
"el-icon-delete"
@
click
=
"handleDelete(scope.row)"
@
click
=
"handleDelete(scope.row)"
v
-
hasPermi
=
"['sdgsat1:case:remove']"
v
-
hasPermi
=
"['sdgsat1:case:remove']"
>
删除
<
/el-button
>
>
删除
<
/el-butto
n
>
<
/template
>
<
/template
>
<
/el-table-column
>
<
/el-table-column
>
<
/el-table
>
<
/el-table
>
<
pagination
<
pagination
v
-
show
=
"total
>
0"
v
-
show
=
"total
>
0"
:
total
=
"total"
:
total
=
"total"
:
page
.
sync
=
"queryParams.pageNum"
:
page
.
sync
=
"queryParams.pageNum"
:
limit
.
sync
=
"queryParams.pageSize"
:
limit
.
sync
=
"queryParams.pageSize"
...
@@ -161,12 +213,19 @@
...
@@ -161,12 +213,19 @@
<
/el-col
>
<
/el-col
>
<
el
-
col
:
span
=
"12"
>
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"应用领域"
prop
=
"applicationField"
>
<
el
-
form
-
item
label
=
"应用领域"
prop
=
"applicationField"
>
<
el
-
input
v
-
model
=
"form.applicationField"
placeholder
=
"请输入应用领域"
/>
<
el
-
input
v
-
model
=
"form.applicationField"
placeholder
=
"请输入应用领域"
/>
<
/el-form-item
>
<
/el-form-item
>
<
/el-col
>
<
/el-col
>
<
el
-
col
:
span
=
"12"
>
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"排序"
prop
=
"sort"
>
<
el
-
form
-
item
label
=
"排序"
prop
=
"sort"
>
<
el
-
input
-
number
v
-
model
=
"form.sort"
controls
-
position
=
"right"
:
min
=
"0"
/>
<
el
-
input
-
number
v
-
model
=
"form.sort"
controls
-
position
=
"right"
:
min
=
"0"
/>
<
/el-form-item
>
<
/el-form-item
>
<
/el-col
>
<
/el-col
>
<
el
-
col
:
span
=
"12"
>
<
el
-
col
:
span
=
"12"
>
...
@@ -179,22 +238,32 @@
...
@@ -179,22 +238,32 @@
<
/el-col
>
<
/el-col
>
<
el
-
col
:
span
=
"24"
>
<
el
-
col
:
span
=
"24"
>
<
el
-
form
-
item
label
=
"封面图片"
>
<
el
-
form
-
item
label
=
"封面图片"
>
<
image
-
upload
v
-
model
=
"form.coverImage"
:
limit
=
"1"
/>
<
image
-
upload
v
-
model
=
"form.coverImage"
:
limit
=
"1"
/>
<
/el-form-item
>
<
/el-form-item
>
<
/el-col
>
<
/el-col
>
<
el
-
col
:
span
=
"24"
>
<
el
-
col
:
span
=
"24"
>
<
el
-
form
-
item
label
=
"概述"
prop
=
"summary"
>
<
el
-
form
-
item
label
=
"概述"
prop
=
"summary"
>
<
el
-
input
v
-
model
=
"form.summary"
type
=
"textarea"
placeholder
=
"请输入概述"
:
rows
=
"3"
/>
<
el
-
input
v
-
model
=
"form.summary"
type
=
"textarea"
placeholder
=
"请输入概述"
:
rows
=
"3"
/>
<
/el-form-item
>
<
/el-form-item
>
<
/el-col
>
<
/el-col
>
<
el
-
col
:
span
=
"24"
>
<
el
-
col
:
span
=
"24"
>
<
el
-
form
-
item
label
=
"内容"
prop
=
"content"
>
<
el
-
form
-
item
label
=
"内容"
prop
=
"content"
>
<
editor
v
-
model
=
"form.content"
:
min
-
height
=
"300"
/>
<
editor
v
-
model
=
"form.content"
:
min
-
height
=
"300"
/>
<
/el-form-item
>
<
/el-form-item
>
<
/el-col
>
<
/el-col
>
<
el
-
col
:
span
=
"24"
>
<
el
-
col
:
span
=
"24"
>
<
el
-
form
-
item
label
=
"备注"
>
<
el
-
form
-
item
label
=
"备注"
>
<
el
-
input
v
-
model
=
"form.remark"
type
=
"textarea"
placeholder
=
"请输入备注"
:
rows
=
"2"
/>
<
el
-
input
v
-
model
=
"form.remark"
type
=
"textarea"
placeholder
=
"请输入备注"
:
rows
=
"2"
/>
<
/el-form-item
>
<
/el-form-item
>
<
/el-col
>
<
/el-col
>
<
/el-row
>
<
/el-row
>
...
@@ -208,7 +277,13 @@
...
@@ -208,7 +277,13 @@
<
/template
>
<
/template
>
<
script
>
<
script
>
import
{
listCase
,
getCase
,
delCase
,
addCase
,
updateCase
}
from
"@/api/sdgsat1/case"
import
{
listCase
,
getCase
,
delCase
,
addCase
,
updateCase
,
}
from
"@/api/sdgsat1/case"
;
export
default
{
export
default
{
name
:
"Case"
,
name
:
"Case"
,
...
@@ -224,53 +299,49 @@ export default {
...
@@ -224,53 +299,49 @@ export default {
title
:
""
,
title
:
""
,
open
:
false
,
open
:
false
,
dateRange
:
[],
dateRange
:
[],
baseUrl
:
''
,
baseUrl
:
""
,
queryParams
:
{
queryParams
:
{
pageNum
:
1
,
pageNum
:
1
,
pageSize
:
10
,
pageSize
:
10
,
title
:
undefined
,
title
:
undefined
,
applicationField
:
undefined
,
applicationField
:
undefined
,
createBy
:
undefined
,
createBy
:
undefined
,
status
:
undefined
status
:
undefined
,
}
,
}
,
form
:
{
}
,
form
:
{
}
,
rules
:
{
rules
:
{
title
:
[
title
:
[
{
required
:
true
,
message
:
"案例名称不能为空"
,
trigger
:
"blur"
}
{
required
:
true
,
message
:
"案例名称不能为空"
,
trigger
:
"blur"
}
,
],
],
applicationField
:
[
applicationField
:
[
{
required
:
true
,
message
:
"应用领域不能为空"
,
trigger
:
"blur"
}
{
required
:
true
,
message
:
"应用领域不能为空"
,
trigger
:
"blur"
}
,
],
],
summary
:
[
summary
:
[{
required
:
true
,
message
:
"概述不能为空"
,
trigger
:
"blur"
}
],
{
required
:
true
,
message
:
"概述不能为空"
,
trigger
:
"blur"
}
content
:
[{
required
:
true
,
message
:
"内容不能为空"
,
trigger
:
"blur"
}
],
],
}
,
content
:
[
}
;
{
required
:
true
,
message
:
"内容不能为空"
,
trigger
:
"blur"
}
]
}
}
}
,
}
,
created
()
{
created
()
{
this
.
baseUrl
=
process
.
env
.
VUE_APP_BASE_API
this
.
baseUrl
=
process
.
env
.
VUE_APP_BASE_API
;
this
.
getList
()
this
.
getList
()
;
}
,
}
,
methods
:
{
methods
:
{
getList
()
{
getList
()
{
this
.
loading
=
true
this
.
loading
=
true
;
this
.
queryParams
.
params
=
{
}
this
.
queryParams
.
params
=
{
}
;
if
(
this
.
dateRange
&&
this
.
dateRange
.
length
===
2
)
{
if
(
this
.
dateRange
&&
this
.
dateRange
.
length
===
2
)
{
this
.
queryParams
.
params
[
'beginTime'
]
=
this
.
dateRange
[
0
]
this
.
queryParams
.
params
[
"beginTime"
]
=
this
.
dateRange
[
0
];
this
.
queryParams
.
params
[
'endTime'
]
=
this
.
dateRange
[
1
]
this
.
queryParams
.
params
[
"endTime"
]
=
this
.
dateRange
[
1
];
}
}
listCase
(
this
.
queryParams
).
then
(
response
=>
{
listCase
(
this
.
queryParams
).
then
(
(
response
)
=>
{
this
.
caseList
=
response
.
rows
this
.
caseList
=
response
.
rows
;
this
.
total
=
response
.
total
this
.
total
=
response
.
total
;
this
.
loading
=
false
this
.
loading
=
false
;
}
)
}
)
;
}
,
}
,
cancel
()
{
cancel
()
{
this
.
open
=
false
this
.
open
=
false
;
this
.
reset
()
this
.
reset
()
;
}
,
}
,
reset
()
{
reset
()
{
this
.
form
=
{
this
.
form
=
{
...
@@ -282,66 +353,70 @@ export default {
...
@@ -282,66 +353,70 @@ export default {
applicationField
:
undefined
,
applicationField
:
undefined
,
sort
:
0
,
sort
:
0
,
status
:
"0"
,
status
:
"0"
,
remark
:
undefined
remark
:
undefined
,
}
}
;
this
.
resetForm
(
"form"
)
this
.
resetForm
(
"form"
)
;
}
,
}
,
handleQuery
()
{
handleQuery
()
{
this
.
queryParams
.
pageNum
=
1
this
.
queryParams
.
pageNum
=
1
;
this
.
getList
()
this
.
getList
()
;
}
,
}
,
resetQuery
()
{
resetQuery
()
{
this
.
dateRange
=
[]
this
.
dateRange
=
[]
;
this
.
resetForm
(
"queryForm"
)
this
.
resetForm
(
"queryForm"
)
;
this
.
handleQuery
()
this
.
handleQuery
()
;
}
,
}
,
handleSelectionChange
(
selection
)
{
handleSelectionChange
(
selection
)
{
this
.
ids
=
selection
.
map
(
item
=>
item
.
id
)
this
.
ids
=
selection
.
map
(
(
item
)
=>
item
.
id
);
this
.
single
=
selection
.
length
!=
1
this
.
single
=
selection
.
length
!=
1
;
this
.
multiple
=
!
selection
.
length
this
.
multiple
=
!
selection
.
length
;
}
,
}
,
handleAdd
()
{
handleAdd
()
{
this
.
reset
()
this
.
reset
()
;
this
.
open
=
true
this
.
open
=
true
;
this
.
title
=
"添加应用案例"
this
.
title
=
"添加应用案例"
;
}
,
}
,
handleUpdate
(
row
)
{
handleUpdate
(
row
)
{
this
.
reset
()
this
.
reset
()
;
const
id
=
row
.
id
||
this
.
ids
const
id
=
row
.
id
||
this
.
ids
;
getCase
(
id
).
then
(
response
=>
{
getCase
(
id
).
then
(
(
response
)
=>
{
this
.
form
=
response
.
data
this
.
form
=
response
.
data
;
this
.
open
=
true
this
.
open
=
true
;
this
.
title
=
"修改应用案例"
this
.
title
=
"修改应用案例"
;
}
)
}
)
;
}
,
}
,
submitForm
:
function
()
{
submitForm
:
function
()
{
this
.
$refs
[
"form"
].
validate
(
valid
=>
{
this
.
$refs
[
"form"
].
validate
(
(
valid
)
=>
{
if
(
valid
)
{
if
(
valid
)
{
if
(
this
.
form
.
id
!=
undefined
)
{
if
(
this
.
form
.
id
!=
undefined
)
{
updateCase
(
this
.
form
).
then
(()
=>
{
updateCase
(
this
.
form
).
then
(()
=>
{
this
.
$modal
.
msgSuccess
(
"修改成功"
)
this
.
$modal
.
msgSuccess
(
"修改成功"
)
;
this
.
open
=
false
this
.
open
=
false
;
this
.
getList
()
this
.
getList
()
;
}
)
}
)
;
}
else
{
}
else
{
addCase
(
this
.
form
).
then
(()
=>
{
addCase
(
this
.
form
).
then
(()
=>
{
this
.
$modal
.
msgSuccess
(
"新增成功"
)
this
.
$modal
.
msgSuccess
(
"新增成功"
)
;
this
.
open
=
false
this
.
open
=
false
;
this
.
getList
()
this
.
getList
()
;
}
)
}
)
;
}
}
}
}
}
)
}
)
;
}
,
}
,
handleDelete
(
row
)
{
handleDelete
(
row
)
{
const
ids
=
row
.
id
||
this
.
ids
const
ids
=
row
.
id
||
this
.
ids
;
this
.
$modal
.
confirm
(
'是否确认删除应用案例编号为"'
+
ids
+
'"的数据项?'
).
then
(
function
()
{
this
.
$modal
return
delCase
(
ids
)
.
confirm
(
'是否确认删除应用案例编号为"'
+
ids
+
'"的数据项?'
)
}
).
then
(()
=>
{
.
then
(
function
()
{
this
.
getList
()
return
delCase
(
ids
);
this
.
$modal
.
msgSuccess
(
"删除成功"
)
}
)
}
).
catch
(()
=>
{
}
)
.
then
(()
=>
{
}
this
.
getList
();
}
this
.
$modal
.
msgSuccess
(
"删除成功"
);
}
}
)
.
catch
(()
=>
{
}
);
}
,
}
,
}
;
<
/script
>
<
/script
>
portal-ui/src/api/portal/progress.js
View file @
b86b7619
...
@@ -49,3 +49,13 @@ export function getImplementationProgress() {
...
@@ -49,3 +49,13 @@ export function getImplementationProgress() {
}
}
})
})
}
}
export
function
getProgressDetail
(
id
)
{
return
request
({
url
:
'/portal/progress/'
+
id
,
method
:
'get'
,
headers
:
{
isToken
:
false
}
})
}
portal-ui/src/components/PortalFooter.vue
View file @
b86b7619
...
@@ -10,7 +10,6 @@
...
@@ -10,7 +10,6 @@
<li><router-link
to=
"/portal/science-plan"
>
科学计划与国际合作
</router-link></li>
<li><router-link
to=
"/portal/science-plan"
>
科学计划与国际合作
</router-link></li>
<li><router-link
to=
"/portal/progress"
>
计划进展
</router-link></li>
<li><router-link
to=
"/portal/progress"
>
计划进展
</router-link></li>
<li><router-link
to=
"/portal/achievement"
>
科研成果
</router-link></li>
<li><router-link
to=
"/portal/achievement"
>
科研成果
</router-link></li>
<li><router-link
to=
"/portal/application"
>
应用与示范
</router-link></li>
<li><router-link
to=
"/portal/sdgsat1"
>
SDGSAT-1专区
</router-link></li>
<li><router-link
to=
"/portal/sdgsat1"
>
SDGSAT-1专区
</router-link></li>
<li><router-link
to=
"/portal/notice"
>
通知公告
</router-link></li>
<li><router-link
to=
"/portal/notice"
>
通知公告
</router-link></li>
</ul>
</ul>
...
...
portal-ui/src/components/PortalNav.vue
View file @
b86b7619
...
@@ -59,7 +59,6 @@ export default {
...
@@ -59,7 +59,6 @@ export default {
{
path
:
'/portal/science-plan'
,
title
:
'科学计划与国际合作'
},
{
path
:
'/portal/science-plan'
,
title
:
'科学计划与国际合作'
},
{
path
:
'/portal/progress'
,
title
:
'计划进展'
},
{
path
:
'/portal/progress'
,
title
:
'计划进展'
},
{
path
:
'/portal/achievement'
,
title
:
'科研成果'
},
{
path
:
'/portal/achievement'
,
title
:
'科研成果'
},
{
path
:
'/portal/application'
,
title
:
'应用与示范'
},
{
path
:
'/portal/sdgsat1'
,
title
:
'SDGSAT-1专区'
},
{
path
:
'/portal/sdgsat1'
,
title
:
'SDGSAT-1专区'
},
{
path
:
'/portal/notice'
,
title
:
'通知公告'
}
{
path
:
'/portal/notice'
,
title
:
'通知公告'
}
]
]
...
...
portal-ui/src/components/portal/BannerCarousel.vue
View file @
b86b7619
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
<div
class=
"banner-carousel"
>
<div
class=
"banner-carousel"
>
<el-carousel
height=
"500px"
:interval=
"5000"
arrow=
"hover"
v-loading=
"loading"
@
change=
"handleCarouselChange"
>
<el-carousel
height=
"500px"
:interval=
"5000"
arrow=
"hover"
v-loading=
"loading"
@
change=
"handleCarouselChange"
>
<el-carousel-item
v-for=
"(item, index) in banners"
:key=
"index"
>
<el-carousel-item
v-for=
"(item, index) in banners"
:key=
"index"
>
<div
class=
"carousel-item"
:style=
"
{ backgroundImage: 'url(' + item.image + ')' }">
<div
class=
"carousel-item"
:style=
"
{ backgroundImage: 'url(' + item.image + ')' }"
@click="goToDetail(item)"
>
</div>
</div>
</el-carousel-item>
</el-carousel-item>
</el-carousel>
</el-carousel>
...
@@ -61,6 +61,14 @@ export default {
...
@@ -61,6 +61,14 @@ export default {
if
(
this
.
banners
.
length
>
0
)
{
if
(
this
.
banners
.
length
>
0
)
{
this
.
currentBanner
=
this
.
banners
[
index
]
this
.
currentBanner
=
this
.
banners
[
index
]
}
}
},
goToDetail
(
item
)
{
if
(
item
.
id
)
{
this
.
$router
.
push
({
path
:
'/portal/progress/detail'
,
query
:
{
id
:
item
.
id
}
})
}
}
}
}
}
}
}
...
@@ -113,6 +121,7 @@ export default {
...
@@ -113,6 +121,7 @@ export default {
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
center
;
position
:
relative
;
position
:
relative
;
cursor
:
pointer
;
&
:
:
before
{
&
:
:
before
{
content
:
''
;
content
:
''
;
...
@@ -123,6 +132,12 @@ export default {
...
@@ -123,6 +132,12 @@ export default {
bottom
:
0
;
bottom
:
0
;
background
:
rgba
(
0
,
0
,
0
,
0
.2
);
background
:
rgba
(
0
,
0
,
0
,
0
.2
);
}
}
&
:hover
{
&
:
:
before
{
background
:
rgba
(
0
,
0
,
0
,
0
.3
);
}
}
}
}
.carousel-content
{
.carousel-content
{
...
...
portal-ui/src/router/index.js
View file @
b86b7619
...
@@ -35,6 +35,12 @@ export const constantRoutes = [
...
@@ -35,6 +35,12 @@ export const constantRoutes = [
component
:
()
=>
import
(
'@/views/portal/Progress'
),
component
:
()
=>
import
(
'@/views/portal/Progress'
),
meta
:
{
title
:
'计划进展'
}
meta
:
{
title
:
'计划进展'
}
},
},
{
path
:
'progress/detail'
,
name
:
'PortalProgressDetail'
,
component
:
()
=>
import
(
'@/views/portal/ProgressDetail'
),
meta
:
{
title
:
'计划进展详情'
}
},
{
{
path
:
'achievement'
,
path
:
'achievement'
,
name
:
'PortalAchievement'
,
name
:
'PortalAchievement'
,
...
@@ -47,12 +53,6 @@ export const constantRoutes = [
...
@@ -47,12 +53,6 @@ export const constantRoutes = [
component
:
()
=>
import
(
'@/views/portal/AchievementDetail'
),
component
:
()
=>
import
(
'@/views/portal/AchievementDetail'
),
meta
:
{
title
:
'科研成果详情'
}
meta
:
{
title
:
'科研成果详情'
}
},
},
{
path
:
'application'
,
name
:
'PortalApplication'
,
component
:
()
=>
import
(
'@/views/portal/Application'
),
meta
:
{
title
:
'应用与示范'
}
},
{
{
path
:
'sdgsat1'
,
path
:
'sdgsat1'
,
name
:
'PortalSDGSAT1'
,
name
:
'PortalSDGSAT1'
,
...
...
portal-ui/src/views/portal/Achievement.vue
View file @
b86b7619
...
@@ -60,6 +60,13 @@
...
@@ -60,6 +60,13 @@
>
>
科学成果
科学成果
</div>
</div>
<div
class=
"menu-item"
:class=
"
{ active: currentMenu === 'sdgCases' }"
@click="handleMenuClick('sdgCases')"
>
SDG应用案例
</div>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -67,7 +74,7 @@
...
@@ -67,7 +74,7 @@
<!-- 右侧内容区域 -->
<!-- 右侧内容区域 -->
<div
class=
"right-content"
>
<div
class=
"right-content"
>
<div
class=
"content-card"
v-loading=
"loading"
>
<div
class=
"content-card"
v-loading=
"loading"
>
<div
class=
"content-header"
v-if=
"currentMenu === 'overview'"
>
<div
class=
"content-header"
>
<span
class=
"title"
>
{{
currentTitle
}}
</span>
<span
class=
"title"
>
{{
currentTitle
}}
</span>
</div>
</div>
<div
class=
"content-body"
>
<div
class=
"content-body"
>
...
@@ -138,6 +145,32 @@
...
@@ -138,6 +145,32 @@
</div>
</div>
</section>
</section>
</div>
</div>
<!-- SDG应用案例内容 -->
<div
v-if=
"currentMenu === 'sdgCases'"
class=
"cases-content"
>
<div
v-if=
"caseList.length === 0"
class=
"empty-container"
>
<i
class=
"el-icon-folder-opened"
></i>
<p>
暂无应用案例数据
</p>
</div>
<div
v-else
class=
"cases-list"
>
<div
class=
"case-item"
v-for=
"(item, index) in caseList"
:key=
"item.id || index"
>
<div
class=
"case-header"
>
<h3
class=
"case-title"
>
{{
item
.
title
}}
</h3>
<div
class=
"case-tag"
>
<el-tag
size=
"small"
:type=
"item.tagType"
>
{{
item
.
tag
}}
</el-tag>
</div>
</div>
<div
class=
"case-thumbnail"
v-if=
"item.thumbnail"
>
<img
:src=
"item.thumbnail"
:alt=
"item.title"
/>
</div>
<div
class=
"case-intro"
v-html=
"item.desc"
></div>
<div
class=
"case-meta"
>
<span><i
class=
"el-icon-location"
></i>
{{
item
.
location
}}
</span>
<span><i
class=
"el-icon-date"
></i>
{{
item
.
date
}}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -150,6 +183,7 @@ import {
...
@@ -150,6 +183,7 @@ import {
getSdgsat1AchievementList
,
getSdgsat1AchievementList
,
getAchievementOverview
,
getAchievementOverview
,
}
from
"@/api/portal/achievement"
;
}
from
"@/api/portal/achievement"
;
import
{
getApplicationList
}
from
"@/api/portal/application"
;
export
default
{
export
default
{
name
:
"Achievement"
,
name
:
"Achievement"
,
...
@@ -167,13 +201,18 @@ export default {
...
@@ -167,13 +201,18 @@ export default {
sdgsat1Total
:
0
,
sdgsat1Total
:
0
,
sdgsat1PageSize
:
10
,
sdgsat1PageSize
:
10
,
sdgsat1PageNum
:
1
,
sdgsat1PageNum
:
1
,
// SDG应用案例数据
caseList
:
[],
};
};
},
},
computed
:
{
computed
:
{
currentTitle
()
{
currentTitle
()
{
return
this
.
currentMenu
===
"overview"
const
titleMap
=
{
?
"成果总体描述"
overview
:
"成果总体描述"
,
:
"科学成果"
;
sdgsat1
:
"科学成果"
,
sdgCases
:
"SDG应用案例"
,
};
return
titleMap
[
this
.
currentMenu
]
||
""
;
},
},
},
},
mounted
()
{
mounted
()
{
...
@@ -227,8 +266,90 @@ export default {
...
@@ -227,8 +266,90 @@ export default {
this
.
fetchAchievementOverview
();
this
.
fetchAchievementOverview
();
}
else
if
(
menu
===
"sdgsat1"
)
{
}
else
if
(
menu
===
"sdgsat1"
)
{
this
.
fetchSdgsat1Achievements
();
this
.
fetchSdgsat1Achievements
();
}
else
if
(
menu
===
"sdgCases"
)
{
this
.
getCaseList
();
}
}
},
},
// 获取SDG应用案例列表
getCaseList
()
{
this
.
loading
=
true
;
const
query
=
{
pageNum
:
1
,
pageSize
:
100
,
status
:
"0"
,
// 只查询正常状态的
};
getApplicationList
(
query
)
.
then
((
response
)
=>
{
if
(
response
.
code
===
200
&&
response
.
rows
)
{
// 转换后端数据为前端展示格式
this
.
caseList
=
response
.
rows
.
map
((
item
)
=>
({
id
:
item
.
id
,
title
:
item
.
caseName
,
desc
:
item
.
introduction
||
item
.
remark
||
"暂无描述"
,
location
:
item
.
applicationUnit
||
"未知"
,
date
:
item
.
publishTime
?
this
.
parseTime
(
item
.
publishTime
,
"{y}-{m}"
)
:
""
,
tag
:
item
.
applicationField
||
"应用案例"
,
tagType
:
this
.
getTagType
(
item
.
applicationField
),
thumbnail
:
item
.
thumbnail
,
}));
}
this
.
loading
=
false
;
})
.
catch
(()
=>
{
this
.
loading
=
false
;
// 如果接口失败,使用默认静态数据
this
.
caseList
=
this
.
getDefaultCaseList
();
});
},
// 根据应用领域获取标签类型
getTagType
(
field
)
{
if
(
!
field
)
return
"info"
;
const
typeMap
=
{
气候变化
:
"primary"
,
生态环境
:
"success"
,
农业
:
"warning"
,
健康
:
"danger"
,
城市
:
"info"
,
水资源
:
"primary"
,
};
for
(
let
key
in
typeMap
)
{
if
(
field
.
includes
(
key
))
{
return
typeMap
[
key
];
}
}
return
"info"
;
},
// 默认案例数据
getDefaultCaseList
()
{
return
[
{
title
:
"气候变化监测系统应用"
,
desc
:
"在某省部署气候变化监测系统,实现气候变化指标的实时监测和预警,为应对气候变化提供科学依据。"
,
location
:
"某省"
,
date
:
"2023-06"
,
tag
:
"气候变化"
,
tagType
:
"primary"
,
},
{
title
:
"生态环境评估平台应用"
,
desc
:
"为某市提供生态环境评估服务,支持生态环境治理决策,有效改善区域生态环境质量。"
,
location
:
"某市"
,
date
:
"2023-08"
,
tag
:
"生态环境"
,
tagType
:
"success"
,
},
{
title
:
"农业产量预测系统应用"
,
desc
:
"在多个农业大县推广农业产量预测系统,提高农业生产效率,助力粮食安全保障。"
,
location
:
"多县"
,
date
:
"2023-09"
,
tag
:
"农业发展"
,
tagType
:
"warning"
,
},
];
},
},
},
};
};
</
script
>
</
script
>
...
@@ -425,6 +546,127 @@ export default {
...
@@ -425,6 +546,127 @@ export default {
}
}
}
}
/* SDG应用案例样式 */
.cases-content
{
.cases-list
{
display
:
flex
;
flex-direction
:
column
;
gap
:
20px
;
.case-item
{
background
:
#ffffff
;
border-radius
:
8px
;
padding
:
24px
;
box-shadow
:
0
2px
12px
rgba
(
0
,
0
,
0
,
0
.08
);
transition
:
all
0
.3s
ease
;
&
:hover
{
transform
:
translateX
(
5px
);
box-shadow
:
0
4px
16px
rgba
(
0
,
0
,
0
,
0
.12
);
}
.case-header
{
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
margin-bottom
:
15px
;
padding-bottom
:
15px
;
border-bottom
:
1px
solid
#e8e8e8
;
.case-title
{
font-size
:
18px
;
font-weight
:
600
;
color
:
#1e3c72
;
margin
:
0
;
flex
:
1
;
}
.case-tag
{
flex-shrink
:
0
;
margin-left
:
15px
;
}
}
.case-thumbnail
{
display
:
flex
;
justify-content
:
center
;
margin-bottom
:
15px
;
img
{
max-width
:
100%
;
max-height
:
300px
;
width
:
auto
;
height
:
auto
;
border-radius
:
8px
;
object-fit
:
contain
;
}
}
.case-intro
{
font-size
:
15px
;
line-height
:
1
.8
;
color
:
#333333
;
margin-bottom
:
15px
;
:deep
(
p
)
{
margin
:
0
0
12px
0
;
&
:last-child
{
margin-bottom
:
0
;
}
}
:deep
(
img
)
{
max-width
:
100%
;
height
:
auto
;
border-radius
:
6px
;
margin
:
10px
0
;
}
:deep
(
h1
),
:deep
(
h2
),
:deep
(
h3
),
:deep
(
h4
)
{
color
:
#1e3c72
;
margin
:
16px
0
10px
0
;
}
:deep
(
ul
),
:deep
(
ol
)
{
margin
:
10px
0
;
padding-left
:
20px
;
}
:deep
(
li
)
{
margin-bottom
:
6px
;
}
:deep
(
a
)
{
color
:
#1e3c72
;
text-decoration
:
none
;
&
:hover
{
text-decoration
:
underline
;
}
}
}
.case-meta
{
display
:
flex
;
gap
:
20px
;
font-size
:
13px
;
color
:
#999999
;
padding-top
:
15px
;
border-top
:
1px
dashed
#e8e8e8
;
span
{
display
:
flex
;
align-items
:
center
;
gap
:
5px
;
i
{
font-size
:
14px
;
}
}
}
}
}
}
.sdgsat1-achievements-list
{
.sdgsat1-achievements-list
{
.achievements-list
{
.achievements-list
{
display
:
flex
;
display
:
flex
;
...
...
portal-ui/src/views/portal/AchievementDetail.vue
View file @
b86b7619
<
template
>
<
template
>
<div
class=
"achievement-detail-page"
>
<div
class=
"achievement-detail-page"
>
<div
class=
"page-container"
>
<!-- 面包屑导航 -->
<div
class=
"back-button"
>
<div
class=
"breadcrumb-container"
>
<el-button
icon=
"el-icon-arrow-left"
@
click=
"goBack"
>
返回列表
</el-button>
<div
class=
"breadcrumb-wrapper"
>
<el-breadcrumb
separator=
"/"
>
<el-breadcrumb-item><a
href=
"/portal"
>
首页
</a></el-breadcrumb-item>
<el-breadcrumb-item><a
href=
"/portal/achievement"
>
科研成果
</a></el-breadcrumb-item>
<el-breadcrumb-item>
成果详情
</el-breadcrumb-item>
</el-breadcrumb>
<el-button
class=
"back-btn"
icon=
"el-icon-arrow-left"
size=
"small"
@
click=
"goBack"
>
返回
</el-button>
</div>
</div>
</div>
<div
class=
"page-container"
>
<div
class=
"detail-card"
v-loading=
"loading"
>
<div
class=
"detail-card"
v-loading=
"loading"
>
<div
class=
"detail-header"
>
<div
class=
"detail-header"
>
<h1
class=
"detail-title"
>
{{
achievement
.
achievementName
}}
</h1>
<h1
class=
"detail-title"
>
{{
achievement
.
achievementName
}}
</h1>
...
@@ -109,16 +117,33 @@ export default {
...
@@ -109,16 +117,33 @@ export default {
width
:
100%
;
width
:
100%
;
min-height
:
calc
(
100vh
-
200px
);
min-height
:
calc
(
100vh
-
200px
);
background
:
linear-gradient
(
135deg
,
#f5f7fa
0%
,
#c3cfe2
100%
);
background
:
linear-gradient
(
135deg
,
#f5f7fa
0%
,
#c3cfe2
100%
);
padding-bottom
:
20px
;
}
}
.page-container
{
/* 面包屑导航 */
.breadcrumb-container
{
// background: #f5f7fa;
padding
:
20px
0
;
// border-bottom: 1px solid #e0e0e0;
}
.breadcrumb-wrapper
{
max-width
:
1200px
;
max-width
:
1200px
;
margin
:
0
auto
;
margin
:
0
auto
;
padding
:
40px
30px
;
padding
:
0
30px
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
.back-btn
{
margin-left
:
20px
;
}
}
}
.back-button
{
.page-container
{
margin-bottom
:
30px
;
max-width
:
1200px
;
margin
:
0
auto
;
padding
:
30px
;
}
}
.detail-card
{
.detail-card
{
...
...
portal-ui/src/views/portal/Application.vue
deleted
100644 → 0
View file @
57104fe8
<
template
>
<div
class=
"application-container"
>
<div
class=
"application-content"
>
<!-- 左侧导航卡片 -->
<div
class=
"left-sidebar"
>
<div
class=
"sidebar-card"
>
<div
class=
"sidebar-header"
>
<span
class=
"title"
>
应用与示范
</span>
</div>
<div
class=
"sidebar-decorator"
>
<div
class=
"decorator-segment"
style=
"background-color: #4B9F37"
></div>
<div
class=
"decorator-segment"
style=
"background-color: #C51A2D"
></div>
<div
class=
"decorator-segment"
style=
"background-color: #E37221"
></div>
<div
class=
"decorator-segment"
style=
"background-color: #0298DB"
></div>
<div
class=
"decorator-segment"
style=
"background-color: #F8C72E"
></div>
<div
class=
"decorator-segment"
style=
"background-color: #D0103A"
></div>
<div
class=
"decorator-segment"
style=
"background-color: #028542"
></div>
<div
class=
"decorator-segment"
style=
"background-color: #BF8B2E"
></div>
<div
class=
"decorator-segment"
style=
"background-color: #0B97D9"
></div>
</div>
<div
class=
"sidebar-menu"
>
<div
class=
"menu-item"
:class=
"
{ active: currentMenu === 'sdgCases' }"
@click="handleMenuClick('sdgCases')"
>
SDG应用案例
</div>
<div
class=
"menu-item"
:class=
"
{ active: currentMenu === 'regionDemos' }"
@click="handleMenuClick('regionDemos')"
>
区域示范
</div>
</div>
</div>
</div>
<!-- 右侧内容区域 -->
<div
class=
"right-content"
>
<div
class=
"content-card"
v-loading=
"loading"
>
<div
class=
"content-header"
>
<span
class=
"title"
>
{{
currentTitle
}}
</span>
</div>
<div
class=
"content-body"
>
<!-- SDG应用案例内容 -->
<div
v-if=
"currentMenu === 'sdgCases'"
class=
"cases-content"
>
<div
v-if=
"caseList.length === 0"
class=
"empty-container"
>
<i
class=
"el-icon-folder-opened"
></i>
<p>
暂无应用案例数据
</p>
</div>
<div
v-else
class=
"cases-list"
>
<div
class=
"case-item"
v-for=
"(item, index) in caseList"
:key=
"item.id || index"
>
<div
class=
"case-header"
>
<h3
class=
"case-title"
>
{{
item
.
title
}}
</h3>
<div
class=
"case-tag"
>
<el-tag
size=
"small"
:type=
"item.tagType"
>
{{
item
.
tag
}}
</el-tag>
</div>
</div>
<div
class=
"case-intro"
v-html=
"item.desc"
></div>
<div
class=
"case-meta"
>
<span><i
class=
"el-icon-location"
></i>
{{
item
.
location
}}
</span>
<span><i
class=
"el-icon-date"
></i>
{{
item
.
date
}}
</span>
</div>
</div>
</div>
</div>
<!-- 区域示范内容 -->
<div
v-if=
"currentMenu === 'regionDemos'"
class=
"demos-content"
>
<div
v-if=
"demoList.length === 0"
class=
"empty-container"
>
<i
class=
"el-icon-s-flag"
></i>
<p>
暂无区域示范数据
</p>
</div>
<div
v-else
class=
"demo-list"
>
<div
class=
"demo-item"
v-for=
"(item, index) in demoList"
:key=
"item.id || index"
>
<div
class=
"demo-status"
>
<el-tag
:type=
"item.statusType"
>
{{
item
.
status
}}
</el-tag>
</div>
<div
class=
"demo-content"
>
<h3>
{{
item
.
title
}}
</h3>
<p>
{{
item
.
desc
}}
</p>
<div
class=
"demo-meta"
>
<span><i
class=
"el-icon-office-building"
></i>
{{
item
.
unit
}}
</span>
<span><i
class=
"el-icon-time"
></i>
{{
item
.
period
}}
</span>
<span><i
class=
"el-icon-map-location"
></i>
{{
item
.
scope
}}
</span>
</div>
</div>
<div
class=
"demo-progress"
>
<div
class=
"progress-label"
>
完成进度
</div>
<el-progress
:percentage=
"item.progress"
:color=
"progressColor"
></el-progress>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
script
>
import
{
getApplicationList
,
getDemoList
}
from
'@/api/portal/application'
export
default
{
name
:
'Application'
,
data
()
{
return
{
loading
:
true
,
currentMenu
:
'sdgCases'
,
// 应用案例数据(来自管理后台)
caseList
:
[],
// 区域示范数据
demoList
:
[],
// 进度条颜色
progressColor
:
[
{
color
:
'#f56c6c'
,
percentage
:
20
},
{
color
:
'#e6a23c'
,
percentage
:
40
},
{
color
:
'#5cb87a'
,
percentage
:
60
},
{
color
:
'#1989fa'
,
percentage
:
80
},
{
color
:
'#6f7ad3'
,
percentage
:
100
}
]
}
},
computed
:
{
currentTitle
()
{
return
this
.
currentMenu
===
'sdgCases'
?
'SDG应用案例'
:
'区域示范'
}
},
created
()
{
this
.
fetchData
()
},
methods
:
{
handleMenuClick
(
menu
)
{
this
.
currentMenu
=
menu
},
// 获取数据
fetchData
()
{
this
.
getCaseList
()
this
.
getDemoList
()
},
// 获取SDG应用案例列表(来自管理后台应用案例管理)
getCaseList
()
{
this
.
loading
=
true
const
query
=
{
pageNum
:
1
,
pageSize
:
100
,
status
:
'0'
// 只查询正常状态的
}
getApplicationList
(
query
).
then
(
response
=>
{
if
(
response
.
code
===
200
&&
response
.
rows
)
{
// 转换后端数据为前端展示格式
this
.
caseList
=
response
.
rows
.
map
(
item
=>
({
id
:
item
.
id
,
title
:
item
.
caseName
,
desc
:
item
.
introduction
||
item
.
remark
||
'暂无描述'
,
location
:
item
.
applicationUnit
||
'未知'
,
date
:
item
.
publishTime
?
this
.
parseTime
(
item
.
publishTime
,
'{y}-{m}'
)
:
''
,
tag
:
item
.
applicationField
||
'应用案例'
,
tagType
:
this
.
getTagType
(
item
.
applicationField
),
thumbnail
:
item
.
thumbnail
}))
}
this
.
loading
=
false
}).
catch
(()
=>
{
this
.
loading
=
false
// 如果接口失败,使用默认静态数据
this
.
caseList
=
this
.
getDefaultCaseList
()
})
},
// 获取区域示范列表
getDemoList
()
{
this
.
loading
=
true
const
query
=
{
pageNum
:
1
,
pageSize
:
100
,
status
:
'0'
}
getDemoList
(
query
).
then
(
response
=>
{
if
(
response
.
code
===
200
&&
response
.
rows
)
{
// 转换后端数据为前端展示格式
this
.
demoList
=
response
.
rows
.
map
((
item
,
index
)
=>
({
id
:
item
.
id
,
title
:
item
.
caseName
,
desc
:
item
.
remark
||
'暂无描述'
,
unit
:
item
.
applicationUnit
||
'未知单位'
,
period
:
item
.
publishTime
?
this
.
parseTime
(
item
.
publishTime
,
'{y}-{m}'
)
:
'2024-2025'
,
scope
:
item
.
applicationField
||
'区域'
,
status
:
'进行中'
,
statusType
:
'warning'
,
progress
:
30
+
(
index
*
15
)
%
70
// 模拟进度
}))
}
this
.
loading
=
false
}).
catch
(()
=>
{
this
.
loading
=
false
// 如果接口失败,使用默认静态数据
this
.
demoList
=
this
.
getDefaultDemoList
()
})
},
// 根据应用领域获取标签类型
getTagType
(
field
)
{
if
(
!
field
)
return
'info'
const
typeMap
=
{
'气候变化'
:
'primary'
,
'生态环境'
:
'success'
,
'农业'
:
'warning'
,
'健康'
:
'danger'
,
'城市'
:
'info'
,
'水资源'
:
'primary'
}
for
(
let
key
in
typeMap
)
{
if
(
field
.
includes
(
key
))
{
return
typeMap
[
key
]
}
}
return
'info'
},
// 默认案例数据
getDefaultCaseList
()
{
return
[
{
title
:
'气候变化监测系统应用'
,
desc
:
'在某省部署气候变化监测系统,实现气候变化指标的实时监测和预警,为应对气候变化提供科学依据。'
,
location
:
'某省'
,
date
:
'2023-06'
,
tag
:
'气候变化'
,
tagType
:
'primary'
},
{
title
:
'生态环境评估平台应用'
,
desc
:
'为某市提供生态环境评估服务,支持生态环境治理决策,有效改善区域生态环境质量。'
,
location
:
'某市'
,
date
:
'2023-08'
,
tag
:
'生态环境'
,
tagType
:
'success'
},
{
title
:
'农业产量预测系统应用'
,
desc
:
'在多个农业大县推广农业产量预测系统,提高农业生产效率,助力粮食安全保障。'
,
location
:
'多县'
,
date
:
'2023-09'
,
tag
:
'农业发展'
,
tagType
:
'warning'
}
]
},
// 默认示范数据
getDefaultDemoList
()
{
return
[
{
title
:
'气候变化监测示范项目'
,
desc
:
'在某省建设气候变化监测示范项目,形成可复制推广的经验,为其他地区提供参考。'
,
unit
:
'某省生态环境厅'
,
period
:
'2023-2025'
,
scope
:
'全省'
,
status
:
'进行中'
,
statusType
:
'warning'
,
progress
:
65
},
{
title
:
'生态环境治理示范项目'
,
desc
:
'在某市开展生态环境治理示范项目,探索生态治理新模式,取得显著成效。'
,
unit
:
'某市生态环境局'
,
period
:
'2023-2024'
,
scope
:
'全市'
,
status
:
'即将完成'
,
statusType
:
'success'
,
progress
:
90
}
]
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.application-container
{
width
:
100%
;
min-height
:
100vh
;
background-color
:
#f5f7fa
;
padding
:
40px
0
;
}
.application-content
{
max-width
:
1390px
;
margin
:
0
auto
;
padding
:
0
30px
;
display
:
grid
;
grid-template-columns
:
300px
1060px
;
gap
:
30px
;
align-items
:
start
;
}
/* 左侧导航卡片 */
.left-sidebar
{
.sidebar-card
{
background
:
#ffffff
;
border-radius
:
8px
;
box-shadow
:
0
2px
12px
rgba
(
0
,
0
,
0
,
0
.08
);
overflow
:
hidden
;
}
.sidebar-header
{
background
:
#1EA8C5
;
// padding: 30px 24px;
height
:
58px
;
display
:
flex
;
align-items
:
center
;
// justify-content: center;
padding-left
:
19px
;
.title
{
font-family
:
Microsoft
YaHei
,
Microsoft
YaHei
;
font-weight
:
bold
;
font-size
:
18px
;
color
:
#FFFFFF
;
line-height
:
18px
;
text-align
:
left
;
font-style
:
normal
;
text-transform
:
none
;
}
}
.sidebar-decorator
{
width
:
100%
;
height
:
6px
;
display
:
flex
;
overflow
:
hidden
;
.decorator-segment
{
width
:
80px
;
height
:
100%
;
&
:first-child
{
margin-left
:
-40px
;
}
&
:last-child
{
margin-right
:
-40px
;
}
}
}
.sidebar-menu
{
padding
:
16px
0
;
.menu-item
{
padding
:
16px
24px
;
cursor
:
pointer
;
transition
:
all
0
.3s
ease
;
font-size
:
16px
;
color
:
#666666
;
border-left
:
3px
solid
transparent
;
&
:hover
{
background-color
:
#f5f7fa
;
color
:
#1e3c72
;
}
&
.active
{
background-color
:
#f0f2f5
;
color
:
#1e3c72
;
font-weight
:
600
;
border-left-color
:
#1e3c72
;
}
}
}
}
/* 右侧内容区域 */
.right-content
{
.content-card
{
background
:
#ffffff
;
border-radius
:
8px
;
box-shadow
:
0
2px
12px
rgba
(
0
,
0
,
0
,
0
.08
);
overflow
:
hidden
;
min-height
:
600px
;
}
.content-header
{
padding
:
30px
30px
0
;
.title
{
font-size
:
20px
;
font-weight
:
600
;
color
:
#1e3c72
;
margin
:
0
;
}
}
.content-body
{
padding
:
30px
;
line-height
:
1
.8
;
color
:
#333333
;
overflow
:
hidden
;
word-wrap
:
break-word
;
overflow-wrap
:
break-word
;
:deep
(
h1
),
:deep
(
h2
),
:deep
(
h3
),
:deep
(
h4
),
:deep
(
h5
),
:deep
(
h6
)
{
color
:
#1e3c72
;
margin-top
:
24px
;
margin-bottom
:
16px
;
}
:deep
(
p
)
{
margin-bottom
:
16px
;
max-width
:
100%
;
overflow
:
hidden
;
}
:deep
(
img
)
{
max-width
:
100%
!
important
;
width
:
100%
!
important
;
height
:
auto
!
important
;
border-radius
:
4px
;
margin
:
16px
0
;
display
:
block
;
box-sizing
:
border-box
;
}
:deep
(
a
)
{
color
:
#1e3c72
;
text-decoration
:
none
;
&
:hover
{
text-decoration
:
underline
;
}
}
:deep
(
ul
),
:deep
(
ol
)
{
margin-left
:
24px
;
margin-bottom
:
16px
;
}
:deep
(
li
)
{
margin-bottom
:
8px
;
}
}
}
/* 应用案例样式 */
.cases-content
{
.cases-list
{
display
:
flex
;
flex-direction
:
column
;
gap
:
20px
;
.case-item
{
background
:
#ffffff
;
border-radius
:
8px
;
padding
:
24px
;
box-shadow
:
0
2px
12px
rgba
(
0
,
0
,
0
,
0
.08
);
transition
:
all
0
.3s
ease
;
&
:hover
{
transform
:
translateX
(
5px
);
box-shadow
:
0
4px
16px
rgba
(
0
,
0
,
0
,
0
.12
);
}
.case-header
{
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
margin-bottom
:
15px
;
padding-bottom
:
15px
;
border-bottom
:
1px
solid
#e8e8e8
;
.case-title
{
font-size
:
18px
;
font-weight
:
600
;
color
:
#1e3c72
;
margin
:
0
;
flex
:
1
;
}
.case-tag
{
flex-shrink
:
0
;
margin-left
:
15px
;
}
}
.case-intro
{
font-size
:
15px
;
line-height
:
1
.8
;
color
:
#333333
;
margin-bottom
:
15px
;
:deep
(
p
)
{
margin
:
0
0
12px
0
;
&
:last-child
{
margin-bottom
:
0
;
}
}
:deep
(
img
)
{
max-width
:
100%
;
height
:
auto
;
border-radius
:
6px
;
margin
:
10px
0
;
}
:deep
(
h1
),
:deep
(
h2
),
:deep
(
h3
),
:deep
(
h4
)
{
color
:
#1e3c72
;
margin
:
16px
0
10px
0
;
}
:deep
(
ul
),
:deep
(
ol
)
{
margin
:
10px
0
;
padding-left
:
20px
;
}
:deep
(
li
)
{
margin-bottom
:
6px
;
}
:deep
(
a
)
{
color
:
#1e3c72
;
text-decoration
:
none
;
&
:hover
{
text-decoration
:
underline
;
}
}
}
.case-meta
{
display
:
flex
;
gap
:
20px
;
font-size
:
13px
;
color
:
#999999
;
padding-top
:
15px
;
border-top
:
1px
dashed
#e8e8e8
;
span
{
display
:
flex
;
align-items
:
center
;
gap
:
5px
;
i
{
font-size
:
14px
;
}
}
}
}
}
}
/* 示范项目样式 */
.demos-content
{
.demo-list
{
display
:
flex
;
flex-direction
:
column
;
gap
:
20px
;
.demo-item
{
display
:
flex
;
align-items
:
flex-start
;
gap
:
20px
;
background
:
#ffffff
;
padding
:
24px
;
border-radius
:
8px
;
box-shadow
:
0
2px
12px
rgba
(
0
,
0
,
0
,
0
.08
);
transition
:
all
0
.3s
ease
;
&
:hover
{
transform
:
translateX
(
10px
);
box-shadow
:
0
4px
16px
rgba
(
0
,
0
,
0
,
0
.12
);
}
.demo-status
{
flex-shrink
:
0
;
}
.demo-content
{
flex
:
1
;
h3
{
font-size
:
18px
;
font-weight
:
600
;
color
:
#1e3c72
;
margin
:
0
0
10px
0
;
}
p
{
font-size
:
14px
;
color
:
#666666
;
line-height
:
1
.6
;
margin
:
0
0
15px
0
;
}
.demo-meta
{
display
:
flex
;
gap
:
25px
;
font-size
:
13px
;
color
:
#999999
;
span
{
display
:
flex
;
align-items
:
center
;
gap
:
5px
;
i
{
font-size
:
14px
;
}
}
}
}
.demo-progress
{
width
:
180px
;
flex-shrink
:
0
;
.progress-label
{
font-size
:
13px
;
color
:
#666666
;
margin-bottom
:
10px
;
}
}
}
}
}
/* 加载和空状态样式 */
.loading-container
,
.empty-container
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
padding
:
80px
20px
;
color
:
#999999
;
i
{
font-size
:
48px
;
margin-bottom
:
16px
;
}
p
{
font-size
:
14px
;
}
}
.loading-container
{
i
{
color
:
#2a5298
;
}
}
/* 响应式设计 */
@media
(
max-width
:
992px
)
{
.application-content
{
grid-template-columns
:
1fr
;
gap
:
20px
;
}
.left-sidebar
{
order
:
2
;
.sidebar-menu
{
display
:
flex
;
overflow-x
:
auto
;
white-space
:
nowrap
;
.menu-item
{
border-left
:
none
;
border-bottom
:
3px
solid
transparent
;
display
:
inline-block
;
margin-right
:
8px
;
border-radius
:
4px
4px
0
0
;
&
.active
{
border-left
:
none
;
border-bottom-color
:
#1e3c72
;
}
}
}
}
.right-content
{
order
:
1
;
}
.demo-item
{
flex-direction
:
column
;
.demo-progress
{
width
:
100%
;
}
}
}
@media
(
max-width
:
768px
)
{
.application-content
{
padding
:
0
20px
;
}
.right-content
{
.content-card
{
min-height
:
500px
;
}
.content-header
{
padding
:
20px
20px
0
;
}
.content-body
{
padding
:
20px
;
}
}
.left-sidebar
{
.sidebar-header
{
padding
:
20px
20px
;
h2
{
font-size
:
20px
;
}
}
.sidebar-menu
{
.menu-item
{
padding
:
12px
20px
;
font-size
:
14px
;
}
}
}
.case-item
{
padding
:
20px
;
}
.demo-item
{
padding
:
20px
;
}
}
</
style
>
<
style
scoped
>
/* 确保图片宽度自适应 */
.content-body
>>>
img
{
max-width
:
100%
!important
;
width
:
100%
!important
;
height
:
auto
!important
;
border-radius
:
4px
;
margin
:
16px
0
;
display
:
block
;
box-sizing
:
border-box
;
}
/* 确保富文本编辑器生成的其他元素也不会溢出 */
.content-body
>>>
.ql-video
{
max-width
:
100%
!important
;
width
:
100%
!important
;
height
:
auto
!important
;
}
</
style
>
portal-ui/src/views/portal/ProgressDetail.vue
0 → 100644
View file @
b86b7619
<
template
>
<div
class=
"progress-detail-page"
>
<!-- 面包屑导航 -->
<div
class=
"breadcrumb-container"
>
<div
class=
"breadcrumb-wrapper"
>
<el-breadcrumb
separator=
"/"
>
<el-breadcrumb-item><a
href=
"/portal"
>
首页
</a></el-breadcrumb-item>
<el-breadcrumb-item><a
href=
"/portal/progress"
>
计划进展
</a></el-breadcrumb-item>
<el-breadcrumb-item>
动态详情
</el-breadcrumb-item>
</el-breadcrumb>
<el-button
class=
"back-btn"
icon=
"el-icon-arrow-left"
size=
"small"
@
click=
"goBack"
>
返回
</el-button>
</div>
</div>
<div
class=
"page-container"
>
<div
class=
"detail-card"
v-loading=
"loading"
>
<div
class=
"detail-header"
>
<h1
class=
"detail-title"
>
{{
progress
.
title
}}
</h1>
<div
class=
"detail-meta"
>
<span
v-if=
"progress.publishTime"
class=
"meta-item"
>
<i
class=
"el-icon-date"
></i>
{{
progress
.
publishTime
}}
</span>
<span
v-if=
"progress.source"
class=
"meta-item"
>
<i
class=
"el-icon-office-building"
></i>
{{
progress
.
source
}}
</span>
</div>
</div>
<div
class=
"detail-body"
>
<div
class=
"detail-thumbnail"
v-if=
"progress.coverImage"
>
<img
:src=
"progress.coverImage"
:alt=
"progress.title"
/>
</div>
<div
class=
"detail-content"
>
<div
class=
"content-section"
v-if=
"progress.summary"
>
<h3>
摘要
</h3>
<p>
{{
progress
.
summary
}}
</p>
</div>
<div
class=
"content-section"
v-if=
"progress.contentCn"
>
<h3>
详情
</h3>
<div
class=
"content-text"
v-html=
"progress.contentCn"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
script
>
import
{
getProgressDetail
}
from
'@/api/portal/progress'
export
default
{
name
:
'ProgressDetail'
,
data
()
{
return
{
progress
:
{},
loading
:
false
}
},
created
()
{
const
id
=
this
.
$route
.
query
.
id
if
(
id
)
{
this
.
fetchProgressDetail
(
id
)
}
else
{
this
.
$message
.
error
(
'缺少动态ID'
)
this
.
goBack
()
}
},
methods
:
{
async
fetchProgressDetail
(
id
)
{
this
.
loading
=
true
try
{
const
response
=
await
getProgressDetail
(
id
)
if
(
response
.
code
===
200
)
{
this
.
progress
=
response
.
data
||
{}
}
else
{
this
.
$message
.
error
(
'获取动态详情失败'
)
}
}
catch
(
error
)
{
console
.
error
(
'获取动态详情失败:'
,
error
)
this
.
$message
.
error
(
'获取动态详情失败'
)
}
finally
{
this
.
loading
=
false
}
},
goBack
()
{
this
.
$router
.
back
()
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.progress-detail-page
{
width
:
100%
;
min-height
:
calc
(
100vh
-
200px
);
background
:
linear-gradient
(
135deg
,
#f5f7fa
0%
,
#c3cfe2
100%
);
padding-bottom
:
20px
;
}
/* 面包屑导航 */
.breadcrumb-container
{
padding
:
20px
0
;
}
.breadcrumb-wrapper
{
max-width
:
1200px
;
margin
:
0
auto
;
padding
:
0
30px
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
.back-btn
{
margin-left
:
20px
;
}
}
.page-container
{
max-width
:
1200px
;
margin
:
0
auto
;
padding
:
30px
;
}
.detail-card
{
background
:
#ffffff
;
border-radius
:
12px
;
box-shadow
:
0
4px
20px
rgba
(
0
,
0
,
0
,
0
.1
);
overflow
:
hidden
;
}
.detail-header
{
padding
:
40px
40px
30px
;
border-bottom
:
1px
solid
#f0f0f0
;
.detail-title
{
font-size
:
32px
;
font-weight
:
700
;
color
:
#1e3c72
;
margin
:
0
0
20px
0
;
line-height
:
1
.4
;
}
.detail-meta
{
display
:
flex
;
flex-wrap
:
wrap
;
gap
:
20px
;
.meta-item
{
display
:
flex
;
align-items
:
center
;
gap
:
8px
;
font-size
:
14px
;
color
:
#666666
;
i
{
font-size
:
16px
;
color
:
#2a5298
;
}
}
}
}
.detail-body
{
padding
:
40px
;
}
.detail-thumbnail
{
width
:
100%
;
max-height
:
500px
;
border-radius
:
8px
;
overflow
:
hidden
;
margin-bottom
:
40px
;
background
:
#f5f7fa
;
img
{
width
:
100%
;
height
:
100%
;
object-fit
:
contain
;
}
}
.detail-content
{
.content-section
{
margin-bottom
:
40px
;
&
:last-child
{
margin-bottom
:
0
;
}
h3
{
font-size
:
20px
;
font-weight
:
600
;
color
:
#1e3c72
;
margin
:
0
0
20px
0
;
padding-bottom
:
10px
;
border-bottom
:
2px
solid
#2a5298
;
}
.content-text
{
font-size
:
15px
;
color
:
#333333
;
line-height
:
1
.8
;
text-align
:
justify
;
::v-deep
{
p
{
margin-bottom
:
15px
;
&
:last-child
{
margin-bottom
:
0
;
}
}
img
{
max-width
:
100%
;
height
:
auto
;
border-radius
:
8px
;
margin
:
20px
0
;
}
}
}
p
{
font-size
:
15px
;
color
:
#333333
;
line-height
:
1
.8
;
margin
:
0
;
}
}
}
@media
(
max-width
:
768px
)
{
.detail-header
{
padding
:
30px
20px
;
.detail-title
{
font-size
:
24px
;
}
}
.detail-body
{
padding
:
20px
;
}
.detail-thumbnail
{
max-height
:
300px
;
}
}
</
style
>
portal-ui/src/views/portal/SDGSAT1.vue
View file @
b86b7619
...
@@ -402,10 +402,11 @@ text-transform: none;
...
@@ -402,10 +402,11 @@ text-transform: none;
background
:
#e0e0e0
;
background
:
#e0e0e0
;
img
{
img
{
width
:
100%
;
width
:
100%
!
important
;
height
:
100%
;
height
:
100%
!
important
;
object-fit
:
cover
;
object-fit
:
cover
;
transition
:
transform
0
.3s
ease
;
transition
:
transform
0
.3s
ease
;
margin
:
0
!
important
;
&
:hover
{
&
:hover
{
transform
:
scale
(
1
.05
);
transform
:
scale
(
1
.05
);
...
...
portal-ui/src/views/portal/SDGSAT1CaseDetail.vue
View file @
b86b7619
<
template
>
<
template
>
<div
class=
"sdgsat1-case-detail"
>
<div
class=
"sdgsat1-case-detail"
>
<!-- 面包屑导航 -->
<!-- 面包屑导航 -->
<div
class=
"breadcrumb"
>
<div
class=
"breadcrumb-container"
>
<div
class=
"breadcrumb-wrapper"
>
<el-breadcrumb
separator=
"/"
>
<el-breadcrumb
separator=
"/"
>
<el-breadcrumb-item><a
href=
"/portal"
>
首页
</a></el-breadcrumb-item>
<el-breadcrumb-item><a
href=
"/portal"
>
首页
</a></el-breadcrumb-item>
<el-breadcrumb-item><a
href=
"/portal/sdgsat1"
>
SDGSAT-1专区
</a></el-breadcrumb-item>
<el-breadcrumb-item
<el-breadcrumb-item><a
href=
"/portal/sdgsat1?menu=cases"
>
数据开发与应用
</a></el-breadcrumb-item>
><a
href=
"/portal/sdgsat1"
>
SDGSAT-1专区
</a></el-breadcrumb-item
>
<el-breadcrumb-item
><a
href=
"/portal/sdgsat1?menu=cases"
>
数据开发与应用
</a
></el-breadcrumb-item
>
<el-breadcrumb-item>
案例详情
</el-breadcrumb-item>
<el-breadcrumb-item>
案例详情
</el-breadcrumb-item>
</el-breadcrumb>
</el-breadcrumb>
<el-button
class=
"back-btn"
icon=
"el-icon-arrow-left"
size=
"small"
@
click=
"goBack"
>
返回
</el-button
>
</div>
</div>
</div>
<!-- 白色背景内容区域 -->
<div
class=
"page-container"
>
<div
class=
"content-container"
v-loading=
"loading"
>
<div
class=
"detail-card"
v-loading=
"loading"
>
<!-- 调试信息 -->
<div
class=
"detail-header"
>
<div
v-if=
"debugInfo"
class=
"debug-info"
>
<h1
class=
"detail-title"
>
{{
caseDetail
.
title
}}
</h1>
<h3>
调试信息
</h3>
<pre>
{{
debugInfo
}}
</pre>
</div>
</div>
<!-- 标题 --
>
<div
class=
"detail-body"
>
<div
class=
"case-title
"
>
<div
class=
"detail-thumbnail"
v-if=
"caseDetail.thumbnail
"
>
<h1>
{{
caseDetail
.
title
}}
</h1
>
<img
:src=
"caseDetail.thumbnail"
:alt=
"caseDetail.title"
/
>
</div>
</div>
<!-- 详情内容 -->
<div
class=
"detail-content"
>
<div
class=
"case-content"
v-html=
"caseDetail.content"
></div>
<div
class=
"content-section"
v-if=
"caseDetail.content"
>
<div
class=
"content-text"
v-html=
"caseDetail.content"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</
template
>
</
template
>
<
script
>
<
script
>
import
{
getCaseDetail
}
from
'@/api/portal/sdgsat1'
import
{
getCaseDetail
}
from
"@/api/portal/sdgsat1"
;
export
default
{
export
default
{
name
:
'SDGSAT1CaseDetail'
,
name
:
"SDGSAT1CaseDetail"
,
data
()
{
data
()
{
return
{
return
{
loading
:
true
,
loading
:
true
,
debugInfo
:
''
,
debugInfo
:
""
,
caseDetail
:
{
caseDetail
:
{
title
:
''
,
title
:
""
,
content
:
''
content
:
""
,
}
}
,
}
}
;
},
},
created
()
{
created
()
{
this
.
getDetail
()
this
.
getDetail
()
;
},
},
methods
:
{
methods
:
{
async
getDetail
()
{
async
getDetail
()
{
this
.
loading
=
true
this
.
loading
=
true
;
try
{
try
{
const
{
id
}
=
this
.
$route
.
query
const
{
id
}
=
this
.
$route
.
query
;
if
(
!
id
)
{
if
(
!
id
)
{
this
.
$message
.
error
(
'缺少案例ID'
)
this
.
$message
.
error
(
"缺少案例ID"
);
this
.
debugInfo
=
'缺少案例ID: '
+
JSON
.
stringify
(
this
.
$route
.
query
)
this
.
debugInfo
=
"缺少案例ID: "
+
JSON
.
stringify
(
this
.
$route
.
query
);
this
.
loading
=
false
this
.
loading
=
false
;
return
return
;
}
}
this
.
debugInfo
=
'获取案例详情,ID: '
+
id
this
.
debugInfo
=
"获取案例详情,ID: "
+
id
;
console
.
log
(
'获取案例详情,ID:'
,
id
)
console
.
log
(
"获取案例详情,ID:"
,
id
);
const
response
=
await
getCaseDetail
(
id
)
const
response
=
await
getCaseDetail
(
id
)
;
this
.
debugInfo
+=
'
\
nAPI响应: '
+
JSON
.
stringify
(
response
)
this
.
debugInfo
+=
"
\n
API响应: "
+
JSON
.
stringify
(
response
);
console
.
log
(
'API响应:'
,
response
)
console
.
log
(
"API响应:"
,
response
);
if
(
response
.
code
===
200
&&
response
.
data
)
{
if
(
response
.
code
===
200
&&
response
.
data
)
{
this
.
caseDetail
=
response
.
data
this
.
caseDetail
=
response
.
data
;
this
.
debugInfo
+=
'
\
n案例详情数据: '
+
JSON
.
stringify
(
this
.
caseDetail
)
this
.
debugInfo
+=
console
.
log
(
'案例详情数据:'
,
this
.
caseDetail
)
"
\n
案例详情数据: "
+
JSON
.
stringify
(
this
.
caseDetail
);
console
.
log
(
"案例详情数据:"
,
this
.
caseDetail
);
}
else
{
}
else
{
this
.
debugInfo
+=
'
\
nAPI响应格式错误: '
+
JSON
.
stringify
(
response
)
this
.
debugInfo
+=
"
\n
API响应格式错误: "
+
JSON
.
stringify
(
response
);
console
.
error
(
'API响应格式错误:'
,
response
)
console
.
error
(
"API响应格式错误:"
,
response
);
this
.
$message
.
error
(
'获取案例详情失败:响应格式错误'
)
this
.
$message
.
error
(
"获取案例详情失败:响应格式错误"
);
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
this
.
debugInfo
+=
'
\
n获取案例详情失败: '
+
error
.
message
this
.
debugInfo
+=
"
\n
获取案例详情失败: "
+
error
.
message
;
console
.
error
(
'获取案例详情失败:'
,
error
)
console
.
error
(
"获取案例详情失败:"
,
error
);
this
.
$message
.
error
(
'获取案例详情失败:网络错误'
)
this
.
$message
.
error
(
"获取案例详情失败:网络错误"
);
}
finally
{
}
finally
{
this
.
loading
=
false
this
.
loading
=
false
;
}
}
}
}
}
},
goBack
()
{
this
.
$router
.
back
();
},
},
};
</
script
>
</
script
>
<
style
lang=
"scss"
scoped
>
<
style
lang=
"scss"
scoped
>
.sdgsat1-case-detail
{
.sdgsat1-case-detail
{
width
:
100%
;
width
:
100%
;
min-height
:
100vh
;
min-height
:
calc
(
100vh
-
200px
);
background-color
:
#f5f7fa
;
background
:
linear-gradient
(
135deg
,
#f5f7fa
0%
,
#c3cfe2
100%
);
padding
:
40px
0
;
}
}
/* 面包屑导航 */
/* 面包屑导航 */
.breadcrumb
{
.breadcrumb-container
{
max-width
:
1390px
;
padding
:
20px
0
;
margin
:
0
auto
30px
;
}
.breadcrumb-wrapper
{
max-width
:
1200px
;
margin
:
0
auto
;
padding
:
0
30px
;
padding
:
0
30px
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
.back-btn
{
margin-left
:
20px
;
}
}
}
/* 内容容器 */
.page-container
{
.content-container
{
max-width
:
1200px
;
max-width
:
1390px
;
margin
:
0
auto
;
margin
:
0
auto
;
padding
:
40px
60px
;
padding
:
30px
;
}
.detail-card
{
background
:
#ffffff
;
background
:
#ffffff
;
border-radius
:
8px
;
border-radius
:
12px
;
box-shadow
:
0
2px
12px
rgba
(
0
,
0
,
0
,
0
.08
);
box-shadow
:
0
4px
20px
rgba
(
0
,
0
,
0
,
0
.1
);
overflow
:
hidden
;
}
}
/* 调试信息 */
.detail-header
{
.debug-info
{
padding
:
40px
40px
30px
;
background
:
#f5f7fa
;
border-bottom
:
1px
solid
#f0f0f0
;
border
:
1px
solid
#e0e0e0
;
border-radius
:
4px
;
padding
:
20px
;
margin-bottom
:
30px
;
h3
{
.detail-title
{
margin-top
:
0
;
font-size
:
32px
;
font-weight
:
700
;
color
:
#1e3c72
;
color
:
#1e3c72
;
}
pre
{
margin
:
0
;
margin
:
0
;
white-space
:
pre-wrap
;
line-height
:
1
.4
;
font-family
:
monospace
;
font-size
:
14px
;
line-height
:
1
.5
;
color
:
#333
;
}
}
}
}
/* 标题样式 */
.detail-body
{
.case-title
{
padding
:
40px
;
}
.detail-thumbnail
{
width
:
100%
;
max-height
:
500px
;
border-radius
:
8px
;
overflow
:
hidden
;
margin-bottom
:
40px
;
margin-bottom
:
40px
;
padding-bottom
:
20px
;
background
:
#f5f7fa
;
border-bottom
:
1px
solid
#e0e0e0
;
h1
{
img
{
font-size
:
28px
;
width
:
100%
;
font-weight
:
700
;
height
:
100%
;
color
:
#1e3c72
;
object-fit
:
contain
;
line-height
:
1
.4
;
margin
:
0
;
}
}
}
}
/* 详情内容样式 */
.detail-content
{
.case-content
{
.content-section
{
line-height
:
1
.8
;
margin-bottom
:
40px
;
&
:last-child
{
margin-bottom
:
0
;
}
.content-text
{
font-size
:
15px
;
color
:
#333333
;
color
:
#333333
;
line-height
:
1
.8
;
text-align
:
justify
;
::v-deep
{
p
{
margin-bottom
:
15px
;
&
:last-child
{
margin-bottom
:
0
;
}
}
img
{
max-width
:
100%
;
height
:
auto
;
border-radius
:
8px
;
margin
:
20px
0
;
}
:deep
(
h1
)
,
h1
,
:deep
(
h2
)
,
h2
,
:deep
(
h3
)
,
h3
,
:deep
(
h4
)
,
h4
,
:deep
(
h5
)
,
h5
,
:deep
(
h6
)
{
h6
{
color
:
#1e3c72
;
color
:
#1e3c72
;
margin-top
:
30px
;
margin-top
:
30px
;
margin-bottom
:
20px
;
margin-bottom
:
20px
;
}
}
:deep
(
h1
)
{
h1
{
font-size
:
24px
;
font-size
:
24px
;
font-weight
:
600
;
font-weight
:
600
;
}
}
:deep
(
h2
)
{
h2
{
font-size
:
20px
;
font-size
:
20px
;
font-weight
:
600
;
font-weight
:
600
;
}
}
:deep
(
h3
)
{
h3
{
font-size
:
18px
;
font-size
:
18px
;
font-weight
:
500
;
font-weight
:
500
;
}
}
:deep
(
p
)
{
ul
,
margin-bottom
:
20px
;
ol
{
}
:deep
(
img
)
{
max-width
:
100%
;
height
:
auto
;
border-radius
:
4px
;
margin
:
20px
0
;
display
:
block
;
}
:deep
(
ul
),
:deep
(
ol
)
{
margin-left
:
24px
;
margin-left
:
24px
;
margin-bottom
:
20px
;
margin-bottom
:
20px
;
}
}
:deep
(
li
)
{
li
{
margin-bottom
:
10px
;
margin-bottom
:
10px
;
}
}
:deep
(
a
)
{
a
{
color
:
#1e3c72
;
color
:
#1e3c72
;
text-decoration
:
none
;
text-decoration
:
none
;
...
@@ -211,25 +253,26 @@ export default {
...
@@ -211,25 +253,26 @@ export default {
text-decoration
:
underline
;
text-decoration
:
underline
;
}
}
}
}
}
}
}
}
}
/* 响应式设计 */
@media
(
max-width
:
768px
)
{
@media
(
max-width
:
768px
)
{
.sdgsat1-case-detail
{
.detail-header
{
padding
:
20px
0
;
padding
:
30px
20px
;
}
.breadcrumb
{
.detail-title
{
margin-bottom
:
20
px
;
font-size
:
24
px
;
padding
:
0
20px
;
}
}
}
.
content-container
{
.
detail-body
{
padding
:
30px
20px
;
padding
:
20px
;
}
}
.
case-title
h1
{
.
detail-thumbnail
{
font-size
:
24
px
;
max-height
:
300
px
;
}
}
}
}
</
style
>
</
style
>
\ No newline at end of file
ruoyi-admin/src/main/java/com/ruoyi/web/controller/portal/PortalProgressController.java
View file @
b86b7619
...
@@ -47,12 +47,14 @@ public class PortalProgressController extends BaseController {
...
@@ -47,12 +47,14 @@ public class PortalProgressController extends BaseController {
return
AjaxResult
.
success
(
list
);
return
AjaxResult
.
success
(
list
);
}
}
@Anonymous
@GetMapping
(
"/projects"
)
@GetMapping
(
"/projects"
)
public
AjaxResult
getProjectList
()
{
public
AjaxResult
getProjectList
()
{
List
<
SysProject
>
list
=
projectService
.
selectSysProjectList
(
new
SysProject
());
List
<
SysProject
>
list
=
projectService
.
selectSysProjectList
(
new
SysProject
());
return
AjaxResult
.
success
(
list
);
return
AjaxResult
.
success
(
list
);
}
}
@Anonymous
@GetMapping
(
"/stats"
)
@GetMapping
(
"/stats"
)
public
AjaxResult
getProgressStats
()
{
public
AjaxResult
getProgressStats
()
{
Map
<
String
,
Object
>
stats
=
new
HashMap
<>();
Map
<
String
,
Object
>
stats
=
new
HashMap
<>();
...
@@ -84,4 +86,14 @@ public class PortalProgressController extends BaseController {
...
@@ -84,4 +86,14 @@ public class PortalProgressController extends BaseController {
SysImplementationProgress
progress
=
implementationProgressService
.
selectSysImplementationProgress
();
SysImplementationProgress
progress
=
implementationProgressService
.
selectSysImplementationProgress
();
return
AjaxResult
.
success
(
progress
);
return
AjaxResult
.
success
(
progress
);
}
}
/**
* 获取实时动态详情
*/
@Anonymous
@GetMapping
(
"/{id}"
)
public
AjaxResult
getProgressDetail
(
@PathVariable
Long
id
)
{
SysRealtimeNews
news
=
realtimeNewsService
.
selectSysRealtimeNewsById
(
id
);
return
AjaxResult
.
success
(
news
);
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment