project-issues-modal.component.html 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <div class="issues-modal" *ngIf="isVisible">
  2. <div class="overlay" (click)="onClose()"></div>
  3. <div class="modal">
  4. <div class="header">
  5. <div class="title-area">
  6. <h3>问题追踪</h3>
  7. <div class="counts">
  8. <span class="count total">总计 {{ counts.total }}</span>
  9. <span class="count open">未开始 {{ counts.open }}</span>
  10. <span class="count in-progress">处理中 {{ counts.in_progress }}</span>
  11. <span class="count resolved">已解决 {{ counts.resolved }}</span>
  12. <span class="count closed">已关闭 {{ counts.closed }}</span>
  13. </div>
  14. </div>
  15. <button class="close-btn" (click)="onClose()" aria-label="关闭">×</button>
  16. </div>
  17. <div class="tools">
  18. <input
  19. class="search-input"
  20. type="text"
  21. placeholder="搜索标题、标签或描述..."
  22. [(ngModel)]="searchText"
  23. (input)="onSearchChange()"
  24. />
  25. <div class="filters">
  26. <button class="chip" [class.active]="filterStatus.includes('open')" (click)="toggleStatusFilter('open')">未开始</button>
  27. <button class="chip" [class.active]="filterStatus.includes('in_progress')" (click)="toggleStatusFilter('in_progress')">处理中</button>
  28. <button class="chip" [class.active]="filterStatus.includes('resolved')" (click)="toggleStatusFilter('resolved')">已解决</button>
  29. <button class="chip" [class.active]="filterStatus.includes('closed')" (click)="toggleStatusFilter('closed')">已关闭</button>
  30. </div>
  31. <button class="primary" (click)="startCreate()" *ngIf="!creating">+ 新建问题</button>
  32. </div>
  33. <div class="create-form" *ngIf="creating">
  34. <div class="form-grid">
  35. <div class="form-item">
  36. <label>标题</label>
  37. <input type="text" [(ngModel)]="newTitle" placeholder="简短描述问题" />
  38. </div>
  39. <div class="form-item">
  40. <label>优先级</label>
  41. <select [(ngModel)]="newPriority">
  42. <option value="low">低</option>
  43. <option value="medium">中</option>
  44. <option value="high">高</option>
  45. <option value="critical">紧急</option>
  46. </select>
  47. </div>
  48. <div class="form-item">
  49. <label>类型</label>
  50. <select [(ngModel)]="newType">
  51. <option value="task">任务</option>
  52. <option value="bug">问题</option>
  53. <option value="feedback">反馈</option>
  54. <option value="risk">风险</option>
  55. </select>
  56. </div>
  57. <div class="form-item">
  58. <label>截止日期</label>
  59. <input type="date" [(ngModel)]="newDueDate" />
  60. </div>
  61. <div class="form-item full">
  62. <label>描述</label>
  63. <textarea rows="3" [(ngModel)]="newDescription" placeholder="可选:详细说明"></textarea>
  64. </div>
  65. <div class="form-item full">
  66. <label>标签</label>
  67. <input type="text" [(ngModel)]="newTagsText" placeholder="用逗号分隔,如:灯光,尺寸" />
  68. </div>
  69. </div>
  70. <div class="form-actions">
  71. <button class="secondary" (click)="cancelCreate()">取消</button>
  72. <button class="primary" (click)="submitCreate()" [disabled]="!newTitle.trim()">创建</button>
  73. </div>
  74. </div>
  75. <div class="body">
  76. <div class="loading" *ngIf="loading">加载中...</div>
  77. <div class="error" *ngIf="error">{{ error }}</div>
  78. <div class="empty" *ngIf="!loading && !error && issues.length === 0">暂无问题,点击右上角“新建问题”开始吧。</div>
  79. <div class="issue-list" *ngIf="!loading && !error && issues.length > 0">
  80. <div class="issue-item" *ngFor="let issue of issues">
  81. <div class="title-row">
  82. <div class="left">
  83. <span class="issue-title">{{ issue.title }}</span>
  84. <span class="badge status" [class.open]="issue.status==='open'" [class.in-progress]="issue.status==='in_progress'" [class.resolved]="issue.status==='resolved'" [class.closed]="issue.status==='closed'">
  85. {{ issue.status === 'open' ? '未开始' : issue.status === 'in_progress' ? '处理中' : issue.status === 'resolved' ? '已解决' : '已关闭' }}
  86. </span>
  87. <span class="badge priority" [class.low]="issue.priority==='low'" [class.medium]="issue.priority==='medium'" [class.high]="issue.priority==='high'" [class.critical]="issue.priority==='critical'">
  88. {{ issue.priority === 'low' ? '低' : issue.priority === 'medium' ? '中' : issue.priority === 'high' ? '高' : '紧急' }}
  89. </span>
  90. </div>
  91. <div class="right">
  92. <button class="icon" title="删除" (click)="deleteIssue(issue)">🗑</button>
  93. </div>
  94. </div>
  95. <div class="description" *ngIf="issue.description">{{ issue.description }}</div>
  96. <div class="meta">
  97. <span class="tag" *ngFor="let t of issue.tags">{{ t }}</span>
  98. <span class="due" *ngIf="issue.dueDate">截止: {{ issue.dueDate | date:'MM-dd' }}</span>
  99. </div>
  100. <div class="actions">
  101. <span class="action-label">状态切换:</span>
  102. <button class="ghost" (click)="setStatus(issue, 'open')">未开始</button>
  103. <button class="ghost" (click)="setStatus(issue, 'in_progress')">处理中</button>
  104. <button class="ghost" (click)="setStatus(issue, 'resolved')">已解决</button>
  105. <button class="ghost" (click)="setStatus(issue, 'closed')">关闭</button>
  106. </div>
  107. <div class="comments">
  108. <div class="comment-item" *ngFor="let c of issue.comments">
  109. <span class="time">{{ c.createdAt | date:'MM-dd HH:mm' }}</span>
  110. <span class="content">{{ c.content }}</span>
  111. </div>
  112. <div class="comment-input">
  113. <input type="text" placeholder="添加评论或催办..." #cInput>
  114. <button class="primary" (click)="addComment(issue, cInput.value); cInput.value=''">发送</button>
  115. </div>
  116. </div>
  117. </div>
  118. </div>
  119. </div>
  120. </div>
  121. </div>