|
@@ -1,83 +1,721 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <div>
|
|
|
|
|
- <vxe-switch v-model="treeConfig.showIcon" />
|
|
|
|
|
|
|
+ <div class="progress-page">
|
|
|
|
|
+ <!-- 统计卡片:放最上面,占满宽度 -->
|
|
|
|
|
+ <div class="progress-summary">
|
|
|
|
|
+ <div class="summary-item">
|
|
|
|
|
+ <span>任务总数</span><strong>{{ totalCount }}</strong>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="summary-item doing">
|
|
|
|
|
+ <span>进行中</span><strong>{{ doingCount }}</strong>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="summary-item done">
|
|
|
|
|
+ <span>已完成</span><strong>{{ doneCount }}</strong>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="summary-item delayed">
|
|
|
|
|
+ <span>已延期</span><strong>{{ delayedCount }}</strong>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
- <vxe-gantt v-bind="ganttOptions" />
|
|
|
|
|
|
|
+ <!-- 筛选栏:白底 -->
|
|
|
|
|
+ <div class="progress-filter">
|
|
|
|
|
+ <el-form :model="query" inline>
|
|
|
|
|
+ <el-form-item label="项目">
|
|
|
|
|
+ <el-select
|
|
|
|
|
+ v-model="query.projectId"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ placeholder="全部项目"
|
|
|
|
|
+ class="!w-240px"
|
|
|
|
|
+ @change="applyFilter"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-option v-for="p in projectOptions" :key="p.id" :label="p.title" :value="p.id" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="责任人">
|
|
|
|
|
+ <el-select
|
|
|
|
|
+ v-model="query.owner"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ placeholder="全部责任人"
|
|
|
|
|
+ class="!w-180px"
|
|
|
|
|
+ @change="applyFilter"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-option v-for="name in ownerOptions" :key="name" :label="name" :value="name" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="时间范围">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-model="query.dateRange"
|
|
|
|
|
+ type="daterange"
|
|
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
|
|
+ range-separator="至"
|
|
|
|
|
+ start-placeholder="开始日期"
|
|
|
|
|
+ end-placeholder="结束日期"
|
|
|
|
|
+ class="!w-260px"
|
|
|
|
|
+ @change="applyFilter"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" />重置</el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 工具栏:左侧留空,右侧视图切换 -->
|
|
|
|
|
+ <div class="progress-toolbar">
|
|
|
|
|
+ <div class="toolbar-right">
|
|
|
|
|
+ <vxe-switch v-model="treeConfig.showIcon" />
|
|
|
|
|
+ <span class="toolbar-hint">展开/收起</span>
|
|
|
|
|
+ <el-radio-group v-model="viewMode" size="default">
|
|
|
|
|
+ <el-radio-button label="gantt"
|
|
|
|
|
+ ><Icon icon="ep:data-line" class="mr-5px" />甘特图</el-radio-button
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-radio-button label="list"><Icon icon="ep:list" class="mr-5px" />列表</el-radio-button>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 甘特图 -->
|
|
|
|
|
+ <vxe-gantt v-if="viewMode === 'gantt'" v-bind="ganttOptions" />
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 列表 -->
|
|
|
|
|
+ <el-table
|
|
|
|
|
+ v-else
|
|
|
|
|
+ :data="flatTasks"
|
|
|
|
|
+ border
|
|
|
|
|
+ class="progress-table"
|
|
|
|
|
+ :row-class-name="rowClassName"
|
|
|
|
|
+ :tree-props="{ children: 'children' }"
|
|
|
|
|
+ row-key="newId"
|
|
|
|
|
+ default-expand-all
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-table-column prop="newTitle" label="任务名称" min-width="260" show-overflow-tooltip />
|
|
|
|
|
+ <el-table-column prop="owner" label="责任人" width="120" align="center" />
|
|
|
|
|
+ <el-table-column prop="start" label="开始时间" width="130" align="center" />
|
|
|
|
|
+ <el-table-column prop="end" label="截止时间" width="130" align="center" />
|
|
|
|
|
+ <el-table-column label="进度" width="200" align="center">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-progress
|
|
|
|
|
+ :percentage="Number(row.progress) || 0"
|
|
|
|
|
+ :status="row.state === 'delayed' ? 'exception' : row.state === 'done' ? 'success' : ''"
|
|
|
|
|
+ :stroke-width="10"
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="状态" width="110" align="center">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-tag v-if="row.state" :type="stateTagType(row.state)" effect="light">
|
|
|
|
|
+ {{ stateLabel(row.state) }}
|
|
|
|
|
+ </el-tag>
|
|
|
|
|
+ <span v-else>—</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <el-empty v-if="!hasAnyTask" description="暂无任务进度" :image-size="80" />
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { reactive } from 'vue'
|
|
|
|
|
|
|
+import { computed, reactive, ref } from 'vue'
|
|
|
import { VxeGanttTaskType } from 'vxe-gantt'
|
|
import { VxeGanttTaskType } from 'vxe-gantt'
|
|
|
|
|
|
|
|
|
|
+/* ===================== 原始数据 ===================== */
|
|
|
|
|
+// 先把源数据抽出来,方便筛选时反复使用
|
|
|
|
|
+const rawList = [
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10001,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务1',
|
|
|
|
|
+ planStartDate: '',
|
|
|
|
|
+ planEndDate: '',
|
|
|
|
|
+ actualStartDate: '',
|
|
|
|
|
+ actualEndDate: '',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '张明远'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10002,
|
|
|
|
|
+ parentId: 10001,
|
|
|
|
|
+ title: '任务2',
|
|
|
|
|
+ planStartDate: '2024-02-27',
|
|
|
|
|
+ planEndDate: '2024-03-03',
|
|
|
|
|
+ actualStartDate: '2024-03-01',
|
|
|
|
|
+ actualEndDate: '2024-03-02',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '张明远'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10003,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务3',
|
|
|
|
|
+ planStartDate: '',
|
|
|
|
|
+ planEndDate: '',
|
|
|
|
|
+ actualStartDate: '',
|
|
|
|
|
+ actualEndDate: '',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '李强'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10004,
|
|
|
|
|
+ parentId: 10003,
|
|
|
|
|
+ title: '任务4',
|
|
|
|
|
+ planStartDate: '2024-03-01',
|
|
|
|
|
+ planEndDate: '2024-03-02',
|
|
|
|
|
+ actualStartDate: '2024-03-03',
|
|
|
|
|
+ actualEndDate: '2024-03-04',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '李强'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10005,
|
|
|
|
|
+ parentId: 10003,
|
|
|
|
|
+ title: '任务5',
|
|
|
|
|
+ planStartDate: '2024-03-03',
|
|
|
|
|
+ planEndDate: '2024-03-05',
|
|
|
|
|
+ actualStartDate: '2024-03-04',
|
|
|
|
|
+ actualEndDate: '2024-03-07',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '李强'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10006,
|
|
|
|
|
+ parentId: 10003,
|
|
|
|
|
+ title: '任务6',
|
|
|
|
|
+ planStartDate: '2024-03-19',
|
|
|
|
|
+ planEndDate: '2024-03-22',
|
|
|
|
|
+ actualStartDate: '2024-03-17',
|
|
|
|
|
+ actualEndDate: '2024-03-20',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '李强'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10007,
|
|
|
|
|
+ parentId: 10005,
|
|
|
|
|
+ title: '任务7',
|
|
|
|
|
+ planStartDate: '2024-03-17',
|
|
|
|
|
+ planEndDate: '2024-03-20',
|
|
|
|
|
+ actualStartDate: '2024-03-19',
|
|
|
|
|
+ actualEndDate: '2024-03-22',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '李强'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10008,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务8',
|
|
|
|
|
+ planStartDate: '',
|
|
|
|
|
+ planEndDate: '',
|
|
|
|
|
+ actualStartDate: '',
|
|
|
|
|
+ actualEndDate: '',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '王璐'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10009,
|
|
|
|
|
+ parentId: 10008,
|
|
|
|
|
+ title: '任务9',
|
|
|
|
|
+ planStartDate: '2024-03-02',
|
|
|
|
|
+ planEndDate: '2024-03-03',
|
|
|
|
|
+ actualStartDate: '2024-03-02',
|
|
|
|
|
+ actualEndDate: '2024-03-03',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '王璐'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10010,
|
|
|
|
|
+ parentId: 10008,
|
|
|
|
|
+ title: '任务10',
|
|
|
|
|
+ planStartDate: '2024-03-05',
|
|
|
|
|
+ planEndDate: '2024-03-07',
|
|
|
|
|
+ actualStartDate: '2024-03-05',
|
|
|
|
|
+ actualEndDate: '2024-03-09',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '王璐'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10011,
|
|
|
|
|
+ parentId: 10008,
|
|
|
|
|
+ title: '任务11',
|
|
|
|
|
+ planStartDate: '2024-03-08',
|
|
|
|
|
+ planEndDate: '2024-03-11',
|
|
|
|
|
+ actualStartDate: '2024-03-11',
|
|
|
|
|
+ actualEndDate: '2024-03-15',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '王璐'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10012,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务12',
|
|
|
|
|
+ planStartDate: '',
|
|
|
|
|
+ planEndDate: '',
|
|
|
|
|
+ actualStartDate: '',
|
|
|
|
|
+ actualEndDate: '',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10013,
|
|
|
|
|
+ parentId: 10012,
|
|
|
|
|
+ title: '任务13',
|
|
|
|
|
+ planStartDate: '2024-03-04',
|
|
|
|
|
+ planEndDate: '2024-03-05',
|
|
|
|
|
+ actualStartDate: '2024-03-06',
|
|
|
|
|
+ actualEndDate: '2024-03-08',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10014,
|
|
|
|
|
+ parentId: 10012,
|
|
|
|
|
+ title: '任务14',
|
|
|
|
|
+ planStartDate: '2024-03-06',
|
|
|
|
|
+ planEndDate: '2024-03-07',
|
|
|
|
|
+ actualStartDate: '2024-03-03',
|
|
|
|
|
+ actualEndDate: '2024-03-05',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10015,
|
|
|
|
|
+ parentId: 10012,
|
|
|
|
|
+ title: '任务15',
|
|
|
|
|
+ planStartDate: '2024-03-09',
|
|
|
|
|
+ planEndDate: '2024-03-12',
|
|
|
|
|
+ actualStartDate: '2024-03-10',
|
|
|
|
|
+ actualEndDate: '2024-03-11',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10016,
|
|
|
|
|
+ parentId: 10012,
|
|
|
|
|
+ title: '任务16',
|
|
|
|
|
+ planStartDate: '2024-03-13',
|
|
|
|
|
+ planEndDate: '2024-03-15',
|
|
|
|
|
+ actualStartDate: '2024-03-17',
|
|
|
|
|
+ actualEndDate: '2024-03-18',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10017,
|
|
|
|
|
+ parentId: 10012,
|
|
|
|
|
+ title: '任务17',
|
|
|
|
|
+ planStartDate: '2024-03-17',
|
|
|
|
|
+ planEndDate: '2024-03-21',
|
|
|
|
|
+ actualStartDate: '2024-03-18',
|
|
|
|
|
+ actualEndDate: '2024-03-19',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10018,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务18',
|
|
|
|
|
+ planStartDate: '2024-03-11',
|
|
|
|
|
+ planEndDate: '2024-03-12',
|
|
|
|
|
+ actualStartDate: '2024-03-12',
|
|
|
|
|
+ actualEndDate: '2024-03-15',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '孙浩'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10019,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务19',
|
|
|
|
|
+ planStartDate: '2024-03-15',
|
|
|
|
|
+ planEndDate: '2024-03-17',
|
|
|
|
|
+ actualStartDate: '2024-03-17',
|
|
|
|
|
+ actualEndDate: '2024-03-20',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '孙浩'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10020,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务20',
|
|
|
|
|
+ planStartDate: '',
|
|
|
|
|
+ planEndDate: '',
|
|
|
|
|
+ actualStartDate: '',
|
|
|
|
|
+ actualEndDate: '',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '周敏'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10021,
|
|
|
|
|
+ parentId: 10020,
|
|
|
|
|
+ title: '任务21',
|
|
|
|
|
+ planStartDate: '2024-03-18',
|
|
|
|
|
+ planEndDate: '2024-03-21',
|
|
|
|
|
+ actualStartDate: '2024-03-19',
|
|
|
|
|
+ actualEndDate: '2024-03-21',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '周敏'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10022,
|
|
|
|
|
+ parentId: 10020,
|
|
|
|
|
+ title: '任务22',
|
|
|
|
|
+ planStartDate: '2024-03-23',
|
|
|
|
|
+ planEndDate: '2024-03-25',
|
|
|
|
|
+ actualStartDate: '2024-03-23',
|
|
|
|
|
+ actualEndDate: '2024-03-25',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '周敏'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10023,
|
|
|
|
|
+ parentId: 10020,
|
|
|
|
|
+ title: '任务23',
|
|
|
|
|
+ planStartDate: '2024-03-27',
|
|
|
|
|
+ planEndDate: '2024-04-02',
|
|
|
|
|
+ actualStartDate: '2024-03-27',
|
|
|
|
|
+ actualEndDate: '2024-03-28',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '周敏'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10024,
|
|
|
|
|
+ parentId: 10020,
|
|
|
|
|
+ title: '任务24',
|
|
|
|
|
+ planStartDate: '2024-04-04',
|
|
|
|
|
+ planEndDate: '2024-04-06',
|
|
|
|
|
+ actualStartDate: '2024-04-02',
|
|
|
|
|
+ actualEndDate: '2024-04-05',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '周敏'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10025,
|
|
|
|
|
+ parentId: 10020,
|
|
|
|
|
+ title: '任务25',
|
|
|
|
|
+ planStartDate: '2024-04-07',
|
|
|
|
|
+ planEndDate: '2024-04-11',
|
|
|
|
|
+ actualStartDate: '2024-04-08',
|
|
|
|
|
+ actualEndDate: '2024-04-13',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '周敏'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10026,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务26',
|
|
|
|
|
+ planStartDate: '2024-04-05',
|
|
|
|
|
+ planEndDate: '2024-04-08',
|
|
|
|
|
+ actualStartDate: '2024-04-07',
|
|
|
|
|
+ actualEndDate: '2024-04-10',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '孙浩'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10027,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务27',
|
|
|
|
|
+ planStartDate: '',
|
|
|
|
|
+ planEndDate: '',
|
|
|
|
|
+ actualStartDate: '',
|
|
|
|
|
+ actualEndDate: '',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '吴迪'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10028,
|
|
|
|
|
+ parentId: 10027,
|
|
|
|
|
+ title: '任务28',
|
|
|
|
|
+ planStartDate: '2024-03-10',
|
|
|
|
|
+ planEndDate: '2024-03-13',
|
|
|
|
|
+ actualStartDate: '2024-03-13',
|
|
|
|
|
+ actualEndDate: '2024-03-14',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '吴迪'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10029,
|
|
|
|
|
+ parentId: 10027,
|
|
|
|
|
+ title: '任务29',
|
|
|
|
|
+ planStartDate: '2024-03-14',
|
|
|
|
|
+ planEndDate: '2024-03-18',
|
|
|
|
|
+ actualStartDate: '2024-03-16',
|
|
|
|
|
+ actualEndDate: '2024-03-18',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '吴迪'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10030,
|
|
|
|
|
+ parentId: 10027,
|
|
|
|
|
+ title: '任务30',
|
|
|
|
|
+ planStartDate: '2024-03-19',
|
|
|
|
|
+ planEndDate: '2024-03-25',
|
|
|
|
|
+ actualStartDate: '2024-03-20',
|
|
|
|
|
+ actualEndDate: '2024-03-26',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '吴迪'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10031,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务31',
|
|
|
|
|
+ planStartDate: '2024-03-22',
|
|
|
|
|
+ planEndDate: '2024-03-24',
|
|
|
|
|
+ actualStartDate: '2024-03-19',
|
|
|
|
|
+ actualEndDate: '2024-03-20',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '郑凯'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10032,
|
|
|
|
|
+ parentId: null,
|
|
|
|
|
+ title: '任务32',
|
|
|
|
|
+ planStartDate: '',
|
|
|
|
|
+ planEndDate: '',
|
|
|
|
|
+ actualStartDate: '',
|
|
|
|
|
+ actualEndDate: '',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ hasChild: true,
|
|
|
|
|
+ owner: '郑凯'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10033,
|
|
|
|
|
+ parentId: 10032,
|
|
|
|
|
+ title: '任务33',
|
|
|
|
|
+ planStartDate: '2024-03-09',
|
|
|
|
|
+ planEndDate: '2024-03-14',
|
|
|
|
|
+ actualStartDate: '2024-03-11',
|
|
|
|
|
+ actualEndDate: '2024-03-15',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '郑凯'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10034,
|
|
|
|
|
+ parentId: 10032,
|
|
|
|
|
+ title: '任务34',
|
|
|
|
|
+ planStartDate: '2024-03-15',
|
|
|
|
|
+ planEndDate: '2024-03-21',
|
|
|
|
|
+ actualStartDate: '2024-03-16',
|
|
|
|
|
+ actualEndDate: '2024-03-19',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '郑凯'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10035,
|
|
|
|
|
+ parentId: 10015,
|
|
|
|
|
+ title: '任务35',
|
|
|
|
|
+ planStartDate: '2024-03-16',
|
|
|
|
|
+ planEndDate: '2024-03-18',
|
|
|
|
|
+ actualStartDate: '2024-03-17',
|
|
|
|
|
+ actualEndDate: '2024-03-19',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10036,
|
|
|
|
|
+ parentId: 10015,
|
|
|
|
|
+ title: '任务36',
|
|
|
|
|
+ planStartDate: '2024-03-12',
|
|
|
|
|
+ planEndDate: '2024-03-14',
|
|
|
|
|
+ actualStartDate: '2024-03-13',
|
|
|
|
|
+ actualEndDate: '2024-03-15',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10037,
|
|
|
|
|
+ parentId: 10016,
|
|
|
|
|
+ title: '任务37',
|
|
|
|
|
+ planStartDate: '2024-03-19',
|
|
|
|
|
+ planEndDate: '2024-03-22',
|
|
|
|
|
+ actualStartDate: '2024-03-21',
|
|
|
|
|
+ actualEndDate: '2024-03-23',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 10038,
|
|
|
|
|
+ parentId: 10016,
|
|
|
|
|
+ title: '任务38',
|
|
|
|
|
+ planStartDate: '2024-03-23',
|
|
|
|
|
+ planEndDate: '2024-03-25',
|
|
|
|
|
+ actualStartDate: '2024-03-24',
|
|
|
|
|
+ actualEndDate: '2024-03-27',
|
|
|
|
|
+ planProgress: 90,
|
|
|
|
|
+ actualProgress: 80,
|
|
|
|
|
+ owner: '赵磊'
|
|
|
|
|
+ }
|
|
|
|
|
+]
|
|
|
|
|
+
|
|
|
|
|
+/* ===================== 筛选状态 ===================== */
|
|
|
|
|
+const query = reactive({
|
|
|
|
|
+ projectId: null,
|
|
|
|
|
+ owner: '',
|
|
|
|
|
+ dateRange: [],
|
|
|
|
|
+ state: 'all'
|
|
|
|
|
+})
|
|
|
|
|
+const viewMode = ref('gantt')
|
|
|
|
|
+
|
|
|
const treeConfig = reactive({
|
|
const treeConfig = reactive({
|
|
|
- transform: true, // 自动将列表转为树结构
|
|
|
|
|
- rowField: 'newId', // 自定义树节点关联的主键
|
|
|
|
|
- parentField: 'newParentId', // 自定义树节点关联的父节点的字段名
|
|
|
|
|
- showIcon: true // 是否显示展开按钮
|
|
|
|
|
|
|
+ transform: true,
|
|
|
|
|
+ rowField: 'newId',
|
|
|
|
|
+ parentField: 'newParentId',
|
|
|
|
|
+ showIcon: true
|
|
|
})
|
|
})
|
|
|
|
|
+
|
|
|
|
|
+// 顶层任务作为「项目」下拉
|
|
|
|
|
+const projectOptions = computed(() =>
|
|
|
|
|
+ rawList.filter((t) => t.parentId === null).map((t) => ({ id: t.id, title: t.title }))
|
|
|
|
|
+)
|
|
|
|
|
+const ownerOptions = computed(() => [...new Set(rawList.map((t) => t.owner).filter(Boolean))])
|
|
|
|
|
+
|
|
|
|
|
+/* ===================== 状态计算 ===================== */
|
|
|
|
|
+// 判定单个任务状态:延期 / 已完成 / 进行中
|
|
|
|
|
+const taskState = (row) => {
|
|
|
|
|
+ const progress = Number(row.planProgress || row.actualProgress || 0)
|
|
|
|
|
+ if (progress >= 100) return 'done'
|
|
|
|
|
+ const end = row.actualEndDate || row.planEndDate
|
|
|
|
|
+ if (end && new Date(end) < new Date('2024-03-20')) return 'delayed'
|
|
|
|
|
+ return 'doing'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 过滤逻辑:项目 → 责任人 → 时间范围 → 状态
|
|
|
|
|
+const filteredList = computed(() => {
|
|
|
|
|
+ const { projectId, owner, dateRange, state } = query
|
|
|
|
|
+ // 命中筛选条件的叶子任务 id 集合
|
|
|
|
|
+ const matchIds = new Set()
|
|
|
|
|
+ rawList.forEach((row) => {
|
|
|
|
|
+ if (projectId && !isDescendantOf(row, projectId)) return
|
|
|
|
|
+ if (owner && row.owner !== owner) return
|
|
|
|
|
+ if (dateRange && dateRange.length === 2) {
|
|
|
|
|
+ const [start, end] = dateRange
|
|
|
|
|
+ const rowStart = row.planStartDate || row.actualStartDate || ''
|
|
|
|
|
+ const rowEnd = row.planEndDate || row.actualEndDate || ''
|
|
|
|
|
+ if (rowEnd && rowEnd < start) return
|
|
|
|
|
+ if (rowStart && rowStart > end) return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (state !== 'all' && taskState(row) !== state) return
|
|
|
|
|
+ matchIds.add(row.id)
|
|
|
|
|
+ })
|
|
|
|
|
+ // 保留命中节点 + 其所有祖先,保证树结构不断裂
|
|
|
|
|
+ const keep = new Set()
|
|
|
|
|
+ rawList.forEach((row) => {
|
|
|
|
|
+ if (matchIds.has(row.id)) {
|
|
|
|
|
+ keep.add(row.id)
|
|
|
|
|
+ let parentId = row.parentId
|
|
|
|
|
+ while (parentId) {
|
|
|
|
|
+ keep.add(parentId)
|
|
|
|
|
+ const parent = rawList.find((r) => r.id === parentId)
|
|
|
|
|
+ parentId = parent?.parentId ?? null
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ return rawList.filter((row) => keep.has(row.id))
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const isDescendantOf = (row, ancestorId) => {
|
|
|
|
|
+ let parentId = row.parentId
|
|
|
|
|
+ while (parentId) {
|
|
|
|
|
+ if (parentId === ancestorId) return true
|
|
|
|
|
+ const parent = rawList.find((r) => r.id === parentId)
|
|
|
|
|
+ parentId = parent?.parentId ?? null
|
|
|
|
|
+ }
|
|
|
|
|
+ return row.id === ancestorId
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ===================== 甘特图数据 ===================== */
|
|
|
const ganttOptions = reactive({
|
|
const ganttOptions = reactive({
|
|
|
border: true,
|
|
border: true,
|
|
|
height: 600,
|
|
height: 600,
|
|
|
- columnConfig: {
|
|
|
|
|
- resizable: true
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ columnConfig: { resizable: true },
|
|
|
treeConfig,
|
|
treeConfig,
|
|
|
taskConfig: {
|
|
taskConfig: {
|
|
|
- titleField: 'newTitle', // 自定义标题字段名
|
|
|
|
|
- startField: 'start', // 自定义开始日期字段名
|
|
|
|
|
- endField: 'end', // 自定义结束期字段名
|
|
|
|
|
- progressField: 'progress', // 自定义进度值字段名
|
|
|
|
|
- typeField: 'type' // 自定义渲染类型字段名
|
|
|
|
|
|
|
+ titleField: 'newTitle',
|
|
|
|
|
+ startField: 'start',
|
|
|
|
|
+ endField: 'end',
|
|
|
|
|
+ progressField: 'progress',
|
|
|
|
|
+ typeField: 'type'
|
|
|
},
|
|
},
|
|
|
taskBarSubviewConfig: {
|
|
taskBarSubviewConfig: {
|
|
|
- showOverview: true, // 是否显示任务总览,当子任务被展开后自动显示任务总览
|
|
|
|
|
- // 自定义子任务视图任务条的样式
|
|
|
|
|
|
|
+ showOverview: true,
|
|
|
barStyle({ row }) {
|
|
barStyle({ row }) {
|
|
|
if (row.flag === 1) {
|
|
if (row.flag === 1) {
|
|
|
- return {
|
|
|
|
|
- top: '-12px', // 偏移位置,计划于实际不重叠
|
|
|
|
|
- backgroundColor: '#40d9eff'
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return { top: '-12px', backgroundColor: '#40d9ef' }
|
|
|
}
|
|
}
|
|
|
if (row.flag === 2) {
|
|
if (row.flag === 2) {
|
|
|
- return {
|
|
|
|
|
- top: '12px', // 偏移位置,计划于实际不重叠
|
|
|
|
|
- backgroundColor: '#31d231'
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return { top: '12px', backgroundColor: '#31d231' }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
taskBarConfig: {
|
|
taskBarConfig: {
|
|
|
- showContent: true, // 是否在任务条显示内容
|
|
|
|
|
- moveable: true, // 是否允许拖拽任务移动日期
|
|
|
|
|
- resizable: true, // 是否允许拖拽任务调整日期
|
|
|
|
|
|
|
+ showContent: true,
|
|
|
|
|
+ moveable: true,
|
|
|
|
|
+ resizable: true,
|
|
|
barStyle({ row }) {
|
|
barStyle({ row }) {
|
|
|
return {
|
|
return {
|
|
|
- round: true, // 圆角
|
|
|
|
|
- bgColor: row.flag === 1 ? '#40d9eff' : '#31d231' // 已完成部分任务条的背景颜色
|
|
|
|
|
|
|
+ round: true,
|
|
|
|
|
+ bgColor: row.flag === 1 ? '#40d9ef' : '#31d231'
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
taskViewConfig: {
|
|
taskViewConfig: {
|
|
|
- tableStyle: {
|
|
|
|
|
- width: 200
|
|
|
|
|
- },
|
|
|
|
|
- viewStyle: {
|
|
|
|
|
- border: 'inner'
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ tableStyle: { width: 200 },
|
|
|
|
|
+ viewStyle: { border: 'inner' }
|
|
|
},
|
|
},
|
|
|
columns: [
|
|
columns: [
|
|
|
{ field: 'newTitle', title: '任务名称', minWidth: 160, treeNode: true },
|
|
{ field: 'newTitle', title: '任务名称', minWidth: 160, treeNode: true },
|
|
|
{ field: 'planStartDate', title: '计划开始日期', width: 140 },
|
|
{ field: 'planStartDate', title: '计划开始日期', width: 140 },
|
|
|
- { field: 'planEndDate', title: '实际 结束日期', width: 140 },
|
|
|
|
|
- { field: 'actualStartDate', title: '计划开始日期', width: 140 },
|
|
|
|
|
|
|
+ { field: 'planEndDate', title: '计划结束日期', width: 140 },
|
|
|
|
|
+ { field: 'actualStartDate', title: '实际开始日期', width: 140 },
|
|
|
{ field: 'actualEndDate', title: '实际结束日期', width: 140 }
|
|
{ field: 'actualEndDate', title: '实际结束日期', width: 140 }
|
|
|
],
|
|
],
|
|
|
data: []
|
|
data: []
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-// 将实际和计划一分二
|
|
|
|
|
|
|
+// 将实际和计划一分二(保留你原有逻辑)
|
|
|
const handleMultiTask = (list) => {
|
|
const handleMultiTask = (list) => {
|
|
|
const multiRest = []
|
|
const multiRest = []
|
|
|
list.forEach((item) => {
|
|
list.forEach((item) => {
|
|
@@ -95,7 +733,6 @@ const handleMultiTask = (list) => {
|
|
|
}
|
|
}
|
|
|
multiRest.push(groupRow)
|
|
multiRest.push(groupRow)
|
|
|
} else {
|
|
} else {
|
|
|
- // 计划
|
|
|
|
|
const planRow = {
|
|
const planRow = {
|
|
|
...item,
|
|
...item,
|
|
|
newTitle: `计划:${item.title}`,
|
|
newTitle: `计划:${item.title}`,
|
|
@@ -106,7 +743,6 @@ const handleMultiTask = (list) => {
|
|
|
end: item.planEndDate,
|
|
end: item.planEndDate,
|
|
|
progress: 0
|
|
progress: 0
|
|
|
}
|
|
}
|
|
|
- // 实际
|
|
|
|
|
const actualRow = {
|
|
const actualRow = {
|
|
|
...item,
|
|
...item,
|
|
|
newTitle: `实际:${item.title}`,
|
|
newTitle: `实际:${item.title}`,
|
|
@@ -123,440 +759,159 @@ const handleMultiTask = (list) => {
|
|
|
return multiRest
|
|
return multiRest
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const loadList = () => {
|
|
|
|
|
- const list = [
|
|
|
|
|
- {
|
|
|
|
|
- id: 10001,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务1',
|
|
|
|
|
- planStartDate: '',
|
|
|
|
|
- planEndDate: '',
|
|
|
|
|
- actualStartDate: '',
|
|
|
|
|
- actualEndDate: '',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10002,
|
|
|
|
|
- parentId: 10001,
|
|
|
|
|
- title: '任务2',
|
|
|
|
|
- planStartDate: '2024-02-27',
|
|
|
|
|
- planEndDate: '2024-03-03',
|
|
|
|
|
- actualStartDate: '2024-03-01',
|
|
|
|
|
- actualEndDate: '2024-03-02',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10003,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务3',
|
|
|
|
|
- planStartDate: '',
|
|
|
|
|
- planEndDate: '',
|
|
|
|
|
- actualStartDate: '',
|
|
|
|
|
- actualEndDate: '',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10004,
|
|
|
|
|
- parentId: 10003,
|
|
|
|
|
- title: '任务4',
|
|
|
|
|
- planStartDate: '2024-03-01',
|
|
|
|
|
- planEndDate: '2024-03-02',
|
|
|
|
|
- actualStartDate: '2024-03-03',
|
|
|
|
|
- actualEndDate: '2024-03-04',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10005,
|
|
|
|
|
- parentId: 10003,
|
|
|
|
|
- title: '任务5',
|
|
|
|
|
- planStartDate: '2024-03-03',
|
|
|
|
|
- planEndDate: '2024-03-05',
|
|
|
|
|
- actualStartDate: '2024-03-04',
|
|
|
|
|
- actualEndDate: '2024-03-07',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10006,
|
|
|
|
|
- parentId: 10003,
|
|
|
|
|
- title: '任务6',
|
|
|
|
|
- planStartDate: '2024-03-19',
|
|
|
|
|
- planEndDate: '2024-03-22',
|
|
|
|
|
- actualStartDate: '2024-03-17',
|
|
|
|
|
- actualEndDate: '2024-03-20',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10007,
|
|
|
|
|
- parentId: 10005,
|
|
|
|
|
- title: '任务7',
|
|
|
|
|
- planStartDate: '2024-03-17',
|
|
|
|
|
- planEndDate: '2024-03-20',
|
|
|
|
|
- actualStartDate: '2024-03-19',
|
|
|
|
|
- actualEndDate: '2024-03-22',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10008,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务8',
|
|
|
|
|
- planStartDate: '',
|
|
|
|
|
- planEndDate: '',
|
|
|
|
|
- actualStartDate: '',
|
|
|
|
|
- actualEndDate: '',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10009,
|
|
|
|
|
- parentId: 10008,
|
|
|
|
|
- title: '任务9',
|
|
|
|
|
- planStartDate: '2024-03-02',
|
|
|
|
|
- planEndDate: '2024-03-03',
|
|
|
|
|
- actualStartDate: '2024-03-02',
|
|
|
|
|
- actualEndDate: '2024-03-03',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10010,
|
|
|
|
|
- parentId: 10008,
|
|
|
|
|
- title: '任务10',
|
|
|
|
|
- planStartDate: '2024-03-05',
|
|
|
|
|
- planEndDate: '2024-03-07',
|
|
|
|
|
- actualStartDate: '2024-03-05',
|
|
|
|
|
- actualEndDate: '2024-03-09',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10011,
|
|
|
|
|
- parentId: 10008,
|
|
|
|
|
- title: '任务11',
|
|
|
|
|
- planStartDate: '2024-03-08',
|
|
|
|
|
- planEndDate: '2024-03-11',
|
|
|
|
|
- actualStartDate: '2024-03-11',
|
|
|
|
|
- actualEndDate: '2024-03-15',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10012,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务12',
|
|
|
|
|
- planStartDate: '',
|
|
|
|
|
- planEndDate: '',
|
|
|
|
|
- actualStartDate: '',
|
|
|
|
|
- actualEndDate: '',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10013,
|
|
|
|
|
- parentId: 10012,
|
|
|
|
|
- title: '任务13',
|
|
|
|
|
- planStartDate: '2024-03-04',
|
|
|
|
|
- planEndDate: '2024-03-05',
|
|
|
|
|
- actualStartDate: '2024-03-06',
|
|
|
|
|
- actualEndDate: '2024-03-08',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10014,
|
|
|
|
|
- parentId: 10012,
|
|
|
|
|
- title: '任务14',
|
|
|
|
|
- planStartDate: '2024-03-06',
|
|
|
|
|
- planEndDate: '2024-03-07',
|
|
|
|
|
- actualStartDate: '2024-03-03',
|
|
|
|
|
- actualEndDate: '2024-03-05',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10015,
|
|
|
|
|
- parentId: 10012,
|
|
|
|
|
- title: '任务15',
|
|
|
|
|
- planStartDate: '2024-03-09',
|
|
|
|
|
- planEndDate: '2024-03-12',
|
|
|
|
|
- actualStartDate: '2024-03-10',
|
|
|
|
|
- actualEndDate: '2024-03-11',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10016,
|
|
|
|
|
- parentId: 10012,
|
|
|
|
|
- title: '任务16',
|
|
|
|
|
- planStartDate: '2024-03-13',
|
|
|
|
|
- planEndDate: '2024-03-15',
|
|
|
|
|
- actualStartDate: '2024-03-17',
|
|
|
|
|
- actualEndDate: '2024-03-18',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10017,
|
|
|
|
|
- parentId: 10012,
|
|
|
|
|
- title: '任务17',
|
|
|
|
|
- planStartDate: '2024-03-17',
|
|
|
|
|
- planEndDate: '2024-03-21',
|
|
|
|
|
- actualStartDate: '2024-03-18',
|
|
|
|
|
- actualEndDate: '2024-03-19',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10018,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务18',
|
|
|
|
|
- planStartDate: '2024-03-11',
|
|
|
|
|
- planEndDate: '2024-03-12',
|
|
|
|
|
- actualStartDate: '2024-03-12',
|
|
|
|
|
- actualEndDate: '2024-03-15',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10019,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务19',
|
|
|
|
|
- planStartDate: '2024-03-15',
|
|
|
|
|
- planEndDate: '2024-03-17',
|
|
|
|
|
- actualStartDate: '2024-03-17',
|
|
|
|
|
- actualEndDate: '2024-03-20',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10020,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务20',
|
|
|
|
|
- planStartDate: '',
|
|
|
|
|
- planEndDate: '',
|
|
|
|
|
- actualStartDate: '',
|
|
|
|
|
- actualEndDate: '',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10021,
|
|
|
|
|
- parentId: 10020,
|
|
|
|
|
- title: '任务21',
|
|
|
|
|
- planStartDate: '2024-03-18',
|
|
|
|
|
- planEndDate: '2024-03-21',
|
|
|
|
|
- actualStartDate: '2024-03-19',
|
|
|
|
|
- actualEndDate: '2024-03-21',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10022,
|
|
|
|
|
- parentId: 10020,
|
|
|
|
|
- title: '任务22',
|
|
|
|
|
- planStartDate: '2024-03-23',
|
|
|
|
|
- planEndDate: '2024-03-25',
|
|
|
|
|
- actualStartDate: '2024-03-23',
|
|
|
|
|
- actualEndDate: '2024-03-25',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10023,
|
|
|
|
|
- parentId: 10020,
|
|
|
|
|
- title: '任务23',
|
|
|
|
|
- planStartDate: '2024-03-27',
|
|
|
|
|
- planEndDate: '2024-04-02',
|
|
|
|
|
- actualStartDate: '2024-03-27',
|
|
|
|
|
- actualEndDate: '2024-03-28',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10024,
|
|
|
|
|
- parentId: 10020,
|
|
|
|
|
- title: '任务24',
|
|
|
|
|
- planStartDate: '2024-04-04',
|
|
|
|
|
- planEndDate: '2024-04-06',
|
|
|
|
|
- actualStartDate: '2024-04-02',
|
|
|
|
|
- actualEndDate: '2024-04-05',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10025,
|
|
|
|
|
- parentId: 10020,
|
|
|
|
|
- title: '任务25',
|
|
|
|
|
- planStartDate: '2024-04-07',
|
|
|
|
|
- planEndDate: '2024-04-11',
|
|
|
|
|
- actualStartDate: '2024-04-08',
|
|
|
|
|
- actualEndDate: '2024-04-13',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10026,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务26',
|
|
|
|
|
- planStartDate: '2024-04-05',
|
|
|
|
|
- planEndDate: '2024-04-08',
|
|
|
|
|
- actualStartDate: '2024-04-07',
|
|
|
|
|
- actualEndDate: '2024-04-10',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10027,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务27',
|
|
|
|
|
- planStartDate: '',
|
|
|
|
|
- planEndDate: '',
|
|
|
|
|
- actualStartDate: '',
|
|
|
|
|
- actualEndDate: '',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10028,
|
|
|
|
|
- parentId: 10027,
|
|
|
|
|
- title: '任务28',
|
|
|
|
|
- planStartDate: '2024-03-10',
|
|
|
|
|
- planEndDate: '2024-03-13',
|
|
|
|
|
- actualStartDate: '2024-03-13',
|
|
|
|
|
- actualEndDate: '2024-03-14',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10029,
|
|
|
|
|
- parentId: 10027,
|
|
|
|
|
- title: '任务29',
|
|
|
|
|
- planStartDate: '2024-03-14',
|
|
|
|
|
- planEndDate: '2024-03-18',
|
|
|
|
|
- actualStartDate: '2024-03-16',
|
|
|
|
|
- actualEndDate: '2024-03-18',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10030,
|
|
|
|
|
- parentId: 10027,
|
|
|
|
|
- title: '任务30',
|
|
|
|
|
- planStartDate: '2024-03-19',
|
|
|
|
|
- planEndDate: '2024-03-25',
|
|
|
|
|
- actualStartDate: '2024-03-20',
|
|
|
|
|
- actualEndDate: '2024-03-26',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10031,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务31',
|
|
|
|
|
- planStartDate: '2024-03-22',
|
|
|
|
|
- planEndDate: '2024-03-24',
|
|
|
|
|
- actualStartDate: '2024-03-19',
|
|
|
|
|
- actualEndDate: '2024-03-20',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10032,
|
|
|
|
|
- parentId: null,
|
|
|
|
|
- title: '任务32',
|
|
|
|
|
- planStartDate: '',
|
|
|
|
|
- planEndDate: '',
|
|
|
|
|
- actualStartDate: '',
|
|
|
|
|
- actualEndDate: '',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80,
|
|
|
|
|
- hasChild: true
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10033,
|
|
|
|
|
- parentId: 10032,
|
|
|
|
|
- title: '任务33',
|
|
|
|
|
- planStartDate: '2024-03-09',
|
|
|
|
|
- planEndDate: '2024-03-14',
|
|
|
|
|
- actualStartDate: '2024-03-11',
|
|
|
|
|
- actualEndDate: '2024-03-15',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10034,
|
|
|
|
|
- parentId: 10032,
|
|
|
|
|
- title: '任务34',
|
|
|
|
|
- planStartDate: '2024-03-15',
|
|
|
|
|
- planEndDate: '2024-03-21',
|
|
|
|
|
- actualStartDate: '2024-03-16',
|
|
|
|
|
- actualEndDate: '2024-03-19',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10035,
|
|
|
|
|
- parentId: 10015,
|
|
|
|
|
- title: '任务35',
|
|
|
|
|
- planStartDate: '2024-03-16',
|
|
|
|
|
- planEndDate: '2024-03-18',
|
|
|
|
|
- actualStartDate: '2024-03-17',
|
|
|
|
|
- actualEndDate: '2024-03-19',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10036,
|
|
|
|
|
- parentId: 10015,
|
|
|
|
|
- title: '任务36',
|
|
|
|
|
- planStartDate: '2024-03-12',
|
|
|
|
|
- planEndDate: '2024-03-14',
|
|
|
|
|
- actualStartDate: '2024-03-13',
|
|
|
|
|
- actualEndDate: '2024-03-15',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10037,
|
|
|
|
|
- parentId: 10016,
|
|
|
|
|
- title: '任务37',
|
|
|
|
|
- planStartDate: '2024-03-19',
|
|
|
|
|
- planEndDate: '2024-03-22',
|
|
|
|
|
- actualStartDate: '2024-03-21',
|
|
|
|
|
- actualEndDate: '2024-03-23',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 10038,
|
|
|
|
|
- parentId: 10016,
|
|
|
|
|
- title: '任务38',
|
|
|
|
|
- planStartDate: '2024-03-23',
|
|
|
|
|
- planEndDate: '2024-03-25',
|
|
|
|
|
- actualStartDate: '2024-03-24',
|
|
|
|
|
- actualEndDate: '2024-03-27',
|
|
|
|
|
- planProgress: 90,
|
|
|
|
|
- actualProgress: 80
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
- const multiRest = handleMultiTask(list)
|
|
|
|
|
- ganttOptions.data = multiRest
|
|
|
|
|
|
|
+const applyFilter = () => {
|
|
|
|
|
+ ganttOptions.data = handleMultiTask(filteredList.value)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-loadList()
|
|
|
|
|
|
|
+// 初始化 + 筛选变化时刷新甘特图
|
|
|
|
|
+applyFilter()
|
|
|
|
|
+
|
|
|
|
|
+/* ===================== 列表视图数据 ===================== */
|
|
|
|
|
+// 直接复用 filteredList,并补上状态字段
|
|
|
|
|
+const flatTasks = computed(() =>
|
|
|
|
|
+ filteredList.value.map((row) => ({
|
|
|
|
|
+ ...row,
|
|
|
|
|
+ state: row.hasChild ? '' : taskState(row)
|
|
|
|
|
+ }))
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+const hasAnyTask = computed(() => filteredList.value.length > 0)
|
|
|
|
|
+
|
|
|
|
|
+/* ===================== 统计 ===================== */
|
|
|
|
|
+// 只统计叶子任务
|
|
|
|
|
+const leafTasks = computed(() =>
|
|
|
|
|
+ rawList.filter((row) => !row.hasChild && filteredList.value.some((r) => r.id === row.id))
|
|
|
|
|
+)
|
|
|
|
|
+const totalCount = computed(() => leafTasks.value.length)
|
|
|
|
|
+const doingCount = computed(() => leafTasks.value.filter((r) => taskState(r) === 'doing').length)
|
|
|
|
|
+const doneCount = computed(() => leafTasks.value.filter((r) => taskState(r) === 'done').length)
|
|
|
|
|
+const delayedCount = computed(
|
|
|
|
|
+ () => leafTasks.value.filter((r) => taskState(r) === 'delayed').length
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+const stateLabel = (state) =>
|
|
|
|
|
+ state === 'done' ? '已完成' : state === 'delayed' ? '已延期' : '进行中'
|
|
|
|
|
+const stateTagType = (state) =>
|
|
|
|
|
+ state === 'done' ? 'success' : state === 'delayed' ? 'danger' : 'primary'
|
|
|
|
|
+const rowClassName = ({ row }) => (row.state === 'delayed' ? 'row-delayed' : '')
|
|
|
|
|
+
|
|
|
|
|
+const resetQuery = () => {
|
|
|
|
|
+ query.projectId = null
|
|
|
|
|
+ query.owner = ''
|
|
|
|
|
+ query.dateRange = []
|
|
|
|
|
+ query.state = 'all'
|
|
|
|
|
+ applyFilter()
|
|
|
|
|
+}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.progress-page {
|
|
|
|
|
+ padding: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+.progress-filter {
|
|
|
|
|
+ padding: 12px 16px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ background: var(--el-fill-color-light);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+.progress-filter :deep(.el-form-item) {
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+.progress-toolbar {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+.progress-summary {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item {
|
|
|
|
|
+ min-width: 96px;
|
|
|
|
|
+ padding: 8px 14px;
|
|
|
|
|
+ background: var(--el-bg-color);
|
|
|
|
|
+ border: 1px solid var(--el-border-color-lighter);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item span {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item strong {
|
|
|
|
|
+ font-size: 20px;
|
|
|
|
|
+ font-variant-numeric: tabular-nums;
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item.doing strong {
|
|
|
|
|
+ color: var(--el-color-primary);
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item.done strong {
|
|
|
|
|
+ color: var(--el-color-success);
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item.delayed strong {
|
|
|
|
|
+ color: var(--el-color-danger);
|
|
|
|
|
+}
|
|
|
|
|
+.toolbar-right {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+.toolbar-hint {
|
|
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+.progress-table :deep(.row-delayed) {
|
|
|
|
|
+ background: var(--el-color-danger-light-9);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.progress-page {
|
|
|
|
|
+ padding: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 四个统计卡片:顶部一行,等分占满宽度 */
|
|
|
|
|
+.progress-summary {
|
|
|
|
|
+ display: grid;
|
|
|
|
|
+ grid-template-columns: repeat(4, 1fr);
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item {
|
|
|
|
|
+ padding: 14px 18px;
|
|
|
|
|
+ background: var(--el-bg-color);
|
|
|
|
|
+ border: 1px solid var(--el-border-color-lighter);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item span {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item strong {
|
|
|
|
|
+ font-size: 22px;
|
|
|
|
|
+ font-variant-numeric: tabular-nums;
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item.doing strong {
|
|
|
|
|
+ color: var(--el-color-primary);
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item.done strong {
|
|
|
|
|
+ color: var(--el-color-success);
|
|
|
|
|
+}
|
|
|
|
|
+.summary-item.delayed strong {
|
|
|
|
|
+ color: var(--el-color-danger);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 筛选栏:白色背景 */
|
|
|
|
|
+.progress-filter {
|
|
|
|
|
+ padding: 12px 16px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border: 1px solid var(--el-border-color-lighter);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+.progress-filter :deep(.el-form-item) {
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|