明树Git Lab
Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
J
jt_front
Project
Project
Details
Activity
Releases
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
Administrator
jt_front
Commits
d7b10ba8
Commit
d7b10ba8
authored
Apr 07, 2026
by
zhanghan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完成项目档案库开发
parent
ffdc2ddb
Pipeline
#109390
passed with stage
in 21 seconds
Changes
6
Pipelines
1
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
285 additions
and
140 deletions
+285
-140
README.md
src/components/CollapseNavigation/README.md
+17
-14
annualAdd.vue
src/views/everydayPage/annualAdd.vue
+0
-5
constructionTimeAdd.vue
src/views/investingManage/constructionTimeAdd.vue
+17
-7
decisionAdd.vue
src/views/investingManage/decisionAdd.vue
+188
-61
projectAllPage.vue
src/views/projectManage/projectAllPage.vue
+0
-1
xmdakDetaill.vue
src/views/projectManage/xmdakDetaill.vue
+63
-52
No files found.
src/components/CollapseNavigation/README.md
View file @
d7b10ba8
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
## 功能说明
## 功能说明
这是一个基于 Element Plus
`el-collapse`
的粘性导航组件,可以自动为折叠面板生成右侧导航,支持:
这是一个基于 Element Plus
`el-collapse`
的粘性导航组件,可以自动为折叠面板生成右侧导航,支持:
-
自动获取所有折叠面板项
-
自动获取所有折叠面板项
-
点击导航快速定位到对应面板
-
点击导航快速定位到对应面板
-
滚动时自动高亮当前可见的面板
-
滚动时自动高亮当前可见的面板
...
@@ -42,10 +43,10 @@
...
@@ -42,10 +43,10 @@
</
template
>
</
template
>
<
script
setup
>
<
script
setup
>
import
{
ref
}
from
'vue'
;
import
{
ref
}
from
"vue"
;
import
CollapseNavigation
from
'@/components/CollapseNavigation/index.vue'
;
import
CollapseNavigation
from
"@/components/CollapseNavigation/index.vue"
;
const
activeCollapse
=
ref
([
'项目基本信息'
]);
const
activeCollapse
=
ref
([
"项目基本信息"
]);
const
navigationItems
=
ref
([]);
// 由指令自动填充
const
navigationItems
=
ref
([]);
// 由指令自动填充
const
handleNavClick
=
(
item
)
=>
{
const
handleNavClick
=
(
item
)
=>
{
...
@@ -77,7 +78,7 @@ const handleNavClick = (item) => {
...
@@ -77,7 +78,7 @@ const handleNavClick = (item) => {
## 组件 Props
## 组件 Props
| 参数 | 说明 | 类型 | 默认值 |
| 参数 | 说明 | 类型 | 默认值 |
|
------|------|------|--------
|
|
--------------- | -------------- | ------------ | -----------
|
| navItems | 导航项列表 | Array |
[]
|
| navItems | 导航项列表 | Array |
[]
|
| activeItem | 当前激活的项 | String/Array | '' |
| activeItem | 当前激活的项 | String/Array | '' |
| width | 导航宽度 | String | '200px' |
| width | 导航宽度 | String | '200px' |
...
@@ -88,7 +89,7 @@ const handleNavClick = (item) => {
...
@@ -88,7 +89,7 @@ const handleNavClick = (item) => {
## 组件事件
## 组件事件
| 事件名 | 说明 | 参数 |
| 事件名 | 说明 | 参数 |
|
--------|------|------
|
|
----------------- | ---------------- | ----------------
|
| navClick | 导航项被点击 | item: 导航项对象 |
| navClick | 导航项被点击 | item: 导航项对象 |
| update:activeItem | 激活项变化时触发 | name: 导航项名称 |
| update:activeItem | 激活项变化时触发 | name: 导航项名称 |
...
@@ -99,6 +100,7 @@ const handleNavClick = (item) => {
...
@@ -99,6 +100,7 @@ const handleNavClick = (item) => {
自动获取
`el-collapse`
的所有子项并生成导航数据。
自动获取
`el-collapse`
的所有子项并生成导航数据。
**用法:**
**用法:**
```
vue
```
vue
<el-collapse
v-collapse-nav=
"navigationItems"
>
<el-collapse
v-collapse-nav=
"navigationItems"
>
<!-- 折叠面板项 -->
<!-- 折叠面板项 -->
...
@@ -106,6 +108,7 @@ const handleNavClick = (item) => {
...
@@ -106,6 +108,7 @@ const handleNavClick = (item) => {
```
```
**参数:**
**参数:**
-
`navigationItems`
: 响应式数组,用于接收生成的导航数据
-
`navigationItems`
: 响应式数组,用于接收生成的导航数据
## 高级配置
## 高级配置
...
...
src/views/everydayPage/annualAdd.vue
View file @
d7b10ba8
...
@@ -1069,11 +1069,6 @@ const navigationItems = ref([]);
...
@@ -1069,11 +1069,6 @@ const navigationItems = ref([]);
const
handleNavClick
=
(
item
)
=>
{
const
handleNavClick
=
(
item
)
=>
{
console
.
log
(
"Navigation clicked:"
,
item
);
console
.
log
(
"Navigation clicked:"
,
item
);
// 点击导航时自动展开对应的折叠面板
if
(
!
activeCollapse
.
value
.
includes
(
item
.
name
))
{
activeCollapse
.
value
.
push
(
item
.
name
);
}
// 等待 DOM 更新后滚动
// 等待 DOM 更新后滚动
nextTick
(()
=>
{
nextTick
(()
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
...
...
src/views/investingManage/constructionTimeAdd.vue
View file @
d7b10ba8
...
@@ -530,6 +530,14 @@ import FinancialTable from "@/components/FinancialTable.vue";
...
@@ -530,6 +530,14 @@ import FinancialTable from "@/components/FinancialTable.vue";
import
InvestmentRecoveryTable
from
"@/components/InvestmentRecoveryTable.vue"
;
import
InvestmentRecoveryTable
from
"@/components/InvestmentRecoveryTable.vue"
;
import
routerBack
from
"@/components/common/routerBack.vue"
;
import
routerBack
from
"@/components/common/routerBack.vue"
;
import
CollapseNavigation
from
"@/components/CollapseNavigation/index.vue"
;
import
CollapseNavigation
from
"@/components/CollapseNavigation/index.vue"
;
// 接收父组件传递的 isPreview prop
const
props
=
defineProps
({
isPreview
:
{
type
:
Boolean
,
default
:
undefined
,
},
});
const
transferColumns
=
ref
([
const
transferColumns
=
ref
([
{
{
prop
:
"njfcgbl"
,
prop
:
"njfcgbl"
,
...
@@ -587,11 +595,6 @@ const navigationItems = ref([]);
...
@@ -587,11 +595,6 @@ const navigationItems = ref([]);
const
handleNavClick
=
(
item
)
=>
{
const
handleNavClick
=
(
item
)
=>
{
console
.
log
(
"Navigation clicked:"
,
item
);
console
.
log
(
"Navigation clicked:"
,
item
);
// 点击导航时自动展开对应的折叠面板
if
(
!
activeCollapse
.
value
.
includes
(
item
.
name
))
{
activeCollapse
.
value
.
push
(
item
.
name
);
}
// 等待 DOM 更新后滚动
// 等待 DOM 更新后滚动
nextTick
(()
=>
{
nextTick
(()
=>
{
setTimeout
(()
=>
{
setTimeout
(()
=>
{
...
@@ -1288,8 +1291,15 @@ const changeProject = (val) => {
...
@@ -1288,8 +1291,15 @@ const changeProject = (val) => {
};
};
// 加载状态
// 加载状态
const
loading
=
ref
(
false
);
const
loading
=
ref
(
false
);
// 是否预览模式
// 是否预览模式 - 优先使用父组件传递的 prop,否则从路由参数读取
const
isPreview
=
ref
(
!!
route
.
query
.
isPreview
);
const
isPreview
=
computed
(()
=>
{
// 如果父组件显式传递了 isPreview prop,使用 prop 的值
if
(
props
.
isPreview
!==
undefined
)
{
return
props
.
isPreview
;
}
// 否则从路由参数读取
return
!!
route
.
query
.
isPreview
;
});
// 项目列表数据
// 项目列表数据
const
projectList
=
ref
([]);
const
projectList
=
ref
([]);
// 当前编辑的记录ID
// 当前编辑的记录ID
...
...
src/views/investingManage/decisionAdd.vue
View file @
d7b10ba8
This diff is collapsed.
Click to expand it.
src/views/projectManage/projectAllPage.vue
View file @
d7b10ba8
...
@@ -259,7 +259,6 @@ const previewProject = (item) => {
...
@@ -259,7 +259,6 @@ const previewProject = (item) => {
name
:
"xmdakDetaill"
,
name
:
"xmdakDetaill"
,
// name: "addProject",
// name: "addProject",
query
:
{
query
:
{
isPreview
:
true
,
projectId
:
item
.
id
,
projectId
:
item
.
id
,
},
},
});
});
...
...
src/views/projectManage/xmdakDetaill.vue
View file @
d7b10ba8
...
@@ -54,7 +54,7 @@
...
@@ -54,7 +54,7 @@
</template>
</template>
<
script
setup
>
<
script
setup
>
import
{
ref
,
computed
,
markRaw
}
from
"vue"
;
import
{
ref
,
computed
,
markRaw
,
onMounted
}
from
"vue"
;
import
{
useRoute
}
from
"vue-router"
;
import
{
useRoute
}
from
"vue-router"
;
import
{
import
{
Document
,
Document
,
...
@@ -66,6 +66,13 @@ import {
...
@@ -66,6 +66,13 @@ import {
const
route
=
useRoute
();
const
route
=
useRoute
();
// 初始化时自动加载第一个tab的第一个子项
onMounted
(
async
()
=>
{
if
(
projectId
.
value
)
{
await
switchTab
(
0
);
}
});
// Tab 配置
// Tab 配置
const
tabs
=
ref
([
const
tabs
=
ref
([
{
{
...
@@ -103,13 +110,13 @@ const routeChildren = {
...
@@ -103,13 +110,13 @@ const routeChildren = {
name
:
"projectDraft"
,
name
:
"projectDraft"
,
title
:
"项目遴选"
,
title
:
"项目遴选"
,
desc
:
"项目初选与评估"
,
desc
:
"项目初选与评估"
,
importFn
:
()
=>
import
(
"@/views/projectManage/
projectDraf
t.vue"
),
importFn
:
()
=>
import
(
"@/views/projectManage/
addProjec
t.vue"
),
},
},
{
{
name
:
"projectSetUp"
,
name
:
"projectSetUp"
,
title
:
"项目立项"
,
title
:
"项目立项"
,
desc
:
"项目立项申请"
,
desc
:
"项目立项申请"
,
importFn
:
()
=>
import
(
"@/views/projectManage/
projectSetUp
.vue"
),
importFn
:
()
=>
import
(
"@/views/projectManage/
addProject
.vue"
),
},
},
{
{
name
:
"projectArgument"
,
name
:
"projectArgument"
,
...
@@ -121,12 +128,6 @@ const routeChildren = {
...
@@ -121,12 +128,6 @@ const routeChildren = {
name
:
"projectDecision"
,
name
:
"projectDecision"
,
title
:
"项目决策"
,
title
:
"项目决策"
,
desc
:
"项目投资决策"
,
desc
:
"项目投资决策"
,
importFn
:
()
=>
import
(
"@/views/projectManage/projectDecision.vue"
),
},
{
name
:
"projectAllPage"
,
title
:
"项目档案库"
,
desc
:
"项目档案管理"
,
importFn
:
()
=>
import
(
"@/views/projectManage/addProject.vue"
),
importFn
:
()
=>
import
(
"@/views/projectManage/addProject.vue"
),
},
},
],
],
...
@@ -135,8 +136,7 @@ const routeChildren = {
...
@@ -135,8 +136,7 @@ const routeChildren = {
name
:
"targetLiabilityStatement"
,
name
:
"targetLiabilityStatement"
,
title
:
"投资目标责任书"
,
title
:
"投资目标责任书"
,
desc
:
"投资目标责任管理"
,
desc
:
"投资目标责任管理"
,
importFn
:
()
=>
importFn
:
()
=>
import
(
"@/views/investingManage/addStatement.vue"
),
import
(
"@/views/investingManage/addStatement.vue"
),
},
},
{
{
name
:
"targetControl"
,
name
:
"targetControl"
,
...
@@ -154,8 +154,7 @@ const routeChildren = {
...
@@ -154,8 +154,7 @@ const routeChildren = {
name
:
"constructionTime"
,
name
:
"constructionTime"
,
title
:
"建设期投资回收"
,
title
:
"建设期投资回收"
,
desc
:
"建设期资金回收"
,
desc
:
"建设期资金回收"
,
importFn
:
()
=>
importFn
:
()
=>
import
(
"@/views/investingManage/constructionTimeAdd.vue"
),
import
(
"@/views/investingManage/constructionTimeAdd.vue"
),
},
},
{
{
name
:
"construction"
,
name
:
"construction"
,
...
@@ -187,8 +186,7 @@ const routeChildren = {
...
@@ -187,8 +186,7 @@ const routeChildren = {
name
:
"investmentCecovery"
,
name
:
"investmentCecovery"
,
title
:
"运营期投资回收"
,
title
:
"运营期投资回收"
,
desc
:
"运营期收益回收"
,
desc
:
"运营期收益回收"
,
importFn
:
()
=>
importFn
:
()
=>
import
(
"@/views/castbehind/investmentCecoveryAdd.vue"
),
import
(
"@/views/castbehind/investmentCecoveryAdd.vue"
),
},
},
{
{
name
:
"runningPeriod"
,
name
:
"runningPeriod"
,
...
@@ -218,10 +216,17 @@ const currentTabChildren = computed(() => {
...
@@ -218,10 +216,17 @@ const currentTabChildren = computed(() => {
});
});
// 切换 Tab
// 切换 Tab
const
switchTab
=
(
index
)
=>
{
const
switchTab
=
async
(
index
)
=>
{
activeTab
.
value
=
index
;
activeTab
.
value
=
index
;
// 获取当前Tab的第一个子项
const
children
=
routeChildren
[
tabs
.
value
[
index
].
key
];
if
(
children
&&
children
.
length
>
0
)
{
await
handleSubItemClick
(
children
[
0
]);
}
else
{
activeSubItem
.
value
=
""
;
activeSubItem
.
value
=
""
;
currentComponent
.
value
=
null
;
currentComponent
.
value
=
null
;
}
};
};
// 处理子项点击 - 直接加载详情组件
// 处理子项点击 - 直接加载详情组件
...
@@ -255,15 +260,22 @@ const handleSubItemClick = async (item) => {
...
@@ -255,15 +260,22 @@ const handleSubItemClick = async (item) => {
flex-direction
:
column
;
flex-direction
:
column
;
}
}
// 主 Tab 切换区域 - 现代政府风格
.detail-section
{
.tab-content
{
padding
:
16px
!
important
;
}
::v-deep
.add-project-back
{
display
:
none
;
}
}
.main-tab-wrapper
{
.main-tab-wrapper
{
background
:
white
;
background
:
white
;
padding
:
0
;
padding
:
0
;
box-shadow
:
0
2px
12px
rgba
(
0
,
86
,
179
,
0
.08
);
position
:
sticky
;
position
:
sticky
;
top
:
0
;
top
:
0
;
z-index
:
100
;
z-index
:
100
;
border-bottom
:
2
px
solid
#e8f4fd
;
border-bottom
:
1
px
solid
#e8f4fd
;
}
}
.main-tab-container
{
.main-tab-container
{
...
@@ -280,15 +292,14 @@ const handleSubItemClick = async (item) => {
...
@@ -280,15 +292,14 @@ const handleSubItemClick = async (item) => {
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
center
;
padding
:
1
8px
24
px
;
padding
:
1
0px
16
px
;
cursor
:
pointer
;
cursor
:
pointer
;
transition
:
all
0
.3s
ease
;
transition
:
all
0
.3s
ease
;
position
:
relative
;
position
:
relative
;
border-radius
:
8px
8px
0
0
;
margin-top
:
0
;
margin-top
:
4px
;
.tab-label
{
.tab-label
{
font-size
:
1
5
px
;
font-size
:
1
4
px
;
font-weight
:
500
;
font-weight
:
500
;
color
:
#5a6c7d
;
color
:
#5a6c7d
;
letter-spacing
:
0
.5px
;
letter-spacing
:
0
.5px
;
...
@@ -298,34 +309,31 @@ const handleSubItemClick = async (item) => {
...
@@ -298,34 +309,31 @@ const handleSubItemClick = async (item) => {
}
}
&
:
:
before
{
&
:
:
before
{
content
:
''
;
content
:
""
;
position
:
absolute
;
position
:
absolute
;
bottom
:
0
;
bottom
:
0
;
left
:
0
;
left
:
0
;
right
:
0
;
right
:
0
;
height
:
3
px
;
height
:
2
px
;
background
:
transparent
;
background
:
transparent
;
transition
:
all
0
.3s
ease
;
transition
:
all
0
.3s
ease
;
border-radius
:
3px
3px
0
0
;
}
}
&
:hover
{
&
:hover
{
background
:
linear-gradient
(
to
bottom
,
#f8fbff
,
#ffffff
)
;
background
:
#f8fbff
;
.tab-label
{
.tab-label
{
color
:
#0056b3
;
color
:
#0056b3
;
}
}
&
:
:
before
{
&
:
:
before
{
background
:
linear-gradient
(
to
right
,
#4dabf7
,
#0056b3
)
;
background
:
#4dabf7
;
opacity
:
0
.6
;
opacity
:
0
.6
;
}
}
}
}
&
.active
{
&
.active
{
background
:
white
;
background
:
white
;
margin-top
:
0
;
padding-top
:
22px
;
.tab-label
{
.tab-label
{
color
:
#0056b3
;
color
:
#0056b3
;
...
@@ -333,23 +341,24 @@ const handleSubItemClick = async (item) => {
...
@@ -333,23 +341,24 @@ const handleSubItemClick = async (item) => {
}
}
&
:
:
before
{
&
:
:
before
{
background
:
linear-gradient
(
to
right
,
#4dabf7
,
#0056b3
);
background
:
#0056b3
;
box-shadow
:
0
-2px
8px
rgba
(
0
,
86
,
179
,
0
.15
);
}
}
}
}
}
}
// 子项导航区域
// 子项导航区域
.sub-tab-wrapper
{
.sub-tab-wrapper
{
background
:
linear-gradient
(
to
bottom
,
#f8fbff
,
#ffffff
);
background
:
#ffffff
;
border-bottom
:
1px
solid
#d4e8fc
;
border-bottom
:
1px
solid
#e8f4fd
;
padding
:
16px
24px
;
padding
:
8px
24px
;
box-shadow
:
0
2px
8px
rgba
(
0
,
86
,
179
,
0
.04
);
position
:
sticky
;
top
:
46px
;
z-index
:
99
;
}
}
.sub-tab-container
{
.sub-tab-container
{
display
:
flex
;
display
:
flex
;
gap
:
12
px
;
gap
:
8
px
;
flex-wrap
:
wrap
;
flex-wrap
:
wrap
;
max-width
:
1400px
;
max-width
:
1400px
;
margin
:
0
auto
;
margin
:
0
auto
;
...
@@ -357,23 +366,28 @@ const handleSubItemClick = async (item) => {
...
@@ -357,23 +366,28 @@ const handleSubItemClick = async (item) => {
}
}
.sub-tab-item
{
.sub-tab-item
{
padding
:
12px
24px
;
display
:
flex
;
border-radius
:
20px
;
padding
:
6px
12px
;
border-radius
:
4px
;
cursor
:
pointer
;
cursor
:
pointer
;
transition
:
all
0
.3s
ease
;
transition
:
all
0
.3s
ease
;
background
:
white
;
background
:
white
;
border
:
1
.5
px
solid
#e8f4fd
;
border
:
1px
solid
#e8f4fd
;
position
:
relative
;
position
:
relative
;
overflow
:
hidden
;
overflow
:
hidden
;
&
:
:
before
{
&
:
:
before
{
content
:
''
;
content
:
""
;
position
:
absolute
;
position
:
absolute
;
top
:
0
;
top
:
0
;
left
:
0
;
left
:
0
;
right
:
0
;
right
:
0
;
bottom
:
0
;
bottom
:
0
;
background
:
linear-gradient
(
135deg
,
rgba
(
77
,
171
,
247
,
0
.05
)
,
rgba
(
0
,
86
,
179
,
0
.05
));
background
:
linear-gradient
(
135deg
,
rgba
(
77
,
171
,
247
,
0
.05
)
,
rgba
(
0
,
86
,
179
,
0
.05
)
);
opacity
:
0
;
opacity
:
0
;
transition
:
opacity
0
.3s
ease
;
transition
:
opacity
0
.3s
ease
;
}
}
...
@@ -391,7 +405,6 @@ const handleSubItemClick = async (item) => {
...
@@ -391,7 +405,6 @@ const handleSubItemClick = async (item) => {
&
:hover
{
&
:hover
{
border-color
:
#4dabf7
;
border-color
:
#4dabf7
;
transform
:
translateY
(
-1px
);
transform
:
translateY
(
-1px
);
box-shadow
:
0
4px
12px
rgba
(
77
,
171
,
247
,
0
.15
);
&
:
:
before
{
&
:
:
before
{
opacity
:
1
;
opacity
:
1
;
...
@@ -403,10 +416,9 @@ const handleSubItemClick = async (item) => {
...
@@ -403,10 +416,9 @@ const handleSubItemClick = async (item) => {
}
}
&
.active
{
&
.active
{
background
:
linear-gradient
(
135deg
,
#4dabf7
,
#0056b3
);
background
:
#0056b3
;
border-color
:
transparent
;
border-color
:
#0056b3
;
box-shadow
:
0
4px
16px
rgba
(
0
,
86
,
179
,
0
.25
);
transform
:
translateY
(
-1px
);
transform
:
translateY
(
-2px
);
&
:
:
before
{
&
:
:
before
{
background
:
transparent
;
background
:
transparent
;
...
@@ -415,7 +427,6 @@ const handleSubItemClick = async (item) => {
...
@@ -415,7 +427,6 @@ const handleSubItemClick = async (item) => {
.sub-tab-label
{
.sub-tab-label
{
color
:
white
;
color
:
white
;
font-weight
:
600
;
font-weight
:
600
;
text-shadow
:
0
1px
2px
rgba
(
0
,
0
,
0
,
0
.1
);
}
}
}
}
}
}
...
@@ -472,7 +483,7 @@ const handleSubItemClick = async (item) => {
...
@@ -472,7 +483,7 @@ const handleSubItemClick = async (item) => {
padding
:
12px
16px
;
padding
:
12px
16px
;
.tab-label
{
.tab-label
{
font-size
:
1
3
px
;
font-size
:
1
4
px
;
}
}
}
}
...
@@ -484,7 +495,7 @@ const handleSubItemClick = async (item) => {
...
@@ -484,7 +495,7 @@ const handleSubItemClick = async (item) => {
padding
:
8px
14px
;
padding
:
8px
14px
;
.sub-tab-label
{
.sub-tab-label
{
font-size
:
1
3
px
;
font-size
:
1
4
px
;
}
}
}
}
}
}
...
...
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