|
|
|
@ -65,14 +65,46 @@ |
|
|
|
|
|
|
|
<!-- 右侧甘特图 --> |
|
|
|
<div class="gantt-section" :class="{ 'expanded': isProjectInfoCollapsed }"> |
|
|
|
<!-- 图例 --> |
|
|
|
<div class="legend"> |
|
|
|
<!-- 图例(整块可点击打开管理弹框) --> |
|
|
|
<div class="legend" @click="openLegendEdit"> |
|
|
|
<div class="legend-item" v-for="(item, index) in legendItems" :key="index"> |
|
|
|
<div class="legend-color" :style="{ backgroundColor: item.color }"></div> |
|
|
|
<span class="legend-text">{{ item.label }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 图例管理弹框:表格列表,可新增、编辑 --> |
|
|
|
<el-dialog title="图例管理" :visible.sync="legendEditVisible" width="620px" append-to-body class="legend-edit-dialog"> |
|
|
|
<div class="legend-dialog-toolbar"> |
|
|
|
<el-button size="small" type="primary" icon="el-icon-plus" @click="addLegendRow">新 增</el-button> |
|
|
|
</div> |
|
|
|
<div class="legend-edit-table-wrap"> |
|
|
|
<el-table :data="legendTableList" border size="small" class="legend-edit-table"> |
|
|
|
<el-table-column type="index" label="序号" width="55" align="center" /> |
|
|
|
<el-table-column label="名称" min-width="140"> |
|
|
|
<template slot-scope="scope"> |
|
|
|
<el-input v-model="scope.row.label" placeholder="请输入图例名称" size="mini" clearable /> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="颜色" width="160" align="center"> |
|
|
|
<template slot-scope="scope"> |
|
|
|
<el-color-picker v-model="scope.row.color" size="small" /> |
|
|
|
<span class="legend-table-color-text">{{ scope.row.color }}</span> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
<el-table-column label="操作" width="80" align="center"> |
|
|
|
<template slot-scope="scope"> |
|
|
|
<el-button type="text" size="mini" style="color: #f56c6c;" @click="removeLegendRow(scope.$index)">删除</el-button> |
|
|
|
</template> |
|
|
|
</el-table-column> |
|
|
|
</el-table> |
|
|
|
</div> |
|
|
|
<span slot="footer" class="dialog-footer"> |
|
|
|
<el-button size="small" @click="legendEditVisible = false">取 消</el-button> |
|
|
|
<el-button size="small" type="primary" @click="saveLegendList">保 存</el-button> |
|
|
|
</span> |
|
|
|
</el-dialog> |
|
|
|
|
|
|
|
<!-- 甘特图时间轴 --> |
|
|
|
<div class="gantt-timeline"> |
|
|
|
<!-- 时间轴头部 --> |
|
|
|
@ -123,7 +155,7 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import { getProjectGanttData, getGanttLegend } from '@/api/project/gantt.js' |
|
|
|
import { getProjectGanttData, getGanttLegend, updateGanttLegend } from '@/api/project/gantt.js' |
|
|
|
import moment from 'moment' |
|
|
|
|
|
|
|
export default { |
|
|
|
@ -218,8 +250,8 @@ export default { |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
// 图例数据 |
|
|
|
legendItems: [ |
|
|
|
// 图例数据(默认兜底,接口会覆盖) |
|
|
|
defaultLegendItems: [ |
|
|
|
{ label: '设计', color: '#ff0000' }, |
|
|
|
{ label: '材料采购', color: '#00ff00' }, |
|
|
|
{ label: '机加工', color: '#0000ff' }, |
|
|
|
@ -230,6 +262,10 @@ export default { |
|
|
|
{ label: 'T1试模', color: '#000000' }, |
|
|
|
{ label: 'OTS试模', color: '#4f6228' }, |
|
|
|
], |
|
|
|
legendItems: [], |
|
|
|
// 图例管理弹框(表格列表) |
|
|
|
legendEditVisible: false, |
|
|
|
legendTableList: [], // 弹框内编辑的列表,打开时从 legendItems 拷贝 |
|
|
|
|
|
|
|
// 项目数据 |
|
|
|
projectList:[], |
|
|
|
@ -637,7 +673,9 @@ export default { |
|
|
|
// 使用外部传入的数据 |
|
|
|
this.projectList = this.externalProjectList |
|
|
|
if (this.externalLegendItems.length > 0) { |
|
|
|
this.legendItems = this.externalLegendItems |
|
|
|
this.legendItems = JSON.parse(JSON.stringify(this.externalLegendItems)) |
|
|
|
} else { |
|
|
|
this.legendItems = JSON.parse(JSON.stringify(this.defaultLegendItems)) |
|
|
|
} |
|
|
|
if (this.externalUpdateDate) { |
|
|
|
this.updateDate = this.externalUpdateDate |
|
|
|
@ -661,42 +699,98 @@ export default { |
|
|
|
queryParams.endDate = this.dateRange[1] |
|
|
|
} |
|
|
|
|
|
|
|
getProjectGanttData(queryParams).then(({ data }) => { |
|
|
|
if (data && data.code === 0) { |
|
|
|
console.log(data); |
|
|
|
this.projectList = data.projectGanttData.projectList |
|
|
|
} |
|
|
|
}) |
|
|
|
|
|
|
|
/* const [ganttData, legendData] = await Promise.all([ |
|
|
|
const [ganttRes, legendRes] = await Promise.all([ |
|
|
|
getProjectGanttData(queryParams), |
|
|
|
getGanttLegend(), |
|
|
|
]) |
|
|
|
|
|
|
|
const ganttData = ganttRes && ganttRes.data !== undefined ? ganttRes.data : ganttRes |
|
|
|
if (ganttData && ganttData.code === 0) { |
|
|
|
this.projectList = ganttData.data.projectList || this.projectList |
|
|
|
this.updateDate = ganttData.data.updateDate || this.updateDate |
|
|
|
|
|
|
|
// 如果API返回了时间范围,更新显示 |
|
|
|
if (ganttData.data.projectStartDate) { |
|
|
|
this.projectStartDate = ganttData.data.projectStartDate |
|
|
|
} |
|
|
|
if (ganttData.data.projectEndDate) { |
|
|
|
this.projectEndDate = ganttData.data.projectEndDate |
|
|
|
} |
|
|
|
const payload = ganttData.projectGanttData || ganttData.data || ganttData |
|
|
|
this.projectList = (payload && payload.projectList) || this.projectList || [] |
|
|
|
} |
|
|
|
|
|
|
|
const legendData = legendRes && legendRes.data !== undefined ? legendRes.data : legendRes |
|
|
|
if (legendData && legendData.code === 0) { |
|
|
|
this.legendItems = legendData.data || this.legendItems |
|
|
|
} */ |
|
|
|
const list = legendData.data || legendData.list || legendData |
|
|
|
if (Array.isArray(list) && list.length > 0) { |
|
|
|
this.legendItems = list.map(it => ({ label: it.label || it.name, color: it.color || '#409EFF' })) |
|
|
|
} else { |
|
|
|
this.legendItems = JSON.parse(JSON.stringify(this.defaultLegendItems)) |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.legendItems = JSON.parse(JSON.stringify(this.defaultLegendItems)) |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('获取甘特图数据失败:', error) |
|
|
|
this.$message.error('获取数据失败,使用默认数据') |
|
|
|
this.legendItems = JSON.parse(JSON.stringify(this.defaultLegendItems)) |
|
|
|
} finally { |
|
|
|
this.loading = false |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 获取图例数据(仅图例,供单独刷新用) |
|
|
|
async fetchLegend() { |
|
|
|
try { |
|
|
|
const res = await getGanttLegend() |
|
|
|
const legendData = res && res.data !== undefined ? res.data : res |
|
|
|
if (legendData && legendData.code === 0) { |
|
|
|
const list = legendData.data || legendData.list || legendData |
|
|
|
if (Array.isArray(list) && list.length > 0) { |
|
|
|
this.legendItems = list.map(it => ({ label: it.label || it.name, color: it.color || '#409EFF' })) |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
console.error('获取图例失败:', e) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 打开图例管理弹框(展示 legendItems 的表格列表) |
|
|
|
openLegendEdit() { |
|
|
|
this.legendTableList = this.legendItems.length |
|
|
|
? JSON.parse(JSON.stringify(this.legendItems)) |
|
|
|
: JSON.parse(JSON.stringify(this.defaultLegendItems)) |
|
|
|
this.legendEditVisible = true |
|
|
|
}, |
|
|
|
|
|
|
|
// 新增一行图例 |
|
|
|
addLegendRow() { |
|
|
|
this.legendTableList.push({ label: '', color: '#409EFF' }) |
|
|
|
}, |
|
|
|
|
|
|
|
// 删除一行图例 |
|
|
|
removeLegendRow(index) { |
|
|
|
this.legendTableList.splice(index, 1) |
|
|
|
}, |
|
|
|
|
|
|
|
// 保存图例列表(写回 legendItems 并提交接口) |
|
|
|
async saveLegendList() { |
|
|
|
const list = this.legendTableList |
|
|
|
.filter(it => it && (it.label || '').trim()) |
|
|
|
.map(it => ({ label: (it.label || '').trim(), color: it.color || '#409EFF' })) |
|
|
|
if (!list.length) { |
|
|
|
this.$message.warning('请至少保留一条图例并填写名称') |
|
|
|
return |
|
|
|
} |
|
|
|
// 校验不能有相同的 label |
|
|
|
const labels = list.map(it => it.label) |
|
|
|
const labelSet = new Set(labels) |
|
|
|
if (labelSet.size !== labels.length) { |
|
|
|
this.$message.warning('图例名称不能重复,请修改后再保存') |
|
|
|
return |
|
|
|
} |
|
|
|
this.legendItems = JSON.parse(JSON.stringify(list)) |
|
|
|
this.legendEditVisible = false |
|
|
|
try { |
|
|
|
await updateGanttLegend(this.legendItems) |
|
|
|
this.$message.success('保存成功') |
|
|
|
} catch (e) { |
|
|
|
console.error('保存图例失败:', e) |
|
|
|
this.$message.warning('本地已更新,保存到服务器失败,请检查后端接口') |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 初始化默认时间范围 |
|
|
|
initDefaultDateRange() { |
|
|
|
if (!this.dateRange || this.dateRange.length === 0) { |
|
|
|
@ -721,6 +815,9 @@ export default { |
|
|
|
|
|
|
|
mounted() { |
|
|
|
this.initDefaultDateRange() |
|
|
|
if (this.legendItems.length === 0 && this.defaultLegendItems.length > 0) { |
|
|
|
this.legendItems = JSON.parse(JSON.stringify(this.defaultLegendItems)) |
|
|
|
} |
|
|
|
this.fetchGanttData() |
|
|
|
}, |
|
|
|
} |
|
|
|
@ -885,6 +982,12 @@ export default { |
|
|
|
padding: 15px; |
|
|
|
border-bottom: 1px solid #eee; |
|
|
|
background-color: #fafafa; |
|
|
|
cursor: pointer; |
|
|
|
border-radius: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.legend:hover { |
|
|
|
background-color: rgba(0, 0, 0, 0.06); |
|
|
|
} |
|
|
|
|
|
|
|
.legend-item { |
|
|
|
@ -893,6 +996,34 @@ export default { |
|
|
|
gap: 5px; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-dialog-toolbar { |
|
|
|
margin-bottom: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-edit-table-wrap { |
|
|
|
max-height: 420px; |
|
|
|
overflow-y: auto; |
|
|
|
margin: 0 -1px; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-edit-table .legend-table-color-text { |
|
|
|
margin-left: 8px; |
|
|
|
font-size: 12px; |
|
|
|
color: #606266; |
|
|
|
vertical-align: middle; |
|
|
|
} |
|
|
|
|
|
|
|
/* 图例弹框:保证内容不溢出、底部按钮始终可见 */ |
|
|
|
.legend-edit-dialog .el-dialog__body { |
|
|
|
padding: 10px 20px 15px; |
|
|
|
max-height: 70vh; |
|
|
|
overflow: visible; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-edit-dialog .el-dialog { |
|
|
|
margin-top: 8vh !important; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-color { |
|
|
|
width: 20px; |
|
|
|
height: 15px; |
|
|
|
@ -1077,3 +1208,29 @@ export default { |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |
|
|
|
|
|
|
|
<!-- 图例弹框挂到 body,需单独样式覆盖全局 table 行高,故不加 scoped --> |
|
|
|
<style lang="scss"> |
|
|
|
.legend-edit-dialog .legend-edit-table-wrap .el-table td, |
|
|
|
.legend-edit-dialog .legend-edit-table-wrap .el-table th { |
|
|
|
padding: 0px 0 !important; |
|
|
|
height: 24px !important; |
|
|
|
min-height: 24px !important; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-edit-dialog .legend-edit-table-wrap .el-table .cell { |
|
|
|
height: auto !important; |
|
|
|
min-height: 24px !important; |
|
|
|
line-height: 1.5 !important; |
|
|
|
padding: 1px 1px !important; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-edit-dialog .legend-edit-table-wrap .el-table .el-input__inner { |
|
|
|
height: 24px !important; |
|
|
|
line-height: 24px !important; |
|
|
|
} |
|
|
|
|
|
|
|
.legend-edit-dialog .legend-edit-table-wrap .el-table .el-color-picker { |
|
|
|
vertical-align: middle; |
|
|
|
} |
|
|
|
</style> |