甘特图开发代码(测试版)
场景:要实现的功能就是单行数据能左右拖动。
流程五个:ABCDE。(对应:Charter开发、概念和计划、初样开发、正样开发、验证)
1、A有开始时间,结束时间。B的开始时间必须是A的结束时间(相等或者大于A的结束时间)。CDE以此类推。
2、一条数据有父子级的话,父级数据的进度条取A的开始时间,E的结束时间,如果当前流程没到E,就是取现有的流程的结束时间。流程阶段影响父级
3、单个流程进度条移动会影响前后进度条,如果没有前后节点就不影响
一、代码实现
https://juejin.cn/post/7451884906761486372
https://juejin.cn/post/7273096710826967092
1、html页面
import React, { useState, useMemo, useRef } from 'react';
import {
Button,
DataSet,
DatePicker,
Dropdown,
Form,
Menu,
message,
Modal,
Select,
Table,
TextField,
} from 'choerodon-ui/pro';
import GanttModal from './components/ganttModal/main';
const platformCharter = () => {
return <GanttModal />
};
export default platformCharter;
2、组件页面
const handleCheckboxClick = useCallback(event => {
const target = event.target;
if (target.tagName === 'INPUT' && target.type === 'checkbox') {
const taskId = target.getAttribute('data-task-id');
const isChecked = target.checked;
// 更新任务数据中的选中状态
const task = gantt.getTask(taskId);
task.selected = isChecked;
gantt.updateTask(taskId);
// 获取子任务
const childTasks = gantt.getChildren(taskId);
childTasks.forEach(childTask => {
const childCheckbox = gantt.getTask(childTask.id);
childCheckbox.selected = isChecked; // 设置子任务的选中状态
gantt.updateTask(childTask.id);
});
// 更新父任务的选中状态
const parentTask = gantt.getTask(task.parent);
if (parentTask) {
const siblings = gantt.getChildren(parentTask.id);
const allChecked = siblings.every(sibling => sibling.selected);
parentTask.selected = allChecked; // 如果所有兄弟任务都选中,父任务选中
gantt.updateTask(parentTask.id);
}
console.log('任务选中状态:', taskId, isChecked);
}
}, []);
.gantt_task {
background-color: #4CAF50; /* 修改任务条的背景色 */
border: 1px solid #333; /* 修改任务条的边框 */
}
.gantt_task_line {
height: 20px; /* 修改任务条的高度 */
}
.gantt_grid_line {
border-color: #ccc; /* 修改网格线的颜色 */
}
gantt.templates.task_text = function(start, end, task) {
return "<span style='color: red;'>" + task.text + "</span>"; // 修改任务文本颜色
};
//
// test
//test
const secondGridColumns = [
{
name: 'actions',
label: '操作',
width: 200,
align: 'center',
template: (task) => {
return `
<div class="gantt-actions">
<div class="edit-btn" data-task-id="${task.id}">编辑</div>
<div class="detail-btn" data-task-id="${task.id}">详情</div>
<div class="record-btn" data-task-id="${task.id}">修改记录</div>
</div>
`;
}
}
];
// demo
<!DOCTYPE html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Grid columns rightside of gantt</title>
<script src="../../codebase/dhtmlxgantt.js?v=9.0.3"></script>
<link rel="stylesheet" href="../../codebase/dhtmlxgantt.css?v=9.0.3">
<style>
html, body {
padding: 0px;
margin: 0px;
height: 100%;
}
.gantt_grid_scale .gantt_grid_head_cell,
.gantt_task .gantt_task_scale .gantt_scale_cell {
font-weight: bold;
font-size: 14px;
color: rgba(0, 0, 0, 0.7);
}
</style>
</head>
<body>
<div id="gantt_here" style='width:100%; height:100%;'></div>
<script>
var secondGridColumns = {
columns: [
{
name: "status", label: "Status", width: 60, align: "center", template: function (task) {
var progress = task.progress || 0;
return Math.floor(progress * 100) + "";
}
},
{
name: "impact", width: 90, label: "Impact", template: function (task) {
return (task.duration * 1000).toLocaleString("en-US", {style: 'currency', currency: 'USD'});
}
}
]
};
gantt.config.layout = {
css: "gantt_container",
rows: [
{
cols: [
{view: "grid", width: 320, scrollY: "scrollVer"},
{resizer: true, width: 1},
{view: "timeline", scrollX: "scrollHor", scrollY: "scrollVer"},
{resizer: true, width: 1},
{view: "grid", width: 160, bind: "task", scrollY: "scrollVer", config: secondGridColumns},
{view: "scrollbar", id: "scrollVer"}
]
},
{view: "scrollbar", id: "scrollHor", height: 20}
]
};
gantt.init("gantt_here");
gantt.parse({
data: [
{id: 1, text: "Office itinerancy", type: gantt.config.types.project, progress: 0.4, open: false},
{id: 2, text: "Office facing", type: gantt.config.types.project, start_date: "02-04-2025", duration: "8", progress: 0.6, parent: "1", open: true},
{id: 3, text: "Furniture installation", type: gantt.config.types.project, start_date: "11-04-2025", duration: "8", parent: "1", progress: 0.6, open: true},
{id: 4, text: "The employee relocation", type: gantt.config.types.project, start_date: "13-04-2025", duration: "6", parent: "1", progress: 0.5, open: true},
{id: 5, text: "Interior office", start_date: "02-04-2025", duration: "7", parent: "2", progress: 0.6, open: true},
{id: 6, text: "Air conditioners check", start_date: "03-04-2025", duration: "7", parent: "2", progress: 0.6, open: true},
{id: 7, text: "Workplaces preparation", start_date: "11-04-2025", duration: "8", parent: "3", progress: 0.6, open: true},
{id: 8, text: "Preparing workplaces", start_date: "14-04-2025", duration: "5", parent: "4", progress: 0.5, open: true},
{id: 9, text: "Workplaces importation", start_date: "14-04-2025", duration: "4", parent: "4", progress: 0.5, open: true},
{id: 10, text: "Workplaces exportation", start_date: "14-04-2025", duration: "3", parent: "4", progress: 0.5, open: true},
{id: 11, text: "Product launch", type: gantt.config.types.project, progress: 0.6, open: true},
{id: 12, text: "Perform Initial testing", start_date: "03-04-2025", duration: "5", parent: "11", progress: 1, open: true},
{id: 13, text: "Development", type: gantt.config.types.project, start_date: "02-04-2025", duration: "7", parent: "11", progress: 0.5, open: true},
{id: 14, text: "Analysis", start_date: "02-04-2025", duration: "6", parent: "11", progress: 0.8, open: true},
{id: 15, text: "Design", type: gantt.config.types.project, start_date: "02-04-2025", duration: "5", parent: "11", progress: 0.2, open: false},
{id: 16, text: "Documentation creation", start_date: "02-04-2025", duration: "7", parent: "11", progress: 0, open: true},
{id: 17, text: "Develop System", start_date: "03-04-2025", duration: "2", parent: "13", progress: 1, open: true},
{id: 25, text: "Beta Release", start_date: "06-04-2025", type: gantt.config.types.milestone, parent: "13", progress: 0, open: true},
{id: 18, text: "Integrate System", start_date: "08-04-2025", duration: "2", parent: "13", progress: 0.8, open: true},
{id: 19, text: "Test", start_date: "10-04-2025", duration: "4", parent: "13", progress: 0.2, open: true},
{id: 20, text: "Marketing", start_date: "10-04-2025", duration: "4", parent: "13", progress: 0, open: true},
{id: 21, text: "Design database", start_date: "03-04-2025", duration: "4", parent: "15", progress: 0.5, open: true},
{id: 22, text: "Software design", start_date: "03-04-2025", duration: "4", parent: "15", progress: 0.1, open: true},
{id: 23, text: "Interface setup", start_date: "03-04-2025", duration: "5", parent: "15", progress: 0, open: true},
{id: 24, text: "Release v1.0", start_date: "15-04-2025", type: gantt.config.types.milestone, parent: "11", progress: 0, open: true}
],
links: [
{id: "1", source: "1", target: "2", type: "1"},
{id: "2", source: "2", target: "3", type: "0"},
{id: "3", source: "3", target: "4", type: "0"},
{id: "4", source: "2", target: "5", type: "2"},
{id: "5", source: "2", target: "6", type: "2"},
{id: "6", source: "3", target: "7", type: "2"},
{id: "7", source: "4", target: "8", type: "2"},
{id: "8", source: "4", target: "9", type: "2"},
{id: "9", source: "4", target: "10", type: "2"},
{id: "10", source: "11", target: "12", type: "1"},
{id: "11", source: "11", target: "13", type: "1"},
{id: "12", source: "11", target: "14", type: "1"},
{id: "13", source: "11", target: "15", type: "1"},
{id: "14", source: "11", target: "16", type: "1"},
{id: "15", source: "13", target: "17", type: "1"},
{id: "16", source: "17", target: "25", type: "0"},
{id: "23", source: "25", target: "18", type: "0"},
{id: "17", source: "18", target: "19", type: "0"},
{id: "18", source: "19", target: "20", type: "0"},
{id: "19", source: "15", target: "21", type: "2"},
{id: "20", source: "15", target: "22", type: "2"},
{id: "21", source: "15", target: "23", type: "2"},
{id: "22", source: "13", target: "24", type: "0"}
]
});
</script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-11031269-1', 'auto');
ga('send', 'pageview');
</script></body>"
import React, {
forwardRef,
useEffect,
useRef,
useState,
useCallback,
} from 'react';
import { Button } from 'choerodon-ui/pro';
import { ButtonColor, FuncType } from 'choerodon-ui/pro/lib/button/enum';
import { observer } from 'mobx-react';
import { gantt } from '@/lib/dhtmlx-gantt/dhtmlxgantt.js';
import '@/lib/dhtmlx-gantt/dhtmlxgantt.css';
import { zoomLevels } from './store';
import './index.less';
import DetailModal from '../detail/main';
import RecordModal from '../record/main';
import { languageConfig } from '@/language/language';
const GanttChart = observer(
forwardRef((props, ref) => {
const [visible, setVisible] = useState(false); // 弹框(详情/编辑)
const [recordVisible, setRecordVisible] = useState(false); // 记录弹框
const [operationType, setOperationType] = useState('detail'); // 弹框类型
const [operationId, setOperationId] = useState(''); // 操作ID(用于调用详情)
const ganttRef = useRef<any>(null);
const [currentZoom, setCurrentZoom] = useState('day'); // 时间刻度(默认值: day)
const currentZoomRef = useRef('day');
/** 配置 Gantt */
const initConfig = useCallback(() => {
// 语言设置-中文
gantt.i18n.setLocale('cn');
// 行高
gantt.config.row_height = 48;
// 日期格式
gantt.config.date_format = '%Y-%m-%d %H:%i';
// 自适应
gantt.config.autosize = 'y';
// 设置列(name为数据字段,label为表头显示的名称,width为列宽,align为对齐方式)
gantt.config.columns = [
{
name: 'selected', // 勾选框列
label: '', // 表头为空
width: 50,
align: 'center',
template: task => {
return `
<div class="gantt-checkbox">
<input
type="checkbox"
data-task-id="${task.id}"
${task.selected ? 'checked' : ''}
/>
</div>
`;
},
},
{
name: 'text',
label: '姓名',
width: 150,
tree: true,
},
{ name: 'start_date', label: '开始日期', width: 130, align: 'center' },
{ name: 'duration', label: '持续时间', width: 80, align: 'center' },
{ name: 'progress', label: '进度', width: 80, align: 'center' },
{
name: 'actions',
label: '操作',
width: 200,
align: 'center',
template: task => {
return `
<div class="gantt-actions">
<div class="edit-btn" data-task-id="${task.id}">编辑</div>
<div class="detail-btn" data-task-id="${task.id}">详情</div>
<div class="record-btn" data-task-id="${task.id}">修改记录</div>
</div>
`;
},
},
];
// 布局
gantt.config.layout = {
css: 'custom-gantt-style',
rows: [
{
cols: [
{ view: 'grid', width: 450 }, // 任务列表
{ view: 'timeline', scrollX: 50, scrollY: 60 }, // 时间轴
],
},
],
resizer: {
width: 10,
handler: true,
},
};
// 启用当前日期标识插件
gantt.plugins({
marker: true,
});
// 设置时间列的样式
gantt.templates.timeline_cell_class = (task, date) => {
const isDisabledZoom = ['month', 'year', 'quarter'].includes(
currentZoomRef.current,
);
if (!isDisabledZoom && !gantt.isWorkTime(date)) return 'week_end';
return '';
};
}, []);
/** 设置当前日期标识线 */
const initCurrentDateMarker = useCallback(() => {
const dateToStr = gantt.date.date_to_str(gantt.config.task_date);
const today = new Date(new Date().setHours(0, 0, 0, 0)); // 当天零点
gantt.addMarker({
start_date: today,
css: 'today',
text: '今日',
title: `Today: ${dateToStr(today)}`,
});
}, []);
/** 初始化缩放配置 */
const initZoom = useCallback(() => {
const zoomConfig = {
levels: zoomLevels,
element: () => gantt.$root.querySelector('.gantt_task'),
};
gantt.ext.zoom.init(zoomConfig);
gantt.ext.zoom.setLevel('day');
}, []);
/** 加载任务数据 */
const loadTasks = useCallback(() => {
const tasks = {
data: [
{
id: 1,
text: 'Karla',
start_date: '2019-08-01 00:00',
duration: 3,
parent: 0,
progress: 0.5,
open: true,
},
{
id: 11,
text: 'Karla-01',
start_date: '2019-08-01 10:00',
duration: 3,
parent: 1,
progress: 0.8,
},
{
id: 2,
text: '前端',
start_date: '2019-08-02 00:00',
duration: 2,
parent: 1,
progress: 0.7,
},
{
id: 3,
text: 'York',
start_date: '2019-08-03 00:00',
duration: 4,
parent: 0,
progress: 0.3,
open: true,
},
{
id: 4,
text: '后端',
start_date: '2019-08-04 00:00',
duration: 1,
parent: 3,
progress: 0.6,
open: true,
},
{
id: 5,
text: 'Coco',
start_date: '2019-08-05 00:00',
duration: 2,
parent: 0,
progress: 0.8,
open: true,
},
{
id: 6,
text: '测试',
start_date: '2019-08-06 00:00',
duration: 5,
parent: 5,
progress: 0.4,
},
{
id: 7,
text: 'Happy',
start_date: '2019-08-07 00:00',
duration: 3,
parent: 0,
progress: 0.9,
},
{
id: 9,
text: 'Rose',
start_date: '2019-08-09 00:00',
duration: 1,
parent: 0,
progress: 0.1,
},
],
};
gantt.parse(tasks);
}, []);
/** change 操作按钮点击事件 */
const handleActionClick = useCallback(event => {
const target = event.target;
const taskId = target.getAttribute('data-task-id');
if (!taskId) return;
setOperationId(taskId);
const actionMap = {
'edit-btn': () => {
console.log('点击了编辑:', taskId);
setOperationType('edit');
setVisible(true);
},
'detail-btn': () => {
console.log('点击了详情:', taskId);
setOperationType('detail');
setVisible(true);
},
'record-btn': () => {
console.log('点击了修改记录:', taskId);
setRecordVisible(true);
},
};
// 调用对应的处理逻辑
const action = actionMap[target.className];
if (action) {
action();
}
}, []);
/**change 时间刻度视图 */
const handleZoomChange = useCallback(zoom => {
setCurrentZoom(zoom);
currentZoomRef.current = zoom;
gantt.ext.zoom.setLevel(zoom);
}, []);
/** 处理勾选框点击事件 */
const handleCheckboxClick = useCallback(event => {
const target = event.target;
if (target.tagName === 'INPUT' && target.type === 'checkbox') {
const taskId = target.getAttribute('data-task-id');
const isChecked = target.checked;
// 更新任务数据中的选中状态
const task = gantt.getTask(taskId);
task.selected = isChecked;
gantt.updateTask(taskId);
console.log('任务选中状态:', taskId, isChecked);
}
}, []);
/** 初始化 Gantt */
useEffect(() => {
initConfig();
initZoom();
initCurrentDateMarker();
// 初始化
gantt.init(ganttRef.current);
// 加载数据
loadTasks();
// 绑定操作按钮的点击事件
const ganttContainer = ganttRef.current;
ganttContainer.addEventListener('click', handleActionClick);
// 绑定勾选框的点击事件
ganttContainer.addEventListener('change', handleCheckboxClick);
// 清理事件监听器
return () => {
ganttContainer.removeEventListener('click', handleActionClick);
ganttContainer.removeEventListener('change', handleCheckboxClick);
};
}, [
initConfig,
initZoom,
initCurrentDateMarker,
loadTasks,
handleActionClick,
handleCheckboxClick,
]);
return (
<div>
{/* 时间刻度:切换按钮 */}
<div style={{ margin: '12px 0' }}>
{zoomLevels.map(item => (
<Button
key={item.name}
color={ButtonColor.primary}
funcType={FuncType.raised}
disabled={item.name === currentZoom}
onClick={() => handleZoomChange(item.name)}
style={{ marginRight: 6 }}
>
{item.label}
</Button>
))}
</div>
{/* Gantt 容器 */}
<div style={{ height: '500px', overflow: 'auto' }}>
<div ref={ganttRef} style={{ width: '100%', height: '100%' }}></div>
</div>
{/* 详情/编辑弹框 */}
{visible && (
<DetailModal
visible={visible}
setVisible={setVisible}
onSelect={() => {}}
title={
operationType === 'detail'
? languageConfig('platformCharter.title.detail', '详情')
: languageConfig('platformCharter.title.edit', '编辑')
}
infoData={{
operationId,
operationType,
}}
/>
)}
{/* 记录 */}
{recordVisible && (
<RecordModal
visible={recordVisible}
setVisible={setRecordVisible}
onSelect={() => {}}
title={languageConfig(
'platformCharter.title.editRecord',
'修改记录',
)}
infoData={{
operationId,
}}
/>
)}
</div>
);
}),
);
export default GanttChart;
store.js文件
export const zoomLevels = [
// {
// name: 'hour',
// label: '小时',
// scale_height: 50,
// min_column_width: 30,
// scales: [
// { unit: 'day', format: '%Y-%m-%d' },
// { unit: 'hour', format: '%H' },
// ],
// },
{
name: 'day',
label: '日',
scale_height: 70,
min_column_width: 30,
scales: [
{ unit: 'month', format: '%Y年 %F' },
// { unit: "day", step: 1, format: "%j %D" },
{
unit: 'day',
step: 1,
format: date => {
const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
const day = new Date(date).getDate();
const weekDay = new Date(date).getDay();
return `<div class='scale-formate-date'>
<span class='formate-date'>${day}</span>
<span class='formate-weekDay'>${weekDays[weekDay]}</span>
</div>`;
// return "<strong>Day " + dayNumber(date) + "</strong><br/>" + dateFormat(date);
},
},
],
},
{
name: 'week',
label: '周',
scale_height: 50,
min_column_width: 50,
scales: [
{ unit: 'month', format: '%Y年 %F' },
{ unit: 'week', step: 1, date: '%W周' },
],
},
{
name: 'month',
label: '月',
scale_height: 50,
min_column_width: 50,
scales: [
// { unit: "year", step: 1, format: "%Y年" },
{
unit: 'quarter',
step: 1,
format: date => {
const year = new Date(date).getFullYear();
const month = new Date(date).getMonth();
const quarter = Math.floor(month / 3 + 1);
return `${year}年-Q${quarter}`;
// return `Q${quarter}`;
},
},
{ unit: 'month', step: 1, format: '%F' },
],
},
{
name: 'quarter',
label: '季',
scale_height: 50,
min_column_width: 50,
scales: [
{ unit: 'year', step: 1, format: '%Y年' },
{
unit: 'quarter',
step: 1,
format: date => {
// const year = new Date(date).getFullYear();
const month = new Date(date).getMonth();
const quarter = Math.floor(month / 3 + 1);
// return `${year}年-Q${quarter}`;
return `Q${quarter}`;
},
},
],
},
{
name: 'year',
label: '年',
scale_height: 50,
min_column_width: 50,
scales: [{ unit: 'year', step: 1, format: '%Y年' }],
},
];
export const zoomMap = {
day: '日',
week: '周',
month: '月',
quarter: '季',
year: '年',
};
.gantt-actions {
display: flex;
gap: 8px;
justify-content: center;
}
/************************************* table Header **************************************/
.gantt_grid_head_cell {
background-color: #f5f7f8;
font-size: 14px;
font-weight: 400;
}
/************************************* checkbox 勾选框 **************************************/
.gantt-checkbox input {
cursor: pointer;
border-radius: 4px;
border: 1px solid #c7cfd8;
width: 14px;
height: 14px;
appearance: none; /* 清除默认样式 */
-webkit-appearance: none; /* 兼容 Safari 和 Chrome */
-moz-appearance: none; /* 兼容 Firefox */
position: relative; /* 为伪元素定位 */
}
/* 选中状态样式 */
.gantt-checkbox input:checked {
background-color: #1890ff; /* 选中时的背景色 */
border-color: #1890ff; /* 选中时的边框颜色 */
}
/* 小勾样式 */
.gantt-checkbox input:checked::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 4px;
height: 8px;
border: solid white;
border-width: 0 2px 2px 0;
transform: translate(-50%, -60%) rotate(45deg); /* 调整位置和旋转角度 */
}
/************************************* 操作(btn) **************************************/
.edit-btn,
.detail-btn,
.record-btn {
color: #007dc6;
cursor: pointer;
}
3、mock数据(暂时没用上)
export const tasksList = {
data: [
{
bid: 1,
pCode: '0',
type: 1,
code: 'm1234',
name: 'm1234',
projectRank: 'm1234',
marketPositioning: 'm1234',
costBenchmarking: 'm1234',
performanceBenchmark: 'm1234',
targetAudienceName: 'm1234',
focusedIndustriesAndClientsName: 'm1234',
newReachableCapacity: 'm1234',
preparationOfKeyTechnologies: null,
valueProposition: 'm1234',
keyCompetitive: 'm1234',
charterInitDate: '2025-01-02 00:00:00',
charterTransferDate: '2025-01-02 00:00:00',
pdcpDate: '2025-01-02 00:00:00',
tr4aDate: '2025-01-02 00:00:00',
edcpDate: '2025-01-02 00:00:00',
adcpDate: '2025-05-02 00:00:00',
insightFinishDate: '2025-03-02 00:00:00',
relateOfferingName: null,
rerlationshipName: null,
serviceSolution: null,
belongSolutionName: null,
productClassL3Name: null,
productSeriesL4Name: null,
productOfferingL5Name: null,
productBelongGroupsName: null,
productBelongSpdtName: null,
charterClass: null,
charterTransferVersionTypeName: null,
decisionLevelName: null,
priorityName: null,
businessPropertyName: null,
bak: null,
verison: null,
state: 1,
createUser: null,
updatedUser: null,
milestones: null,
children: [
{
bid: 4,
pCode: 'm1234',
type: 2,
code: 'm1234567',
name: 'm1234',
projectRank: 'm1234',
marketPositioning: 'm1234',
costBenchmarking: 'm1234',
performanceBenchmark: 'm1234',
targetAudienceName: 'm1234',
focusedIndustriesAndClientsName: 'm1234',
newReachableCapacity: 'm1234',
preparationOfKeyTechnologies: null,
valueProposition: 'm1234',
keyCompetitive: 'm1234',
charterInitDate: '2025-01-02 00:00:00',
charterTransferDate: '2025-02-02 00:00:00',
pdcpDate: '2025-03-02 00:00:00',
tr4aDate: '2025-04-02 00:00:00',
edcpDate: '2025-05-02 00:00:00',
adcpDate: '2025-09-02 00:00:00',
insightFinishDate: '2025-09-02 00:00:00',
relateOfferingName: null,
rerlationshipName: null,
serviceSolution: null,
belongSolutionName: null,
productClassL3Name: null,
productSeriesL4Name: null,
productOfferingL5Name: null,
productBelongGroupsName: null,
productBelongSpdtName: null,
charterClass: null,
charterTransferVersionTypeName: null,
decisionLevelName: null,
priorityName: null,
businessPropertyName: null,
bak: null,
verison: null,
state: 1,
createUser: null,
updatedUser: null,
milestones: [
{
id: 'm1234567-1',
pCode: 'm1234567',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm1234567',
start_date: '2025-01-02',
end_date: '2025-02-02',
},
{
id: 'm1234567-2',
pCode: 'm1234567',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm1234567',
start_date: '2025-02-02',
end_date: '2025-03-02',
},
{
id: 'm1234567-3',
pCode: 'm1234567',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm1234567',
start_date: '2025-03-02',
end_date: '2025-04-02',
},
{
id: 'm1234567-4',
pCode: 'm1234567',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm1234567',
start_date: '2025-04-02',
end_date: '2025-05-02',
},
{
id: 'm1234567-5',
pCode: 'm1234567',
startDate: '2025-05-02',
endDate: '2025-09-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm1234567',
start_date: '2025-05-02',
end_date: '2025-09-02',
},
],
children: null,
parent: 'm1234',
render: 'split',
isChildrenNode: true,
},
{
bid: 5,
pCode: 'm1234',
type: 2,
code: 'm12345678',
name: 'm1234',
projectRank: 'm1234',
marketPositioning: 'm1234',
costBenchmarking: 'm1234',
performanceBenchmark: 'm1234',
targetAudienceName: 'm1234',
focusedIndustriesAndClientsName: 'm1234',
newReachableCapacity: 'm1234',
preparationOfKeyTechnologies: null,
valueProposition: 'm1234',
keyCompetitive: 'm1234',
charterInitDate: '2025-01-02 00:00:00',
charterTransferDate: '2025-02-02 00:00:00',
pdcpDate: '2025-03-02 00:00:00',
tr4aDate: '2025-04-02 00:00:00',
edcpDate: '2025-05-02 00:00:00',
adcpDate: '2025-07-02 00:00:00',
insightFinishDate: '2025-09-02 00:00:00',
relateOfferingName: null,
rerlationshipName: null,
serviceSolution: null,
belongSolutionName: null,
productClassL3Name: null,
productSeriesL4Name: null,
productOfferingL5Name: null,
productBelongGroupsName: null,
productBelongSpdtName: null,
charterClass: null,
charterTransferVersionTypeName: null,
decisionLevelName: null,
priorityName: null,
businessPropertyName: null,
bak: null,
verison: null,
state: 1,
createUser: null,
updatedUser: null,
milestones: [
{
id: 'm12345678-1',
pCode: 'm12345678',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm12345678',
start_date: '2025-01-02',
end_date: '2025-02-02',
},
{
id: 'm12345678-2',
pCode: 'm12345678',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm12345678',
start_date: '2025-02-02',
end_date: '2025-03-02',
},
{
id: 'm12345678-3',
pCode: 'm12345678',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm12345678',
start_date: '2025-03-02',
end_date: '2025-04-02',
},
{
id: 'm12345678-4',
pCode: 'm12345678',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm12345678',
start_date: '2025-04-02',
end_date: '2025-05-02',
},
{
id: 'm12345678-5',
pCode: 'm12345678',
startDate: '2025-05-02',
endDate: '2025-07-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm12345678',
start_date: '2025-05-02',
end_date: '2025-07-02',
},
],
children: null,
parent: 'm1234',
render: 'split',
isChildrenNode: true,
},
],
id: 'm1234',
color: '#c7cfd8',
text: '',
},
{
id: 'm1234567-1',
pCode: 'm1234567',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm1234567',
start_date: '2025-01-02',
end_date: '2025-02-02',
color: '#adbbff',
},
{
id: 'm1234567-2',
pCode: 'm1234567',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm1234567',
start_date: '2025-02-02',
end_date: '2025-03-02',
color: '#ffe179',
},
{
id: 'm1234567-3',
pCode: 'm1234567',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm1234567',
start_date: '2025-03-02',
end_date: '2025-04-02',
color: '#adbbff',
},
{
id: 'm1234567-4',
pCode: 'm1234567',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm1234567',
start_date: '2025-04-02',
end_date: '2025-05-02',
color: '#92d9fb',
},
{
id: 'm1234567-5',
pCode: 'm1234567',
startDate: '2025-05-02',
endDate: '2025-09-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm1234567',
start_date: '2025-05-02',
end_date: '2025-09-02',
color: '#64e0b7',
},
{
bid: 4,
pCode: 'm1234',
type: 2,
code: 'm1234567',
name: 'm1234',
projectRank: 'm1234',
marketPositioning: 'm1234',
costBenchmarking: 'm1234',
performanceBenchmark: 'm1234',
targetAudienceName: 'm1234',
focusedIndustriesAndClientsName: 'm1234',
newReachableCapacity: 'm1234',
preparationOfKeyTechnologies: null,
valueProposition: 'm1234',
keyCompetitive: 'm1234',
charterInitDate: '2025-01-02 00:00:00',
charterTransferDate: '2025-02-02 00:00:00',
pdcpDate: '2025-03-02 00:00:00',
tr4aDate: '2025-04-02 00:00:00',
edcpDate: '2025-05-02 00:00:00',
adcpDate: '2025-09-02 00:00:00',
insightFinishDate: '2025-09-02 00:00:00',
relateOfferingName: null,
rerlationshipName: null,
serviceSolution: null,
belongSolutionName: null,
productClassL3Name: null,
productSeriesL4Name: null,
productOfferingL5Name: null,
productBelongGroupsName: null,
productBelongSpdtName: null,
charterClass: null,
charterTransferVersionTypeName: null,
decisionLevelName: null,
priorityName: null,
businessPropertyName: null,
bak: null,
verison: null,
state: 1,
createUser: null,
updatedUser: null,
milestones: [
{
id: 'm1234567-1',
pCode: 'm1234567',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm1234567',
start_date: '2025-01-02',
end_date: '2025-02-02',
},
{
id: 'm1234567-2',
pCode: 'm1234567',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm1234567',
start_date: '2025-02-02',
end_date: '2025-03-02',
},
{
id: 'm1234567-3',
pCode: 'm1234567',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm1234567',
start_date: '2025-03-02',
end_date: '2025-04-02',
},
{
id: 'm1234567-4',
pCode: 'm1234567',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm1234567',
start_date: '2025-04-02',
end_date: '2025-05-02',
},
{
id: 'm1234567-5',
pCode: 'm1234567',
startDate: '2025-05-02',
endDate: '2025-09-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm1234567',
start_date: '2025-05-02',
end_date: '2025-09-02',
},
],
children: null,
parent: 'm1234',
render: 'split',
isChildrenNode: true,
id: 'm1234567',
},
{
id: 'm12345678-1',
pCode: 'm12345678',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm12345678',
start_date: '2025-01-02',
end_date: '2025-02-02',
color: '#adbbff',
},
{
id: 'm12345678-2',
pCode: 'm12345678',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm12345678',
start_date: '2025-02-02',
end_date: '2025-03-02',
color: '#ffe179',
},
{
id: 'm12345678-3',
pCode: 'm12345678',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm12345678',
start_date: '2025-03-02',
end_date: '2025-04-02',
color: '#adbbff',
},
{
id: 'm12345678-4',
pCode: 'm12345678',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm12345678',
start_date: '2025-04-02',
end_date: '2025-05-02',
color: '#92d9fb',
},
{
id: 'm12345678-5',
pCode: 'm12345678',
startDate: '2025-05-02',
endDate: '2025-07-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm12345678',
start_date: '2025-05-02',
end_date: '2025-07-02',
color: '#64e0b7',
},
{
bid: 5,
pCode: 'm1234',
type: 2,
code: 'm12345678',
name: 'm1234',
projectRank: 'm1234',
marketPositioning: 'm1234',
costBenchmarking: 'm1234',
performanceBenchmark: 'm1234',
targetAudienceName: 'm1234',
focusedIndustriesAndClientsName: 'm1234',
newReachableCapacity: 'm1234',
preparationOfKeyTechnologies: null,
valueProposition: 'm1234',
keyCompetitive: 'm1234',
charterInitDate: '2025-01-02 00:00:00',
charterTransferDate: '2025-02-02 00:00:00',
pdcpDate: '2025-03-02 00:00:00',
tr4aDate: '2025-04-02 00:00:00',
edcpDate: '2025-05-02 00:00:00',
adcpDate: '2025-07-02 00:00:00',
insightFinishDate: '2025-09-02 00:00:00',
relateOfferingName: null,
rerlationshipName: null,
serviceSolution: null,
belongSolutionName: null,
productClassL3Name: null,
productSeriesL4Name: null,
productOfferingL5Name: null,
productBelongGroupsName: null,
productBelongSpdtName: null,
charterClass: null,
charterTransferVersionTypeName: null,
decisionLevelName: null,
priorityName: null,
businessPropertyName: null,
bak: null,
verison: null,
state: 1,
createUser: null,
updatedUser: null,
milestones: [
{
id: 'm12345678-1',
pCode: 'm12345678',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm12345678',
start_date: '2025-01-02',
end_date: '2025-02-02',
},
{
id: 'm12345678-2',
pCode: 'm12345678',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm12345678',
start_date: '2025-02-02',
end_date: '2025-03-02',
},
{
id: 'm12345678-3',
pCode: 'm12345678',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm12345678',
start_date: '2025-03-02',
end_date: '2025-04-02',
},
{
id: 'm12345678-4',
pCode: 'm12345678',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm12345678',
start_date: '2025-04-02',
end_date: '2025-05-02',
},
{
id: 'm12345678-5',
pCode: 'm12345678',
startDate: '2025-05-02',
endDate: '2025-07-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm12345678',
start_date: '2025-05-02',
end_date: '2025-07-02',
},
],
children: null,
parent: 'm1234',
render: 'split',
isChildrenNode: true,
id: 'm12345678',
},
{
id: 'm12345-1',
pCode: 'm12345',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm12345',
start_date: '2025-01-02',
end_date: '2025-02-02',
color: '#adbbff',
},
{
id: 'm12345-2',
pCode: 'm12345',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm12345',
start_date: '2025-02-02',
end_date: '2025-03-02',
color: '#ffe179',
},
{
id: 'm12345-3',
pCode: 'm12345',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm12345',
start_date: '2025-03-02',
end_date: '2025-04-02',
color: '#adbbff',
},
{
id: 'm12345-4',
pCode: 'm12345',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm12345',
start_date: '2025-04-02',
end_date: '2025-05-02',
color: '#92d9fb',
},
{
id: 'm12345-5',
pCode: 'm12345',
startDate: '2025-05-02',
endDate: '2025-06-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm12345',
start_date: '2025-05-02',
end_date: '2025-06-02',
color: '#64e0b7',
},
{
bid: 2,
pCode: '0',
type: 2,
code: 'm12345',
name: 'm1234',
projectRank: 'm1234',
marketPositioning: 'm1234',
costBenchmarking: 'm1234',
performanceBenchmark: 'm1234',
targetAudienceName: 'm1234',
focusedIndustriesAndClientsName: 'm1234',
newReachableCapacity: 'm1234',
preparationOfKeyTechnologies: null,
valueProposition: 'm1234',
keyCompetitive: 'm1234',
charterInitDate: '2025-01-02 00:00:00',
charterTransferDate: '2025-02-02 00:00:00',
pdcpDate: '2025-03-02 00:00:00',
tr4aDate: '2025-04-02 00:00:00',
edcpDate: '2025-05-02 00:00:00',
adcpDate: '2025-06-02 00:00:00',
insightFinishDate: '2025-07-02 00:00:00',
relateOfferingName: null,
rerlationshipName: null,
serviceSolution: null,
belongSolutionName: null,
productClassL3Name: null,
productSeriesL4Name: null,
productOfferingL5Name: null,
productBelongGroupsName: null,
productBelongSpdtName: null,
charterClass: null,
charterTransferVersionTypeName: null,
decisionLevelName: null,
priorityName: null,
businessPropertyName: null,
bak: null,
verison: null,
state: 1,
createUser: null,
updatedUser: null,
milestones: [
{
id: 'm12345-1',
pCode: 'm12345',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm12345',
start_date: '2025-01-02',
end_date: '2025-02-02',
},
{
id: 'm12345-2',
pCode: 'm12345',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm12345',
start_date: '2025-02-02',
end_date: '2025-03-02',
},
{
id: 'm12345-3',
pCode: 'm12345',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm12345',
start_date: '2025-03-02',
end_date: '2025-04-02',
},
{
id: 'm12345-4',
pCode: 'm12345',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm12345',
start_date: '2025-04-02',
end_date: '2025-05-02',
},
{
id: 'm12345-5',
pCode: 'm12345',
startDate: '2025-05-02',
endDate: '2025-06-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm12345',
start_date: '2025-05-02',
end_date: '2025-06-02',
},
],
children: null,
render: 'split',
id: 'm12345',
},
{
id: 'm12346-1',
pCode: 'm12346',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm12346',
start_date: '2025-01-02',
end_date: '2025-02-02',
color: '#adbbff',
},
{
id: 'm12346-2',
pCode: 'm12346',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm12346',
start_date: '2025-02-02',
end_date: '2025-03-02',
color: '#ffe179',
},
{
id: 'm12346-3',
pCode: 'm12346',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm12346',
start_date: '2025-03-02',
end_date: '2025-04-02',
color: '#adbbff',
},
{
id: 'm12346-4',
pCode: 'm12346',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm12346',
start_date: '2025-04-02',
end_date: '2025-05-02',
color: '#92d9fb',
},
{
id: 'm12346-5',
pCode: 'm12346',
startDate: '2025-05-02',
endDate: '2025-08-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm12346',
start_date: '2025-05-02',
end_date: '2025-08-02',
color: '#64e0b7',
},
{
bid: 3,
pCode: '0',
type: 2,
code: 'm12346',
name: 'm1234',
projectRank: 'm1234',
marketPositioning: 'm1234',
costBenchmarking: 'm1234',
performanceBenchmark: 'm1234',
targetAudienceName: 'm1234',
focusedIndustriesAndClientsName: 'm1234',
newReachableCapacity: 'm1234',
preparationOfKeyTechnologies: null,
valueProposition: 'm1234',
keyCompetitive: 'm1234',
charterInitDate: '2025-01-02 00:00:00',
charterTransferDate: '2025-02-02 00:00:00',
pdcpDate: '2025-03-02 00:00:00',
tr4aDate: '2025-04-02 00:00:00',
edcpDate: '2025-05-02 00:00:00',
adcpDate: '2025-08-02 00:00:00',
insightFinishDate: '2025-09-02 00:00:00',
relateOfferingName: null,
rerlationshipName: null,
serviceSolution: null,
belongSolutionName: null,
productClassL3Name: null,
productSeriesL4Name: null,
productOfferingL5Name: null,
productBelongGroupsName: null,
productBelongSpdtName: null,
charterClass: null,
charterTransferVersionTypeName: null,
decisionLevelName: null,
priorityName: null,
businessPropertyName: null,
bak: null,
verison: null,
state: 1,
createUser: null,
updatedUser: null,
milestones: [
{
id: 'm12346-1',
pCode: 'm12346',
startDate: '2025-01-02',
endDate: '2025-02-02',
text: 'Charter开发',
milestonskey: 'CHARTER_DEVELOPMENT',
parent: 'm12346',
start_date: '2025-01-02',
end_date: '2025-02-02',
},
{
id: 'm12346-2',
pCode: 'm12346',
startDate: '2025-02-02',
endDate: '2025-03-02',
text: '概念和计划',
milestonskey: 'CONCEPT_AND_PLAN',
parent: 'm12346',
start_date: '2025-02-02',
end_date: '2025-03-02',
},
{
id: 'm12346-3',
pCode: 'm12346',
startDate: '2025-03-02',
endDate: '2025-04-02',
text: '初样开发',
milestonskey: 'INITIAL_SAMPLE_DEVELOPMENT',
parent: 'm12346',
start_date: '2025-03-02',
end_date: '2025-04-02',
},
{
id: 'm12346-4',
pCode: 'm12346',
startDate: '2025-04-02',
endDate: '2025-05-02',
text: '正样开发',
milestonskey: 'PROTOTYPE_DEVELOPMENT',
parent: 'm12346',
start_date: '2025-04-02',
end_date: '2025-05-02',
},
{
id: 'm12346-5',
pCode: 'm12346',
startDate: '2025-05-02',
endDate: '2025-08-02',
text: '验证',
milestonskey: 'VERIFY',
parent: 'm12346',
start_date: '2025-05-02',
end_date: '2025-08-02',
},
],
children: null,
render: 'split',
id: 'm12346',
},
],
};