team-assign.component.html 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <!-- 设计师分配组件 -->
  2. <div class="card designer-card">
  3. <div class="card-header">
  4. <h3 class="card-title">
  5. 设计师分配
  6. </h3>
  7. <p class="card-subtitle">先选择项目组,再选择组员</p>
  8. </div>
  9. <div class="card-content">
  10. <!-- 已分配组员展示 -->
  11. @if (projectTeams.length > 0) {
  12. <div class="assigned-teams-section">
  13. <h4 class="section-title">已分配组员</h4>
  14. <div class="team-list">
  15. @for (team of projectTeams; track team.id) {
  16. <div
  17. class="team-item"
  18. [class.clickable]="canEdit"
  19. (click)="canEdit ? editAssignedDesigner(team) : null">
  20. <div class="team-member">
  21. <div class="member-avatar">
  22. @if (team.get('profile')?.get('data')?.avatar) {
  23. <img [src]="team.get('profile').get('data').avatar" alt="组员头像" />
  24. } @else {
  25. <svg class="icon avatar-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  26. <path fill="currentColor" d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm0 60a60 60 0 11-60 60 60 60 0 0160-60zm0 336c-63.6 0-119.92-36.47-146.39-89.68C109.74 329.09 176.24 296 256 296s146.26 33.09 146.39 58.32C376.92 407.53 319.6 444 256 444z"/>
  27. </svg>
  28. }
  29. </div>
  30. <div class="member-info">
  31. <h5>{{ team.get('profile')?.get('name') }}</h5>
  32. <p class="member-spaces">负责空间: {{ getMemberSpaces(team) }}</p>
  33. </div>
  34. </div>
  35. @if (canEdit) {
  36. <svg class="icon edit-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  37. <path fill="currentColor" d="M384 224v184a40 40 0 01-40 40H104a40 40 0 01-40-40V168a40 40 0 0140-40h167.48M459.94 53.25a16.06 16.06 0 00-23.22-.56L424.35 65a8 8 0 000 11.31l11.34 11.32a8 8 0 0011.34 0l12.06-12c6.1-6.09 6.67-16.01.85-22.38zM399.34 90L218.82 270.2a9 9 0 00-2.31 3.93L208.16 299a3.91 3.91 0 004.86 4.86l24.85-8.35a9 9 0 003.93-2.31L422 112.66a9 9 0 000-12.66l-9.95-10a9 9 0 00-12.71 0z"/>
  38. </svg>
  39. }
  40. </div>
  41. }
  42. </div>
  43. </div>
  44. }
  45. <!-- 项目组选择 -->
  46. <div class="department-section">
  47. <h4 class="section-title">选择项目组</h4>
  48. @if (departments.length === 0) {
  49. <div class="empty-state">
  50. <p>暂无可用项目组</p>
  51. </div>
  52. } @else {
  53. <div class="department-grid">
  54. @for (dept of departments; track dept.id) {
  55. <div
  56. class="department-item"
  57. [class.selected]="selectedDepartment?.id === dept.id"
  58. (click)="selectDepartment(dept)">
  59. <h5>{{ dept.get('name') }}</h5>
  60. <p>组长: {{ dept.get('leader')?.get('name') || '未指定' }}</p>
  61. @if (selectedDepartment?.id === dept.id) {
  62. <svg class="icon selected-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  63. <path fill="currentColor" d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm-38 312.38L137.4 280.8a24 24 0 0133.94-33.94l50.2 50.2 95.74-95.74a24 24 0 0133.94 33.94z"/>
  64. </svg>
  65. }
  66. </div>
  67. }
  68. </div>
  69. }
  70. </div>
  71. <!-- 组员选择 -->
  72. @if (selectedDepartment) {
  73. <div class="designer-section">
  74. <h4 class="section-title">选择组员</h4>
  75. @if (loadingMembers) {
  76. <div class="loading-spinner">
  77. <div class="spinner-sm"></div>
  78. <p>加载组员中...</p>
  79. </div>
  80. } @else if (departmentMembers.length === 0) {
  81. <div class="empty-state">
  82. <p>该项目组暂无可用组员</p>
  83. </div>
  84. } @else {
  85. <div class="designer-grid">
  86. @for (designer of departmentMembers; track designer.id) {
  87. @if(designer?.get){
  88. <div
  89. class="designer-item"
  90. [class.selected]="selectedDesigner?.id === designer?.id"
  91. (click)="selectDesigner(designer)">
  92. <div class="designer-avatar">
  93. @if (designer?.get('data')?.avatar) {
  94. <img [src]="designer?.get('data').avatar" alt="设计师头像" />
  95. } @else {
  96. <svg class="icon avatar-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  97. <path fill="currentColor" d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm0 60a60 60 0 11-60 60 60 60 0 0160-60zm0 336c-63.6 0-119.92-36.47-146.39-89.68C109.74 329.09 176.24 296 256 296s146.26 33.09 146.39 58.32C376.92 407.53 319.6 444 256 444z"/>
  98. </svg>
  99. }
  100. </div>
  101. <div class="designer-info">
  102. <h4>{{ designer?.get('name') }}</h4>
  103. <p>{{ getDesignerWorkload(designer) }}</p>
  104. </div>
  105. @if (selectedDesigner?.id === designer?.id) {
  106. <svg class="icon selected-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  107. <path fill="currentColor" d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm-38 312.38L137.4 280.8a24 24 0 0133.94-33.94l50.2 50.2 95.74-95.74a24 24 0 0133.94 33.94z"/>
  108. </svg>
  109. }
  110. </div>
  111. }
  112. }
  113. </div>
  114. }
  115. </div>
  116. }
  117. </div>
  118. </div>
  119. <!-- 设计师分配对话框 -->
  120. @if (showAssignDialog && assigningDesigner) {
  121. <div class="modal-overlay" (click)="cancelAssignDialog()">
  122. <div class="modal-dialog" (click)="$event.stopPropagation()">
  123. <div class="modal-header">
  124. <h3 class="modal-title">{{ editingTeam ? '编辑分配' : '分配设计师' }}</h3>
  125. <button class="modal-close" (click)="cancelAssignDialog()">
  126. <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  127. <path fill="currentColor" d="M289.94 256l95-95A24 24 0 00351 127l-95 95-95-95a24 24 0 00-34 34l95 95-95 95a24 24 0 1034 34l95-95 95 95a24 24 0 0034-34z"/>
  128. </svg>
  129. </button>
  130. </div>
  131. <div class="modal-content">
  132. <div class="designer-preview">
  133. <div class="designer-avatar">
  134. @if (assigningDesigner.get('data')?.avatar) {
  135. <img [src]="assigningDesigner.get('data').avatar" alt="设计师头像" />
  136. } @else {
  137. <svg class="icon avatar-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
  138. <path fill="currentColor" d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm0 60a60 60 0 11-60 60 60 60 0 0160-60zm0 336c-63.6 0-119.92-36.47-146.39-89.68C109.74 329.09 176.24 296 256 296s146.26 33.09 146.39 58.32C376.92 407.53 319.6 444 256 444z"/>
  139. </svg>
  140. }
  141. </div>
  142. <div class="designer-name">{{ assigningDesigner.get('name') }}</div>
  143. </div>
  144. <div class="space-selection-section">
  145. <h4 class="form-label">指派空间场景 <span class="required">*</span></h4>
  146. <p class="form-help">请选择该设计师负责的空间</p>
  147. <div class="space-checkbox-list">
  148. @for (space of projectSpaces; track space.id) {
  149. <label class="space-checkbox-item">
  150. <input
  151. type="checkbox"
  152. [checked]="selectedSpaces.includes(space.name)"
  153. (change)="toggleSpaceSelection(space.name)" />
  154. <span class="checkbox-custom"></span>
  155. <span class="space-name">{{ space.name }}</span>
  156. </label>
  157. }
  158. </div>
  159. </div>
  160. </div>
  161. <div class="modal-footer">
  162. <button class="btn btn-outline" (click)="cancelAssignDialog()">
  163. 取消
  164. </button>
  165. <button
  166. class="btn btn-primary"
  167. (click)="confirmAssignDesigner()"
  168. [disabled]="saving || selectedSpaces.length === 0">
  169. {{ editingTeam ? '确认更新' : '确认分配' }}
  170. </button>
  171. </div>
  172. </div>
  173. </div>
  174. }