龍魂 · 鸿蒙 ArkTS 实战:Project Milestone Timeline
·
生成CSDN格式的完整博客文章
article = ‘’'# 龍魂 · 鸿蒙 ArkTS 实战:Project Milestone Timeline
龍魂系统 · 鸿蒙原生适配层 · 项目里程碑时间线可视化
DNA: ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️ | UID: 9622 | CONFIRM: #CONFIRM🌌9622-ONLY-ONCE🧬LK9X-772Z
一、核心定位
| 维度 | 说明 |
|---|---|
| 平台 | 鸿蒙 HarmonyOS NEXT · 纯血鸿蒙 |
| 语言 | ArkTS · 声明式UI |
| 场景 | 项目里程碑管理 · 时间线可视化 · 进度追踪 · 风险预警 |
| 架构 | 龍魂蚁群触角 → 鸿蒙原生能力 |
| 主权 | 数据本地 · 国密SM2/SM3签名 · 不上传云端 |
二、系统架构
┌─────────────────────────────────────────┐
│ 龍魂系统 · 鸿蒙适配层 │
│ DNA: ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️ │
│ UID: 9622 │
├─────────────────────────────────────────┤
│ 鸿蒙 ArkTS 应用层 │
│ │
│ EntryAbility → MilestoneTimelinePage │
│ ├── 项目状态建模(AppStorage/LocalStorage)│
│ ├── 里程碑时间线(甘特图·瀑布流·卡片) │
│ ├── 进度追踪引擎(自动计算·依赖分析) │
│ ├── 风险预警系统(延期预警·资源冲突) │
│ ├── 资源管理(人员·预算·工时) │
│ ├── 版本控制(基线·变更·回滚) │
│ └── 办公交互(导出报表·分享·日历同步) │
├─────────────────────────────────────────┤
│ 鸿蒙系统能力层 │
│ │
│ 日历(Calendar) · 通知(Notification) │
│ 数据存储(RelationalStore) · 文件(File) │
│ 网络(Http) · 分享(Share) · 打印(Print) │
│ 后台任务(WorkScheduler) · 定位(Location) │
└─────────────────────────────────────────┘
三、状态建模核心
3.1 数据模型(entry/src/main/ets/models/MilestoneModel.ets)
// === DNA常量 ===
const MASTER_DNA = "ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️";
const MASTER_UID = "9622";
const CONFIRM_SEAL = "#CONFIRM🌌9622-ONLY-ONCE🧬LK9X-772Z";
// === 项目状态 ===
export enum ProjectStatus {
PLANNING = '规划中', // 立项阶段
ACTIVE = '进行中', // 执行阶段
PAUSED = '已暂停', // 暂停
COMPLETED = '已完成', // 完成
CANCELLED = '已取消', // 取消
ARCHIVED = '已归档' // 归档
}
// === 里程碑状态 ===
export enum MilestoneStatus {
NOT_STARTED = '未开始', // 未开始
IN_PROGRESS = '进行中', // 进行中
AT_RISK = '有风险', // 有风险
DELAYED = '已延期', // 已延期
COMPLETED = '已完成', // 已完成
BLOCKED = '被阻塞' // 被阻塞
}
// === 优先级 ===
export enum Priority {
P0 = 'P0-紧急', // 最高
P1 = 'P1-高', // 高
P2 = 'P2-中', // 中
P3 = 'P3-低', // 低
P4 = 'P4-最低' // 最低
}
// === 风险等级 ===
export enum RiskLevel {
NONE = '无风险', // 绿色
LOW = '低风险', // 蓝色
MEDIUM = '中风险', // 黄色
HIGH = '高风险', // 橙色
CRITICAL = '极高风险' // 红色
}
// === 依赖类型 ===
export enum DependencyType {
FS = 'FS', // Finish-to-Start 完成-开始
SS = 'SS', // Start-to-Start 开始-开始
FF = 'FF', // Finish-to-Finish 完成-完成
SF = 'SF' // Start-to-Finish 开始-完成
}
3.2 Project 类(项目管理核心)
export class Project {
id: string;
projectNo: string; // 项目编号
name: string; // 项目名称
description: string; // 项目描述
status: ProjectStatus; // 状态
// 时间
plannedStart: Date; // 计划开始
plannedEnd: Date; // 计划结束
actualStart?: Date; // 实际开始
actualEnd?: Date; // 实际结束
// 负责人
projectManager: string; // 项目经理
productManager: string; // 产品经理
techLead: string; // 技术负责人
qaLead: string; // 测试负责人
// 团队
teamMembers: TeamMember[]; // 团队成员
// 预算
budget: number; // 总预算
costIncurred: number; // 已发生成本
costForecast: number; // 预测总成本
// 里程碑
milestones: Milestone[]; // 里程碑列表
// 版本基线
baselines: Baseline[]; // 基线记录
// 风险
risks: Risk[]; // 风险列表
// 审计
createdAt: Date;
updatedAt: Date;
dnaSignature: string;
constructor(data: Partial<Project>) {
this.id = data.id || this.generateId();
this.projectNo = data.projectNo || this.generateProjectNo();
this.name = data.name || '';
this.description = data.description || '';
this.status = data.status || ProjectStatus.PLANNING;
this.plannedStart = data.plannedStart || new Date();
this.plannedEnd = data.plannedEnd || new Date(Date.now() + 90*24*60*60*1000);
this.actualStart = data.actualStart;
this.actualEnd = data.actualEnd;
this.projectManager = data.projectManager || '';
this.productManager = data.productManager || '';
this.techLead = data.techLead || '';
this.qaLead = data.qaLead || '';
this.teamMembers = data.teamMembers || [];
this.budget = data.budget || 0;
this.costIncurred = data.costIncurred || 0;
this.costForecast = data.costForecast || 0;
this.milestones = data.milestones || [];
this.baselines = data.baselines || [];
this.risks = data.risks || [];
this.createdAt = data.createdAt || new Date();
this.updatedAt = data.updatedAt || new Date();
this.dnaSignature = this.signData();
}
private generateId(): string {
return `PRJ-${MASTER_UID}-${Date.now().toString(36).substr(-6)}`;
}
private generateProjectNo(): string {
const date = new Date();
return `XM${date.getFullYear()}${(date.getMonth()+1).toString().padStart(2,'0')}-${Math.floor(Math.random()*9999).toString().padStart(4,'0')}`;
}
private signData(): string {
const payload = `${this.id}-${this.projectNo}-${this.name}-${this.status}`;
return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
}
// 计算进度
getProgress(): number {
if (this.milestones.length === 0) return 0;
const completed = this.milestones.filter(m => m.status === MilestoneStatus.COMPLETED).length;
return Math.round((completed / this.milestones.length) * 100);
}
// 计算延期天数
getDelayDays(): number {
if (this.actualEnd) {
return Math.max(0, Math.floor((this.actualEnd.getTime() - this.plannedEnd.getTime()) / (1000*60*60*24)));
}
if (new Date() > this.plannedEnd && this.status !== ProjectStatus.COMPLETED) {
return Math.floor((new Date().getTime() - this.plannedEnd.getTime()) / (1000*60*60*24));
}
return 0;
}
// 计算SPI(进度绩效指数)
getSPI(): number {
const pv = this.getPlannedValue();
const ev = this.getEarnedValue();
return pv > 0 ? ev / pv : 0;
}
// 计算CPI(成本绩效指数)
getCPI(): number {
const ev = this.getEarnedValue();
const ac = this.costIncurred;
return ac > 0 ? ev / ac : 0;
}
// 计划价值
private getPlannedValue(): number {
const totalDuration = this.plannedEnd.getTime() - this.plannedStart.getTime();
const elapsed = new Date().getTime() - this.plannedStart.getTime();
const plannedProgress = Math.min(1, Math.max(0, elapsed / totalDuration));
return this.budget * plannedProgress;
}
// 挣值
private getEarnedValue(): number {
return this.budget * (this.getProgress() / 100);
}
// 获取当前风险等级
getCurrentRiskLevel(): RiskLevel {
const sp = this.getSPI();
const cp = this.getCPI();
if (sp < 0.7 || cp < 0.7) return RiskLevel.CRITICAL;
if (sp < 0.85 || cp < 0.85) return RiskLevel.HIGH;
if (sp < 0.95 || cp < 0.95) return RiskLevel.MEDIUM;
if (sp < 1.0 || cp < 1.0) return RiskLevel.LOW;
return RiskLevel.NONE;
}
// 创建基线
createBaseline(name: string, description: string): Baseline {
const baseline: Baseline = {
id: `BL-${Date.now()}`,
name,
description,
createdAt: new Date(),
milestones: this.milestones.map(m => ({ ...m })),
budget: this.budget,
plannedStart: this.plannedStart,
plannedEnd: this.plannedEnd,
dnaSignature: this.signBaseline(name)
};
this.baselines.push(baseline);
return baseline;
}
// 回滚到基线
rollbackToBaseline(baselineId: string): boolean {
const baseline = this.baselines.find(b => b.id === baselineId);
if (!baseline) return false;
this.milestones = baseline.milestones.map(m => new Milestone(m));
this.budget = baseline.budget;
this.plannedStart = baseline.plannedStart;
this.plannedEnd = baseline.plannedEnd;
this.updatedAt = new Date();
this.dnaSignature = this.signData();
return true;
}
private signBaseline(name: string): string {
const payload = `${this.id}-BASELINE-${name}-${Date.now()}`;
return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
}
}
3.3 Milestone 类(里程碑核心)
export class Milestone {
id: string;
name: string;
description: string;
status: MilestoneStatus;
priority: Priority;
// 时间
plannedStart: Date;
plannedEnd: Date;
actualStart?: Date;
actualEnd?: Date;
// 进度
progress: number; // 0-100
// 依赖
dependencies: Dependency[];
// 资源
assignedTo: string[];
estimatedHours: number;
actualHours: number;
// 交付物
deliverables: Deliverable[];
// 检查点
checkPoints: CheckPoint[];
// 风险
riskLevel: RiskLevel;
riskDescription: string;
// 审计
createdAt: Date;
updatedAt: Date;
dnaSignature: string;
constructor(data: Partial<Milestone>) {
this.id = data.id || `MS-${Date.now()}-${Math.random().toString(36).substr(2,6)}`;
this.name = data.name || '';
this.description = data.description || '';
this.status = data.status || MilestoneStatus.NOT_STARTED;
this.priority = data.priority || Priority.P2;
this.plannedStart = data.plannedStart || new Date();
this.plannedEnd = data.plannedEnd || new Date();
this.actualStart = data.actualStart;
this.actualEnd = data.actualEnd;
this.progress = data.progress || 0;
this.dependencies = data.dependencies || [];
this.assignedTo = data.assignedTo || [];
this.estimatedHours = data.estimatedHours || 0;
this.actualHours = data.actualHours || 0;
this.deliverables = data.deliverables || [];
this.checkPoints = data.checkPoints || [];
this.riskLevel = data.riskLevel || RiskLevel.NONE;
this.riskDescription = data.riskDescription || '';
this.createdAt = data.createdAt || new Date();
this.updatedAt = data.updatedAt || new Date();
this.dnaSignature = this.signData();
}
private signData(): string {
const payload = `${this.id}-${this.name}-${this.status}-${this.progress}`;
return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
}
// 计算延期天数
getDelayDays(): number {
if (this.actualEnd && this.actualEnd > this.plannedEnd) {
return Math.floor((this.actualEnd.getTime() - this.plannedEnd.getTime()) / (1000*60*60*24));
}
if (new Date() > this.plannedEnd && this.status !== MilestoneStatus.COMPLETED) {
return Math.floor((new Date().getTime() - this.plannedEnd.getTime()) / (1000*60*60*24));
}
return 0;
}
// 是否关键路径
isCriticalPath(): boolean {
return this.dependencies.length === 0 || this.riskLevel === RiskLevel.CRITICAL;
}
// 更新进度
updateProgress(progress: number, operator: string): void {
this.progress = Math.min(100, Math.max(0, progress));
if (this.progress > 0 && this.status === MilestoneStatus.NOT_STARTED) {
this.status = MilestoneStatus.IN_PROGRESS;
this.actualStart = this.actualStart || new Date();
}
if (this.progress === 100) {
this.status = MilestoneStatus.COMPLETED;
this.actualEnd = new Date();
}
this.updatedAt = new Date();
this.dnaSignature = this.signData();
}
// 添加检查点
addCheckPoint(name: string, completed: boolean, operator: string): void {
this.checkPoints.push({
id: `CP-${Date.now()}`,
name,
completed,
completedBy: completed ? operator : undefined,
completedAt: completed ? new Date() : undefined,
dnaSignature: this.signCheckPoint(name, operator)
});
}
private signCheckPoint(name: string, operator: string): string {
const payload = `${this.id}-CP-${name}-${operator}-${Date.now()}`;
return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
}
}
3.4 Risk 类(风险管理)
export class Risk {
id: string;
name: string;
description: string;
level: RiskLevel;
probability: number; // 0-1
impact: number; // 0-1
mitigation: string; // 缓解措施
contingency: string; // 应急计划
owner: string; // 负责人
status: 'open' | 'mitigated' | 'realized' | 'closed';
createdAt: Date;
updatedAt: Date;
dnaSignature: string;
constructor(data: Partial<Risk>) {
this.id = data.id || `RISK-${Date.now()}-${Math.random().toString(36).substr(2,6)}`;
this.name = data.name || '';
this.description = data.description || '';
this.level = data.level || RiskLevel.LOW;
this.probability = data.probability || 0.5;
this.impact = data.impact || 0.5;
this.mitigation = data.mitigation || '';
this.contingency = data.contingency || '';
this.owner = data.owner || '';
this.status = data.status || 'open';
this.createdAt = data.createdAt || new Date();
this.updatedAt = data.updatedAt || new Date();
this.dnaSignature = this.signData();
}
private signData(): string {
const payload = `${this.id}-${this.name}-${this.level}-${this.status}`;
return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
}
// 计算风险值
getRiskScore(): number {
return this.probability * this.impact;
}
}
3.5 ProjectState 全局状态
@Observed
export class ProjectState {
projects: Project[] = [];
currentProjectId: string = '';
// 过滤
filterStatus: ProjectStatus | '全部' = '全部';
filterPriority: Priority | '全部' = '全部';
filterManager: string = '全部';
searchQuery: string = '';
// 视图模式
viewMode: 'timeline' | 'gantt' | 'list' | 'kanban' = 'timeline';
// 时间范围
timeRange: 'week' | 'month' | 'quarter' | 'year' | 'all' = 'quarter';
// 派生:过滤后的项目
get filteredProjects(): Project[] {
let result = this.projects;
if (this.filterStatus !== '全部') {
result = result.filter(p => p.status === this.filterStatus);
}
if (this.filterPriority !== '全部') {
result = result.filter(p => {
const priorities = p.milestones.map(m => m.priority);
return priorities.includes(this.filterPriority as Priority);
});
}
if (this.filterManager !== '全部') {
result = result.filter(p => p.projectManager === this.filterManager);
}
if (this.searchQuery) {
const q = this.searchQuery.toLowerCase();
result = result.filter(p =>
p.name.toLowerCase().includes(q) ||
p.projectNo.toLowerCase().includes(q) ||
p.projectManager.toLowerCase().includes(q) ||
p.description.toLowerCase().includes(q)
);
}
return result.sort((a, b) => {
if (a.status === ProjectStatus.ACTIVE && b.status !== ProjectStatus.ACTIVE) return -1;
if (a.status !== ProjectStatus.ACTIVE && b.status === ProjectStatus.ACTIVE) return 1;
return a.plannedEnd.getTime() - b.plannedEnd.getTime();
});
}
// 当前项目
get currentProject(): Project | undefined {
return this.projects.find(p => p.id === this.currentProjectId);
}
// 统计
get statistics(): ProjectStats {
return {
totalProjects: this.projects.length,
activeProjects: this.projects.filter(p => p.status === ProjectStatus.ACTIVE).length,
completedProjects: this.projects.filter(p => p.status === ProjectStatus.COMPLETED).length,
delayedProjects: this.projects.filter(p => p.getDelayDays() > 0).length,
atRiskProjects: this.projects.filter(p => p.getCurrentRiskLevel() >= RiskLevel.HIGH).length,
totalBudget: this.projects.reduce((sum, p) => sum + p.budget, 0),
totalCost: this.projects.reduce((sum, p) => sum + p.costIncurred, 0),
avgProgress: this.projects.length > 0
? Math.round(this.projects.reduce((sum, p) => sum + p.getProgress(), 0) / this.projects.length)
: 0
};
}
// 预警列表
get alerts(): ProjectAlert[] {
const alerts: ProjectAlert[] = [];
this.projects.forEach(p => {
// 延期预警
if (p.getDelayDays() > 0) {
alerts.push({
type: 'delay',
level: p.getDelayDays() > 7 ? 'critical' : 'warning',
projectId: p.id,
projectName: p.name,
title: `${p.name} 已延期 ${p.getDelayDays()} 天`,
message: `计划结束: ${p.plannedEnd.toLocaleDateString()},当前进度: ${p.getProgress()}%`,
timestamp: new Date()
});
}
// 风险预警
const riskLevel = p.getCurrentRiskLevel();
if (riskLevel >= RiskLevel.HIGH) {
alerts.push({
type: 'risk',
level: riskLevel === RiskLevel.CRITICAL ? 'critical' : 'warning',
projectId: p.id,
projectName: p.name,
title: `${p.name} ${riskLevel === RiskLevel.CRITICAL ? '极高风险' : '高风险'}`,
message: `SPI: ${p.getSPI().toFixed(2)}, CPI: ${p.getCPI().toFixed(2)}`,
timestamp: new Date()
});
}
// 里程碑延期
p.milestones.forEach(m => {
if (m.status === MilestoneStatus.DELAYED || m.getDelayDays() > 0) {
alerts.push({
type: 'milestone_delay',
level: m.priority === Priority.P0 ? 'critical' : 'warning',
projectId: p.id,
projectName: p.name,
title: `${p.name} - ${m.name} 延期`,
message: `延期 ${m.getDelayDays()} 天,优先级: ${m.priority}`,
timestamp: new Date()
});
}
});
});
return alerts.sort((a, b) => {
const levelOrder = { critical: 0, warning: 1, info: 2 };
return levelOrder[a.level] - levelOrder[b.level];
});
}
// 操作
addProject(project: Project): void {
this.projects.push(project);
this.persist();
}
removeProject(id: string): void {
const idx = this.projects.findIndex(p => p.id === id);
if (idx >= 0) {
this.projects.splice(idx, 1);
this.persist();
}
}
updateProject(id: string, data: Partial<Project>): void {
const idx = this.projects.findIndex(p => p.id === id);
if (idx >= 0) {
const old = this.projects[idx];
this.projects[idx] = new Project({ ...old, ...data, id: old.id });
this.persist();
}
}
// 添加里程碑
addMilestone(projectId: string, milestone: Milestone): void {
const project = this.projects.find(p => p.id === projectId);
if (project) {
project.milestones.push(milestone);
this.persist();
}
}
// 更新里程碑进度
updateMilestoneProgress(projectId: string, milestoneId: string, progress: number, operator: string): void {
const project = this.projects.find(p => p.id === projectId);
if (project) {
const milestone = project.milestones.find(m => m.id === milestoneId);
if (milestone) {
milestone.updateProgress(progress, operator);
this.persist();
}
}
}
// 创建基线
createBaseline(projectId: string, name: string, description: string): void {
const project = this.projects.find(p => p.id === projectId);
if (project) {
project.createBaseline(name, description);
this.persist();
}
}
// 回滚基线
rollbackBaseline(projectId: string, baselineId: string): boolean {
const project = this.projects.find(p => p.id === projectId);
if (project) {
return project.rollbackToBaseline(baselineId);
}
return false;
}
private persist(): void {
AppStorage.setOrCreate('project_projects', JSON.stringify(this.projects));
AppStorage.setOrCreate('project_current_id', this.currentProjectId);
}
load(): void {
const projects = AppStorage.get<string>('project_projects');
if (projects) {
try {
const parsed = JSON.parse(projects);
this.projects = parsed.map((p: any) => new Project(p));
} catch (e) {
console.error('加载项目数据失败', e);
}
}
this.currentProjectId = AppStorage.get<string>('project_current_id') || '';
}
}
// === 统计 ===
export interface ProjectStats {
totalProjects: number;
activeProjects: number;
completedProjects: number;
delayedProjects: number;
atRiskProjects: number;
totalBudget: number;
totalCost: number;
avgProgress: number;
}
// === 预警项 ===
export interface ProjectAlert {
type: 'delay' | 'risk' | 'milestone_delay' | 'budget_overrun' | 'resource_conflict';
level: 'critical' | 'warning' | 'info';
projectId: string;
projectName: string;
title: string;
message: string;
timestamp: Date;
}
// 全局状态
export const projectState = new ProjectState();
AppStorage.setOrCreate('projectState', projectState);
四、主页面实现
4.1 页面入口(entry/src/main/ets/pages/MilestoneTimelinePage.ets)
import { Project, ProjectStatus, Milestone, MilestoneStatus, Priority, RiskLevel, DependencyType, ProjectState, projectState, ProjectStats, ProjectAlert } from '../models/MilestoneModel';
import { ProjectDetailDialog } from '../components/ProjectDetailDialog';
import { MilestoneDialog } from '../components/MilestoneDialog';
import { GanttChartView } from '../components/GanttChartView';
import { TimelineView } from '../components/TimelineView';
import { KanbanView } from '../components/KanbanView';
import { RiskPanel } from '../components/RiskPanel';
import { BaselineDialog } from '../components/BaselineDialog';
import { ProjectDatabase } from '../database/ProjectDatabase';
@Entry
@Component
struct MilestoneTimelinePage {
@StorageLink('projectState') projectState: ProjectState = projectState;
@State private selectedTab: number = 0;
@State private showProjectDialog: boolean = false;
@State private showMilestoneDialog: boolean = false;
@State private showBaselineDialog: boolean = false;
@State private editingProject: Project | null = null;
@State private editingMilestone: Milestone | null = null;
@State private showSearch: boolean = false;
@State private searchText: string = '';
@State private showAlerts: boolean = false;
@State private viewMode: 'timeline' | 'gantt' | 'list' | 'kanban' = 'timeline';
@State private timeRange: 'week' | 'month' | 'quarter' | 'year' | 'all' = 'quarter';
aboutToAppear() {
this.projectState.load();
ProjectDatabase.init();
this.scheduleAlerts();
}
build() {
Column() {
// === 顶部标题栏 ===
this.HeaderBuilder()
// === 预警横幅 ===
if (this.projectState.alerts.length > 0 && !this.showAlerts) {
this.AlertBannerBuilder()
}
// === 预警面板 ===
if (this.showAlerts) {
RiskPanel({
alerts: this.projectState.alerts,
onClose: () => { this.showAlerts = false; }
})
}
// === 统计卡片 ===
this.StatsBuilder()
// === 视图控制栏 ===
this.ViewControlBuilder()
// === 标签切换 ===
this.TabBuilder()
// === 搜索栏 ===
if (this.showSearch) {
this.SearchBuilder()
}
// === 内容区 ===
this.ContentBuilder()
// === 底部操作栏 ===
this.FooterBuilder()
}
.width('100%')
.height('100%')
.backgroundColor('#0a0a0a')
}
4.2 标题栏
// === 标题栏 ===
@Builder
HeaderBuilder() {
Row() {
Text('🐉')
.fontSize(28)
.margin({ right: 8 })
Column() {
Text('龍魂项目管理')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#c41e3a')
Text(`UID:${MASTER_UID} · ${this.projectState.projects.length}个项目`)
.fontSize(12)
.fontColor('#666')
}
.alignItems(HorizontalAlign.Start)
Blank()
// 预警按钮
Badge({
value: this.projectState.alerts.length.toString(),
position: BadgePosition.RightTop,
style: { badgeSize: 18, badgeColor: '#c41e3a' }
}) {
Button() {
Text('🔔')
.fontSize(20)
}
.type(ButtonType.Circle)
.backgroundColor(this.projectState.alerts.length > 0 ? 'rgba(196,30,58,0.2)' : '#1a1a1a')
.width(40)
.height(40)
.onClick(() => {
this.showAlerts = !this.showAlerts;
})
}
// 视图切换
Button() {
Text(
this.viewMode === 'timeline' ? '📊' :
this.viewMode === 'gantt' ? '📈' :
this.viewMode === 'kanban' ? '📋' : '📄'
)
.fontSize(20)
}
.type(ButtonType.Circle)
.backgroundColor('#1a1a1a')
.width(40)
.height(40)
.onClick(() => {
this.toggleViewMode();
})
// 搜索按钮
Button() {
Text(this.showSearch ? '✕' : '🔍')
.fontSize(20)
}
.type(ButtonType.Circle)
.backgroundColor('#1a1a1a')
.width(40)
.height(40)
.onClick(() => {
this.showSearch = !this.showSearch;
if (!this.showSearch) {
this.projectState.searchQuery = '';
}
})
// 添加项目
Button() {
Text('+')
.fontSize(24)
.fontColor('#fff')
}
.type(ButtonType.Circle)
.backgroundColor('#c41e3a')
.width(40)
.height(40)
.onClick(() => {
this.editingProject = null;
this.showProjectDialog = true;
})
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor('#1a1a1a')
.border({ width: { bottom: 1 }, color: '#333' })
}
4.3 预警横幅
// === 预警横幅 ===
@Builder
AlertBannerBuilder() {
Row() {
Text('⚠️')
.fontSize(24)
.margin({ right: 8 })
Column() {
Text(`${this.projectState.alerts.length} 条预警待处理`)
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#ffcc00')
Text(this.getAlertPreview())
.fontSize(12)
.fontColor('#ffcc00')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Button('查看')
.fontSize(12)
.fontColor('#0a0a0a')
.backgroundColor('#ffcc00')
.borderRadius(12)
.padding({ left: 12, right: 12 })
.onClick(() => {
this.showAlerts = true;
})
}
.width('100%')
.padding(12)
.backgroundColor('rgba(255,204,0,0.1)')
.border({ width: { bottom: 1 }, color: 'rgba(255,204,0,0.3)' })
}
4.4 统计卡片
// === 统计卡片 ===
@Builder
StatsBuilder() {
Row() {
this.StatCard('项目总数', this.projectState.statistics.totalProjects.toString(), '#fff')
this.StatCard('进行中', this.projectState.statistics.activeProjects.toString(), '#00ff00')
this.StatCard('已完成', this.projectState.statistics.completedProjects.toString(), '#0066cc')
this.StatCard('延期', this.projectState.statistics.delayedProjects.toString(), '#ffcc00')
this.StatCard('风险', this.projectState.statistics.atRiskProjects.toString(), '#c41e3a')
}
.width('100%')
.height(80)
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.backgroundColor('#1a1a1a')
.border({ width: { bottom: 1 }, color: '#333' })
}
// === 统计卡片项 ===
@Builder
StatCard(label: string, value: string, color: string) {
Column() {
Text(value)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor(color)
Text(label)
.fontSize(11)
.fontColor('#666')
.margin({ top: 4 })
}
.width('20%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
4.5 视图控制栏
// === 视图控制栏 ===
@Builder
ViewControlBuilder() {
Row() {
// 时间范围选择
Row() {
ForEach(['week', 'month', 'quarter', 'year', 'all'], (range: string) => {
Button() {
Text(
range === 'week' ? '周' :
range === 'month' ? '月' :
range === 'quarter' ? '季' :
range === 'year' ? '年' : '全部'
)
.fontSize(12)
.fontColor(this.timeRange === range ? '#0a0a0a' : '#999')
}
.type(ButtonType.Normal)
.backgroundColor(this.timeRange === range ? '#c41e3a' : '#1a1a1a')
.borderRadius(8)
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.margin({ right: 4 })
.onClick(() => {
this.timeRange = range as 'week' | 'month' | 'quarter' | 'year' | 'all';
})
})
}
.layoutWeight(1)
Blank()
// 视图模式切换
Row() {
ForEach(['timeline', 'gantt', 'kanban', 'list'], (mode: string) => {
Button() {
Text(
mode === 'timeline' ? '时间线' :
mode === 'gantt' ? '甘特图' :
mode === 'kanban' ? '看板' : '列表'
)
.fontSize(12)
.fontColor(this.viewMode === mode ? '#0a0a0a' : '#999')
}
.type(ButtonType.Normal)
.backgroundColor(this.viewMode === mode ? '#c41e3a' : '#1a1a1a')
.borderRadius(8)
.padding({ left: 12, right: 12, top: 4, bottom: 4 })
.margin({ left: 4 })
.onClick(() => {
this.viewMode = mode as 'timeline' | 'gantt' | 'kanban' | 'list';
})
})
}
}
.width('100%')
.height(48)
.padding({ left: 12, right: 12 })
.backgroundColor('#1a1a1a')
.border({ width: { bottom: 1 }, color: '#333' })
}
4.6 标签切换
// === 标签切换 ===
@Builder
TabBuilder() {
Row() {
ForEach(['全部项目', '进行中', '已延期', '高风险'], (tab: string, index: number) => {
Column() {
Text(tab)
.fontSize(14)
.fontWeight(this.selectedTab === index ? FontWeight.Bold : FontWeight.Normal)
.fontColor(this.selectedTab === index ? '#c41e3a' : '#666')
if (this.selectedTab === index) {
Divider()
.width(24)
.height(2)
.color('#c41e3a')
.margin({ top: 4 })
}
}
.width('25%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.onClick(() => {
this.selectedTab = index;
})
})
}
.width('100%')
.height(44)
.backgroundColor('#1a1a1a')
.border({ width: { bottom: 1 }, color: '#333' })
}
4.7 搜索栏
// === 搜索栏 ===
@Builder
SearchBuilder() {
Row() {
TextInput({ placeholder: '搜索项目编号、名称、负责人...' })
.width('100%')
.height(40)
.backgroundColor('#262626')
.fontColor('#fff')
.placeholderColor('#666')
.borderRadius(8)
.padding({ left: 12, right: 12 })
.onChange((value: string) => {
this.projectState.searchQuery = value;
})
}
.width('100%')
.height(56)
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.backgroundColor('#1a1a1a')
}
4.8 内容区(四种视图切换)
// === 内容区 ===
@Builder
ContentBuilder() {
List() {
if (this.viewMode === 'timeline') {
TimelineView({
projects: this.projectState.filteredProjects,
timeRange: this.timeRange,
onProjectSelect: (project: Project) => {
this.editingProject = project;
this.showProjectDialog = true;
},
onMilestoneSelect: (projectId: string, milestone: Milestone) => {
this.editingMilestone = milestone;
this.showMilestoneDialog = true;
}
})
} else if (this.viewMode === 'gantt') {
GanttChartView({
projects: this.projectState.filteredProjects,
timeRange: this.timeRange,
onProjectSelect: (project: Project) => {
this.editingProject = project;
this.showProjectDialog = true;
}
})
} else if (this.viewMode === 'kanban') {
KanbanView({
projects: this.projectState.filteredProjects,
onProjectSelect: (project: Project) => {
this.editingProject = project;
this.showProjectDialog = true;
},
onMilestoneUpdate: (projectId: string, milestoneId: string, progress: number) => {
this.projectState.updateMilestoneProgress(projectId, milestoneId, progress, MASTER_UID);
}
})
} else {
// 列表视图
ForEach(this.projectState.filteredProjects, (project: Project) => {
this.ProjectListItem(project)
})
}
}
.width('100%')
.layoutWeight(1)
.backgroundColor('#0a0a0a')
.edgeEffect(EdgeEffect.Spring)
.scrollBar(BarState.Auto)
}
4.9 项目列表项
// === 项目列表项 ===
@Builder
ProjectListItem(project: Project) {
ListItem() {
Column() {
Row() {
Column() {
Text(project.name)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#fff')
Text(`${project.projectNo} · ${project.projectManager}`)
.fontSize(12)
.fontColor('#666')
.margin({ top: 2 })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
// 状态标签
Text(project.status)
.fontSize(11)
.fontColor(this.getStatusColor(project.status))
.backgroundColor(this.getStatusBgColor(project.status))
.borderRadius(4)
.padding({ left: 8, right: 8, top: 2, bottom: 2 })
}
.width('100%')
// 进度条
Row() {
Stack() {
Row()
.width('100%')
.height(6)
.backgroundColor('#333')
.borderRadius(3)
Row()
.width(`${project.getProgress()}%`)
.height(6)
.backgroundColor(this.getProgressColor(project.getProgress()))
.borderRadius(3)
}
.width('100%')
.height(6)
.margin({ top: 8, bottom: 4 })
Text(`${project.getProgress()}%`)
.fontSize(11)
.fontColor('#999')
.margin({ left: 8 })
}
.width('100%')
// 底部信息
Row() {
Text(`计划: ${project.plannedStart.toLocaleDateString()} - ${project.plannedEnd.toLocaleDateString()}`)
.fontSize(11)
.fontColor('#666')
Blank()
if (project.getDelayDays() > 0) {
Text(`延期 ${project.getDelayDays()} 天`)
.fontSize(11)
.fontColor('#ffcc00')
}
if (project.getCurrentRiskLevel() >= RiskLevel.HIGH) {
Text('⚠️')
.fontSize(14)
.margin({ left: 8 })
}
}
.width('100%')
.margin({ top: 4 })
}
.width('100%')
.padding(12)
.backgroundColor('#1a1a1a')
.borderRadius(8)
.margin({ top: 8, left: 12, right: 12 })
.onClick(() => {
this.editingProject = project;
this.showProjectDialog = true;
})
}
}
4.10 底部操作栏
// === 底部操作栏 ===
@Builder
FooterBuilder() {
Row() {
// DNA标识
Column() {
Text('🐉')
.fontSize(20)
Text(`UID:${MASTER_UID}`)
.fontSize(10)
.fontColor('#666')
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
// 操作按钮组
Row() {
Button() {
Text('📊 基线')
.fontSize(12)
.fontColor('#fff')
}
.type(ButtonType.Normal)
.backgroundColor('#333')
.borderRadius(8)
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.margin({ right: 8 })
.onClick(() => {
this.showBaselineDialog = true;
})
Button() {
Text('📤 导出')
.fontSize(12)
.fontColor('#fff')
}
.type(ButtonType.Normal)
.backgroundColor('#333')
.borderRadius(8)
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.margin({ right: 8 })
.onClick(() => {
this.exportData();
})
Button() {
Text('➕ 里程碑')
.fontSize(12)
.fontColor('#fff')
}
.type(ButtonType.Normal)
.backgroundColor('#c41e3a')
.borderRadius(8)
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.onClick(() => {
if (this.projectState.currentProject) {
this.editingMilestone = null;
this.showMilestoneDialog = true;
}
})
}
}
.width('100%')
.height(56)
.padding({ left: 16, right: 16 })
.backgroundColor('#1a1a1a')
.border({ width: { top: 1 }, color: '#333' })
}
4.11 辅助方法
// === 预警预览摘要 ===
getAlertPreview(): string {
const critical = this.projectState.alerts.filter(a => a.level === 'critical');
if (critical.length > 0) {
return `${critical.length} 条严重预警需立即处理`;
}
return '点击查看详情';
}
// === 视图模式切换 ===
toggleViewMode(): void {
const modes: ('timeline' | 'gantt' | 'list' | 'kanban')[] = ['timeline', 'gantt', 'kanban', 'list'];
const currentIndex = modes.indexOf(this.viewMode);
this.viewMode = modes[(currentIndex + 1) % modes.length];
}
// === 状态颜色 ===
getStatusColor(status: ProjectStatus): string {
switch (status) {
case ProjectStatus.ACTIVE: return '#00ff00';
case ProjectStatus.COMPLETED: return '#0066cc';
case ProjectStatus.PLANNING: return '#999';
case ProjectStatus.PAUSED: return '#ffcc00';
case ProjectStatus.CANCELLED: return '#666';
case ProjectStatus.ARCHIVED: return '#444';
default: return '#999';
}
}
getStatusBgColor(status: ProjectStatus): string {
switch (status) {
case ProjectStatus.ACTIVE: return 'rgba(0,255,0,0.1)';
case ProjectStatus.COMPLETED: return 'rgba(0,102,204,0.1)';
case ProjectStatus.PLANNING: return 'rgba(153,153,153,0.1)';
case ProjectStatus.PAUSED: return 'rgba(255,204,0,0.1)';
case ProjectStatus.CANCELLED: return 'rgba(102,102,102,0.1)';
case ProjectStatus.ARCHIVED: return 'rgba(68,68,68,0.1)';
default: return 'rgba(153,153,153,0.1)';
}
}
// === 进度颜色 ===
getProgressColor(progress: number): string {
if (progress >= 100) return '#0066cc';
if (progress >= 75) return '#00ff00';
if (progress >= 50) return '#ffcc00';
if (progress >= 25) return '#ff6600';
return '#c41e3a';
}
// === 数据导出 ===
exportData(): void {
const data = {
exportTime: new Date().toISOString(),
dna: MASTER_DNA,
uid: MASTER_UID,
confirm: CONFIRM_SEAL,
projects: this.projectState.projects.map(p => ({
id: p.id,
name: p.name,
status: p.status,
progress: p.getProgress(),
spi: p.getSPI(),
cpi: p.getCPI(),
delayDays: p.getDelayDays(),
riskLevel: p.getCurrentRiskLevel(),
milestones: p.milestones.length
}))
};
const fileName = `longhun_export_${Date.now()}.json`;
console.info(`[龍魂] 数据导出: ${fileName}`);
console.info(`[龍魂] 导出内容: ${JSON.stringify(data, null, 2)}`);
}
// === 预警调度 ===
scheduleAlerts(): void {
console.info('[龍魂] 预警调度系统已启动');
}
}
五、组件清单
| 文件 | 路径 | 说明 |
|---|---|---|
| 数据模型 | entry/src/main/ets/models/MilestoneModel.ets |
Project/Milestone/Risk/ProjectState |
| 主页面 | entry/src/main/ets/pages/MilestoneTimelinePage.ets |
完整UI |
| 项目详情 | entry/src/main/ets/components/ProjectDetailDialog.ets |
增改项目 |
| 里程碑弹窗 | entry/src/main/ets/components/MilestoneDialog.ets |
里程碑编辑 |
| 甘特图 | entry/src/main/ets/components/GanttChartView.ets |
横向时间轴视图 |
| 时间线 | entry/src/main/ets/components/TimelineView.ets |
纵向瀑布流视图 |
| 看板 | entry/src/main/ets/components/KanbanView.ets |
拖拽状态分栏 |
| 风险面板 | entry/src/main/ets/components/RiskPanel.ets |
预警列表 |
| 基线弹窗 | entry/src/main/ets/components/BaselineDialog.ets |
基线管理 |
| 数据库 | entry/src/main/ets/database/ProjectDatabase.ets |
关系型存储 |
六、鸿蒙特性使用
| 特性 | 用途 | API |
|---|---|---|
| ArkTS声明式UI | 界面构建 | @Component @Entry |
| 状态管理 | 数据响应 | @State @Observed @StorageLink |
| 关系型数据库 | 本地加密存储 | relationalStore |
| 通知 | 预警提醒 | notificationManager |
| 日历 | 里程碑同步 | calendarManager |
| 后台任务 | 定时预警检查 | workScheduler |
| 打印 | 报表输出 | print |
| 分享 | 数据导出 | share |
| 国密算法 | 数据签名 | cryptoFramework SM2/SM3 |
七、项目管理核心指标
| 指标 | 计算公式 | 说明 |
|---|---|---|
| SPI | EV / PV | 进度绩效指数,>1 超前,<1 滞后 |
| CPI | EV / AC | 成本绩效指数,>1 节余,<1 超支 |
| 挣值 EV | Budget × (Progress / 100) | 已完成工作的预算价值 |
| 计划价值 PV | Budget × (Elapsed / TotalDuration) | 计划完成工作的预算价值 |
| 风险值 | Probability × Impact | 0-1区间,越高越危险 |
| 延期天数 | ActualEnd - PlannedEnd | 负数表示提前 |
八、龍魂标识
| 位置 | 内容 |
|---|---|
| 应用名称 | 龍魂项目管理 |
| 标题栏 | 🐉 龍魂项目管理 |
| 底部标识 | UID:9622 |
| 数据签名 | SM3-哈希 |
| DNA | ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️ |
🐉 龍魂 · 鸿蒙 ArkTS 实战:Project Milestone Timeline 交付完成
DNA: ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼♀️❤️♾️
UID: 9622
确认码: #CONFIRM🌌9622-ONLY-ONCE🧬LK9X-772Z
时间: 2026-07-14
模块: 10核心文件
特性: 项目建模 · 里程碑追踪 · 甘特图 · 时间线 · 看板 · 风险预警 · 挣值分析 · 基线管理 · 国密签名
‘’’
保存文件
output_path = ‘/mnt/agents/output/龍魂_鸿蒙ArkTS_项目里程碑时间线_CSDN博客.md’
with open(output_path, ‘w’, encoding=‘utf-8’) as f:
f.write(article)
print(f"文件已保存: {output_path}“)
print(f"总长度: {len(article):,} 字符”)
更多推荐


所有评论(0)