You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

429 lines
9.2 KiB

2 months ago
<template>
<div class="bottom-left-panel">
<div class="panel-toggle" @click="togglePanel" :title="isExpanded ? '收起' : '展开'">
<i :class="isExpanded ? 'el-icon-s-fold' : 'el-icon-s-unfold'"></i>
<span v-if="!isExpanded" class="toggle-text">工具</span>
</div>
<div class="panel-content" :class="{ expanded: isExpanded }">
<div class="panel-item" @click="showTimeline">
<i class="el-icon-time"></i>
<span>时间线</span>
</div>
<div class="panel-item" @click="showProgress">
<i class="el-icon-s-data"></i>
<span>进度检查</span>
</div>
<div class="panel-item" @click="showSixSteps">
<i class="el-icon-s-operation"></i>
<span>六步法</span>
</div>
</div>
<el-dialog
:visible.sync="dialogVisible"
:title="dialogTitle"
width="350px"
:modal="false"
custom-class="panel-dialog"
>
<div class="dialog-content">
<div v-if="activeTab === 'timeline'" class="timeline-content">
<h3>时间线</h3>
<div class="timeline-list">
2 months ago
<div v-for="(item, index) in timelineData" :key="index" class="timeline-item" :class="{ current: item.current }">
2 months ago
<div class="timeline-dot"></div>
<div class="timeline-info">
<div class="timeline-time">{{ item.time }}</div>
<div class="timeline-event">{{ item.event }}</div>
</div>
</div>
</div>
</div>
<div v-if="activeTab === 'progress'" class="progress-content">
<h3>进度检查</h3>
<div class="progress-list">
<div v-for="(item, index) in progressData" :key="index" class="progress-item">
<div class="progress-label">{{ item.label }}</div>
<el-progress :percentage="item.percentage" :status="item.status"></el-progress>
</div>
</div>
</div>
<div v-if="activeTab === 'sixsteps'" class="sixsteps-content">
<h3>六步法</h3>
<div class="steps-container">
<div v-for="(step, index) in sixStepsData" :key="index" class="step-item" :class="{ active: step.active, completed: step.completed }">
<div class="step-number">{{ index + 1 }}</div>
<div class="step-content">
<div class="step-title">{{ step.title }}</div>
<div class="step-desc">{{ step.desc }}</div>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'BottomLeftPanel',
data() {
return {
isExpanded: false,
dialogVisible: false,
dialogTitle: '',
activeTab: '',
timelineData: [
2 months ago
{ time: 'K-02:00', event: '任务准备阶段', current: false },
{ time: 'K-01:00', event: '资源调配', current: false },
{ time: 'K时', event: '任务执行', current: true },
{ time: 'K+01:00', event: '任务监控', current: false },
{ time: 'K+02:00', event: '任务完成', current: false }
2 months ago
],
progressData: [
{ label: '任务准备', percentage: 100, status: 'success' },
{ label: '资源调配', percentage: 80, status: '' },
{ label: '任务执行', percentage: 45, status: '' },
{ label: '任务监控', percentage: 20, status: 'exception' },
{ label: '任务完成', percentage: 0, status: '' }
],
sixStepsData: [
{ title: '理解', desc: '明确任务目标和要求', active: true, completed: true },
{ title: '判断', desc: '评估可用资源和能力', active: false, completed: true },
{ title: '规划', desc: '制定详细执行方案', active: false, completed: false },
{ title: '准备', desc: '识别和评估潜在风险', active: false, completed: false },
{ title: '执行', desc: '实时监控执行过程', active: false, completed: false },
{ title: '评估', desc: '评估任务完成效果', active: false, completed: false }
]
}
},
methods: {
togglePanel() {
this.isExpanded = !this.isExpanded
},
showTimeline() {
this.activeTab = 'timeline'
this.dialogTitle = '时间线'
this.dialogVisible = true
},
showProgress() {
this.activeTab = 'progress'
this.dialogTitle = '进度检查'
this.dialogVisible = true
},
showSixSteps() {
this.activeTab = 'sixsteps'
this.dialogTitle = '六步法'
this.dialogVisible = true
}
}
}
</script>
<style scoped>
.bottom-left-panel {
position: absolute;
bottom: 20px;
left: 20px;
z-index: 100;
}
.panel-toggle {
width: 50px;
height: 50px;
background: rgba(0, 138, 255, 0.9);
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
cursor: pointer;
color: white;
font-size: 20px;
box-shadow: 0 4px 12px rgba(0, 138, 255, 0.4);
transition: all 0.3s;
}
.panel-toggle:hover {
transform: scale(1.1);
box-shadow: 0 6px 16px rgba(0, 138, 255, 0.6);
}
.toggle-text {
font-size: 10px;
margin-top: 2px;
}
.panel-content {
position: absolute;
bottom: 60px;
left: 0;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
padding: 10px;
min-width: 150px;
opacity: 0;
transform: translateY(20px);
pointer-events: none;
transition: all 0.3s;
}
.panel-content.expanded {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
.panel-item {
display: flex;
align-items: center;
padding: 12px 15px;
cursor: pointer;
border-radius: 8px;
transition: all 0.3s;
color: #333;
}
.panel-item:hover {
background: rgba(0, 138, 255, 0.1);
color: #008aff;
transform: translateX(5px);
}
.panel-item i {
font-size: 18px;
margin-right: 10px;
color: #008aff;
}
.panel-item span {
font-size: 14px;
font-weight: 500;
}
.dialog-content {
padding: 0;
}
.timeline-content h3,
.progress-content h3,
.sixsteps-content h3 {
margin: 0 0 15px 0;
font-size: 14px;
color: #333;
border-bottom: 2px solid #409EFF;
padding-bottom: 8px;
}
.timeline-list {
max-height: 280px;
overflow-y: auto;
}
.timeline-item {
display: flex;
align-items: flex-start;
margin-bottom: 12px;
position: relative;
}
2 months ago
.timeline-item.current {
background: rgba(64, 158, 255, 0.1);
border-radius: 6px;
padding: 8px;
}
.timeline-item.current .timeline-dot {
background: #ff6600;
box-shadow: 0 0 0 4px rgba(255, 102, 0, 0.3);
animation: pulse 2s infinite;
}
.timeline-item.current .timeline-time {
color: #ff6600;
font-weight: 700;
}
.timeline-item.current .timeline-event {
color: #333;
font-weight: 600;
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.2);
opacity: 0.7;
}
100% {
transform: scale(1);
opacity: 1;
}
}
2 months ago
.timeline-item::before {
content: '';
position: absolute;
left: 5px;
top: 15px;
bottom: -12px;
width: 2px;
background: #e0e0e0;
}
.timeline-item:last-child::before {
display: none;
}
.timeline-dot {
width: 12px;
height: 12px;
background: #409EFF;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.2);
}
.timeline-info {
flex: 1;
}
.timeline-time {
font-size: 12px;
color: #409EFF;
font-weight: 600;
margin-bottom: 3px;
}
.timeline-event {
font-size: 12px;
color: #666;
}
.progress-list {
max-height: 280px;
overflow-y: auto;
}
.progress-item {
margin-bottom: 15px;
}
.progress-label {
font-size: 12px;
color: #333;
margin-bottom: 5px;
font-weight: 500;
}
.steps-container {
display: flex;
flex-direction: column;
gap: 8px;
}
.step-item {
display: flex;
align-items: flex-start;
padding: 10px;
background: #f5f7fa;
border-radius: 6px;
transition: all 0.3s;
border-left: 3px solid #dcdfe6;
}
.step-item.active {
background: rgba(64, 158, 255, 0.1);
border-left-color: #409EFF;
}
.step-item.completed {
background: rgba(103, 194, 58, 0.1);
border-left-color: #67c23a;
}
.step-number {
width: 24px;
height: 24px;
background: #dcdfe6;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
font-weight: 600;
color: #909399;
margin-right: 10px;
flex-shrink: 0;
}
.step-item.active .step-number {
background: #409EFF;
color: white;
}
.step-item.completed .step-number {
background: #67c23a;
color: white;
}
.step-content {
flex: 1;
}
.step-title {
font-size: 13px;
font-weight: 600;
color: #333;
margin-bottom: 3px;
}
.step-desc {
font-size: 11px;
color: #666;
}
</style>
<style>
.panel-dialog {
position: absolute !important;
left: 170px !important;
bottom: 20px !important;
top: auto !important;
margin: 0 !important;
max-height: 400px;
}
.panel-dialog .el-dialog__header {
padding: 12px 15px;
background: #409EFF;
color: white;
}
.panel-dialog .el-dialog__title {
color: white;
font-size: 14px;
font-weight: 600;
}
.panel-dialog .el-dialog__headerbtn .el-dialog__close {
color: white;
}
.panel-dialog .el-dialog__body {
padding: 15px;
max-height: 350px;
overflow-y: auto;
}
</style>