明树Git Lab

Commit ffdc2ddb authored by zhanghan's avatar zhanghan

1

parent 2d120db9
Pipeline #109376 passed with stage
in 21 seconds
...@@ -136,9 +136,7 @@ ...@@ -136,9 +136,7 @@
</DynamicTable> </DynamicTable>
</el-collapse-item> </el-collapse-item>
<el-collapse-item <el-collapse-item title="投资额完成情况" name="投资额完成情况"
title="投资额完成情况(单位:万元)"
name="投资额完成情况(单位:万元)"
><el-row gutter="20"> ><el-row gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item <el-form-item
...@@ -1240,12 +1238,11 @@ const getActiveCollapseItems = () => [ ...@@ -1240,12 +1238,11 @@ const getActiveCollapseItems = () => [
"出资情况", "出资情况",
"合同约定权益获取", "合同约定权益获取",
"分红情况", "分红情况",
"投资额完成情况(万元)", "投资额完成情况",
"投资回收(决策)", "投资回收(决策)",
"投资回收(计划)", "投资回收(计划)",
dynamicTitles.value.yearlyUpdateTitle, dynamicTitles.value.yearlyUpdateTitle,
"净现金流", "净现金流",
"投资额完成情况(单位:万元)",
"截止12月末累计实收", "截止12月末累计实收",
"资金流出", "资金流出",
"分红情况", "分红情况",
......
...@@ -136,9 +136,7 @@ ...@@ -136,9 +136,7 @@
</DynamicTable> </DynamicTable>
</el-collapse-item> </el-collapse-item>
<el-collapse-item <el-collapse-item title="投资额完成情况" name="投资额完成情况"
title="投资额完成情况(单位:万元)"
name="投资额完成情况(单位:万元)"
><el-row gutter="20"> ><el-row gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item <el-form-item
...@@ -1236,7 +1234,7 @@ const getActiveCollapseItems = () => [ ...@@ -1236,7 +1234,7 @@ const getActiveCollapseItems = () => [
"出资情况", "出资情况",
"合同约定权益获取", "合同约定权益获取",
"分红情况", "分红情况",
"投资额完成情况(万元)", "投资额完成情况",
"投资回收(决策)", "投资回收(决策)",
"投资回收(计划)", "投资回收(计划)",
dynamicTitles.value.yearlyUpdateTitle, dynamicTitles.value.yearlyUpdateTitle,
......
<template> <template>
<div class="xmdak-detail-container"> <div class="xmdak-detail-container">
<!-- Tab 切换区域 --> <!-- Tab 切换区域 -->
<div class="tab-wrapper"> <div class="main-tab-wrapper">
<div class="tab-container"> <div class="main-tab-container">
<div <div
v-for="(tab, index) in tabs" v-for="(tab, index) in tabs"
:key="index" :key="index"
:class="['tab-item', { active: activeTab === index }]" :class="['main-tab-item', { active: activeTab === index }]"
@click="switchTab(index)" @click="switchTab(index)"
> >
<div class="tab-icon">
<component :is="tab.icon" />
</div>
<span class="tab-label">{{ tab.label }}</span> <span class="tab-label">{{ tab.label }}</span>
</div> </div>
</div> </div>
</div> </div>
<!-- 内容区域 --> <!-- 子项导航区域 -->
<div class="content-section"> <div class="sub-tab-wrapper">
<!-- 子项列表 --> <div class="sub-tab-container">
<div v-if="!showComponentView" class="sub-items-section">
<div class="sub-items-grid">
<div <div
v-for="(item, idx) in currentTabChildren" v-for="(item, idx) in currentTabChildren"
:key="idx" :key="idx"
class="sub-item-card" :class="['sub-tab-item', { active: activeSubItem === item.name }]"
@click="handleSubItemClick(item)" @click="handleSubItemClick(item)"
> >
<div class="card-icon"> <span class="sub-tab-label">{{ item.title }}</span>
<el-icon><Document /></el-icon>
</div>
<div class="card-content">
<h3 class="card-title">{{ item.title }}</h3>
<p class="card-desc">{{ item.desc }}</p>
</div>
<div class="card-arrow">
<el-icon><ArrowRight /></el-icon>
</div>
</div> </div>
</div> </div>
</div> </div>
<!-- 详情组件区域 --> <!-- 详情内容区域 -->
<div v-else class="component-view-section"> <div class="detail-section">
<div v-if="isLoading" class="loading-overlay"> <div v-if="isLoading" class="loading-overlay">
<el-icon class="is-loading"><Loading /></el-icon> <el-icon class="is-loading"><Loading /></el-icon>
<span>正在加载...</span> <span>正在加载...</span>
</div> </div>
<div v-else class="view-content"> <div v-else class="detail-content">
<component <component
:is="currentComponent" :is="currentComponent"
v-if="currentComponent" v-if="currentComponent"
:project-id="projectId" :project-id="projectId"
:key="activeTab + activeSubItem"
/> />
<div v-else class="error-content"> <div v-else class="empty-content">
<el-empty description="组件加载失败"> <el-empty description="请选择上方功能模块">
<el-button type="primary" @click="backToList">返回列表</el-button> <template #image>
<el-icon :size="80"><Document /></el-icon>
</template>
</el-empty> </el-empty>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>
<script setup> <script setup>
...@@ -70,7 +58,6 @@ import { ref, computed, markRaw } from "vue"; ...@@ -70,7 +58,6 @@ import { ref, computed, markRaw } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { import {
Document, Document,
ArrowRight,
FolderOpened, FolderOpened,
Management, Management,
Finished, Finished,
...@@ -100,9 +87,9 @@ const tabs = ref([ ...@@ -100,9 +87,9 @@ const tabs = ref([
// 当前激活的 Tab // 当前激活的 Tab
const activeTab = ref(0); const activeTab = ref(0);
// 当前激活的子项
// 显示组件视图 const activeSubItem = ref("");
const showComponentView = ref(false); // 当前组件
const currentComponent = ref(null); const currentComponent = ref(null);
const isLoading = ref(false); const isLoading = ref(false);
...@@ -233,7 +220,8 @@ const currentTabChildren = computed(() => { ...@@ -233,7 +220,8 @@ const currentTabChildren = computed(() => {
// 切换 Tab // 切换 Tab
const switchTab = (index) => { const switchTab = (index) => {
activeTab.value = index; activeTab.value = index;
backToList(); activeSubItem.value = "";
currentComponent.value = null;
}; };
// 处理子项点击 - 直接加载详情组件 // 处理子项点击 - 直接加载详情组件
...@@ -243,7 +231,7 @@ const handleSubItemClick = async (item) => { ...@@ -243,7 +231,7 @@ const handleSubItemClick = async (item) => {
return; return;
} }
showComponentView.value = true; activeSubItem.value = item.name;
isLoading.value = true; isLoading.value = true;
currentComponent.value = null; currentComponent.value = null;
...@@ -257,271 +245,247 @@ const handleSubItemClick = async (item) => { ...@@ -257,271 +245,247 @@ const handleSubItemClick = async (item) => {
isLoading.value = false; isLoading.value = false;
} }
}; };
// 返回列表
const backToList = () => {
showComponentView.value = false;
currentComponent.value = null;
isLoading.value = false;
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.xmdak-detail-container { .xmdak-detail-container {
min-height: 100vh; min-height: 100vh;
background: #f5f7fa; background: #f5f7fa;
padding: 0; display: flex;
} flex-direction: column;
// 简洁的头部
.page-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 16px 20px;
text-align: center;
color: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
.page-title {
font-size: 20px;
font-weight: 600;
margin: 0;
letter-spacing: 1px;
}
} }
// Tab 容器 // 主 Tab 切换区域 - 现代政府风格
.tab-wrapper { .main-tab-wrapper {
background: white; background: white;
padding: 12px 20px; padding: 0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); 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;
} }
.tab-container { .main-tab-container {
display: flex; display: flex;
max-width: 1200px; max-width: 1400px;
margin: 0 auto; margin: 0 auto;
gap: 8px; gap: 4px;
background: #f8f9fa; background: transparent;
padding: 6px; padding: 0 20px;
border-radius: 12px;
} }
.tab-item { .main-tab-item {
flex: 1; flex: 1;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 8px; padding: 18px 24px;
padding: 12px 20px;
border-radius: 8px;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.3s ease;
position: relative; position: relative;
border-radius: 8px 8px 0 0;
.tab-icon { margin-top: 4px;
font-size: 18px;
transition: transform 0.2s ease;
}
.tab-label { .tab-label {
font-size: 14px; font-size: 15px;
font-weight: 500; font-weight: 500;
color: #495057; color: #5a6c7d;
transition: all 0.2s ease; letter-spacing: 0.5px;
transition: all 0.3s ease;
position: relative;
z-index: 1;
}
&::before {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 3px;
background: transparent;
transition: all 0.3s ease;
border-radius: 3px 3px 0 0;
} }
&:hover { &:hover {
background: rgba(102, 126, 234, 0.08); background: linear-gradient(to bottom, #f8fbff, #ffffff);
transform: translateY(-1px);
.tab-icon { .tab-label {
transform: scale(1.05); color: #0056b3;
}
&::before {
background: linear-gradient(to right, #4dabf7, #0056b3);
opacity: 0.6;
} }
} }
&.active { &.active {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: white;
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); margin-top: 0;
padding-top: 22px;
.tab-icon,
.tab-label { .tab-label {
color: white; color: #0056b3;
} font-weight: 600;
} }
}
// 内容区域 &::before {
.content-section { background: linear-gradient(to right, #4dabf7, #0056b3);
max-width: 1440px; box-shadow: 0 -2px 8px rgba(0, 86, 179, 0.15);
margin: 24px auto; }
padding: 0 20px; }
}
.sub-items-section {
min-height: 300px;
} }
.tab-content { // 子项导航区域
min-height: 300px; .sub-tab-wrapper {
background: linear-gradient(to bottom, #f8fbff, #ffffff);
border-bottom: 1px solid #d4e8fc;
padding: 16px 24px;
box-shadow: 0 2px 8px rgba(0, 86, 179, 0.04);
} }
// 子项网格 - 增加宽度 .sub-tab-container {
.sub-items-grid {
display: flex; display: flex;
gap: 14px; gap: 12px;
flex-wrap: wrap; flex-wrap: wrap;
max-width: 1400px;
margin: 0 auto; margin: 0 auto;
justify-content: center; justify-content: center;
} }
.sub-item-card { .sub-tab-item {
background: white; padding: 12px 24px;
border-radius: 10px; border-radius: 20px;
padding: 16px;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all 0.3s ease;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06); background: white;
display: flex; border: 1.5px solid #e8f4fd;
align-items: center;
gap: 12px;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
&::before { &::before {
content: ""; content: '';
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 3px; right: 0;
height: 100%; bottom: 0;
background: linear-gradient(180deg, #667eea, #764ba2); background: linear-gradient(135deg, rgba(77, 171, 247, 0.05), rgba(0, 86, 179, 0.05));
opacity: 0; opacity: 0;
transition: opacity 0.2s ease; transition: opacity 0.3s ease;
}
.sub-tab-label {
font-size: 14px;
color: #5a6c7d;
font-weight: 500;
transition: all 0.3s ease;
position: relative;
z-index: 1;
letter-spacing: 0.3px;
} }
&:hover { &:hover {
transform: translateY(-2px); border-color: #4dabf7;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15); transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(77, 171, 247, 0.15);
&::before { &::before {
opacity: 1; opacity: 1;
} }
.card-arrow { .sub-tab-label {
transform: translateX(2px); color: #0056b3;
color: #667eea;
}
.card-icon {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
transform: scale(1.05);
} }
} }
.card-icon { &.active {
width: 42px; background: linear-gradient(135deg, #4dabf7, #0056b3);
height: 42px; border-color: transparent;
border-radius: 8px; box-shadow: 0 4px 16px rgba(0, 86, 179, 0.25);
background: #f8f9fa; transform: translateY(-2px);
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
color: #667eea;
transition: all 0.2s ease;
flex-shrink: 0;
}
.card-content { &::before {
flex: 1; background: transparent;
min-width: 0;
} }
.card-title { .sub-tab-label {
font-size: 14px; color: white;
font-weight: 600; font-weight: 600;
color: #212529; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
margin: 0 0 3px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.card-desc {
font-size: 12px;
color: #868e96;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
.card-arrow {
color: #adb5bd;
font-size: 16px;
transition: all 0.2s ease;
flex-shrink: 0;
} }
} }
// 详情组件区域 // 详情内容区域
.component-view-section { .detail-section {
max-width: 100%; flex: 1;
width: 100%; background: #f5f7fa;
margin: 16px 0 24px; overflow: hidden;
padding: 0 20px; display: flex;
flex-direction: column;
}
.loading-overlay { .loading-overlay {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 60px 20px; padding: 80px 20px;
color: #667eea; color: #0056b3;
font-size: 16px; font-size: 16px;
.el-icon { .el-icon {
font-size: 32px; font-size: 40px;
margin-bottom: 12px; margin-bottom: 16px;
} color: #0056b3;
} }
}
.view-content { .detail-content {
background: white; flex: 1;
border-radius: 12px; overflow-y: auto;
padding: 20px; padding: 20px;
min-height: 500px; min-height: 500px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); }
}
.error-content { .empty-content {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-height: 300px; min-height: 500px;
background: white;
border-radius: 4px;
.el-icon {
color: #0056b3;
opacity: 0.3;
} }
} }
// 响应式设计 // 响应式设计
@media (max-width: 768px) { @media (max-width: 768px) {
.tab-container { .main-tab-item {
flex-direction: column; padding: 12px 16px;
}
.sub-items-grid { .tab-label {
grid-template-columns: 1fr; font-size: 13px;
}
} }
.tab-item { .sub-tab-container {
padding: 10px 16px; gap: 6px;
} }
.tab-label { .sub-tab-item {
padding: 8px 14px;
.sub-tab-label {
font-size: 13px; font-size: 13px;
} }
}
} }
</style> </style>
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