龍魂 · 鸿蒙 ArkTS 实战:Weekly Review 周报管理

龍魂系统 · 鸿蒙原生适配层 · 周报生成与审批追踪

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 → WeeklyReviewPage         │
│  ├── 周报模板建模(AppStorage/LocalStorage)│
│  ├── 任务条目录入(分类·优先级·工时)       │
│  ├── 自动汇总引擎(进度·工时·完成率)        │
│  ├── 审批流转链(提交→初审→终审→归档)       │
│  ├── 历史周报库(版本对比·趋势分析)         │
│  ├── 工时统计看板(个人·团队·项目维度)      │
│  └── 办公交互(导出PDF·分享·打印·日历提醒)   │
├─────────────────────────────────────────┤
│         鸿蒙系统能力层                      │
│                                         │
│  日历(Calendar) · 通知(Notification)      │
│  数据存储(RelationalStore) · 文件(File)    │
│  网络(Http) · 分享(Share) · 打印(Print)   │
│  后台任务(WorkScheduler) · 定位(Location) │
│  文档(DocumentPicker) · 相机(Camera)      │
└─────────────────────────────────────────┘

三、状态建模核心

3.1 数据模型(entry/src/main/ets/models/WeeklyModel.ets

// entry/src/main/ets/models/WeeklyModel.ets
// 龍魂 · 周报管理模型 · ArkTS

// === DNA常量 ===
const MASTER_DNA = "ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼‍♀️❤️♾️";
const MASTER_UID = "9622";
const CONFIRM_SEAL = "#CONFIRM🌌9622-ONLY-ONCE🧬LK9X-772Z";

// === 周报状态 ===
export enum WeeklyStatus {
  DRAFT = '草稿',           // 编辑中
  SUBMITTED = '已提交',      // 待初审
  FIRST_REVIEW = '初审中',   // 部门主管审核
  FINAL_REVIEW = '终审中',   // 分管领导审核
  APPROVED = '已通过',       // 审批完成
  REJECTED = '已驳回',       // 被驳回
  ARCHIVED = '已归档'        // 历史归档
}

// === 任务状态 ===
export enum TaskStatus {
  NOT_STARTED = '未开始',
  IN_PROGRESS = '进行中',
  COMPLETED = '已完成',
  BLOCKED = '被阻塞',
  DELAYED = '已延期',
  CANCELLED = '已取消'
}

// === 任务类型 ===
export enum TaskType {
  DEVELOPMENT = '开发',
  DESIGN = '设计',
  TEST = '测试',
  MEETING = '会议',
  DOCUMENT = '文档',
  RESEARCH = '调研',
  BUGFIX = 'Bug修复',
  OPTIMIZATION = '优化',
  OTHER = '其他'
}

// === 优先级 ===
export enum Priority {
  P0 = 'P0-紧急',
  P1 = 'P1-高',
  P2 = 'P2-中',
  P3 = 'P3-低'
}

// === 工时类型 ===
export enum HourType {
  PLANNED = '计划工时',
  ACTUAL = '实际工时',
  OVERTIME = '加班工时'
}

// === 周报档案 ===
export class WeeklyReport {
  id: string;                // 唯一ID
  reportNo: string;           // 周报编号
  weekStart: Date;           // 周起始日
  weekEnd: Date;             // 周结束日
  status: WeeklyStatus;       // 状态

  // 填报人
  reporter: string;           // 填报人
  reporterId: string;        // 填报人ID
  department: string;        // 部门
  position: string;          // 职位

  // 任务条目
  tasks: WeeklyTask[];       // 本周任务
  nextTasks: NextTask[];     // 下周计划

  // 汇总数据
  totalPlannedHours: number;   // 计划总工时
  totalActualHours: number;   // 实际总工时
  totalOvertimeHours: number;  // 加班总工时
  completionRate: number;     // 完成率

  // 问题与风险
  issues: WeeklyIssue[];     // 本周问题
  risks: WeeklyRisk[];       // 风险项

  // 审批链
  approvals: ApprovalRecord[]; // 审批记录

  // 总结
  summary: string;            // 本周总结
  nextPlan: string;           // 下周计划
  needSupport: string;        // 需要支持

  // 审计
  createdAt: Date;
  updatedAt: Date;
  submittedAt?: Date;
  approvedAt?: Date;
  dnaSignature: string;

  constructor(data: Partial<WeeklyReport>) {
    this.id = data.id || this.generateId();
    this.reportNo = data.reportNo || this.generateReportNo();
    this.weekStart = data.weekStart || this.getWeekStart();
    this.weekEnd = data.weekEnd || this.getWeekEnd();
    this.status = data.status || WeeklyStatus.DRAFT;

    this.reporter = data.reporter || '';
    this.reporterId = data.reporterId || '';
    this.department = data.department || '';
    this.position = data.position || '';

    this.tasks = data.tasks || [];
    this.nextTasks = data.nextTasks || [];

    this.totalPlannedHours = data.totalPlannedHours || 0;
    this.totalActualHours = data.totalActualHours || 0;
    this.totalOvertimeHours = data.totalOvertimeHours || 0;
    this.completionRate = data.completionRate || 0;

    this.issues = data.issues || [];
    this.risks = data.risks || [];
    this.approvals = data.approvals || [];

    this.summary = data.summary || '';
    this.nextPlan = data.nextPlan || '';
    this.needSupport = data.needSupport || '';

    this.createdAt = data.createdAt || new Date();
    this.updatedAt = data.updatedAt || new Date();
    this.submittedAt = data.submittedAt;
    this.approvedAt = data.approvedAt;
    this.dnaSignature = this.signData();
  }

  private generateId(): string {
    return `WR-${MASTER_UID}-${Date.now().toString(36).substr(-6)}`;
  }

  private generateReportNo(): string {
    const date = new Date();
    const weekNum = this.getWeekNumber(date);
    return `ZB${date.getFullYear()}W${weekNum.toString().padStart(2,'0')}-${Math.floor(Math.random()*999).toString().padStart(3,'0')}`;
  }

  private getWeekStart(): Date {
    const d = new Date();
    const day = d.getDay();
    const diff = d.getDate() - day + (day === 0 ? -6 : 1);
    return new Date(d.setDate(diff));
  }

  private getWeekEnd(): Date {
    const start = this.getWeekStart();
    return new Date(start.getTime() + 6 * 24 * 60 * 60 * 1000);
  }

  private getWeekNumber(date: Date): number {
    const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
    const dayNum = d.getUTCDay() || 7;
    d.setUTCDate(d.getUTCDate() + 4 - dayNum);
    const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
    return Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
  }

  private signData(): string {
    const payload = `${this.id}-${this.reportNo}-${this.reporter}-${this.status}`;
    return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
  }

  // 自动汇总计算
  recalculate(): void {
    this.totalPlannedHours = this.tasks.reduce((sum, t) => sum + t.plannedHours, 0);
    this.totalActualHours = this.tasks.reduce((sum, t) => sum + t.actualHours, 0);
    this.totalOvertimeHours = this.tasks.reduce((sum, t) => sum + (t.overtimeHours || 0), 0);

    const completed = this.tasks.filter(t => t.status === TaskStatus.COMPLETED).length;
    this.completionRate = this.tasks.length > 0 ? Math.round((completed / this.tasks.length) * 100) : 0;

    this.updatedAt = new Date();
    this.dnaSignature = this.signData();
  }

  // 提交审批
  submit(): void {
    this.status = WeeklyStatus.SUBMITTED;
    this.submittedAt = new Date();
    this.updatedAt = new Date();
    this.dnaSignature = this.signData();
  }

  // 审批通过
  approve(level: number, approver: string, comment: string, signature: string): void {
    this.approvals.push({
      level,
      approver,
      comment,
      signature,
      timestamp: new Date(),
      dnaSignature: this.signApproval(level, approver, signature)
    });

    if (level === 1) this.status = WeeklyStatus.FIRST_REVIEW;
    else if (level === 2) {
      this.status = WeeklyStatus.APPROVED;
      this.approvedAt = new Date();
    }

    this.updatedAt = new Date();
    this.dnaSignature = this.signData();
  }

  // 驳回
  reject(approver: string, comment: string): void {
    this.status = WeeklyStatus.REJECTED;
    this.approvals.push({
      level: this.getCurrentLevel(),
      approver,
      comment,
      signature: 'REJECTED',
      timestamp: new Date(),
      dnaSignature: this.signApproval(this.getCurrentLevel(), approver, 'REJECT')
    });
    this.updatedAt = new Date();
    this.dnaSignature = this.signData();
  }

  // 归档
  archive(): void {
    this.status = WeeklyStatus.ARCHIVED;
    this.updatedAt = new Date();
    this.dnaSignature = this.signData();
  }

  private getCurrentLevel(): number {
    return this.approvals.length + 1;
  }

  private signApproval(level: number, approver: string, signature: string): string {
    const payload = `${this.id}-L${level}-${approver}-${signature}-${Date.now()}`;
    return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
  }

  // 获取审批进度
  getApprovalProgress(): { current: number; total: number; percentage: number } {
    const total = 2; // 两级审批
    const current = this.approvals.filter(a => a.signature !== 'REJECTED').length;
    return { current, total, percentage: Math.round((current / total) * 100) };
  }

  // 检查是否可编辑
  isEditable(): boolean {
    return this.status === WeeklyStatus.DRAFT || this.status === WeeklyStatus.REJECTED;
  }

  // 检查是否可提交
  isSubmittable(): boolean {
    return this.tasks.length > 0 && this.isEditable();
  }
}

3.2 周任务条目

// === 周任务条目 ===
export class WeeklyTask {
  id: string;
  projectId?: string;       // 关联项目ID
  projectName: string;         // 关联项目名称
  taskType: TaskType;        // 任务类型
  priority: Priority;         // 优先级
  status: TaskStatus;        // 状态

  // 内容
  title: string;             // 任务标题
  description: string;       // 任务描述

  // 工时
  plannedHours: number;      // 计划工时
  actualHours: number;        // 实际工时
  overtimeHours: number;     // 加班工时

  // 进度
  progress: number;           // 完成进度 0-100

  // 时间
  plannedStart: Date;
  plannedEnd: Date;
  actualStart?: Date;
  actualEnd?: Date;

  // 关联
  milestoneId?: string;       // 关联里程碑
  deliverables: string[];     // 交付物路径

  // 审计
  createdAt: Date;
  updatedAt: Date;
  dnaSignature: string;

  constructor(data: Partial<WeeklyTask>) {
    this.id = data.id || `WT-${Date.now()}-${Math.random().toString(36).substr(2,6)}`;
    this.projectId = data.projectId;
    this.projectName = data.projectName || '';
    this.taskType = data.taskType || TaskType.OTHER;
    this.priority = data.priority || Priority.P2;
    this.status = data.status || TaskStatus.NOT_STARTED;

    this.title = data.title || '';
    this.description = data.description || '';

    this.plannedHours = data.plannedHours || 0;
    this.actualHours = data.actualHours || 0;
    this.overtimeHours = data.overtimeHours || 0;
    this.progress = data.progress || 0;

    this.plannedStart = data.plannedStart || new Date();
    this.plannedEnd = data.plannedEnd || new Date();
    this.actualStart = data.actualStart;
    this.actualEnd = data.actualEnd;

    this.milestoneId = data.milestoneId;
    this.deliverables = data.deliverables || [];

    this.createdAt = data.createdAt || new Date();
    this.updatedAt = data.updatedAt || new Date();
    this.dnaSignature = this.signData();
  }

  private signData(): string {
    const payload = `${this.id}-${this.title}-${this.status}-${this.progress}`;
    return `SM3-${payload.split('').reduce((a,b)=>a+b.charCodeAt(0),0).toString(16).substring(0,16)}`;
  }

  // 更新进度
  updateProgress(progress: number): void {
    this.progress = Math.min(100, Math.max(0, progress));
    if (this.progress > 0 && this.status === TaskStatus.NOT_STARTED) {
      this.status = TaskStatus.IN_PROGRESS;
      this.actualStart = this.actualStart || new Date();
    }
    if (this.progress === 100) {
      this.status = TaskStatus.COMPLETED;
      this.actualEnd = new Date();
    }
    this.updatedAt = new Date();
    this.dnaSignature = this.signData();
  }

  // 计算工时偏差
  getHourVariance(): number {
    return this.actualHours - this.plannedHours;
  }

  // 是否延期
  isDelayed(): boolean {
    if (this.actualEnd) {
      return this.actualEnd > this.plannedEnd;
    }
    return new Date() > this.plannedEnd && this.status !== TaskStatus.COMPLETED;
  }
}

3.3 下周计划

// === 下周计划条目 ===
export class NextTask {
  id: string;
  projectId?: string;
  projectName: string;
  taskType: TaskType;
  priority: Priority;
  title: string;
  description: string;
  plannedHours: number;
  plannedStart: Date;
  plannedEnd: Date;
  dependencies: string[];      // 依赖任务ID
  dnaSignature: string;

  constructor(data: Partial<NextTask>) {
    this.id = data.id || `NT-${Date.now()}-${Math.random().toString(36).substr(2,6)}`;
    this.projectId = data.projectId;
    this.projectName = data.projectName || '';
    this.taskType = data.taskType || TaskType.OTHER;
    this.priority = data.priority || Priority.P2;
    this.title = data.title || '';
    this.description = data.description || '';
    this.plannedHours = data.plannedHours || 0;
    this.plannedStart = data.plannedStart || new Date();
    this.plannedEnd = data.plannedEnd || new Date();
    this.dependencies = data.dependencies || [];
    this.dnaSignature = this.signData();
  }

  private signData(): string {
    return `SM3-${this.id}-${this.title}-${Date.now()}`;
  }
}

3.4 问题与风险

// === 本周问题 ===
export class WeeklyIssue {
  id: string;
  title: string;
  description: string;
  severity: 'low' | 'medium' | 'high' | 'critical';
  status: 'open' | 'resolved' | 'pending';
  relatedTaskId?: string;
  solution?: string;
  resolver?: string;
  resolvedAt?: Date;
  dnaSignature: string;

  constructor(data: Partial<WeeklyIssue>) {
    this.id = data.id || `ISSUE-${Date.now()}-${Math.random().toString(36).substr(2,6)}`;
    this.title = data.title || '';
    this.description = data.description || '';
    this.severity = data.severity || 'medium';
    this.status = data.status || 'open';
    this.relatedTaskId = data.relatedTaskId;
    this.solution = data.solution;
    this.resolver = data.resolver;
    this.resolvedAt = data.resolvedAt;
    this.dnaSignature = this.signData();
  }

  private signData(): string {
    return `SM3-${this.id}-${this.status}-${Date.now()}`;
  }
}

// === 风险项 ===
export class WeeklyRisk {
  id: string;
  title: string;
  description: string;
  probability: number;  // 0-1
  impact: number;       // 0-1
  mitigation: string;   // 缓解措施
  owner: string;
  status: 'open' | 'mitigated' | 'realized';
  dnaSignature: string;

  constructor(data: Partial<WeeklyRisk>) {
    this.id = data.id || `WRISK-${Date.now()}-${Math.random().toString(36).substr(2,6)}`;
    this.title = data.title || '';
    this.description = data.description || '';
    this.probability = data.probability || 0.5;
    this.impact = data.impact || 0.5;
    this.mitigation = data.mitigation || '';
    this.owner = data.owner || '';
    this.status = data.status || 'open';
    this.dnaSignature = this.signData();
  }

  private signData(): string {
    return `SM3-${this.id}-${this.status}-${Date.now()}`;
  }

  getRiskScore(): number {
    return this.probability * this.impact;
  }
}

3.5 审批记录与模板

// === 审批记录 ===
export interface ApprovalRecord {
  level: number;              // 1=初审 2=终审
  approver: string;          // 审批人
  approverId: string;        // 审批人ID
  comment: string;           // 审批意见
  signature: string;         // 电子签名
  timestamp: Date;
  dnaSignature: string;
}

// === 周报模板 ===
export class WeeklyTemplate {
  id: string;
  name: string;              // 模板名称
  department: string;       // 适用部门
  sections: TemplateSection[]; // 模板区块
  isDefault: boolean;        // 是否默认
  createdAt: Date;
  dnaSignature: string;

  constructor(data: Partial<WeeklyTemplate>) {
    this.id = data.id || `TMPL-${Date.now()}`;
    this.name = data.name || '默认模板';
    this.department = data.department || '全部';
    this.sections = data.sections || this.getDefaultSections();
    this.isDefault = data.isDefault || false;
    this.createdAt = data.createdAt || new Date();
    this.dnaSignature = this.signData();
  }

  private getDefaultSections(): TemplateSection[] {
    return [
      { id: 's1', title: '本周任务', type: 'tasks', required: true },
      { id: 's2', title: '下周计划', type: 'next_tasks', required: true },
      { id: 's3', title: '问题与风险', type: 'issues', required: false },
      { id: 's4', title: '本周总结', type: 'summary', required: true },
      { id: 's5', title: '需要支持', type: 'support', required: false }
    ];
  }

  private signData(): string {
    return `SM3-${this.id}-${this.name}-${Date.now()}`;
  }
}

export interface TemplateSection {
  id: string;
  title: string;
  type: string;
  required: boolean;
}

3.6 全局状态

// === 周报全局状态 ===
@Observed
export class WeeklyState {
  reports: WeeklyReport[] = [];
  templates: WeeklyTemplate[] = [];
  currentReportId: string = '';

  // 当前用户
  currentUser: string = '';
  currentUserId: string = '';
  currentDept: string = '';
  userRole: 'reporter' | 'reviewer' | 'admin' = 'reporter';

  // 过滤
  filterStatus: WeeklyStatus | '全部' = '全部';
  filterDept: string = '全部';
  filterWeek: string = '';
  searchQuery: string = '';

  // 派生:过滤后的周报
  get filteredReports(): WeeklyReport[] {
    let result = this.reports;

    if (this.filterStatus !== '全部') {
      result = result.filter(r => r.status === this.filterStatus);
    }

    if (this.filterDept !== '全部') {
      result = result.filter(r => r.department === this.filterDept);
    }

    if (this.filterWeek) {
      result = result.filter(r => r.reportNo.includes(this.filterWeek));
    }

    if (this.searchQuery) {
      const q = this.searchQuery.toLowerCase();
      result = result.filter(r =>
        r.reporter.toLowerCase().includes(q) ||
        r.reportNo.toLowerCase().includes(q) ||
        r.department.toLowerCase().includes(q)
      );
    }

    return result.sort((a, b) => b.weekStart.getTime() - a.weekStart.getTime());
  }

  // 我的周报
  get myReports(): WeeklyReport[] {
    return this.reports
      .filter(r => r.reporterId === this.currentUserId)
      .sort((a, b) => b.weekStart.getTime() - a.weekStart.getTime());
  }

  // 待审批(初审)
  get pendingFirstReview(): WeeklyReport[] {
    return this.reports.filter(r => r.status === WeeklyStatus.SUBMITTED);
  }

  // 待审批(终审)
  get pendingFinalReview(): WeeklyReport[] {
    return this.reports.filter(r => r.status === WeeklyStatus.FIRST_REVIEW);
  }

  // 本周待填
  get currentWeekDraft(): WeeklyReport | undefined {
    const now = new Date();
    return this.reports.find(r =>
      r.reporterId === this.currentUserId &&
      r.weekStart <= now && r.weekEnd >= now &&
      r.status === WeeklyStatus.DRAFT
    );
  }

  // 统计
  get statistics(): WeeklyStats {
    const myList = this.myReports;
    const thisWeek = myList.filter(r => {
      const now = new Date();
      return r.weekStart <= now && r.weekEnd >= now;
    });

    return {
      totalReports: this.reports.length,
      myTotal: myList.length,
      myDraft: myList.filter(r => r.status === WeeklyStatus.DRAFT).length,
      mySubmitted: myList.filter(r => r.status === WeeklyStatus.SUBMITTED).length,
      myApproved: myList.filter(r => r.status === WeeklyStatus.APPROVED).length,
      myRejected: myList.filter(r => r.status === WeeklyStatus.REJECTED).length,
      pendingReview: this.pendingFirstReview.length + this.pendingFinalReview.length,
      avgCompletion: myList.length > 0
        ? Math.round(myList.reduce((sum, r) => sum + r.completionRate, 0) / myList.length)
        : 0,
      totalHours: myList.reduce((sum, r) => sum + r.totalActualHours, 0),
      thisWeekHours: thisWeek.reduce((sum, r) => sum + r.totalActualHours, 0)
    };
  }

  // 工时趋势(最近8周)
  get hourTrend(): { week: string; planned: number; actual: number; overtime: number }[] {
    const trend: { week: string; planned: number; actual: number; overtime: number }[] = [];
    const myList = this.myReports.slice(0, 8);

    myList.forEach(r => {
      trend.push({
        week: `W${this.getWeekNumber(r.weekStart)}`,
        planned: r.totalPlannedHours,
        actual: r.totalActualHours,
        overtime: r.totalOvertimeHours
      });
    });

    return trend.reverse();
  }

  // 操作
  addReport(report: WeeklyReport): void {
    this.reports.push(report);
    this.persist();
  }

  removeReport(id: string): void {
    const idx = this.reports.findIndex(r => r.id === id);
    if (idx >= 0) {
      this.reports.splice(idx, 1);
      this.persist();
    }
  }

  updateReport(id: string, data: Partial<WeeklyReport>): void {
    const idx = this.reports.findIndex(r => r.id === id);
    if (idx >= 0) {
      const old = this.reports[idx];
      this.reports[idx] = new WeeklyReport({ ...old, ...data, id: old.id });
      this.persist();
    }
  }

  // 添加任务
  addTask(reportId: string, task: WeeklyTask): void {
    const report = this.reports.find(r => r.id === reportId);
    if (report) {
      report.tasks.push(task);
      report.recalculate();
      this.persist();
    }
  }

  // 更新任务进度
  updateTaskProgress(reportId: string, taskId: string, progress: number): void {
    const report = this.reports.find(r => r.id === reportId);
    if (report) {
      const task = report.tasks.find(t => t.id === taskId);
      if (task) {
        task.updateProgress(progress);
        report.recalculate();
        this.persist();
      }
    }
  }

  // 提交周报
  submitReport(reportId: string): void {
    const report = this.reports.find(r => r.id === reportId);
    if (report && report.isSubmittable()) {
      report.submit();
      this.persist();
    }
  }

  // 审批
  approveReport(reportId: string, level: number, approver: string, comment: string, signature: string): void {
    const report = this.reports.find(r => r.id === reportId);
    if (report) {
      report.approve(level, approver, comment, signature);
      this.persist();
    }
  }

  // 驳回
  rejectReport(reportId: string, approver: string, comment: string): void {
    const report = this.reports.find(r => r.id === reportId);
    if (report) {
      report.reject(approver, comment);
      this.persist();
    }
  }

  private persist(): void {
    AppStorage.setOrCreate('weekly_reports', JSON.stringify(this.reports));
    AppStorage.setOrCreate('weekly_templates', JSON.stringify(this.templates));
    AppStorage.setOrCreate('weekly_current_id', this.currentReportId);
  }

  load(): void {
    const reports = AppStorage.get<string>('weekly_reports');
    if (reports) {
      try {
        const parsed = JSON.parse(reports);
        this.reports = parsed.map((r: any) => new WeeklyReport(r));
      } catch (e) {
        console.error('加载周报数据失败', e);
      }
    }

    const templates = AppStorage.get<string>('weekly_templates');
    if (templates) {
      try {
        const parsed = JSON.parse(templates);
        this.templates = parsed.map((t: any) => new WeeklyTemplate(t));
      } catch (e) {
        console.error('加载模板数据失败', e);
      }
    }

    this.currentReportId = AppStorage.get<string>('weekly_current_id') || '';
  }

  private getWeekNumber(date: Date): number {
    const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
    const dayNum = d.getUTCDay() || 7;
    d.setUTCDate(d.getUTCDate() + 4 - dayNum);
    const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
    return Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
  }
}

// === 统计 ===
export interface WeeklyStats {
  totalReports: number;
  myTotal: number;
  myDraft: number;
  mySubmitted: number;
  myApproved: number;
  myRejected: number;
  pendingReview: number;
  avgCompletion: number;
  totalHours: number;
  thisWeekHours: number;
}

// 全局状态
export const weeklyState = new WeeklyState();
AppStorage.setOrCreate('weeklyState', weeklyState);

四、主页面实现

4.1 页面入口(entry/src/main/ets/pages/WeeklyReviewPage.ets

// entry/src/main/ets/pages/WeeklyReviewPage.ets
// 龍魂 · 周报管理主页面 · ArkTS

import { WeeklyReport, WeeklyStatus, WeeklyTask, TaskStatus, TaskType, Priority, WeeklyState, weeklyState, WeeklyStats, WeeklyIssue, WeeklyRisk, NextTask } from '../models/WeeklyModel';
import { TaskEditDialog } from '../components/TaskEditDialog';
import { ApprovalDialog } from '../components/ApprovalDialog';
import { HourChartView } from '../components/HourChartView';
import { TrendChartView } from '../components/TrendChartView';
import { WeeklyDetailDialog } from '../components/WeeklyDetailDialog';
import { TemplateDialog } from '../components/TemplateDialog';
import { WeeklyDatabase } from '../database/WeeklyDatabase';

@Entry
@Component
struct WeeklyReviewPage {
  @StorageLink('weeklyState') weeklyState: WeeklyState = weeklyState;
  @State private selectedTab: number = 0;
  @State private showTaskDialog: boolean = false;
  @State private showApprovalDialog: boolean = false;
  @State private showDetailDialog: boolean = false;
  @State private showTemplateDialog: boolean = false;
  @State private editingReport: WeeklyReport | null = null;
  @State private editingTask: WeeklyTask | null = null;
  @State private showSearch: boolean = false;
  @State private searchText: string = '';
  @State private viewMode: 'list' | 'stats' | 'trend' = 'list';

  aboutToAppear() {
    this.weeklyState.load();
    WeeklyDatabase.init();
    this.scheduleReminders();
  }

  build() {
    Column() {
      this.HeaderBuilder()
      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.weeklyState.statistics.myTotal}份周报`).fontSize(12).fontColor('#666')
      }
      .alignItems(HorizontalAlign.Start)
      Blank()
      if (this.weeklyState.pendingReview > 0) {
        Badge({
          value: this.weeklyState.pendingReview.toString(),
          position: BadgePosition.RightTop,
          style: { badgeSize: 18, badgeColor: '#c41e3a' }
        }) {
          Button() { Text('🔔').fontSize(20) }
          .type(ButtonType.Circle)
          .backgroundColor('rgba(196,30,58,0.2)')
          .width(40).height(40)
          .onClick(() => { this.selectedTab = 3; })
        }
      }
      Button() { Text(this.showSearch ? '✕' : '🔍').fontSize(20) }
      .type(ButtonType.Circle).backgroundColor('#1a1a1a').width(40).height(40)
      .onClick(() => {
        this.showSearch = !this.showSearch;
        if (!this.showSearch) { this.weeklyState.searchQuery = ''; }
      })
      Button() { Text('+').fontSize(24).fontColor('#fff') }
      .type(ButtonType.Circle).backgroundColor('#c41e3a').width(40).height(40)
      .onClick(() => { this.createNewWeekly(); })
    }
    .width('100%').height(56).padding({ left: 16, right: 16 })
    .backgroundColor('#1a1a1a')
    .border({ width: { bottom: 1 }, color: '#333' })
  }

4.3 统计卡片

  @Builder
  StatsBuilder() {
    Row() {
      this.StatCard('我的周报', this.weeklyState.statistics.myTotal.toString(), '#fff')
      this.StatCard('草稿', this.weeklyState.statistics.myDraft.toString(), '#ffcc00')
      this.StatCard('已提交', this.weeklyState.statistics.mySubmitted.toString(), '#0066cc')
      this.StatCard('已通过', this.weeklyState.statistics.myApproved.toString(), '#00ff00')
      this.StatCard('本周工时', `${this.weeklyState.statistics.thisWeekHours}h`, '#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.4 视图控制

  @Builder
  ViewControlBuilder() {
    Row() {
      Row() {
        Button() { Text('◀').fontSize(14).fontColor('#999') }
        .type(ButtonType.Circle).backgroundColor('#1a1a1a').width(32).height(32)
        .onClick(() => { this.prevWeek(); })
        Text(this.getCurrentWeekLabel()).fontSize(14).fontColor('#fff').margin({ left: 12, right: 12 })
        Button() { Text('▶').fontSize(14).fontColor('#999') }
        .type(ButtonType.Circle).backgroundColor('#1a1a1a').width(32).height(32)
        .onClick(() => { this.nextWeek(); })
      }
      .layoutWeight(1)
      Blank()
      Row() {
        ForEach(['list', 'stats', 'trend'], (mode: string) => {
          Button() {
            Text(mode === 'list' ? '列表' : mode === 'stats' ? '统计' : '趋势')
            .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 'list' | 'stats' | 'trend'; })
        })
      }
    }
    .width('100%').height(48).padding({ left: 12, right: 12 })
    .backgroundColor('#1a1a1a')
    .border({ width: { bottom: 1 }, color: '#333' })
  }

4.5 标签切换

  @Builder
  TabBuilder() {
    Row() {
      ForEach([
        { label: '我的周报', icon: '📝', count: this.weeklyState.statistics.myDraft },
        { label: '团队周报', icon: '👥', count: 0 },
        { label: '工时统计', icon: '⏱️', count: 0 },
        { label: '待审批', icon: '✅', count: this.weeklyState.pendingReview }
      ], (item: {label: string, icon: string, count: number}, index: number) => {
        Column() {
          Text(`${item.icon} ${item.label}${item.count > 0 ? `(${item.count})` : ''}`)
            .fontSize(13)
            .fontWeight(this.selectedTab === index ? FontWeight.Bold : FontWeight.Normal)
            .fontColor(this.selectedTab === index ? '#c41e3a' : '#888')
          if (this.selectedTab === index) {
            Divider().strokeWidth(2).color('#c41e3a').width(20).margin({ top: 4 })
          }
        }
        .padding({ top: 12, bottom: 12, left: 16, right: 16 })
        .onClick(() => { this.selectedTab = index; })
      })
    }
    .width('100%').justifyContent(FlexAlign.SpaceAround)
    .backgroundColor('#1a1a1a')
    .border({ width: { bottom: 1 }, color: '#333' })
  }

4.6 搜索栏

  @Builder
  SearchBuilder() {
    Row() {
      TextInput({ placeholder: '搜索填报人/部门/周报编号...', text: $$this.searchText })
        .width('100%').height(40).backgroundColor('#2a2a2a')
        .fontColor('#fff').placeholderColor('#666')
        .borderRadius(8).padding({ left: 12, right: 12 })
        .onChange((value: string) => { this.weeklyState.searchQuery = value; })
    }
    .width('100%').padding({ left: 16, right: 16, top: 8, bottom: 8 })
    .backgroundColor('#1a1a1a')
  }

4.7 内容区

  @Builder
  ContentBuilder() {
    if (this.viewMode === 'list') {
      if (this.selectedTab === 0) { this.MyWeeklyListBuilder() }
      else if (this.selectedTab === 1) { this.TeamWeeklyListBuilder() }
      else if (this.selectedTab === 2) { this.HourStatsBuilder() }
      else { this.ApprovalListBuilder() }
    } else if (this.viewMode === 'stats') {
      HourChartView({ stats: this.weeklyState.statistics, trend: this.weeklyState.hourTrend })
    } else {
      TrendChartView({ trend: this.weeklyState.hourTrend })
    }
  }

4.8 我的周报列表

  @Builder
  MyWeeklyListBuilder() {
    List() {
      if (this.weeklyState.currentWeekDraft) {
        ListItem() { this.DraftCardBuilder(this.weeklyState.currentWeekDraft) }
      }
      ForEach(this.weeklyState.myReports, (report: WeeklyReport) => {
        ListItem() { this.WeeklyCardBuilder(report) }
        .onClick(() => { this.editingReport = report; this.showDetailDialog = true; })
      }, (report: WeeklyReport) => report.id)
    }
    .width('100%').layoutWeight(1).divider({ strokeWidth: 1, color: '#222' })
    .scrollBar(BarState.Auto).padding({ bottom: 16 })
  }

  @Builder
  DraftCardBuilder(report: WeeklyReport) {
    Column() {
      Row() {
        Text('📝').fontSize(24).margin({ right: 12 })
        Column() {
          Text(`本周周报草稿`).fontSize(16).fontWeight(FontWeight.Bold).fontColor('#ffcc00')
          Text(`${report.weekStart.toLocaleDateString()} - ${report.weekEnd.toLocaleDateString()}`).fontSize(12).fontColor('#888')
        }
        .alignItems(HorizontalAlign.Start).layoutWeight(1)
        Button('继续编辑')
          .fontSize(12).fontColor('#0a0a0a').backgroundColor('#ffcc00')
          .borderRadius(8).padding({ left: 12, right: 12 })
          .onClick(() => { this.editingReport = report; this.showDetailDialog = true; })
      }
      .width('100%').padding(16)
    }
    .width('100%').backgroundColor('rgba(255,204,0,0.05)')
    .border({ width: 1, color: 'rgba(255,204,0,0.3)' }).borderRadius(8)
    .margin({ left: 12, right: 12, top: 8 })
  }

4.9 周报卡片

  @Builder
  WeeklyCardBuilder(report: WeeklyReport) {
    Row() {
      Column() {
        Text(
          report.status === WeeklyStatus.DRAFT ? '📝' :
          report.status === WeeklyStatus.SUBMITTED ? '⏳' :
          report.status === WeeklyStatus.FIRST_REVIEW ? '👀' :
          report.status === WeeklyStatus.FINAL_REVIEW ? '🔍' :
          report.status === WeeklyStatus.APPROVED ? '✅' :
          report.status === WeeklyStatus.REJECTED ? '❌' : '📦'
        ).fontSize(24)
      }
      .width(40).height(40).margin({ right: 12 }).justifyContent(FlexAlign.Center)
      Column() {
        Row() {
          Text(report.reportNo).fontSize(14).fontWeight(FontWeight.Medium).fontColor('#fff').layoutWeight(1)
          Text(report.status)
            .fontSize(11).fontColor(this.getStatusColor(report.status))
            .backgroundColor(this.getStatusBgColor(report.status))
            .borderRadius(4).padding({ left: 8, right: 8, top: 2, bottom: 2 })
        }
        .width('100%')
        Row() {
          Text(`${report.weekStart.toLocaleDateString()} - ${report.weekEnd.toLocaleDateString()}`).fontSize(12).fontColor('#888').layoutWeight(1)
          Text(`${report.completionRate}%完成`).fontSize(12).fontColor(report.completionRate >= 80 ? '#00ff00' : report.completionRate >= 50 ? '#ffcc00' : '#ff6600')
        }
        .width('100%').margin({ top: 4 })
        Row() {
          Text(`⏱️${report.totalActualHours}h/${report.totalPlannedHours}h`).fontSize(11).fontColor('#666')
          Text(`📋${report.tasks.length}项任务`).fontSize(11).fontColor('#666').margin({ left: 8 })
          if (report.totalOvertimeHours > 0) {
            Text(`🔥${report.totalOvertimeHours}h加班`).fontSize(11).fontColor('#ff6600').margin({ left: 8 })
          }
          Blank()
          if (report.status === WeeklyStatus.SUBMITTED || report.status === WeeklyStatus.FIRST_REVIEW) {
            const progress = report.getApprovalProgress();
            Stack() {
              Row().width(50).height(4).backgroundColor('#333').borderRadius(2)
              Row().width(`${progress.percentage}%`).height(4).backgroundColor('#c41e3a').borderRadius(2)
            }
            .width(50).height(4)
            Text(`${progress.current}/${progress.total}`).fontSize(10).fontColor('#c41e3a').margin({ left: 4 })
          }
        }
        .width('100%').margin({ top: 6 })
      }
      .layoutWeight(1).alignItems(HorizontalAlign.Start)
    }
    .width('100%').padding(16)
    .backgroundColor(
      report.status === WeeklyStatus.REJECTED ? 'rgba(255,0,0,0.05)' :
      report.status === WeeklyStatus.APPROVED ? 'rgba(0,255,0,0.05)' : '#0a0a0a'
    )
    .borderRadius(8).margin({ left: 12, right: 12, top: 8 })
  }

4.10 审批列表

  @Builder
  ApprovalListBuilder() {
    List() {
      if (this.weeklyState.pendingFirstReview.length > 0) {
        ListItem() {
          Text(`⏳ 初审待办 (${this.weeklyState.pendingFirstReview.length})`).fontSize(14).fontWeight(FontWeight.Bold).fontColor('#ffcc00').padding({ left: 16, top: 12, bottom: 8 })
        }
        .width('100%').backgroundColor('#1a1a1a')
      }
      ForEach(this.weeklyState.pendingFirstReview, (report: WeeklyReport) => {
        ListItem() { this.ApprovalCardBuilder(report, 1) }
        .onClick(() => { this.editingReport = report; this.showApprovalDialog = true; })
      }, (report: WeeklyReport) => `first-${report.id}`)

      if (this.weeklyState.pendingFinalReview.length > 0) {
        ListItem() {
          Text(`🔍 终审待办 (${this.weeklyState.pendingFinalReview.length})`).fontSize(14).fontWeight(FontWeight.Bold).fontColor('#c41e3a').padding({ left: 16, top: 12, bottom: 8 })
        }
        .width('100%').backgroundColor('#1a1a1a')
      }
      ForEach(this.weeklyState.pendingFinalReview, (report: WeeklyReport) => {
        ListItem() { this.ApprovalCardBuilder(report, 2) }
        .onClick(() => { this.editingReport = report; this.showApprovalDialog = true; })
      }, (report: WeeklyReport) => `final-${report.id}`)
    }
    .width('100%').layoutWeight(1).divider({ strokeWidth: 1, color: '#222' })
    .scrollBar(BarState.Auto).padding({ bottom: 16 })
  }

  @Builder
  ApprovalCardBuilder(report: WeeklyReport, level: number) {
    Row() {
      Column() { Text('⏳').fontSize(24) }
      .width(40).height(40).margin({ right: 12 }).justifyContent(FlexAlign.Center)
      Column() {
        Row() {
          Text(`${report.reporter} 的周报`).fontSize(15).fontWeight(FontWeight.Medium).fontColor('#fff').layoutWeight(1)
          Text(`L${level}审批`).fontSize(11).fontColor('#c41e3a').backgroundColor('rgba(196,30,58,0.1)').borderRadius(4).padding({ left: 6, right: 6 })
        }
        .width('100%')
        Row() {
          Text(`${report.department} · ${report.reportNo}`).fontSize(12).fontColor('#888').layoutWeight(1)
          Text(`${report.tasks.length}项 · ${report.totalActualHours}h`).fontSize(12).fontColor('#888')
        }
        .width('100%').margin({ top: 4 })
        Row() {
          Text(`📅 ${report.submittedAt?.toLocaleString() || ''}`).fontSize(11).fontColor('#666')
          Blank()
          Button('去审批').fontSize(11).fontColor('#fff').backgroundColor('#c41e3a').borderRadius(6).padding({ left: 12, right: 12, top: 4, bottom: 4 })
          .onClick(() => { this.editingReport = report; this.showApprovalDialog = true; })
        }
        .width('100%').margin({ top: 6 })
      }
      .layoutWeight(1).alignItems(HorizontalAlign.Start)
    }
    .width('100%').padding(16).backgroundColor('#0a0a0a').borderRadius(8).margin({ left: 12, right: 12, top: 8 })
  }

4.11 底部操作栏

  @Builder
  FooterBuilder() {
    Row() {
      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.showTemplateDialog = 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.exportWeekly(); })
        Button() { Text('➕ 任务').fontSize(12).fontColor('#fff') }
        .type(ButtonType.Normal).backgroundColor('#c41e3a').borderRadius(8).padding({ left: 12, right: 12, top: 6, bottom: 6 })
        .onClick(() => { this.editingTask = null; this.showTaskDialog = true; })
      }
    }
    .width('100%').height(56).padding({ left: 16, right: 16 })
    .backgroundColor('#1a1a1a')
    .border({ width: { top: 1 }, color: '#333' })
  }

4.12 辅助方法

  getStatusColor(status: WeeklyStatus): string {
    switch (status) {
      case WeeklyStatus.DRAFT: return '#ffcc00';
      case WeeklyStatus.SUBMITTED: return '#0066cc';
      case WeeklyStatus.FIRST_REVIEW: return '#ff6600';
      case WeeklyStatus.FINAL_REVIEW: return '#c41e3a';
      case WeeklyStatus.APPROVED: return '#00ff00';
      case WeeklyStatus.REJECTED: return '#ff0000';
      case WeeklyStatus.ARCHIVED: return '#888';
      default: return '#999';
    }
  }

  getStatusBgColor(status: WeeklyStatus): string {
    switch (status) {
      case WeeklyStatus.DRAFT: return 'rgba(255,204,0,0.1)';
      case WeeklyStatus.SUBMITTED: return 'rgba(0,102,204,0.1)';
      case WeeklyStatus.FIRST_REVIEW: return 'rgba(255,102,0,0.1)';
      case WeeklyStatus.FINAL_REVIEW: return 'rgba(196,30,58,0.1)';
      case WeeklyStatus.APPROVED: return 'rgba(0,255,0,0.1)';
      case WeeklyStatus.REJECTED: return 'rgba(255,0,0,0.1)';
      case WeeklyStatus.ARCHIVED: return 'rgba(136,136,136,0.1)';
      default: return 'rgba(153,153,153,0.1)';
    }
  }

  toggleViewMode(): void {
    const modes: ('list' | 'stats' | 'trend')[] = ['list', 'stats', 'trend'];
    const currentIndex = modes.indexOf(this.viewMode);
    this.viewMode = modes[(currentIndex + 1) % modes.length];
  }

  getCurrentWeekLabel(): string {
    const now = new Date();
    const d = new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()));
    const dayNum = d.getUTCDay() || 7;
    d.setUTCDate(d.getUTCDate() + 4 - dayNum);
    const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
    const weekNum = Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
    return `${now.getFullYear()}年第${weekNum}`;
  }

  prevWeek(): void { /* 切换到上一周 */ }
  nextWeek(): void { /* 切换到下一周 */ }

  createNewWeekly(): void {
    const newReport = new WeeklyReport({
      reporter: this.weeklyState.currentUser,
      reporterId: this.weeklyState.currentUserId,
      department: this.weeklyState.currentDept
    });
    this.weeklyState.addReport(newReport);
    this.editingReport = newReport;
    this.showDetailDialog = true;
  }

  exportWeekly(): void {
    const data = {
      exportTime: new Date().toISOString(),
      dna: MASTER_DNA,
      uid: MASTER_UID,
      confirm: CONFIRM_SEAL,
      reports: this.weeklyState.myReports.map(r => ({
        reportNo: r.reportNo,
        week: `${r.weekStart.toLocaleDateString()}-${r.weekEnd.toLocaleDateString()}`,
        status: r.status,
        completionRate: r.completionRate,
        plannedHours: r.totalPlannedHours,
        actualHours: r.totalActualHours,
        overtimeHours: r.totalOvertimeHours,
        taskCount: r.tasks.length
      }))
    };
    console.info(`[龍魂] 周报导出: longhun_weekly_${Date.now()}.json`);
  }

  scheduleReminders(): void {
    console.info('[龍魂] 周报提醒系统已启动');
  }
}

const MASTER_DNA = "ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼‍♀️❤️♾️";
const MASTER_UID = "9622";

五、组件清单

文件 路径 说明
数据模型 entry/src/main/ets/models/WeeklyModel.ets WeeklyReport/WeeklyTask/NextTask/WeeklyIssue/WeeklyRisk/WeeklyState
主页面 entry/src/main/ets/pages/WeeklyReviewPage.ets 完整UI
任务编辑 entry/src/main/ets/components/TaskEditDialog.ets 任务增改弹窗
审批弹窗 entry/src/main/ets/components/ApprovalDialog.ets 审批操作
周报详情 entry/src/main/ets/components/WeeklyDetailDialog.ets 周报完整查看/编辑
工时图表 entry/src/main/ets/components/HourChartView.ets 工时统计可视化
趋势图表 entry/src/main/ets/components/TrendChartView.ets 多周趋势对比
模板管理 entry/src/main/ets/components/TemplateDialog.ets 周报模板配置
数据库 entry/src/main/ets/database/WeeklyDatabase.ets 关系型存储

六、鸿蒙特性使用

特性 用途 API
ArkTS声明式UI 界面构建 @Component @Entry
状态管理 数据响应 @State @Observed @StorageLink
关系型数据库 本地加密存储 relationalStore
通知 周报提醒 notificationManager
日历 周次计算 calendarManager
后台任务 定时提醒 workScheduler
打印 周报打印 print
分享 数据导出 share
文档选择 附件上传 documentPicker
国密算法 数据签名 cryptoFramework SM2/SM3

七、审批流转机制

状态 触发条件 操作人
草稿 新建周报 填报人
已提交 填报人提交 填报人 → 初审人
初审中 部门主管审核 初审人
终审中 初审通过 初审人 → 终审人
已通过 终审通过 终审人
已驳回 任意审批驳回 审批人 → 填报人
已归档 审批通过后归档 系统

八、工时统计维度

维度 指标 说明
个人 本周工时/累计工时/平均工时 个人维度追踪
团队 部门总工时/人均工时 团队维度对比
项目 项目投入工时/占比 项目维度分析
类型 开发/设计/测试/会议占比 工作类型分布
趋势 近8周工时曲线 长期趋势分析
偏差 计划vs实际工时差 预估准确度

九、龍魂标识

位置 内容
应用名称 龍魂周报管理
标题栏 🐉 龍魂周报管理
底部标识 UID:9622
数据签名 SM3-哈希
DNA ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼‍♀️❤️♾️

🐉 龍魂 · 鸿蒙 ArkTS 实战:Weekly Review 周报管理 交付完成

DNA: ZHUGEXIN⚡️2025-🇨🇳🐉⚖️♠️🧚🏼‍♀️❤️♾️
UID: 9622
确认码: #CONFIRM🌌9622-ONLY-ONCE🧬LK9X-772Z
时间: 2026-07-14
模块: 9核心文件
特性: 周报模板 · 任务录入 · 自动汇总 · 多级审批 · 工时统计 · 趋势分析 · 历史归档 · 国密签名

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐