明树Git Lab

Commit d7b10ba8 authored by zhanghan's avatar zhanghan

完成项目档案库开发

parent ffdc2ddb
Pipeline #109390 passed with stage
in 21 seconds
...@@ -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`: 响应式数组,用于接收生成的导航数据
## 高级配置 ## 高级配置
......
...@@ -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(() => {
......
...@@ -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
......
This diff is collapsed.
...@@ -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,
}, },
}); });
......
...@@ -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/projectDraft.vue"), importFn: () => import("@/views/projectManage/addProject.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: 2px solid #e8f4fd; border-bottom: 1px 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: 18px 24px; padding: 10px 16px;
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: 15px; font-size: 14px;
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: 3px; height: 2px;
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: 12px; gap: 8px;
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.5px 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: 13px; font-size: 14px;
} }
} }
...@@ -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: 13px; font-size: 14px;
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment